@mclawnet/agent 0.6.23 → 0.6.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/start.ts","../src/hub-connection.ts","../src/fs-handler.ts","../src/swarm-control-dispatch.ts","../src/schedule-runtime.ts","../src/session-manager.ts","../src/skill-loader.ts","../src/errors.ts","../src/checkpoint.ts","../src/brain-bridge.ts","../src/fs-bridge.ts","../src/swarm-session-bridge.ts"],"sourcesContent":["import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { loadConfig, type AgentConfig } from \"./config.js\";\nimport { HubConnection } from \"./hub-connection.js\";\nimport { ScheduleRuntime } from \"./schedule-runtime.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { SwarmCoordinator, initRoles } from \"@mclawnet/swarm\";\nimport { TaskStore } from \"@mclawnet/task\";\nimport { initSkills, getSkillList } from \"./skill-loader.js\";\nimport { BrainBridge } from \"./brain-bridge.js\";\nimport { FsBridge } from \"./fs-bridge.js\";\nimport { createSwarmAwareSessionStartedHandler } from \"./swarm-session-bridge.js\";\nimport type { BackendAdapter } from \"./backend-adapter.js\";\nimport { createLogger } from \"@mclawnet/logger\";\nimport {\n initDatabase,\n MemoryStore,\n EmbeddingService,\n createEmbeddingProviders,\n distillConversation,\n} from \"@mclawnet/memory\";\nimport {\n SkillStore,\n EvolutionPipeline,\n AccumulationScanner,\n triggerFromAccumulation,\n type MemoryRef,\n} from \"@mclawnet/skill-manager\";\n\nconst log = createLogger({ module: \"agent\" });\n\nexport interface StartOptions {\n config?: Partial<AgentConfig>;\n adapter: BackendAdapter;\n}\n\n/**\n * Start the ClawNet agent: connect to Hub and register a BackendAdapter.\n */\nexport async function startAgent(options: StartOptions): Promise<{\n hub: HubConnection;\n sessionManager: SessionManager;\n swarmCoordinator: SwarmCoordinator;\n scheduleRuntime: ScheduleRuntime;\n brainBridge: BrainBridge;\n fsBridge: FsBridge;\n}> {\n const config = loadConfig(options.config);\n\n if (!config.token) {\n log.error(\"no token configured — set CLAWNET_TOKEN or use --token\");\n process.exit(1);\n }\n\n log.info({ backend: options.adapter.type }, \"starting agent\");\n log.info({ hubUrl: config.hubUrl }, \"connecting to hub\");\n\n // Initialize role templates\n await initRoles();\n\n // Initialize skill system (copy built-in skills + ensure mcp.json)\n await initSkills();\n\n const hub = new HubConnection({\n hubUrl: config.hubUrl,\n token: config.token,\n hostname: config.name,\n onConnect: (agentId) => {\n log.info({ agentId }, \"connected to hub\");\n // Push available skills to browsers via Hub\n const skills = getSkillList();\n if (skills.length > 0) {\n hub.sendSkillList(skills);\n log.info({ count: skills.length }, \"pushed skill list to hub\");\n }\n // PR-C: as soon as the hub link is up, drain the previous-run\n // checkpoint and tell hub which sessions are dead. Doing this here\n // (rather than before connect) guarantees the session.died frames are\n // actually deliverable — sending them to a disconnected hub would just\n // queue them in the offline buffer with no recipient.\n void sessionManager\n .recoverFromCheckpoint()\n .then((report) => {\n for (const entry of report.dead) {\n hub.send({\n type: \"session.died\",\n sessionId: entry.sessionId,\n reason: \"agent_restart\",\n claudeSessionId: entry.claudeSessionId,\n });\n }\n log.info(\n { deadCount: report.dead.length, orphanCount: report.orphan.length },\n \"checkpoint recover: cleanup complete\",\n );\n })\n .catch((err) => {\n // Corrupt checkpoint or unreadable file should NOT block startup.\n // Worst case: we miss one round of session.died notifications and\n // the UI stays in the \"spinner\" state until the next user action.\n log.warn({ err }, \"checkpoint recover: failed (degrading to no-op)\");\n });\n },\n onDisconnect: (code, reason) => {\n log.info({ code, reason }, \"disconnected from hub\");\n },\n onError: (err) => {\n log.error({ err }, \"hub connection error\");\n },\n });\n\n // Create SwarmCoordinator (needs hub reference; sessionManager set after construction)\n // We use a lazy reference so the coordinator can be created before sessionManager\n let swarmCoordinator: SwarmCoordinator;\n\n // Shared infra for distillation + accumulation scanning on session close\n const clawnetDir = process.env.CLAWNET_DIR ?? join(homedir(), \".clawnet\");\n const dbPath = process.env.CLAWNET_MEMORY_DB ?? join(clawnetDir, \"memory.db\");\n let memoryStore: MemoryStore | null = null;\n let embeddingService: EmbeddingService | null = null;\n let evolutionPipeline: EvolutionPipeline | null = null;\n let skillStore: SkillStore | null = null;\n let memoryDb: ReturnType<typeof initDatabase> | null = null;\n try {\n memoryDb = initDatabase(dbPath);\n memoryStore = new MemoryStore(memoryDb);\n embeddingService = new EmbeddingService(memoryDb, createEmbeddingProviders());\n skillStore = new SkillStore(clawnetDir);\n evolutionPipeline = new EvolutionPipeline(clawnetDir);\n } catch (err) {\n log.warn({ err }, \"failed to init memory/skill infra; distillation disabled\");\n }\n\n const onBeforeClose = async (\n sessionId: string,\n messages: Array<{ role: string; content: string }>,\n ) => {\n if (messages.length === 0) return;\n if (!memoryStore || !embeddingService) return;\n\n // (1) Distill the conversation into role-__assistant__ memories.\n try {\n await distillConversation(\n messages,\n \"role-__assistant__\",\n memoryStore,\n embeddingService,\n );\n } catch (err) {\n log.warn({ err, sessionId }, \"distillation failed (non-fatal)\");\n }\n\n // (2) Scan recent assistant memories for accumulation signals and file\n // Layer-3 proposals against the current Skill set.\n try {\n if (!skillStore || !evolutionPipeline) return;\n const skills = skillStore.scan();\n if (skills.length === 0) return;\n const recent = memoryStore.getMemoriesByRole(\"role-__assistant__\", \"working\");\n const refs: MemoryRef[] = recent.map((m) => ({\n id: m.id,\n type: m.type,\n content: m.content,\n domain: m.domain,\n }));\n const scanner = new AccumulationScanner();\n const signals = scanner.scan(\n refs,\n skills.map((s) => s.name),\n );\n if (signals.length > 0) {\n await triggerFromAccumulation(signals, evolutionPipeline);\n }\n } catch (err) {\n log.warn({ err, sessionId }, \"accumulation scan failed (non-fatal)\");\n }\n };\n\n const sessionManager = new SessionManager({\n adapter: options.adapter,\n onOutput: (sessionId, data) => {\n // Intercept swarm role output\n if (swarmCoordinator.handleRoleOutput(sessionId, data)) return;\n\n // Normal (non-swarm) session output\n hub.send({\n type: \"claude.output\",\n sessionId,\n data,\n });\n },\n onTurnComplete: (sessionId, info) => {\n // Intercept swarm role turn completion\n if (swarmCoordinator.handleRoleTurnComplete(sessionId, info)) return;\n\n // Normal (non-swarm) session\n hub.send({\n type: \"claude.turn_complete\",\n sessionId,\n claudeSessionId: info.claudeSessionId,\n cost: info.cost,\n duration: info.duration,\n contextUsage: info.contextUsage,\n });\n },\n onSessionStarted: (sessionId, info) => {\n // Early backfill: tell hub the real claudeSessionId as soon as the\n // backend's `system/init` frame lands. Without this, db's\n // claude_session_id stays NULL until turn_complete — and a mid-turn\n // crash makes the jsonl file unfindable for `--resume`.\n //\n // Also bridges into the local SwarmCoordinator so per-role\n // claudeSessionId is captured in the swarm snapshot for restart resume.\n const handler = createSwarmAwareSessionStartedHandler({\n hub,\n swarmCoordinator,\n });\n handler(sessionId, info);\n },\n onSessionError: (sessionId, error) => {\n hub.send({\n type: \"session.error\",\n sessionId,\n error,\n });\n },\n onBeforeClose,\n // PR-A: classify session kind for the idle sweeper. SessionManager stays\n // independent of the swarm package; we hand it a closure that defers to\n // SwarmCoordinator (created below) at call time. Lazy-read is safe because\n // createSession can't run until the hub connection is up, by which point\n // swarmCoordinator is already assigned.\n classify: (sessionId) =>\n swarmCoordinator?.isSwarmSession(sessionId) ? \"swarm-role\" : \"chat\",\n // PR-C: enable logical-state checkpoint. Lives next to memory.db under\n // CLAWNET_DIR so backup/wipe affects both consistently. Per-call writes\n // are debounced to 5s by SessionManager itself.\n checkpointPath: join(clawnetDir, \"agent-sessions.json\"),\n });\n\n swarmCoordinator = new SwarmCoordinator(sessionManager, hub, (workDir) => {\n // Per-swarm TaskStore (Phase 7-E briefing injection).\n // TaskStore convention: `home` is the parent of `.clawnet/`, so we pass\n // `homedir()`. CLAWNET_DIR override is rare (mostly tests); when set, we\n // strip a trailing `.clawnet` to recover the parent.\n try {\n const env = process.env.CLAWNET_DIR;\n const home = env\n ? env.replace(/\\/\\.clawnet\\/?$/, \"\")\n : homedir();\n return new TaskStore({ workDir, home });\n } catch (err) {\n log.warn({ err, workDir }, \"TaskStore factory failed\");\n return undefined;\n }\n }, process.env.CLAWNET_HOME ?? homedir());\n\n hub.setSessionManager(sessionManager);\n hub.setSwarmCoordinator(swarmCoordinator);\n\n const scheduleRuntime = new ScheduleRuntime({ hub, sessionManager, swarmCoordinator });\n hub.setScheduleRuntime(scheduleRuntime);\n await scheduleRuntime.start();\n\n // Initialize BrainBridge (registers \"brain\" namespace handler)\n const brainBridge = new BrainBridge(hub);\n\n // Initialize FsBridge (registers \"fs\" namespace handler)\n const fsBridge = new FsBridge(hub);\n\n // PR-A: start idle TTL sweeper. Disabled when CLAWNET_CHAT_IDLE_TTL_MS=0.\n // Must be started after SessionManager is fully wired (handlers attached)\n // but before the hub connect, so a session created during the connect flow\n // is already covered.\n sessionManager.startIdleSweeper();\n\n // Graceful shutdown\n const shutdown = async () => {\n log.info(\"shutting down\");\n await sessionManager.closeAll();\n await scheduleRuntime.stop();\n hub.destroy();\n if (memoryDb) {\n try {\n memoryDb.close();\n } catch (err) {\n log.warn({ err }, \"failed to close memory db\");\n }\n }\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n hub.connect();\n\n return { hub, sessionManager, swarmCoordinator, scheduleRuntime, brainBridge, fsBridge };\n}\n","import { hostname as osHostname } from \"node:os\";\nimport WebSocket from \"ws\";\nimport {\n HEARTBEAT_INTERVAL_MS,\n DEFAULT_RECONNECT_MS,\n MAX_RECONNECT_MS,\n WS_CLOSE_INVALID_TOKEN,\n} from \"@mclawnet/shared\";\nimport type {\n AgentServerMessage,\n AgentClientMessage,\n AgentGenericRequest,\n AgentSessionDied,\n} from \"@mclawnet/shared\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { SwarmCoordinator } from \"@mclawnet/swarm\";\nimport { listRecoverableSwarms, recoverSwarm, listRoles, loadRole, listRecoverableSwarmIds, deleteSwarmSnapshot, listTemplates, loadTemplate } from \"@mclawnet/swarm\";\nimport { handleListDir, handleListFolders, handleListHistorySessions, handleLoadSessionHistory } from \"./fs-handler.js\";\nimport { handleSwarmControl, type SwarmControlMsg } from \"./swarm-control-dispatch.js\";\nimport { createLogger, previewFields } from \"@mclawnet/logger\";\n\nconst log = createLogger({ module: \"agent\" });\n\n/**\n * Structural type for the schedule runtime; declared locally so hub-connection\n * does not import from `./schedule-runtime.js` (which itself imports\n * `./session-manager.js`) — keeps this module's import graph stable and avoids\n * accidental cycles.\n */\ninterface ScheduleRuntimeBridge {\n handleHubMessage(msg: unknown): void;\n}\n\nexport interface HubConnectionOptions {\n hubUrl: string;\n token: string;\n hostname?: string;\n version?: string;\n capabilities?: string[];\n heartbeatInterval?: number;\n reconnectDelay?: number;\n maxReconnectDelay?: number;\n onMessage?: (data: unknown) => void;\n onConnect?: (agentId: string) => void;\n onDisconnect?: (code: number, reason: string) => void;\n onError?: (err: Error) => void;\n}\n\ntype AuthState = \"pending\" | \"authenticating\" | \"authenticated\";\n\nexport class HubConnection {\n private ws: WebSocket | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectDelay: number;\n private destroyed = false;\n private authState: AuthState = \"pending\";\n\n readonly hubUrl: string;\n readonly token: string;\n readonly hostname: string;\n readonly version: string | undefined;\n readonly capabilities: string[] | undefined;\n readonly heartbeatInterval: number;\n readonly maxReconnectDelay: number;\n\n /** Agent ID assigned by Hub after successful auth */\n agentId: string | null = null;\n\n /** Swarm IDs that have been completed/failed — prevents accidental recreation */\n private finishedSwarms = new Set<string>();\n\n /** Session manager — set after construction via setSessionManager() */\n private sessionManager: SessionManager | null = null;\n\n /** Swarm coordinator — set after construction via setSwarmCoordinator() */\n private swarmCoordinator: SwarmCoordinator | null = null;\n\n /** Schedule runtime — set after construction via setScheduleRuntime() */\n private scheduleRuntime: ScheduleRuntimeBridge | null = null;\n\n /** Namespace-based generic message handlers */\n private namespaceHandlers = new Map<\n string,\n (msg: AgentGenericRequest) => Promise<Record<string, unknown>>\n >();\n\n private onMessage?: (data: unknown) => void;\n private onConnectCb?: (agentId: string) => void;\n private onDisconnect?: (code: number, reason: string) => void;\n private onError?: (err: Error) => void;\n\n constructor(opts: HubConnectionOptions) {\n this.hubUrl = opts.hubUrl;\n this.token = opts.token;\n this.hostname = opts.hostname ?? osHostname();\n this.version = opts.version;\n this.capabilities = opts.capabilities;\n this.heartbeatInterval = opts.heartbeatInterval ?? HEARTBEAT_INTERVAL_MS;\n this.reconnectDelay = opts.reconnectDelay ?? DEFAULT_RECONNECT_MS;\n this.maxReconnectDelay = opts.maxReconnectDelay ?? MAX_RECONNECT_MS;\n this.onMessage = opts.onMessage;\n this.onConnectCb = opts.onConnect;\n this.onDisconnect = opts.onDisconnect;\n this.onError = opts.onError;\n }\n\n setSessionManager(manager: SessionManager): void {\n this.sessionManager = manager;\n }\n\n setSwarmCoordinator(coordinator: SwarmCoordinator): void {\n this.swarmCoordinator = coordinator;\n }\n\n setScheduleRuntime(runtime: ScheduleRuntimeBridge): void {\n this.scheduleRuntime = runtime;\n }\n\n registerNamespace(\n namespace: string,\n handler: (msg: AgentGenericRequest) => Promise<Record<string, unknown>>\n ) {\n this.namespaceHandlers.set(namespace, handler);\n }\n\n sendPush(namespace: string, event: string, data: Record<string, unknown>) {\n this.send({\n type: \"generic.push\",\n namespace,\n event,\n data,\n });\n }\n\n sendSkillList(skills: Array<{ name: string; description: string }>) {\n this.send({\n type: \"skill_list_update\",\n skills,\n });\n }\n\n get readyState(): number {\n return this.ws?.readyState ?? WebSocket.CLOSED;\n }\n\n get isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN && this.authState === \"authenticated\";\n }\n\n connect(): void {\n if (this.destroyed) return;\n this.cleanupConnection();\n this.authState = \"pending\";\n\n this.ws = new WebSocket(this.hubUrl);\n\n this.ws.on(\"open\", () => {\n this.reconnectDelay = DEFAULT_RECONNECT_MS;\n });\n\n this.ws.on(\"message\", (raw) => {\n let data: AgentServerMessage;\n try {\n data = JSON.parse(raw.toString());\n } catch {\n return;\n }\n\n // Step 1: Hub sends auth_required → reply with auth\n if (this.authState === \"pending\" && data.type === \"auth_required\") {\n log.info(\"hub requires auth, sending credentials\");\n this.authState = \"authenticating\";\n this.sendRaw({\n type: \"auth\",\n token: this.token,\n hostname: this.hostname,\n version: this.version,\n capabilities: this.capabilities,\n });\n return;\n }\n\n // Step 2: Hub sends registered → auth complete\n if (this.authState === \"authenticating\" && data.type === \"registered\") {\n log.info({ agentId: data.agentId }, \"registered with hub\");\n this.authState = \"authenticated\";\n this.agentId = data.agentId ?? null;\n this.startHeartbeat();\n this.onConnectCb?.(this.agentId!);\n\n // Attempt to recover any persisted swarms\n this.tryRecoverSwarms();\n\n // Report any sessions that survived reconnect to Hub\n this.reportLiveSessions();\n return;\n }\n\n // Post-auth message handling\n if (this.authState === \"authenticated\") {\n if (this.handleSessionMessage(data)) return;\n this.onMessage?.(data);\n }\n });\n\n this.ws.on(\"close\", (code, reason) => {\n log.warn({ code, reason: reason.toString() }, \"disconnected from hub\");\n this.stopHeartbeat();\n this.authState = \"pending\";\n this.onDisconnect?.(code, reason.toString());\n if (code === WS_CLOSE_INVALID_TOKEN) {\n log.error(\"auth failed — not reconnecting, check your token\");\n return;\n }\n this.scheduleReconnect();\n });\n\n this.ws.on(\"error\", (err) => {\n log.error({ err }, \"ws connection error\");\n this.onError?.(err);\n });\n }\n\n send(data: AgentClientMessage): boolean {\n // Track swarm completion to prevent accidental recreation\n const msg = data as any;\n if (msg.type === \"swarm.status\" && (msg.swarmStatus === \"completed\" || msg.swarmStatus === \"failed\")) {\n this.finishedSwarms.add(msg.sessionId);\n }\n return this.sendRaw(data);\n }\n\n destroy(): void {\n this.destroyed = true;\n this.cleanup();\n }\n\n // ── Session message handling ─────────────────────────────────────\n\n private handleSessionMessage(msg: AgentServerMessage): boolean {\n // ── Schedule routing — forward any schedule:* type to the schedule\n // runtime if one has been wired. Done before any other dispatch so the\n // runtime owns the entire `schedule:*` namespace.\n const msgType = (msg as { type?: unknown }).type;\n if (\n typeof msgType === \"string\" &&\n msgType.startsWith(\"schedule:\") &&\n this.scheduleRuntime\n ) {\n this.scheduleRuntime.handleHubMessage(msg);\n return true;\n }\n\n // ── Filesystem / history requests (no sessionManager needed) ─────\n\n if (msg.type === \"fs.list_dir\") {\n log.info({ path: msg.path }, \"fs.list_dir\");\n handleListDir(msg.path)\n .then((result) => {\n this.send({ type: \"fs.list_dir_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, path: msg.path }, \"fs.list_dir failed\");\n this.send({\n type: \"fs.list_dir_result\",\n requestId: msg.requestId,\n path: msg.path || \"/\",\n entries: [],\n });\n });\n return true;\n }\n\n if (msg.type === \"list_folders\") {\n log.info(\"list_folders\");\n handleListFolders()\n .then((result) => {\n this.send({ type: \"folders_list_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err }, \"list_folders failed\");\n this.send({ type: \"folders_list_result\", requestId: msg.requestId, folders: [] });\n });\n return true;\n }\n\n if (msg.type === \"list_history_sessions\") {\n log.info({ workDir: msg.workDir }, \"list_history_sessions\");\n handleListHistorySessions(msg.workDir)\n .then((result) => {\n this.send({ type: \"history_sessions_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, workDir: msg.workDir }, \"list_history_sessions failed\");\n this.send({\n type: \"history_sessions_result\",\n requestId: msg.requestId,\n workDir: msg.workDir,\n sessions: [],\n });\n });\n return true;\n }\n\n if (msg.type === \"load_session_history\") {\n log.info(\n { workDir: msg.workDir, claudeSessionId: msg.claudeSessionId, before: msg.before, limit: msg.limit },\n \"load_session_history\",\n );\n handleLoadSessionHistory(msg.workDir, msg.claudeSessionId, { before: msg.before, limit: msg.limit })\n .then((result) => {\n this.send({ type: \"session_history_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, workDir: msg.workDir }, \"load_session_history failed\");\n this.send({ type: \"session_history_result\", requestId: msg.requestId, messages: [], oldestSeq: 0, hasMore: false });\n });\n return true;\n }\n\n // ── Swarm handling (requires swarmCoordinator) ──────────────────────\n\n if (msg.type === \"list_roles\") {\n log.info(\"list_roles\");\n const roleNames = listRoles();\n const roles = roleNames.map((name) => {\n try {\n const def = loadRole(name);\n return {\n name: def.name,\n displayName: def.displayName || def.description || def.name,\n description: def.description || \"\",\n capabilities: def.capabilities || [],\n type: def.type,\n color: def.color,\n promptBody: def.promptBody || \"\",\n };\n } catch {\n return { name, displayName: name, description: \"\", capabilities: [], promptBody: \"\" };\n }\n });\n this.send({\n type: \"roles_list_result\",\n sessionId: (msg as any).sessionId,\n roles,\n } as any);\n return true;\n }\n\n if (msg.type === \"list_templates\") {\n log.info(\"list_templates\");\n try {\n const names = listTemplates();\n const templates = names.map((name) => {\n const tpl = loadTemplate(name);\n return {\n name: tpl.name,\n displayName: tpl.displayName,\n description: tpl.description,\n icon: tpl.icon,\n roles: tpl.roles,\n };\n });\n this.send({\n type: \"templates_list_result\",\n sessionId: (msg as any).sessionId,\n templates,\n } as any);\n } catch (err) {\n log.error({ err }, \"list_templates failed\");\n this.send({\n type: \"templates_list_result\",\n sessionId: (msg as any).sessionId,\n templates: [],\n } as any);\n }\n return true;\n }\n\n // ── Generic request: dispatch to registered namespace handlers ──\n if (msg.type === \"generic.request\") {\n const handler = this.namespaceHandlers.get(msg.namespace);\n if (handler) {\n log.info({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request received\");\n handler(msg)\n .then((result) => {\n log.info({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request handled OK\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: result,\n requestId: msg.requestId,\n });\n })\n .catch((err) => {\n log.error({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId, err }, \"generic.request handler error\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: {},\n requestId: msg.requestId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n return true;\n }\n log.warn({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request unknown namespace\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: {},\n requestId: msg.requestId,\n error: `Unknown namespace: ${msg.namespace}`,\n });\n return true;\n }\n\n // ── Swarm control: CLI-driven swarm_spawn / swarm_resume ────────\n if ((msg.type === \"swarm_spawn\" || msg.type === \"swarm_resume\") && this.swarmCoordinator) {\n const coord = this.swarmCoordinator;\n handleSwarmControl(coord, msg as SwarmControlMsg, {\n defaultWorkDir: process.cwd(),\n home: process.env.CLAWNET_HOME,\n })\n .then((result) => {\n log.info({ type: msg.type, ok: result.ok, swarmId: result.swarmId, error: result.error }, \"swarm control handled\");\n })\n .catch((err) => {\n log.error({ err, type: msg.type }, \"swarm control crashed\");\n });\n return true;\n }\n\n if (msg.type === \"swarm.execute\" && this.swarmCoordinator) {\n const { sessionId, content, workDir, targetInstance, crewConfig } = msg;\n\n if (this.swarmCoordinator.hasSwarm(sessionId)) {\n // Existing swarm — forward user message\n log.info({ sessionId, targetInstance }, \"swarm.execute: forwarding to existing swarm\");\n this.swarmCoordinator.handleUserMessage(sessionId, content, targetInstance).catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n } else if (this.finishedSwarms.has(sessionId)) {\n // Swarm completed/failed — recreate to continue if config available\n if (crewConfig?.templateName || crewConfig?.roles) {\n this.finishedSwarms.delete(sessionId);\n const templateName = crewConfig.templateName;\n const roles = crewConfig.roles;\n log.info({ sessionId, templateName, rolesCount: roles?.length }, \"swarm.execute: continuing finished swarm\");\n this.swarmCoordinator.create(sessionId, { workDir, templateName, roles, task: content, isContinuation: true }).catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n } else {\n log.info({ sessionId }, \"swarm.execute ignored: swarm finished, no config to recreate\");\n this.send({\n type: \"session.error\",\n sessionId,\n error: \"蜂群任务已完成且无法恢复配置。请创建新的蜂群任务。\",\n });\n }\n } else if (crewConfig?.templateName || crewConfig?.roles) {\n // Create new swarm: template-based or direct roles\n const templateName = crewConfig.templateName;\n const roles = crewConfig.roles;\n log.info({ sessionId, templateName, rolesCount: roles?.length }, \"swarm.execute: creating new swarm\");\n this.swarmCoordinator.create(sessionId, { workDir, templateName, roles, task: content }).catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n } else {\n // No swarm and no crewConfig — shouldn't happen normally\n log.info({ sessionId }, \"swarm.execute ignored: swarm not found, no config\");\n this.send({\n type: \"session.error\",\n sessionId,\n error: \"蜂群任务已完成,无法继续操作。请创建新的蜂群任务。\",\n });\n }\n return true;\n }\n\n // ── Session management (requires sessionManager) ─────────────────\n\n if (!this.sessionManager) return false;\n\n if (msg.type === \"abort_execution\") {\n const { sessionId } = msg;\n log.info({ sessionId }, \"abort_execution\");\n if (this.sessionManager?.hasSession(sessionId)) {\n this.sessionManager.abortSession(sessionId).then(() => {\n this.send({ type: \"execution_aborted\", sessionId } as any);\n }).catch(() => {\n this.send({ type: \"execution_aborted\", sessionId } as any);\n });\n } else {\n // No active session — just acknowledge\n this.send({ type: \"execution_aborted\", sessionId } as any);\n }\n return true;\n }\n\n // claude.execute — auto-create session if needed, then send input.\n // Three branches:\n // 1. healthy reuse — process alive, write directly\n // 2. unhealthy + db has claudeSessionId — abort residue, spawn --resume\n // and notify hub via session.died so it can flush stale turnBuffer\n // 3. brand new — original create path\n if (msg.type === \"claude.execute\") {\n const { sessionId, content, workDir, claudeSessionId, useBrainCore } = msg;\n const sm = this.sessionManager;\n\n const spawnAndSend = (\n resumeId: string | undefined,\n label: string,\n maxOutputTokens: number | undefined,\n ) => {\n log.info(\n { sessionId, claudeSessionId: resumeId, workDir, label, maxOutputTokens },\n \"claude.execute: spawning\",\n );\n log.debug({ sessionId, ...previewFields(content) }, \"claude.execute: input\");\n sm.createSession({\n sessionId,\n workDir,\n resumeId,\n useBrainCore,\n roleId: \"role-__assistant__\",\n maxOutputTokens,\n })\n .then(() => {\n sm.sendInput(sessionId, content);\n })\n .catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n };\n\n if (sm.isHealthy(sessionId)) {\n log.info({ sessionId }, \"claude.execute: reusing healthy session\");\n log.debug({ sessionId, ...previewFields(content) }, \"claude.execute: input\");\n sm.sendInput(sessionId, content);\n } else if (sm.hasSession(sessionId) && claudeSessionId) {\n // Snapshot the ladder hint BEFORE abort — abortSession deletes meta\n // and the recommendation goes with it; without this read the respawn\n // would silently revert to ladder index 0.\n const recommendedMax = sm.getRecommendedMaxOutputTokens(sessionId);\n // Map entry exists but process is dead (exit handler may not have\n // fired yet, or stdin closed). Tear down and respawn via --resume.\n // Notify hub first so it can flush the orphan turnBuffer before the\n // new session's first chunk arrives.\n log.warn({ sessionId, claudeSessionId }, \"claude.execute: session unhealthy, recreating with --resume\");\n this.send({\n type: \"session.died\",\n sessionId,\n reason: \"unhealthy_before_input\",\n } satisfies AgentSessionDied);\n sm.abortSession(sessionId)\n .catch((err) => {\n // Don't bail — log and continue; createSession below will surface\n // any real failure. Silent swallow used to mask \"two children racing\n // on the same sessionId\" bugs.\n log.warn({ sessionId, err: err instanceof Error ? err.message : String(err) }, \"abortSession failed during unhealthy fallback, proceeding to respawn\");\n })\n .then(() => spawnAndSend(claudeSessionId, \"unhealthy_fallback_resume\", recommendedMax));\n } else if (claudeSessionId) {\n // No live process but db has claudeSessionId → resume from disk.\n // recoveredLadderIndex (populated by recoverFromCheckpoint) is read\n // *inside* createSession, so a brand-new SessionManager call here\n // automatically inherits any escalated ladder from the previous run.\n spawnAndSend(claudeSessionId, \"fresh_resume\", sm.getRecommendedMaxOutputTokens(sessionId));\n } else {\n spawnAndSend(undefined, \"brand_new\", undefined);\n }\n return true;\n }\n\n // session.force_restart — hub detected stuck session and asked agent to\n // tear it down. Agent aborts and replies with session.died so hub can\n // flush turnBuffer; the next claude.execute will go through the unhealthy\n // fallback above and respawn via --resume.\n if (msg.type === \"session.force_restart\") {\n const { sessionId, reason } = msg;\n log.warn({ sessionId, reason }, \"session.force_restart received\");\n const sm = this.sessionManager;\n const reply: AgentSessionDied = {\n type: \"session.died\",\n sessionId,\n reason: reason ?? \"force_restart\",\n };\n if (sm.hasSession(sessionId)) {\n sm.abortSession(sessionId)\n .catch((err) => {\n log.warn({ sessionId, err: err instanceof Error ? err.message : String(err) }, \"abortSession failed during force_restart\");\n })\n .finally(() => {\n this.send(reply);\n });\n } else {\n this.send(reply);\n }\n return true;\n }\n\n if (msg.type === \"session.create\") {\n log.info({ sessionId: msg.sessionId, roleId: \"role-__assistant__\" }, \"session.create with memory injection\");\n this.sessionManager\n .createSession({\n sessionId: msg.sessionId,\n workDir: msg.workDir,\n resumeId: msg.resumeId,\n roleId: \"role-__assistant__\",\n })\n .then((claudeSessionId) => {\n this.send({\n type: \"session.created\",\n sessionId: msg.sessionId,\n claudeSessionId,\n });\n })\n .catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId: msg.sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n return true;\n }\n\n if (msg.type === \"session.close\") {\n log.info({ sessionId: msg.sessionId }, \"session.close\");\n this.sessionManager.closeSession(msg.sessionId).catch(() => {});\n return true;\n }\n\n if (msg.type === \"claude.input\") {\n log.debug(\n { sessionId: msg.sessionId, ...previewFields(msg.content) },\n \"claude.input\",\n );\n this.sessionManager.sendInput(msg.sessionId, msg.content);\n return true;\n }\n\n return false;\n }\n\n // ── Internal helpers ─────────────────────────────────────────────\n\n private tryRecoverSwarms(): void {\n if (!this.swarmCoordinator) return;\n try {\n const allIds = listRecoverableSwarmIds();\n const snapshots = listRecoverableSwarms();\n const recoverableIds = new Set(snapshots.map((s) => s.id));\n\n // Clean up expired/completed/failed snapshots\n for (const { workDir, swarmId } of allIds) {\n if (!recoverableIds.has(swarmId)) {\n deleteSwarmSnapshot(workDir, swarmId);\n log.info({ swarmId }, \"cleaned up non-recoverable swarm snapshot\");\n }\n }\n\n for (const snap of snapshots) {\n log.info({ swarmId: snap.id }, \"recovering swarm\");\n recoverSwarm(this.swarmCoordinator, snap).catch((err) => {\n log.error({ err, swarmId: snap.id }, \"failed to recover swarm\");\n });\n }\n } catch (err) {\n log.error({ err }, \"swarm recovery failed\");\n }\n }\n\n private reportLiveSessions(): void {\n if (!this.sessionManager) return;\n const ids = this.sessionManager.getActiveSessionIds();\n if (ids.length === 0) return;\n log.info({ count: ids.length }, \"reporting live sessions to hub after reconnect\");\n for (const sessionId of ids) {\n this.send({\n type: \"session.state\",\n sessionId,\n processState: \"ready\",\n });\n }\n }\n\n private sendRaw(data: unknown): boolean {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return false;\n this.ws.send(JSON.stringify(data));\n return true;\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n this.send({ type: \"heartbeat\", ts: Date.now() });\n }, this.heartbeatInterval);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.destroyed) return;\n log.warn({ delayMs: this.reconnectDelay }, \"reconnecting to hub...\");\n this.reconnectTimer = setTimeout(() => {\n this.connect();\n }, this.reconnectDelay);\n this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);\n }\n\n private cleanup(): void {\n this.cleanupConnection();\n this.sessionManager?.closeAll().catch(() => {});\n }\n\n private cleanupConnection(): void {\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.removeAllListeners();\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n this.ws = null;\n }\n }\n}\n","import { readdir, stat, readFile } from \"node:fs/promises\";\nimport { existsSync, readdirSync, statSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst SKIP_DIRS = new Set([\".git\", \"node_modules\", \"__pycache__\", \".next\", \".nuxt\", \".cache\"]);\n\n// ── fs.list_dir ─────────────────────────────────────────────────────\n\nexport async function handleListDir(\n path: string,\n): Promise<{ path: string; entries: Array<{ name: string; type: \"directory\" | \"file\" }> }> {\n const target = path || homedir();\n const dirents = await readdir(target, { withFileTypes: true });\n\n const entries = dirents\n .filter((d) => !(d.isDirectory() && SKIP_DIRS.has(d.name)))\n .map((d) => ({\n name: d.name,\n type: (d.isDirectory() ? \"directory\" : \"file\") as \"directory\" | \"file\",\n }))\n .sort((a, b) => {\n if (a.type !== b.type) return a.type === \"directory\" ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n\n return { path: target, entries };\n}\n\n// ── list_folders (scan ~/.claude/projects/) ──────────────────────────\n\nfunction getClaudeProjectsDir(): string {\n return join(homedir(), \".claude\", \"projects\");\n}\n\nfunction pathToProjectFolder(workDir: string): string {\n return workDir.replace(/:/g, \"-\").replace(/[/\\\\]/g, \"-\");\n}\n\nfunction extractWorkDirFromSessionFile(filePath: string): string | null {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n for (const line of lines.slice(0, 5)) {\n try {\n const data = JSON.parse(line);\n if (data.cwd) return data.cwd.replace(/\\\\/g, \"/\");\n } catch {}\n }\n } catch {}\n return null;\n}\n\nfunction getWorkDirFromProjectFolder(folderPath: string): string | null {\n try {\n const files = readdirSync(folderPath);\n for (const file of files) {\n if (file.endsWith(\".jsonl\")) {\n const workDir = extractWorkDirFromSessionFile(join(folderPath, file));\n if (workDir) return workDir;\n }\n }\n } catch {}\n // No source of truth available. Refuse to fabricate — the encoder is lossy\n // (`/` and `-` both map to `-`), so any reverse decode would be a guess.\n return null;\n}\n\nexport async function handleListFolders(): Promise<{\n folders: Array<{ path: string; sessionCount: number; lastModified?: number }>;\n}> {\n const projectsDir = getClaudeProjectsDir();\n const folders: Array<{ path: string; sessionCount: number; lastModified?: number }> = [];\n\n if (!existsSync(projectsDir)) return { folders };\n\n const entries = readdirSync(projectsDir);\n for (const entry of entries) {\n const entryPath = join(projectsDir, entry);\n let entryStat;\n try {\n entryStat = statSync(entryPath);\n } catch {\n continue;\n }\n if (!entryStat.isDirectory()) continue;\n\n // Skip crew role directories\n if (entry.includes(\"--crew-roles-\")) continue;\n\n const originalPath = getWorkDirFromProjectFolder(entryPath);\n if (originalPath === null) continue;\n\n let sessionCount = 0;\n let lastModified = entryStat.mtime.getTime();\n\n try {\n const files = readdirSync(entryPath);\n for (const file of files) {\n if (file.endsWith(\".jsonl\")) {\n sessionCount++;\n try {\n const fileStats = statSync(join(entryPath, file));\n if (fileStats.mtime.getTime() > lastModified) {\n lastModified = fileStats.mtime.getTime();\n }\n } catch {}\n }\n }\n } catch {}\n\n folders.push({ path: originalPath, sessionCount, lastModified });\n }\n\n folders.sort((a, b) => (b.lastModified ?? 0) - (a.lastModified ?? 0));\n return { folders };\n}\n\n// ── list_history_sessions ───────────────────────────────────────────\n\nexport async function handleListHistorySessions(workDir: string): Promise<{\n workDir: string;\n sessions: Array<{ sessionId: string; title: string; workDir?: string; lastModified?: number }>;\n}> {\n const projectsDir = getClaudeProjectsDir();\n const projectFolder = pathToProjectFolder(workDir);\n const projectPath = join(projectsDir, projectFolder);\n\n if (!existsSync(projectPath)) {\n return { workDir, sessions: [] };\n }\n\n const sessions: Array<{ sessionId: string; title: string; workDir?: string; lastModified?: number }> = [];\n const files = readdirSync(projectPath);\n\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const sessionId = file.replace(\".jsonl\", \"\");\n const filePath = join(projectPath, file);\n let fileStats;\n try {\n fileStats = statSync(filePath);\n } catch {\n continue;\n }\n\n let title = \"\";\n let hasUserMessage = false;\n let customTitle = \"\";\n let jsonlSummary = \"\";\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n if (!hasUserMessage && data.type === \"user\" && data.message?.content) {\n const text =\n typeof data.message.content === \"string\"\n ? data.message.content\n : data.message.content[0]?.text || \"\";\n if (text.trim()) {\n title = text.substring(0, 100);\n hasUserMessage = true;\n }\n }\n if (data.type === \"custom-title\" && data.customTitle) {\n customTitle = data.customTitle;\n }\n if (data.type === \"summary\" && data.summary) {\n jsonlSummary = data.summary;\n }\n } catch {}\n }\n } catch {}\n\n if (hasUserMessage) {\n sessions.push({\n sessionId,\n title: customTitle || jsonlSummary || title || sessionId.slice(0, 8),\n workDir,\n lastModified: fileStats.mtime.getTime(),\n });\n }\n }\n\n sessions.sort((a, b) => (b.lastModified ?? 0) - (a.lastModified ?? 0));\n return { workDir, sessions };\n}\n\n// ── load_session_history ────────────────────────────────────────────\n\ninterface HistoryMessage {\n role: \"user\" | \"assistant\";\n content: string;\n toolCalls?: Array<{ name: string; input?: string; output?: string; status: string }>;\n thinking?: string;\n}\n\n/**\n * Load message history from a Claude jsonl file.\n *\n * Pagination contract:\n * - `seq` is the index into the post-filter messages array (NOT raw jsonl\n * line number). Filtering is a pure function of the file contents, so\n * a given (file, fs-handler version) pair always yields the same\n * mapping. jsonl is append-only — new assistant turns only ever\n * extend the array, so a seq captured by the browser remains valid.\n * - `before`: return messages with seq < before. Omit/0 = newest tail.\n * - `limit`: max messages returned. Default 50.\n * - `oldestSeq`: seq of the FIRST message in the returned slice. The\n * browser passes this as `before` on the next \"load earlier\" request.\n * - `hasMore`: true iff oldestSeq > 0 (older messages exist on disk).\n *\n * Caveat: changes to the filter rules below (added/removed block types)\n * invalidate any cached seq across all clients. Treat as a protocol-level\n * breaking change — bump shared protocol version when modifying.\n */\nexport async function handleLoadSessionHistory(\n workDir: string,\n claudeSessionId: string,\n opts?: { before?: number; limit?: number },\n): Promise<{ messages: HistoryMessage[]; oldestSeq: number; hasMore: boolean }> {\n const projectsDir = getClaudeProjectsDir();\n const projectFolder = pathToProjectFolder(workDir);\n const filePath = join(projectsDir, projectFolder, `${claudeSessionId}.jsonl`);\n\n if (!existsSync(filePath)) {\n return { messages: [], oldestSeq: 0, hasMore: false };\n }\n\n const messages: HistoryMessage[] = [];\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n\n if (data.type === \"user\" && data.message?.content) {\n const blocks = Array.isArray(data.message.content)\n ? data.message.content\n : [{ type: \"text\", text: String(data.message.content) }];\n\n // Extract user text (only text blocks, skip tool_result etc.)\n const textParts: string[] = [];\n for (const block of blocks) {\n if (block.type === \"text\" && block.text?.trim()) {\n textParts.push(block.text);\n }\n }\n if (textParts.length > 0) {\n messages.push({ role: \"user\", content: textParts.join(\"\\n\") });\n }\n\n // Attach tool_result outputs to the last assistant's toolCalls\n const lastAssistant = messages.length > 0\n ? [...messages].reverse().find((m) => m.role === \"assistant\" && m.toolCalls?.length)\n : undefined;\n if (lastAssistant?.toolCalls) {\n for (const block of blocks) {\n if (block.type === \"tool_result\") {\n // Match by tool_use_id or just fill the next pending one\n const pending = lastAssistant.toolCalls.find((tc) => !tc.output);\n if (pending) {\n pending.output = typeof block.content === \"string\"\n ? block.content\n : Array.isArray(block.content)\n ? block.content.map((c: any) => c.text ?? \"\").join(\"\")\n : JSON.stringify(block.content);\n pending.status = block.is_error ? \"error\" : \"done\";\n }\n }\n }\n }\n }\n\n if (data.type === \"assistant\" && data.message?.content) {\n let text = \"\";\n const toolCalls: HistoryMessage[\"toolCalls\"] = [];\n let thinking = \"\";\n\n for (const block of data.message.content) {\n if (block.type === \"text\") {\n text += block.text;\n } else if (block.type === \"tool_use\") {\n toolCalls.push({\n name: block.name,\n input: typeof block.input === \"string\" ? block.input : JSON.stringify(block.input, null, 2),\n status: \"done\",\n });\n } else if (block.type === \"thinking\") {\n thinking += block.thinking ?? \"\";\n }\n }\n\n messages.push({\n role: \"assistant\",\n content: text,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n thinking: thinking || undefined,\n });\n }\n } catch {}\n }\n } catch {}\n\n const limit = Math.max(1, Math.min(opts?.limit ?? 50, 200));\n // `before` semantics: return messages with seq < before. When omitted,\n // tail-load (newest `limit`).\n const upper = opts?.before === undefined || opts.before <= 0 || opts.before > messages.length\n ? messages.length\n : opts.before;\n const lower = Math.max(0, upper - limit);\n const slice = messages.slice(lower, upper);\n return {\n messages: slice,\n oldestSeq: lower,\n hasMore: lower > 0,\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { createLogger } from \"@mclawnet/logger\";\nimport { InboxStore } from \"@mclawnet/swarm\";\nimport type { SwarmCoordinator } from \"@mclawnet/swarm\";\n\nconst log = createLogger({ module: \"agent/swarm-control\" });\n\nexport interface SwarmSpawnMsg {\n type: \"swarm_spawn\";\n teamName: string;\n msg?: string;\n workDir?: string;\n /** Optional caller-provided id; falls back to randomUUID when absent. */\n swarmId?: string;\n}\n\nexport interface SwarmResumeMsg {\n type: \"swarm_resume\";\n swarmId: string;\n}\n\nexport type SwarmControlMsg = SwarmSpawnMsg | SwarmResumeMsg;\n\nexport interface DispatchOptions {\n /** Fallback workDir when CLI omits one. */\n defaultWorkDir: string;\n /**\n * Optional override for the user-home root (no `.clawnet` suffix). Threaded\n * to InboxStore so process-launched inbox seeds land in the same tree the\n * coordinator watches. When omitted, falls back to `CLAWNET_HOME` env var\n * then `homedir()` inside InboxStore.\n */\n home?: string;\n}\n\nexport interface DispatchResult {\n ok: boolean;\n swarmId?: string;\n error?: string;\n}\n\n/**\n * Coordinator surface used by this dispatcher. The real SwarmCoordinator\n * implements all of these (getSwarm is a thin lookup over its private map;\n * findQueenInstance identifies the queen by `definition.type === \"queen\"`\n * so custom queen roles with non-default names are also recognised).\n */\ntype CoordLike = Pick<SwarmCoordinator, \"create\" | \"recover\" | \"inboxRelay\"> & {\n getSwarm?: (id: string) => { workDir?: string } | undefined;\n findQueenInstance?: (id: string) => { instanceId: string } | undefined;\n};\n\nexport async function handleSwarmControl(\n coord: CoordLike,\n msg: SwarmControlMsg,\n opts: DispatchOptions,\n): Promise<DispatchResult> {\n if (!msg || (msg.type !== \"swarm_spawn\" && msg.type !== \"swarm_resume\")) {\n return { ok: false, error: \"unknown control type\" };\n }\n\n if (msg.type === \"swarm_resume\") {\n try {\n await coord.recover(msg.swarmId);\n log.info({ swarmId: msg.swarmId }, \"swarm_resume: recovered\");\n return { ok: true, swarmId: msg.swarmId };\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n log.error({ err, swarmId: msg.swarmId }, \"swarm_resume failed\");\n return { ok: false, error };\n }\n }\n\n // swarm_spawn\n const workDir = msg.workDir ?? opts.defaultWorkDir;\n const swarmId = msg.swarmId ?? randomUUID();\n try {\n await coord.create(swarmId, { workDir, templateName: msg.teamName });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n log.error({ err, teamName: msg.teamName }, \"swarm_spawn: create failed\");\n return { ok: false, error };\n }\n\n if (msg.msg && msg.msg.length > 0) {\n const swarm = coord.getSwarm?.(swarmId);\n const queen = coord.findQueenInstance?.(swarmId);\n if (swarm && swarm.workDir && queen) {\n try {\n const store = new InboxStore(swarm.workDir, swarmId, opts.home);\n await store.append(queen.instanceId, {\n id: randomUUID(),\n from: \"user\",\n type: \"user\",\n data: msg.msg,\n timestamp: Date.now(),\n delivered: false,\n });\n await coord.inboxRelay.deliver(swarmId, queen.instanceId);\n } catch (err) {\n log.warn({ err, swarmId }, \"swarm_spawn: inbox seed failed (non-fatal)\");\n }\n } else {\n log.warn({ swarmId, hasSwarm: !!swarm, hasQueen: !!queen }, \"swarm_spawn: queen instance not found, skipping inbox seed\");\n }\n }\n\n log.info({ swarmId, teamName: msg.teamName }, \"swarm_spawn: created\");\n return { ok: true, swarmId };\n}\n","import { spawn, execSync } from \"node:child_process\";\nimport {\n JsonScheduleRepository,\n SchedulerService,\n createOneShotExecutor,\n createSwarmExecutor,\n MAX_STDOUT_BYTES,\n MAX_STDERR_BYTES,\n type Schedule,\n type ScheduleRun,\n type ScheduleExecutor,\n type SpawnFn,\n type SwarmStarter,\n type TypedEventEmitter,\n type SchedulerEvents,\n} from \"@mclawnet/scheduler\";\nimport { createLogger } from \"@mclawnet/logger\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { SwarmCoordinator } from \"@mclawnet/swarm\";\n\nconst log = createLogger({ module: \"agent/schedule-runtime\" });\n\n// ── In-memory stdout/stderr caps for the spawned `claude` child process. ──\n//\n// Disk-side caps (`MAX_STDOUT_BYTES` / `MAX_STDERR_BYTES`) live in\n// `@mclawnet/scheduler` and apply at write time. The runtime additionally\n// caps the in-memory accumulator so a noisy long-running task can't balloon\n// the agent's heap before the executor returns.\n//\n// Stdout has a generous 1MB budget because the `claude --output-format\n// stream-json` channel needs enough room to emit a long assistant message\n// payload. Stderr typically only carries warnings, so a 256KB budget is\n// plenty (and matches the on-disk `MAX_STDOUT_BYTES`/`MAX_STDERR_BYTES`\n// proportions roughly).\nconst SPAWN_STDOUT_CAP_BYTES = 1024 * 1024; // 1 MiB\nconst SPAWN_STDERR_CAP_BYTES = 256 * 1024; // 256 KiB\n\n// Touch the imports so tree-shakers / lint don't strip them — they document\n// the disk-side caps the executor enforces downstream.\nvoid MAX_STDOUT_BYTES;\nvoid MAX_STDERR_BYTES;\n\n/**\n * Minimal hub send surface; mirrors HubConnection.send() but kept structural so\n * the runtime is unit-testable without spinning up a real WebSocket.\n */\nexport interface ScheduleHubSink {\n send(msg: unknown): boolean;\n}\n\n/**\n * Optional repo surface used by ScheduleRuntime — kept structural so tests can\n * inject a vi.fn-backed fake without subclassing JsonScheduleRepository.\n */\nexport interface ScheduleRepoLike {\n create: JsonScheduleRepository[\"create\"];\n update: JsonScheduleRepository[\"update\"];\n delete: JsonScheduleRepository[\"delete\"];\n getById: JsonScheduleRepository[\"getById\"];\n listAll: JsonScheduleRepository[\"listAll\"];\n listByCwd: JsonScheduleRepository[\"listByCwd\"];\n listRuns: JsonScheduleRepository[\"listRuns\"];\n readRunLogs: JsonScheduleRepository[\"readRunLogs\"];\n}\n\n/**\n * Optional scheduler surface — same rationale as ScheduleRepoLike. The real\n * SchedulerService satisfies this implicitly.\n */\nexport interface SchedulerLike {\n start(): Promise<void>;\n stop(): Promise<void>;\n register(s: Schedule): void;\n unregister(id: string): void;\n triggerNow(id: string): Promise<ScheduleRun>;\n cancel(runId: string): boolean;\n events: TypedEventEmitter<SchedulerEvents>;\n}\n\nexport interface ScheduleRuntimeOptions {\n hub: ScheduleHubSink;\n /** Real swarm bootstrap deps; only needed when wiring real executors. */\n sessionManager?: SessionManager;\n swarmCoordinator?: SwarmCoordinator;\n /** DI overrides for tests. */\n repo?: ScheduleRepoLike;\n scheduler?: SchedulerLike;\n executors?: { oneshot?: ScheduleExecutor; swarm?: ScheduleExecutor };\n}\n\n/**\n * Bridges Hub WS schedule:* messages to a local SchedulerService + repository,\n * and lifts SchedulerService events back to the Hub. Construction is fully\n * dependency-injected so unit tests can run without the real cron/fs layers.\n *\n * NOTE (Phase 7+): the hub-side broadcast handler currently routes only the\n * three push events ({@link Schedule}/{@link ScheduleRun} / `schedule:removed`).\n * The `:result` and `:error` envelopes sent here are correct on the wire but\n * will be dropped at the hub until PR-B teaches `schedule-broadcast.ts` to\n * route them back to the originating user. See plan Task 6.x notes.\n */\nexport class ScheduleRuntime {\n private readonly hub: ScheduleHubSink;\n private readonly repo: ScheduleRepoLike;\n private readonly scheduler: SchedulerLike;\n private started = false;\n // Tracks fire-and-forget handler promises so stop() can drain them before\n // detaching listeners and stopping the scheduler. Without this, an in-flight\n // handler could resolve after stop() returns and emit a phantom send().\n private readonly inflight = new Set<Promise<void>>();\n\n // Bound handlers retained so stop() can detach them cleanly.\n private readonly onChange: (s: Schedule) => void;\n private readonly onRun: (r: ScheduleRun) => void;\n\n constructor(opts: ScheduleRuntimeOptions) {\n this.hub = opts.hub;\n this.repo = opts.repo ?? new JsonScheduleRepository();\n\n const oneshotExec =\n opts.executors?.oneshot ?? createOneShotExecutor(makeRealOneShotSpawn());\n const swarmExec =\n opts.executors?.swarm ??\n createSwarmExecutor(\n makeRealSwarmStarter({\n sessionManager: opts.sessionManager,\n swarmCoordinator: opts.swarmCoordinator,\n }),\n );\n\n this.scheduler =\n opts.scheduler ??\n new SchedulerService(this.repo as JsonScheduleRepository, {\n oneshot: oneshotExec,\n swarm: swarmExec,\n });\n\n this.onChange = (s) => {\n this.safeSend({ type: \"schedule:changed\", schedule: s });\n };\n this.onRun = (r) => {\n this.safeSend({ type: \"schedule:run\", run: r });\n };\n }\n\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n this.scheduler.events.on(\"change\", this.onChange);\n this.scheduler.events.on(\"run\", this.onRun);\n await this.scheduler.start();\n }\n\n async stop(): Promise<void> {\n if (!this.started) return;\n // Flip the flag first so any handler that wakes up mid-drain bails out of\n // its `safeSend()` calls. This is the post-stop-send guard referenced in\n // the I-3 fix.\n this.started = false;\n // Snapshot the in-flight set so a handler that spawns another handler\n // during the drain doesn't make us loop forever (we accept that the spawn\n // itself is benign — no-op once `started` is false).\n const pending = Array.from(this.inflight);\n if (pending.length > 0) {\n await Promise.allSettled(pending);\n }\n this.scheduler.events.off(\"change\", this.onChange);\n this.scheduler.events.off(\"run\", this.onRun);\n await this.scheduler.stop();\n }\n\n /**\n * Wraps `hub.send` with a started-flag guard so handlers that race against\n * `stop()` can't emit phantom messages after the runtime has shut down.\n */\n private safeSend(msg: unknown): void {\n if (!this.started) return;\n this.hub.send(msg);\n }\n\n /**\n * Records `p` in the in-flight set so `stop()` can wait for it, and removes\n * it on settle. Returns the same promise so callers can `void track(...)`.\n */\n private track(p: Promise<void>): Promise<void> {\n this.inflight.add(p);\n return p.finally(() => {\n this.inflight.delete(p);\n });\n }\n\n /**\n * Entry point for any `schedule:*` message arriving from the Hub. Always\n * returns synchronously; per-branch async work runs on its own microtask\n * chain and reports results back to the hub.\n */\n handleHubMessage(msg: unknown): void {\n if (!isMsg(msg)) return;\n const requestId = typeof msg.requestId === \"string\" ? msg.requestId : undefined;\n const m = msg as Record<string, unknown>;\n\n switch (msg.type) {\n case \"schedule:create\":\n void this.track(this.handleCreate(m, requestId));\n return;\n case \"schedule:update\":\n void this.track(this.handleUpdate(m, requestId));\n return;\n case \"schedule:delete\":\n void this.track(this.handleDelete(m, requestId));\n return;\n case \"schedule:pause\":\n void this.track(this.handlePauseResume(m, requestId, \"paused\"));\n return;\n case \"schedule:resume\":\n void this.track(this.handlePauseResume(m, requestId, \"active\"));\n return;\n case \"schedule:trigger\":\n void this.track(this.handleTrigger(m, requestId));\n return;\n case \"schedule:list\":\n void this.track(this.handleList(m, requestId));\n return;\n case \"schedule:runs\":\n void this.track(this.handleRuns(m, requestId));\n return;\n case \"schedule:log\":\n void this.track(this.handleLog(m, requestId));\n return;\n default:\n // Unknown schedule:* type. If the caller used a requestId they're\n // waiting for a reply — answer with INTERNAL/unknown-type rather than\n // letting them time out. Push-style messages (no requestId) just log.\n log.warn({ type: msg.type }, \"schedule-runtime: unknown message type\");\n if (requestId !== undefined) {\n this.safeSend({\n type: \"schedule:error\",\n requestId,\n error: {\n code: \"INTERNAL\",\n message: `unknown schedule message type: ${msg.type}`,\n },\n });\n }\n }\n }\n\n // ── Per-branch handlers ─────────────────────────────────────────────\n\n private async handleCreate(\n msg: Record<string, unknown>,\n requestId: string | undefined,\n ): Promise<void> {\n try {\n // Trust the wire shape — repo.create() validates internally and the\n // scheduler protocol is the contract. Avoid a redundant zod step.\n const created = await this.repo.create(\n msg.input as Parameters<JsonScheduleRepository[\"create\"]>[0],\n );\n this.scheduler.register(created);\n this.safeSend({\n type: \"schedule:create:result\",\n requestId,\n schedule: created,\n });\n this.safeSend({ type: \"schedule:changed\", schedule: created });\n } catch (err) {\n this.sendError(requestId, err);\n }\n }\n\n private async handleUpdate(\n msg: Record<string, unknown>,\n requestId: string | undefined,\n ): Promise<void> {\n try {\n const id = String(msg.id);\n const updated = await this.repo.update(\n id,\n msg.patch as Parameters<JsonScheduleRepository[\"update\"]>[1],\n );\n if (updated.status === \"active\") {\n this.scheduler.register(updated);\n } else {\n this.scheduler.unregister(id);\n }\n this.safeSend({\n type: \"schedule:update:result\",\n requestId,\n schedule: updated,\n });\n this.safeSend({ type: \"schedule:changed\", schedule: updated });\n } catch (err) {\n this.sendError(requestId, err);\n }\n }\n\n private async handleDelete(\n msg: Record<string, unknown>,\n requestId: string | undefined,\n ): Promise<void> {\n const id = String(msg.id);\n try {\n this.scheduler.unregister(id);\n await this.repo.delete(id);\n this.safeSend({ type: \"schedule:delete:result\", requestId, id });\n this.safeSend({ type: \"schedule:removed\", id });\n } catch (err) {\n this.sendError(requestId, err);\n }\n }\n\n private async handlePauseResume(\n msg: Record<string, unknown>,\n requestId: string | undefined,\n nextStatus: \"active\" | \"paused\",\n ): Promise<void> {\n const id = String(msg.id);\n try {\n const updated = await this.repo.update(id, { status: nextStatus });\n if (nextStatus === \"active\") {\n this.scheduler.register(updated);\n } else {\n this.scheduler.unregister(id);\n }\n const resultType =\n nextStatus === \"paused\"\n ? \"schedule:pause:result\"\n : \"schedule:resume:result\";\n this.safeSend({ type: resultType, requestId, schedule: updated });\n this.safeSend({ type: \"schedule:changed\", schedule: updated });\n } catch (err) {\n this.sendError(requestId, err);\n }\n }\n\n private async handleTrigger(\n msg: Record<string, unknown>,\n requestId: string | undefined,\n ): Promise<void> {\n const id = String(msg.id);\n try {\n await this.scheduler.triggerNow(id);\n // The scheduler emits the actual run via the `run` event (relayed above);\n // the trigger:result echo here is just an ack with the latest snapshot.\n const snap = await this.repo.getById(id);\n this.safeSend({\n type: \"schedule:trigger:result\",\n requestId,\n schedule: snap,\n });\n } catch (err) {\n this.sendError(requestId, err);\n }\n }\n\n private async handleList(\n msg: Record<string, unknown>,\n requestId: string | undefined,\n ): Promise<void> {\n try {\n const all = await this.repo.listAll();\n const list =\n typeof msg.encodedCwd === \"string\"\n ? all.filter((s) => s.encodedCwd === msg.encodedCwd)\n : all;\n this.safeSend({\n type: \"schedule:list:result\",\n requestId,\n schedules: list,\n });\n } catch (err) {\n this.sendError(requestId, err);\n }\n }\n\n private async handleRuns(\n msg: Record<string, unknown>,\n requestId: string | undefined,\n ): Promise<void> {\n const id = String(msg.id);\n try {\n const runs = await this.repo.listRuns(id);\n this.safeSend({ type: \"schedule:runs:result\", requestId, runs });\n } catch (err) {\n this.sendError(requestId, err);\n }\n }\n\n private async handleLog(\n msg: Record<string, unknown>,\n requestId: string | undefined,\n ): Promise<void> {\n const id = String(msg.id);\n const runId = String(msg.runId);\n try {\n const { stdout, stderr } = await this.repo.readRunLogs(id, runId);\n this.safeSend({\n type: \"schedule:log:result\",\n requestId,\n runId,\n stdout,\n stderr,\n });\n } catch (err) {\n this.sendError(requestId, err);\n }\n }\n\n private sendError(requestId: string | undefined, err: unknown): void {\n const message = err instanceof Error ? err.message : String(err);\n log.warn({ err: message, requestId }, \"schedule-runtime: branch failed\");\n this.safeSend({\n type: \"schedule:error\",\n requestId,\n error: { code: \"INTERNAL\", message },\n });\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction isMsg(x: unknown): x is { type: string; requestId?: unknown } {\n return (\n typeof x === \"object\" &&\n x !== null &&\n typeof (x as { type?: unknown }).type === \"string\"\n );\n}\n\n// ── Real executor shims ──────────────────────────────────────────────────\n\n/**\n * Inline minimal claude binary resolver. Avoids depending on a non-exported\n * helper inside @mclawnet/claude-adapter (and avoids reusing\n * ClaudeCodeAdapter.spawn() which is built for persistent stdin sessions).\n */\nfunction resolveClaudeBin(): string {\n if (process.env.CLAUDE_BIN) return process.env.CLAUDE_BIN;\n try {\n const which = process.platform === \"win32\" ? \"where\" : \"which\";\n const out = execSync(`${which} claude`, { stdio: [\"ignore\", \"pipe\", \"ignore\"] })\n .toString()\n .split(/\\r?\\n/)\n .map((l) => l.trim())\n .filter(Boolean);\n if (out[0]) return out[0];\n } catch {\n // fallthrough — let spawn fail loudly with ENOENT.\n }\n return \"claude\";\n}\n\n/**\n * Head+tail byte-budgeted accumulator for child-process stdout/stderr. Keeps\n * the first N bytes and the last N bytes (each ~half the cap) so debugging\n * still has both ends available, with a single truncation marker between\n * them. Byte-aware so multi-byte UTF-8 sequences are never split.\n *\n * Why two buffers and not just `s += chunk; if (s.length > cap) s = s.slice(...)`?\n * - String slicing is char-aware, not byte-aware: a CJK-heavy stream would\n * blow past the byte budget by 3x.\n * - Repeatedly creating a new copy of a 1MB string per chunk is O(n^2).\n *\n * Keeping a Buffer-backed head + ring-tail caps the work at O(chunk size) per\n * push regardless of total volume.\n */\nclass BoundedBuffer {\n private head = Buffer.alloc(0);\n private tailRing: Buffer[] = [];\n private tailBytes = 0;\n private totalBytes = 0;\n private readonly headCap: number;\n private readonly tailCap: number;\n\n constructor(private readonly cap: number) {\n this.headCap = Math.floor(cap / 2);\n this.tailCap = cap - this.headCap;\n }\n\n push(chunk: string): void {\n if (chunk.length === 0) return;\n const buf = Buffer.from(chunk, \"utf8\");\n this.totalBytes += buf.byteLength;\n\n // Fill the head first.\n if (this.head.byteLength < this.headCap) {\n const need = this.headCap - this.head.byteLength;\n if (buf.byteLength <= need) {\n this.head = Buffer.concat([this.head, buf]);\n return;\n }\n // Split: the head takes `need` bytes, but we must not split a multi-\n // byte UTF-8 sequence. If we'd land mid-codepoint, back off to the\n // last codepoint boundary.\n let split = need;\n while (split > 0 && (buf[split] & 0xc0) === 0x80) split -= 1;\n this.head = Buffer.concat([this.head, buf.subarray(0, split)]);\n // Push the rest into the tail ring.\n this.appendToTail(buf.subarray(split));\n return;\n }\n this.appendToTail(buf);\n }\n\n private appendToTail(buf: Buffer): void {\n if (buf.byteLength === 0) return;\n this.tailRing.push(buf);\n this.tailBytes += buf.byteLength;\n // Trim from the front of the ring whenever we're over budget.\n while (this.tailBytes > this.tailCap && this.tailRing.length > 0) {\n const front = this.tailRing[0];\n const overflow = this.tailBytes - this.tailCap;\n if (front.byteLength <= overflow) {\n this.tailRing.shift();\n this.tailBytes -= front.byteLength;\n } else {\n // Partial trim from the front of `front`. Snap forward past any\n // continuation bytes so we don't expose a partial codepoint to the\n // decoder.\n let start = overflow;\n while (start < front.byteLength && (front[start] & 0xc0) === 0x80) {\n start += 1;\n }\n this.tailRing[0] = front.subarray(start);\n this.tailBytes -= start;\n }\n }\n }\n\n toString(): string {\n const tail = this.tailRing.length > 0 ? Buffer.concat(this.tailRing) : Buffer.alloc(0);\n if (this.totalBytes <= this.cap) {\n // Never truncated: head + tail == original.\n return Buffer.concat([this.head, tail]).toString(\"utf8\");\n }\n const dropped = this.totalBytes - this.head.byteLength - tail.byteLength;\n const marker = `\\n...[truncated ${dropped} bytes]...\\n`;\n return (\n this.head.toString(\"utf8\") + marker + tail.toString(\"utf8\")\n );\n }\n}\n\n/**\n * Best-effort SpawnFn for the OneShot executor. Streams stdout/stderr into\n * bounded buffers, parses stream-json lines (with chunk-boundary safety) to\n * extract the last assistant text, and honours an external AbortSignal.\n *\n * NOTE: tests do NOT exercise the spawn path itself (the binary lookup +\n * child_process invocation); chunk-boundary parsing and byte-cap behaviour\n * ARE covered via __tests__/schedule-runtime-spawn.test.ts which mocks\n * node:child_process.spawn.\n */\nexport function makeRealOneShotSpawn(): SpawnFn {\n return async (args, opts) => {\n const bin = resolveClaudeBin();\n const proc = spawn(bin, args, {\n cwd: opts.cwd,\n env: opts.env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n const stdoutBuf = new BoundedBuffer(SPAWN_STDOUT_CAP_BYTES);\n const stderrBuf = new BoundedBuffer(SPAWN_STDERR_CAP_BYTES);\n // Per-stream line buffer for stream-json parsing. A JSON object can be\n // emitted across two `data` events; concatenating into a residual buffer\n // and only parsing complete (newline-terminated) lines is the only way\n // to avoid silently dropping the assistant message.\n let stdoutLineResidual = \"\";\n let lastAssistantText: string | undefined;\n\n const tryExtractAssistant = (line: string): void => {\n const trimmed = line.trim();\n if (!trimmed) return;\n try {\n const obj = JSON.parse(trimmed) as {\n type?: string;\n message?: { content?: Array<{ type?: string; text?: string }> };\n };\n if (obj.type === \"assistant\" && obj.message?.content) {\n for (const piece of obj.message.content) {\n if (piece.type === \"text\" && typeof piece.text === \"string\") {\n lastAssistantText = piece.text;\n }\n }\n }\n } catch {\n // ignore non-JSON noise (e.g. interleaved warnings)\n }\n };\n\n proc.stdout?.setEncoding(\"utf8\");\n proc.stderr?.setEncoding(\"utf8\");\n proc.stdout?.on(\"data\", (chunk: string) => {\n stdoutBuf.push(chunk);\n // Combine residual + chunk and split. The LAST element may be partial\n // (no trailing \\n), so keep it in the residual for the next chunk.\n const combined = stdoutLineResidual + chunk;\n const lines = combined.split(\"\\n\");\n stdoutLineResidual = lines.pop() ?? \"\";\n for (const line of lines) tryExtractAssistant(line);\n });\n proc.stderr?.on(\"data\", (chunk: string) => {\n stderrBuf.push(chunk);\n });\n\n const onAbort = () => {\n try {\n proc.kill(\"SIGTERM\");\n } catch {\n /* ignore */\n }\n };\n if (opts.signal.aborted) onAbort();\n else opts.signal.addEventListener(\"abort\", onAbort, { once: true });\n\n return new Promise((resolve, reject) => {\n proc.once(\"error\", (err) => {\n opts.signal.removeEventListener(\"abort\", onAbort);\n reject(err);\n });\n proc.once(\"close\", (code) => {\n opts.signal.removeEventListener(\"abort\", onAbort);\n // Flush any trailing line that lacked a final newline. Without this,\n // a process that emits its last assistant message without a closing\n // \\n would lose its summary.\n if (stdoutLineResidual.length > 0) {\n tryExtractAssistant(stdoutLineResidual);\n stdoutLineResidual = \"\";\n }\n resolve({\n exitCode: code ?? -1,\n stdout: stdoutBuf.toString(),\n stderr: stderrBuf.toString(),\n lastAssistantText,\n });\n });\n });\n };\n}\n\n/**\n * Placeholder swarm starter. Wiring this to the real swarm runtime requires\n * piping a one-shot prompt through SwarmCoordinator + SessionManager and\n * extracting a final summary, which has no precedent yet — left for Phase 7+\n * once the UI surfaces a \"trigger swarm schedule now\" affordance.\n *\n * TODO(plan Task 6.x follow-up): wire to SwarmCoordinator.create() + listen\n * for queen completion to resolve { swarmId, sessionId, summary, exitCode }.\n * See packages/@clawnet/agent/src/schedule-runtime.ts:makeRealSwarmStarter\n * (this function).\n */\nexport function makeRealSwarmStarter(_deps: {\n sessionManager?: SessionManager;\n swarmCoordinator?: SwarmCoordinator;\n}): SwarmStarter {\n return async () => {\n throw new Error(\"swarm scheduler executor not yet wired\");\n };\n}\n","import { createLogger, previewFields } from \"@mclawnet/logger\";\nimport { buildMemorySection } from \"@mclawnet/memory\";\nimport { MAX_TOKENS_LADDER, clampLadderIndex } from \"@mclawnet/shared\";\nimport { getPendingNotification } from \"./skill-loader.js\";\nimport type { BackendAdapter, BackendProcess, SpawnOptions } from \"./backend-adapter.js\";\nimport {\n SessionLimitReachedError,\n type SessionKind,\n type SessionPoolSnapshot,\n} from \"./errors.js\";\nimport {\n atomicWriteJson,\n isPidAlive,\n readCheckpoint,\n type CheckpointEntry,\n type CheckpointFile,\n type RecoveryReport,\n} from \"./checkpoint.js\";\n\nconst log = createLogger({ module: \"agent/session-manager\" });\n\nconst DEFAULT_MAX_PROCESSES = 30;\nconst MAX_PROCESSES = Number(process.env.CLAWNET_MAX_PROCESSES) || DEFAULT_MAX_PROCESSES;\n\n// PR-A: idle TTL configuration. `0` (or any non-positive value) disables the\n// sweeper entirely — kept as a runtime escape hatch for ops/debugging.\nconst DEFAULT_CHAT_IDLE_TTL_MS = 60 * 60 * 1000; // 60 min\nconst DEFAULT_IDLE_SWEEP_INTERVAL_MS = 5 * 60 * 1000; // 5 min (hermes-style)\nconst CHAT_IDLE_TTL_MS = (() => {\n const raw = process.env.CLAWNET_CHAT_IDLE_TTL_MS;\n if (raw === undefined) return DEFAULT_CHAT_IDLE_TTL_MS;\n const parsed = Number(raw);\n // Allow `0` to mean \"disabled\". `Number(undefined)` is NaN, so the explicit\n // env-undefined branch above keeps the default.\n return Number.isFinite(parsed) ? parsed : DEFAULT_CHAT_IDLE_TTL_MS;\n})();\nconst IDLE_SWEEP_INTERVAL_MS = (() => {\n const raw = process.env.CLAWNET_IDLE_SWEEP_INTERVAL_MS;\n if (raw === undefined) return DEFAULT_IDLE_SWEEP_INTERVAL_MS;\n const parsed = Number(raw);\n // PR-C fixup #2: symmetric with CHAT_IDLE_TTL_MS parsing above. `0` would\n // be nonsensical for an interval (busy-loop), but Number.isFinite still\n // gates against NaN / Infinity so a malformed env var falls back to default\n // instead of silently producing a broken setInterval.\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_IDLE_SWEEP_INTERVAL_MS;\n})();\n\n/**\n * Per-session metadata kept parallel to `sessions: Map<sid, BackendProcess>`.\n *\n * Why a parallel map (and not a richer BackendProcess type): BackendProcess is\n * the adapter abstraction layer (\"backend capability\"); polluting it with\n * business timestamps would force every adapter to track them. The two maps\n * stay in lockstep through createSession/closeSession/abortSession/onExit.\n */\ninterface SessionMeta {\n kind: SessionKind;\n workDir: string;\n /** Set when the backend reports its session_started frame. */\n claudeSessionId?: string;\n /** Only set for swarm-role sessions (parsed from `${swarmId}::${instanceId}`). */\n agentInstanceId?: string;\n startedAt: number;\n /**\n * Updated only on sendInput and onTurnComplete — NOT on onOutput, since\n * mid-turn tool-use stdout is too chatty to be a meaningful \"user activity\"\n * signal. Mirrors hermes `_last_activity_ts`.\n */\n lastActivityAt: number;\n /** Reserved for future use-count-based recycling (P4); incremented but unused this PR. */\n turnsCompleted: number;\n /**\n * D-lite ladder index for max_output_tokens. 0 = 32k (default), 1 = 16k,\n * 2 = 8k. Bumped by the token_budget_warning handler; consumed by the next\n * spawn via getRecommendedMaxOutputTokens(). Persisted in checkpoint so a\n * restart picks up where escalation left off — without persistence a\n * SIGTERM right after escalation would silently revert the session to 32k.\n */\n currentLadderIndex?: number;\n}\n\n/**\n * Manages active sessions, mapping ClawNet session IDs to BackendProcess instances.\n *\n * When `options.roleId` is set, the manager automatically injects:\n * - Pipeline A: memory prompt + roleId hint via `--append-system-prompt`\n *\n * Note: MCP config is now handled globally via ~/.clawnet/mcp.json\n * (mounted by ClaudeCodeAdapter), no longer generated per-session.\n */\nexport class SessionManager {\n private sessions = new Map<string, BackendProcess>();\n private conversationBuffer = new Map<string, Array<{ role: string; content: string }>>();\n // PR-A: parallel metadata map (kind, timestamps). See SessionMeta jsdoc.\n private sessionMeta = new Map<string, SessionMeta>();\n // PR-A: sessions currently inside a sendInput→turn_complete window. Idle\n // sweeper must skip these even if lastActivityAt looks ancient — a\n // long-running deep-research turn would otherwise be killed mid-flight.\n private activelyExecuting = new Set<string>();\n // Sessions whose abort is in flight. Treated as not-present by hasSession /\n // isHealthy so a racing claude.execute (e.g., right after force_restart) is\n // correctly routed to the \"spawn new + --resume\" branch instead of trying\n // to write to a process we are about to kill.\n private aborting = new Set<string>();\n private idleSweepTimer: NodeJS.Timeout | null = null;\n // PR-A: effective sweeper config. Initialized from env at construct time\n // and overridable per-instance via startIdleSweeper(overrides) — the\n // override path is mostly for tests (drive sweeps with sub-second TTLs)\n // and for ops scripts that want a one-off short cycle.\n private idleTtlMs = CHAT_IDLE_TTL_MS;\n private idleSweepIntervalMs = IDLE_SWEEP_INTERVAL_MS;\n // PR-C: checkpoint state. `checkpointPath` is null when checkpoint is\n // disabled (no path supplied → tests, or env override later). Debouncer\n // coalesces structural events into ≤ 1 disk write per 5s; agentStartedAt\n // is recorded once at construction so a restart can correlate logs.\n private checkpointPath: string | null;\n private checkpointDebounceMs: number;\n private checkpointDebouncer: NodeJS.Timeout | null = null;\n private agentStartedAt = Date.now();\n // PR-C fixup: one-shot guard. start.ts wires recoverFromCheckpoint() into\n // hub `onConnect`, which fires on every reconnect. After the first call the\n // checkpoint file holds *current-run* entries owned by us — re-classifying\n // them would falsely flag every live session as \"orphan\" and spam logs. The\n // flag is intentionally process-lifetime: a new agent process gets a fresh\n // SessionManager and re-runs recovery exactly once.\n private hasRecovered = false;\n /**\n * Carry-over ladder indices from the previous run's checkpoint. Populated by\n * `recoverFromCheckpoint`, drained one-shot by `createSession`. Without this\n * a SIGTERM right after escalating to 16k would silently revert the next\n * spawn back to 32k and re-hit the 168k wall on its first turn.\n */\n private recoveredLadderIndex = new Map<string, number>();\n private adapter: BackendAdapter;\n private onOutput: (sessionId: string, data: unknown) => void;\n private onTurnComplete: (\n sessionId: string,\n info: {\n claudeSessionId?: string;\n cost?: number;\n duration?: number;\n contextUsage?: { used: number; total: number };\n },\n ) => void;\n private onSessionError: (sessionId: string, error: string) => void;\n private onSessionStarted?: (sessionId: string, info: { claudeSessionId: string }) => void;\n private onBeforeClose?: (sessionId: string, messages: Array<{ role: string; content: string }>) => Promise<void>;\n // PR-A: classifies a sessionId as 'chat' or 'swarm-role'. Injected by\n // start.ts via SwarmCoordinator.isSwarmSession to keep SessionManager\n // independent of the swarm package. Defaults to 'chat' if absent — safe\n // because the worst-case (mis-classify a swarm-role as chat) is bounded by\n // activelyExecuting protection during turn execution.\n private classify: (sessionId: string) => SessionKind;\n\n constructor(options: {\n adapter: BackendAdapter;\n onOutput: (sessionId: string, data: unknown) => void;\n onTurnComplete: (\n sessionId: string,\n info: {\n claudeSessionId?: string;\n cost?: number;\n duration?: number;\n contextUsage?: { used: number; total: number };\n },\n ) => void;\n onSessionError: (sessionId: string, error: string) => void;\n onSessionStarted?: (sessionId: string, info: { claudeSessionId: string }) => void;\n onBeforeClose?: (sessionId: string, messages: Array<{ role: string; content: string }>) => Promise<void>;\n classify?: (sessionId: string) => SessionKind;\n /**\n * (PR-C) Where to write the agent-sessions.json checkpoint. Pass `null`\n * (or omit) to disable checkpointing entirely — useful for tests and for\n * the rare embedded use case where there's no writable directory. When\n * set, the file is written via temp+rename on debounced structural events.\n */\n checkpointPath?: string | null;\n /** (PR-C) Override the 5s debounce window. Tests use ~50ms. */\n checkpointDebounceMs?: number;\n }) {\n this.adapter = options.adapter;\n this.onOutput = options.onOutput;\n this.onTurnComplete = options.onTurnComplete;\n this.onSessionError = options.onSessionError;\n this.onSessionStarted = options.onSessionStarted;\n this.onBeforeClose = options.onBeforeClose;\n this.classify = options.classify ?? (() => \"chat\");\n this.checkpointPath = options.checkpointPath ?? null;\n this.checkpointDebounceMs = options.checkpointDebounceMs ?? 5_000;\n }\n\n async createSession(options: SpawnOptions): Promise<string> {\n if (this.sessions.has(options.sessionId)) {\n throw new Error(`Session ${options.sessionId} already exists`);\n }\n\n if (this.sessions.size >= MAX_PROCESSES) {\n // PR-B: fail-fast with rich pool details so hub/UI can render an\n // actionable message (\"oldest idle is X, idle for Ns\") instead of a\n // generic limit-reached string. Uses an Error subclass with a stable\n // `code` so dispatchers can branch without importing this class.\n throw new SessionLimitReachedError(this.snapshotPoolForError());\n }\n\n // ── Unified memory injection ──\n if (options.roleId) {\n // Pipeline A: prepend memory section + roleId hint to system prompt\n try {\n const memorySection = buildMemorySection(options.roleId);\n const roleHint = `\\n\\n[Memory Context] Your roleId is \"${options.roleId}\". Always use this roleId when calling memory_search, memory_store, memory_stats, or memory_reflect.`;\n options.systemPrompt = options.systemPrompt\n ? `${memorySection}${roleHint}\\n\\n${options.systemPrompt}`\n : `${memorySection}${roleHint}`;\n log.debug({ roleId: options.roleId, sessionId: options.sessionId }, \"memory prompt + roleId hint injected\");\n } catch (err) {\n log.warn({ err, roleId: options.roleId }, \"failed to build memory section, proceeding without\");\n }\n }\n\n // ── Pending skill-evolution notification ──\n try {\n const notice = getPendingNotification();\n if (notice) {\n const noticeBlock = `\\n\\n[Skill 进化提案]\\n${notice.text}`;\n options.systemPrompt = options.systemPrompt\n ? `${options.systemPrompt}${noticeBlock}`\n : noticeBlock.trimStart();\n log.debug(\n { sessionId: options.sessionId, pending: notice.count },\n \"pending skill evolution notice injected\",\n );\n }\n } catch (err) {\n log.debug({ err }, \"failed to inject pending notification\");\n }\n\n try {\n const process = await this.adapter.spawn(options);\n this.sessions.set(options.sessionId, process);\n\n // PR-A: register metadata in lockstep with sessions Map. Initial\n // lastActivityAt = now, so a brand-new session always survives the next\n // sweeper tick regardless of TTL.\n const now = Date.now();\n const kind = this.classify(options.sessionId);\n const agentInstanceId =\n kind === \"swarm-role\" ? options.sessionId.split(\"::\")[1] : undefined;\n this.sessionMeta.set(options.sessionId, {\n kind,\n workDir: options.workDir ?? process.workDir,\n agentInstanceId,\n startedAt: now,\n lastActivityAt: now,\n turnsCompleted: 0,\n // Restore ladder index if this sessionId was carried over from the\n // previous run's checkpoint. drain-on-read so a future re-creation of\n // a different session with the same id starts fresh.\n currentLadderIndex: this.recoveredLadderIndex.get(options.sessionId),\n });\n this.recoveredLadderIndex.delete(options.sessionId);\n\n // PR-C: structural event → schedule checkpoint flush.\n this.scheduleCheckpoint();\n\n // Wire up output handler\n this.adapter.onOutput(process, (data) => {\n // Accumulate assistant text messages for distillation\n const msg = data as any;\n if (msg?.type === \"assistant\" && msg?.message?.content) {\n const buf = this.conversationBuffer.get(options.sessionId) ?? [];\n // Extract text from content blocks\n const text = Array.isArray(msg.message.content)\n ? msg.message.content.filter((b: any) => b.type === \"text\").map((b: any) => b.text).join(\"\\n\")\n : String(msg.message.content);\n if (text) {\n buf.push({ role: \"assistant\", content: text });\n this.conversationBuffer.set(options.sessionId, buf);\n }\n }\n this.onOutput(options.sessionId, data);\n });\n\n // Wire up turn-complete handler\n this.adapter.onTurnComplete?.(process, (info) => {\n // PR-A: turn boundary is the canonical activity-pulse signal.\n const meta = this.sessionMeta.get(options.sessionId);\n if (meta) {\n meta.lastActivityAt = Date.now();\n meta.turnsCompleted += 1;\n }\n // Always release the executing flag — even if onTurnComplete fires\n // multiple times or out of order, Set.delete is idempotent.\n this.activelyExecuting.delete(options.sessionId);\n this.onTurnComplete(options.sessionId, info);\n });\n\n // Wire up error handler\n this.adapter.onError?.(process, (error) => {\n // PR-A: errors mid-turn also end the executing window — otherwise a\n // dead session would be permanently pinned by activelyExecuting and\n // never sweep-eligible.\n this.activelyExecuting.delete(options.sessionId);\n this.onSessionError(options.sessionId, error.message);\n });\n\n // Wire token-budget warning → escalate ladder for next spawn.\n // Why we don't kill the current process here: the warning fires at the\n // result frame, i.e. the model already produced *this* turn's reply.\n // Killing now would only delay the next user turn for no benefit. The\n // updated ladder index is consumed when the user's NEXT turn comes in\n // (hub-connection.spawnAndSend pulls getRecommendedMaxOutputTokens()).\n this.adapter.onTokenBudgetWarning?.(process, (info) => {\n const meta = this.sessionMeta.get(options.sessionId);\n if (!meta) return;\n const currentIndex = clampLadderIndex(meta.currentLadderIndex);\n const atFloor = currentIndex >= MAX_TOKENS_LADDER.length - 1;\n if (atFloor) {\n log.warn(\n {\n sessionId: options.sessionId,\n used: info.used,\n hardLimit: info.hardLimit,\n maxOutputTokens: info.maxOutputTokens,\n },\n \"token_budget_warning at ladder floor (8k) — cannot escalate further\",\n );\n return;\n }\n const nextIndex = currentIndex + 1;\n meta.currentLadderIndex = nextIndex;\n log.warn(\n {\n sessionId: options.sessionId,\n used: info.used,\n hardLimit: info.hardLimit,\n previousMaxOutputTokens: info.maxOutputTokens,\n nextMaxOutputTokens: MAX_TOKENS_LADDER[nextIndex],\n ladderIndex: nextIndex,\n },\n \"token_budget_warning: escalating max_output_tokens for next spawn\",\n );\n // Persist immediately so a restart between now and the next spawn\n // doesn't lose the escalation state.\n this.scheduleCheckpoint();\n });\n\n // Wire up early session-started handler — Claude CLI emits its real\n // session_id in the first `system/init` frame, well before turn_complete.\n // Persisting it immediately means a mid-turn crash still leaves db\n // pointing at the correct jsonl file for `--resume`.\n //\n // B2 race guard: stdout buffered before SIGTERM lands can still emit\n // `system/init` after we've decided to abort. Suppress those late frames\n // so hub doesn't resurrect a dead session's claudeSessionId / spinner.\n if (this.onSessionStarted) {\n this.adapter.onSessionStarted?.(process, (info) => {\n if (this.aborting.has(options.sessionId)) {\n log.debug(\n { sessionId: options.sessionId },\n \"suppressing late session_started — session is aborting\",\n );\n return;\n }\n if (this.sessions.get(options.sessionId) !== process) {\n // Map already swapped to a fresh process for this sessionId — the\n // event belongs to the previous, now-orphaned process.\n return;\n }\n // PR-A: persist claudeSessionId into meta for future checkpoint use\n // (P2). Cheap to do here since we're already filtering for the\n // current owner.\n const meta = this.sessionMeta.get(options.sessionId);\n if (meta) meta.claudeSessionId = info.claudeSessionId;\n // PR-C: claudeSessionId entering the meta map is exactly the kind\n // of structural fact we want in the next checkpoint snapshot — so\n // a kill -9 between system/init and turn_complete still leaves a\n // resumable jsonl reference on disk.\n this.scheduleCheckpoint();\n this.onSessionStarted!(options.sessionId, info);\n });\n }\n\n // Auto-evict on unexpected exit (crash, EPIPE, OOM, external SIGKILL).\n // Without this, hasSession() keeps returning true after the child dies\n // and reuse path writes to a dead pipe — root cause of the \"stuck\n // session\" symptom this PR fixes.\n this.adapter.onExit?.(process, (code) => {\n if (this.sessions.get(options.sessionId) === process) {\n this.sessions.delete(options.sessionId);\n this.sessionMeta.delete(options.sessionId);\n this.activelyExecuting.delete(options.sessionId);\n this.conversationBuffer.delete(options.sessionId);\n // PR-C: structural removal → schedule checkpoint flush so a stale\n // entry doesn't survive the next agent restart and trigger a\n // spurious session.died notification.\n this.scheduleCheckpoint();\n log.warn({ sessionId: options.sessionId, exitCode: code }, \"backend process exited unexpectedly, evicted from session map\");\n this.onSessionError(options.sessionId, `backend process exited (code=${code ?? \"null\"})`);\n }\n });\n\n return process.id;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.onSessionError(options.sessionId, message);\n throw err;\n }\n }\n\n sendInput(sessionId: string, input: string): void {\n const process = this.sessions.get(sessionId);\n if (!process) {\n this.onSessionError(sessionId, `No active session: ${sessionId}`);\n return;\n }\n // PR-A: mark executing *before* writing to stdin. We accept that an\n // adapter.send throw will leave the flag set — onError handler clears it.\n // No try/finally here because the executing window is bounded by the\n // *next turn boundary*, not by the synchronous send call.\n this.activelyExecuting.add(sessionId);\n const meta = this.sessionMeta.get(sessionId);\n if (meta) meta.lastActivityAt = Date.now();\n log.debug(\n { sessionId, ...previewFields(input) },\n \"sendInput → backend stdin\",\n );\n this.adapter.send(process, input);\n }\n\n async abortSession(sessionId: string): Promise<void> {\n const process = this.sessions.get(sessionId);\n if (!process) return;\n // Mark aborting *before* awaiting stop() so concurrent isHealthy / hasSession\n // calls immediately see the session as gone — fixes the race where hub\n // sends force_restart and claude.execute back-to-back.\n this.aborting.add(sessionId);\n this.conversationBuffer.delete(sessionId);\n this.sessions.delete(sessionId);\n this.sessionMeta.delete(sessionId);\n this.activelyExecuting.delete(sessionId);\n // PR-C: same rationale as createSession — structural removal needs to\n // make it into the next checkpoint so a restart doesn't see the abort\n // victim as \"presumed alive but gone\".\n this.scheduleCheckpoint();\n try {\n await this.adapter.stop(process);\n } finally {\n this.aborting.delete(sessionId);\n }\n }\n\n async closeSession(sessionId: string): Promise<void> {\n const process = this.sessions.get(sessionId);\n if (!process) return;\n\n // Trigger distillation before closing\n const messages = this.conversationBuffer.get(sessionId);\n if (this.onBeforeClose && messages?.length) {\n await this.onBeforeClose(sessionId, messages).catch(() => {});\n }\n this.conversationBuffer.delete(sessionId);\n\n this.sessions.delete(sessionId);\n this.sessionMeta.delete(sessionId);\n this.activelyExecuting.delete(sessionId);\n // PR-C: structural removal → schedule flush.\n this.scheduleCheckpoint();\n await this.adapter.stop(process);\n }\n\n async closeAll(): Promise<void> {\n // PR-A: stop sweeper first so it can't race a closeAll-driven cleanup.\n this.stopIdleSweeper();\n const promises = Array.from(this.sessions.entries()).map(\n async ([sessionId, process]) => {\n // Trigger distillation before closing\n const messages = this.conversationBuffer.get(sessionId);\n if (this.onBeforeClose && messages?.length) {\n await this.onBeforeClose(sessionId, messages).catch(() => {});\n }\n this.conversationBuffer.delete(sessionId);\n this.sessions.delete(sessionId);\n this.sessionMeta.delete(sessionId);\n this.activelyExecuting.delete(sessionId);\n await this.adapter.stop(process).catch(() => {});\n },\n );\n await Promise.all(promises);\n // PR-C: graceful shutdown → flush a final, deterministic snapshot\n // (entries=[] post-closeAll). This is the contract the docs §5\n // \"三阶段衔接\" table relies on: a clean exit leaves an empty file so the\n // next start finds nothing to recover and goes straight to normal mode.\n if (this.checkpointPath) {\n // Cancel any pending debounced flush — its snapshot would race with\n // ours and could non-deterministically overwrite the empty file.\n if (this.checkpointDebouncer) {\n clearTimeout(this.checkpointDebouncer);\n this.checkpointDebouncer = null;\n }\n await this.flushCheckpoint().catch((err) =>\n log.warn({ err }, \"checkpoint: final flushCheckpoint failed\"),\n );\n }\n }\n\n hasSession(sessionId: string): boolean {\n return this.sessions.has(sessionId) && !this.aborting.has(sessionId);\n }\n\n /**\n * Stricter than hasSession(): also requires the underlying process to still\n * be alive (not exited, stdin still writable). Callers in the reuse path\n * must use this to avoid sending input into a dead pipe — if it returns\n * false they should fall back to `--resume` against db's claudeSessionId.\n */\n isHealthy(sessionId: string): boolean {\n if (this.aborting.has(sessionId)) return false;\n const process = this.sessions.get(sessionId);\n return !!process && process.isAlive();\n }\n\n get activeSessionCount(): number {\n return this.sessions.size;\n }\n\n getActiveSessionIds(): string[] {\n return Array.from(this.sessions.keys());\n }\n\n /**\n * Recommended `CLAUDE_CODE_MAX_OUTPUT_TOKENS` for the *next* spawn of this\n * session. Returns `undefined` for unknown sessions OR sessions still at\n * ladder index 0 — callers omit the env override in that case so the CLI\n * picks its own default. Returning `undefined` (instead of `32_000`) keeps\n * env composition free of redundant overrides for the common path.\n *\n * Used by hub-connection.spawnAndSend on every reuse / fresh-resume\n * branch — without that wiring the ladder change in meta would be inert.\n */\n getRecommendedMaxOutputTokens(sessionId: string): number | undefined {\n const meta = this.sessionMeta.get(sessionId);\n if (!meta) return undefined;\n const idx = clampLadderIndex(meta.currentLadderIndex);\n if (idx <= 0) return undefined;\n return MAX_TOKENS_LADDER[idx];\n }\n\n // ─── PR-A: idle TTL sweeper ─────────────────────────────────────────\n\n /**\n * Start the periodic idle sweeper. Idempotent: a second call is a no-op.\n * Disabled (no-op) when effective TTL is `<= 0` — set via env\n * `CLAWNET_CHAT_IDLE_TTL_MS=0` or via the `ttlMs` override.\n *\n * The timer is `unref()`-ed so it never blocks process exit.\n *\n * @param overrides - test/ops hook to override env-derived defaults.\n */\n startIdleSweeper(overrides?: { ttlMs?: number; intervalMs?: number }): void {\n if (overrides?.ttlMs !== undefined) this.idleTtlMs = overrides.ttlMs;\n if (overrides?.intervalMs !== undefined)\n this.idleSweepIntervalMs = overrides.intervalMs;\n if (this.idleSweepTimer) return;\n if (this.idleTtlMs <= 0) {\n log.info(\"idleSweeper disabled (ttlMs <= 0)\");\n return;\n }\n this.idleSweepTimer = setInterval(() => {\n this.sweepIdleSessions().catch((err) =>\n log.warn({ err }, \"idleSweeper: tick failed\"),\n );\n }, this.idleSweepIntervalMs);\n this.idleSweepTimer.unref?.();\n log.info(\n { ttlMs: this.idleTtlMs, intervalMs: this.idleSweepIntervalMs },\n \"idleSweeper started\",\n );\n }\n\n stopIdleSweeper(): void {\n if (this.idleSweepTimer) {\n clearInterval(this.idleSweepTimer);\n this.idleSweepTimer = null;\n }\n }\n\n /**\n * One sweep tick. Exposed for tests (so they can drive sweeps deterministically\n * without faking interval timers) and for ops scripts. Safe to call concurrently\n * with normal traffic — the sweeper only ever calls closeSession, which itself\n * is idempotent on missing IDs.\n */\n async sweepIdleSessions(): Promise<void> {\n const now = Date.now();\n const ttl = this.idleTtlMs;\n if (ttl <= 0) return;\n const victims: string[] = [];\n\n for (const [sid, meta] of this.sessionMeta) {\n // 1. Only chat sessions are idle-evictable. Swarm-role lifecycle is\n // owned by SwarmCoordinator (it knows when a role is no longer needed).\n if (meta.kind !== \"chat\") continue;\n // 2. Do not interrupt an in-flight turn — even if the user has been\n // \"silent\" for hours, the model could be in a deep-research loop.\n if (this.activelyExecuting.has(sid)) continue;\n // 3. Skip sessions that another caller is already tearing down.\n if (this.aborting.has(sid)) continue;\n // 4. TTL gate.\n if (now - meta.lastActivityAt < ttl) continue;\n victims.push(sid);\n }\n\n for (const sid of victims) {\n const idleMs = now - (this.sessionMeta.get(sid)?.lastActivityAt ?? now);\n log.info(\n { sessionId: sid, idleMs, ttlMs: ttl },\n \"idleSweeper: closing idle chat session\",\n );\n await this.closeSession(sid).catch((err) =>\n log.warn({ err, sessionId: sid }, \"idleSweeper: closeSession failed, continuing\"),\n );\n }\n }\n\n // ─── PR-B: fail-fast saturation snapshot ────────────────────────────\n\n /**\n * Build the SessionPoolSnapshot attached to a SessionLimitReachedError.\n *\n * \"Idle\" here means \"not currently executing a turn\". A session whose\n * lastActivityAt is hours old but is mid-turn (long-running deep-research)\n * is intentionally NOT a candidate — pointing the user at it would be\n * misleading. The selection mirrors `sweepIdleSessions` filters minus the\n * TTL gate (since at saturation we report the LRU regardless of TTL).\n */\n private snapshotPoolForError(): SessionPoolSnapshot {\n const byKind: Record<SessionKind, number> = { chat: 0, \"swarm-role\": 0 };\n let oldestIdleSessionId: string | null = null;\n let oldestIdleTs = Infinity;\n let oldestIdleKind: SessionKind | null = null;\n const now = Date.now();\n\n for (const [sid, meta] of this.sessionMeta) {\n byKind[meta.kind]++;\n // Skip executing sessions — same rationale as sweepIdleSessions step 2.\n if (this.activelyExecuting.has(sid)) continue;\n if (this.aborting.has(sid)) continue;\n if (meta.lastActivityAt < oldestIdleTs) {\n oldestIdleTs = meta.lastActivityAt;\n oldestIdleSessionId = sid;\n oldestIdleKind = meta.kind;\n }\n }\n\n return {\n used: this.sessions.size,\n max: MAX_PROCESSES,\n byKind,\n oldestIdleSessionId,\n oldestIdleAgeMs: oldestIdleSessionId ? now - oldestIdleTs : null,\n oldestIdleKind,\n };\n }\n\n // ─── PR-C: logical-state checkpoint ─────────────────────────────────\n\n /**\n * Schedule a debounced flush of the in-memory pool to the checkpoint file.\n *\n * Burst protection: if a debounce timer is already pending, this is a no-op\n * — the flush captures the pool state at firing time, so all events in the\n * 5s window are observable in the eventual snapshot. This collapses the\n * \"create + onSessionStarted + close\" 3-event sequence into one disk write.\n */\n scheduleCheckpoint(): void {\n if (!this.checkpointPath) return;\n if (this.checkpointDebouncer) return;\n this.checkpointDebouncer = setTimeout(() => {\n this.checkpointDebouncer = null;\n this.flushCheckpoint().catch((err) =>\n log.warn({ err }, \"checkpoint: flush failed\"),\n );\n }, this.checkpointDebounceMs);\n this.checkpointDebouncer.unref?.();\n }\n\n /**\n * Flush the current pool to the checkpoint file via temp+rename. Public\n * for tests and for the graceful-shutdown final-flush in `closeAll`.\n *\n * Sessions whose underlying BackendProcess has no `pid` (e.g., in-process\n * mock backends) are skipped — without a pid the recovery probe can't\n * distinguish dead from alive, and writing them in would just generate\n * spurious session.died notifications on restart.\n */\n async flushCheckpoint(): Promise<void> {\n if (!this.checkpointPath) return;\n const entries: CheckpointEntry[] = [];\n for (const [sid, meta] of this.sessionMeta) {\n const proc = this.sessions.get(sid);\n if (!proc) continue;\n if (proc.pid === undefined) continue;\n entries.push({\n sessionId: sid,\n kind: meta.kind,\n workDir: meta.workDir,\n claudeSessionId: meta.claudeSessionId,\n agentInstanceId: meta.agentInstanceId,\n startedAt: meta.startedAt,\n lastActivityAt: meta.lastActivityAt,\n pid: proc.pid,\n currentLadderIndex: meta.currentLadderIndex,\n });\n }\n const data: CheckpointFile = {\n version: 1,\n agentStartedAt: this.agentStartedAt,\n entries,\n };\n await atomicWriteJson(this.checkpointPath, data);\n }\n\n /**\n * Read the previous-run checkpoint, classify each entry as `dead` or\n * `orphan` via pid probe, then reset the file to the current (empty)\n * truth. Caller (start.ts) is expected to forward `dead` entries to hub\n * via `session.died` so db's processState clears.\n *\n * Returns `{dead: [], orphan: []}` on first boot (no file). Throws on\n * file-system error or JSON parse failure — start.ts catches and logs so a\n * corrupt checkpoint does not block agent startup.\n */\n async recoverFromCheckpoint(): Promise<RecoveryReport> {\n if (!this.checkpointPath) return { dead: [], orphan: [] };\n // PR-C fixup #1: idempotent across hub reconnects. onConnect fires every\n // time the WebSocket re-establishes; without this guard, the second call\n // would read entries WE just wrote (with our own child pids), classify\n // them as live → \"orphan\", and rewrite the same file. Subsequent boots of\n // a different agent process get a fresh `hasRecovered = false`, so the\n // semantics (\"recover once per process\") is preserved.\n if (this.hasRecovered) return { dead: [], orphan: [] };\n this.hasRecovered = true;\n const file = await readCheckpoint(this.checkpointPath);\n if (!file) return { dead: [], orphan: [] };\n\n const dead: CheckpointEntry[] = [];\n const orphan: CheckpointEntry[] = [];\n for (const entry of file.entries) {\n // Stash any ladder index so the next createSession() with this\n // sessionId resumes at the same step. Done unconditionally — works for\n // both `dead` (will respawn via --resume) and `orphan` (won't respawn\n // here but no harm in keeping the carry-over until it's drained or the\n // process exits).\n if (typeof entry.currentLadderIndex === \"number\") {\n this.recoveredLadderIndex.set(entry.sessionId, entry.currentLadderIndex);\n }\n if (isPidAlive(entry.pid)) {\n orphan.push(entry);\n log.warn(\n { sessionId: entry.sessionId, pid: entry.pid },\n \"recover: pid still alive but not owned by current agent (orphan)\",\n );\n } else {\n dead.push(entry);\n }\n }\n // Reset to current truth (which is empty — recover runs before any new\n // sessions are created). If we skip this, the next agent that starts\n // before any structural event would re-process the same dead entries.\n await this.flushCheckpoint();\n return { dead, orphan };\n }\n}\n","import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { join, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { createLogger } from \"@mclawnet/logger\";\nimport { ManifestManager, mergeSkillSections } from \"@mclawnet/skill-manager\";\n\nconst log = createLogger({ module: \"agent/skill-loader\" });\n\n/** ~/.clawnet base directory */\nconst CLAWNET_DIR = join(homedir(), \".clawnet\");\n/** Skill target directory: ~/.clawnet/.claude/skills/ */\nconst SKILLS_DIR = join(CLAWNET_DIR, \".claude\", \"skills\");\n/** MCP config file: ~/.clawnet/mcp.json */\nconst MCP_CONFIG_PATH = join(CLAWNET_DIR, \"mcp.json\");\n\n/**\n * Initialize ClawNet skill system:\n * 1. Ensure skill directory exists\n * 2. Sync built-in skills via the manifest (three-way merge aware)\n * 3. Ensure MCP config exists\n */\nexport async function initSkills(): Promise<void> {\n ensureSkillsDir();\n syncBuiltinSkills(CLAWNET_DIR, defaultBuiltinSourceDir());\n ensureMcpConfig();\n scanSkills();\n}\n\n/** Built-in skills live next to the agent's compiled output at `../skills`. */\nfunction defaultBuiltinSourceDir(): string {\n const thisFile = fileURLToPath(import.meta.url);\n return join(dirname(thisFile), \"..\", \"skills\");\n}\n\nfunction sha256(s: string): string {\n return createHash(\"sha256\").update(s).digest(\"hex\");\n}\n\n/** Read version from built-in skill frontmatter (defaults to 1.0.0). */\nfunction readBuiltinVersion(content: string): string {\n const match = content.match(/^version:\\s*(.+)$/m);\n return match ? match[1].trim().replace(/^[\"']|[\"']$/g, \"\") : \"1.0.0\";\n}\n\n/**\n * Synchronize built-in skills into `rootDir/.claude/skills` using the\n * manifest so user edits are preserved across official upgrades:\n *\n * - brand-new skill → install + register in manifest\n * - user unchanged, official changed → overwrite + update manifest\n * - user changed, official unchanged → skip (nothing to do)\n * - both changed → attempt section-level 3-way merge; on conflict write\n * a `SKILL.md.conflict` sibling file and leave user copy untouched.\n */\nexport function syncBuiltinSkills(rootDir: string, srcDir: string): void {\n const skillsDir = join(rootDir, \".claude\", \"skills\");\n if (!existsSync(skillsDir)) mkdirSync(skillsDir, { recursive: true });\n\n if (!existsSync(srcDir)) {\n log.debug({ srcDir }, \"no built-in skills directory found, skipping\");\n return;\n }\n\n const manifest = new ManifestManager(rootDir);\n\n let entries: string[];\n try {\n entries = readdirSync(srcDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n log.warn({ srcDir }, \"failed to read built-in skills directory\");\n return;\n }\n\n for (const skillName of entries) {\n const srcSkillMd = join(srcDir, skillName, \"SKILL.md\");\n if (!existsSync(srcSkillMd)) continue;\n\n const destDir = join(skillsDir, skillName);\n const destSkillMd = join(destDir, \"SKILL.md\");\n const baseSnapshotPath = join(destDir, \".base.md\");\n\n let officialContent: string;\n try {\n officialContent = readFileSync(srcSkillMd, \"utf-8\");\n } catch (err) {\n log.warn({ skill: skillName, err }, \"failed to read built-in skill\");\n continue;\n }\n const officialHash = sha256(officialContent);\n const officialVersion = readBuiltinVersion(officialContent);\n\n // Brand new skill on this machine\n if (!existsSync(destSkillMd)) {\n try {\n mkdirSync(destDir, { recursive: true });\n writeFileSync(destSkillMd, officialContent);\n writeFileSync(baseSnapshotPath, officialContent);\n manifest.register(skillName, officialHash, officialVersion);\n log.info({ skill: skillName, version: officialVersion }, \"installed built-in skill\");\n } catch (err) {\n log.warn({ skill: skillName, err }, \"failed to install built-in skill\");\n }\n continue;\n }\n\n // Existing skill — consult manifest\n const userContent = readFileSync(destSkillMd, \"utf-8\");\n const userHash = sha256(userContent);\n manifest.refresh(skillName, userHash);\n\n // 惰性回填 .base.md:若之前版本没写过,而用户从未改动(userHash 与\n // manifest 记录的 baseHash 一致),则当前用户内容即为上次官方版本,\n // 可以直接作为 base 快照,为未来的三方合并打下基础。\n if (!existsSync(baseSnapshotPath)) {\n const entry = manifest.load().skills[skillName];\n if (entry && !entry.userModified) {\n try {\n writeFileSync(baseSnapshotPath, userContent);\n } catch (err) {\n log.debug({ skill: skillName, err }, \"failed to write lazy .base.md\");\n }\n }\n }\n\n const action = manifest.determineSyncAction(skillName, officialHash, officialVersion);\n switch (action) {\n case \"skip\":\n log.debug({ skill: skillName }, \"skill already up to date\");\n break;\n case \"direct-overwrite\":\n try {\n writeFileSync(destSkillMd, officialContent);\n writeFileSync(baseSnapshotPath, officialContent);\n manifest.markSynced(skillName, officialHash, officialHash, officialVersion);\n log.info({ skill: skillName, version: officialVersion }, \"upgraded built-in skill\");\n } catch (err) {\n log.warn({ skill: skillName, err }, \"failed to overwrite skill\");\n }\n break;\n case \"keep-user\":\n log.debug({ skill: skillName }, \"keeping user-modified skill\");\n break;\n case \"needs-merge\": {\n // 必须要有 .base.md 才能安全地做三方合并;若不存在(旧版本未写),\n // 则无法区分谁改了什么,直接写 .conflict 建议用户手动处理,保留用户副本。\n if (!existsSync(baseSnapshotPath)) {\n try {\n writeFileSync(\n destSkillMd + \".conflict\",\n renderConflictFile(skillName, officialContent, [\n {\n section: \"(entire file)\",\n official: officialContent,\n user: userContent,\n },\n ]),\n );\n log.warn(\n { skill: skillName },\n \"missing .base.md snapshot — skipping auto-merge, wrote .conflict advisory\",\n );\n } catch (err) {\n log.warn({ skill: skillName, err }, \"failed to write .conflict advisory\");\n }\n break;\n }\n const baseContent = readFileSync(baseSnapshotPath, \"utf-8\");\n const merged = mergeSkillSections(baseContent, officialContent, userContent);\n if (merged.success && merged.content) {\n try {\n writeFileSync(destSkillMd, merged.content);\n writeFileSync(baseSnapshotPath, officialContent);\n const newCurrentHash = sha256(merged.content);\n manifest.markSynced(skillName, officialHash, newCurrentHash, officialVersion);\n log.info({ skill: skillName }, \"auto-merged skill upgrade\");\n } catch (err) {\n log.warn({ skill: skillName, err }, \"failed to write merged skill\");\n }\n } else {\n // Conflict → write a .conflict sibling for later notification,\n // leave user copy intact.\n try {\n writeFileSync(\n destSkillMd + \".conflict\",\n renderConflictFile(skillName, officialContent, merged.conflicts ?? []),\n );\n log.warn(\n { skill: skillName, conflicts: merged.conflicts?.length },\n \"skill merge conflict — user version kept, .conflict file written\",\n );\n } catch (err) {\n log.warn({ skill: skillName, err }, \"failed to write .conflict file\");\n }\n }\n break;\n }\n }\n }\n}\n\nfunction renderConflictFile(\n skillName: string,\n officialContent: string,\n conflicts: Array<{ section: string; official: string; user: string }>,\n): string {\n const lines = [\n `# Skill upgrade conflict: ${skillName}`,\n ``,\n `The official skill was updated, and your local copy was also modified.`,\n `Please review each section below and reconcile manually.`,\n ``,\n `## Conflicted sections`,\n ``,\n ];\n for (const c of conflicts) {\n lines.push(`### ${c.section}`);\n lines.push(\"\");\n lines.push(\"**Official:**\");\n lines.push(\"```\");\n lines.push(c.official);\n lines.push(\"```\");\n lines.push(\"\");\n lines.push(\"**Your version:**\");\n lines.push(\"```\");\n lines.push(c.user);\n lines.push(\"```\");\n lines.push(\"\");\n }\n lines.push(\"## Full official content\");\n lines.push(\"```\");\n lines.push(officialContent);\n lines.push(\"```\");\n return lines.join(\"\\n\");\n}\n\n/** Create ~/.clawnet/.claude/skills/ if it doesn't exist. */\nfunction ensureSkillsDir(): void {\n if (!existsSync(SKILLS_DIR)) {\n mkdirSync(SKILLS_DIR, { recursive: true });\n log.info({ dir: SKILLS_DIR }, \"created skills directory\");\n }\n}\n\nexport interface SkillInfo {\n name: string;\n description: string;\n}\n\n/** Cached skill list, populated by scanSkills(). */\nlet cachedSkills: SkillInfo[] = [];\n\n/** Scan ~/.clawnet/.claude/skills/ and parse SKILL.md frontmatter\n * to build a list of { name, description }.\n */\nexport function scanSkills(): SkillInfo[] {\n if (!existsSync(SKILLS_DIR)) return [];\n\n let dirs: string[];\n try {\n dirs = readdirSync(SKILLS_DIR, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n log.warn(\"failed to read skills directory for scanning\");\n return [];\n }\n\n const skills: SkillInfo[] = [];\n for (const dirName of dirs) {\n const skillMd = join(SKILLS_DIR, dirName, \"SKILL.md\");\n if (!existsSync(skillMd)) continue;\n\n try {\n const content = readFileSync(skillMd, \"utf-8\");\n const parsed = parseFrontmatter(content);\n if (parsed.name) {\n skills.push({\n name: parsed.name,\n description: parsed.description || dirName,\n });\n }\n } catch (err) {\n log.debug({ skill: dirName, err }, \"failed to parse SKILL.md frontmatter\");\n }\n }\n\n cachedSkills = skills;\n log.info({ count: skills.length }, \"scanned skills\");\n return skills;\n}\n\n/** Get the cached skill list (call scanSkills() first). */\nexport function getSkillList(): SkillInfo[] {\n return cachedSkills;\n}\n\nexport interface PendingNotification {\n count: number;\n text: string;\n}\n\n/**\n * Read pending Skill evolution proposals and render a short notification.\n * Returns null if there are no pending proposals or the file is unreadable.\n */\nexport function getPendingNotification(): PendingNotification | null {\n const pendingPath = join(CLAWNET_DIR, \".claude\", \"pending-evolutions.json\");\n if (!existsSync(pendingPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(pendingPath, \"utf-8\"));\n const pending = Array.isArray(raw?.pending) ? raw.pending : [];\n if (pending.length === 0) return null;\n const lines = pending.map(\n (p: { signal?: string; skillName?: string; problem?: string; confidence?: number }) =>\n `- [${p.signal ?? \"?\"}] ${p.skillName ?? \"?\"}: ${p.problem ?? \"\"} (confidence: ${p.confidence ?? \"?\"})`,\n );\n const text =\n `有 ${pending.length} 条 Skill 进化提案待审核:\\n${lines.join(\"\\n\")}\\n` +\n `使用 skill_pending_list 查看详情,skill_pending_approve / skill_pending_reject 处理。`;\n return { count: pending.length, text };\n } catch (err) {\n log.debug({ err }, \"failed to read pending-evolutions.json\");\n return null;\n }\n}\n\n/** Parse YAML frontmatter from SKILL.md content. */\nfunction parseFrontmatter(content: string): { name: string; description: string } {\n const match = content.match(/^---\\s*\\n([\\s\\S]*?)\\n---/);\n if (!match) return { name: \"\", description: \"\" };\n\n const yaml = match[1];\n const nameMatch = yaml.match(/^name:\\s*(.+)$/m);\n const descMatch = yaml.match(/^description:\\s*(.+)$/m);\n const strip = (s: string) => s.trim().replace(/^[\"']|[\"']$/g, \"\");\n return {\n name: strip(nameMatch?.[1] ?? \"\"),\n description: strip(descMatch?.[1] ?? \"\"),\n };\n}\n\n/**\n * Ensure ~/.clawnet/mcp.json registers the unified `clawnet-mcp` server.\n *\n * Behaviour matrix (designed to safely upgrade pre-existing installs):\n * - File missing → write fresh config with clawnet-mcp.\n * - File present, no clawnet-mcp entry → add clawnet-mcp; preserve other servers.\n * - File present, clawnet-mcp at stale path → rewrite args to current server.js.\n * - File present, clawnet-mcp already correct → no-op (no disk write).\n * - File present, malformed JSON → leave alone, warn (do not destroy user state).\n * - File present, missing `mcpServers` field → inject mcpServers without dropping siblings.\n *\n * We also drop a legacy `clawnet-memory` entry IF (and only if) it points at\n * the auto-generated path inside `@mclawnet/agent/node_modules/@mclawnet/memory`.\n * That path is what older agent versions used to write; the unified clawnet-mcp\n * supersedes it. A `clawnet-memory` entry pointing elsewhere is treated as\n * user customization and preserved.\n *\n * Exported for testability — tests drive the function directly with mocked fs.\n */\nexport function ensureMcpConfig(): void {\n // Resolve the unified MCP server.js path from the installed package.\n let mcpServerPath: string;\n try {\n const req = createRequire(import.meta.url);\n const mcpPkgDir = dirname(req.resolve(\"@mclawnet/mcp-server/package.json\"));\n mcpServerPath = join(mcpPkgDir, \"dist\", \"server.js\");\n } catch {\n log.warn(\"could not resolve @mclawnet/mcp-server package path, skipping mcp.json generation\");\n return;\n }\n\n type ServerEntry = { command: string; args: string[]; env?: Record<string, string> };\n type Config = { mcpServers?: Record<string, ServerEntry> } & Record<string, unknown>;\n\n const desired: ServerEntry = { command: \"node\", args: [mcpServerPath] };\n\n // Read existing config (if any). Bail on parse error to avoid trampling\n // a hand-edited file.\n let config: Config = {};\n let fileExists = false;\n if (existsSync(MCP_CONFIG_PATH)) {\n fileExists = true;\n try {\n config = JSON.parse(readFileSync(MCP_CONFIG_PATH, \"utf-8\")) as Config;\n } catch (err) {\n log.warn({ err, path: MCP_CONFIG_PATH }, \"mcp.json malformed — leaving alone\");\n return;\n }\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n } else {\n config = { mcpServers: {} };\n }\n\n const servers = config.mcpServers!;\n let changed = false;\n\n // Inject / update clawnet-mcp.\n const existing = servers[\"clawnet-mcp\"];\n const existingMatches =\n existing &&\n existing.command === desired.command &&\n Array.isArray(existing.args) &&\n existing.args[0] === desired.args[0];\n if (!existingMatches) {\n servers[\"clawnet-mcp\"] = desired;\n changed = true;\n }\n\n // Drop legacy auto-generated clawnet-memory only.\n const legacy = servers[\"clawnet-memory\"];\n if (\n legacy &&\n legacy.command === \"node\" &&\n Array.isArray(legacy.args) &&\n typeof legacy.args[0] === \"string\" &&\n /@mclawnet\\/agent\\/node_modules\\/@mclawnet\\/memory\\/dist\\/mcp\\/server\\.js$/.test(\n legacy.args[0],\n )\n ) {\n delete servers[\"clawnet-memory\"];\n changed = true;\n }\n\n if (!changed) {\n log.debug(\"mcp.json already up-to-date — no write\");\n return;\n }\n\n try {\n mkdirSync(CLAWNET_DIR, { recursive: true });\n writeFileSync(MCP_CONFIG_PATH, JSON.stringify(config, null, 2) + \"\\n\");\n log.info(\n { path: MCP_CONFIG_PATH, fresh: !fileExists },\n fileExists ? \"updated mcp.json (clawnet-mcp ensured)\" : \"generated default mcp.json\",\n );\n } catch (err) {\n log.warn({ err }, \"failed to write mcp.json\");\n }\n}\n","/**\n * Session-pool error types and shared snapshots.\n *\n * Lives in its own file because the SessionLimitReachedError family is expected\n * to grow (RecoverableSessionError / SessionGoneError later) and session-manager.ts\n * is already close to 300 lines. The `SessionKind` union is also the type-source\n * for SessionMeta and idle-sweep classification — exporting it here keeps a\n * single source of truth that hub/UI consumers can import too.\n */\n\nexport type SessionKind = \"chat\" | \"swarm-role\";\n\n/**\n * Snapshot of pool state at the moment a saturation error is thrown.\n *\n * Kept as a plain object (not an instance) so it survives JSON.stringify when\n * forwarded to hub/UI through the error envelope.\n *\n * `byKind` uses `Record<SessionKind, number>` rather than fixed fields so a\n * future `schedule-role` kind extends naturally without API breakage.\n */\nexport interface SessionPoolSnapshot {\n used: number;\n max: number;\n byKind: Record<SessionKind, number>;\n oldestIdleSessionId: string | null;\n oldestIdleAgeMs: number | null;\n oldestIdleKind: SessionKind | null;\n}\n\n/**\n * Thrown by SessionManager.createSession when the pool is at MAX_PROCESSES.\n *\n * The `code` constant lets hub-side dispatchers branch on the error without\n * importing the class (which would tie hub to the agent package). Hub forwards\n * `code` + `details` as a `session.limit_reached` envelope to the UI.\n */\nexport class SessionLimitReachedError extends Error {\n readonly code = \"SESSION_LIMIT_REACHED\";\n\n constructor(public readonly details: SessionPoolSnapshot) {\n super(buildMessage(details));\n this.name = \"SessionLimitReachedError\";\n }\n}\n\nfunction buildMessage(d: SessionPoolSnapshot): string {\n const kindParts = Object.entries(d.byKind)\n .map(([k, n]) => `${k}=${n}`)\n .join(\", \");\n const oldest = d.oldestIdleSessionId\n ? `Oldest idle: ${d.oldestIdleSessionId} (${d.oldestIdleKind}, idle ${Math.round(\n (d.oldestIdleAgeMs ?? 0) / 1000,\n )}s).`\n : \"No idle sessions to reclaim.\";\n return `Session limit reached (${d.used}/${d.max}). ${kindParts}. ${oldest}`;\n}\n","/**\n * PR-C: Logical-state checkpoint for SessionManager.\n *\n * Lives in its own file because the checkpoint format is a stable contract\n * (versioned schema + atomic temp+rename + pid-probe recovery) that is\n * orthogonal to the in-memory session pool. Keeping it here lets us evolve\n * the schema independently and write focused unit tests without spinning up\n * a full SessionManager.\n *\n * Design references: see `docs/plans/2026-05-06-session-pool-lifecycle-design.md`\n * §5 — checkpoint is *not* a source of truth, only a recovery aid.\n */\nimport { promises as fs } from \"node:fs\";\nimport type { SessionKind } from \"./errors.js\";\n\n/**\n * One checkpointed session. `pid` is recorded **only** for the startup probe\n * (`process.kill(pid, 0)`) — the agent never tries to take over an old pid,\n * which is the safety property that prevents two agents racing on the same\n * Claude CLI child process.\n */\nexport interface CheckpointEntry {\n sessionId: string;\n kind: SessionKind;\n workDir: string;\n claudeSessionId?: string;\n agentInstanceId?: string;\n startedAt: number;\n lastActivityAt: number;\n pid: number;\n /**\n * Token-budget ladder index (0 = 32k, 1 = 16k, 2 = 8k). Persisted so a\n * SessionManager restart resumes at the same step instead of starting over\n * at 32k — otherwise a session that just escalated to 16k right before a\n * restart would re-hit the 168k wall on the very first turn after recover.\n * Undefined for entries written before this field existed (treat as 0).\n */\n currentLadderIndex?: number;\n}\n\nexport interface CheckpointFile {\n version: 1;\n agentStartedAt: number;\n entries: CheckpointEntry[];\n}\n\n/**\n * Result of `recoverFromCheckpoint`. `dead` should be reported to hub via\n * `session.died`; `orphan` is logged as a warning but not actioned (we don't\n * SIGKILL processes we don't own — see design §5).\n */\nexport interface RecoveryReport {\n dead: CheckpointEntry[];\n orphan: CheckpointEntry[];\n}\n\n/**\n * Atomically write `data` to `path` via temp+rename — POSIX guarantees rename\n * atomicity within the same filesystem, so a partial write or kill -9 mid-flush\n * leaves either the previous version or the new version, never a corrupted\n * file. Mirrors hermes `tools/process_registry.py:19-24`.\n */\nexport async function atomicWriteJson(\n path: string,\n data: unknown,\n): Promise<void> {\n const tmp = `${path}.tmp`;\n await fs.writeFile(tmp, JSON.stringify(data, null, 2));\n await fs.rename(tmp, path);\n}\n\n/**\n * Read the checkpoint file. Returns `null` (not throws) on ENOENT — first\n * boot has no file, and the caller treats that the same as \"empty file\".\n * Throws on any other I/O error and on JSON parse failure: a corrupt\n * checkpoint should surface loudly rather than silently lose state.\n */\nexport async function readCheckpoint(\n path: string,\n): Promise<CheckpointFile | null> {\n let raw: string;\n try {\n raw = await fs.readFile(path, \"utf8\");\n } catch (err: any) {\n if (err && err.code === \"ENOENT\") return null;\n throw err;\n }\n return JSON.parse(raw) as CheckpointFile;\n}\n\n/**\n * Standard pid-liveness probe. `process.kill(pid, 0)` doesn't actually send\n * a signal — kernel just returns success/ESRCH/EPERM based on whether the\n * pid exists and whether we have permission. `EPERM` means the pid exists\n * but isn't owned by us → still alive, just not killable from here.\n *\n * Behavior differences across platforms:\n * - POSIX (Linux/macOS): exact semantics described above.\n * - Windows: Node's runtime translates to OpenProcess; ESRCH/EPERM still\n * surface but the boundary cases are rarer. Acceptable; the worst case\n * is a slightly stale \"alive\" classification on Windows.\n */\nexport function isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err: any) {\n return err && err.code === \"EPERM\";\n }\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createLogger } from \"@mclawnet/logger\";\nimport type { AgentGenericRequest } from \"@mclawnet/shared\";\nimport type { HubConnection } from \"./hub-connection.js\";\n\nconst log = createLogger({ module: \"brain-bridge\" });\n\nexport type BrainSetupStatus = \"not_installed\" | \"needs_config\" | \"ready\";\n\nexport interface BrainBridgeOptions {\n brainHomePath?: string;\n brainCorePath?: string;\n}\n\nexport class BrainBridge {\n private brainHome: string;\n private brainCorePath: string;\n\n constructor(\n private hub: HubConnection,\n options?: BrainBridgeOptions\n ) {\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n this.brainHome =\n options?.brainHomePath ||\n process.env.BRAIN_HOME ||\n join(home, \"BrainData\");\n this.brainCorePath =\n options?.brainCorePath || join(home, \".brain\", \"BrainCore\");\n\n this.hub.registerNamespace(\"brain\", (msg) => this.handleRequest(msg));\n log.info(\n { brainHome: this.brainHome, brainCorePath: this.brainCorePath },\n \"BrainBridge initialized\"\n );\n }\n\n async handleRequest(\n msg: AgentGenericRequest\n ): Promise<Record<string, unknown>> {\n log.info({ action: msg.action, requestId: msg.requestId }, \"brain request\");\n switch (msg.action) {\n case \"setup_status\": {\n const status = this.checkSetup();\n log.info({ status }, \"setup_status result\");\n return { status };\n }\n case \"get_briefing\":\n return await this.getBriefing(msg.params.date as string | undefined);\n case \"get_meeting_recap\":\n return await this.getMeetingRecap(msg.params.recapPath as string);\n default:\n log.warn({ action: msg.action }, \"unknown brain action\");\n throw new Error(`Unknown brain action: ${msg.action}`);\n }\n }\n\n checkSetup(): BrainSetupStatus {\n if (!existsSync(this.brainCorePath)) {\n return \"not_installed\";\n }\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n const installJson = join(home, \".brain\", \"install.json\");\n if (!existsSync(installJson)) {\n return \"needs_config\";\n }\n if (!existsSync(this.brainHome)) {\n return \"needs_config\";\n }\n return \"ready\";\n }\n\n /** Read the most recent daily briefing report */\n private async getBriefing(\n date?: string\n ): Promise<Record<string, unknown>> {\n const targetDate = date || new Date().toISOString().slice(0, 10);\n const reportsDir = join(this.brainHome, \"reports\", \"daily\");\n\n if (!existsSync(reportsDir)) {\n log.info({ reportsDir }, \"get_briefing: reports dir not found\");\n return { briefing: null, actions: [], projects: [], meetings: [], feed: [] };\n }\n\n const files = readdirSync(reportsDir)\n .filter((f: string) => f.includes(targetDate) && f.endsWith(\".md\"))\n .sort()\n .reverse();\n\n if (files.length === 0) {\n log.info({ targetDate }, \"get_briefing: no report for date\");\n return { briefing: null, actions: [], projects: [], meetings: [], feed: [] };\n }\n\n log.info({ targetDate, file: files[0] }, \"get_briefing: reading report\");\n\n const content = readFileSync(join(reportsDir, files[0]), \"utf-8\");\n\n // Extract TL;DR\n const tldrMatch = content.match(/## TL;DR\\n([\\s\\S]*?)(?=\\n---|\\n## )/);\n const tldr = tldrMatch ? tldrMatch[1].trim() : content.slice(0, 200);\n\n const actions = this.parseActions(content);\n const projects = this.parseProjects(content);\n const meetings = this.parseMeetings(content);\n const feed = this.parseFeed(content);\n\n log.info(\n { actions: actions.length, projects: projects.length, meetings: meetings.length, feed: feed.length },\n \"get_briefing: parsed\"\n );\n\n return {\n briefing: {\n date: targetDate,\n tldr,\n generatedAt: new Date().toISOString(),\n },\n actions,\n projects,\n meetings,\n feed,\n };\n }\n\n /** Parse \"## Action Required\" section into ActionItem[] */\n private parseActions(content: string): Array<Record<string, unknown>> {\n const sectionMatch = content.match(/## Action Required\\n([\\s\\S]*?)(?=\\n---|\\n## [^A])/);\n if (!sectionMatch) return [];\n\n const section = sectionMatch[1];\n const items: Array<Record<string, unknown>> = [];\n let currentPriority: string = \"p3\";\n let idCounter = 0;\n\n for (const line of section.split(\"\\n\")) {\n // Detect priority headers\n if (line.includes(\"🔴 Today\")) { currentPriority = \"p1\"; continue; }\n if (line.includes(\"🟡 This Week\")) { currentPriority = \"p2\"; continue; }\n if (line.includes(\"⚪ FYI\") || line.includes(\"FYI —\")) { currentPriority = \"p4\"; continue; }\n\n // Numbered items: \"1. **Title** → description\"\n const numberedMatch = line.match(/^\\d+\\.\\s+\\*\\*(.+?)\\*\\*\\s*[→—–-]\\s*(.+)/);\n if (numberedMatch) {\n items.push({\n id: `action-${++idCounter}`,\n priority: currentPriority,\n title: `${numberedMatch[1].trim()} — ${numberedMatch[2].trim()}`,\n source: this.guessSource(numberedMatch[2]),\n timeAgo: \"\",\n done: false,\n });\n continue;\n }\n\n // Bullet items under FYI: \"- description\"\n if (currentPriority === \"p4\") {\n const bulletMatch = line.match(/^-\\s+(.+)/);\n if (bulletMatch) {\n items.push({\n id: `action-${++idCounter}`,\n priority: \"p4\",\n title: bulletMatch[1].replace(/\\*\\*/g, \"\").trim(),\n source: this.guessSource(bulletMatch[1]),\n timeAgo: \"\",\n done: false,\n });\n }\n }\n }\n\n return items;\n }\n\n /** Parse project sections \"## 🔵 ProjectName\" with Status tables */\n private parseProjects(content: string): Array<Record<string, unknown>> {\n const projects: Array<Record<string, unknown>> = [];\n // Match \"## 🔵 ProjectName\" sections\n const projectRegex = /## 🔵\\s+(.+)\\n([\\s\\S]*?)(?=\\n## |$)/g;\n let match;\n\n while ((match = projectRegex.exec(content)) !== null) {\n const name = match[1].trim();\n const body = match[2];\n\n // Parse status table: | 🟡 At Risk | ... | or | 🟢 On Track | ... |\n let status: string = \"on_track\";\n const statusMatch = body.match(/\\|\\s*(🟡|🔴|🟢)\\s*(.*?)\\s*\\|/);\n if (statusMatch) {\n const icon = statusMatch[1];\n if (icon === \"🔴\") status = \"blocked\";\n else if (icon === \"🟡\") status = \"blocked\";\n else if (icon === \"🟢\") status = \"good\";\n }\n\n // Count \"Teams Chats\" subsections (#### headers under ### Teams Chats)\n const teamsSection = body.match(/### Teams Chats\\n([\\s\\S]*?)(?=\\n### [^T]|\\n---|\\n## |$)/);\n let newMessages = 0;\n if (teamsSection) {\n const chatHeaders = teamsSection[1].match(/^####/gm);\n newMessages = chatHeaders ? chatHeaders.length : 0;\n }\n\n // Count \"Key Decisions\" items\n let pendingDecisions = 0;\n const decisionsMatches = body.match(/\\*\\*\\[(?:Decided|Leaning)\\]\\*\\*/g);\n if (decisionsMatches) pendingDecisions = decisionsMatches.length;\n\n projects.push({\n slug: name.toLowerCase().replace(/[^a-z0-9]+/g, \"-\"),\n name,\n status,\n newMessages,\n pendingDecisions,\n });\n }\n\n return projects;\n }\n\n /** Parse meetings from \"### Meetings\" subsections */\n private parseMeetings(content: string): Array<Record<string, unknown>> {\n const meetings: Array<Record<string, unknown>> = [];\n // Find all \"#### MeetingTitle\" under \"### Meetings\" sections\n const meetingSectionRegex = /### Meetings\\n([\\s\\S]*?)(?=\\n### [^M]|\\n---|\\n## |$)/g;\n let sectionMatch;\n let idCounter = 0;\n\n while ((sectionMatch = meetingSectionRegex.exec(content)) !== null) {\n const section = sectionMatch[1];\n // Each meeting: \"#### Title\\n\\n📅 time | status | participants | host\"\n const meetingRegex = /####\\s+(.+)\\n\\n📅\\s*(\\S+)\\s+\\w+\\s*\\|\\s*(\\w+)/g;\n let m;\n\n while ((m = meetingRegex.exec(section)) !== null) {\n const title = m[1].trim();\n const time = m[2].trim();\n const statusWord = m[3].toLowerCase();\n\n let status = \"completed\";\n if (statusWord === \"missed\") status = \"completed\"; // still show recap\n else if (statusWord === \"upcoming\") status = \"upcoming\";\n else if (statusWord.includes(\"progress\")) status = \"in_progress\";\n\n // Get the text slice for this specific meeting (from current match to next #### or section end)\n const meetingEndIdx = section.indexOf(\"\\n####\", m.index + m[0].length);\n const meetingSlice = meetingEndIdx !== -1\n ? section.slice(m.index, meetingEndIdx)\n : section.slice(m.index);\n\n const recapMatch = meetingSlice.match(/📎\\s*\\[Full recap\\]\\((.+?)\\)/);\n const recapPath = recapMatch ? recapMatch[1] : undefined;\n\n meetings.push({\n id: `meeting-${++idCounter}`,\n time,\n title,\n status,\n hasRecap: !!recapPath,\n recapPath,\n });\n }\n }\n\n return meetings;\n }\n\n /** Parse feed items from Teams Chats subsections across all project sections and Announcements */\n private parseFeed(content: string): Array<Record<string, unknown>> {\n const items: Array<Record<string, unknown>> = [];\n let idCounter = 0;\n\n // 1) Extract feed items from \"### Teams Chats\" under \"## 🔵 ProjectName\" sections\n const projectRegex = /## 🔵\\s+(.+)\\n([\\s\\S]*?)(?=\\n## |$)/g;\n let projectMatch;\n\n while ((projectMatch = projectRegex.exec(content)) !== null) {\n const projectName = projectMatch[1].trim();\n const projectBody = projectMatch[2];\n\n this.extractTeamsChatItems(projectBody, projectName, items, idCounter);\n idCounter = items.length;\n }\n\n // 2) Extract feed items from \"## 📢 Announcements & FYI\" section (no project)\n const announcementMatch = content.match(/## 📢\\s+Announcements[^\\n]*\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (announcementMatch) {\n this.extractTeamsChatItems(announcementMatch[1], \"\", items, idCounter);\n }\n\n return items;\n }\n\n /** Extract chat items from a \"### Teams Chats\" subsection within a body block */\n private extractTeamsChatItems(\n body: string,\n project: string,\n items: Array<Record<string, unknown>>,\n _startId: number\n ): void {\n // Find \"### Teams Chats\" subsection\n const teamsChatMatch = body.match(/### Teams Chats\\n([\\s\\S]*?)(?=\\n### [^T]|\\n---|\\n## |$)/);\n if (!teamsChatMatch) return;\n\n const teamsSection = teamsChatMatch[1];\n\n // Find \"#### ChatTitle — Priority\" headers and their content\n const chatRegex = /####\\s+(.+?)(?:\\s*—\\s*(.+))?\\n([\\s\\S]*?)(?=\\n####|\\n###|\\n---|$)/g;\n let chatMatch;\n\n while ((chatMatch = chatRegex.exec(teamsSection)) !== null) {\n const chatBody = chatMatch[3];\n\n // Extract bold names like **Person Name** as sender\n const senderMatch = chatBody.match(/\\*\\*(.+?)\\*\\*/);\n const sender = senderMatch ? senderMatch[1].trim() : \"Unknown\";\n\n // Extract content: first meaningful line after the sender, or first sentence\n let contentPreview = \"\";\n const lines = chatBody.split(\"\\n\").filter((l: string) => l.trim().length > 0);\n for (const line of lines) {\n // Skip lines that are just metadata (timestamps, status indicators)\n const cleaned = line.replace(/\\*\\*.*?\\*\\*/g, \"\").replace(/[>*-]/g, \"\").trim();\n if (cleaned.length > 10) {\n contentPreview = cleaned.slice(0, 100);\n break;\n }\n }\n // Fallback: use the entire chat body trimmed\n if (!contentPreview && lines.length > 0) {\n contentPreview = lines[0].replace(/\\*\\*/g, \"\").trim().slice(0, 100);\n }\n\n // Try to extract a time from the body (e.g., \"10:30\" or \"14:23\")\n const timeMatch = chatBody.match(/(\\d{1,2}:\\d{2})/);\n const time = timeMatch ? timeMatch[1] : \"\";\n\n items.push({\n id: `feed-${items.length + 1}`,\n time,\n source: \"teams\",\n sender,\n content: contentPreview,\n project: project || undefined,\n });\n }\n }\n\n /** Fetch and parse a meeting recap file */\n private async getMeetingRecap(recapPath: string): Promise<Record<string, unknown>> {\n if (!recapPath) {\n return { error: \"No recap path provided\" };\n }\n const fullPath = join(this.brainHome, recapPath);\n if (!existsSync(fullPath)) {\n log.warn({ fullPath }, \"meeting recap file not found\");\n return { error: \"Recap file not found\" };\n }\n const content = readFileSync(fullPath, \"utf-8\");\n return { recap: this.parseRecapMarkdown(content) };\n }\n\n /** Parse meeting recap markdown into structured sections */\n private parseRecapMarkdown(content: string): Record<string, unknown> {\n // Extract TL;DR / Summary section\n const tldrMatch = content.match(/##\\s*(?:TL;DR|Summary|概要)\\n([\\s\\S]*?)(?=\\n## |\\n---|\\n$)/);\n const tldr = tldrMatch ? tldrMatch[1].trim() : \"\";\n\n // Extract \"Relevant to You\" / \"与你相关\" section\n const relevantMatch = content.match(/##\\s*(?:与你相关|Relevant|For You|Action for You)\\n([\\s\\S]*?)(?=\\n## |\\n---|\\n$)/);\n const relevant = relevantMatch ? relevantMatch[1].trim() : \"\";\n\n // Extract \"Decisions\" / \"决定事项\" / \"Key Decisions\" section\n const decisionsMatch = content.match(/##\\s*(?:决定事项|Decisions|Key Decisions)\\n([\\s\\S]*?)(?=\\n## |\\n---|\\n$)/);\n const decisions = decisionsMatch ? decisionsMatch[1].trim() : \"\";\n\n // Extract \"Action Items\" / \"行动项\" section\n const actionsMatch = content.match(/##\\s*(?:行动项|Action Items|Next Steps)\\n([\\s\\S]*?)(?=\\n## |\\n---|\\n$)/);\n const actionItems = actionsMatch ? actionsMatch[1].trim() : \"\";\n\n return {\n tldr,\n relevant,\n decisions,\n actionItems,\n rawMarkdown: content,\n };\n }\n\n /** Guess message source from text content */\n private guessSource(text: string): string {\n const lower = text.toLowerCase();\n if (lower.includes(\"teams\")) return \"teams\";\n if (lower.includes(\"email\") || lower.includes(\"mail\")) return \"email\";\n if (lower.includes(\"meeting\") || lower.includes(\"sync\")) return \"meeting\";\n if (lower.includes(\"pr\") || lower.includes(\"ado\") || lower.includes(\"work item\")) return \"ado\";\n return \"teams\";\n }\n}\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { extname, isAbsolute } from \"node:path\";\nimport { createLogger } from \"@mclawnet/logger\";\nimport type { AgentGenericRequest } from \"@mclawnet/shared\";\nimport type { HubConnection } from \"./hub-connection.js\";\n\nconst log = createLogger({ module: \"fs-bridge\" });\n\nconst MAX_TEXT_SIZE = 5 * 1024 * 1024; // 5MB\n\nconst MIME_MAP: Record<string, string> = {\n \".ts\": \"text/typescript\", \".tsx\": \"text/typescript\",\n \".js\": \"text/javascript\", \".jsx\": \"text/javascript\",\n \".json\": \"application/json\", \".html\": \"text/html\",\n \".css\": \"text/css\", \".md\": \"text/markdown\",\n \".py\": \"text/x-python\", \".sh\": \"text/x-shellscript\",\n \".yaml\": \"text/yaml\", \".yml\": \"text/yaml\",\n \".xml\": \"text/xml\", \".sql\": \"text/x-sql\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\", \".jpg\": \"image/jpeg\", \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\", \".webp\": \"image/webp\",\n \".mp4\": \"video/mp4\", \".webm\": \"video/webm\",\n \".mp3\": \"audio/mpeg\", \".wav\": \"audio/wav\",\n};\n\nfunction getMimeType(filePath: string): string {\n return MIME_MAP[extname(filePath).toLowerCase()] || \"application/octet-stream\";\n}\n\nfunction isTextMime(mime: string): boolean {\n return mime.startsWith(\"text/\") || mime === \"application/json\" || mime === \"image/svg+xml\";\n}\n\nexport class FsBridge {\n constructor(private hub: HubConnection) {\n this.hub.registerNamespace(\"fs\", (msg) => this.handleRequest(msg));\n log.info(\"FsBridge initialized\");\n }\n\n async handleRequest(msg: AgentGenericRequest): Promise<Record<string, unknown>> {\n log.info({ action: msg.action, requestId: msg.requestId }, \"fs request\");\n switch (msg.action) {\n case \"read\":\n return this.readFile(msg.params);\n default:\n throw new Error(`Unknown fs action: ${msg.action}`);\n }\n }\n\n private readFile(params: Record<string, unknown>): Record<string, unknown> {\n const filePath = params.path as string;\n if (!filePath) throw new Error(\"Missing path parameter\");\n\n // Security: only allow absolute paths (no relative traversal tricks)\n if (!isAbsolute(filePath)) {\n throw new Error(`Access denied: only absolute paths allowed`);\n }\n\n if (!existsSync(filePath)) {\n throw new Error(`File not found: ${filePath}`);\n }\n\n const stat = statSync(filePath);\n if (!stat.isFile()) {\n throw new Error(`Not a file: ${filePath}`);\n }\n\n const mimeType = getMimeType(filePath);\n const totalSize = stat.size;\n\n if (isTextMime(mimeType)) {\n const raw = readFileSync(filePath, \"utf-8\");\n const truncated = raw.length > MAX_TEXT_SIZE;\n const content = truncated ? raw.slice(0, MAX_TEXT_SIZE) : raw;\n return { content, encoding: \"utf-8\", size: content.length, totalSize, mimeType, truncated };\n }\n\n // Binary: base64\n const buf = readFileSync(filePath);\n const truncated = buf.length > MAX_TEXT_SIZE;\n const slice = truncated ? buf.subarray(0, MAX_TEXT_SIZE) : buf;\n return { content: slice.toString(\"base64\"), encoding: \"base64\", size: slice.length, totalSize, mimeType, truncated };\n }\n}\n","import type { SwarmCoordinator } from \"@mclawnet/swarm\";\nimport { createLogger } from \"@mclawnet/logger\";\n\nconst log = createLogger({ module: \"agent:swarm-bridge\" });\n\n/**\n * Build the SessionManager.onSessionStarted handler used by start.ts.\n *\n * Two responsibilities:\n * 1. Forward the early `claude.session_started` frame to the hub so the\n * central db can backfill `claude_session_id` (existing behavior).\n * 2. If the sessionId belongs to an in-process swarm role (convention\n * `${swarmId}::${instanceId}`), also push the claudeSessionId into the\n * local SwarmCoordinator so it's captured in the snapshot — without\n * having to wait for the hub round-trip. This is what lets a restarted\n * agent `--resume` the right per-role conversation (Task 4).\n */\nexport function createSwarmAwareSessionStartedHandler(deps: {\n hub: { send: (msg: any) => unknown };\n swarmCoordinator: Pick<SwarmCoordinator, \"setRoleClaudeSessionIdBySession\" | \"isSwarmSession\">;\n}): (sessionId: string, info: { claudeSessionId: string }) => void {\n return (sessionId, info) => {\n deps.hub.send({\n type: \"claude.session_started\",\n sessionId,\n claudeSessionId: info.claudeSessionId,\n });\n\n if (deps.swarmCoordinator.isSwarmSession(sessionId)) {\n try {\n const ok = deps.swarmCoordinator.setRoleClaudeSessionIdBySession(\n sessionId,\n info.claudeSessionId,\n );\n if (!ok) {\n log.debug(\n { sessionId },\n \"session_started for swarm-shaped sessionId, but no matching role (already destroyed?)\",\n );\n }\n } catch (err) {\n log.warn({ err, sessionId }, \"failed to bridge session_started into swarm\");\n }\n }\n };\n}\n"],"mappings":"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","names":["homedir","join","createLogger","log","createLogger","log","log","createLogger","previewFields","existsSync","readdirSync","readFileSync","join","homedir","createLogger","log","log","createLogger","process","previewFields","existsSync","readFileSync","readdirSync","join","createLogger","log","existsSync","readFileSync","statSync","createLogger","log","stat","truncated","createLogger","log","createLogger","log","join","homedir"]}