(sessionDir: string, state: StateJson, deriveHomedir = false)
| 255 | } |
| 256 | |
| 257 | async function inventoryAgents(sessionDir: string, state: StateJson, deriveHomedir = false): Promise<AgentInfo[]> { |
| 258 | const result: AgentInfo[] = []; |
| 259 | for (const [id, meta] of Object.entries(state.agents ?? {})) { |
| 260 | if (!isSafeAgentId(id)) continue; |
| 261 | // A type-corrupt entry (e.g. `{ "main": null }`) must not throw on the |
| 262 | // field dereferences below; skip it so the empty-inventory fallback in |
| 263 | // readImportedDetail can recover the agent from disk instead. |
| 264 | if (typeof meta !== 'object' || meta === null) continue; |
| 265 | const wirePath = join(sessionDir, 'agents', id, 'wire.jsonl'); |
| 266 | const exists = await pathExists(wirePath); |
| 267 | let readable = exists; |
| 268 | let info: { count: number; protocolVersion: string | null } = { count: 0, protocolVersion: null }; |
| 269 | if (exists) { |
| 270 | try { |
| 271 | info = await scanWire(wirePath); |
| 272 | } catch { |
| 273 | // The file exists but is unreadable / malformed. Report it as |
| 274 | // unavailable so wire/context routes return 404 ("wire missing") |
| 275 | // instead of 500 ("READ_ERROR") and the UI shows the "no wire" |
| 276 | // badge consistently with the missing-file path. |
| 277 | readable = false; |
| 278 | } |
| 279 | } |
| 280 | result.push({ |
| 281 | agentId: id, |
| 282 | type: meta.type, |
| 283 | parentAgentId: meta.parentAgentId, |
| 284 | // For imported bundles the persisted homedir is the exporting machine's |
| 285 | // absolute path; re-derive it from the local extraction so blob reads |
| 286 | // (which join homedir) resolve under the imported directory. |
| 287 | homedir: deriveHomedir ? join(sessionDir, 'agents', id) : meta.homedir, |
| 288 | wireExists: readable, |
| 289 | wireRecordCount: info.count, |
| 290 | wireProtocolVersion: info.protocolVersion, |
| 291 | swarmItem: meta.swarmItem ?? null, |
| 292 | }); |
| 293 | } |
| 294 | return result.sort((a, b) => compareAgentIds(a.agentId, b.agentId)); |
| 295 | } |
| 296 | |
| 297 | async function readState(sessionDir: string): Promise<StateJson | null> { |
| 298 | try { |
no test coverage detected