@dev-anywhere/proxy 0.1.1 → 0.1.3
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.
- package/README.md +4 -1
- package/dist/{chunk-TG7JPHE5.js → chunk-JGGDVMY5.js} +2 -2
- package/dist/{chunk-QXOARRC2.js → chunk-ODK6N2NP.js} +2 -2
- package/dist/{chunk-DFLQ3TFT.js → chunk-RFBTVZ2X.js} +16 -1
- package/dist/chunk-RFBTVZ2X.js.map +1 -0
- package/dist/{chunk-CDKXSDAV.js → chunk-TX6HNHDB.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/serve.js +242 -51
- package/dist/serve.js.map +1 -1
- package/dist/session-worker.js +2 -2
- package/dist/{terminal-GIU6MXOR.js → terminal-ES6I5W32.js} +4 -4
- package/package.json +3 -3
- package/dist/chunk-DFLQ3TFT.js.map +0 -1
- /package/dist/{chunk-TG7JPHE5.js.map → chunk-JGGDVMY5.js.map} +0 -0
- /package/dist/{chunk-QXOARRC2.js.map → chunk-ODK6N2NP.js.map} +0 -0
- /package/dist/{chunk-CDKXSDAV.js.map → chunk-TX6HNHDB.js.map} +0 -0
- /package/dist/{terminal-GIU6MXOR.js.map → terminal-ES6I5W32.js.map} +0 -0
package/dist/serve.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/serve.ts","../src/serve/session-manager.ts","../src/serve/relay-connection.ts","../src/serve/message-queue.ts","../src/common/config.ts","../src/serve/handlers/control-messages.ts","../src/serve/session-history.ts","../src/serve/command-discovery.ts","../src/serve/path-errors.ts","../src/serve/worker-registry.ts","../src/serve/session-termination.ts","../src/serve/clipboard-image-upload.ts","../src/serve/pty-input.ts","../src/serve/relay-input-handlers.ts","../src/serve/relay-history-handlers.ts","../src/serve/relay-permission-handlers.ts","../src/serve/relay-resource-handlers.ts","../src/serve/relay-session-create-handler.ts","../src/serve/hosted-pty-registry.ts","../src/serve/relay-router.ts","../src/serve/json-observer.ts","../src/serve/permission-broker.ts","../src/serve/hook-event-router.ts","../src/serve/agent-status-registry.ts","../src/serve/session-broadcast.ts","../src/serve/service-files.ts","../src/serve/pty-state-guard.ts","../src/serve/pty-semantic-lifecycle.ts","../src/serve/terminal-ipc.ts","../src/serve/hook-registry.ts","../src/serve/hook-server.ts","../src/serve/provider-hook-runtime.ts"],"sourcesContent":["import { createServer, type Socket } from \"node:net\";\nimport { unlinkSync, writeFileSync, chmodSync, rmSync } from \"node:fs\";\nimport { SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"./common/logger.js\";\nimport { SessionManager } from \"./serve/session-manager.js\";\nimport { RelayConnection } from \"./serve/relay-connection.js\";\nimport {\n SOCK_PATH,\n PID_PATH,\n STOPPED_PATH,\n SESSIONS_PATH,\n PROXY_ID_PATH,\n PROFILE_NAME,\n ensureProfileWorkspace,\n sessionPaths,\n} from \"./common/paths.js\";\nimport { buildProviderEnv, loadConfig } from \"./common/config.js\";\nimport { serializeIpc } from \"./ipc/ipc-protocol.js\";\nimport { createControlMessageHandlers } from \"./serve/handlers/control-messages.js\";\nimport { WorkerRegistry } from \"./serve/worker-registry.js\";\nimport { RelayRouter } from \"./serve/relay-router.js\";\nimport { JsonObserver } from \"./serve/json-observer.js\";\nimport { PermissionBroker } from \"./serve/permission-broker.js\";\nimport { HookEventRouter } from \"./serve/hook-event-router.js\";\nimport { AgentStatusRegistry } from \"./serve/agent-status-registry.js\";\nimport { HostedPtyRegistry } from \"./serve/hosted-pty-registry.js\";\nimport { SeqCounter } from \"./common/seq-counter.js\";\nimport {\n broadcastSessionList,\n broadcastSessionSync,\n changeSessionState,\n touchSessionActivity,\n} from \"./serve/session-broadcast.js\";\nimport { cleanupStaleResources, getProxyName } from \"./serve/service-files.js\";\nimport { handleTerminalConnection } from \"./serve/terminal-ipc.js\";\nimport { createProviderHookRuntime } from \"./serve/provider-hook-runtime.js\";\nimport type { ProviderId } from \"./providers/types.js\";\n\nfunction resolveInterruptedApprovals(\n permissionBroker: PermissionBroker,\n hookEventRouter: HookEventRouter,\n relay: RelayConnection,\n sessionId: string,\n): void {\n const approvals = permissionBroker.listSession(sessionId);\n if (approvals.length === 0) return;\n\n const message = \"Permission request was interrupted in the PTY.\";\n for (const approval of approvals) {\n if (!permissionBroker.resolve(approval.requestId, { behavior: \"deny\", message })) continue;\n hookEventRouter.onPermissionResolved(\n approval.sessionId,\n approval.provider,\n approval.requestId,\n \"deny\",\n { toolName: approval.toolName, toolInput: approval.input },\n );\n relay.sendRaw(\n JSON.stringify({\n type: \"permission_decision_result\",\n sessionId: approval.sessionId,\n requestId: approval.requestId,\n outcome: \"deny\",\n delivered: true,\n message,\n }),\n );\n }\n serviceLogger.info(\n { sessionId, count: approvals.length },\n \"Pending approvals cleared after PTY interruption\",\n );\n}\n\nexport interface ServiceOptions {\n relayUrl?: string;\n relayName?: string;\n}\n\nfunction parseServiceOptions(argv: readonly string[]): ServiceOptions {\n const options: ServiceOptions = {};\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--relay\") {\n const relayName = argv[i + 1];\n if (!relayName || relayName.startsWith(\"-\")) {\n throw new Error(\"Missing value for --relay\");\n }\n options.relayName = relayName;\n i++;\n continue;\n }\n if (arg.startsWith(\"--relay=\")) {\n const relayName = arg.slice(\"--relay=\".length);\n if (!relayName) throw new Error(\"Missing value for --relay\");\n options.relayName = relayName;\n }\n }\n return options;\n}\n\nexport async function startService(options?: ServiceOptions): Promise<void> {\n ensureProfileWorkspace();\n await cleanupStaleResources();\n try {\n unlinkSync(STOPPED_PATH);\n } catch {\n // STOPPED 文件不存在时忽略\n }\n\n const permissionBroker = new PermissionBroker();\n const agentStatusRegistry = new AgentStatusRegistry();\n let unregisterHookSession: (sessionId: string) => void = () => {};\n const sessionManager = new SessionManager({\n persistPath: SESSIONS_PATH,\n onSessionRemoved: (id, context) => {\n if (!context?.preserveProviderHooks) {\n unregisterHookSession(id);\n }\n permissionBroker.cleanupSession(id, \"session removed\");\n agentStatusRegistry.delete(id);\n const paths = sessionPaths(id);\n try {\n rmSync(paths.dir, { recursive: true, force: true });\n } catch {\n // 会话目录清理失败不影响主流程\n }\n },\n });\n sessionManager.startReaper();\n\n const terminalSockets = new Map<string, Socket>();\n const proxyName = getProxyName();\n\n // 连接中转服务器:优先用调用方传入的 relayUrl,否则从配置文件读取\n // relay 是 proxy 存在的必要前提,未配置直接 fail-fast,不再支持\"本地独立\"模式\n let proxyConfig = loadConfig({ relayName: options?.relayName });\n const getProviderEnv = (): NodeJS.ProcessEnv => buildProviderEnv(proxyConfig, process.env);\n const getAgentCliSuggestions = (): Partial<Record<ProviderId, string[]>> =>\n proxyConfig.agentCliSuggestions;\n const setAgentCliPath = (provider: ProviderId, path: string): void => {\n const field = provider === \"claude\" ? \"claudeBin\" : \"codexBin\";\n const existing = proxyConfig.agentCliSuggestions[provider] ?? [];\n proxyConfig = {\n ...proxyConfig,\n [field]: path,\n agentCliSuggestions: {\n ...proxyConfig.agentCliSuggestions,\n [provider]: [path, ...existing.filter((candidate) => candidate !== path)],\n },\n sources: {\n ...proxyConfig.sources,\n [field]: \"file\",\n },\n };\n };\n const relayUrl = options?.relayUrl ?? proxyConfig.relayUrl;\n const relayToken = proxyConfig.relayToken;\n const statusConfig = {\n profile: PROFILE_NAME,\n relayName: proxyConfig.relayName,\n relayNameSource: proxyConfig.sources.relayName,\n relayUrl,\n relayUrlSource: proxyConfig.sources.relayUrl,\n relayTokenSource: proxyConfig.sources.relayToken,\n hookPort: proxyConfig.hookPort ?? 17654,\n hookPortSource: proxyConfig.sources.hookPort,\n };\n if (!relayUrl) {\n const msg = `Relay URL is required. Set relays.${proxyConfig.relayName}.url in ~/.dev-anywhere/config.json or pass --relay <name>.`;\n serviceLogger.error(msg);\n console.error(msg);\n process.exit(1);\n }\n const relayConnection = new RelayConnection(relayUrl, {\n name: proxyName,\n token: relayToken,\n proxyIdPath: PROXY_ID_PATH,\n });\n const relaySend = (data: string): void => relayConnection.sendRaw(data);\n const controlHandlers = createControlMessageHandlers(relaySend, sessionManager);\n\n // 两个观察通道共用同一个底层 changeSessionState 原语;由 FSM 按 session.mode 路由到对应转换表\n const observerChangeState = (sessionId: string, next: SessionState): boolean =>\n changeSessionState(sessionManager, relayConnection, sessionId, next);\n const observerTouchActivity = (sessionId: string): boolean =>\n touchSessionActivity(sessionManager, relayConnection, sessionId);\n const emitAgentStatus = (sessionId: string, phase: AgentStatusPayload[\"phase\"]): void => {\n const session = sessionManager.getSession(sessionId);\n if (!session) return;\n const payload: AgentStatusPayload = {\n provider: session.provider,\n phase,\n seq: new SeqCounter(sessionId).next(),\n updatedAt: Date.now(),\n };\n agentStatusRegistry.set(sessionId, payload);\n relayConnection.sendRaw(JSON.stringify({ type: \"agent_status\", sessionId, payload }));\n };\n const jsonObserver = new JsonObserver({\n changeSessionState: observerChangeState,\n emitAgentStatus,\n });\n const hookRuntime = await createProviderHookRuntime({\n hookPort: proxyConfig.hookPort,\n permissionBroker,\n sessionManager,\n relayConnection,\n agentStatusRegistry,\n changeSessionState: observerChangeState,\n });\n unregisterHookSession = (sessionId) => hookRuntime.hookRegistry.unregisterSession(sessionId);\n\n // WorkerRegistry 建在 relay 之后、listener 之前;构造期订阅 envelope_dropped 事件\n const workerRegistry = new WorkerRegistry({\n sessionManager,\n permissionBroker,\n relayConnection,\n jsonObserver,\n touchSessionActivity: observerTouchActivity,\n getProviderEnv,\n });\n const hostedPtyRegistry = new HostedPtyRegistry({\n sessionManager,\n relayConnection,\n getProviderEnv,\n changeSessionState: observerChangeState,\n touchSessionActivity: observerTouchActivity,\n onTurnComplete: (sessionId) => {\n resolveInterruptedApprovals(\n permissionBroker,\n hookRuntime.hookEventRouter,\n relayConnection,\n sessionId,\n );\n emitAgentStatus(sessionId, \"idle\");\n },\n onSessionClosed: (sessionId) => {\n controlHandlers.cleanup(sessionId);\n agentStatusRegistry.delete(sessionId);\n broadcastSessionList(relayConnection, sessionManager);\n },\n });\n\n relayConnection.connect();\n serviceLogger.info(\n {\n relayName: proxyConfig.relayName,\n profile: PROFILE_NAME,\n relayUrl,\n proxyName,\n tokenSet: !!relayToken,\n relayUrlSource: proxyConfig.sources.relayUrl,\n },\n \"Connecting to relay server\",\n );\n\n const relayRouter = new RelayRouter({\n sessionManager,\n workerRegistry,\n controlHandlers,\n relayConnection,\n relaySend,\n terminalSockets,\n hostedPtyRegistry,\n broadcastSessionList: () => broadcastSessionList(relayConnection, sessionManager),\n broadcastSessionSync: (session) => broadcastSessionSync(relayConnection, session),\n jsonObserver,\n createHookContext: hookRuntime.createHookContext,\n cleanupHookContext: (sessionId) => hookRuntime.hookRegistry.unregisterSession(sessionId),\n permissionBroker,\n hookEventRouter: hookRuntime.hookEventRouter,\n agentStatusRegistry,\n getProviderEnv,\n getAgentCliSuggestions,\n setAgentCliPath,\n });\n\n relayConnection.on(\"message\", (msg: Record<string, unknown>) => relayRouter.handle(msg));\n relayConnection.on(\"connected\", () => {\n controlHandlers.reinitializeOnReconnect();\n broadcastBridgeStatus(true);\n });\n relayConnection.on(\"disconnected\", () => {\n broadcastBridgeStatus(false);\n });\n\n // 把 relay 连接状态广播给所有已注册的 terminal,终端进程会 stderr 打 banner 提示用户\n function broadcastBridgeStatus(connected: boolean): void {\n const msg = serializeIpc({ type: \"bridge_status\", connected });\n for (const [, sock] of terminalSockets) {\n if (sock.writable) sock.write(msg);\n }\n }\n\n await workerRegistry.reconnectAll();\n\n const server = createServer((socket) => {\n handleTerminalConnection(socket, {\n sessionManager,\n workerRegistry,\n terminalSockets,\n hostedPtyRegistry,\n relayConnection,\n controlHandlers,\n agentStatusRegistry,\n permissionBroker,\n hookEventRouter: hookRuntime.hookEventRouter,\n createHookContext: hookRuntime.createHookContext,\n emitAgentStatus,\n config: statusConfig,\n resolveInterruptedApprovals: (sessionId) =>\n resolveInterruptedApprovals(\n permissionBroker,\n hookRuntime.hookEventRouter,\n relayConnection,\n sessionId,\n ),\n });\n });\n\n server.listen(SOCK_PATH, () => {\n writeFileSync(PID_PATH, String(process.pid));\n chmodSync(SOCK_PATH, 0o600);\n serviceLogger.info({ pid: process.pid, sock: SOCK_PATH }, \"Service started\");\n });\n\n async function shutdown(): Promise<void> {\n serviceLogger.info(\"Shutting down service\");\n sessionManager.stopReaper();\n await hookRuntime.hookServer.close();\n relayConnection.close();\n workerRegistry.destroyAll();\n hostedPtyRegistry.destroyAll();\n server.close();\n try {\n unlinkSync(SOCK_PATH);\n } catch {\n // 关闭时 socket 文件可能已被删除\n }\n try {\n unlinkSync(PID_PATH);\n } catch {\n // 关闭时 PID 文件可能已被删除\n }\n process.exit(0);\n }\n\n process.on(\"SIGTERM\", () => {\n shutdown();\n });\n process.on(\"SIGINT\", () => {\n shutdown();\n });\n}\n\nconst isMainModule =\n process.argv[1] && (process.argv[1].endsWith(\"serve.js\") || process.argv[1].endsWith(\"serve.ts\"));\n\nif (isMainModule) {\n startService(parseServiceOptions(process.argv.slice(2))).catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n serviceLogger.error({ err: message }, \"Service failed to start\");\n console.error(message);\n process.exit(1);\n });\n}\n","import { mkdirSync, readFileSync, renameSync, writeFileSync, existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { nanoid } from \"nanoid\";\nimport { SessionState } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { defineFSM } from \"../common/state-machine.js\";\nimport type { ProviderId } from \"../providers/index.js\";\n\nexport interface SessionInfo {\n id: string;\n mode: \"pty\" | \"json\";\n provider: ProviderId;\n ptyOwner?: \"local-terminal\" | \"proxy-hosted\";\n state: SessionState;\n createdAt: number;\n updatedAt: number;\n name?: string;\n cwd: string;\n // Claude CLI 自己生成的 session ID,和上面 id 字段无关\n // 用途:定位 ~/.claude/projects/<encoded-cwd>/<claudeSessionId>.jsonl 历史文件 / 支持 --resume\n claudeSessionId?: string;\n pid: number;\n}\n\ninterface SessionManagerOptions {\n persistPath: string;\n reaperIntervalMs?: number;\n onSessionRemoved?: (id: string, context?: SessionRemoveContext) => void;\n}\n\ninterface SessionRemoveContext {\n preserveProviderHooks?: boolean;\n}\n\n// 两个观察通道的合法转换表分离:PTY 看 OSC 信号、JSON 看 stream-json 事件,各自的状态空间和规则不同。\n// terminated 是终态,不允许任何转出。\n\n// PTY 观察通道:从终端 OSC 0/9 信号 + idle timer 推导状态。\n// ERROR 在 PTY 观察通道不可达:PTY 错误体现为终端 ANSI 内容,proxy 不建模观察器失联。\nconst PTY_TRANSITIONS: Record<SessionState, readonly SessionState[]> = {\n [SessionState.IDLE]: [\n // claude 开始响应用户输入 → handlePtyData 首字节翻 working\n SessionState.WORKING,\n // provider hook 是语义事件,可能比 PTY 字节观察更早到达;PermissionRequest 可直接进入审批等待。\n SessionState.WAITING_APPROVAL,\n // 终态兜底;现阶段 terminated 走 terminateSession 直接删 map 不经 updateState,本边未被触发\n SessionState.TERMINATED,\n ],\n [SessionState.WORKING]: [\n // 5s 静默且 currentPtyState === \"working\" → idle timer 推 turn_complete\n SessionState.IDLE,\n // claude 发 OSC 9 \"needs your permission: <tool>\" → handlePtyData 推 approval_wait\n SessionState.WAITING_APPROVAL,\n // 终态兜底\n SessionState.TERMINATED,\n ],\n [SessionState.WAITING_APPROVAL]: [\n // 审批解除后 provider 可能继续工作,也可能直接结束本轮。\n // 真实 Claude 拒绝工具审批后会直接发 turn_complete,因此 WAITING_APPROVAL -> IDLE 是合法边。\n SessionState.WORKING,\n SessionState.IDLE,\n // 终态兜底\n SessionState.TERMINATED,\n ],\n // PTY 永不进入 ERROR;本行仅为满足 Record<SessionState,_> 枚举完整性保留\n [SessionState.ERROR]: [SessionState.TERMINATED],\n [SessionState.TERMINATED]: [],\n};\n\n// JSON 观察通道:从 stream-json 事件 + relay 入站消息推导状态。\n// 注意:turn 结束时 result.is_error === true 不走 ERROR——它属于 turn 内部错误,观察通道本身健康,仍按 onTurnResult → IDLE 处理。\nconst JSON_TRANSITIONS: Record<SessionState, readonly SessionState[]> = {\n [SessionState.IDLE]: [\n // 用户在 relay/web 端发消息 → onTurnStart,turn 开始\n SessionState.WORKING,\n // 空闲期观察通道失联(worker socket 死但 pid 仍在等)→ onChannelBroken\n SessionState.ERROR,\n // 终态兜底;同 PTY,当前不经 updateState\n SessionState.TERMINATED,\n ],\n [SessionState.WORKING]: [\n // stream-json result event → onTurnResult,turn 结束\n SessionState.IDLE,\n // claude 发 control_request → onApprovalRequested,阻塞等审批\n SessionState.WAITING_APPROVAL,\n // turn 进行中通道失联 → onChannelBroken\n SessionState.ERROR,\n // 终态兜底\n SessionState.TERMINATED,\n ],\n [SessionState.WAITING_APPROVAL]: [\n // 粒度丢失:审批解除后 claude 继续跑,proxy 观察不到中间的 WORKING 信号,\n // 直到 result event 才感知 → onTurnResult 一次性从 WAITING_APPROVAL 跳到 IDLE。\n // 因此不列 WAITING_APPROVAL → WORKING 这条边。\n SessionState.IDLE,\n // 审批死锁:control_response 写 worker stdin 失败 → onChannelBroken。\n // 这是 ERROR 态最明确的落地场景,让 UI 能区分 \"正在等用户决定\" 和 \"审批通道坏了\"。\n SessionState.ERROR,\n // 终态兜底\n SessionState.TERMINATED,\n ],\n [SessionState.ERROR]: [\n // 观察通道坏了之后只能 terminate,不回 IDLE/WORKING——恢复机制未实现\n SessionState.TERMINATED,\n ],\n [SessionState.TERMINATED]: [],\n};\n\nconst ptyFSM = defineFSM(PTY_TRANSITIONS);\nconst jsonFSM = defineFSM(JSON_TRANSITIONS);\n\nfunction fsmForMode(mode: \"pty\" | \"json\"): ReturnType<typeof defineFSM<SessionState>> {\n return mode === \"pty\" ? ptyFSM : jsonFSM;\n}\n\nfunction isProviderId(value: unknown): value is ProviderId {\n return value === \"claude\" || value === \"codex\";\n}\n\nexport class SessionManager {\n private sessions: Map<string, SessionInfo> = new Map();\n private reaperTimer: NodeJS.Timeout | null = null;\n private readonly persistPath: string;\n private readonly reaperIntervalMs: number;\n private readonly onSessionRemoved?: (id: string, context?: SessionRemoveContext) => void;\n\n constructor(options: SessionManagerOptions) {\n this.persistPath = options.persistPath;\n this.reaperIntervalMs = options.reaperIntervalMs ?? 60000;\n this.onSessionRemoved = options.onSessionRemoved;\n this.load();\n }\n\n createSession(\n mode: \"pty\" | \"json\",\n cwd: string,\n pid: number,\n name?: string,\n id?: string,\n provider: ProviderId = \"claude\",\n ptyOwner?: \"local-terminal\" | \"proxy-hosted\",\n ): SessionInfo {\n const now = Date.now();\n const info: SessionInfo = {\n id: id ?? nanoid(),\n mode,\n provider,\n ...(mode === \"pty\" && ptyOwner !== undefined ? { ptyOwner } : {}),\n state: SessionState.IDLE,\n createdAt: now,\n updatedAt: now,\n cwd,\n pid,\n ...(name !== undefined ? { name } : {}),\n };\n this.sessions.set(info.id, info);\n this.save();\n serviceLogger.info({ sessionId: info.id, mode, provider, ptyOwner, name }, \"Session created\");\n return info;\n }\n\n listSessions(): SessionInfo[] {\n return Array.from(this.sessions.values()).sort((a, b) => b.createdAt - a.createdAt);\n }\n\n getSession(id: string): SessionInfo | undefined {\n return this.sessions.get(id);\n }\n\n updateState(id: string, newState: SessionState): boolean {\n const session = this.sessions.get(id);\n if (!session) {\n // session 不存在是调用方 bug,不是观察竞态,保留 throw\n throw new Error(`Session not found: ${id}`);\n }\n const oldState = session.state;\n if (oldState === newState) return false;\n const fsm = fsmForMode(session.mode);\n if (!fsm.canTransition(oldState, newState)) {\n // 吸收态(传递闭包推导:TERMINATED + 所有出边都指向吸收态的状态)之后的残余转换请求\n // 是进程竞态,日志降噪到 debug;其他非法转换是协议违反或 bug,warn 以便盯盘能看到\n const level = fsm.isAbsorbing(oldState) ? \"debug\" : \"warn\";\n serviceLogger[level](\n { sessionId: id, from: oldState, to: newState, mode: session.mode },\n level === \"debug\"\n ? \"State change after absorbing state (residual, likely race)\"\n : \"Invalid state transition rejected by FSM\",\n );\n return false;\n }\n session.state = newState;\n session.updatedAt = Date.now();\n this.save();\n serviceLogger.info({ sessionId: id, from: oldState, to: newState }, \"Session state changed\");\n return true;\n }\n\n touchSession(id: string, now: number = Date.now(), minIntervalMs = 0): boolean {\n const session = this.sessions.get(id);\n if (!session) return false;\n if (now - session.updatedAt < minIntervalMs) return false;\n session.updatedAt = now;\n this.save();\n return true;\n }\n\n terminateSession(id: string, context?: SessionRemoveContext): { success: boolean; pid?: number } {\n const session = this.sessions.get(id);\n if (!session) {\n return { success: false };\n }\n const pid = session.pid;\n this.sessions.delete(id);\n this.save();\n serviceLogger.info({ sessionId: id, mode: session.mode, pid }, \"Session terminated\");\n this.onSessionRemoved?.(id, context);\n return { success: true, pid };\n }\n\n terminateAll(): number[] {\n const pids: number[] = [];\n const ids = Array.from(this.sessions.keys());\n for (const id of ids) {\n const session = this.sessions.get(id)!;\n if (session.mode === \"json\" && session.pid !== undefined) {\n pids.push(session.pid);\n }\n this.sessions.delete(id);\n this.onSessionRemoved?.(id);\n }\n this.save();\n return pids;\n }\n\n setClaudeSessionId(id: string, claudeSessionId: string): void {\n const session = this.sessions.get(id);\n if (!session) {\n throw new Error(`Session not found: ${id}`);\n }\n session.claudeSessionId = claudeSessionId;\n this.save();\n }\n\n setPid(id: string, pid: number): void {\n const session = this.sessions.get(id);\n if (!session) {\n throw new Error(`Session not found: ${id}`);\n }\n session.pid = pid;\n this.save();\n }\n\n startReaper(intervalMs: number = this.reaperIntervalMs): void {\n this.stopReaper();\n this.reaperTimer = setInterval(() => this.reap(), intervalMs);\n }\n\n stopReaper(): void {\n if (this.reaperTimer) {\n clearInterval(this.reaperTimer);\n this.reaperTimer = null;\n }\n }\n\n private reap(): void {\n const toRemove: Array<{ id: string; reason: string }> = [];\n // 检查 JSON 会话的子进程是否存活\n // PTY 会话的生命周期由 IPC socket close 事件管理,不需要 reaper 参与\n for (const session of this.sessions.values()) {\n if (\n session.mode === \"json\" &&\n session.pid !== undefined &&\n session.state !== SessionState.TERMINATED\n ) {\n if (!this.isProcessAlive(session.pid)) {\n toRemove.push({ id: session.id, reason: `JSON worker process ${session.pid} is dead` });\n }\n }\n }\n for (const { id, reason } of toRemove) {\n serviceLogger.warn({ sessionId: id, reason }, \"Reaping stale session\");\n this.terminateSession(id);\n }\n }\n\n private isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n private save(): void {\n const dir = dirname(this.persistPath);\n mkdirSync(dir, { recursive: true });\n // state 是对 claude 的观察值,进程死后无意义,不落盘。磁盘上只留 identity(id/mode/cwd/pid/...)。\n const persisted = Array.from(this.sessions.values()).map((s) => ({\n id: s.id,\n mode: s.mode,\n provider: s.provider,\n createdAt: s.createdAt,\n updatedAt: s.updatedAt,\n cwd: s.cwd,\n pid: s.pid,\n ...(s.name !== undefined ? { name: s.name } : {}),\n ...(s.claudeSessionId !== undefined ? { claudeSessionId: s.claudeSessionId } : {}),\n }));\n const data = JSON.stringify(persisted, null, 2);\n const tmpPath = this.persistPath + \".tmp\";\n writeFileSync(tmpPath, data, \"utf-8\");\n renameSync(tmpPath, this.persistPath);\n }\n\n private load(): void {\n if (!existsSync(this.persistPath)) {\n return;\n }\n const raw = readFileSync(this.persistPath, \"utf-8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(`Failed to parse session persistence file at ${this.persistPath}`, {\n cause: err,\n });\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n `Session persistence file has invalid format at ${this.persistPath}: expected array`,\n );\n }\n for (const item of parsed) {\n if (item && typeof item === \"object\" && \"state\" in item) {\n throw new Error(\n `Session persistence file has invalid persisted state for session ${String(\n (item as { id?: unknown }).id,\n )}`,\n );\n }\n const info = item as Omit<SessionInfo, \"state\"> & { state?: SessionState };\n if (!isProviderId(info.provider)) {\n const sessionId = String(info.id);\n this.onSessionRemoved?.(sessionId);\n serviceLogger.warn(\n { sessionId, provider: info.provider },\n \"Session persistence file has invalid provider; cleaning session\",\n );\n continue;\n }\n if (info.mode === \"pty\") {\n if (info.pid && this.isProcessAlive(info.pid)) {\n // terminal 进程仍存活,会重连,保留磁盘数据但不加载到内存\n serviceLogger.info(\n { sessionId: info.id, pid: info.pid },\n \"PTY session skipped on load, terminal alive\",\n );\n } else {\n // terminal 进程已死,清理数据\n this.onSessionRemoved?.(info.id);\n serviceLogger.info(\n { sessionId: info.id, pid: info.pid },\n \"PTY session cleaned on load, terminal dead\",\n );\n }\n continue;\n }\n // JSON 会话:检查 worker 进程是否存活,无 PID 或进程已死则清理\n if (info.pid && this.isProcessAlive(info.pid)) {\n // 加载回内存时 state 固定回观察零点 IDLE,等观察器下一轮信号推到位\n this.sessions.set(info.id, { ...info, state: SessionState.IDLE });\n } else {\n this.onSessionRemoved?.(info.id);\n serviceLogger.info(\n { sessionId: info.id, pid: info.pid },\n \"JSON session cleaned on load, worker dead\",\n );\n }\n }\n // 清理后回写磁盘,避免已清理的会话在下次启动时重复处理\n this.save();\n if (this.sessions.size > 0) {\n serviceLogger.info({ count: this.sessions.size }, \"Sessions restored from persistence\");\n }\n }\n}\n","import WebSocket from \"ws\";\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { nanoid } from \"nanoid\";\nimport { EventEmitter } from \"node:events\";\nimport type { MessageEnvelope } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { createFSM } from \"../common/state-machine.js\";\nimport { MemoryMessageQueue } from \"./message-queue.js\";\n\n// 默认 proxyId 存储路径\nconst DEFAULT_PROXY_ID_PATH = join(homedir(), \".dev-anywhere\", \"proxy-id\");\n\n// 指数退避上限 30 秒\nconst MAX_BACKOFF_MS = 30000;\n// 退避基数 1 秒\nconst BASE_BACKOFF_MS = 1000;\n// 消息队列上限\nconst MAX_QUEUE_SIZE = 10000;\n\nexport const RelayConnectionState = {\n DISCONNECTED: \"disconnected\",\n CONNECTING: \"connecting\",\n REGISTERING: \"registering\",\n SYNCED: \"synced\",\n WAITING_RECONNECT: \"waiting_reconnect\",\n CLOSED: \"closed\",\n} as const;\nexport type RelayConnectionState = (typeof RelayConnectionState)[keyof typeof RelayConnectionState];\n\n// 合法的 WS 连接状态转移\n// CLOSED 是终态;connect 流转: DISCONNECTED → CONNECTING → REGISTERING → SYNCED\n// 断线: SYNCED/REGISTERING/CONNECTING → WAITING_RECONNECT → CONNECTING\n// 主动关: 任意 → CLOSED\nconst RELAY_TRANSITIONS: Record<RelayConnectionState, readonly RelayConnectionState[]> = {\n [RelayConnectionState.DISCONNECTED]: [\n RelayConnectionState.CONNECTING,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.CONNECTING]: [\n RelayConnectionState.REGISTERING,\n RelayConnectionState.WAITING_RECONNECT,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.REGISTERING]: [\n RelayConnectionState.SYNCED,\n RelayConnectionState.WAITING_RECONNECT,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.SYNCED]: [\n RelayConnectionState.WAITING_RECONNECT,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.WAITING_RECONNECT]: [\n RelayConnectionState.CONNECTING,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.CLOSED]: [],\n};\n\ninterface RelayConnectionOptions {\n // 自定义 proxyId 文件路径,测试时使用临时目录\n proxyIdPath?: string;\n // proxy 显示名称,注册时发送给 relay\n name?: string;\n // 公网 relay 的 /proxy 端点预共享 token, relay 侧 RELAY_PROXY_TOKEN 对应\n token?: string;\n}\n\n// 管理代理到中转服务器的出站 WebSocket 连接,支持自动重连和消息队列\nexport class RelayConnection extends EventEmitter {\n private ws: WebSocket | null = null;\n private proxyId: string;\n private relayUrl: string;\n private queue: MemoryMessageQueue = new MemoryMessageQueue();\n private reconnectAttempt: number = 0;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private fsm = createFSM({\n initial: RelayConnectionState.DISCONNECTED as RelayConnectionState,\n transitions: RELAY_TRANSITIONS,\n onTransition: (from, to) =>\n serviceLogger.info({ from, to }, \"RelayConnection state transition\"),\n onRejected: (from, to, isAbsorbing) =>\n serviceLogger[isAbsorbing ? \"debug\" : \"warn\"](\n { from, to },\n isAbsorbing\n ? \"Late event after absorbing state, ignored\"\n : \"Invalid relay connection transition rejected\",\n ),\n });\n private name?: string;\n private token?: string;\n\n constructor(relayUrl: string, options?: RelayConnectionOptions) {\n super();\n this.relayUrl = relayUrl;\n this.proxyId = this.loadOrCreateProxyId(options?.proxyIdPath ?? DEFAULT_PROXY_ID_PATH);\n this.name = options?.name;\n this.token = options?.token;\n }\n\n // 从文件读取或生成新的 proxyId,生成后持久化到文件\n private loadOrCreateProxyId(idPath: string): string {\n if (existsSync(idPath)) {\n const existing = readFileSync(idPath, \"utf-8\").trim();\n if (existing.length > 0) {\n return existing;\n }\n }\n\n const id = nanoid(21);\n const dir = dirname(idPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(idPath, id, \"utf-8\");\n return id;\n }\n\n // 连接到 relay server\n connect(): void {\n if (!this.fsm.tryTransitionTo(RelayConnectionState.CONNECTING)) return;\n this.doConnect();\n }\n\n // 实际建立 WebSocket 连接的内部方法\n private doConnect(): void {\n try {\n const base = this.relayUrl.replace(/\\/$/, \"\") + \"/proxy\";\n const url = this.token ? `${base}?token=${encodeURIComponent(this.token)}` : base;\n this.ws = new WebSocket(url);\n\n this.ws.on(\"open\", () => {\n // open 属异步回调,若同步 close() 已先切 CLOSED,REGISTERING 会被拒,需跳过后续 register\n if (!this.fsm.tryTransitionTo(RelayConnectionState.REGISTERING)) return;\n serviceLogger.info(\n { proxyId: this.proxyId, url: base, tokenSet: !!this.token },\n \"Connected to relay server\",\n );\n this.ws!.send(\n JSON.stringify({\n type: \"proxy_register\",\n proxyId: this.proxyId,\n ...(this.name ? { name: this.name } : {}),\n }),\n );\n });\n\n this.ws.on(\"message\", (data) => {\n const raw = data.toString();\n let msg: Record<string, unknown>;\n try {\n msg = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n serviceLogger.warn({ error: String(err) }, \"Non-JSON message from relay, dropped\");\n return;\n }\n if (msg.type === \"proxy_register_response\") {\n serviceLogger.info({ status: msg.status }, \"Received register response\");\n if (!this.fsm.tryTransitionTo(RelayConnectionState.SYNCED)) return;\n this.reconnectAttempt = 0;\n this.flushQueue();\n this.emit(\"connected\");\n return;\n }\n this.emit(\"message\", msg);\n });\n\n this.ws.on(\"close\", () => {\n this.ws = null;\n if (this.fsm.current() !== RelayConnectionState.CLOSED) {\n this.fsm.tryTransitionTo(RelayConnectionState.WAITING_RECONNECT);\n serviceLogger.info(\"Relay connection closed unexpectedly\");\n this.emit(\"disconnected\");\n this.scheduleReconnect();\n } else {\n serviceLogger.info(\"Relay connection closed\");\n }\n });\n\n this.ws.on(\"error\", (err) => {\n serviceLogger.error({ error: String(err) }, \"Relay connection error\");\n });\n } catch (err) {\n serviceLogger.error({ error: String(err) }, \"Failed to create relay connection\");\n if (this.fsm.current() !== RelayConnectionState.CLOSED) {\n this.fsm.tryTransitionTo(RelayConnectionState.WAITING_RECONNECT);\n this.scheduleReconnect();\n }\n }\n }\n\n // 将队列中缓存的消息依次发送到 relay\n private flushQueue(): void {\n for (const raw of this.queue.drain()) {\n this.ws?.send(raw);\n }\n }\n\n // 计算全抖动指数退避延迟并调度重连\n private scheduleReconnect(): void {\n const backoff =\n Math.random() *\n Math.min(MAX_BACKOFF_MS, BASE_BACKOFF_MS * Math.pow(2, this.reconnectAttempt));\n serviceLogger.info(\n { attempt: this.reconnectAttempt + 1, backoffMs: Math.round(backoff) },\n \"Scheduling reconnect\",\n );\n this.reconnectTimer = setTimeout(() => {\n this.reconnectAttempt++;\n // 必须先回 CONNECTING 才能让 open handler 合法转到 REGISTERING;\n // 若 close() 抢先切 CLOSED(clearTimeout 理论上拦得住,保险再守一层),跳过重连\n if (!this.fsm.tryTransitionTo(RelayConnectionState.CONNECTING)) return;\n this.doConnect();\n }, backoff);\n }\n\n // 发送 MessageEnvelope 到 relay,离线时自动入队\n sendEnvelope(envelope: MessageEnvelope): void {\n const raw = JSON.stringify(envelope);\n this.sendRaw(raw);\n }\n\n // 发送 binary PTY 帧到 relay,断线时直接丢弃不入队\n sendBinary(data: Buffer): void {\n if (\n this.fsm.current() === RelayConnectionState.SYNCED &&\n this.ws?.readyState === WebSocket.OPEN\n ) {\n this.ws.send(data);\n }\n // binary 帧无队列,断线丢弃\n }\n\n // 发送原始 JSON 字符串到 relay,根据 connectionState 决定直发、入队或丢弃\n sendRaw(raw: string): void {\n if (\n this.fsm.current() === RelayConnectionState.SYNCED &&\n this.ws?.readyState === WebSocket.OPEN\n ) {\n this.ws.send(raw);\n } else if (this.fsm.current() === RelayConnectionState.CLOSED) {\n serviceLogger.warn(\"Message discarded: connection is closed\");\n } else {\n if (this.queue.size() >= MAX_QUEUE_SIZE) {\n const dropped = this.queue.dropOldest();\n serviceLogger.warn(\n { maxSize: MAX_QUEUE_SIZE },\n \"Message queue overflow, oldest message dropped\",\n );\n // 通知订阅方(WorkerRegistry)补偿被丢的 envelope,例如清理 pending 审批\n if (dropped !== null) this.emit(\"envelope_dropped\", dropped);\n }\n this.queue.enqueue(raw);\n serviceLogger.debug({ queueSize: this.queue.size() }, \"Message queued during disconnect\");\n }\n }\n\n // 主动关闭连接,发送 proxy_disconnect 通知 relay 立即清理,不触发重连\n close(): void {\n // 幂等:已 CLOSED 直接跳过,避免 FSM 抛 closed -> closed\n if (this.fsm.is(RelayConnectionState.CLOSED)) return;\n this.fsm.tryTransitionTo(RelayConnectionState.CLOSED);\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n if (this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify({ type: \"proxy_disconnect\", proxyId: this.proxyId }));\n }\n this.ws.close();\n this.ws = null;\n }\n }\n\n // 获取当前 proxyId\n getProxyId(): string {\n return this.proxyId;\n }\n\n // 获取连接状态摘要,用于 CLI status 输出\n getStatus(): {\n connected: boolean;\n connectionState: RelayConnectionState;\n proxyId: string;\n reconnectAttempt: number;\n queueDepth: number;\n } {\n return {\n connected: this.fsm.current() === RelayConnectionState.SYNCED,\n connectionState: this.fsm.current(),\n proxyId: this.proxyId,\n reconnectAttempt: this.reconnectAttempt,\n queueDepth: this.queue.size(),\n };\n }\n}\n","// 发送队列只负责内存背压和有序 drain;持久化恢复由 relay/proxy 重拉协议承担。\ninterface MessageQueue {\n enqueue(raw: string): void;\n drain(): string[];\n size(): number;\n clear(): void;\n dropOldest(): string | null;\n}\n\nexport class MemoryMessageQueue implements MessageQueue {\n private items: string[] = [];\n\n enqueue(raw: string): void {\n this.items.push(raw);\n }\n\n drain(): string[] {\n const all = this.items;\n this.items = [];\n return all;\n }\n\n size(): number {\n return this.items.length;\n }\n\n clear(): void {\n this.items = [];\n }\n\n // 丢弃最旧消息,返回被丢弃的 raw 供 caller 做补偿(例如清理对应 pending 审批)\n dropOldest(): string | null {\n return this.items.shift() ?? null;\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute } from \"node:path\";\nimport { CONFIG_PATH, PROFILE_NAME, defaultHookPortForProfile } from \"./paths.js\";\nimport { serviceLogger } from \"./logger.js\";\nimport type { ProviderId } from \"../providers/types.js\";\n\nexport interface ProxyConfig {\n profileName: string;\n relayName: string;\n relayUrl?: string;\n // /proxy 端点的预共享 token, 和 relay 侧 RELAY_PROXY_TOKEN 对应. 公网 relay 必须设置\n relayToken?: string;\n hookPort?: number;\n claudeBin?: string;\n codexBin?: string;\n agentCliSuggestions: Record<ProviderId, string[]>;\n sources: {\n relayName: \"cli\" | \"profile\";\n relayUrl: \"env\" | \"file\" | \"none\";\n relayToken: \"env\" | \"file\" | \"none\";\n hookPort: \"env\" | \"default\";\n claudeBin: \"env\" | \"file\" | \"none\";\n codexBin: \"env\" | \"file\" | \"none\";\n };\n}\n\ninterface ProxyProfileConfig {\n relay?: string;\n}\n\ninterface RelayTargetConfig {\n url?: string;\n proxyToken?: string;\n}\n\ninterface ProxyConfigFile {\n defaultProfile?: string;\n profiles: Record<string, ProxyProfileConfig | undefined>;\n relays: Record<string, RelayTargetConfig | undefined>;\n agentCli?: AgentCliConfig;\n}\n\ninterface AgentCliConfig {\n claudeBin?: string;\n codexBin?: string;\n claudeBinHistory?: string[];\n codexBinHistory?: string[];\n}\n\nfunction parsePort(value: string | undefined, source: string): number | undefined {\n if (!value) return undefined;\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error(`Invalid ${source}: expected TCP port 1-65535`);\n }\n return port;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction validateConfigShape(value: unknown): ProxyConfigFile {\n if (!isRecord(value) || !isRecord(value.profiles) || !isRecord(value.relays)) {\n throw new Error(`Invalid config shape in ${CONFIG_PATH}: expected \"profiles\" and \"relays\".`);\n }\n return value as unknown as ProxyConfigFile;\n}\n\nfunction readConfigFile(): ProxyConfigFile {\n if (!existsSync(CONFIG_PATH)) {\n throw new Error(`Dev Anywhere config not found at ${CONFIG_PATH}. Run \"dev-anywhere init\".`);\n }\n return validateConfigShape(JSON.parse(readFileSync(CONFIG_PATH, \"utf-8\")));\n}\n\nfunction agentCliField(provider: ProviderId): \"claudeBin\" | \"codexBin\" {\n return provider === \"claude\" ? \"claudeBin\" : \"codexBin\";\n}\n\nfunction agentCliHistoryField(provider: ProviderId): \"claudeBinHistory\" | \"codexBinHistory\" {\n return provider === \"claude\" ? \"claudeBinHistory\" : \"codexBinHistory\";\n}\n\nfunction validateAgentCliPath(path: string): string {\n const normalized = path.trim();\n if (!normalized) throw new Error(\"请输入 CLI 路径\");\n if (!isAbsolute(normalized)) throw new Error(\"CLI 路径必须是绝对路径\");\n return normalized;\n}\n\nfunction uniqueAbsolutePaths(paths: Array<string | undefined>): string[] {\n const seen = new Set<string>();\n const result: string[] = [];\n for (const path of paths) {\n const normalized = path?.trim();\n if (!normalized || !isAbsolute(normalized) || seen.has(normalized)) continue;\n seen.add(normalized);\n result.push(normalized);\n }\n return result;\n}\n\nfunction resolveRelayConfig(\n fromFile: ProxyConfigFile,\n requestedRelayName?: string,\n): {\n relayName: string;\n relayNameSource: ProxyConfig[\"sources\"][\"relayName\"];\n relay: RelayTargetConfig;\n} {\n const profile = fromFile.profiles[PROFILE_NAME];\n if (!profile) {\n const available = Object.keys(fromFile.profiles).sort();\n throw new Error(\n `Unknown profile \"${PROFILE_NAME}\". Available profiles: ${available.length > 0 ? available.join(\", \") : \"(none)\"}`,\n );\n }\n\n const relayName = requestedRelayName?.trim() || profile.relay?.trim();\n if (!relayName) {\n throw new Error(`Profile \"${PROFILE_NAME}\" must specify a relay.`);\n }\n\n const relay = fromFile.relays[relayName];\n if (!relay) {\n const available = Object.keys(fromFile.relays).sort();\n throw new Error(\n `Unknown relay \"${relayName}\". Available relays: ${available.length > 0 ? available.join(\", \") : \"(none)\"}`,\n );\n }\n\n return {\n relayName,\n relayNameSource: requestedRelayName?.trim() ? \"cli\" : \"profile\",\n relay,\n };\n}\n\nexport function loadConfig(options?: { relayName?: string }): ProxyConfig {\n const fromFile = readConfigFile();\n const agentCli = fromFile.agentCli ?? {};\n const resolved = resolveRelayConfig(fromFile, options?.relayName);\n const claudeBin = process.env.CLAUDE_BIN ?? agentCli.claudeBin;\n const codexBin = process.env.CODEX_BIN ?? agentCli.codexBin;\n const config: ProxyConfig = {\n profileName: PROFILE_NAME,\n relayName: resolved.relayName,\n relayUrl: process.env.RELAY_URL ?? resolved.relay.url,\n relayToken: process.env.RELAY_PROXY_TOKEN ?? resolved.relay.proxyToken,\n hookPort:\n parsePort(process.env.DEV_ANYWHERE_HOOK_PORT, \"DEV_ANYWHERE_HOOK_PORT\") ??\n defaultHookPortForProfile(PROFILE_NAME),\n claudeBin,\n codexBin,\n agentCliSuggestions: {\n claude: uniqueAbsolutePaths([\n process.env.CLAUDE_BIN,\n agentCli.claudeBin,\n ...(agentCli.claudeBinHistory ?? []),\n ]),\n codex: uniqueAbsolutePaths([\n process.env.CODEX_BIN,\n agentCli.codexBin,\n ...(agentCli.codexBinHistory ?? []),\n ]),\n },\n sources: {\n relayName: resolved.relayNameSource,\n relayUrl: process.env.RELAY_URL ? \"env\" : resolved.relay.url ? \"file\" : \"none\",\n relayToken: process.env.RELAY_PROXY_TOKEN\n ? \"env\"\n : resolved.relay.proxyToken\n ? \"file\"\n : \"none\",\n hookPort: process.env.DEV_ANYWHERE_HOOK_PORT ? \"env\" : \"default\",\n claudeBin: process.env.CLAUDE_BIN ? \"env\" : agentCli.claudeBin ? \"file\" : \"none\",\n codexBin: process.env.CODEX_BIN ? \"env\" : agentCli.codexBin ? \"file\" : \"none\",\n },\n };\n\n serviceLogger.info(\n {\n profile: config.profileName,\n relayName: config.relayName,\n relayNameSource: config.sources.relayName,\n relayUrl: config.relayUrl ?? \"(unset)\",\n relayUrlSource: config.sources.relayUrl,\n relayTokenSource: config.sources.relayToken,\n hookPort: config.hookPort,\n hookPortSource: config.sources.hookPort,\n claudeBinSource: config.sources.claudeBin,\n codexBinSource: config.sources.codexBin,\n },\n \"Config loaded\",\n );\n\n return config;\n}\n\nexport function buildProviderEnv(\n config: ProxyConfig,\n baseEnv: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n return {\n ...baseEnv,\n ...(config.claudeBin ? { CLAUDE_BIN: config.claudeBin } : {}),\n ...(config.codexBin ? { CODEX_BIN: config.codexBin } : {}),\n };\n}\n\nfunction updateAgentCliConfig(\n config: AgentCliConfig,\n provider: ProviderId,\n path: string,\n): AgentCliConfig {\n const field = agentCliField(provider);\n const historyField = agentCliHistoryField(provider);\n const history = uniqueAbsolutePaths([path, ...(config[historyField] ?? [])]).slice(0, 8);\n return {\n ...config,\n [field]: path,\n [historyField]: history,\n };\n}\n\nexport function saveAgentCliPath(provider: ProviderId, path: string): void {\n const normalized = validateAgentCliPath(path);\n const fromFile = readConfigFile();\n fromFile.agentCli = updateAgentCliConfig(fromFile.agentCli ?? {}, provider, normalized);\n mkdirSync(dirname(CONFIG_PATH), { recursive: true });\n writeFileSync(CONFIG_PATH, `${JSON.stringify(fromFile, null, 2)}\\n`, \"utf-8\");\n}\n","import { readdir, mkdir } from \"node:fs/promises\";\nimport { join, isAbsolute, normalize } from \"node:path\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport type { SessionManager } from \"../session-manager.js\";\nimport { scanSessionHistory } from \"../session-history.js\";\nimport { discoverCommands } from \"../command-discovery.js\";\nimport { serviceLogger } from \"../../common/logger.js\";\nimport { classifyPathError } from \"../path-errors.js\";\n\nexport interface ControlMessageHandlers {\n handleDirListRequest(msg: { path: string; requestId?: string }): Promise<void>;\n handleDirCreateRequest(msg: { path: string; requestId?: string }): Promise<void>;\n handleSessionHistoryRequest(msg: { requestId?: string }): Promise<void>;\n handleSessionResourcesRequest(msg: {\n sessionId: string;\n requestId?: string;\n workDir: string;\n }): Promise<void>;\n pushCommandList(sessionId: string, workDir: string): Promise<void>;\n pushFileTree(sessionId: string, workDir: string): Promise<void>;\n reinitializeOnReconnect(): Promise<void>;\n cleanup(sessionId: string): void;\n}\n\n// 每个 session 的定时器和资源\ninterface SessionResources {\n commandRefreshTimer?: NodeJS.Timeout;\n fileTreeWorkDir?: string;\n}\n\n// 命令刷新间隔 6 小时\nconst COMMAND_REFRESH_MS = 6 * 60 * 60 * 1000;\n\n// 路径安全校验:拒绝相对路径和路径遍历\nfunction isPathSafe(path: string): boolean {\n if (!isAbsolute(path)) return false;\n const normalized = normalize(path);\n // 检查 normalize 后是否仍包含 ..(理论上不会,但做防御)\n if (normalized.includes(\"..\")) return false;\n return true;\n}\n\n// picker 展示忽略规则: dotfile + node_modules\n// listDirectory (按需) 与 getFileTree (预热) 必须共用, 否则逐层下钻会暴露 node_modules\nconst HIDDEN_ENTRY_NAMES = new Set([\"node_modules\"]);\nfunction isPickerVisible(name: string): boolean {\n return !name.startsWith(\".\") && !HIDDEN_ENTRY_NAMES.has(name);\n}\n\n// 目录优先 + 字母序, picker 侧依赖这个顺序做键盘导航默认选中\nfunction sortEntries(\n a: { isDir: boolean; name: string },\n b: { isDir: boolean; name: string },\n): number {\n if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;\n return a.name.localeCompare(b.name);\n}\n\nasync function scanDir(dirPath: string): Promise<Array<{ name: string; isDir: boolean }>> {\n const entries = await readdir(dirPath, { withFileTypes: true });\n return entries\n .filter((e) => isPickerVisible(e.name))\n .map((e) => ({ name: e.name, isDir: e.isDirectory() }))\n .sort(sortEntries);\n}\n\n// 预热 cwd + 直接子目录两层, 按目录分组返回, 前端写入 tree[path] 后逐层 picker 直接命中\ninterface FileTreeGroup {\n path: string;\n entries: Array<{ name: string; isDir: boolean }>;\n}\n\nasync function getFileTree(rootPath: string): Promise<FileTreeGroup[]> {\n const groups: FileTreeGroup[] = [];\n\n let rootEntries: Array<{ name: string; isDir: boolean }>;\n try {\n rootEntries = await scanDir(rootPath);\n } catch {\n return groups;\n }\n groups.push({ path: rootPath, entries: rootEntries });\n\n for (const sub of rootEntries) {\n if (!sub.isDir) continue;\n const subPath = join(rootPath, sub.name);\n try {\n const subEntries = await scanDir(subPath);\n groups.push({ path: subPath, entries: subEntries });\n } catch {\n // 无法读取子目录, 跳过这一层分组 (picker 会在点击时触发 dir_list_request 补齐)\n }\n }\n\n return groups;\n}\n\nexport function createControlMessageHandlers(\n send: (data: string) => void,\n sessionManager: SessionManager,\n): ControlMessageHandlers {\n const sessionResources = new Map<string, SessionResources>();\n\n function getResources(sessionId: string): SessionResources {\n let res = sessionResources.get(sessionId);\n if (!res) {\n res = {};\n sessionResources.set(sessionId, res);\n }\n return res;\n }\n\n function scheduleCommandRefresh(sessionId: string, workDir: string): void {\n const resources = getResources(sessionId);\n if (resources.commandRefreshTimer) {\n clearInterval(resources.commandRefreshTimer);\n }\n resources.commandRefreshTimer = setInterval(async () => {\n try {\n const commands = await discoverCommands(workDir);\n send(\n JSON.stringify({\n type: \"command_list_push\",\n commands,\n }),\n );\n serviceLogger.debug({ sessionId, count: commands.length }, \"Command list refreshed\");\n } catch (err) {\n serviceLogger.warn({ sessionId, error: String(err) }, \"Command refresh failed\");\n }\n }, COMMAND_REFRESH_MS);\n }\n\n return {\n async handleDirListRequest(msg: { path: string; requestId?: string }): Promise<void> {\n if (!isPathSafe(msg.path)) {\n send(\n JSON.stringify({\n type: \"dir_list_response\",\n requestId: msg.requestId,\n path: msg.path,\n entries: [],\n errorCode: ControlErrorCode.INVALID_PATH,\n error: \"Invalid path: must be absolute and must not contain path traversal\",\n }),\n );\n serviceLogger.warn({ path: msg.path }, \"Rejected dir_list_request: unsafe path\");\n return;\n }\n\n try {\n const entries = await scanDir(msg.path);\n send(\n JSON.stringify({\n type: \"dir_list_response\",\n requestId: msg.requestId,\n path: msg.path,\n entries,\n }),\n );\n serviceLogger.debug({ path: msg.path, count: entries.length }, \"Dir list response sent\");\n } catch (err) {\n send(\n JSON.stringify({\n type: \"dir_list_response\",\n requestId: msg.requestId,\n path: msg.path,\n entries: [],\n errorCode: classifyPathError(err),\n error: String(err),\n }),\n );\n serviceLogger.warn({ path: msg.path, error: String(err) }, \"Dir list request failed\");\n }\n },\n\n async handleDirCreateRequest(msg: { path: string; requestId?: string }): Promise<void> {\n if (!isPathSafe(msg.path)) {\n send(\n JSON.stringify({\n type: \"dir_create_response\",\n requestId: msg.requestId,\n path: msg.path,\n success: false,\n errorCode: ControlErrorCode.INVALID_PATH,\n error: \"Invalid path: must be absolute and must not contain path traversal\",\n }),\n );\n serviceLogger.warn({ path: msg.path }, \"Rejected dir_create_request: unsafe path\");\n return;\n }\n\n try {\n await mkdir(msg.path, { recursive: true });\n send(\n JSON.stringify({\n type: \"dir_create_response\",\n requestId: msg.requestId,\n path: msg.path,\n success: true,\n }),\n );\n serviceLogger.info({ path: msg.path }, \"Directory created\");\n } catch (err) {\n send(\n JSON.stringify({\n type: \"dir_create_response\",\n requestId: msg.requestId,\n path: msg.path,\n success: false,\n errorCode: classifyPathError(err),\n error: String(err),\n }),\n );\n serviceLogger.warn({ path: msg.path, error: String(err) }, \"Dir create failed\");\n }\n },\n\n async handleSessionHistoryRequest(msg: { requestId?: string }): Promise<void> {\n try {\n const sessions = await scanSessionHistory();\n send(\n JSON.stringify({\n type: \"session_history_response\",\n requestId: msg.requestId,\n sessions,\n }),\n );\n serviceLogger.debug({ count: sessions.length }, \"Session history response sent\");\n } catch (err) {\n send(\n JSON.stringify({\n type: \"session_history_response\",\n requestId: msg.requestId,\n sessions: [],\n }),\n );\n serviceLogger.warn({ error: String(err) }, \"Session history scan failed\");\n }\n },\n\n async handleSessionResourcesRequest(msg: {\n sessionId: string;\n requestId?: string;\n workDir: string;\n }): Promise<void> {\n getResources(msg.sessionId).fileTreeWorkDir = msg.workDir;\n scheduleCommandRefresh(msg.sessionId, msg.workDir);\n\n const [commandsResult, groupsResult] = await Promise.allSettled([\n discoverCommands(msg.workDir),\n getFileTree(msg.workDir),\n ]);\n const commands = commandsResult.status === \"fulfilled\" ? commandsResult.value : [];\n const groups = groupsResult.status === \"fulfilled\" ? groupsResult.value : [];\n const failedReason =\n commandsResult.status === \"rejected\"\n ? commandsResult.reason\n : groupsResult.status === \"rejected\"\n ? groupsResult.reason\n : undefined;\n\n send(\n JSON.stringify({\n type: \"session_resources_response\",\n requestId: msg.requestId,\n sessionId: msg.sessionId,\n commands,\n groups,\n ...(failedReason\n ? {\n errorCode: classifyPathError(failedReason),\n error: String(failedReason),\n }\n : {}),\n }),\n );\n serviceLogger.info(\n { sessionId: msg.sessionId, commandCount: commands.length, groupCount: groups.length },\n \"Session resources snapshot sent\",\n );\n },\n\n async pushCommandList(sessionId: string, workDir: string): Promise<void> {\n try {\n const commands = await discoverCommands(workDir);\n send(\n JSON.stringify({\n type: \"command_list_push\",\n commands,\n }),\n );\n serviceLogger.info({ sessionId, count: commands.length, workDir }, \"Command list pushed\");\n } catch (err) {\n serviceLogger.warn({ sessionId, error: String(err) }, \"Command discovery failed\");\n }\n\n // 6 小时定时刷新\n scheduleCommandRefresh(sessionId, workDir);\n },\n\n async pushFileTree(sessionId: string, workDir: string): Promise<void> {\n const resources = getResources(sessionId);\n resources.fileTreeWorkDir = workDir;\n\n try {\n const groups = await getFileTree(workDir);\n send(\n JSON.stringify({\n type: \"file_tree_push\",\n groups,\n }),\n );\n serviceLogger.debug(\n { sessionId, path: workDir, groupCount: groups.length },\n \"File tree pushed\",\n );\n } catch (err) {\n serviceLogger.warn({ sessionId, error: String(err) }, \"File tree push failed\");\n }\n },\n\n // relay 重连时同步 session 列表并重新推送控制数据\n async reinitializeOnReconnect(): Promise<void> {\n const activeSessions = sessionManager.listSessions().filter((s) => s.state !== \"terminated\");\n\n // 先同步 session 列表,relay 据此建立 proxy-session 关联\n if (activeSessions.length > 0) {\n send(\n JSON.stringify({\n type: \"session_sync\",\n sessions: activeSessions.map((s) => ({\n id: s.id,\n mode: s.mode,\n provider: s.provider,\n ...(s.ptyOwner !== undefined ? { ptyOwner: s.ptyOwner } : {}),\n state: s.state,\n })),\n }),\n );\n serviceLogger.info({ count: activeSessions.length }, \"Session list synced to relay\");\n }\n\n for (const session of activeSessions) {\n const resources = sessionResources.get(session.id);\n const workDir = resources?.fileTreeWorkDir;\n if (workDir) {\n try {\n const commands = await discoverCommands(workDir);\n send(\n JSON.stringify({\n type: \"command_list_push\",\n commands,\n }),\n );\n const groups = await getFileTree(workDir);\n send(\n JSON.stringify({\n type: \"file_tree_push\",\n groups,\n }),\n );\n serviceLogger.info(\n { sessionId: session.id },\n \"Reinitialized control data after reconnect\",\n );\n } catch (err) {\n serviceLogger.warn(\n { sessionId: session.id, error: String(err) },\n \"Reinitialize failed\",\n );\n }\n }\n }\n },\n\n cleanup(sessionId: string): void {\n const resources = sessionResources.get(sessionId);\n if (resources) {\n if (resources.commandRefreshTimer) {\n clearInterval(resources.commandRefreshTimer);\n }\n sessionResources.delete(sessionId);\n }\n },\n };\n}\n","import { readdir, stat, access, open } from \"node:fs/promises\";\nimport { createReadStream } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createInterface } from \"node:readline\";\n\ninterface SessionHistoryEntry {\n id: string;\n title: string;\n projectDir: string;\n updatedAt: number;\n provider: \"claude\" | \"codex\";\n}\n\nconst claudeProjectsDir = (): string => join(homedir(), \".claude\", \"projects\");\nconst codexSessionsDir = (): string => join(homedir(), \".codex\", \"sessions\");\nconst UNTITLED_SESSION_TITLE = \"未命名会话\";\nconst MAX_HISTORY_TITLE_LENGTH = 40;\nconst IGNORED_SLASH_COMMANDS = new Set([\n \"/clear\",\n \"/model\",\n \"/compact\",\n \"/help\",\n \"/config\",\n \"/logout\",\n]);\nconst XMLISH_NOISE_PREFIXES = [\n \"environment\",\n \"system\",\n \"developer\",\n \"assistant\",\n \"user\",\n \"tool\",\n \"context\",\n];\nconst INTERNAL_TITLE_PATTERNS = [\n /^the following is the codex agent history\\b/i,\n /^codex agent history\\b/i,\n /^conversation summary\\b/i,\n];\n\n// 扫描 ~/.claude/projects/ 获取 Claude Code 会话历史\n// 实际目录结构: ~/.claude/projects/<encoded-project-path>/<session-id>.jsonl\nexport async function scanSessionHistory(): Promise<SessionHistoryEntry[]> {\n const entries = [...(await scanClaudeSessionHistory()), ...(await scanCodexSessionHistory())];\n entries.sort((a, b) => b.updatedAt - a.updatedAt);\n // 按 provider + title + projectDir 去重,resume 产生的多个 session 只保留最新的\n const seen = new Set<string>();\n return entries.filter((e) => {\n const key = `${e.provider}::${e.projectDir}::${e.title}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nasync function scanClaudeSessionHistory(): Promise<SessionHistoryEntry[]> {\n const entries: SessionHistoryEntry[] = [];\n let projectDirs: string[];\n try {\n projectDirs = await readdir(claudeProjectsDir());\n } catch {\n return [];\n }\n\n for (const encodedDir of projectDirs) {\n const projectPath = join(claudeProjectsDir(), encodedDir);\n\n let files: string[];\n try {\n files = await readdir(projectPath);\n } catch {\n continue;\n }\n\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const filePath = join(projectPath, file);\n try {\n const fileStat = await stat(filePath);\n const sessionId = file.replace(/\\.jsonl$/, \"\");\n const { title, cwd } = await extractTitleAndCwd(filePath);\n\n entries.push({\n id: sessionId,\n title: title || UNTITLED_SESSION_TITLE,\n projectDir: cwd || \"/\" + encodedDir.replace(/^-/, \"\").split(\"-\").join(\"/\"),\n updatedAt: fileStat.mtimeMs,\n provider: \"claude\",\n });\n } catch {\n continue;\n }\n }\n }\n\n return entries;\n}\n\nasync function scanCodexSessionHistory(): Promise<SessionHistoryEntry[]> {\n const files = await collectJsonlFiles(codexSessionsDir());\n const entries: SessionHistoryEntry[] = [];\n for (const filePath of files) {\n try {\n const fileStat = await stat(filePath);\n const meta = await extractCodexTitleAndCwd(filePath);\n if (!meta.id) continue;\n entries.push({\n id: meta.id,\n title: meta.title || UNTITLED_SESSION_TITLE,\n projectDir: meta.cwd || homedir(),\n updatedAt: fileStat.mtimeMs,\n provider: \"codex\",\n });\n } catch {\n continue;\n }\n }\n return entries;\n}\n\ninterface SessionMessage {\n role: \"user\" | \"assistant\";\n text: string;\n timestamp?: number;\n cursor?: string;\n}\n\ninterface SessionMessagesPage {\n messages: SessionMessage[];\n hasMore: boolean;\n nextBefore?: string;\n}\n\ninterface SessionMessagesPageOptions {\n limit?: number;\n before?: string;\n}\n\nconst DEFAULT_HISTORY_PAGE_LIMIT = 50;\nconst MAX_HISTORY_PAGE_LIMIT = 200;\nconst HISTORY_READ_CHUNK_BYTES = 64 * 1024;\nconst HISTORY_CURSOR_PREFIX = \"b:\";\n\nfunction normalizeHistoryPageLimit(limit: unknown): number {\n if (typeof limit !== \"number\" || !Number.isFinite(limit)) return DEFAULT_HISTORY_PAGE_LIMIT;\n return Math.max(1, Math.min(MAX_HISTORY_PAGE_LIMIT, Math.floor(limit)));\n}\n\nfunction encodeHistoryCursor(offset: number): string {\n return `${HISTORY_CURSOR_PREFIX}${Math.max(0, Math.floor(offset))}`;\n}\n\nfunction decodeHistoryCursor(cursor: string | undefined, fileSize: number): number {\n if (!cursor) return fileSize;\n const raw = cursor.startsWith(HISTORY_CURSOR_PREFIX)\n ? cursor.slice(HISTORY_CURSOR_PREFIX.length)\n : cursor;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || parsed < 0) return fileSize;\n return Math.min(parsed, fileSize);\n}\n\nasync function findClaudeSessionFile(claudeSessionId: string): Promise<string | null> {\n let projectDirs: string[];\n try {\n projectDirs = await readdir(claudeProjectsDir());\n } catch {\n return null;\n }\n\n for (const encodedDir of projectDirs) {\n const filePath = join(claudeProjectsDir(), encodedDir, `${claudeSessionId}.jsonl`);\n try {\n await access(filePath);\n return filePath;\n } catch {\n continue;\n }\n }\n\n return null;\n}\n\nfunction extractConversationMessageFromJson(obj: unknown): Omit<SessionMessage, \"cursor\"> | null {\n if (!obj || typeof obj !== \"object\") return null;\n const record = obj as {\n type?: unknown;\n isMeta?: unknown;\n message?: unknown;\n timestamp?: unknown;\n };\n if (record.type === \"user\") {\n if (record.isMeta) return null;\n const text = extractConversationText(record.message);\n if (!text) return null;\n const ts =\n typeof record.timestamp === \"string\" ? new Date(record.timestamp).getTime() : undefined;\n return { role: \"user\", text, timestamp: ts };\n }\n if (record.type === \"assistant\") {\n const text = extractConversationText(record.message);\n if (!text) return null;\n const ts =\n typeof record.timestamp === \"string\" ? new Date(record.timestamp).getTime() : undefined;\n return { role: \"assistant\", text, timestamp: ts };\n }\n return null;\n}\n\nfunction splitLineSegments(\n block: Buffer,\n blockStart: number,\n): Array<{ start: number; line: Buffer }> {\n const segments: Array<{ start: number; line: Buffer }> = [];\n let start = 0;\n for (let i = 0; i < block.length; i += 1) {\n if (block[i] !== 10) continue;\n segments.push({ start: blockStart + start, line: block.subarray(start, i) });\n start = i + 1;\n }\n segments.push({ start: blockStart + start, line: block.subarray(start) });\n return segments;\n}\n\nfunction stripCarriageReturn(line: Buffer): Buffer {\n return line.length > 0 && line[line.length - 1] === 13 ? line.subarray(0, -1) : line;\n}\n\nasync function readSessionMessagesPageFromFile(\n filePath: string,\n options: SessionMessagesPageOptions = {},\n): Promise<SessionMessagesPage> {\n const limit = normalizeHistoryPageLimit(options.limit);\n const file = await open(filePath, \"r\");\n try {\n const fileStat = await file.stat();\n const endOffset = decodeHistoryCursor(options.before, fileStat.size);\n if (endOffset <= 0) return { messages: [], hasMore: false };\n\n let position = endOffset;\n let carry: Buffer = Buffer.alloc(0);\n const collected: SessionMessage[] = [];\n\n while (position > 0 && collected.length <= limit) {\n const readSize = Math.min(HISTORY_READ_CHUNK_BYTES, position);\n position -= readSize;\n const chunk = Buffer.alloc(readSize);\n await file.read(chunk, 0, readSize, position);\n\n const block = carry.length > 0 ? Buffer.concat([chunk, carry]) : chunk;\n const segments = splitLineSegments(block, position);\n const firstCompleteIndex = position > 0 ? 1 : 0;\n carry = position > 0 ? (segments[0]?.line ?? Buffer.alloc(0)) : Buffer.alloc(0);\n\n for (let i = segments.length - 1; i >= firstCompleteIndex; i -= 1) {\n const segment = segments[i];\n if (!segment) continue;\n const line = stripCarriageReturn(segment.line);\n if (line.length === 0) continue;\n try {\n const parsed = JSON.parse(line.toString(\"utf-8\"));\n const message = extractConversationMessageFromJson(parsed);\n if (!message) continue;\n collected.push({ ...message, cursor: encodeHistoryCursor(segment.start) });\n if (collected.length > limit) break;\n } catch {\n /* skip malformed lines */\n }\n }\n }\n\n const page = collected.slice(0, limit).reverse();\n const hasMore = collected.length > limit;\n return {\n messages: page,\n hasMore,\n ...(hasMore && page[0]?.cursor ? { nextBefore: page[0].cursor } : {}),\n };\n } finally {\n await file.close();\n }\n}\n\n// 从 JSONL 文件中提取 user/assistant 对话消息用于恢复时展示历史\nexport async function readSessionMessages(claudeSessionId: string): Promise<SessionMessage[]> {\n const filePath = await findClaudeSessionFile(claudeSessionId);\n if (!filePath) return [];\n\n const messages: SessionMessage[] = [];\n return new Promise((resolve) => {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n\n rl.on(\"line\", (line) => {\n if (!line.trim()) return;\n try {\n const message = extractConversationMessageFromJson(JSON.parse(line));\n if (message) messages.push(message);\n } catch {\n /* skip */\n }\n });\n\n rl.on(\"close\", () => resolve(messages));\n rl.on(\"error\", () => resolve(messages));\n });\n}\n\nexport async function readSessionMessagesPage(\n claudeSessionId: string,\n options: SessionMessagesPageOptions = {},\n): Promise<SessionMessagesPage> {\n const filePath = await findClaudeSessionFile(claudeSessionId);\n if (!filePath) return { messages: [], hasMore: false };\n return readSessionMessagesPageFromFile(filePath, options);\n}\n\n// 从 message 字段提取文本,统一处理多种格式\nfunction collapseWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\nfunction truncateTitle(text: string): string {\n const chars = Array.from(text);\n return chars.length > MAX_HISTORY_TITLE_LENGTH\n ? `${chars.slice(0, MAX_HISTORY_TITLE_LENGTH).join(\"\")}...`\n : text;\n}\n\nfunction isXmlishNoise(text: string): boolean {\n const match = text.match(/^<([A-Za-z][\\w:-]*)\\b/);\n if (!match) return false;\n const tag = match[1].toLowerCase();\n return XMLISH_NOISE_PREFIXES.some((prefix) => tag === prefix || tag.startsWith(`${prefix}_`));\n}\n\nexport function normalizeHistoryTitle(raw: string | null | undefined): string | null {\n if (!raw) return null;\n const text = collapseWhitespace(raw);\n if (text.length < 2) return null;\n if (text.startsWith(\"<\") || isXmlishNoise(text)) return null;\n if (INTERNAL_TITLE_PATTERNS.some((pattern) => pattern.test(text))) return null;\n\n const slashCommand = text.match(/^\\/\\S+/)?.[0];\n if (slashCommand && IGNORED_SLASH_COMMANDS.has(slashCommand)) return null;\n\n return truncateTitle(text);\n}\n\nfunction extractSlashCommand(text: string): string | null {\n const nameMatch = text.match(/<command-name>([^<]+)<\\/command-name>/);\n if (!nameMatch) return null;\n const argsMatch = text.match(/<command-args>([^<]+)<\\/command-args>/);\n const args = argsMatch ? argsMatch[1].trim() : \"\";\n return normalizeHistoryTitle(args ? `${nameMatch[1]} ${args}` : nameMatch[1]);\n}\n\nfunction extractMessageText(msg: unknown): string | null {\n if (typeof msg === \"string\") {\n const cmd = extractSlashCommand(msg);\n if (cmd) return cmd;\n return normalizeHistoryTitle(msg);\n }\n\n if (msg && typeof msg === \"object\" && \"content\" in msg) {\n const content = (msg as { content: unknown }).content;\n if (typeof content === \"string\") {\n const cmd = extractSlashCommand(content);\n if (cmd) return cmd;\n return normalizeHistoryTitle(content);\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter(\n (b: { type?: string; text?: string }) => b.type === \"text\" && typeof b.text === \"string\",\n )\n .map((b: { text: string }) => b.text);\n const joined = texts.join(\"\\n\").trim();\n return normalizeHistoryTitle(joined);\n }\n }\n\n if (Array.isArray(msg)) {\n const texts = msg\n .filter(\n (b: { type?: string; text?: string }) => b.type === \"text\" && typeof b.text === \"string\",\n )\n .map((b: { text: string }) => b.text);\n const joined = texts.join(\"\\n\").trim();\n return normalizeHistoryTitle(joined);\n }\n\n return null;\n}\n\nfunction normalizeConversationText(text: string): string | null {\n const trimmed = text.trim();\n if (!trimmed) return null;\n return trimmed;\n}\n\n// 对话正文恢复必须保留换行和 Markdown 结构;不能复用标题归一化逻辑。\nfunction extractConversationText(msg: unknown): string | null {\n if (typeof msg === \"string\") {\n const cmd = extractSlashCommand(msg);\n if (cmd) return cmd;\n return normalizeConversationText(msg);\n }\n\n if (msg && typeof msg === \"object\" && \"content\" in msg) {\n const content = (msg as { content: unknown }).content;\n if (typeof content === \"string\") {\n const cmd = extractSlashCommand(content);\n if (cmd) return cmd;\n return normalizeConversationText(content);\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter(\n (b: { type?: string; text?: string }) => b.type === \"text\" && typeof b.text === \"string\",\n )\n .map((b: { text: string }) => b.text);\n return normalizeConversationText(texts.join(\"\\n\"));\n }\n }\n\n if (Array.isArray(msg)) {\n const texts = msg\n .filter(\n (b: { type?: string; text?: string }) => b.type === \"text\" && typeof b.text === \"string\",\n )\n .map((b: { text: string }) => b.text);\n return normalizeConversationText(texts.join(\"\\n\"));\n }\n\n return null;\n}\n\n// 从 JSONL 文件头部提取 cwd 和第一条有效用户文本消息作为标题\n// cwd 从任意行的 cwd 字段获取,title 从第一条 user 消息获取\nasync function extractTitleAndCwd(\n filePath: string,\n): Promise<{ title: string | null; cwd: string | null }> {\n return new Promise((resolve) => {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n let resolved = false;\n let cwd: string | null = null;\n let title: string | null = null;\n\n rl.on(\"line\", (line) => {\n if (resolved) return;\n if (!line.trim()) return;\n\n try {\n const obj = JSON.parse(line);\n if (!cwd && typeof obj.cwd === \"string\") {\n cwd = obj.cwd;\n }\n if (!title && obj.type === \"user\" && !obj.isMeta) {\n const text = extractMessageText(obj.message);\n if (text) title = text;\n }\n if (cwd && title) {\n resolved = true;\n rl.close();\n }\n } catch {\n /* skip malformed lines */\n }\n });\n\n rl.on(\"close\", () => {\n if (!resolved) resolve({ title, cwd });\n else resolve({ title, cwd });\n });\n rl.on(\"error\", () => resolve({ title, cwd }));\n });\n}\n\nasync function collectJsonlFiles(root: string): Promise<string[]> {\n let entries: Array<{ name: string; isDirectory(): boolean; isFile(): boolean }>;\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n return [];\n }\n\n const files: string[] = [];\n for (const entry of entries) {\n const child = join(root, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await collectJsonlFiles(child)));\n } else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n files.push(child);\n }\n }\n return files;\n}\n\nasync function extractCodexTitleAndCwd(\n filePath: string,\n): Promise<{ id: string | null; title: string | null; cwd: string | null }> {\n return new Promise((resolve) => {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n let id: string | null = null;\n let cwd: string | null = null;\n let title: string | null = null;\n\n rl.on(\"line\", (line) => {\n if (!line.trim()) return;\n try {\n const obj = JSON.parse(line);\n if (obj.type === \"session_meta\" && obj.payload) {\n if (!id && typeof obj.payload.id === \"string\") id = obj.payload.id;\n if (!cwd && typeof obj.payload.cwd === \"string\") cwd = obj.payload.cwd;\n }\n if (!title && obj.type === \"response_item\") {\n const text = extractCodexUserText(obj.payload);\n if (text) title = text;\n }\n if (id && cwd && title) rl.close();\n } catch {\n /* skip malformed lines */\n }\n });\n\n rl.on(\"close\", () => resolve({ id, title, cwd }));\n rl.on(\"error\", () => resolve({ id, title, cwd }));\n });\n}\n\nfunction extractCodexUserText(payload: unknown): string | null {\n if (!payload || typeof payload !== \"object\") return null;\n const item = payload as { type?: unknown; role?: unknown; content?: unknown };\n if (item.type !== \"message\" || item.role !== \"user\") return null;\n if (typeof item.content === \"string\") return normalizeHistoryTitle(item.content);\n if (!Array.isArray(item.content)) return null;\n const texts = item.content\n .map((block: unknown) => {\n if (!block || typeof block !== \"object\") return \"\";\n const typed = block as { type?: unknown; text?: unknown };\n return typed.type === \"input_text\" && typeof typed.text === \"string\" ? typed.text : \"\";\n })\n .filter(Boolean);\n const joined = texts.join(\"\\n\").trim();\n return normalizeHistoryTitle(joined);\n}\n","import { readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\ninterface CommandEntry {\n name: string;\n description: string;\n argumentHint?: string;\n source: string;\n}\n\nconst REPL_BUILTINS: CommandEntry[] = [\n { name: \"/compact\", description: \"Compact conversation history\", source: \"builtin\" },\n { name: \"/status\", description: \"Show session status\", source: \"builtin\" },\n { name: \"/cost\", description: \"Show token usage and cost\", source: \"builtin\" },\n { name: \"/clear\", description: \"Clear conversation history\", source: \"builtin\" },\n {\n name: \"/model\",\n description: \"Switch AI model\",\n argumentHint: \"model name (e.g., Haiku, Sonnet)\",\n source: \"builtin\",\n },\n { name: \"/help\", description: \"Show available commands\", source: \"builtin\" },\n { name: \"/memory\", description: \"Edit CLAUDE.md memory\", source: \"builtin\" },\n { name: \"/review\", description: \"Review diff of changes\", source: \"builtin\" },\n { name: \"/vim\", description: \"Enter vim mode\", source: \"builtin\" },\n { name: \"/terminal-setup\", description: \"Configure terminal integration\", source: \"builtin\" },\n { name: \"/permissions\", description: \"View and manage permissions\", source: \"builtin\" },\n { name: \"/allowed-tools\", description: \"View allowed tools\", source: \"builtin\" },\n {\n name: \"/add-dir\",\n description: \"Add working directory\",\n argumentHint: \"directory path\",\n source: \"builtin\",\n },\n { name: \"/init\", description: \"Initialize CLAUDE.md in project\", source: \"builtin\" },\n { name: \"/listen\", description: \"Listen for multi-turn responses\", source: \"builtin\" },\n { name: \"/pr-comments\", description: \"View PR comments\", source: \"builtin\" },\n { name: \"/release-notes\", description: \"Generate release notes\", source: \"builtin\" },\n { name: \"/ide\", description: \"Open IDE integration\", source: \"builtin\" },\n];\n\nconst COMMAND_BLACKLIST = new Set([\n \"/login\",\n \"/logout\",\n \"/config\",\n \"/plugin\",\n \"/mcp\",\n \"/install\",\n \"/setup-token\",\n \"/doctor\",\n \"/update\",\n \"/upgrade\",\n \"/memory\",\n \"/vim\",\n \"/terminal-setup\",\n \"/permissions\",\n \"/allowed-tools\",\n \"/ide\",\n \"/listen\",\n]);\n\ninterface DiscoverOptions {\n homeDir?: string;\n}\n\n/**\n * 从 SKILL.md 内容中解析 YAML frontmatter 的 name/description/argument-hint\n */\nexport function parseSkillFrontmatter(content: string): {\n name?: string;\n description?: string;\n argumentHint?: string;\n} {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/);\n if (!match) return {};\n\n const yaml = match[1];\n const result: { name?: string; description?: string; argumentHint?: string } = {};\n\n const nameMatch = yaml.match(/^name:\\s*(.+)$/m);\n if (nameMatch) result.name = nameMatch[1].trim();\n\n const descMatch = yaml.match(/^description:\\s*(.+)$/m);\n if (descMatch) result.description = descMatch[1].trim();\n\n const hintMatch = yaml.match(/^argument-hint:\\s*(.+)$/m);\n if (hintMatch) result.argumentHint = hintMatch[1].trim();\n\n return result;\n}\n\n/**\n * 扫描 skills 目录,每个子目录下的 SKILL.md 解析为一条命令\n */\nfunction scanSkillsDir(dirPath: string, source: string): CommandEntry[] {\n let entries: string[];\n try {\n entries = readdirSync(dirPath, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n return [];\n }\n\n const commands: CommandEntry[] = [];\n for (const name of entries) {\n const skillPath = join(dirPath, name, \"SKILL.md\");\n try {\n const content = readFileSync(skillPath, \"utf-8\");\n const parsed = parseSkillFrontmatter(content);\n commands.push({\n name: `/${parsed.name ?? name}`,\n description: parsed.description ?? \"\",\n argumentHint: parsed.argumentHint,\n source,\n });\n } catch {\n // SKILL.md 不存在或不可读,跳过\n }\n }\n return commands;\n}\n\n/**\n * 扫描 commands 目录,每个 .md 文件名即为命令名\n */\nfunction scanCommandsDir(dirPath: string, source: string): CommandEntry[] {\n let entries: string[];\n try {\n entries = readdirSync(dirPath).filter((f) => f.endsWith(\".md\"));\n } catch {\n return [];\n }\n\n const commands: CommandEntry[] = [];\n for (const filename of entries) {\n const cmdName = filename.replace(/\\.md$/, \"\");\n try {\n const content = readFileSync(join(dirPath, filename), \"utf-8\");\n const firstLine = content.split(\"\\n\")[0].trim();\n commands.push({\n name: `/${cmdName}`,\n description: firstLine,\n source,\n });\n } catch {\n commands.push({\n name: `/${cmdName}`,\n description: \"\",\n source,\n });\n }\n }\n return commands;\n}\n\n/**\n * 扫描插件目录中的 skills 和 commands 子目录\n */\nfunction scanPluginDirs(homeDir: string): CommandEntry[] {\n const pluginCacheDir = join(homeDir, \".claude\", \"plugins\", \"cache\");\n let pluginNames: string[];\n try {\n pluginNames = readdirSync(pluginCacheDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n return [];\n }\n\n const commands: CommandEntry[] = [];\n for (const pluginName of pluginNames) {\n const pluginDir = join(pluginCacheDir, pluginName);\n const skillCmds = scanSkillsDir(join(pluginDir, \"skills\"), \"plugin-skill\");\n const cmdCmds = scanCommandsDir(join(pluginDir, \"commands\"), \"plugin-command\");\n commands.push(...skillCmds, ...cmdCmds);\n }\n return commands;\n}\n\n/**\n * 发现所有可用的斜杠命令,合并多个来源并过滤黑名单\n *\n * 来源优先级: project > user > plugin > builtin\n * 同名命令按优先级高的保留\n */\nexport async function discoverCommands(\n workDir: string,\n options?: DiscoverOptions,\n): Promise<CommandEntry[]> {\n const homeDir = options?.homeDir ?? homedir();\n\n const builtins = REPL_BUILTINS.filter((c) => !COMMAND_BLACKLIST.has(c.name));\n const userSkills = scanSkillsDir(join(homeDir, \".claude\", \"skills\"), \"user-skill\");\n const projectSkills = scanSkillsDir(join(workDir, \".claude\", \"skills\"), \"project-skill\");\n const userCommands = scanCommandsDir(join(homeDir, \".claude\", \"commands\"), \"user-command\");\n const projectCommands = scanCommandsDir(join(workDir, \".claude\", \"commands\"), \"project-command\");\n const pluginCommands = scanPluginDirs(homeDir);\n\n // 按优先级从低到高合并,同名命令后者覆盖前者\n const commandMap = new Map<string, CommandEntry>();\n for (const cmd of builtins) commandMap.set(cmd.name, cmd);\n for (const cmd of pluginCommands) commandMap.set(cmd.name, cmd);\n for (const cmd of userSkills) commandMap.set(cmd.name, cmd);\n for (const cmd of userCommands) commandMap.set(cmd.name, cmd);\n for (const cmd of projectSkills) commandMap.set(cmd.name, cmd);\n for (const cmd of projectCommands) commandMap.set(cmd.name, cmd);\n\n // 再次过滤黑名单,防止外部来源引入黑名单命令\n const result: CommandEntry[] = [];\n for (const cmd of commandMap.values()) {\n if (!COMMAND_BLACKLIST.has(cmd.name)) {\n result.push(cmd);\n }\n }\n\n return result;\n}\n","import { ControlErrorCode } from \"@dev-anywhere/shared\";\n\nfunction getFsErrorCode(err: unknown): string | undefined {\n return typeof err === \"object\" && err !== null && \"code\" in err\n ? String((err as { code?: unknown }).code)\n : undefined;\n}\n\nexport function classifyPathError(err: unknown): ControlErrorCode {\n switch (getFsErrorCode(err)) {\n case \"ENOENT\":\n return ControlErrorCode.PATH_NOT_FOUND;\n case \"ENOTDIR\":\n return ControlErrorCode.PATH_NOT_DIRECTORY;\n case \"EACCES\":\n case \"EPERM\":\n return ControlErrorCode.PATH_ACCESS_DENIED;\n default:\n return ControlErrorCode.UNKNOWN;\n }\n}\n","import { connect, type Socket } from \"node:net\";\nimport { unlinkSync, existsSync, readdirSync } from \"node:fs\";\nimport type { ChildProcess } from \"node:child_process\";\nimport { buildMessage } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport {\n ContentBlockDeltaSchema,\n IGNORED_EVENT_TYPES,\n KnownContentBlockSchema,\n StreamJsonEventSchema,\n} from \"../common/stream-json-schema.js\";\nimport { DATA_DIR, sessionPaths } from \"../common/paths.js\";\nimport { spawnScript } from \"../common/env.js\";\nimport { SeqCounter } from \"../common/seq-counter.js\";\nimport { createWorkerReader, serializeWorkerMsg, type WorkerMessage } from \"../ipc/ipc-protocol.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { JsonObserver } from \"./json-observer.js\";\nimport type { ProviderHookContext } from \"../providers/index.js\";\nimport type { PermissionBroker, PermissionDecision } from \"./permission-broker.js\";\n\ninterface WorkerRegistryDeps {\n sessionManager: SessionManager;\n permissionBroker: PermissionBroker;\n relayConnection: RelayConnection;\n // JSON 观察通道状态机;forwardEvent / forwardApprovalRequest 据此推状态变迁\n jsonObserver: JsonObserver;\n touchSessionActivity?: (sessionId: string) => boolean;\n getProviderEnv: () => NodeJS.ProcessEnv;\n nextSeq?: (sessionId: string) => number;\n}\n\ninterface SpawnOptions {\n cwd?: string;\n resumeSessionId?: string;\n permissionMode?: string;\n // 开启后 worker spawn claude 带 --include-partial-messages,forwardEvent 处理 stream_event delta;\n // aggregated assistant 的 text/thinking 会被跳过避免和 delta 重复\n streamDelta?: boolean;\n hook?: ProviderHookContext;\n}\n\n// 管理 session → worker socket 的映射,封装全部 worker IO:\n// - spawn / connect / reconnectAll / destroyAll 生命周期入口\n// - send(sessionId, msg) 统一出口\n// - worker_event 路由、worker_approval_request 转发、worker_exit 清理都在内部闭环\nexport class WorkerRegistry {\n private sockets = new Map<string, Socket>();\n private children = new Map<string, ChildProcess>();\n // 记录哪些 session 是 spawn 时带 --stream-delta 的;forwardEvent 据此决定是否跳过 aggregated 去重\n private streamDeltaSessions = new Set<string>();\n\n constructor(private deps: WorkerRegistryDeps) {\n // relay queue 溢出时,被 drop 的 envelope 不会到达 client;若是 tool_use_request,\n // 主动清 pending 审批并回 worker env-failure deny,避免 worker 永挂、permission broker 泄漏。\n deps.relayConnection.on(\"envelope_dropped\", (raw: string) => this.onEnvelopeDropped(raw));\n }\n\n private onEnvelopeDropped(raw: string): void {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return;\n }\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n (parsed as { type?: unknown }).type !== \"tool_use_request\"\n ) {\n return;\n }\n const envelope = parsed as {\n sessionId?: unknown;\n payload?: { toolId?: unknown };\n };\n const sessionId = typeof envelope.sessionId === \"string\" ? envelope.sessionId : null;\n const requestId =\n envelope.payload && typeof envelope.payload.toolId === \"string\"\n ? envelope.payload.toolId\n : null;\n if (!sessionId || !requestId) return;\n if (\n !this.deps.permissionBroker.resolve(requestId, {\n behavior: \"deny\",\n message: \"Approval request was dropped due to relay queue overflow.\",\n })\n ) {\n return;\n }\n\n serviceLogger.warn(\n { sessionId, requestId },\n \"Tool approval request lost to relay queue overflow, denying worker\",\n );\n }\n\n spawn(sessionId: string, options?: SpawnOptions): number {\n const paths = sessionPaths(sessionId);\n const args: string[] = [sessionId, paths.workerSock];\n if (options?.cwd) args.push(\"--cwd\", options.cwd);\n if (options?.resumeSessionId) args.push(\"--resume\", options.resumeSessionId);\n // 远程场景默认 default,每个工具都需审批,覆盖用户全局 claude settings 的 defaultMode\n args.push(\"--permission-mode\", options?.permissionMode ?? \"default\");\n if (options?.streamDelta) {\n args.push(\"--stream-delta\");\n this.streamDeltaSessions.add(sessionId);\n }\n if (options?.hook) {\n args.push(\n \"--hook-provider\",\n options.hook.provider,\n \"--hook-url\",\n options.hook.hookUrl,\n \"--hook-marker\",\n options.hook.marker,\n );\n }\n args.push(\"--\");\n\n const providerEnv = this.deps.getProviderEnv();\n const child = spawnScript(new URL(\"../session-worker\", import.meta.url), args, {\n logger: serviceLogger,\n env: options?.hook\n ? { ...providerEnv, DEV_ANYWHERE_HOOK_TOKEN: options.hook.token }\n : providerEnv,\n });\n const workerPid = child.pid!;\n this.children.set(sessionId, child);\n serviceLogger.info(\n { sessionId, workerPid, cwd: options?.cwd, resume: options?.resumeSessionId },\n \"Worker process spawned\",\n );\n return workerPid;\n }\n\n connect(sessionId: string, sockPath: string): Promise<Socket | null> {\n return new Promise((resolve) => {\n const sock = connect(sockPath);\n sock.on(\"connect\", () => {\n this.sockets.set(sessionId, sock);\n createWorkerReader(sock, (msg) => this.handleWorkerMessage(sessionId, msg));\n sock.on(\"close\", () => this.onDisconnect(sessionId));\n sock.on(\"error\", () => this.onDisconnect(sessionId));\n resolve(sock);\n });\n sock.on(\"error\", () => resolve(null));\n });\n }\n\n // 枚举 DATA_DIR 下所有 session 目录,尝试连接存活的 worker.sock;失败则清理 stale socket。\n async reconnectAll(): Promise<void> {\n if (!existsSync(DATA_DIR)) return;\n\n const dirs = readdirSync(DATA_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());\n\n for (const dir of dirs) {\n const sessionId = dir.name;\n const paths = sessionPaths(sessionId);\n if (!existsSync(paths.workerSock)) continue;\n\n const sock = await this.connect(sessionId, paths.workerSock);\n if (sock) {\n if (!this.deps.sessionManager.getSession(sessionId)) {\n // 两边数据源不一致:DATA_DIR 下的 worker.sock 能连通说明 worker 进程还在跑,\n // 但 SessionManager 的内存 Map(持久化已在 load 时清过)里没这条 session。\n // 成因:sessions.json 被删 / 写盘失败 / 记录丢失而 worker 没跟着退。这类孤儿 worker 清掉。\n serviceLogger.warn(\n { sessionId },\n \"Orphaned worker found without session data, terminating\",\n );\n sock.end();\n this.sockets.delete(sessionId);\n continue;\n }\n serviceLogger.info({ sessionId }, \"Reconnected to existing worker\");\n } else {\n try {\n unlinkSync(paths.workerSock);\n } catch {\n // socket 文件可能已被删除\n }\n serviceLogger.info({ sessionId }, \"Cleaned up stale worker socket\");\n }\n }\n }\n\n has(sessionId: string): boolean {\n return this.sockets.has(sessionId);\n }\n\n delete(sessionId: string): void {\n this.children.delete(sessionId);\n this.sockets.delete(sessionId);\n this.streamDeltaSessions.delete(sessionId);\n }\n\n terminateProcess(sessionId: string, signal: NodeJS.Signals = \"SIGTERM\"): boolean {\n const child = this.children.get(sessionId);\n const sock = this.sockets.get(sessionId);\n sock?.destroy();\n this.sockets.delete(sessionId);\n this.streamDeltaSessions.delete(sessionId);\n this.children.delete(sessionId);\n if (!child || child.killed) return false;\n return child.kill(signal);\n }\n\n // 向指定 session 的 worker 写 WorkerMessage;socket 缺失或不可写返回 false 由 caller 决定日志。\n send(sessionId: string, msg: WorkerMessage): boolean {\n const sock = this.sockets.get(sessionId);\n if (!sock?.writable) return false;\n sock.write(serializeWorkerMsg(msg));\n return true;\n }\n\n destroyAll(): void {\n for (const [, ws] of this.sockets) {\n ws.destroy();\n }\n this.sockets.clear();\n }\n\n private handleWorkerMessage(sessionId: string, msg: WorkerMessage): void {\n switch (msg.type) {\n case \"worker_ready\":\n serviceLogger.info({ sessionId, pid: msg.pid }, \"Worker ready\");\n break;\n\n case \"worker_event\":\n try {\n this.forwardEvent(sessionId, msg.seq, msg.event);\n } catch (err) {\n serviceLogger.debug(\n { sessionId, error: String(err) },\n \"Failed to forward event to relay\",\n );\n }\n serviceLogger.debug({ sessionId, eventType: msg.event.type }, \"JSON session event\");\n break;\n\n case \"worker_exit\":\n this.deps.sessionManager.terminateSession(sessionId);\n this.delete(sessionId);\n serviceLogger.info({ sessionId, exitCode: msg.code }, \"JSON session exited\");\n break;\n\n case \"worker_approval_request\":\n this.forwardApprovalRequest(sessionId, msg);\n break;\n\n case \"worker_claude_session_id\":\n this.deps.sessionManager.setClaudeSessionId(sessionId, msg.sessionId);\n serviceLogger.info(\n { sessionId, claudeSessionId: msg.sessionId },\n \"Claude session ID captured\",\n );\n break;\n }\n }\n\n // worker 连接断开或异常时的统一清理入口。仅记录一份,不再区分 close vs error 语义。\n private onDisconnect(sessionId: string): void {\n this.sockets.delete(sessionId);\n this.deps.permissionBroker.cleanupSession(sessionId, \"Worker disconnected\");\n }\n\n // 对齐 Claude CLI stream-json 输出,按 type 分发:\n // stream_event.content_block_delta → 增量 text/thinking envelope(仅 streamDelta 会话产生)\n // assistant.content[].text → assistant_message envelope(streamDelta 下跳过,避免重复)\n // assistant.content[].thinking → thinking envelope(streamDelta 下跳过)\n // assistant.content[].tool_use → assistant_tool_use envelope\n // user.content[].tool_result → tool_result envelope\n // result → turn_result control + 会话状态回 IDLE\n // system/rate_limit_event/其他 → 静默忽略\n // schema 未识别的 event/block 以 warn 暴露,作为 Claude CLI 协议变化的 runtime canary。\n private forwardEvent(sessionId: string, seq: number, event: Record<string, unknown>): void {\n const relay = this.deps.relayConnection;\n const parsed = StreamJsonEventSchema.safeParse(event);\n if (!parsed.success) {\n const rawType = typeof event.type === \"string\" ? event.type : \"<missing>\";\n if (IGNORED_EVENT_TYPES.has(rawType)) {\n serviceLogger.debug({ sessionId, type: rawType }, \"Dropped ignored stream-json event\");\n return;\n }\n serviceLogger.warn(\n { sessionId, type: rawType, issues: parsed.error.issues.slice(0, 3) },\n \"Unknown stream-json event type; Claude CLI schema may have changed\",\n );\n return;\n }\n const ev = parsed.data;\n this.deps.touchSessionActivity?.(sessionId);\n const isStreamDeltaSession = this.streamDeltaSessions.has(sessionId);\n\n if (ev.type === \"stream_event\") {\n const delta = ContentBlockDeltaSchema.safeParse(ev.event);\n if (!delta.success) return; // 非 content_block_delta 的内层事件(message_start 等)忽略\n const d = delta.data.delta;\n if (d.type === \"text_delta\" && d.text) {\n relay.sendEnvelope(\n buildMessage(\n \"assistant_message\",\n sessionId,\n seq,\n { text: d.text, isPartial: true },\n \"proxy\",\n ),\n );\n } else if (d.type === \"thinking_delta\" && d.thinking) {\n relay.sendEnvelope(buildMessage(\"thinking\", sessionId, seq, { text: d.thinking }, \"proxy\"));\n }\n return;\n }\n\n if (ev.type === \"assistant\") {\n for (const raw of ev.message.content) {\n const blockParse = KnownContentBlockSchema.safeParse(raw);\n if (!blockParse.success) {\n const rawType =\n raw && typeof raw === \"object\"\n ? ((raw as Record<string, unknown>).type as string | undefined)\n : undefined;\n serviceLogger.warn(\n { sessionId, seq, blockType: rawType ?? \"<missing>\" },\n \"Unknown assistant content block; Claude CLI schema may have changed\",\n );\n continue;\n }\n const block = blockParse.data;\n if (block.type === \"text\") {\n // streamDelta 下增量已经发过了,aggregated 全文跳过避免重复\n if (!isStreamDeltaSession && block.text) {\n relay.sendEnvelope(\n buildMessage(\n \"assistant_message\",\n sessionId,\n seq,\n { text: block.text, isPartial: true },\n \"proxy\",\n ),\n );\n }\n } else if (block.type === \"thinking\") {\n // Opus extended thinking 明文被 Anthropic 服务端 redact 时 block.thinking 为空字符串,\n // 不转发;session WORKING 状态已经覆盖\"Claude 在思考\"信号,redacted envelope 无新信息\n if (!isStreamDeltaSession && block.thinking) {\n relay.sendEnvelope(\n buildMessage(\"thinking\", sessionId, seq, { text: block.thinking }, \"proxy\"),\n );\n }\n } else if (block.type === \"tool_use\") {\n relay.sendEnvelope(\n buildMessage(\n \"assistant_tool_use\",\n sessionId,\n seq,\n { toolName: block.name, toolId: block.id, parameters: block.input },\n \"proxy\",\n ),\n );\n }\n }\n return;\n }\n\n if (ev.type === \"user\") {\n for (const raw of ev.message.content) {\n const blockParse = KnownContentBlockSchema.safeParse(raw);\n if (!blockParse.success) continue;\n const block = blockParse.data;\n if (block.type !== \"tool_result\") continue;\n relay.sendEnvelope(\n buildMessage(\n \"tool_result\",\n sessionId,\n seq,\n { toolId: block.tool_use_id, result: block.content, isError: block.is_error ?? false },\n \"proxy\",\n ),\n );\n }\n return;\n }\n\n if (ev.type === \"result\") {\n const resultText = typeof ev.result === \"string\" ? ev.result : undefined;\n relay.sendRaw(\n JSON.stringify({\n type: \"turn_result\",\n sessionId,\n success: ev.subtype === \"success\",\n isError: ev.is_error ?? false,\n ...(resultText ? { result: resultText } : {}),\n }),\n );\n this.deps.jsonObserver.onTurnResult(sessionId);\n }\n }\n\n private forwardApprovalRequest(\n sessionId: string,\n msg: Extract<WorkerMessage, { type: \"worker_approval_request\" }>,\n ): void {\n serviceLogger.info(\n { sessionId, toolName: msg.toolName, requestId: msg.requestId },\n \"Tool approval forwarding to relay\",\n );\n this.deps.jsonObserver.onApprovalRequested(sessionId);\n try {\n const approvalSeq = this.deps.nextSeq?.(sessionId) ?? new SeqCounter(sessionId).next();\n const envelope = buildMessage(\n \"tool_use_request\",\n sessionId,\n approvalSeq,\n {\n toolName: msg.toolName,\n toolId: msg.requestId,\n parameters: msg.input,\n },\n \"proxy\",\n );\n const session = this.deps.sessionManager.getSession(sessionId);\n const registered = this.deps.permissionBroker.registerWorkerRequest(\n {\n requestId: msg.requestId,\n provider: session?.provider ?? \"claude\",\n sessionId,\n toolName: msg.toolName,\n input: msg.input,\n },\n (decision: PermissionDecision) => {\n this.send(sessionId, {\n type: \"worker_approval_response\",\n requestId: msg.requestId,\n behavior: decision.behavior,\n ...(decision.message ? { message: decision.message } : {}),\n });\n },\n );\n if (!registered) return;\n this.deps.relayConnection.sendEnvelope(envelope);\n } catch (err) {\n const resolved = this.deps.permissionBroker.resolve(msg.requestId, {\n behavior: \"deny\",\n message: \"Failed to forward approval request to relay.\",\n });\n if (!resolved) {\n this.send(sessionId, {\n type: \"worker_approval_response\",\n requestId: msg.requestId,\n behavior: \"deny\",\n message: \"Failed to forward approval request to relay.\",\n });\n }\n // envelope 构造失败回 deny,避免 worker 无限等待。\n serviceLogger.warn(\n { sessionId, error: String(err) },\n \"Failed to forward tool approval to relay, denying\",\n );\n }\n }\n}\n","import type { Socket } from \"node:net\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { serializeIpc } from \"../ipc/ipc-protocol.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport type { HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\n\ntype SessionTerminationAction =\n | \"detach_local_terminal\"\n | \"terminate_hosted_pty\"\n | \"terminate_json_worker\"\n | \"not_found\";\n\ninterface TerminateSessionDeps {\n sessionManager: SessionManager;\n workerRegistry: WorkerRegistry;\n controlHandlers: ControlMessageHandlers;\n terminalSockets: Map<string, Socket>;\n hostedPtyRegistry: HostedPtyRegistry;\n agentStatusRegistry: AgentStatusRegistry;\n}\n\nexport function terminateSessionByOwnership(\n deps: TerminateSessionDeps,\n sessionId: string,\n): { success: boolean; action: SessionTerminationAction } {\n const session = deps.sessionManager.getSession(sessionId);\n\n if (session?.mode === \"pty\" && session.ptyOwner === \"local-terminal\") {\n const terminalSocket = deps.terminalSockets.get(sessionId);\n if (terminalSocket?.writable) {\n terminalSocket.write(serializeIpc({ type: \"pty_detach\", sessionId }));\n }\n deps.terminalSockets.delete(sessionId);\n const result = deps.sessionManager.terminateSession(sessionId, {\n preserveProviderHooks: true,\n });\n deps.controlHandlers.cleanup(sessionId);\n deps.agentStatusRegistry.delete(sessionId);\n serviceLogger.info(\n { sessionId, success: result.success },\n \"Local terminal session detached from remote view\",\n );\n return { success: result.success, action: \"detach_local_terminal\" };\n }\n\n if (session?.mode === \"pty\" && session.ptyOwner === \"proxy-hosted\") {\n const success = deps.hostedPtyRegistry.terminate(sessionId);\n serviceLogger.info({ sessionId, success }, \"Hosted PTY termination requested\");\n return { success, action: \"terminate_hosted_pty\" };\n }\n\n if (session?.mode === \"json\") {\n deps.workerRegistry.send(sessionId, { type: \"worker_stop\" });\n deps.workerRegistry.delete(sessionId);\n const result = deps.sessionManager.terminateSession(sessionId);\n deps.controlHandlers.cleanup(sessionId);\n deps.agentStatusRegistry.delete(sessionId);\n serviceLogger.info({ sessionId, success: result.success }, \"JSON worker session terminated\");\n return { success: result.success, action: \"terminate_json_worker\" };\n }\n\n const hostedTerminated = deps.hostedPtyRegistry.terminate(sessionId);\n if (hostedTerminated) {\n return { success: true, action: \"terminate_hosted_pty\" };\n }\n return { success: false, action: \"not_found\" };\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\nimport { nanoid } from \"nanoid\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport { DATA_DIR } from \"../common/paths.js\";\n\nconst MAX_CLIPBOARD_IMAGE_BYTES = 10 * 1024 * 1024;\nconst MAX_CLIPBOARD_IMAGE_BASE64_LENGTH = Math.ceil(MAX_CLIPBOARD_IMAGE_BYTES / 3) * 4;\nconst IMAGE_EXTENSIONS: ReadonlyMap<string, string> = new Map([\n [\"image/png\", \"png\"],\n [\"image/jpeg\", \"jpg\"],\n [\"image/webp\", \"webp\"],\n [\"image/gif\", \"gif\"],\n] as const);\n\nexport type ClipboardImageUploadRequest = {\n sessionId: string;\n mimeType: string;\n dataBase64: string;\n fileName?: string;\n};\n\ntype ClipboardImageUploadResult = {\n success: boolean;\n path: string;\n error?: string;\n errorCode?: ControlErrorCode;\n};\n\ntype ClipboardImageUploadOptions = {\n dataDir?: string;\n now?: () => number;\n randomSuffix?: () => string;\n};\n\nfunction formatTimestamp(ms: number): string {\n const [date, time = \"000000\"] = new Date(ms)\n .toISOString()\n .replace(/\\.\\d{3}Z$/, \"\")\n .split(\"T\");\n return `${date.replace(/-/g, \"\")}-${time.replace(/:/g, \"\")}`;\n}\n\nfunction normalizeBase64(input: string): string {\n return input.replace(/^data:[^;]+;base64,/i, \"\").replace(/\\s/g, \"\");\n}\n\nfunction decodeBase64Image(dataBase64: string): Buffer {\n const normalized = normalizeBase64(dataBase64);\n if (normalized.length > MAX_CLIPBOARD_IMAGE_BASE64_LENGTH) {\n throw new Error(\"图片超过 10MB 限制\");\n }\n if (!normalized || !/^[A-Za-z0-9+/]*={0,2}$/.test(normalized)) {\n throw new Error(\"图片数据不是有效的 base64\");\n }\n const buffer = Buffer.from(normalized, \"base64\");\n if (buffer.length === 0) throw new Error(\"图片数据为空\");\n if (buffer.length > MAX_CLIPBOARD_IMAGE_BYTES) {\n throw new Error(\"图片超过 10MB 限制\");\n }\n return buffer;\n}\n\nfunction resolveSessionClipboardDir(dataDir: string, sessionId: string): string {\n const root = resolve(dataDir);\n const uploadDir = resolve(root, sessionId, \"clipboard\");\n const relativePath = relative(root, uploadDir);\n if (!relativePath || relativePath.startsWith(\"..\") || isAbsolute(relativePath)) {\n throw new Error(\"会话路径无效\");\n }\n return uploadDir;\n}\n\nexport function saveClipboardImageUpload(\n request: ClipboardImageUploadRequest,\n options: ClipboardImageUploadOptions = {},\n): ClipboardImageUploadResult {\n const extension = IMAGE_EXTENSIONS.get(request.mimeType);\n if (!extension) {\n return {\n success: false,\n path: \"\",\n error: \"不支持这种图片格式\",\n errorCode: ControlErrorCode.UNKNOWN,\n };\n }\n\n try {\n const dataDir = options.dataDir ?? DATA_DIR;\n const uploadDir = resolveSessionClipboardDir(dataDir, request.sessionId);\n const buffer = decodeBase64Image(request.dataBase64);\n const now = options.now ?? Date.now;\n const suffix = options.randomSuffix?.() ?? nanoid(6);\n const fileName = `pasted-${formatTimestamp(now())}-${suffix}.${extension}`;\n const path = join(uploadDir, fileName);\n\n mkdirSync(uploadDir, { recursive: true });\n writeFileSync(path, buffer, { mode: 0o600 });\n return { success: true, path };\n } catch (err) {\n return {\n success: false,\n path: \"\",\n error: err instanceof Error ? err.message : String(err),\n errorCode: ControlErrorCode.UNKNOWN,\n };\n }\n}\n","import { serializeIpc } from \"../ipc/ipc-protocol.js\";\n\nexport function serializeRawPtyInput(sessionId: string, data: string): string {\n return serializeIpc({ type: \"pty_input\", sessionId, data });\n}\n","import type { Socket } from \"node:net\";\nimport { ControlErrorCode, MessageEnvelopeSchema } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { saveClipboardImageUpload } from \"./clipboard-image-upload.js\";\nimport { serializeRawPtyInput } from \"./pty-input.js\";\nimport type { HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport type { JsonObserver } from \"./json-observer.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\n\ninterface RelayInputHandlersDeps {\n sessionManager: SessionManager;\n workerRegistry: WorkerRegistry;\n relayConnection: RelayConnection;\n terminalSockets: Map<string, Socket>;\n hostedPtyRegistry: HostedPtyRegistry;\n jsonObserver: JsonObserver;\n}\n\nexport class RelayInputHandlers {\n constructor(private readonly deps: RelayInputHandlersDeps) {}\n\n onUserInput(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n if (!sessionId) return;\n\n const session = this.deps.sessionManager.getSession(sessionId);\n if (!session) {\n serviceLogger.warn({ sessionId }, \"Remote input dropped: session not found\");\n return;\n }\n\n const payload = msg.payload as { text?: string; messageId?: string } | undefined;\n const text = payload?.text ?? \"\";\n\n if (session.mode === \"json\") {\n this.deps.jsonObserver.onTurnStart(sessionId);\n const sent = this.deps.workerRegistry.send(sessionId, {\n type: \"worker_input\",\n content: text,\n });\n if (!sent) {\n serviceLogger.warn({ sessionId }, \"Remote input dropped: JSON worker socket not available\");\n return;\n }\n const timestamp =\n typeof msg.timestamp === \"number\" && Number.isFinite(msg.timestamp)\n ? msg.timestamp\n : Date.now();\n const seq =\n typeof msg.seq === \"number\" && Number.isInteger(msg.seq) && msg.seq >= 0 ? msg.seq : 0;\n const version = typeof msg.version === \"string\" ? msg.version : \"1\";\n const messageId =\n typeof payload?.messageId === \"string\" && payload.messageId.length > 0\n ? payload.messageId\n : `${sessionId}-user-${timestamp}`;\n this.deps.relayConnection.sendEnvelope(\n MessageEnvelopeSchema.parse({\n type: \"user_input\",\n sessionId,\n seq,\n timestamp,\n source: \"proxy\",\n version,\n payload: { text, messageId },\n }),\n );\n serviceLogger.info({ sessionId }, \"Remote input forwarded to JSON worker\");\n return;\n }\n\n serviceLogger.warn(\n { sessionId, mode: session.mode },\n \"Remote batch input dropped: PTY sessions require remote_input_raw\",\n );\n }\n\n onRemoteInputRaw(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const data = msg.data as string | undefined;\n if (!sessionId || data === undefined) return;\n\n const ts = this.deps.terminalSockets.get(sessionId);\n if (!ts?.writable && this.deps.hostedPtyRegistry.write(sessionId, data)) {\n serviceLogger.info(\n { sessionId, bytes: data.length },\n \"Raw PTY input forwarded to hosted PTY\",\n );\n return;\n }\n if (!ts?.writable) {\n serviceLogger.warn({ sessionId }, \"Raw PTY input dropped: terminal socket unavailable\");\n return;\n }\n ts.write(serializeRawPtyInput(sessionId, data));\n serviceLogger.info({ sessionId, bytes: data.length }, \"Raw PTY input forwarded\");\n }\n\n onClipboardImageUpload(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n if (!sessionId) return;\n\n const session = this.deps.sessionManager.getSession(sessionId);\n if (!session) {\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"clipboard_image_upload_response\",\n requestId,\n sessionId,\n success: false,\n path: \"\",\n error: \"会话不存在\",\n errorCode: ControlErrorCode.SESSION_NOT_FOUND,\n }),\n );\n serviceLogger.warn({ sessionId }, \"Clipboard image upload rejected: session not found\");\n return;\n }\n\n const result = saveClipboardImageUpload({\n sessionId,\n mimeType: typeof msg.mimeType === \"string\" ? msg.mimeType : \"\",\n dataBase64: typeof msg.dataBase64 === \"string\" ? msg.dataBase64 : \"\",\n fileName: typeof msg.fileName === \"string\" ? msg.fileName : undefined,\n });\n\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"clipboard_image_upload_response\",\n requestId,\n sessionId,\n ...result,\n }),\n );\n serviceLogger.info({ sessionId, success: result.success }, \"Clipboard image upload handled\");\n }\n}\n","import { serviceLogger } from \"../common/logger.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\nimport { readSessionMessagesPage } from \"./session-history.js\";\nimport type { SessionManager } from \"./session-manager.js\";\n\ninterface RelayHistoryHandlersDeps {\n relaySend: RelaySend;\n sessionManager: SessionManager;\n permissionBroker: PermissionBroker;\n}\n\nexport class RelayHistoryHandlers {\n constructor(private readonly deps: RelayHistoryHandlersDeps) {}\n\n onSessionMessagesRequest(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n if (!sid) return;\n const requestId = msg.requestId as string | undefined;\n const before = msg.before as string | undefined;\n const limit = msg.limit as number | undefined;\n\n const session = this.deps.sessionManager.getSession(sid);\n if (session?.claudeSessionId) {\n readSessionMessagesPage(session.claudeSessionId, { before, limit })\n .then((page) => {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_history_messages\",\n requestId,\n sessionId: sid,\n ...(before !== undefined ? { before } : {}),\n messages: page.messages,\n hasMore: page.hasMore,\n ...(page.nextBefore !== undefined ? { nextBefore: page.nextBefore } : {}),\n }),\n );\n serviceLogger.info(\n {\n sessionId: sid,\n before,\n hasMore: page.hasMore,\n nextBefore: page.nextBefore,\n messageCount: page.messages.length,\n },\n \"History message page sent on request\",\n );\n })\n .catch((err) => {\n serviceLogger.warn(\n { sessionId: sid, error: String(err) },\n \"Failed to read session history page on request\",\n );\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_history_messages\",\n requestId,\n sessionId: sid,\n ...(before !== undefined ? { before } : {}),\n messages: [],\n hasMore: false,\n }),\n );\n });\n } else {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_history_messages\",\n requestId,\n sessionId: sid,\n ...(before !== undefined ? { before } : {}),\n messages: [],\n hasMore: false,\n }),\n );\n }\n\n const approvals = this.deps.permissionBroker.listSession(sid).map((approval) => ({\n requestId: approval.requestId,\n toolName: approval.toolName,\n input: approval.input,\n }));\n this.deps.relaySend(\n JSON.stringify({ type: \"pending_approvals_push\", sessionId: sid, approvals }),\n );\n serviceLogger.info({ sessionId: sid, count: approvals.length }, \"Pending approvals pushed\");\n }\n}\n","import { serviceLogger } from \"../common/logger.js\";\nimport type { HookEventRouter } from \"./hook-event-router.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\n\ninterface RelayPermissionHandlersDeps {\n relaySend: RelaySend;\n permissionBroker: PermissionBroker;\n hookEventRouter: HookEventRouter;\n workerRegistry: WorkerRegistry;\n}\n\nexport class RelayPermissionHandlers {\n constructor(private readonly deps: RelayPermissionHandlersDeps) {}\n\n onToolApprove(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const payload = msg.payload as { toolId?: string; whitelistTool?: boolean } | undefined;\n if (!sessionId || !payload?.toolId) return;\n\n const pending = this.deps.permissionBroker.get(payload.toolId);\n if (!pending) {\n this.pushPermissionDecisionResult(\n sessionId,\n payload.toolId,\n \"allow\",\n false,\n \"Permission request is no longer pending.\",\n );\n return;\n }\n if (!this.deps.permissionBroker.resolve(payload.toolId, { behavior: \"allow\" })) {\n this.pushPermissionDecisionResult(\n pending.sessionId,\n payload.toolId,\n \"allow\",\n false,\n \"Permission request is no longer pending.\",\n );\n return;\n }\n this.deps.hookEventRouter.onPermissionResolved(\n pending.sessionId,\n pending.provider,\n payload.toolId,\n \"allow\",\n { toolName: pending.toolName, toolInput: pending.input },\n );\n\n if (pending.source === \"worker\" && payload.whitelistTool) {\n const toolName = pending.toolName;\n if (toolName) {\n const whitelisted = this.deps.workerRegistry.send(pending.sessionId, {\n type: \"worker_whitelist_add\",\n toolName,\n });\n if (whitelisted) {\n serviceLogger.info(\n { sessionId: pending.sessionId, toolName },\n \"Tool added to session whitelist via relay\",\n );\n }\n }\n }\n this.pushPermissionDecisionResult(pending.sessionId, payload.toolId, \"allow\", true);\n serviceLogger.info(\n { sessionId, toolId: payload.toolId, whitelistTool: payload.whitelistTool },\n \"Tool approved via relay\",\n );\n }\n\n onToolDeny(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const payload = msg.payload as { toolId?: string; reason?: string } | undefined;\n if (!sessionId || !payload?.toolId) return;\n\n const reason = payload.reason ?? \"Denied by remote user\";\n const pending = this.deps.permissionBroker.get(payload.toolId);\n if (!pending) {\n this.pushPermissionDecisionResult(\n sessionId,\n payload.toolId,\n \"deny\",\n false,\n \"Permission request is no longer pending.\",\n );\n return;\n }\n if (\n !this.deps.permissionBroker.resolve(payload.toolId, {\n behavior: \"deny\",\n message: reason,\n })\n ) {\n this.pushPermissionDecisionResult(\n pending.sessionId,\n payload.toolId,\n \"deny\",\n false,\n \"Permission request is no longer pending.\",\n );\n return;\n }\n this.deps.hookEventRouter.onPermissionResolved(\n pending.sessionId,\n pending.provider,\n payload.toolId,\n \"deny\",\n { toolName: pending.toolName, toolInput: pending.input },\n );\n this.pushPermissionDecisionResult(pending.sessionId, payload.toolId, \"deny\", true, reason);\n serviceLogger.info({ sessionId, toolId: payload.toolId }, \"Tool denied via relay\");\n }\n\n onPermissionRequestDelivered(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n if (!sid || !requestId) return;\n const marked = this.deps.permissionBroker.markDelivered(requestId);\n serviceLogger.info({ sessionId: sid, requestId, marked }, \"Permission request delivered\");\n }\n\n private pushPermissionDecisionResult(\n sessionId: string,\n requestId: string,\n outcome: \"allow\" | \"deny\",\n delivered: boolean,\n message?: string,\n ): void {\n this.deps.relaySend(\n JSON.stringify({\n type: \"permission_decision_result\",\n sessionId,\n requestId,\n outcome,\n delivered,\n ...(message ? { message } : {}),\n }),\n );\n }\n}\n","import { homedir } from \"node:os\";\nimport { accessSync, constants, statSync } from \"node:fs\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { saveAgentCliPath } from \"../common/config.js\";\nimport { detectAgentCliStatus } from \"../providers/index.js\";\nimport type { ProviderId } from \"../providers/types.js\";\n\ninterface RelayResourceHandlersDeps {\n relaySend: RelaySend;\n controlHandlers: ControlMessageHandlers;\n sessionManager: SessionManager;\n getProviderEnv: () => NodeJS.ProcessEnv;\n getAgentCliSuggestions: () => Partial<Record<ProviderId, string[]>>;\n setAgentCliPath: (provider: ProviderId, path: string) => void;\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction validateExecutablePath(path: string): string {\n const normalized = path.trim();\n if (!normalized.startsWith(\"/\")) throw new Error(\"CLI 路径必须是绝对路径\");\n const stat = statSync(normalized);\n if (!stat.isFile()) throw new Error(\"CLI 路径不是可执行文件\");\n accessSync(normalized, constants.X_OK);\n return normalized;\n}\n\nexport class RelayResourceHandlers {\n constructor(private readonly deps: RelayResourceHandlersDeps) {}\n\n onProxyInfoRequest(msg: Record<string, unknown>): void {\n this.deps.relaySend(\n JSON.stringify({\n type: \"proxy_info\",\n requestId: msg.requestId as string | undefined,\n homePath: homedir() || \"/\",\n agentCli: detectAgentCliStatus(this.deps.getProviderEnv(), {\n suggestions: this.deps.getAgentCliSuggestions(),\n }),\n }),\n );\n }\n\n onAgentCliConfigUpdate(msg: Record<string, unknown>): void {\n const requestId = msg.requestId as string | undefined;\n const provider = msg.provider as ProviderId | undefined;\n const rawPath = msg.path as string | undefined;\n\n if (provider !== \"claude\" && provider !== \"codex\") {\n this.deps.relaySend(\n JSON.stringify({\n type: \"agent_cli_config_update_response\",\n requestId,\n provider: \"claude\",\n errorCode: ControlErrorCode.PROVIDER_UNSUPPORTED,\n error: \"Unsupported Agent CLI.\",\n }),\n );\n return;\n }\n\n try {\n const path = validateExecutablePath(rawPath ?? \"\");\n saveAgentCliPath(provider, path);\n this.deps.setAgentCliPath(provider, path);\n const agentCli = detectAgentCliStatus(this.deps.getProviderEnv(), {\n suggestions: this.deps.getAgentCliSuggestions(),\n });\n this.deps.relaySend(\n JSON.stringify({\n type: \"agent_cli_config_update_response\",\n requestId,\n provider,\n agentCli,\n }),\n );\n serviceLogger.info({ provider, path }, \"Agent CLI path updated\");\n } catch (err) {\n const error = errorMessage(err);\n this.deps.relaySend(\n JSON.stringify({\n type: \"agent_cli_config_update_response\",\n requestId,\n provider,\n errorCode: ControlErrorCode.INVALID_PATH,\n error,\n }),\n );\n serviceLogger.warn({ provider, path: rawPath, error }, \"Agent CLI path update rejected\");\n }\n }\n\n onDirListRequest(msg: Record<string, unknown>): void {\n this.deps.controlHandlers.handleDirListRequest({\n path: (msg.path as string) ?? \"\",\n requestId: msg.requestId as string | undefined,\n });\n }\n\n onDirCreateRequest(msg: Record<string, unknown>): void {\n this.deps.controlHandlers.handleDirCreateRequest({\n path: (msg.path as string) ?? \"\",\n requestId: msg.requestId as string | undefined,\n });\n }\n\n onSessionResourcesRequest(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n if (!sid) return;\n\n const session = this.deps.sessionManager.getSession(sid);\n if (!session?.cwd) {\n serviceLogger.warn({ sessionId: sid }, \"Session resources request: no cwd available\");\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_resources_response\",\n requestId: msg.requestId as string | undefined,\n sessionId: sid,\n commands: [],\n groups: [],\n errorCode: ControlErrorCode.SESSION_NOT_FOUND,\n error: \"Session not found or cwd unavailable\",\n }),\n );\n return;\n }\n this.deps.controlHandlers.handleSessionResourcesRequest({\n sessionId: sid,\n requestId: msg.requestId as string | undefined,\n workDir: session.cwd,\n });\n serviceLogger.info({ sessionId: sid, cwd: session.cwd }, \"Session resources requested\");\n }\n}\n","import { rmSync, statSync } from \"node:fs\";\nimport { isAbsolute } from \"node:path\";\nimport { nanoid } from \"nanoid\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { sessionPaths, tildify } from \"../common/paths.js\";\nimport type { ProviderHookContext, ProviderId } from \"../providers/index.js\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport { buildHostedPtyArgs, type HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\nimport type { SessionInfo, SessionManager } from \"./session-manager.js\";\nimport { readSessionMessagesPage } from \"./session-history.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport { classifyPathError } from \"./path-errors.js\";\n\ninterface RelaySessionCreateHandlerDeps {\n relaySend: RelaySend;\n workerRegistry: WorkerRegistry;\n sessionManager: SessionManager;\n hostedPtyRegistry: HostedPtyRegistry;\n controlHandlers: ControlMessageHandlers;\n permissionBroker: PermissionBroker;\n agentStatusRegistry: AgentStatusRegistry;\n getProviderEnv: () => NodeJS.ProcessEnv;\n createHookContext: (\n sessionId: string,\n provider: ProviderHookContext[\"provider\"],\n ) => ProviderHookContext;\n cleanupHookContext: (sessionId: string) => void;\n broadcastSessionSync: (session: SessionInfo) => void;\n broadcastSessionList: () => void;\n}\n\ninterface SessionCwdValidationError {\n message: string;\n code: ControlErrorCode;\n}\n\nfunction validateSessionCwd(cwd: unknown): SessionCwdValidationError | null {\n if (typeof cwd !== \"string\" || !cwd.trim()) {\n return { message: \"请输入工作目录\", code: ControlErrorCode.INVALID_PATH };\n }\n const trimmed = cwd.trim();\n if (!isAbsolute(trimmed)) {\n return { message: \"工作目录必须是绝对路径\", code: ControlErrorCode.INVALID_PATH };\n }\n try {\n const stat = statSync(trimmed);\n return stat.isDirectory()\n ? null\n : { message: \"工作目录不是目录\", code: ControlErrorCode.PATH_NOT_DIRECTORY };\n } catch (err) {\n return {\n message: `工作目录不存在或不可访问: ${trimmed}`,\n code: classifyPathError(err),\n };\n }\n}\n\nexport class RelaySessionCreateHandler {\n constructor(private readonly deps: RelaySessionCreateHandlerDeps) {}\n\n onSessionCreate(msg: Record<string, unknown>): void {\n const requestId = msg.requestId as string | undefined;\n const cwd = msg.cwd as string | undefined;\n const cwdError = validateSessionCwd(cwd);\n if (cwdError) {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId,\n sessionId: \"\",\n error: cwdError.message,\n errorCode: cwdError.code,\n }),\n );\n serviceLogger.warn({ cwd }, \"Session create rejected: invalid cwd\");\n return;\n }\n const sessionCwd = typeof cwd === \"string\" ? cwd.trim() : \"\";\n\n const provider = msg.provider as ProviderId | undefined;\n const mode = (msg.mode as \"json\" | \"pty\" | undefined) ?? \"json\";\n const permissionMode = msg.permissionMode as string | undefined;\n if (mode === \"pty\") {\n this.createHostedPtySession(msg, sessionCwd, provider ?? \"claude\", permissionMode);\n return;\n }\n\n if (provider !== \"claude\") {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId,\n sessionId: \"\",\n errorCode: ControlErrorCode.PROVIDER_UNSUPPORTED,\n error:\n provider === \"codex\"\n ? \"Codex chat sessions are not supported yet; start a Codex terminal session instead.\"\n : \"Unsupported provider for JSON session.\",\n }),\n );\n serviceLogger.warn({ provider }, \"JSON session create rejected for unsupported provider\");\n return;\n }\n\n const resumeSessionId = msg.resumeSessionId as string | undefined;\n const streamDelta = msg.streamDelta === true;\n const name = tildify(sessionCwd);\n const pendingId = nanoid();\n const hook = this.deps.createHookContext(pendingId, provider);\n const workerPid = this.deps.workerRegistry.spawn(pendingId, {\n cwd: sessionCwd,\n resumeSessionId,\n permissionMode,\n streamDelta,\n hook,\n });\n\n const paths = sessionPaths(pendingId);\n let attempt = 0;\n const maxRetries = 20;\n const tryConnect = () => {\n attempt++;\n this.deps.workerRegistry.connect(pendingId, paths.workerSock).then((sock) => {\n if (sock) {\n const session = this.deps.sessionManager.createSession(\n \"json\",\n sessionCwd,\n workerPid,\n name,\n pendingId,\n provider,\n );\n if (resumeSessionId) {\n this.deps.sessionManager.setClaudeSessionId(session.id, resumeSessionId);\n }\n this.deps.relaySend(\n JSON.stringify({ type: \"session_create_response\", requestId, sessionId: session.id }),\n );\n if (resumeSessionId) {\n this.pushHistoryMessages(session.id, resumeSessionId);\n }\n serviceLogger.info(\n { sessionId: session.id, cwd: sessionCwd },\n \"JSON session created via relay\",\n );\n this.deps.controlHandlers.pushCommandList(session.id, sessionCwd);\n this.deps.broadcastSessionSync(session);\n this.deps.broadcastSessionList();\n } else if (attempt < maxRetries) {\n setTimeout(tryConnect, Math.min(100 * attempt, 2000));\n } else {\n this.cleanupPendingJsonSession(pendingId);\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId,\n sessionId: pendingId,\n errorCode: ControlErrorCode.WORKER_START_FAILED,\n error: \"Worker failed to start\",\n }),\n );\n serviceLogger.error({ sessionId: pendingId }, \"Worker connection timeout via relay\");\n }\n });\n };\n setTimeout(tryConnect, 100);\n }\n\n private cleanupPendingJsonSession(sessionId: string): void {\n const killed = this.deps.workerRegistry.terminateProcess(sessionId);\n const paths = sessionPaths(sessionId);\n rmSync(paths.dir, { recursive: true, force: true });\n this.deps.cleanupHookContext(sessionId);\n this.deps.permissionBroker.cleanupSession(sessionId, \"Worker failed to start\");\n this.deps.agentStatusRegistry.delete(sessionId);\n serviceLogger.warn(\n { sessionId, killed },\n \"Cleaned up pending JSON session after startup failure\",\n );\n }\n\n private createHostedPtySession(\n msg: Record<string, unknown>,\n cwd: string,\n provider: ProviderId,\n permissionMode?: string,\n ): void {\n if (provider !== \"claude\" && provider !== \"codex\") {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId: msg.requestId as string | undefined,\n sessionId: \"\",\n errorCode: ControlErrorCode.PROVIDER_UNSUPPORTED,\n error: \"Unsupported provider for PTY session.\",\n }),\n );\n return;\n }\n\n const resumeSessionId = msg.resumeSessionId as string | undefined;\n const pendingId = nanoid();\n const name = tildify(cwd);\n const hook = this.deps.createHookContext(pendingId, provider);\n try {\n const pid = this.deps.hostedPtyRegistry.start({\n sessionId: pendingId,\n provider,\n cwd,\n args: buildHostedPtyArgs(provider, resumeSessionId),\n permissionMode,\n hook,\n });\n const session = this.deps.sessionManager.createSession(\n \"pty\",\n cwd,\n pid,\n name,\n pendingId,\n provider,\n \"proxy-hosted\",\n );\n if (resumeSessionId && provider === \"claude\") {\n this.deps.sessionManager.setClaudeSessionId(session.id, resumeSessionId);\n }\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId: msg.requestId as string | undefined,\n sessionId: session.id,\n mode: \"pty\",\n provider,\n ptyOwner: \"proxy-hosted\",\n }),\n );\n this.deps.controlHandlers.pushCommandList(session.id, cwd);\n this.deps.controlHandlers.pushFileTree(session.id, cwd);\n this.deps.broadcastSessionSync(session);\n this.deps.broadcastSessionList();\n serviceLogger.info({ sessionId: session.id, provider, cwd }, \"Hosted PTY session created\");\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId: msg.requestId as string | undefined,\n sessionId: \"\",\n errorCode: ControlErrorCode.PROCESS_START_FAILED,\n error,\n }),\n );\n const providerEnv = this.deps.getProviderEnv();\n serviceLogger.warn(\n {\n provider,\n cwd,\n error,\n claudeBin: providerEnv.CLAUDE_BIN,\n codexBin: providerEnv.CODEX_BIN,\n path: providerEnv.PATH,\n },\n \"Hosted PTY session create failed\",\n );\n }\n }\n\n private pushHistoryMessages(sessionId: string, resumeSessionId: string): void {\n readSessionMessagesPage(resumeSessionId)\n .then((page) => {\n if (page.messages.length === 0) return;\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_history_messages\",\n sessionId,\n messages: page.messages,\n hasMore: page.hasMore,\n ...(page.nextBefore !== undefined ? { nextBefore: page.nextBefore } : {}),\n }),\n );\n serviceLogger.info(\n {\n sessionId,\n resumeSessionId,\n messageCount: page.messages.length,\n hasMore: page.hasMore,\n },\n \"History message page sent for resumed session\",\n );\n })\n .catch((err) => {\n serviceLogger.warn(\n { sessionId, error: String(err) },\n \"Failed to read session history page\",\n );\n });\n }\n}\n","import * as pty from \"node-pty\";\nimport type { IPty } from \"node-pty\";\nimport { SessionState } from \"@dev-anywhere/shared\";\nimport pkg from \"@xterm/headless\";\nconst { Terminal: HeadlessTerminal } = pkg;\nimport { SerializeAddon } from \"@xterm/addon-serialize\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport {\n extractOscSequences,\n extractOscSignals,\n type PtySemanticState,\n} from \"../common/osc-extractor.js\";\nimport {\n shouldReleaseApprovalWait,\n stateAfterApprovalRelease,\n} from \"../common/pty-approval-state.js\";\nimport {\n CLAUDE_PROVIDER,\n CODEX_PROVIDER,\n type ProviderAdapter,\n type ProviderHookContext,\n type ProviderId,\n} from \"../providers/index.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { SessionManager } from \"./session-manager.js\";\n\nconst DEFAULT_COLS = 80;\nconst DEFAULT_ROWS = 24;\nconst IDLE_CHECK_INTERVAL_MS = 3_000;\nconst IDLE_THRESHOLD_MS = 3_000;\n\nconst PROVIDERS: Record<ProviderId, ProviderAdapter> = {\n claude: CLAUDE_PROVIDER,\n codex: CODEX_PROVIDER,\n};\n\nconst HOSTED_PTY_TERM = \"xterm-256color\";\nconst HOSTED_PTY_COLORTERM = \"truecolor\";\n\ninterface HostedPtyRegistryDeps {\n sessionManager: SessionManager;\n relayConnection: RelayConnection;\n getProviderEnv: () => NodeJS.ProcessEnv;\n changeSessionState: (sessionId: string, next: SessionState) => boolean;\n touchSessionActivity: (sessionId: string) => boolean;\n onTurnComplete: (sessionId: string) => void;\n onSessionClosed: (sessionId: string) => void;\n}\n\ninterface HostedPtyStartOptions {\n sessionId: string;\n provider: ProviderId;\n cwd: string;\n args: string[];\n permissionMode?: string;\n hook: ProviderHookContext;\n cols?: number;\n rows?: number;\n}\n\ninterface HostedPtySession {\n child: IPty;\n terminal: InstanceType<typeof HeadlessTerminal>;\n serializeAddon: SerializeAddon;\n idleTimer: NodeJS.Timeout;\n lastOutputTime: number;\n currentState: PtySemanticState;\n outputSeq: number;\n}\n\nexport function buildHostedPtyArgs(provider: ProviderId, resumeSessionId?: string): string[] {\n if (!resumeSessionId) return [];\n return provider === \"codex\" ? [\"resume\", resumeSessionId] : [\"--resume\", resumeSessionId];\n}\n\nexport function normalizeHostedPtyEnv(env: NodeJS.ProcessEnv): Record<string, string> {\n const normalized: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (value === undefined) continue;\n normalized[key] = value;\n }\n\n delete normalized.NO_COLOR;\n if (normalized.CLICOLOR === \"0\") {\n delete normalized.CLICOLOR;\n }\n\n normalized.TERM = HOSTED_PTY_TERM;\n normalized.COLORTERM = HOSTED_PTY_COLORTERM;\n normalized.CLICOLOR = \"1\";\n return normalized;\n}\n\nexport class HostedPtyRegistry {\n private sessions = new Map<string, HostedPtySession>();\n\n constructor(private readonly deps: HostedPtyRegistryDeps) {}\n\n start(options: HostedPtyStartOptions): number {\n const provider = PROVIDERS[options.provider];\n const cols = options.cols ?? DEFAULT_COLS;\n const rows = options.rows ?? DEFAULT_ROWS;\n const command = provider.buildTerminalCommand(\n { args: options.args, permissionMode: options.permissionMode, hook: options.hook },\n this.deps.getProviderEnv(),\n );\n const env = normalizeHostedPtyEnv(command.env);\n const child = pty.spawn(command.command, command.args, {\n name: HOSTED_PTY_TERM,\n cols,\n rows,\n cwd: options.cwd,\n env,\n });\n\n const terminal = new HeadlessTerminal({ cols, rows, scrollback: 5000, allowProposedApi: true });\n const serializeAddon = new SerializeAddon();\n terminal.loadAddon(serializeAddon);\n void import(\"@xterm/addon-unicode-graphemes\")\n .then(({ UnicodeGraphemesAddon }) => terminal.loadAddon(new UnicodeGraphemesAddon()))\n .catch((err) => {\n serviceLogger.warn(\n { sessionId: options.sessionId, error: String(err) },\n \"Unicode addon unavailable\",\n );\n });\n\n const hosted: HostedPtySession = {\n child,\n terminal,\n serializeAddon,\n idleTimer: setInterval(() => this.checkIdle(options.sessionId), IDLE_CHECK_INTERVAL_MS),\n lastOutputTime: 0,\n currentState: \"turn_complete\",\n outputSeq: 0,\n };\n this.sessions.set(options.sessionId, hosted);\n\n child.onData((data) => this.handleData(options.sessionId, data));\n child.onExit(({ exitCode, signal }) => {\n const code = signal ? 128 + signal : exitCode;\n serviceLogger.info({ sessionId: options.sessionId, code }, \"Hosted PTY exited\");\n this.close(options.sessionId, { kill: false, notify: true });\n });\n\n serviceLogger.info(\n {\n sessionId: options.sessionId,\n provider: options.provider,\n command: command.command,\n pid: child.pid,\n cwd: options.cwd,\n cols,\n rows,\n },\n \"Hosted PTY started\",\n );\n return child.pid;\n }\n\n has(sessionId: string): boolean {\n return this.sessions.has(sessionId);\n }\n\n write(sessionId: string, data: string): boolean {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return false;\n hosted.child.write(data);\n return true;\n }\n\n resize(sessionId: string, cols: number, rows: number): boolean {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return false;\n hosted.child.resize(cols, rows);\n hosted.terminal.resize(cols, rows);\n this.deps.relayConnection.sendRaw(\n JSON.stringify({ type: \"terminal_resize\", sessionId, cols, rows }),\n );\n serviceLogger.info({ sessionId, cols, rows }, \"Hosted PTY resized\");\n return true;\n }\n\n snapshot(sessionId: string, requestId?: string): boolean {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return false;\n const data = hosted.serializeAddon.serialize();\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"session_snapshot\",\n sessionId,\n cols: hosted.terminal.cols,\n rows: hosted.terminal.rows,\n data,\n outputSeq: hosted.outputSeq,\n requestId,\n }),\n );\n serviceLogger.info(\n { sessionId, cols: hosted.terminal.cols, rows: hosted.terminal.rows, bytes: data.length },\n \"Hosted PTY snapshot sent\",\n );\n return true;\n }\n\n terminate(sessionId: string): boolean {\n return this.close(sessionId, { kill: true, notify: true });\n }\n\n destroyAll(): void {\n for (const sessionId of Array.from(this.sessions.keys())) {\n this.close(sessionId, { kill: true, notify: false });\n }\n }\n\n private handleData(sessionId: string, data: string): void {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return;\n hosted.lastOutputTime = Date.now();\n hosted.outputSeq += 1;\n hosted.terminal.write(data);\n this.deps.touchSessionActivity(sessionId);\n this.sendBinary(sessionId, Buffer.from(data, \"utf-8\"), hosted.outputSeq);\n\n const oscSequences = extractOscSequences(data);\n const session = this.deps.sessionManager.getSession(sessionId);\n const signal = extractOscSignals(data, session?.provider);\n if (oscSequences.length > 0) {\n serviceLogger.debug(\n {\n sessionId,\n oscSequences,\n signal,\n },\n \"Hosted PTY OSC sequences parsed\",\n );\n }\n if (signal?.title) {\n this.sendTerminalTitle(sessionId, signal.title);\n }\n if (signal?.state === \"approval_wait\") {\n hosted.currentState = \"approval_wait\";\n this.deps.changeSessionState(sessionId, SessionState.WAITING_APPROVAL);\n this.sendPtyState(sessionId, \"approval_wait\", { title: signal?.title, tool: signal?.tool });\n return;\n }\n if (\n shouldReleaseApprovalWait({\n currentState: hosted.currentState,\n signalState: signal?.state,\n })\n ) {\n const nextState = stateAfterApprovalRelease(signal?.state);\n hosted.currentState = nextState;\n if (nextState === \"turn_complete\") {\n this.deps.onTurnComplete(sessionId);\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n } else {\n this.deps.changeSessionState(sessionId, SessionState.WORKING);\n }\n this.sendPtyState(sessionId, nextState, { title: signal?.title, tool: signal?.tool });\n return;\n }\n if (\n (session?.state === SessionState.WAITING_APPROVAL ||\n hosted.currentState === \"approval_wait\") &&\n signal?.state !== \"turn_complete\"\n ) {\n hosted.currentState = \"approval_wait\";\n this.sendPtyState(sessionId, \"approval_wait\", { title: signal?.title, tool: signal?.tool });\n return;\n }\n if (signal && signal.state !== \"working\") {\n hosted.currentState = signal.state;\n if (signal.state === \"turn_complete\") {\n this.deps.onTurnComplete(sessionId);\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n }\n this.sendPtyState(sessionId, signal.state, { title: signal.title, tool: signal.tool });\n return;\n }\n if (hosted.currentState !== \"working\") {\n hosted.currentState = \"working\";\n this.deps.changeSessionState(sessionId, SessionState.WORKING);\n this.sendPtyState(sessionId, \"working\");\n }\n }\n\n private checkIdle(sessionId: string): void {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return;\n if (hosted.lastOutputTime === 0 || Date.now() - hosted.lastOutputTime <= IDLE_THRESHOLD_MS) {\n return;\n }\n hosted.lastOutputTime = 0;\n if (hosted.currentState !== \"working\") return;\n hosted.currentState = \"turn_complete\";\n this.deps.onTurnComplete(sessionId);\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n this.sendPtyState(sessionId, \"turn_complete\");\n }\n\n private sendPtyState(\n sessionId: string,\n state: PtySemanticState,\n meta?: { title?: string; tool?: string },\n ): void {\n const payload = {\n state,\n ...(meta?.title !== undefined ? { title: meta.title } : {}),\n ...(meta?.tool !== undefined ? { tool: meta.tool } : {}),\n };\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"pty_state\",\n sessionId,\n payload,\n }),\n );\n const logPayload = { sessionId, ...payload };\n if (state === \"approval_wait\" || state === \"turn_complete\") {\n serviceLogger.info(logPayload, \"Hosted PTY semantic event pushed\");\n } else {\n serviceLogger.debug(logPayload, \"Hosted PTY semantic event pushed\");\n }\n }\n\n private sendTerminalTitle(sessionId: string, title: string): void {\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"terminal_title\",\n sessionId,\n title,\n }),\n );\n }\n\n private sendBinary(sessionId: string, data: Buffer, outputSeq: number): void {\n const sessionIdBuf = Buffer.from(sessionId, \"utf-8\");\n const frame = Buffer.alloc(1 + sessionIdBuf.length + 4 + data.length);\n frame[0] = sessionIdBuf.length;\n sessionIdBuf.copy(frame, 1);\n frame.writeUInt32LE(outputSeq, 1 + sessionIdBuf.length);\n data.copy(frame, 1 + sessionIdBuf.length + 4);\n this.deps.relayConnection.sendBinary(frame);\n }\n\n private close(sessionId: string, options: { kill: boolean; notify: boolean }): boolean {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return false;\n this.sessions.delete(sessionId);\n clearInterval(hosted.idleTimer);\n if (options.kill) {\n try {\n hosted.child.kill();\n } catch {\n // PTY may already have exited.\n }\n }\n hosted.terminal.dispose();\n if (options.notify) {\n this.sendPtyState(sessionId, \"turn_complete\");\n this.deps.sessionManager.terminateSession(sessionId);\n this.deps.onSessionClosed(sessionId);\n }\n return true;\n }\n}\n","import type { Socket } from \"node:net\";\nimport { SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { serializeIpc } from \"../ipc/ipc-protocol.js\";\nimport type { SessionInfo, SessionManager } from \"./session-manager.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { JsonObserver } from \"./json-observer.js\";\nimport type { ProviderHookContext } from \"../providers/index.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { HookEventRouter } from \"./hook-event-router.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport type { HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport { terminateSessionByOwnership } from \"./session-termination.js\";\nimport { RelayInputHandlers } from \"./relay-input-handlers.js\";\nimport { RelayHistoryHandlers } from \"./relay-history-handlers.js\";\nimport { RelayPermissionHandlers } from \"./relay-permission-handlers.js\";\nimport { RelayResourceHandlers } from \"./relay-resource-handlers.js\";\nimport { RelaySessionCreateHandler } from \"./relay-session-create-handler.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\n\ninterface RelayRouterDeps {\n sessionManager: SessionManager;\n workerRegistry: WorkerRegistry;\n controlHandlers: ControlMessageHandlers;\n relayConnection: RelayConnection;\n relaySend: RelaySend;\n terminalSockets: Map<string, Socket>;\n hostedPtyRegistry: HostedPtyRegistry;\n broadcastSessionList: () => void;\n broadcastSessionSync: (session: SessionInfo) => void;\n // user_input 注入触发 turn 开始(JSON 观察器)\n jsonObserver: JsonObserver;\n createHookContext: (\n sessionId: string,\n provider: ProviderHookContext[\"provider\"],\n ) => ProviderHookContext;\n cleanupHookContext: (sessionId: string) => void;\n permissionBroker: PermissionBroker;\n hookEventRouter: HookEventRouter;\n agentStatusRegistry: AgentStatusRegistry;\n getProviderEnv: () => NodeJS.ProcessEnv;\n getAgentCliSuggestions: () => Partial<Record<ProviderHookContext[\"provider\"], string[]>>;\n setAgentCliPath: (provider: ProviderHookContext[\"provider\"], path: string) => void;\n}\n\n// 按 type 分发入站 relay 消息到独立 handler。未知 type warn 不丢,schema 逐步收紧。\nexport class RelayRouter {\n private readonly historyHandlers: RelayHistoryHandlers;\n private readonly inputHandlers: RelayInputHandlers;\n private readonly permissionHandlers: RelayPermissionHandlers;\n private readonly resourceHandlers: RelayResourceHandlers;\n private readonly sessionCreateHandler: RelaySessionCreateHandler;\n\n constructor(private deps: RelayRouterDeps) {\n this.historyHandlers = new RelayHistoryHandlers({\n relaySend: deps.relaySend,\n sessionManager: deps.sessionManager,\n permissionBroker: deps.permissionBroker,\n });\n this.inputHandlers = new RelayInputHandlers({\n sessionManager: deps.sessionManager,\n workerRegistry: deps.workerRegistry,\n relayConnection: deps.relayConnection,\n terminalSockets: deps.terminalSockets,\n hostedPtyRegistry: deps.hostedPtyRegistry,\n jsonObserver: deps.jsonObserver,\n });\n this.resourceHandlers = new RelayResourceHandlers({\n relaySend: deps.relaySend,\n controlHandlers: deps.controlHandlers,\n sessionManager: deps.sessionManager,\n getProviderEnv: deps.getProviderEnv,\n getAgentCliSuggestions: deps.getAgentCliSuggestions,\n setAgentCliPath: deps.setAgentCliPath,\n });\n this.permissionHandlers = new RelayPermissionHandlers({\n relaySend: deps.relaySend,\n permissionBroker: deps.permissionBroker,\n hookEventRouter: deps.hookEventRouter,\n workerRegistry: deps.workerRegistry,\n });\n this.sessionCreateHandler = new RelaySessionCreateHandler({\n relaySend: deps.relaySend,\n workerRegistry: deps.workerRegistry,\n sessionManager: deps.sessionManager,\n hostedPtyRegistry: deps.hostedPtyRegistry,\n controlHandlers: deps.controlHandlers,\n permissionBroker: deps.permissionBroker,\n agentStatusRegistry: deps.agentStatusRegistry,\n getProviderEnv: deps.getProviderEnv,\n createHookContext: deps.createHookContext,\n cleanupHookContext: deps.cleanupHookContext,\n broadcastSessionSync: deps.broadcastSessionSync,\n broadcastSessionList: deps.broadcastSessionList,\n });\n }\n\n handle(parsed: Record<string, unknown>): void {\n const type = parsed.type as string | undefined;\n if (!type) {\n serviceLogger.warn(\"Relay message without type discriminator\");\n return;\n }\n\n const handler = this.handlers[type];\n if (!handler) {\n serviceLogger.warn({ type }, \"Unhandled relay message type\");\n return;\n }\n\n try {\n handler.call(this, parsed);\n } catch (err) {\n serviceLogger.warn({ type, error: String(err) }, \"Relay handler threw\");\n }\n }\n\n private readonly handlers: Record<string, (msg: Record<string, unknown>) => void> = {\n user_input: (msg) => this.inputHandlers.onUserInput(msg),\n remote_input_raw: (msg) => this.inputHandlers.onRemoteInputRaw(msg),\n clipboard_image_upload: (msg) => this.inputHandlers.onClipboardImageUpload(msg),\n tool_approve: (msg) => this.permissionHandlers.onToolApprove(msg),\n tool_deny: (msg) => this.permissionHandlers.onToolDeny(msg),\n proxy_info_request: (msg) => this.resourceHandlers.onProxyInfoRequest(msg),\n agent_cli_config_update: (msg) => this.resourceHandlers.onAgentCliConfigUpdate(msg),\n dir_list_request: (msg) => this.resourceHandlers.onDirListRequest(msg),\n dir_create_request: (msg) => this.resourceHandlers.onDirCreateRequest(msg),\n session_create: (msg) => this.sessionCreateHandler.onSessionCreate(msg),\n session_messages_request: (msg) => this.historyHandlers.onSessionMessagesRequest(msg),\n session_resources_request: (msg) => this.resourceHandlers.onSessionResourcesRequest(msg),\n agent_status_request: (msg) => this.onAgentStatusRequest(msg),\n permission_request_delivered: (msg) =>\n this.permissionHandlers.onPermissionRequestDelivered(msg),\n session_terminate: (msg) => this.onSessionTerminate(msg),\n session_worker_abort: (msg) => this.onSessionWorkerAbort(msg),\n session_history_request: (msg) =>\n this.deps.controlHandlers.handleSessionHistoryRequest({\n requestId: msg.requestId as string | undefined,\n }),\n session_list: () => this.onSessionList(),\n permission_mode_change: (msg) => this.onPermissionModeChange(msg),\n session_subscribe: (msg) => this.onSessionSubscribe(msg),\n terminal_resize_request: (msg) => this.onTerminalResizeRequest(msg),\n };\n\n private onAgentStatusRequest(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n if (sid) {\n const status = this.deps.agentStatusRegistry.get(sid);\n const statuses =\n status && this.deps.sessionManager.getSession(sid)\n ? [{ sessionId: sid, payload: status }]\n : [];\n this.deps.relaySend(JSON.stringify({ type: \"agent_status_response\", requestId, statuses }));\n serviceLogger.info({ sessionId: sid, count: statuses.length }, \"Agent status snapshot sent\");\n return;\n }\n\n const statuses: Array<{ sessionId: string; payload: AgentStatusPayload }> = [];\n for (const { sessionId, status } of this.deps.agentStatusRegistry.list()) {\n if (!this.deps.sessionManager.getSession(sessionId)) continue;\n statuses.push({ sessionId, payload: status });\n }\n this.deps.relaySend(JSON.stringify({ type: \"agent_status_response\", requestId, statuses }));\n serviceLogger.info({ count: statuses.length }, \"Agent status snapshot sent\");\n }\n\n private onSessionTerminate(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n if (!sid) return;\n\n const result = terminateSessionByOwnership(this.deps, sid);\n serviceLogger.info(\n { sessionId: sid, success: result.success, action: result.action },\n \"Session termination handled via relay\",\n );\n if (result.action !== \"terminate_hosted_pty\") this.deps.broadcastSessionList();\n }\n\n private onSessionWorkerAbort(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n if (!sid) return;\n\n const session = this.deps.sessionManager.getSession(sid);\n if (!session) {\n serviceLogger.warn({ sessionId: sid }, \"session_worker_abort: session not found\");\n return;\n }\n if (session.state === SessionState.TERMINATED) {\n serviceLogger.info({ sessionId: sid }, \"session_worker_abort: already terminated, dropping\");\n return;\n }\n\n if (session.mode === \"pty\") {\n // PTY 会话直接把 Ctrl+C 写入 PTY stdin,避免杀掉 terminal wrapper 进程\n const ts = this.deps.terminalSockets.get(sid);\n if (this.deps.hostedPtyRegistry.write(sid, \"\\x03\")) {\n serviceLogger.info({ sessionId: sid }, \"session_worker_abort: Ctrl+C sent to hosted PTY\");\n } else if (ts?.writable) {\n ts.write(serializeIpc({ type: \"pty_input\", sessionId: sid, data: \"\\x03\" }));\n serviceLogger.info({ sessionId: sid }, \"session_worker_abort: Ctrl+C sent to PTY\");\n } else {\n serviceLogger.warn(\n { sessionId: sid },\n \"session_worker_abort: PTY terminal socket unavailable\",\n );\n }\n return;\n }\n\n try {\n process.kill(session.pid, \"SIGINT\");\n serviceLogger.info(\n { sessionId: sid, pid: session.pid },\n \"session_worker_abort: SIGINT sent to worker\",\n );\n } catch (err) {\n serviceLogger.warn(\n { sessionId: sid, pid: session.pid, error: String(err) },\n \"session_worker_abort: kill failed\",\n );\n }\n }\n\n private onSessionList(): void {\n this.deps.broadcastSessionList();\n serviceLogger.info(\"Session list sent via relay\");\n }\n\n private onPermissionModeChange(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const mode = msg.mode;\n if (!sid) {\n serviceLogger.info(\n { mode },\n \"Permission mode change received via relay (global, no sessionId)\",\n );\n return;\n }\n\n const session = this.deps.sessionManager.getSession(sid);\n if (session?.mode !== \"pty\") {\n serviceLogger.info(\n { sessionId: sid, mode },\n \"Permission mode change received for JSON session (no-op, not supported)\",\n );\n return;\n }\n\n // PTY 会话:发 Shift+Tab (CSI Z) 让 claude CLI 循环 permission mode\n // mode 字段当前保留但不使用 —— Claude CLI 仅支持循环键,无法一键直选档位\n const ts = this.deps.terminalSockets.get(sid);\n if (this.deps.hostedPtyRegistry.write(sid, \"\\x1b[Z\")) {\n serviceLogger.info(\n { sessionId: sid, mode },\n \"Permission mode cycle: Shift+Tab sent to hosted PTY\",\n );\n } else if (ts?.writable) {\n ts.write(serializeIpc({ type: \"pty_input\", sessionId: sid, data: \"\\x1b[Z\" }));\n serviceLogger.info({ sessionId: sid, mode }, \"Permission mode cycle: Shift+Tab sent to PTY\");\n } else {\n serviceLogger.warn(\n { sessionId: sid },\n \"Permission mode cycle: PTY terminal socket unavailable\",\n );\n }\n }\n\n private onSessionSubscribe(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n if (!sid) return;\n\n const ts = this.deps.terminalSockets.get(sid);\n if (this.deps.hostedPtyRegistry.snapshot(sid, requestId)) {\n serviceLogger.info({ sessionId: sid, requestId }, \"Subscribe handled by hosted PTY\");\n } else if (ts?.writable) {\n ts.write(serializeIpc({ type: \"pty_subscribe\", sessionId: sid, requestId }));\n serviceLogger.info({ sessionId: sid, requestId }, \"Subscribe forwarded to terminal\");\n } else {\n serviceLogger.warn({ sessionId: sid }, \"Subscribe failed: terminal socket not available\");\n }\n }\n\n private onTerminalResizeRequest(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const cols = msg.cols as number | undefined;\n const rows = msg.rows as number | undefined;\n if (!sid || !cols || !rows) return;\n if (!this.deps.hostedPtyRegistry.resize(sid, cols, rows)) {\n serviceLogger.debug({ sessionId: sid, cols, rows }, \"Resize request ignored: not hosted PTY\");\n }\n }\n}\n","import { SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\n\ninterface JsonObserverDeps {\n changeSessionState: (sessionId: string, next: SessionState) => boolean;\n emitAgentStatus?: (sessionId: string, phase: AgentStatusPayload[\"phase\"]) => void;\n}\n\n// JSON 观察通道:把 worker 转发的 stream-json 事件翻译成 SessionState。\n// ERROR 态表达 \"worker 进程活着,但 proxy 观察/控制通道已坏\"(control_response 写入失败、\n// stream 连续 parse 失败、未来可能的 heartbeat 超时等);turn 内部的 is_error=true 不是观察失联,\n// 不触发 ERROR,仍按 onTurnResult 回 IDLE 处理。\nexport class JsonObserver {\n constructor(private deps: JsonObserverDeps) {}\n\n // 用户消息注入 worker(relay-router 收到 user_input)→ 进入 WORKING\n onTurnStart(sessionId: string): void {\n this.deps.changeSessionState(sessionId, SessionState.WORKING);\n this.deps.emitAgentStatus?.(sessionId, \"thinking\");\n }\n\n // stream-json result event 到达 → turn 结束回 IDLE\n onTurnResult(sessionId: string): void {\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n this.deps.emitAgentStatus?.(sessionId, \"idle\");\n }\n\n // control_request event 到达 → worker 阻塞等审批\n onApprovalRequested(sessionId: string): void {\n this.deps.changeSessionState(sessionId, SessionState.WAITING_APPROVAL);\n this.deps.emitAgentStatus?.(sessionId, \"waiting_permission\");\n }\n\n // 观察通道失联 → ERROR,待人工干预或后续 terminate\n onChannelBroken(sessionId: string): void {\n this.deps.changeSessionState(sessionId, SessionState.ERROR);\n }\n}\n","import { serviceLogger } from \"../common/logger.js\";\nimport type { HookProviderId } from \"./hook-registry.js\";\n\ninterface PermissionRequest {\n requestId: string;\n sessionId: string;\n provider: HookProviderId;\n toolName: string;\n input: Record<string, unknown>;\n}\n\nexport interface PermissionDecision {\n behavior: \"allow\" | \"deny\";\n message?: string;\n}\n\ninterface PendingPermission extends PermissionRequest {\n source: \"hook\" | \"worker\";\n resolve: (decision: PermissionDecision) => void;\n createdAt: number;\n deliveredAt?: number;\n}\n\nexport class PermissionBroker {\n private readonly pending = new Map<string, PendingPermission>();\n\n request(request: PermissionRequest): Promise<PermissionDecision> {\n const existing = this.pending.get(request.requestId);\n if (existing) {\n return Promise.resolve({\n behavior: \"deny\",\n message: \"Duplicate permission request id.\",\n });\n }\n\n return new Promise((resolve) => {\n this.pending.set(request.requestId, {\n ...request,\n source: \"hook\",\n resolve,\n createdAt: Date.now(),\n });\n });\n }\n\n registerWorkerRequest(\n request: PermissionRequest,\n onDecision: (decision: PermissionDecision) => void,\n ): boolean {\n const existing = this.pending.get(request.requestId);\n if (existing) {\n onDecision({\n behavior: \"deny\",\n message: \"Duplicate permission request id.\",\n });\n return false;\n }\n\n this.pending.set(request.requestId, {\n ...request,\n source: \"worker\",\n resolve: onDecision,\n createdAt: Date.now(),\n });\n return true;\n }\n\n resolve(requestId: string, decision: PermissionDecision): boolean {\n const pending = this.pending.get(requestId);\n if (!pending) return false;\n this.pending.delete(requestId);\n pending.resolve(decision);\n return true;\n }\n\n markDelivered(requestId: string): boolean {\n const pending = this.pending.get(requestId);\n if (!pending) return false;\n pending.deliveredAt = Date.now();\n return true;\n }\n\n get(requestId: string): {\n requestId: string;\n sessionId: string;\n provider: HookProviderId;\n source: \"hook\" | \"worker\";\n toolName: string;\n input: Record<string, unknown>;\n createdAt: number;\n deliveredAt?: number;\n } | null {\n const pending = this.pending.get(requestId);\n if (!pending) return null;\n return {\n requestId: pending.requestId,\n sessionId: pending.sessionId,\n provider: pending.provider,\n source: pending.source,\n toolName: pending.toolName,\n input: pending.input,\n createdAt: pending.createdAt,\n ...(pending.deliveredAt !== undefined ? { deliveredAt: pending.deliveredAt } : {}),\n };\n }\n\n cleanupSession(sessionId: string, reason: string): void {\n for (const [requestId, pending] of this.pending) {\n if (pending.sessionId !== sessionId) continue;\n this.pending.delete(requestId);\n pending.resolve({ behavior: \"deny\", message: reason });\n serviceLogger.info({ sessionId, requestId, reason }, \"Pending hook permission dropped\");\n }\n }\n\n listSession(sessionId: string): Array<Omit<PendingPermission, \"resolve\">> {\n const out: Array<Omit<PendingPermission, \"resolve\">> = [];\n for (const pending of this.pending.values()) {\n if (pending.sessionId !== sessionId) continue;\n out.push({\n requestId: pending.requestId,\n sessionId: pending.sessionId,\n provider: pending.provider,\n source: pending.source,\n toolName: pending.toolName,\n input: pending.input,\n createdAt: pending.createdAt,\n ...(pending.deliveredAt !== undefined ? { deliveredAt: pending.deliveredAt } : {}),\n });\n }\n return out;\n }\n}\n","import { buildMessage, SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\nimport { SeqCounter } from \"../common/seq-counter.js\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { AuthenticatedHookEvent } from \"./hook-server.js\";\nimport type { HookProviderId } from \"./hook-registry.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\n\ninterface HookEventRouterDeps {\n relayConnection: RelayConnection;\n agentStatusRegistry: AgentStatusRegistry;\n changeSessionState: (sessionId: string, next: SessionState) => boolean;\n nextSeq?: (sessionId: string) => number;\n}\n\nfunction hookPayloadRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nfunction toolNameFromPayload(payload: Record<string, unknown>): string {\n return typeof payload.toolName === \"string\"\n ? payload.toolName\n : typeof payload.tool_name === \"string\"\n ? payload.tool_name\n : \"unknown\";\n}\n\nfunction toolInputFromPayload(payload: Record<string, unknown>): Record<string, unknown> {\n return hookPayloadRecord(payload.input ?? payload.tool_input);\n}\n\nexport class HookEventRouter {\n constructor(private readonly deps: HookEventRouterDeps) {}\n\n handle(event: AuthenticatedHookEvent): void {\n switch (event.event) {\n case \"SessionStart\":\n this.deps.changeSessionState(event.sessionId, SessionState.IDLE);\n this.forwardAgentStatus(event, \"idle\");\n break;\n case \"UserPromptSubmit\":\n this.deps.changeSessionState(event.sessionId, SessionState.WORKING);\n this.forwardAgentStatus(event, \"thinking\");\n break;\n case \"PostToolUse\":\n case \"PostToolUseFailure\":\n this.deps.changeSessionState(event.sessionId, SessionState.WORKING);\n this.forwardAgentStatus(event, \"outputting\");\n break;\n case \"Stop\":\n this.deps.changeSessionState(event.sessionId, SessionState.IDLE);\n this.forwardAgentStatus(event, \"idle\");\n break;\n case \"PermissionRequest\":\n this.forwardPermissionRequest(event);\n break;\n case \"PreToolUse\":\n this.forwardToolUse(event);\n break;\n default:\n serviceLogger.debug(\n { sessionId: event.sessionId, provider: event.provider, event: event.event },\n \"Unknown provider hook event ignored\",\n );\n break;\n }\n }\n\n onPermissionResolved(\n sessionId: string,\n provider: HookProviderId,\n requestId: string,\n outcome: \"allow\" | \"deny\",\n context?: { toolName?: string; toolInput?: Record<string, unknown> },\n ): void {\n this.deps.changeSessionState(sessionId, SessionState.WORKING);\n if (outcome === \"deny\") {\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n }\n this.forwardAgentStatus(\n {\n sessionId,\n provider,\n event: \"PermissionResolved\",\n requestId,\n payload: {},\n },\n outcome === \"allow\" ? \"tool_use\" : \"idle\",\n {\n toolName: context?.toolName,\n toolInput: context?.toolInput,\n permissionResolution: { requestId, outcome },\n },\n );\n serviceLogger.info({ sessionId, requestId, outcome }, \"Hook permission resolved\");\n }\n\n private forwardPermissionRequest(event: AuthenticatedHookEvent): void {\n const requestId = event.requestId ?? `${event.sessionId}:${Date.now()}`;\n const toolName = toolNameFromPayload(event.payload);\n const input = toolInputFromPayload(event.payload);\n\n this.deps.changeSessionState(event.sessionId, SessionState.WAITING_APPROVAL);\n this.forwardAgentStatus(event, \"waiting_permission\", {\n toolName,\n toolInput: input,\n permissionRequest: {\n requestId,\n toolName,\n input,\n },\n });\n\n const seq = this.deps.nextSeq?.(event.sessionId) ?? new SeqCounter(event.sessionId).next();\n const envelope = buildMessage(\n \"tool_use_request\",\n event.sessionId,\n seq,\n {\n toolName,\n toolId: requestId,\n parameters: input,\n },\n \"proxy\",\n );\n this.deps.relayConnection.sendEnvelope(envelope);\n }\n\n private forwardToolUse(event: AuthenticatedHookEvent): void {\n const toolName = toolNameFromPayload(event.payload);\n const input = toolInputFromPayload(event.payload);\n this.forwardAgentStatus(event, \"tool_use\", {\n toolName,\n toolInput: input,\n });\n }\n\n private forwardAgentStatus(\n event: AuthenticatedHookEvent,\n phase: AgentStatusPayload[\"phase\"],\n extra?: Partial<AgentStatusPayload>,\n ): void {\n const payload: AgentStatusPayload = {\n provider: event.provider,\n phase,\n seq: this.nextSeq(event.sessionId),\n updatedAt: Date.now(),\n ...extra,\n };\n this.deps.agentStatusRegistry.set(event.sessionId, payload);\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"agent_status\",\n sessionId: event.sessionId,\n payload,\n }),\n );\n }\n\n private nextSeq(sessionId: string): number {\n return this.deps.nextSeq?.(sessionId) ?? new SeqCounter(sessionId).next();\n }\n}\n","import type { AgentStatusPayload } from \"@dev-anywhere/shared\";\n\nexport class AgentStatusRegistry {\n private readonly statuses = new Map<string, AgentStatusPayload>();\n\n set(sessionId: string, status: AgentStatusPayload): void {\n const current = this.statuses.get(sessionId);\n if (current && current.seq > status.seq) return;\n this.statuses.set(sessionId, status);\n }\n\n get(sessionId: string): AgentStatusPayload | null {\n return this.statuses.get(sessionId) ?? null;\n }\n\n list(): Array<{ sessionId: string; status: AgentStatusPayload }> {\n return Array.from(this.statuses, ([sessionId, status]) => ({ sessionId, status }));\n }\n\n delete(sessionId: string): void {\n this.statuses.delete(sessionId);\n }\n}\n","import { buildMessage, SessionState } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { SessionInfo, SessionManager } from \"./session-manager.js\";\n\nconst ACTIVITY_STATUS_PUSH_INTERVAL_MS = 15_000;\n\nfunction toSessionListPayload(s: SessionInfo) {\n return {\n sessionId: s.id,\n mode: s.mode,\n provider: s.provider,\n ...(s.ptyOwner !== undefined ? { ptyOwner: s.ptyOwner } : {}),\n state: s.state,\n lastActive: s.updatedAt,\n ...(s.name !== undefined ? { name: s.name } : {}),\n };\n}\n\nfunction pushSessionStatus(\n relay: RelayConnection,\n sessionManager: SessionManager,\n sessionId: string,\n): void {\n const session = sessionManager.getSession(sessionId);\n if (!session) return;\n try {\n const envelope = buildMessage(\n \"session_status\",\n session.id,\n Date.now(),\n { sessionId: session.id, state: session.state, lastActive: session.updatedAt },\n \"proxy\",\n );\n relay.sendEnvelope(envelope);\n } catch (err) {\n serviceLogger.debug({ sessionId, error: String(err) }, \"Failed to push session_status\");\n }\n}\n\nexport function broadcastSessionList(relay: RelayConnection, sessionManager: SessionManager): void {\n relay.sendRaw(\n JSON.stringify({\n type: \"session_list\",\n sessionId: \"\",\n seq: 0,\n timestamp: Date.now(),\n source: \"proxy\",\n version: \"1\",\n payload: { sessions: sessionManager.listSessions().map(toSessionListPayload) },\n }),\n );\n}\n\nexport function broadcastSessionSync(relay: RelayConnection, session: SessionInfo): void {\n relay.sendRaw(\n JSON.stringify({\n type: \"session_sync\",\n sessions: [\n {\n id: session.id,\n mode: session.mode,\n provider: session.provider,\n ...(session.ptyOwner !== undefined ? { ptyOwner: session.ptyOwner } : {}),\n state: session.state,\n },\n ],\n }),\n );\n}\n\nexport function changeSessionState(\n sessionManager: SessionManager,\n relay: RelayConnection,\n sessionId: string,\n next: SessionState,\n): boolean {\n if (!sessionManager.getSession(sessionId)) return false;\n const changed = sessionManager.updateState(sessionId, next);\n if (changed) pushSessionStatus(relay, sessionManager, sessionId);\n return changed;\n}\n\nexport function touchSessionActivity(\n sessionManager: SessionManager,\n relay: RelayConnection,\n sessionId: string,\n now: number = Date.now(),\n): boolean {\n const touched = sessionManager.touchSession(sessionId, now, ACTIVITY_STATUS_PUSH_INTERVAL_MS);\n if (touched) pushSessionStatus(relay, sessionManager, sessionId);\n return touched;\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync, readFileSync, unlinkSync } from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { connect, type Socket } from \"node:net\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { DEFAULT_PROXY_PROFILE, PID_PATH, PROFILE_NAME, SOCK_PATH } from \"../common/paths.js\";\n\nfunction tryConnectSocket(sockPath: string): Promise<Socket | null> {\n return new Promise((resolve) => {\n const s = connect(sockPath);\n s.on(\"connect\", () => resolve(s));\n s.on(\"error\", () => resolve(null));\n });\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function cleanupStaleResources(): Promise<void> {\n if (existsSync(SOCK_PATH)) {\n const existing = await tryConnectSocket(SOCK_PATH);\n if (existing) {\n existing.destroy();\n const msg = `Another service is already running on ${SOCK_PATH}`;\n serviceLogger.error(msg);\n console.error(msg);\n process.exit(1);\n }\n unlinkSync(SOCK_PATH);\n serviceLogger.info(\"Removed stale socket file\");\n }\n\n if (existsSync(PID_PATH)) {\n const pidStr = readFileSync(PID_PATH, \"utf-8\").trim();\n const pid = parseInt(pidStr, 10);\n if (!isNaN(pid) && isProcessAlive(pid)) {\n const msg = `Another service is already running with PID ${pid}`;\n serviceLogger.error(msg);\n console.error(msg);\n process.exit(1);\n }\n unlinkSync(PID_PATH);\n serviceLogger.info(\"Removed stale PID file\");\n }\n}\n\nexport function formatProxyNameForProfile(baseName: string, profileName = PROFILE_NAME): string {\n return profileName === DEFAULT_PROXY_PROFILE ? baseName : `${baseName} (${profileName})`;\n}\n\nexport function getProxyName(): string {\n const explicitName = process.env.DEV_ANYWHERE_PROXY_NAME?.trim();\n if (explicitName) return explicitName;\n\n return formatProxyNameForProfile(getComputerName() || hostname());\n}\n\nfunction getComputerName(): string | null {\n try {\n return (\n execSync(\"scutil --get ComputerName\", { stdio: [\"pipe\", \"pipe\", \"ignore\"] })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n","import { SessionState } from \"@dev-anywhere/shared\";\nimport type { SessionInfo } from \"./session-manager.js\";\n\nexport function shouldPromotePtyActivityToWorking(\n session: SessionInfo | undefined,\n pendingApprovalCount: number,\n): boolean {\n if (!session || session.mode !== \"pty\") return false;\n if (pendingApprovalCount > 0) return false;\n return session.state === SessionState.IDLE || session.state === SessionState.WAITING_APPROVAL;\n}\n","import { SessionState } from \"@dev-anywhere/shared\";\nimport type { PtySemanticState } from \"../common/osc-extractor.js\";\n\nexport function resolvePtySemanticSessionTransitions(\n currentState: SessionState | undefined,\n semanticState: PtySemanticState,\n): SessionState[] {\n if (semanticState !== \"turn_complete\") return [];\n\n if (currentState === SessionState.WAITING_APPROVAL) {\n return [SessionState.IDLE];\n }\n\n if (currentState === SessionState.WORKING) {\n return [SessionState.IDLE];\n }\n\n return [];\n}\n","import type { Socket } from \"node:net\";\nimport { SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { createIpcReader, serializeIpc, type IpcMessage } from \"../ipc/ipc-protocol.js\";\nimport type { ProviderHookContext } from \"../providers/index.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport type { HookEventRouter } from \"./hook-event-router.js\";\nimport type { HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport { shouldPromotePtyActivityToWorking } from \"./pty-state-guard.js\";\nimport { resolvePtySemanticSessionTransitions } from \"./pty-semantic-lifecycle.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport {\n broadcastSessionList,\n broadcastSessionSync,\n changeSessionState,\n touchSessionActivity,\n} from \"./session-broadcast.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport { terminateSessionByOwnership } from \"./session-termination.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\nimport { isProcessAlive } from \"./service-files.js\";\n\ninterface TerminalConnectionDeps {\n sessionManager: SessionManager;\n workerRegistry: WorkerRegistry;\n terminalSockets: Map<string, Socket>;\n hostedPtyRegistry: HostedPtyRegistry;\n relayConnection: RelayConnection;\n controlHandlers: ControlMessageHandlers;\n agentStatusRegistry: AgentStatusRegistry;\n permissionBroker: PermissionBroker;\n hookEventRouter: HookEventRouter;\n createHookContext: (\n sessionId: string,\n provider: ProviderHookContext[\"provider\"],\n ) => ProviderHookContext;\n emitAgentStatus: (sessionId: string, phase: AgentStatusPayload[\"phase\"]) => void;\n resolveInterruptedApprovals: (sessionId: string) => void;\n config: Extract<IpcMessage, { type: \"service_status_response\" }>[\"config\"];\n}\n\nexport function handleTerminalConnection(socket: Socket, deps: TerminalConnectionDeps): void {\n const {\n sessionManager,\n workerRegistry,\n terminalSockets,\n hostedPtyRegistry,\n relayConnection,\n controlHandlers,\n agentStatusRegistry,\n permissionBroker,\n createHookContext,\n emitAgentStatus,\n resolveInterruptedApprovals,\n config,\n } = deps;\n\n createIpcReader(\n socket,\n (msg: IpcMessage) => {\n switch (msg.type) {\n case \"session_create_request\": {\n if (msg.mode !== \"pty\") {\n socket.write(\n serializeIpc({\n type: \"session_create_response\",\n sessionId: \"\",\n error: `Unsupported mode via IPC: ${msg.mode}`,\n }),\n );\n break;\n }\n const provider = msg.provider;\n const existing = msg.sessionId ? sessionManager.getSession(msg.sessionId) : undefined;\n const session =\n existing ??\n sessionManager.createSession(\n \"pty\",\n msg.cwd,\n msg.pid,\n msg.name,\n msg.sessionId,\n provider,\n \"local-terminal\",\n );\n if (existing) {\n sessionManager.setPid(session.id, msg.pid);\n }\n socket.write(\n serializeIpc({\n type: \"session_create_response\",\n sessionId: session.id,\n hook: createHookContext(session.id, provider),\n }),\n );\n serviceLogger.info(\n { sessionId: session.id, mode: \"pty\", provider },\n \"PTY session created\",\n );\n break;\n }\n\n case \"service_status_request\": {\n const relayStatus = relayConnection.getStatus();\n const sessions = sessionManager.listSessions();\n socket.write(\n serializeIpc({\n type: \"service_status_response\",\n config,\n relay: relayStatus,\n sessions: sessions.map((s) => ({\n id: s.id,\n mode: s.mode,\n provider: s.provider,\n state: s.state,\n createdAt: new Date(s.createdAt).toISOString(),\n ...(s.name !== undefined ? { name: s.name } : {}),\n hasWorker: workerRegistry.has(s.id),\n })),\n }),\n );\n break;\n }\n\n case \"pty_title_change\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"terminal_title\",\n sessionId: msg.sessionId,\n title: msg.title,\n }),\n );\n break;\n }\n\n case \"pty_semantic_event\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n const logPayload = {\n sessionId: msg.sessionId,\n state: msg.state,\n ...(msg.title !== undefined ? { title: msg.title } : {}),\n ...(msg.tool !== undefined ? { tool: msg.tool } : {}),\n };\n if (msg.state === \"approval_wait\" || msg.state === \"turn_complete\") {\n serviceLogger.info(logPayload, \"PTY semantic event received\");\n } else {\n serviceLogger.debug(logPayload, \"PTY semantic event received\");\n }\n if (msg.state === \"approval_wait\") {\n changeSessionState(\n sessionManager,\n relayConnection,\n msg.sessionId,\n SessionState.WAITING_APPROVAL,\n );\n } else if (msg.state === \"working\" || msg.state === \"mid_pause\") {\n const session = sessionManager.getSession(msg.sessionId);\n const pendingApprovals = permissionBroker.listSession(msg.sessionId);\n if (shouldPromotePtyActivityToWorking(session, pendingApprovals.length)) {\n changeSessionState(\n sessionManager,\n relayConnection,\n msg.sessionId,\n SessionState.WORKING,\n );\n } else if (session?.state === SessionState.WAITING_APPROVAL) {\n serviceLogger.debug(\n {\n sessionId: msg.sessionId,\n ptyState: msg.state,\n pendingApprovals: pendingApprovals.length,\n },\n \"PTY working signal ignored while permission approval is pending\",\n );\n }\n }\n\n if (msg.state === \"turn_complete\") {\n resolveInterruptedApprovals(msg.sessionId);\n const session = sessionManager.getSession(msg.sessionId);\n const transitions = resolvePtySemanticSessionTransitions(session?.state, msg.state);\n for (const next of transitions) {\n changeSessionState(sessionManager, relayConnection, msg.sessionId, next);\n }\n emitAgentStatus(msg.sessionId, \"idle\");\n }\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"pty_state\",\n sessionId: msg.sessionId,\n payload: {\n state: msg.state,\n ...(msg.title !== undefined ? { title: msg.title } : {}),\n ...(msg.tool !== undefined ? { tool: msg.tool } : {}),\n },\n }),\n );\n break;\n }\n\n case \"pty_resize\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"terminal_resize\",\n sessionId: msg.sessionId,\n cols: msg.cols,\n rows: msg.rows,\n }),\n );\n break;\n }\n\n case \"session_terminate_request\": {\n const result = terminateSessionByOwnership(\n {\n sessionManager,\n workerRegistry,\n controlHandlers,\n terminalSockets,\n hostedPtyRegistry,\n agentStatusRegistry,\n },\n msg.sessionId,\n );\n socket.write(\n serializeIpc({\n type: \"session_terminate_response\",\n sessionId: msg.sessionId,\n success: result.success,\n }),\n );\n serviceLogger.info(\n { sessionId: msg.sessionId, success: result.success, action: result.action },\n \"Session termination request handled\",\n );\n break;\n }\n\n case \"pty_register\": {\n if (!sessionManager.getSession(msg.sessionId)) {\n serviceLogger.warn(\n { sessionId: msg.sessionId },\n \"PTY register ignored: session missing\",\n );\n break;\n }\n sessionManager.setPid(msg.sessionId, msg.pid);\n terminalSockets.set(msg.sessionId, socket);\n socket.write(\n serializeIpc({\n type: \"bridge_status\",\n connected: relayConnection.getStatus().connected,\n }),\n );\n const session = sessionManager.getSession(msg.sessionId);\n if (session) {\n broadcastSessionSync(relayConnection, session);\n }\n broadcastSessionList(relayConnection, sessionManager);\n serviceLogger.info({ sessionId: msg.sessionId }, \"PTY session registered\");\n break;\n }\n\n case \"pty_deregister\": {\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"pty_state\",\n sessionId: msg.sessionId,\n payload: { state: \"turn_complete\" },\n }),\n );\n sessionManager.terminateSession(msg.sessionId);\n terminalSockets.delete(msg.sessionId);\n\n controlHandlers.cleanup(msg.sessionId);\n agentStatusRegistry.delete(msg.sessionId);\n broadcastSessionList(relayConnection, sessionManager);\n serviceLogger.info({ sessionId: msg.sessionId }, \"PTY session deregistered\");\n break;\n }\n\n case \"pty_input\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n const targetSocket = terminalSockets.get(msg.sessionId);\n if (hostedPtyRegistry.write(msg.sessionId, msg.data)) {\n break;\n }\n if (targetSocket?.writable) {\n targetSocket.write(\n serializeIpc({\n type: \"pty_input\",\n sessionId: msg.sessionId,\n data: msg.data,\n }),\n );\n }\n break;\n }\n\n case \"session_status_update\": {\n changeSessionState(sessionManager, relayConnection, msg.sessionId, msg.state);\n break;\n }\n\n case \"pty_snapshot\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"session_snapshot\",\n sessionId: msg.sessionId,\n cols: msg.cols,\n rows: msg.rows,\n data: msg.data,\n outputSeq: msg.outputSeq,\n requestId: msg.requestId,\n }),\n );\n serviceLogger.info(\n { sessionId: msg.sessionId, cols: msg.cols, rows: msg.rows },\n \"Session snapshot forwarded to relay\",\n );\n break;\n }\n\n default: {\n serviceLogger.warn({ type: (msg as IpcMessage).type }, \"Unhandled IPC message type\");\n }\n }\n },\n (sessionId, data, outputSeq) => {\n if (!sessionManager.getSession(sessionId)) return;\n touchSessionActivity(sessionManager, relayConnection, sessionId);\n const sessionIdBuf = Buffer.from(sessionId, \"utf-8\");\n const wsFrame = Buffer.alloc(1 + sessionIdBuf.length + 4 + data.length);\n wsFrame[0] = sessionIdBuf.length;\n sessionIdBuf.copy(wsFrame, 1);\n wsFrame.writeUInt32LE(outputSeq, 1 + sessionIdBuf.length);\n data.copy(wsFrame, 1 + sessionIdBuf.length + 4);\n relayConnection.sendBinary(wsFrame);\n },\n );\n\n socket.on(\"close\", () => {\n for (const [sessionId, terminalSocket] of terminalSockets) {\n if (terminalSocket === socket) {\n terminalSockets.delete(sessionId);\n const session = sessionManager.getSession(sessionId);\n if (!session) {\n serviceLogger.info({ sessionId }, \"Terminal socket closed, session already cleaned\");\n continue;\n }\n if (session.mode === \"pty\" && session.pid && isProcessAlive(session.pid)) {\n serviceLogger.info(\n { sessionId, pid: session.pid },\n \"Terminal socket closed but process alive, skipping cleanup\",\n );\n continue;\n }\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"pty_state\",\n sessionId,\n payload: { state: \"turn_complete\" },\n }),\n );\n sessionManager.terminateSession(sessionId);\n controlHandlers.cleanup(sessionId);\n agentStatusRegistry.delete(sessionId);\n broadcastSessionList(relayConnection, sessionManager);\n serviceLogger.info(\n { sessionId },\n \"PTY session cleaned up on socket close (crash fallback)\",\n );\n }\n }\n });\n\n socket.on(\"error\", (err) => {\n serviceLogger.warn({ error: String(err) }, \"Client socket error\");\n });\n}\n","import { createHash, randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { z } from \"zod\";\nimport { serviceLogger } from \"../common/logger.js\";\n\nexport type HookProviderId = \"claude\" | \"codex\";\n\ninterface HookSessionBinding {\n sessionId: string;\n provider: HookProviderId;\n marker: string;\n tokenHash: string;\n createdAt: number;\n expiresAt?: number;\n}\n\ninterface HookSessionCredentials {\n sessionId: string;\n provider: HookProviderId;\n marker: string;\n token: string;\n}\n\ninterface VerifyOptions {\n sessionId: string;\n marker: string;\n token: string;\n provider?: HookProviderId;\n now?: number;\n}\n\ninterface HookRegistryOptions {\n persistPath?: string;\n}\n\nconst PersistedHookSessionBindingSchema = z.object({\n sessionId: z.string(),\n provider: z.enum([\"claude\", \"codex\"]),\n marker: z.string(),\n tokenHash: z.string(),\n createdAt: z.number(),\n expiresAt: z.number().optional(),\n});\n\nconst PersistedHookRegistrySchema = z.object({\n version: z.literal(1),\n bindings: z.array(PersistedHookSessionBindingSchema),\n});\n\nfunction hashToken(token: string): string {\n return createHash(\"sha256\").update(token).digest(\"hex\");\n}\n\nfunction randomSecret(): string {\n return randomBytes(32).toString(\"base64url\");\n}\n\nexport class HookRegistry {\n private readonly bindingsBySession = new Map<string, HookSessionBinding>();\n private readonly persistPath?: string;\n\n constructor(options: HookRegistryOptions = {}) {\n this.persistPath = options.persistPath;\n this.load();\n }\n\n registerSession(\n sessionId: string,\n provider: HookProviderId,\n options: { ttlMs?: number; now?: number } = {},\n ): HookSessionCredentials {\n const now = options.now ?? Date.now();\n const token = randomSecret();\n const marker = randomSecret();\n this.bindingsBySession.set(sessionId, {\n sessionId,\n provider,\n marker,\n tokenHash: hashToken(token),\n createdAt: now,\n ...(options.ttlMs ? { expiresAt: now + options.ttlMs } : {}),\n });\n this.save();\n return { sessionId, provider, marker, token };\n }\n\n verify(options: VerifyOptions): HookSessionBinding | null {\n const binding = this.bindingsBySession.get(options.sessionId);\n if (!binding) return null;\n if (options.provider && binding.provider !== options.provider) return null;\n if (binding.marker !== options.marker) return null;\n if (binding.tokenHash !== hashToken(options.token)) return null;\n if (binding.expiresAt && (options.now ?? Date.now()) > binding.expiresAt) return null;\n return binding;\n }\n\n getSession(sessionId: string): HookSessionBinding | null {\n return this.bindingsBySession.get(sessionId) ?? null;\n }\n\n unregisterSession(sessionId: string): void {\n if (this.bindingsBySession.delete(sessionId)) {\n this.save();\n }\n }\n\n private load(): void {\n if (!this.persistPath || !existsSync(this.persistPath)) return;\n try {\n const parsed = PersistedHookRegistrySchema.parse(\n JSON.parse(readFileSync(this.persistPath, \"utf8\")),\n );\n this.bindingsBySession.clear();\n for (const binding of parsed.bindings) {\n this.bindingsBySession.set(binding.sessionId, binding);\n }\n } catch (err) {\n serviceLogger.warn(\n { path: this.persistPath, error: String(err) },\n \"Failed to load hook registry state\",\n );\n }\n }\n\n private save(): void {\n if (!this.persistPath) return;\n try {\n mkdirSync(dirname(this.persistPath), { recursive: true });\n const tmpPath = `${this.persistPath}.${process.pid}.${Date.now()}.tmp`;\n writeFileSync(\n tmpPath,\n JSON.stringify(\n {\n version: 1,\n bindings: Array.from(this.bindingsBySession.values()),\n },\n null,\n 2,\n ),\n );\n renameSync(tmpPath, this.persistPath);\n } catch (err) {\n serviceLogger.warn(\n { path: this.persistPath, error: String(err) },\n \"Failed to persist hook registry state\",\n );\n }\n }\n}\n","import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { HookRegistry, type HookProviderId } from \"./hook-registry.js\";\nimport { PermissionBroker } from \"./permission-broker.js\";\n\ninterface HookServerOptions {\n port: number;\n registry: HookRegistry;\n permissionBroker: PermissionBroker;\n host?: string;\n maxBodyBytes?: number;\n isSessionActive?: (sessionId: string) => boolean;\n onEvent?: (event: AuthenticatedHookEvent) => void;\n}\n\nexport interface AuthenticatedHookEvent {\n sessionId: string;\n provider: HookProviderId;\n event: string;\n requestId?: string;\n payload: Record<string, unknown>;\n}\n\ninterface HookRequestBody {\n sessionId?: unknown;\n provider?: unknown;\n marker?: unknown;\n event?: unknown;\n requestId?: unknown;\n payload?: unknown;\n}\n\nfunction getBearerToken(req: IncomingMessage): string | null {\n const header = req.headers.authorization;\n if (!header?.startsWith(\"Bearer \")) return null;\n return header.slice(\"Bearer \".length).trim() || null;\n}\n\nfunction asProvider(value: unknown): HookProviderId | null {\n return value === \"claude\" || value === \"codex\" ? value : null;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nexport class HookServer {\n private server: Server | null = null;\n private readonly host: string;\n private readonly maxBodyBytes: number;\n\n constructor(private readonly options: HookServerOptions) {\n this.host = options.host ?? \"127.0.0.1\";\n this.maxBodyBytes = options.maxBodyBytes ?? 1024 * 1024;\n }\n\n start(): Promise<void> {\n if (this.server) return Promise.resolve();\n this.server = createServer((req, res) => {\n this.handle(req, res).catch((err) => {\n serviceLogger.error({ err: String(err) }, \"Hook request failed\");\n this.writeJson(res, 500, { error: \"internal_error\" });\n });\n });\n\n return new Promise((resolve, reject) => {\n const onError = (err: Error) => {\n this.server?.off(\"listening\", onListening);\n reject(err);\n };\n const onListening = () => {\n this.server?.off(\"error\", onError);\n serviceLogger.info({ host: this.host, port: this.options.port }, \"Hook server listening\");\n resolve();\n };\n this.server!.once(\"error\", onError);\n this.server!.once(\"listening\", onListening);\n this.server!.listen(this.options.port, this.host);\n });\n }\n\n close(): Promise<void> {\n if (!this.server) return Promise.resolve();\n const server = this.server;\n this.server = null;\n return new Promise((resolve, reject) => {\n server.close((err) => (err ? reject(err) : resolve()));\n });\n }\n\n getListeningPort(): number | null {\n const address = this.server?.address();\n if (!address || typeof address === \"string\") return null;\n return (address as AddressInfo).port;\n }\n\n private async handle(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (req.method !== \"POST\" || req.url !== \"/hook\") {\n this.writeJson(res, 404, { error: \"not_found\" });\n return;\n }\n\n const token = getBearerToken(req);\n if (!token) {\n this.writeJson(res, 401, { error: \"missing_token\" });\n return;\n }\n\n const body = await this.readBody(req);\n const parsed = JSON.parse(body) as HookRequestBody;\n const provider = asProvider(parsed.provider);\n if (\n typeof parsed.sessionId !== \"string\" ||\n typeof parsed.marker !== \"string\" ||\n typeof parsed.event !== \"string\" ||\n !provider\n ) {\n this.writeJson(res, 400, { error: \"invalid_hook_payload\" });\n return;\n }\n\n const binding = this.options.registry.verify({\n sessionId: parsed.sessionId,\n marker: parsed.marker,\n token,\n provider,\n });\n if (!binding) {\n this.writeJson(res, 403, { error: \"invalid_hook_credentials\" });\n return;\n }\n if (this.options.isSessionActive && !this.options.isSessionActive(binding.sessionId)) {\n serviceLogger.info(\n { sessionId: binding.sessionId, provider: binding.provider, event: parsed.event },\n \"Provider hook ignored for inactive session\",\n );\n this.writeProviderResponse(res, this.toNeutralProviderResponse(provider, parsed.event));\n return;\n }\n\n const payload = asRecord(parsed.payload);\n const requestId =\n typeof parsed.requestId === \"string\"\n ? parsed.requestId\n : typeof payload.tool_use_id === \"string\"\n ? payload.tool_use_id\n : undefined;\n const event: AuthenticatedHookEvent = {\n sessionId: binding.sessionId,\n provider: binding.provider,\n event: parsed.event,\n ...(requestId !== undefined ? { requestId } : {}),\n payload,\n };\n\n if (event.event === \"PermissionRequest\") {\n await this.handlePermissionRequest(event, res);\n return;\n }\n\n this.options.onEvent?.(event);\n this.writeProviderResponse(res, this.toNeutralProviderResponse(event.provider, event.event));\n }\n\n private async handlePermissionRequest(\n event: AuthenticatedHookEvent,\n res: ServerResponse,\n ): Promise<void> {\n const requestId =\n event.requestId ??\n (typeof event.payload.tool_use_id === \"string\" ? event.payload.tool_use_id : undefined) ??\n `${event.sessionId}:${Date.now()}`;\n const toolName =\n typeof event.payload.toolName === \"string\"\n ? event.payload.toolName\n : typeof event.payload.tool_name === \"string\"\n ? event.payload.tool_name\n : \"unknown\";\n const input = asRecord(event.payload.input ?? event.payload.tool_input);\n\n this.options.onEvent?.({ ...event, requestId });\n const decision = await this.options.permissionBroker.request({\n requestId,\n sessionId: event.sessionId,\n provider: event.provider,\n toolName,\n input,\n });\n this.writeJson(res, 200, this.toProviderDecision(event.event, decision));\n }\n\n private toProviderDecision(\n eventName: string,\n decision: { behavior: \"allow\" | \"deny\"; message?: string },\n ): object {\n if (eventName === \"PreToolUse\") {\n return {\n hookSpecificOutput: {\n hookEventName: \"PreToolUse\",\n permissionDecision: decision.behavior,\n ...(decision.message ? { permissionDecisionReason: decision.message } : {}),\n },\n };\n }\n\n return {\n hookSpecificOutput: {\n hookEventName: \"PermissionRequest\",\n decision,\n },\n };\n }\n\n private toNeutralProviderResponse(provider: HookProviderId, eventName: string): object | null {\n if (eventName === \"PreToolUse\") {\n if (provider === \"codex\") {\n return null;\n }\n return {\n hookSpecificOutput: {\n hookEventName: \"PreToolUse\",\n permissionDecision: \"defer\",\n },\n };\n }\n\n return null;\n }\n\n private writeProviderResponse(res: ServerResponse, payload: object | null): void {\n if (res.headersSent) return;\n if (payload === null) {\n res.writeHead(200);\n res.end();\n return;\n }\n this.writeJson(res, 200, payload);\n }\n\n private readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n let body = \"\";\n let size = 0;\n req.setEncoding(\"utf8\");\n req.on(\"data\", (chunk: string) => {\n size += Buffer.byteLength(chunk);\n if (size > this.maxBodyBytes) {\n reject(new Error(\"hook body too large\"));\n req.destroy();\n return;\n }\n body += chunk;\n });\n req.on(\"end\", () => resolve(body));\n req.on(\"error\", reject);\n });\n }\n\n private writeJson(res: ServerResponse, statusCode: number, payload: object): void {\n if (res.headersSent) return;\n res.writeHead(statusCode, { \"content-type\": \"application/json; charset=utf-8\" });\n res.end(JSON.stringify(payload));\n }\n}\n","import { serviceLogger } from \"../common/logger.js\";\nimport { HOOK_REGISTRY_PATH } from \"../common/paths.js\";\nimport type { ProviderHookContext } from \"../providers/index.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport { HookEventRouter } from \"./hook-event-router.js\";\nimport { HookRegistry } from \"./hook-registry.js\";\nimport { HookServer } from \"./hook-server.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { SessionState } from \"@dev-anywhere/shared\";\n\ninterface ProviderHookRuntimeOptions {\n hookPort?: number;\n permissionBroker: PermissionBroker;\n sessionManager: SessionManager;\n relayConnection: RelayConnection;\n agentStatusRegistry: AgentStatusRegistry;\n changeSessionState: (sessionId: string, next: SessionState) => boolean;\n}\n\ninterface ProviderHookRuntime {\n hookRegistry: HookRegistry;\n hookEventRouter: HookEventRouter;\n hookServer: HookServer;\n createHookContext: (\n sessionId: string,\n provider: ProviderHookContext[\"provider\"],\n ) => ProviderHookContext;\n}\n\nexport async function createProviderHookRuntime(\n options: ProviderHookRuntimeOptions,\n): Promise<ProviderHookRuntime> {\n const hookRegistry = new HookRegistry({ persistPath: HOOK_REGISTRY_PATH });\n const hookEventRouter = new HookEventRouter({\n relayConnection: options.relayConnection,\n agentStatusRegistry: options.agentStatusRegistry,\n changeSessionState: options.changeSessionState,\n });\n const port = options.hookPort ?? 17654;\n const hookServer = new HookServer({\n port,\n registry: hookRegistry,\n permissionBroker: options.permissionBroker,\n isSessionActive: (sessionId) => !!options.sessionManager.getSession(sessionId),\n onEvent: (event) => {\n serviceLogger.info(\n {\n sessionId: event.sessionId,\n provider: event.provider,\n event: event.event,\n requestId: event.requestId,\n },\n \"Provider hook event received\",\n );\n hookEventRouter.handle(event);\n },\n });\n\n try {\n await hookServer.start();\n } catch (err) {\n const msg = `Failed to start hook server on 127.0.0.1:${port}: ${String(err)}`;\n serviceLogger.error(msg);\n console.error(msg);\n process.exit(1);\n }\n\n const hookUrl = `http://127.0.0.1:${hookServer.getListeningPort() ?? port}/hook`;\n const createHookContext: ProviderHookRuntime[\"createHookContext\"] = (sessionId, provider) => {\n const credentials = hookRegistry.registerSession(sessionId, provider);\n return {\n provider,\n sessionId,\n hookUrl,\n marker: credentials.marker,\n token: credentials.token,\n };\n };\n\n return {\n hookRegistry,\n hookEventRouter,\n hookServer,\n createHookContext,\n };\n}\n"],"mappings":"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","names":["createServer","unlinkSync","writeFileSync","rmSync","readFileSync","writeFileSync","mkdirSync","existsSync","dirname","nanoid","existsSync","readFileSync","nanoid","dirname","mkdirSync","writeFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","readdir","join","isAbsolute","join","homedir","resolve","join","readFileSync","homedir","join","isAbsolute","readdir","join","existsSync","readdirSync","resolve","existsSync","readdirSync","mkdirSync","writeFileSync","isAbsolute","join","nanoid","isAbsolute","nanoid","join","mkdirSync","writeFileSync","homedir","stat","homedir","statSync","isAbsolute","nanoid","isAbsolute","stat","statSync","nanoid","statuses","resolve","existsSync","readFileSync","unlinkSync","connect","resolve","connect","existsSync","unlinkSync","readFileSync","resolveInterruptedApprovals","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","renameSync","resolve","unlinkSync","rmSync","createServer","writeFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/serve.ts","../src/serve/session-manager.ts","../src/serve/relay-connection.ts","../src/serve/message-queue.ts","../src/common/config.ts","../src/serve/handlers/control-messages.ts","../src/serve/session-history.ts","../src/serve/command-discovery.ts","../src/serve/path-errors.ts","../src/serve/worker-registry.ts","../src/serve/session-termination.ts","../src/serve/clipboard-image-upload.ts","../src/serve/image-preview.ts","../src/serve/pty-input.ts","../src/serve/relay-input-handlers.ts","../src/serve/relay-history-handlers.ts","../src/serve/relay-permission-handlers.ts","../src/serve/relay-resource-handlers.ts","../src/serve/relay-session-create-handler.ts","../src/serve/hosted-pty-registry.ts","../src/serve/relay-router.ts","../src/serve/json-observer.ts","../src/serve/permission-broker.ts","../src/serve/hook-event-router.ts","../src/serve/agent-status-registry.ts","../src/serve/session-broadcast.ts","../src/serve/service-files.ts","../src/serve/pty-state-guard.ts","../src/serve/pty-semantic-lifecycle.ts","../src/serve/terminal-ipc.ts","../src/serve/hook-registry.ts","../src/serve/hook-server.ts","../src/serve/provider-hook-runtime.ts"],"sourcesContent":["import { createServer, type Socket } from \"node:net\";\nimport { unlinkSync, writeFileSync, chmodSync, rmSync } from \"node:fs\";\nimport { SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"./common/logger.js\";\nimport { SessionManager } from \"./serve/session-manager.js\";\nimport { RelayConnection } from \"./serve/relay-connection.js\";\nimport {\n SOCK_PATH,\n PID_PATH,\n STOPPED_PATH,\n SESSIONS_PATH,\n PROXY_ID_PATH,\n PROFILE_NAME,\n ensureProfileWorkspace,\n sessionPaths,\n} from \"./common/paths.js\";\nimport { buildProviderEnv, loadConfig } from \"./common/config.js\";\nimport { serializeIpc } from \"./ipc/ipc-protocol.js\";\nimport { createControlMessageHandlers } from \"./serve/handlers/control-messages.js\";\nimport { WorkerRegistry } from \"./serve/worker-registry.js\";\nimport { RelayRouter } from \"./serve/relay-router.js\";\nimport { JsonObserver } from \"./serve/json-observer.js\";\nimport { PermissionBroker } from \"./serve/permission-broker.js\";\nimport { HookEventRouter } from \"./serve/hook-event-router.js\";\nimport { AgentStatusRegistry } from \"./serve/agent-status-registry.js\";\nimport { HostedPtyRegistry } from \"./serve/hosted-pty-registry.js\";\nimport { SeqCounter } from \"./common/seq-counter.js\";\nimport {\n broadcastSessionList,\n broadcastSessionSync,\n changeSessionState,\n touchSessionActivity,\n} from \"./serve/session-broadcast.js\";\nimport { cleanupStaleResources, getProxyName } from \"./serve/service-files.js\";\nimport { handleTerminalConnection } from \"./serve/terminal-ipc.js\";\nimport { createProviderHookRuntime } from \"./serve/provider-hook-runtime.js\";\nimport type { ProviderId } from \"./providers/types.js\";\n\nfunction resolveInterruptedApprovals(\n permissionBroker: PermissionBroker,\n hookEventRouter: HookEventRouter,\n relay: RelayConnection,\n sessionId: string,\n): void {\n const approvals = permissionBroker.listSession(sessionId);\n if (approvals.length === 0) return;\n\n const message = \"Permission request was interrupted in the PTY.\";\n for (const approval of approvals) {\n if (!permissionBroker.resolve(approval.requestId, { behavior: \"deny\", message })) continue;\n hookEventRouter.onPermissionResolved(\n approval.sessionId,\n approval.provider,\n approval.requestId,\n \"deny\",\n { toolName: approval.toolName, toolInput: approval.input },\n );\n relay.sendRaw(\n JSON.stringify({\n type: \"permission_decision_result\",\n sessionId: approval.sessionId,\n requestId: approval.requestId,\n outcome: \"deny\",\n delivered: true,\n message,\n }),\n );\n }\n serviceLogger.info(\n { sessionId, count: approvals.length },\n \"Pending approvals cleared after PTY interruption\",\n );\n}\n\nexport interface ServiceOptions {\n relayUrl?: string;\n relayName?: string;\n}\n\nfunction parseServiceOptions(argv: readonly string[]): ServiceOptions {\n const options: ServiceOptions = {};\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--relay\") {\n const relayName = argv[i + 1];\n if (!relayName || relayName.startsWith(\"-\")) {\n throw new Error(\"Missing value for --relay\");\n }\n options.relayName = relayName;\n i++;\n continue;\n }\n if (arg.startsWith(\"--relay=\")) {\n const relayName = arg.slice(\"--relay=\".length);\n if (!relayName) throw new Error(\"Missing value for --relay\");\n options.relayName = relayName;\n }\n }\n return options;\n}\n\nexport async function startService(options?: ServiceOptions): Promise<void> {\n ensureProfileWorkspace();\n await cleanupStaleResources();\n try {\n unlinkSync(STOPPED_PATH);\n } catch {\n // STOPPED 文件不存在时忽略\n }\n\n const permissionBroker = new PermissionBroker();\n const agentStatusRegistry = new AgentStatusRegistry();\n let unregisterHookSession: (sessionId: string) => void = () => {};\n const sessionManager = new SessionManager({\n persistPath: SESSIONS_PATH,\n onSessionRemoved: (id, context) => {\n if (!context?.preserveProviderHooks) {\n unregisterHookSession(id);\n }\n permissionBroker.cleanupSession(id, \"session removed\");\n agentStatusRegistry.delete(id);\n const paths = sessionPaths(id);\n try {\n rmSync(paths.dir, { recursive: true, force: true });\n } catch {\n // 会话目录清理失败不影响主流程\n }\n },\n });\n sessionManager.startReaper();\n\n const terminalSockets = new Map<string, Socket>();\n const proxyName = getProxyName();\n\n // 连接中转服务器:优先用调用方传入的 relayUrl,否则从配置文件读取\n // relay 是 proxy 存在的必要前提,未配置直接 fail-fast,不再支持\"本地独立\"模式\n let proxyConfig = loadConfig({ relayName: options?.relayName });\n const getProviderEnv = (): NodeJS.ProcessEnv => buildProviderEnv(proxyConfig, process.env);\n const getAgentCliSuggestions = (): Partial<Record<ProviderId, string[]>> =>\n proxyConfig.agentCliSuggestions;\n const getPreviewRoots = (): string[] => proxyConfig.previewRoots;\n const setAgentCliPath = (provider: ProviderId, path: string): void => {\n const field = provider === \"claude\" ? \"claudeBin\" : \"codexBin\";\n const existing = proxyConfig.agentCliSuggestions[provider] ?? [];\n proxyConfig = {\n ...proxyConfig,\n [field]: path,\n agentCliSuggestions: {\n ...proxyConfig.agentCliSuggestions,\n [provider]: [path, ...existing.filter((candidate) => candidate !== path)],\n },\n sources: {\n ...proxyConfig.sources,\n [field]: \"file\",\n },\n };\n };\n const relayUrl = options?.relayUrl ?? proxyConfig.relayUrl;\n const relayToken = proxyConfig.relayToken;\n const statusConfig = {\n profile: PROFILE_NAME,\n relayName: proxyConfig.relayName,\n relayNameSource: proxyConfig.sources.relayName,\n relayUrl,\n relayUrlSource: proxyConfig.sources.relayUrl,\n relayTokenSource: proxyConfig.sources.relayToken,\n hookPort: proxyConfig.hookPort ?? 17654,\n hookPortSource: proxyConfig.sources.hookPort,\n };\n if (!relayUrl) {\n const msg = `Relay URL is required. Set relays.${proxyConfig.relayName}.url in ~/.dev-anywhere/config.json or pass --relay <name>.`;\n serviceLogger.error(msg);\n console.error(msg);\n process.exit(1);\n }\n const relayConnection = new RelayConnection(relayUrl, {\n name: proxyName,\n token: relayToken,\n proxyIdPath: PROXY_ID_PATH,\n });\n const relaySend = (data: string): void => relayConnection.sendRaw(data);\n const controlHandlers = createControlMessageHandlers(relaySend, sessionManager);\n\n // 两个观察通道共用同一个底层 changeSessionState 原语;由 FSM 按 session.mode 路由到对应转换表\n const observerChangeState = (sessionId: string, next: SessionState): boolean =>\n changeSessionState(sessionManager, relayConnection, sessionId, next);\n const observerTouchActivity = (sessionId: string): boolean =>\n touchSessionActivity(sessionManager, relayConnection, sessionId);\n const emitAgentStatus = (sessionId: string, phase: AgentStatusPayload[\"phase\"]): void => {\n const session = sessionManager.getSession(sessionId);\n if (!session) return;\n const payload: AgentStatusPayload = {\n provider: session.provider,\n phase,\n seq: new SeqCounter(sessionId).next(),\n updatedAt: Date.now(),\n };\n agentStatusRegistry.set(sessionId, payload);\n relayConnection.sendRaw(JSON.stringify({ type: \"agent_status\", sessionId, payload }));\n };\n const jsonObserver = new JsonObserver({\n changeSessionState: observerChangeState,\n emitAgentStatus,\n });\n const hookRuntime = await createProviderHookRuntime({\n hookPort: proxyConfig.hookPort,\n permissionBroker,\n sessionManager,\n relayConnection,\n agentStatusRegistry,\n changeSessionState: observerChangeState,\n });\n unregisterHookSession = (sessionId) => hookRuntime.hookRegistry.unregisterSession(sessionId);\n\n // WorkerRegistry 建在 relay 之后、listener 之前;构造期订阅 envelope_dropped 事件\n const workerRegistry = new WorkerRegistry({\n sessionManager,\n permissionBroker,\n relayConnection,\n jsonObserver,\n touchSessionActivity: observerTouchActivity,\n getProviderEnv,\n });\n const hostedPtyRegistry = new HostedPtyRegistry({\n sessionManager,\n relayConnection,\n getProviderEnv,\n changeSessionState: observerChangeState,\n touchSessionActivity: observerTouchActivity,\n onTurnComplete: (sessionId) => {\n resolveInterruptedApprovals(\n permissionBroker,\n hookRuntime.hookEventRouter,\n relayConnection,\n sessionId,\n );\n emitAgentStatus(sessionId, \"idle\");\n },\n onSessionClosed: (sessionId) => {\n controlHandlers.cleanup(sessionId);\n agentStatusRegistry.delete(sessionId);\n broadcastSessionList(relayConnection, sessionManager);\n },\n });\n\n relayConnection.connect();\n serviceLogger.info(\n {\n relayName: proxyConfig.relayName,\n profile: PROFILE_NAME,\n relayUrl,\n proxyName,\n tokenSet: !!relayToken,\n relayUrlSource: proxyConfig.sources.relayUrl,\n },\n \"Connecting to relay server\",\n );\n\n const relayRouter = new RelayRouter({\n sessionManager,\n workerRegistry,\n controlHandlers,\n relayConnection,\n relaySend,\n terminalSockets,\n hostedPtyRegistry,\n broadcastSessionList: () => broadcastSessionList(relayConnection, sessionManager),\n broadcastSessionSync: (session) => broadcastSessionSync(relayConnection, session),\n jsonObserver,\n createHookContext: hookRuntime.createHookContext,\n cleanupHookContext: (sessionId) => hookRuntime.hookRegistry.unregisterSession(sessionId),\n permissionBroker,\n hookEventRouter: hookRuntime.hookEventRouter,\n agentStatusRegistry,\n getProviderEnv,\n getAgentCliSuggestions,\n setAgentCliPath,\n getPreviewRoots,\n });\n\n relayConnection.on(\"message\", (msg: Record<string, unknown>) => relayRouter.handle(msg));\n relayConnection.on(\"connected\", () => {\n controlHandlers.reinitializeOnReconnect();\n broadcastBridgeStatus(true);\n });\n relayConnection.on(\"disconnected\", () => {\n broadcastBridgeStatus(false);\n });\n\n // 把 relay 连接状态广播给所有已注册的 terminal,终端进程会 stderr 打 banner 提示用户\n function broadcastBridgeStatus(connected: boolean): void {\n const msg = serializeIpc({ type: \"bridge_status\", connected });\n for (const [, sock] of terminalSockets) {\n if (sock.writable) sock.write(msg);\n }\n }\n\n await workerRegistry.reconnectAll();\n\n const server = createServer((socket) => {\n handleTerminalConnection(socket, {\n sessionManager,\n workerRegistry,\n terminalSockets,\n hostedPtyRegistry,\n relayConnection,\n controlHandlers,\n agentStatusRegistry,\n permissionBroker,\n hookEventRouter: hookRuntime.hookEventRouter,\n createHookContext: hookRuntime.createHookContext,\n emitAgentStatus,\n config: statusConfig,\n resolveInterruptedApprovals: (sessionId) =>\n resolveInterruptedApprovals(\n permissionBroker,\n hookRuntime.hookEventRouter,\n relayConnection,\n sessionId,\n ),\n });\n });\n\n server.listen(SOCK_PATH, () => {\n writeFileSync(PID_PATH, String(process.pid));\n chmodSync(SOCK_PATH, 0o600);\n serviceLogger.info({ pid: process.pid, sock: SOCK_PATH }, \"Service started\");\n });\n\n async function shutdown(): Promise<void> {\n serviceLogger.info(\"Shutting down service\");\n sessionManager.stopReaper();\n await hookRuntime.hookServer.close();\n relayConnection.close();\n workerRegistry.destroyAll();\n hostedPtyRegistry.destroyAll();\n server.close();\n try {\n unlinkSync(SOCK_PATH);\n } catch {\n // 关闭时 socket 文件可能已被删除\n }\n try {\n unlinkSync(PID_PATH);\n } catch {\n // 关闭时 PID 文件可能已被删除\n }\n process.exit(0);\n }\n\n process.on(\"SIGTERM\", () => {\n shutdown();\n });\n process.on(\"SIGINT\", () => {\n shutdown();\n });\n}\n\nconst isMainModule =\n process.argv[1] && (process.argv[1].endsWith(\"serve.js\") || process.argv[1].endsWith(\"serve.ts\"));\n\nif (isMainModule) {\n startService(parseServiceOptions(process.argv.slice(2))).catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n serviceLogger.error({ err: message }, \"Service failed to start\");\n console.error(message);\n process.exit(1);\n });\n}\n","import { mkdirSync, readFileSync, renameSync, writeFileSync, existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { nanoid } from \"nanoid\";\nimport { SessionState } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { defineFSM } from \"../common/state-machine.js\";\nimport type { ProviderId } from \"../providers/index.js\";\n\nexport interface SessionInfo {\n id: string;\n mode: \"pty\" | \"json\";\n provider: ProviderId;\n ptyOwner?: \"local-terminal\" | \"proxy-hosted\";\n state: SessionState;\n createdAt: number;\n updatedAt: number;\n name?: string;\n cwd: string;\n // Claude CLI 自己生成的 session ID,和上面 id 字段无关\n // 用途:定位 ~/.claude/projects/<encoded-cwd>/<claudeSessionId>.jsonl 历史文件 / 支持 --resume\n claudeSessionId?: string;\n pid: number;\n}\n\ninterface SessionManagerOptions {\n persistPath: string;\n reaperIntervalMs?: number;\n onSessionRemoved?: (id: string, context?: SessionRemoveContext) => void;\n}\n\ninterface SessionRemoveContext {\n preserveProviderHooks?: boolean;\n}\n\n// 两个观察通道的合法转换表分离:PTY 看 OSC 信号、JSON 看 stream-json 事件,各自的状态空间和规则不同。\n// terminated 是终态,不允许任何转出。\n\n// PTY 观察通道:从终端 OSC 0/9 信号 + idle timer 推导状态。\n// ERROR 在 PTY 观察通道不可达:PTY 错误体现为终端 ANSI 内容,proxy 不建模观察器失联。\nconst PTY_TRANSITIONS: Record<SessionState, readonly SessionState[]> = {\n [SessionState.IDLE]: [\n // claude 开始响应用户输入 → handlePtyData 首字节翻 working\n SessionState.WORKING,\n // provider hook 是语义事件,可能比 PTY 字节观察更早到达;PermissionRequest 可直接进入审批等待。\n SessionState.WAITING_APPROVAL,\n // 终态兜底;现阶段 terminated 走 terminateSession 直接删 map 不经 updateState,本边未被触发\n SessionState.TERMINATED,\n ],\n [SessionState.WORKING]: [\n // 5s 静默且 currentPtyState === \"working\" → idle timer 推 turn_complete\n SessionState.IDLE,\n // claude 发 OSC 9 \"needs your permission: <tool>\" → handlePtyData 推 approval_wait\n SessionState.WAITING_APPROVAL,\n // 终态兜底\n SessionState.TERMINATED,\n ],\n [SessionState.WAITING_APPROVAL]: [\n // 审批解除后 provider 可能继续工作,也可能直接结束本轮。\n // 真实 Claude 拒绝工具审批后会直接发 turn_complete,因此 WAITING_APPROVAL -> IDLE 是合法边。\n SessionState.WORKING,\n SessionState.IDLE,\n // 终态兜底\n SessionState.TERMINATED,\n ],\n // PTY 永不进入 ERROR;本行仅为满足 Record<SessionState,_> 枚举完整性保留\n [SessionState.ERROR]: [SessionState.TERMINATED],\n [SessionState.TERMINATED]: [],\n};\n\n// JSON 观察通道:从 stream-json 事件 + relay 入站消息推导状态。\n// 注意:turn 结束时 result.is_error === true 不走 ERROR——它属于 turn 内部错误,观察通道本身健康,仍按 onTurnResult → IDLE 处理。\nconst JSON_TRANSITIONS: Record<SessionState, readonly SessionState[]> = {\n [SessionState.IDLE]: [\n // 用户在 relay/web 端发消息 → onTurnStart,turn 开始\n SessionState.WORKING,\n // 空闲期观察通道失联(worker socket 死但 pid 仍在等)→ onChannelBroken\n SessionState.ERROR,\n // 终态兜底;同 PTY,当前不经 updateState\n SessionState.TERMINATED,\n ],\n [SessionState.WORKING]: [\n // stream-json result event → onTurnResult,turn 结束\n SessionState.IDLE,\n // claude 发 control_request → onApprovalRequested,阻塞等审批\n SessionState.WAITING_APPROVAL,\n // turn 进行中通道失联 → onChannelBroken\n SessionState.ERROR,\n // 终态兜底\n SessionState.TERMINATED,\n ],\n [SessionState.WAITING_APPROVAL]: [\n // 粒度丢失:审批解除后 claude 继续跑,proxy 观察不到中间的 WORKING 信号,\n // 直到 result event 才感知 → onTurnResult 一次性从 WAITING_APPROVAL 跳到 IDLE。\n // 因此不列 WAITING_APPROVAL → WORKING 这条边。\n SessionState.IDLE,\n // 审批死锁:control_response 写 worker stdin 失败 → onChannelBroken。\n // 这是 ERROR 态最明确的落地场景,让 UI 能区分 \"正在等用户决定\" 和 \"审批通道坏了\"。\n SessionState.ERROR,\n // 终态兜底\n SessionState.TERMINATED,\n ],\n [SessionState.ERROR]: [\n // 观察通道坏了之后只能 terminate,不回 IDLE/WORKING——恢复机制未实现\n SessionState.TERMINATED,\n ],\n [SessionState.TERMINATED]: [],\n};\n\nconst ptyFSM = defineFSM(PTY_TRANSITIONS);\nconst jsonFSM = defineFSM(JSON_TRANSITIONS);\n\nfunction fsmForMode(mode: \"pty\" | \"json\"): ReturnType<typeof defineFSM<SessionState>> {\n return mode === \"pty\" ? ptyFSM : jsonFSM;\n}\n\nfunction isProviderId(value: unknown): value is ProviderId {\n return value === \"claude\" || value === \"codex\";\n}\n\nexport class SessionManager {\n private sessions: Map<string, SessionInfo> = new Map();\n private reaperTimer: NodeJS.Timeout | null = null;\n private readonly persistPath: string;\n private readonly reaperIntervalMs: number;\n private readonly onSessionRemoved?: (id: string, context?: SessionRemoveContext) => void;\n\n constructor(options: SessionManagerOptions) {\n this.persistPath = options.persistPath;\n this.reaperIntervalMs = options.reaperIntervalMs ?? 60000;\n this.onSessionRemoved = options.onSessionRemoved;\n this.load();\n }\n\n createSession(\n mode: \"pty\" | \"json\",\n cwd: string,\n pid: number,\n name?: string,\n id?: string,\n provider: ProviderId = \"claude\",\n ptyOwner?: \"local-terminal\" | \"proxy-hosted\",\n ): SessionInfo {\n const now = Date.now();\n const info: SessionInfo = {\n id: id ?? nanoid(),\n mode,\n provider,\n ...(mode === \"pty\" && ptyOwner !== undefined ? { ptyOwner } : {}),\n state: SessionState.IDLE,\n createdAt: now,\n updatedAt: now,\n cwd,\n pid,\n ...(name !== undefined ? { name } : {}),\n };\n this.sessions.set(info.id, info);\n this.save();\n serviceLogger.info({ sessionId: info.id, mode, provider, ptyOwner, name }, \"Session created\");\n return info;\n }\n\n listSessions(): SessionInfo[] {\n return Array.from(this.sessions.values()).sort((a, b) => b.createdAt - a.createdAt);\n }\n\n getSession(id: string): SessionInfo | undefined {\n return this.sessions.get(id);\n }\n\n updateState(id: string, newState: SessionState): boolean {\n const session = this.sessions.get(id);\n if (!session) {\n // session 不存在是调用方 bug,不是观察竞态,保留 throw\n throw new Error(`Session not found: ${id}`);\n }\n const oldState = session.state;\n if (oldState === newState) return false;\n const fsm = fsmForMode(session.mode);\n if (!fsm.canTransition(oldState, newState)) {\n // 吸收态(传递闭包推导:TERMINATED + 所有出边都指向吸收态的状态)之后的残余转换请求\n // 是进程竞态,日志降噪到 debug;其他非法转换是协议违反或 bug,warn 以便盯盘能看到\n const level = fsm.isAbsorbing(oldState) ? \"debug\" : \"warn\";\n serviceLogger[level](\n { sessionId: id, from: oldState, to: newState, mode: session.mode },\n level === \"debug\"\n ? \"State change after absorbing state (residual, likely race)\"\n : \"Invalid state transition rejected by FSM\",\n );\n return false;\n }\n session.state = newState;\n session.updatedAt = Date.now();\n this.save();\n serviceLogger.info({ sessionId: id, from: oldState, to: newState }, \"Session state changed\");\n return true;\n }\n\n touchSession(id: string, now: number = Date.now(), minIntervalMs = 0): boolean {\n const session = this.sessions.get(id);\n if (!session) return false;\n if (now - session.updatedAt < minIntervalMs) return false;\n session.updatedAt = now;\n this.save();\n return true;\n }\n\n terminateSession(id: string, context?: SessionRemoveContext): { success: boolean; pid?: number } {\n const session = this.sessions.get(id);\n if (!session) {\n return { success: false };\n }\n const pid = session.pid;\n this.sessions.delete(id);\n this.save();\n serviceLogger.info({ sessionId: id, mode: session.mode, pid }, \"Session terminated\");\n this.onSessionRemoved?.(id, context);\n return { success: true, pid };\n }\n\n terminateAll(): number[] {\n const pids: number[] = [];\n const ids = Array.from(this.sessions.keys());\n for (const id of ids) {\n const session = this.sessions.get(id)!;\n if (session.mode === \"json\" && session.pid !== undefined) {\n pids.push(session.pid);\n }\n this.sessions.delete(id);\n this.onSessionRemoved?.(id);\n }\n this.save();\n return pids;\n }\n\n setClaudeSessionId(id: string, claudeSessionId: string): void {\n const session = this.sessions.get(id);\n if (!session) {\n throw new Error(`Session not found: ${id}`);\n }\n session.claudeSessionId = claudeSessionId;\n this.save();\n }\n\n setPid(id: string, pid: number): void {\n const session = this.sessions.get(id);\n if (!session) {\n throw new Error(`Session not found: ${id}`);\n }\n session.pid = pid;\n this.save();\n }\n\n startReaper(intervalMs: number = this.reaperIntervalMs): void {\n this.stopReaper();\n this.reaperTimer = setInterval(() => this.reap(), intervalMs);\n }\n\n stopReaper(): void {\n if (this.reaperTimer) {\n clearInterval(this.reaperTimer);\n this.reaperTimer = null;\n }\n }\n\n private reap(): void {\n const toRemove: Array<{ id: string; reason: string }> = [];\n // 检查 JSON 会话的子进程是否存活\n // PTY 会话的生命周期由 IPC socket close 事件管理,不需要 reaper 参与\n for (const session of this.sessions.values()) {\n if (\n session.mode === \"json\" &&\n session.pid !== undefined &&\n session.state !== SessionState.TERMINATED\n ) {\n if (!this.isProcessAlive(session.pid)) {\n toRemove.push({ id: session.id, reason: `JSON worker process ${session.pid} is dead` });\n }\n }\n }\n for (const { id, reason } of toRemove) {\n serviceLogger.warn({ sessionId: id, reason }, \"Reaping stale session\");\n this.terminateSession(id);\n }\n }\n\n private isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n private save(): void {\n const dir = dirname(this.persistPath);\n mkdirSync(dir, { recursive: true });\n // state 是对 claude 的观察值,进程死后无意义,不落盘。磁盘上只留 identity(id/mode/cwd/pid/...)。\n const persisted = Array.from(this.sessions.values()).map((s) => ({\n id: s.id,\n mode: s.mode,\n provider: s.provider,\n createdAt: s.createdAt,\n updatedAt: s.updatedAt,\n cwd: s.cwd,\n pid: s.pid,\n ...(s.name !== undefined ? { name: s.name } : {}),\n ...(s.claudeSessionId !== undefined ? { claudeSessionId: s.claudeSessionId } : {}),\n }));\n const data = JSON.stringify(persisted, null, 2);\n const tmpPath = this.persistPath + \".tmp\";\n writeFileSync(tmpPath, data, \"utf-8\");\n renameSync(tmpPath, this.persistPath);\n }\n\n private load(): void {\n if (!existsSync(this.persistPath)) {\n return;\n }\n const raw = readFileSync(this.persistPath, \"utf-8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(`Failed to parse session persistence file at ${this.persistPath}`, {\n cause: err,\n });\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n `Session persistence file has invalid format at ${this.persistPath}: expected array`,\n );\n }\n for (const item of parsed) {\n if (item && typeof item === \"object\" && \"state\" in item) {\n throw new Error(\n `Session persistence file has invalid persisted state for session ${String(\n (item as { id?: unknown }).id,\n )}`,\n );\n }\n const info = item as Omit<SessionInfo, \"state\"> & { state?: SessionState };\n if (!isProviderId(info.provider)) {\n const sessionId = String(info.id);\n this.onSessionRemoved?.(sessionId);\n serviceLogger.warn(\n { sessionId, provider: info.provider },\n \"Session persistence file has invalid provider; cleaning session\",\n );\n continue;\n }\n if (info.mode === \"pty\") {\n if (info.pid && this.isProcessAlive(info.pid)) {\n // terminal 进程仍存活,会重连,保留磁盘数据但不加载到内存\n serviceLogger.info(\n { sessionId: info.id, pid: info.pid },\n \"PTY session skipped on load, terminal alive\",\n );\n } else {\n // terminal 进程已死,清理数据\n this.onSessionRemoved?.(info.id);\n serviceLogger.info(\n { sessionId: info.id, pid: info.pid },\n \"PTY session cleaned on load, terminal dead\",\n );\n }\n continue;\n }\n // JSON 会话:检查 worker 进程是否存活,无 PID 或进程已死则清理\n if (info.pid && this.isProcessAlive(info.pid)) {\n // 加载回内存时 state 固定回观察零点 IDLE,等观察器下一轮信号推到位\n this.sessions.set(info.id, { ...info, state: SessionState.IDLE });\n } else {\n this.onSessionRemoved?.(info.id);\n serviceLogger.info(\n { sessionId: info.id, pid: info.pid },\n \"JSON session cleaned on load, worker dead\",\n );\n }\n }\n // 清理后回写磁盘,避免已清理的会话在下次启动时重复处理\n this.save();\n if (this.sessions.size > 0) {\n serviceLogger.info({ count: this.sessions.size }, \"Sessions restored from persistence\");\n }\n }\n}\n","import WebSocket from \"ws\";\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { nanoid } from \"nanoid\";\nimport { EventEmitter } from \"node:events\";\nimport type { MessageEnvelope } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { createFSM } from \"../common/state-machine.js\";\nimport { MemoryMessageQueue } from \"./message-queue.js\";\n\n// 默认 proxyId 存储路径\nconst DEFAULT_PROXY_ID_PATH = join(homedir(), \".dev-anywhere\", \"proxy-id\");\n\n// 指数退避上限 30 秒\nconst MAX_BACKOFF_MS = 30000;\n// 退避基数 1 秒\nconst BASE_BACKOFF_MS = 1000;\n// 消息队列上限\nconst MAX_QUEUE_SIZE = 10000;\n\nexport const RelayConnectionState = {\n DISCONNECTED: \"disconnected\",\n CONNECTING: \"connecting\",\n REGISTERING: \"registering\",\n SYNCED: \"synced\",\n WAITING_RECONNECT: \"waiting_reconnect\",\n CLOSED: \"closed\",\n} as const;\nexport type RelayConnectionState = (typeof RelayConnectionState)[keyof typeof RelayConnectionState];\n\n// 合法的 WS 连接状态转移\n// CLOSED 是终态;connect 流转: DISCONNECTED → CONNECTING → REGISTERING → SYNCED\n// 断线: SYNCED/REGISTERING/CONNECTING → WAITING_RECONNECT → CONNECTING\n// 主动关: 任意 → CLOSED\nconst RELAY_TRANSITIONS: Record<RelayConnectionState, readonly RelayConnectionState[]> = {\n [RelayConnectionState.DISCONNECTED]: [\n RelayConnectionState.CONNECTING,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.CONNECTING]: [\n RelayConnectionState.REGISTERING,\n RelayConnectionState.WAITING_RECONNECT,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.REGISTERING]: [\n RelayConnectionState.SYNCED,\n RelayConnectionState.WAITING_RECONNECT,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.SYNCED]: [\n RelayConnectionState.WAITING_RECONNECT,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.WAITING_RECONNECT]: [\n RelayConnectionState.CONNECTING,\n RelayConnectionState.CLOSED,\n ],\n [RelayConnectionState.CLOSED]: [],\n};\n\ninterface RelayConnectionOptions {\n // 自定义 proxyId 文件路径,测试时使用临时目录\n proxyIdPath?: string;\n // proxy 显示名称,注册时发送给 relay\n name?: string;\n // 公网 relay 的 /proxy 端点预共享 token, relay 侧 RELAY_PROXY_TOKEN 对应\n token?: string;\n}\n\n// 管理代理到中转服务器的出站 WebSocket 连接,支持自动重连和消息队列\nexport class RelayConnection extends EventEmitter {\n private ws: WebSocket | null = null;\n private proxyId: string;\n private relayUrl: string;\n private queue: MemoryMessageQueue = new MemoryMessageQueue();\n private reconnectAttempt: number = 0;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private fsm = createFSM({\n initial: RelayConnectionState.DISCONNECTED as RelayConnectionState,\n transitions: RELAY_TRANSITIONS,\n onTransition: (from, to) =>\n serviceLogger.info({ from, to }, \"RelayConnection state transition\"),\n onRejected: (from, to, isAbsorbing) =>\n serviceLogger[isAbsorbing ? \"debug\" : \"warn\"](\n { from, to },\n isAbsorbing\n ? \"Late event after absorbing state, ignored\"\n : \"Invalid relay connection transition rejected\",\n ),\n });\n private name?: string;\n private token?: string;\n\n constructor(relayUrl: string, options?: RelayConnectionOptions) {\n super();\n this.relayUrl = relayUrl;\n this.proxyId = this.loadOrCreateProxyId(options?.proxyIdPath ?? DEFAULT_PROXY_ID_PATH);\n this.name = options?.name;\n this.token = options?.token;\n }\n\n // 从文件读取或生成新的 proxyId,生成后持久化到文件\n private loadOrCreateProxyId(idPath: string): string {\n if (existsSync(idPath)) {\n const existing = readFileSync(idPath, \"utf-8\").trim();\n if (existing.length > 0) {\n return existing;\n }\n }\n\n const id = nanoid(21);\n const dir = dirname(idPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(idPath, id, \"utf-8\");\n return id;\n }\n\n // 连接到 relay server\n connect(): void {\n if (!this.fsm.tryTransitionTo(RelayConnectionState.CONNECTING)) return;\n this.doConnect();\n }\n\n // 实际建立 WebSocket 连接的内部方法\n private doConnect(): void {\n try {\n const base = this.relayUrl.replace(/\\/$/, \"\") + \"/proxy\";\n const url = this.token ? `${base}?token=${encodeURIComponent(this.token)}` : base;\n this.ws = new WebSocket(url);\n\n this.ws.on(\"open\", () => {\n // open 属异步回调,若同步 close() 已先切 CLOSED,REGISTERING 会被拒,需跳过后续 register\n if (!this.fsm.tryTransitionTo(RelayConnectionState.REGISTERING)) return;\n serviceLogger.info(\n { proxyId: this.proxyId, url: base, tokenSet: !!this.token },\n \"Connected to relay server\",\n );\n this.ws!.send(\n JSON.stringify({\n type: \"proxy_register\",\n proxyId: this.proxyId,\n ...(this.name ? { name: this.name } : {}),\n }),\n );\n });\n\n this.ws.on(\"message\", (data) => {\n const raw = data.toString();\n let msg: Record<string, unknown>;\n try {\n msg = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n serviceLogger.warn({ error: String(err) }, \"Non-JSON message from relay, dropped\");\n return;\n }\n if (msg.type === \"proxy_register_response\") {\n serviceLogger.info({ status: msg.status }, \"Received register response\");\n if (!this.fsm.tryTransitionTo(RelayConnectionState.SYNCED)) return;\n this.reconnectAttempt = 0;\n this.flushQueue();\n this.emit(\"connected\");\n return;\n }\n this.emit(\"message\", msg);\n });\n\n this.ws.on(\"close\", () => {\n this.ws = null;\n if (this.fsm.current() !== RelayConnectionState.CLOSED) {\n this.fsm.tryTransitionTo(RelayConnectionState.WAITING_RECONNECT);\n serviceLogger.info(\"Relay connection closed unexpectedly\");\n this.emit(\"disconnected\");\n this.scheduleReconnect();\n } else {\n serviceLogger.info(\"Relay connection closed\");\n }\n });\n\n this.ws.on(\"error\", (err) => {\n serviceLogger.error({ error: String(err) }, \"Relay connection error\");\n });\n } catch (err) {\n serviceLogger.error({ error: String(err) }, \"Failed to create relay connection\");\n if (this.fsm.current() !== RelayConnectionState.CLOSED) {\n this.fsm.tryTransitionTo(RelayConnectionState.WAITING_RECONNECT);\n this.scheduleReconnect();\n }\n }\n }\n\n // 将队列中缓存的消息依次发送到 relay\n private flushQueue(): void {\n for (const raw of this.queue.drain()) {\n this.ws?.send(raw);\n }\n }\n\n // 计算全抖动指数退避延迟并调度重连\n private scheduleReconnect(): void {\n const backoff =\n Math.random() *\n Math.min(MAX_BACKOFF_MS, BASE_BACKOFF_MS * Math.pow(2, this.reconnectAttempt));\n serviceLogger.info(\n { attempt: this.reconnectAttempt + 1, backoffMs: Math.round(backoff) },\n \"Scheduling reconnect\",\n );\n this.reconnectTimer = setTimeout(() => {\n this.reconnectAttempt++;\n // 必须先回 CONNECTING 才能让 open handler 合法转到 REGISTERING;\n // 若 close() 抢先切 CLOSED(clearTimeout 理论上拦得住,保险再守一层),跳过重连\n if (!this.fsm.tryTransitionTo(RelayConnectionState.CONNECTING)) return;\n this.doConnect();\n }, backoff);\n }\n\n // 发送 MessageEnvelope 到 relay,离线时自动入队\n sendEnvelope(envelope: MessageEnvelope): void {\n const raw = JSON.stringify(envelope);\n this.sendRaw(raw);\n }\n\n // 发送 binary PTY 帧到 relay,断线时直接丢弃不入队\n sendBinary(data: Buffer): void {\n if (\n this.fsm.current() === RelayConnectionState.SYNCED &&\n this.ws?.readyState === WebSocket.OPEN\n ) {\n this.ws.send(data);\n }\n // binary 帧无队列,断线丢弃\n }\n\n // 发送原始 JSON 字符串到 relay,根据 connectionState 决定直发、入队或丢弃\n sendRaw(raw: string): void {\n if (\n this.fsm.current() === RelayConnectionState.SYNCED &&\n this.ws?.readyState === WebSocket.OPEN\n ) {\n this.ws.send(raw);\n } else if (this.fsm.current() === RelayConnectionState.CLOSED) {\n serviceLogger.warn(\"Message discarded: connection is closed\");\n } else {\n if (this.queue.size() >= MAX_QUEUE_SIZE) {\n const dropped = this.queue.dropOldest();\n serviceLogger.warn(\n { maxSize: MAX_QUEUE_SIZE },\n \"Message queue overflow, oldest message dropped\",\n );\n // 通知订阅方(WorkerRegistry)补偿被丢的 envelope,例如清理 pending 审批\n if (dropped !== null) this.emit(\"envelope_dropped\", dropped);\n }\n this.queue.enqueue(raw);\n serviceLogger.debug({ queueSize: this.queue.size() }, \"Message queued during disconnect\");\n }\n }\n\n // 主动关闭连接,发送 proxy_disconnect 通知 relay 立即清理,不触发重连\n close(): void {\n // 幂等:已 CLOSED 直接跳过,避免 FSM 抛 closed -> closed\n if (this.fsm.is(RelayConnectionState.CLOSED)) return;\n this.fsm.tryTransitionTo(RelayConnectionState.CLOSED);\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n if (this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify({ type: \"proxy_disconnect\", proxyId: this.proxyId }));\n }\n this.ws.close();\n this.ws = null;\n }\n }\n\n // 获取当前 proxyId\n getProxyId(): string {\n return this.proxyId;\n }\n\n // 获取连接状态摘要,用于 CLI status 输出\n getStatus(): {\n connected: boolean;\n connectionState: RelayConnectionState;\n proxyId: string;\n reconnectAttempt: number;\n queueDepth: number;\n } {\n return {\n connected: this.fsm.current() === RelayConnectionState.SYNCED,\n connectionState: this.fsm.current(),\n proxyId: this.proxyId,\n reconnectAttempt: this.reconnectAttempt,\n queueDepth: this.queue.size(),\n };\n }\n}\n","// 发送队列只负责内存背压和有序 drain;持久化恢复由 relay/proxy 重拉协议承担。\ninterface MessageQueue {\n enqueue(raw: string): void;\n drain(): string[];\n size(): number;\n clear(): void;\n dropOldest(): string | null;\n}\n\nexport class MemoryMessageQueue implements MessageQueue {\n private items: string[] = [];\n\n enqueue(raw: string): void {\n this.items.push(raw);\n }\n\n drain(): string[] {\n const all = this.items;\n this.items = [];\n return all;\n }\n\n size(): number {\n return this.items.length;\n }\n\n clear(): void {\n this.items = [];\n }\n\n // 丢弃最旧消息,返回被丢弃的 raw 供 caller 做补偿(例如清理对应 pending 审批)\n dropOldest(): string | null {\n return this.items.shift() ?? null;\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute } from \"node:path\";\nimport { CONFIG_PATH, PROFILE_NAME, defaultHookPortForProfile } from \"./paths.js\";\nimport { serviceLogger } from \"./logger.js\";\nimport type { ProviderId } from \"../providers/types.js\";\n\nexport interface ProxyConfig {\n profileName: string;\n relayName: string;\n relayUrl?: string;\n // /proxy 端点的预共享 token, 和 relay 侧 RELAY_PROXY_TOKEN 对应. 公网 relay 必须设置\n relayToken?: string;\n hookPort?: number;\n claudeBin?: string;\n codexBin?: string;\n previewRoots: string[];\n agentCliSuggestions: Record<ProviderId, string[]>;\n sources: {\n relayName: \"cli\" | \"profile\";\n relayUrl: \"env\" | \"file\" | \"none\";\n relayToken: \"env\" | \"file\" | \"none\";\n hookPort: \"env\" | \"default\";\n claudeBin: \"env\" | \"file\" | \"none\";\n codexBin: \"env\" | \"file\" | \"none\";\n };\n}\n\ninterface ProxyProfileConfig {\n relay?: string;\n}\n\ninterface RelayTargetConfig {\n url?: string;\n proxyToken?: string;\n}\n\ninterface ProxyConfigFile {\n defaultProfile?: string;\n profiles: Record<string, ProxyProfileConfig | undefined>;\n relays: Record<string, RelayTargetConfig | undefined>;\n agentCli?: AgentCliConfig;\n previewRoots?: string[];\n}\n\ninterface AgentCliConfig {\n claudeBin?: string;\n codexBin?: string;\n claudeBinHistory?: string[];\n codexBinHistory?: string[];\n}\n\nfunction parsePort(value: string | undefined, source: string): number | undefined {\n if (!value) return undefined;\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error(`Invalid ${source}: expected TCP port 1-65535`);\n }\n return port;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction validateConfigShape(value: unknown): ProxyConfigFile {\n if (!isRecord(value) || !isRecord(value.profiles) || !isRecord(value.relays)) {\n throw new Error(`Invalid config shape in ${CONFIG_PATH}: expected \"profiles\" and \"relays\".`);\n }\n return value as unknown as ProxyConfigFile;\n}\n\nfunction readConfigFile(): ProxyConfigFile {\n if (!existsSync(CONFIG_PATH)) {\n throw new Error(`Dev Anywhere config not found at ${CONFIG_PATH}. Run \"dev-anywhere init\".`);\n }\n return validateConfigShape(JSON.parse(readFileSync(CONFIG_PATH, \"utf-8\")));\n}\n\nfunction agentCliField(provider: ProviderId): \"claudeBin\" | \"codexBin\" {\n return provider === \"claude\" ? \"claudeBin\" : \"codexBin\";\n}\n\nfunction agentCliHistoryField(provider: ProviderId): \"claudeBinHistory\" | \"codexBinHistory\" {\n return provider === \"claude\" ? \"claudeBinHistory\" : \"codexBinHistory\";\n}\n\nfunction validateAgentCliPath(path: string): string {\n const normalized = path.trim();\n if (!normalized) throw new Error(\"请输入 CLI 路径\");\n if (!isAbsolute(normalized)) throw new Error(\"CLI 路径必须是绝对路径\");\n return normalized;\n}\n\nfunction uniqueAbsolutePaths(paths: Array<string | undefined>): string[] {\n const seen = new Set<string>();\n const result: string[] = [];\n for (const path of paths) {\n const normalized = path?.trim();\n if (!normalized || !isAbsolute(normalized) || seen.has(normalized)) continue;\n seen.add(normalized);\n result.push(normalized);\n }\n return result;\n}\n\nfunction resolveRelayConfig(\n fromFile: ProxyConfigFile,\n requestedRelayName?: string,\n): {\n relayName: string;\n relayNameSource: ProxyConfig[\"sources\"][\"relayName\"];\n relay: RelayTargetConfig;\n} {\n const profile = fromFile.profiles[PROFILE_NAME];\n if (!profile) {\n const available = Object.keys(fromFile.profiles).sort();\n throw new Error(\n `Unknown profile \"${PROFILE_NAME}\". Available profiles: ${available.length > 0 ? available.join(\", \") : \"(none)\"}`,\n );\n }\n\n const relayName = requestedRelayName?.trim() || profile.relay?.trim();\n if (!relayName) {\n throw new Error(`Profile \"${PROFILE_NAME}\" must specify a relay.`);\n }\n\n const relay = fromFile.relays[relayName];\n if (!relay) {\n const available = Object.keys(fromFile.relays).sort();\n throw new Error(\n `Unknown relay \"${relayName}\". Available relays: ${available.length > 0 ? available.join(\", \") : \"(none)\"}`,\n );\n }\n\n return {\n relayName,\n relayNameSource: requestedRelayName?.trim() ? \"cli\" : \"profile\",\n relay,\n };\n}\n\nexport function loadConfig(options?: { relayName?: string }): ProxyConfig {\n const fromFile = readConfigFile();\n const agentCli = fromFile.agentCli ?? {};\n const resolved = resolveRelayConfig(fromFile, options?.relayName);\n const claudeBin = process.env.CLAUDE_BIN ?? agentCli.claudeBin;\n const codexBin = process.env.CODEX_BIN ?? agentCli.codexBin;\n const config: ProxyConfig = {\n profileName: PROFILE_NAME,\n relayName: resolved.relayName,\n relayUrl: process.env.RELAY_URL ?? resolved.relay.url,\n relayToken: process.env.RELAY_PROXY_TOKEN ?? resolved.relay.proxyToken,\n hookPort:\n parsePort(process.env.DEV_ANYWHERE_HOOK_PORT, \"DEV_ANYWHERE_HOOK_PORT\") ??\n defaultHookPortForProfile(PROFILE_NAME),\n claudeBin,\n codexBin,\n previewRoots: uniqueAbsolutePaths(fromFile.previewRoots ?? []),\n agentCliSuggestions: {\n claude: uniqueAbsolutePaths([\n process.env.CLAUDE_BIN,\n agentCli.claudeBin,\n ...(agentCli.claudeBinHistory ?? []),\n ]),\n codex: uniqueAbsolutePaths([\n process.env.CODEX_BIN,\n agentCli.codexBin,\n ...(agentCli.codexBinHistory ?? []),\n ]),\n },\n sources: {\n relayName: resolved.relayNameSource,\n relayUrl: process.env.RELAY_URL ? \"env\" : resolved.relay.url ? \"file\" : \"none\",\n relayToken: process.env.RELAY_PROXY_TOKEN\n ? \"env\"\n : resolved.relay.proxyToken\n ? \"file\"\n : \"none\",\n hookPort: process.env.DEV_ANYWHERE_HOOK_PORT ? \"env\" : \"default\",\n claudeBin: process.env.CLAUDE_BIN ? \"env\" : agentCli.claudeBin ? \"file\" : \"none\",\n codexBin: process.env.CODEX_BIN ? \"env\" : agentCli.codexBin ? \"file\" : \"none\",\n },\n };\n\n serviceLogger.info(\n {\n profile: config.profileName,\n relayName: config.relayName,\n relayNameSource: config.sources.relayName,\n relayUrl: config.relayUrl ?? \"(unset)\",\n relayUrlSource: config.sources.relayUrl,\n relayTokenSource: config.sources.relayToken,\n hookPort: config.hookPort,\n hookPortSource: config.sources.hookPort,\n claudeBinSource: config.sources.claudeBin,\n codexBinSource: config.sources.codexBin,\n },\n \"Config loaded\",\n );\n\n return config;\n}\n\nexport function buildProviderEnv(\n config: ProxyConfig,\n baseEnv: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n return {\n ...baseEnv,\n ...(config.claudeBin ? { CLAUDE_BIN: config.claudeBin } : {}),\n ...(config.codexBin ? { CODEX_BIN: config.codexBin } : {}),\n };\n}\n\nfunction updateAgentCliConfig(\n config: AgentCliConfig,\n provider: ProviderId,\n path: string,\n): AgentCliConfig {\n const field = agentCliField(provider);\n const historyField = agentCliHistoryField(provider);\n const history = uniqueAbsolutePaths([path, ...(config[historyField] ?? [])]).slice(0, 8);\n return {\n ...config,\n [field]: path,\n [historyField]: history,\n };\n}\n\nexport function saveAgentCliPath(provider: ProviderId, path: string): void {\n const normalized = validateAgentCliPath(path);\n const fromFile = readConfigFile();\n fromFile.agentCli = updateAgentCliConfig(fromFile.agentCli ?? {}, provider, normalized);\n mkdirSync(dirname(CONFIG_PATH), { recursive: true });\n writeFileSync(CONFIG_PATH, `${JSON.stringify(fromFile, null, 2)}\\n`, \"utf-8\");\n}\n","import { readdir, mkdir } from \"node:fs/promises\";\nimport { join, isAbsolute, normalize } from \"node:path\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport type { SessionManager } from \"../session-manager.js\";\nimport { scanSessionHistory } from \"../session-history.js\";\nimport { discoverCommands } from \"../command-discovery.js\";\nimport { serviceLogger } from \"../../common/logger.js\";\nimport { classifyPathError } from \"../path-errors.js\";\n\nexport interface ControlMessageHandlers {\n handleDirListRequest(msg: { path: string; requestId?: string }): Promise<void>;\n handleDirCreateRequest(msg: { path: string; requestId?: string }): Promise<void>;\n handleSessionHistoryRequest(msg: { requestId?: string }): Promise<void>;\n handleSessionResourcesRequest(msg: {\n sessionId: string;\n requestId?: string;\n workDir: string;\n }): Promise<void>;\n pushCommandList(sessionId: string, workDir: string): Promise<void>;\n pushFileTree(sessionId: string, workDir: string): Promise<void>;\n reinitializeOnReconnect(): Promise<void>;\n cleanup(sessionId: string): void;\n}\n\n// 每个 session 的定时器和资源\ninterface SessionResources {\n commandRefreshTimer?: NodeJS.Timeout;\n fileTreeWorkDir?: string;\n}\n\n// 命令刷新间隔 6 小时\nconst COMMAND_REFRESH_MS = 6 * 60 * 60 * 1000;\n\n// 路径安全校验:拒绝相对路径和路径遍历\nfunction isPathSafe(path: string): boolean {\n if (!isAbsolute(path)) return false;\n const normalized = normalize(path);\n // 检查 normalize 后是否仍包含 ..(理论上不会,但做防御)\n if (normalized.includes(\"..\")) return false;\n return true;\n}\n\n// picker 展示忽略规则: dotfile + node_modules\n// listDirectory (按需) 与 getFileTree (预热) 必须共用, 否则逐层下钻会暴露 node_modules\nconst HIDDEN_ENTRY_NAMES = new Set([\"node_modules\"]);\nfunction isPickerVisible(name: string): boolean {\n return !name.startsWith(\".\") && !HIDDEN_ENTRY_NAMES.has(name);\n}\n\n// 目录优先 + 字母序, picker 侧依赖这个顺序做键盘导航默认选中\nfunction sortEntries(\n a: { isDir: boolean; name: string },\n b: { isDir: boolean; name: string },\n): number {\n if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;\n return a.name.localeCompare(b.name);\n}\n\nasync function scanDir(dirPath: string): Promise<Array<{ name: string; isDir: boolean }>> {\n const entries = await readdir(dirPath, { withFileTypes: true });\n return entries\n .filter((e) => isPickerVisible(e.name))\n .map((e) => ({ name: e.name, isDir: e.isDirectory() }))\n .sort(sortEntries);\n}\n\n// 预热 cwd + 直接子目录两层, 按目录分组返回, 前端写入 tree[path] 后逐层 picker 直接命中\ninterface FileTreeGroup {\n path: string;\n entries: Array<{ name: string; isDir: boolean }>;\n}\n\nasync function getFileTree(rootPath: string): Promise<FileTreeGroup[]> {\n const groups: FileTreeGroup[] = [];\n\n let rootEntries: Array<{ name: string; isDir: boolean }>;\n try {\n rootEntries = await scanDir(rootPath);\n } catch {\n return groups;\n }\n groups.push({ path: rootPath, entries: rootEntries });\n\n for (const sub of rootEntries) {\n if (!sub.isDir) continue;\n const subPath = join(rootPath, sub.name);\n try {\n const subEntries = await scanDir(subPath);\n groups.push({ path: subPath, entries: subEntries });\n } catch {\n // 无法读取子目录, 跳过这一层分组 (picker 会在点击时触发 dir_list_request 补齐)\n }\n }\n\n return groups;\n}\n\nexport function createControlMessageHandlers(\n send: (data: string) => void,\n sessionManager: SessionManager,\n): ControlMessageHandlers {\n const sessionResources = new Map<string, SessionResources>();\n\n function getResources(sessionId: string): SessionResources {\n let res = sessionResources.get(sessionId);\n if (!res) {\n res = {};\n sessionResources.set(sessionId, res);\n }\n return res;\n }\n\n function scheduleCommandRefresh(sessionId: string, workDir: string): void {\n const resources = getResources(sessionId);\n if (resources.commandRefreshTimer) {\n clearInterval(resources.commandRefreshTimer);\n }\n resources.commandRefreshTimer = setInterval(async () => {\n try {\n const commands = await discoverCommands(workDir);\n send(\n JSON.stringify({\n type: \"command_list_push\",\n commands,\n }),\n );\n serviceLogger.debug({ sessionId, count: commands.length }, \"Command list refreshed\");\n } catch (err) {\n serviceLogger.warn({ sessionId, error: String(err) }, \"Command refresh failed\");\n }\n }, COMMAND_REFRESH_MS);\n }\n\n return {\n async handleDirListRequest(msg: { path: string; requestId?: string }): Promise<void> {\n if (!isPathSafe(msg.path)) {\n send(\n JSON.stringify({\n type: \"dir_list_response\",\n requestId: msg.requestId,\n path: msg.path,\n entries: [],\n errorCode: ControlErrorCode.INVALID_PATH,\n error: \"Invalid path: must be absolute and must not contain path traversal\",\n }),\n );\n serviceLogger.warn({ path: msg.path }, \"Rejected dir_list_request: unsafe path\");\n return;\n }\n\n try {\n const entries = await scanDir(msg.path);\n send(\n JSON.stringify({\n type: \"dir_list_response\",\n requestId: msg.requestId,\n path: msg.path,\n entries,\n }),\n );\n serviceLogger.debug({ path: msg.path, count: entries.length }, \"Dir list response sent\");\n } catch (err) {\n send(\n JSON.stringify({\n type: \"dir_list_response\",\n requestId: msg.requestId,\n path: msg.path,\n entries: [],\n errorCode: classifyPathError(err),\n error: String(err),\n }),\n );\n serviceLogger.warn({ path: msg.path, error: String(err) }, \"Dir list request failed\");\n }\n },\n\n async handleDirCreateRequest(msg: { path: string; requestId?: string }): Promise<void> {\n if (!isPathSafe(msg.path)) {\n send(\n JSON.stringify({\n type: \"dir_create_response\",\n requestId: msg.requestId,\n path: msg.path,\n success: false,\n errorCode: ControlErrorCode.INVALID_PATH,\n error: \"Invalid path: must be absolute and must not contain path traversal\",\n }),\n );\n serviceLogger.warn({ path: msg.path }, \"Rejected dir_create_request: unsafe path\");\n return;\n }\n\n try {\n await mkdir(msg.path, { recursive: true });\n send(\n JSON.stringify({\n type: \"dir_create_response\",\n requestId: msg.requestId,\n path: msg.path,\n success: true,\n }),\n );\n serviceLogger.info({ path: msg.path }, \"Directory created\");\n } catch (err) {\n send(\n JSON.stringify({\n type: \"dir_create_response\",\n requestId: msg.requestId,\n path: msg.path,\n success: false,\n errorCode: classifyPathError(err),\n error: String(err),\n }),\n );\n serviceLogger.warn({ path: msg.path, error: String(err) }, \"Dir create failed\");\n }\n },\n\n async handleSessionHistoryRequest(msg: { requestId?: string }): Promise<void> {\n try {\n const sessions = await scanSessionHistory();\n send(\n JSON.stringify({\n type: \"session_history_response\",\n requestId: msg.requestId,\n sessions,\n }),\n );\n serviceLogger.debug({ count: sessions.length }, \"Session history response sent\");\n } catch (err) {\n send(\n JSON.stringify({\n type: \"session_history_response\",\n requestId: msg.requestId,\n sessions: [],\n }),\n );\n serviceLogger.warn({ error: String(err) }, \"Session history scan failed\");\n }\n },\n\n async handleSessionResourcesRequest(msg: {\n sessionId: string;\n requestId?: string;\n workDir: string;\n }): Promise<void> {\n getResources(msg.sessionId).fileTreeWorkDir = msg.workDir;\n scheduleCommandRefresh(msg.sessionId, msg.workDir);\n\n const [commandsResult, groupsResult] = await Promise.allSettled([\n discoverCommands(msg.workDir),\n getFileTree(msg.workDir),\n ]);\n const commands = commandsResult.status === \"fulfilled\" ? commandsResult.value : [];\n const groups = groupsResult.status === \"fulfilled\" ? groupsResult.value : [];\n const failedReason =\n commandsResult.status === \"rejected\"\n ? commandsResult.reason\n : groupsResult.status === \"rejected\"\n ? groupsResult.reason\n : undefined;\n\n send(\n JSON.stringify({\n type: \"session_resources_response\",\n requestId: msg.requestId,\n sessionId: msg.sessionId,\n commands,\n groups,\n ...(failedReason\n ? {\n errorCode: classifyPathError(failedReason),\n error: String(failedReason),\n }\n : {}),\n }),\n );\n serviceLogger.info(\n { sessionId: msg.sessionId, commandCount: commands.length, groupCount: groups.length },\n \"Session resources snapshot sent\",\n );\n },\n\n async pushCommandList(sessionId: string, workDir: string): Promise<void> {\n try {\n const commands = await discoverCommands(workDir);\n send(\n JSON.stringify({\n type: \"command_list_push\",\n commands,\n }),\n );\n serviceLogger.info({ sessionId, count: commands.length, workDir }, \"Command list pushed\");\n } catch (err) {\n serviceLogger.warn({ sessionId, error: String(err) }, \"Command discovery failed\");\n }\n\n // 6 小时定时刷新\n scheduleCommandRefresh(sessionId, workDir);\n },\n\n async pushFileTree(sessionId: string, workDir: string): Promise<void> {\n const resources = getResources(sessionId);\n resources.fileTreeWorkDir = workDir;\n\n try {\n const groups = await getFileTree(workDir);\n send(\n JSON.stringify({\n type: \"file_tree_push\",\n groups,\n }),\n );\n serviceLogger.debug(\n { sessionId, path: workDir, groupCount: groups.length },\n \"File tree pushed\",\n );\n } catch (err) {\n serviceLogger.warn({ sessionId, error: String(err) }, \"File tree push failed\");\n }\n },\n\n // relay 重连时同步 session 列表并重新推送控制数据\n async reinitializeOnReconnect(): Promise<void> {\n const activeSessions = sessionManager.listSessions().filter((s) => s.state !== \"terminated\");\n\n // 先同步 session 列表,relay 据此建立 proxy-session 关联\n if (activeSessions.length > 0) {\n send(\n JSON.stringify({\n type: \"session_sync\",\n sessions: activeSessions.map((s) => ({\n id: s.id,\n mode: s.mode,\n provider: s.provider,\n ...(s.ptyOwner !== undefined ? { ptyOwner: s.ptyOwner } : {}),\n state: s.state,\n })),\n }),\n );\n serviceLogger.info({ count: activeSessions.length }, \"Session list synced to relay\");\n }\n\n for (const session of activeSessions) {\n const resources = sessionResources.get(session.id);\n const workDir = resources?.fileTreeWorkDir;\n if (workDir) {\n try {\n const commands = await discoverCommands(workDir);\n send(\n JSON.stringify({\n type: \"command_list_push\",\n commands,\n }),\n );\n const groups = await getFileTree(workDir);\n send(\n JSON.stringify({\n type: \"file_tree_push\",\n groups,\n }),\n );\n serviceLogger.info(\n { sessionId: session.id },\n \"Reinitialized control data after reconnect\",\n );\n } catch (err) {\n serviceLogger.warn(\n { sessionId: session.id, error: String(err) },\n \"Reinitialize failed\",\n );\n }\n }\n }\n },\n\n cleanup(sessionId: string): void {\n const resources = sessionResources.get(sessionId);\n if (resources) {\n if (resources.commandRefreshTimer) {\n clearInterval(resources.commandRefreshTimer);\n }\n sessionResources.delete(sessionId);\n }\n },\n };\n}\n","import { readdir, stat, access, open } from \"node:fs/promises\";\nimport { createReadStream } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createInterface } from \"node:readline\";\n\ninterface SessionHistoryEntry {\n id: string;\n title: string;\n projectDir: string;\n updatedAt: number;\n provider: \"claude\" | \"codex\";\n}\n\nconst claudeProjectsDir = (): string => join(homedir(), \".claude\", \"projects\");\nconst codexSessionsDir = (): string => join(homedir(), \".codex\", \"sessions\");\nconst UNTITLED_SESSION_TITLE = \"未命名会话\";\nconst MAX_HISTORY_TITLE_LENGTH = 40;\nconst IGNORED_SLASH_COMMANDS = new Set([\n \"/clear\",\n \"/model\",\n \"/compact\",\n \"/help\",\n \"/config\",\n \"/logout\",\n]);\nconst XMLISH_NOISE_PREFIXES = [\n \"environment\",\n \"system\",\n \"developer\",\n \"assistant\",\n \"user\",\n \"tool\",\n \"context\",\n];\nconst INTERNAL_TITLE_PATTERNS = [\n /^the following is the codex agent history\\b/i,\n /^codex agent history\\b/i,\n /^conversation summary\\b/i,\n];\n\n// 扫描 ~/.claude/projects/ 获取 Claude Code 会话历史\n// 实际目录结构: ~/.claude/projects/<encoded-project-path>/<session-id>.jsonl\nexport async function scanSessionHistory(): Promise<SessionHistoryEntry[]> {\n const entries = [...(await scanClaudeSessionHistory()), ...(await scanCodexSessionHistory())];\n entries.sort((a, b) => b.updatedAt - a.updatedAt);\n // 按 provider + title + projectDir 去重,resume 产生的多个 session 只保留最新的\n const seen = new Set<string>();\n return entries.filter((e) => {\n const key = `${e.provider}::${e.projectDir}::${e.title}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nasync function scanClaudeSessionHistory(): Promise<SessionHistoryEntry[]> {\n const entries: SessionHistoryEntry[] = [];\n let projectDirs: string[];\n try {\n projectDirs = await readdir(claudeProjectsDir());\n } catch {\n return [];\n }\n\n for (const encodedDir of projectDirs) {\n const projectPath = join(claudeProjectsDir(), encodedDir);\n\n let files: string[];\n try {\n files = await readdir(projectPath);\n } catch {\n continue;\n }\n\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const filePath = join(projectPath, file);\n try {\n const fileStat = await stat(filePath);\n const sessionId = file.replace(/\\.jsonl$/, \"\");\n const { title, cwd } = await extractTitleAndCwd(filePath);\n\n entries.push({\n id: sessionId,\n title: title || UNTITLED_SESSION_TITLE,\n projectDir: cwd || \"/\" + encodedDir.replace(/^-/, \"\").split(\"-\").join(\"/\"),\n updatedAt: fileStat.mtimeMs,\n provider: \"claude\",\n });\n } catch {\n continue;\n }\n }\n }\n\n return entries;\n}\n\nasync function scanCodexSessionHistory(): Promise<SessionHistoryEntry[]> {\n const files = await collectJsonlFiles(codexSessionsDir());\n const entries: SessionHistoryEntry[] = [];\n for (const filePath of files) {\n try {\n const fileStat = await stat(filePath);\n const meta = await extractCodexTitleAndCwd(filePath);\n if (!meta.id) continue;\n entries.push({\n id: meta.id,\n title: meta.title || UNTITLED_SESSION_TITLE,\n projectDir: meta.cwd || homedir(),\n updatedAt: fileStat.mtimeMs,\n provider: \"codex\",\n });\n } catch {\n continue;\n }\n }\n return entries;\n}\n\ninterface SessionMessage {\n role: \"user\" | \"assistant\";\n text: string;\n timestamp?: number;\n cursor?: string;\n}\n\ninterface SessionMessagesPage {\n messages: SessionMessage[];\n hasMore: boolean;\n nextBefore?: string;\n}\n\ninterface SessionMessagesPageOptions {\n limit?: number;\n before?: string;\n}\n\nconst DEFAULT_HISTORY_PAGE_LIMIT = 50;\nconst MAX_HISTORY_PAGE_LIMIT = 200;\nconst HISTORY_READ_CHUNK_BYTES = 64 * 1024;\nconst HISTORY_CURSOR_PREFIX = \"b:\";\n\nfunction normalizeHistoryPageLimit(limit: unknown): number {\n if (typeof limit !== \"number\" || !Number.isFinite(limit)) return DEFAULT_HISTORY_PAGE_LIMIT;\n return Math.max(1, Math.min(MAX_HISTORY_PAGE_LIMIT, Math.floor(limit)));\n}\n\nfunction encodeHistoryCursor(offset: number): string {\n return `${HISTORY_CURSOR_PREFIX}${Math.max(0, Math.floor(offset))}`;\n}\n\nfunction decodeHistoryCursor(cursor: string | undefined, fileSize: number): number {\n if (!cursor) return fileSize;\n const raw = cursor.startsWith(HISTORY_CURSOR_PREFIX)\n ? cursor.slice(HISTORY_CURSOR_PREFIX.length)\n : cursor;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || parsed < 0) return fileSize;\n return Math.min(parsed, fileSize);\n}\n\nasync function findClaudeSessionFile(claudeSessionId: string): Promise<string | null> {\n let projectDirs: string[];\n try {\n projectDirs = await readdir(claudeProjectsDir());\n } catch {\n return null;\n }\n\n for (const encodedDir of projectDirs) {\n const filePath = join(claudeProjectsDir(), encodedDir, `${claudeSessionId}.jsonl`);\n try {\n await access(filePath);\n return filePath;\n } catch {\n continue;\n }\n }\n\n return null;\n}\n\nfunction extractConversationMessageFromJson(obj: unknown): Omit<SessionMessage, \"cursor\"> | null {\n if (!obj || typeof obj !== \"object\") return null;\n const record = obj as {\n type?: unknown;\n isMeta?: unknown;\n message?: unknown;\n timestamp?: unknown;\n };\n if (record.type === \"user\") {\n if (record.isMeta) return null;\n const text = extractConversationText(record.message);\n if (!text) return null;\n const ts =\n typeof record.timestamp === \"string\" ? new Date(record.timestamp).getTime() : undefined;\n return { role: \"user\", text, timestamp: ts };\n }\n if (record.type === \"assistant\") {\n const text = extractConversationText(record.message);\n if (!text) return null;\n const ts =\n typeof record.timestamp === \"string\" ? new Date(record.timestamp).getTime() : undefined;\n return { role: \"assistant\", text, timestamp: ts };\n }\n return null;\n}\n\nfunction splitLineSegments(\n block: Buffer,\n blockStart: number,\n): Array<{ start: number; line: Buffer }> {\n const segments: Array<{ start: number; line: Buffer }> = [];\n let start = 0;\n for (let i = 0; i < block.length; i += 1) {\n if (block[i] !== 10) continue;\n segments.push({ start: blockStart + start, line: block.subarray(start, i) });\n start = i + 1;\n }\n segments.push({ start: blockStart + start, line: block.subarray(start) });\n return segments;\n}\n\nfunction stripCarriageReturn(line: Buffer): Buffer {\n return line.length > 0 && line[line.length - 1] === 13 ? line.subarray(0, -1) : line;\n}\n\nasync function readSessionMessagesPageFromFile(\n filePath: string,\n options: SessionMessagesPageOptions = {},\n): Promise<SessionMessagesPage> {\n const limit = normalizeHistoryPageLimit(options.limit);\n const file = await open(filePath, \"r\");\n try {\n const fileStat = await file.stat();\n const endOffset = decodeHistoryCursor(options.before, fileStat.size);\n if (endOffset <= 0) return { messages: [], hasMore: false };\n\n let position = endOffset;\n let carry: Buffer = Buffer.alloc(0);\n const collected: SessionMessage[] = [];\n\n while (position > 0 && collected.length <= limit) {\n const readSize = Math.min(HISTORY_READ_CHUNK_BYTES, position);\n position -= readSize;\n const chunk = Buffer.alloc(readSize);\n await file.read(chunk, 0, readSize, position);\n\n const block = carry.length > 0 ? Buffer.concat([chunk, carry]) : chunk;\n const segments = splitLineSegments(block, position);\n const firstCompleteIndex = position > 0 ? 1 : 0;\n carry = position > 0 ? (segments[0]?.line ?? Buffer.alloc(0)) : Buffer.alloc(0);\n\n for (let i = segments.length - 1; i >= firstCompleteIndex; i -= 1) {\n const segment = segments[i];\n if (!segment) continue;\n const line = stripCarriageReturn(segment.line);\n if (line.length === 0) continue;\n try {\n const parsed = JSON.parse(line.toString(\"utf-8\"));\n const message = extractConversationMessageFromJson(parsed);\n if (!message) continue;\n collected.push({ ...message, cursor: encodeHistoryCursor(segment.start) });\n if (collected.length > limit) break;\n } catch {\n /* skip malformed lines */\n }\n }\n }\n\n const page = collected.slice(0, limit).reverse();\n const hasMore = collected.length > limit;\n return {\n messages: page,\n hasMore,\n ...(hasMore && page[0]?.cursor ? { nextBefore: page[0].cursor } : {}),\n };\n } finally {\n await file.close();\n }\n}\n\n// 从 JSONL 文件中提取 user/assistant 对话消息用于恢复时展示历史\nexport async function readSessionMessages(claudeSessionId: string): Promise<SessionMessage[]> {\n const filePath = await findClaudeSessionFile(claudeSessionId);\n if (!filePath) return [];\n\n const messages: SessionMessage[] = [];\n return new Promise((resolve) => {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n\n rl.on(\"line\", (line) => {\n if (!line.trim()) return;\n try {\n const message = extractConversationMessageFromJson(JSON.parse(line));\n if (message) messages.push(message);\n } catch {\n /* skip */\n }\n });\n\n rl.on(\"close\", () => resolve(messages));\n rl.on(\"error\", () => resolve(messages));\n });\n}\n\nexport async function readSessionMessagesPage(\n claudeSessionId: string,\n options: SessionMessagesPageOptions = {},\n): Promise<SessionMessagesPage> {\n const filePath = await findClaudeSessionFile(claudeSessionId);\n if (!filePath) return { messages: [], hasMore: false };\n return readSessionMessagesPageFromFile(filePath, options);\n}\n\n// 从 message 字段提取文本,统一处理多种格式\nfunction collapseWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\nfunction truncateTitle(text: string): string {\n const chars = Array.from(text);\n return chars.length > MAX_HISTORY_TITLE_LENGTH\n ? `${chars.slice(0, MAX_HISTORY_TITLE_LENGTH).join(\"\")}...`\n : text;\n}\n\nfunction isXmlishNoise(text: string): boolean {\n const match = text.match(/^<([A-Za-z][\\w:-]*)\\b/);\n if (!match) return false;\n const tag = match[1].toLowerCase();\n return XMLISH_NOISE_PREFIXES.some((prefix) => tag === prefix || tag.startsWith(`${prefix}_`));\n}\n\nexport function normalizeHistoryTitle(raw: string | null | undefined): string | null {\n if (!raw) return null;\n const text = collapseWhitespace(raw);\n if (text.length < 2) return null;\n if (text.startsWith(\"<\") || isXmlishNoise(text)) return null;\n if (INTERNAL_TITLE_PATTERNS.some((pattern) => pattern.test(text))) return null;\n\n const slashCommand = text.match(/^\\/\\S+/)?.[0];\n if (slashCommand && IGNORED_SLASH_COMMANDS.has(slashCommand)) return null;\n\n return truncateTitle(text);\n}\n\nfunction extractSlashCommand(text: string): string | null {\n const nameMatch = text.match(/<command-name>([^<]+)<\\/command-name>/);\n if (!nameMatch) return null;\n const argsMatch = text.match(/<command-args>([^<]+)<\\/command-args>/);\n const args = argsMatch ? argsMatch[1].trim() : \"\";\n return normalizeHistoryTitle(args ? `${nameMatch[1]} ${args}` : nameMatch[1]);\n}\n\nfunction extractMessageText(msg: unknown): string | null {\n if (typeof msg === \"string\") {\n const cmd = extractSlashCommand(msg);\n if (cmd) return cmd;\n return normalizeHistoryTitle(msg);\n }\n\n if (msg && typeof msg === \"object\" && \"content\" in msg) {\n const content = (msg as { content: unknown }).content;\n if (typeof content === \"string\") {\n const cmd = extractSlashCommand(content);\n if (cmd) return cmd;\n return normalizeHistoryTitle(content);\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter(\n (b: { type?: string; text?: string }) => b.type === \"text\" && typeof b.text === \"string\",\n )\n .map((b: { text: string }) => b.text);\n const joined = texts.join(\"\\n\").trim();\n return normalizeHistoryTitle(joined);\n }\n }\n\n if (Array.isArray(msg)) {\n const texts = msg\n .filter(\n (b: { type?: string; text?: string }) => b.type === \"text\" && typeof b.text === \"string\",\n )\n .map((b: { text: string }) => b.text);\n const joined = texts.join(\"\\n\").trim();\n return normalizeHistoryTitle(joined);\n }\n\n return null;\n}\n\nfunction normalizeConversationText(text: string): string | null {\n const trimmed = text.trim();\n if (!trimmed) return null;\n return trimmed;\n}\n\n// 对话正文恢复必须保留换行和 Markdown 结构;不能复用标题归一化逻辑。\nfunction extractConversationText(msg: unknown): string | null {\n if (typeof msg === \"string\") {\n const cmd = extractSlashCommand(msg);\n if (cmd) return cmd;\n return normalizeConversationText(msg);\n }\n\n if (msg && typeof msg === \"object\" && \"content\" in msg) {\n const content = (msg as { content: unknown }).content;\n if (typeof content === \"string\") {\n const cmd = extractSlashCommand(content);\n if (cmd) return cmd;\n return normalizeConversationText(content);\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter(\n (b: { type?: string; text?: string }) => b.type === \"text\" && typeof b.text === \"string\",\n )\n .map((b: { text: string }) => b.text);\n return normalizeConversationText(texts.join(\"\\n\"));\n }\n }\n\n if (Array.isArray(msg)) {\n const texts = msg\n .filter(\n (b: { type?: string; text?: string }) => b.type === \"text\" && typeof b.text === \"string\",\n )\n .map((b: { text: string }) => b.text);\n return normalizeConversationText(texts.join(\"\\n\"));\n }\n\n return null;\n}\n\n// 从 JSONL 文件头部提取 cwd 和第一条有效用户文本消息作为标题\n// cwd 从任意行的 cwd 字段获取,title 从第一条 user 消息获取\nasync function extractTitleAndCwd(\n filePath: string,\n): Promise<{ title: string | null; cwd: string | null }> {\n return new Promise((resolve) => {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n let resolved = false;\n let cwd: string | null = null;\n let title: string | null = null;\n\n rl.on(\"line\", (line) => {\n if (resolved) return;\n if (!line.trim()) return;\n\n try {\n const obj = JSON.parse(line);\n if (!cwd && typeof obj.cwd === \"string\") {\n cwd = obj.cwd;\n }\n if (!title && obj.type === \"user\" && !obj.isMeta) {\n const text = extractMessageText(obj.message);\n if (text) title = text;\n }\n if (cwd && title) {\n resolved = true;\n rl.close();\n }\n } catch {\n /* skip malformed lines */\n }\n });\n\n rl.on(\"close\", () => {\n if (!resolved) resolve({ title, cwd });\n else resolve({ title, cwd });\n });\n rl.on(\"error\", () => resolve({ title, cwd }));\n });\n}\n\nasync function collectJsonlFiles(root: string): Promise<string[]> {\n let entries: Array<{ name: string; isDirectory(): boolean; isFile(): boolean }>;\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n return [];\n }\n\n const files: string[] = [];\n for (const entry of entries) {\n const child = join(root, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await collectJsonlFiles(child)));\n } else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n files.push(child);\n }\n }\n return files;\n}\n\nasync function extractCodexTitleAndCwd(\n filePath: string,\n): Promise<{ id: string | null; title: string | null; cwd: string | null }> {\n return new Promise((resolve) => {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n let id: string | null = null;\n let cwd: string | null = null;\n let title: string | null = null;\n\n rl.on(\"line\", (line) => {\n if (!line.trim()) return;\n try {\n const obj = JSON.parse(line);\n if (obj.type === \"session_meta\" && obj.payload) {\n if (!id && typeof obj.payload.id === \"string\") id = obj.payload.id;\n if (!cwd && typeof obj.payload.cwd === \"string\") cwd = obj.payload.cwd;\n }\n if (!title && obj.type === \"response_item\") {\n const text = extractCodexUserText(obj.payload);\n if (text) title = text;\n }\n if (id && cwd && title) rl.close();\n } catch {\n /* skip malformed lines */\n }\n });\n\n rl.on(\"close\", () => resolve({ id, title, cwd }));\n rl.on(\"error\", () => resolve({ id, title, cwd }));\n });\n}\n\nfunction extractCodexUserText(payload: unknown): string | null {\n if (!payload || typeof payload !== \"object\") return null;\n const item = payload as { type?: unknown; role?: unknown; content?: unknown };\n if (item.type !== \"message\" || item.role !== \"user\") return null;\n if (typeof item.content === \"string\") return normalizeHistoryTitle(item.content);\n if (!Array.isArray(item.content)) return null;\n const texts = item.content\n .map((block: unknown) => {\n if (!block || typeof block !== \"object\") return \"\";\n const typed = block as { type?: unknown; text?: unknown };\n return typed.type === \"input_text\" && typeof typed.text === \"string\" ? typed.text : \"\";\n })\n .filter(Boolean);\n const joined = texts.join(\"\\n\").trim();\n return normalizeHistoryTitle(joined);\n}\n","import { readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\ninterface CommandEntry {\n name: string;\n description: string;\n argumentHint?: string;\n source: string;\n}\n\nconst REPL_BUILTINS: CommandEntry[] = [\n { name: \"/compact\", description: \"Compact conversation history\", source: \"builtin\" },\n { name: \"/status\", description: \"Show session status\", source: \"builtin\" },\n { name: \"/cost\", description: \"Show token usage and cost\", source: \"builtin\" },\n { name: \"/clear\", description: \"Clear conversation history\", source: \"builtin\" },\n {\n name: \"/model\",\n description: \"Switch AI model\",\n argumentHint: \"model name (e.g., Haiku, Sonnet)\",\n source: \"builtin\",\n },\n { name: \"/help\", description: \"Show available commands\", source: \"builtin\" },\n { name: \"/memory\", description: \"Edit CLAUDE.md memory\", source: \"builtin\" },\n { name: \"/review\", description: \"Review diff of changes\", source: \"builtin\" },\n { name: \"/vim\", description: \"Enter vim mode\", source: \"builtin\" },\n { name: \"/terminal-setup\", description: \"Configure terminal integration\", source: \"builtin\" },\n { name: \"/permissions\", description: \"View and manage permissions\", source: \"builtin\" },\n { name: \"/allowed-tools\", description: \"View allowed tools\", source: \"builtin\" },\n {\n name: \"/add-dir\",\n description: \"Add working directory\",\n argumentHint: \"directory path\",\n source: \"builtin\",\n },\n { name: \"/init\", description: \"Initialize CLAUDE.md in project\", source: \"builtin\" },\n { name: \"/listen\", description: \"Listen for multi-turn responses\", source: \"builtin\" },\n { name: \"/pr-comments\", description: \"View PR comments\", source: \"builtin\" },\n { name: \"/release-notes\", description: \"Generate release notes\", source: \"builtin\" },\n { name: \"/ide\", description: \"Open IDE integration\", source: \"builtin\" },\n];\n\nconst COMMAND_BLACKLIST = new Set([\n \"/login\",\n \"/logout\",\n \"/config\",\n \"/plugin\",\n \"/mcp\",\n \"/install\",\n \"/setup-token\",\n \"/doctor\",\n \"/update\",\n \"/upgrade\",\n \"/memory\",\n \"/vim\",\n \"/terminal-setup\",\n \"/permissions\",\n \"/allowed-tools\",\n \"/ide\",\n \"/listen\",\n]);\n\ninterface DiscoverOptions {\n homeDir?: string;\n}\n\n/**\n * 从 SKILL.md 内容中解析 YAML frontmatter 的 name/description/argument-hint\n */\nexport function parseSkillFrontmatter(content: string): {\n name?: string;\n description?: string;\n argumentHint?: string;\n} {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/);\n if (!match) return {};\n\n const yaml = match[1];\n const result: { name?: string; description?: string; argumentHint?: string } = {};\n\n const nameMatch = yaml.match(/^name:\\s*(.+)$/m);\n if (nameMatch) result.name = nameMatch[1].trim();\n\n const descMatch = yaml.match(/^description:\\s*(.+)$/m);\n if (descMatch) result.description = descMatch[1].trim();\n\n const hintMatch = yaml.match(/^argument-hint:\\s*(.+)$/m);\n if (hintMatch) result.argumentHint = hintMatch[1].trim();\n\n return result;\n}\n\n/**\n * 扫描 skills 目录,每个子目录下的 SKILL.md 解析为一条命令\n */\nfunction scanSkillsDir(dirPath: string, source: string): CommandEntry[] {\n let entries: string[];\n try {\n entries = readdirSync(dirPath, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n return [];\n }\n\n const commands: CommandEntry[] = [];\n for (const name of entries) {\n const skillPath = join(dirPath, name, \"SKILL.md\");\n try {\n const content = readFileSync(skillPath, \"utf-8\");\n const parsed = parseSkillFrontmatter(content);\n commands.push({\n name: `/${parsed.name ?? name}`,\n description: parsed.description ?? \"\",\n argumentHint: parsed.argumentHint,\n source,\n });\n } catch {\n // SKILL.md 不存在或不可读,跳过\n }\n }\n return commands;\n}\n\n/**\n * 扫描 commands 目录,每个 .md 文件名即为命令名\n */\nfunction scanCommandsDir(dirPath: string, source: string): CommandEntry[] {\n let entries: string[];\n try {\n entries = readdirSync(dirPath).filter((f) => f.endsWith(\".md\"));\n } catch {\n return [];\n }\n\n const commands: CommandEntry[] = [];\n for (const filename of entries) {\n const cmdName = filename.replace(/\\.md$/, \"\");\n try {\n const content = readFileSync(join(dirPath, filename), \"utf-8\");\n const firstLine = content.split(\"\\n\")[0].trim();\n commands.push({\n name: `/${cmdName}`,\n description: firstLine,\n source,\n });\n } catch {\n commands.push({\n name: `/${cmdName}`,\n description: \"\",\n source,\n });\n }\n }\n return commands;\n}\n\n/**\n * 扫描插件目录中的 skills 和 commands 子目录\n */\nfunction scanPluginDirs(homeDir: string): CommandEntry[] {\n const pluginCacheDir = join(homeDir, \".claude\", \"plugins\", \"cache\");\n let pluginNames: string[];\n try {\n pluginNames = readdirSync(pluginCacheDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n return [];\n }\n\n const commands: CommandEntry[] = [];\n for (const pluginName of pluginNames) {\n const pluginDir = join(pluginCacheDir, pluginName);\n const skillCmds = scanSkillsDir(join(pluginDir, \"skills\"), \"plugin-skill\");\n const cmdCmds = scanCommandsDir(join(pluginDir, \"commands\"), \"plugin-command\");\n commands.push(...skillCmds, ...cmdCmds);\n }\n return commands;\n}\n\n/**\n * 发现所有可用的斜杠命令,合并多个来源并过滤黑名单\n *\n * 来源优先级: project > user > plugin > builtin\n * 同名命令按优先级高的保留\n */\nexport async function discoverCommands(\n workDir: string,\n options?: DiscoverOptions,\n): Promise<CommandEntry[]> {\n const homeDir = options?.homeDir ?? homedir();\n\n const builtins = REPL_BUILTINS.filter((c) => !COMMAND_BLACKLIST.has(c.name));\n const userSkills = scanSkillsDir(join(homeDir, \".claude\", \"skills\"), \"user-skill\");\n const projectSkills = scanSkillsDir(join(workDir, \".claude\", \"skills\"), \"project-skill\");\n const userCommands = scanCommandsDir(join(homeDir, \".claude\", \"commands\"), \"user-command\");\n const projectCommands = scanCommandsDir(join(workDir, \".claude\", \"commands\"), \"project-command\");\n const pluginCommands = scanPluginDirs(homeDir);\n\n // 按优先级从低到高合并,同名命令后者覆盖前者\n const commandMap = new Map<string, CommandEntry>();\n for (const cmd of builtins) commandMap.set(cmd.name, cmd);\n for (const cmd of pluginCommands) commandMap.set(cmd.name, cmd);\n for (const cmd of userSkills) commandMap.set(cmd.name, cmd);\n for (const cmd of userCommands) commandMap.set(cmd.name, cmd);\n for (const cmd of projectSkills) commandMap.set(cmd.name, cmd);\n for (const cmd of projectCommands) commandMap.set(cmd.name, cmd);\n\n // 再次过滤黑名单,防止外部来源引入黑名单命令\n const result: CommandEntry[] = [];\n for (const cmd of commandMap.values()) {\n if (!COMMAND_BLACKLIST.has(cmd.name)) {\n result.push(cmd);\n }\n }\n\n return result;\n}\n","import { ControlErrorCode } from \"@dev-anywhere/shared\";\n\nfunction getFsErrorCode(err: unknown): string | undefined {\n return typeof err === \"object\" && err !== null && \"code\" in err\n ? String((err as { code?: unknown }).code)\n : undefined;\n}\n\nexport function classifyPathError(err: unknown): ControlErrorCode {\n switch (getFsErrorCode(err)) {\n case \"ENOENT\":\n return ControlErrorCode.PATH_NOT_FOUND;\n case \"ENOTDIR\":\n return ControlErrorCode.PATH_NOT_DIRECTORY;\n case \"EACCES\":\n case \"EPERM\":\n return ControlErrorCode.PATH_ACCESS_DENIED;\n default:\n return ControlErrorCode.UNKNOWN;\n }\n}\n","import { connect, type Socket } from \"node:net\";\nimport { unlinkSync, existsSync, readdirSync } from \"node:fs\";\nimport type { ChildProcess } from \"node:child_process\";\nimport { buildMessage } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport {\n ContentBlockDeltaSchema,\n IGNORED_EVENT_TYPES,\n KnownContentBlockSchema,\n StreamJsonEventSchema,\n} from \"../common/stream-json-schema.js\";\nimport { DATA_DIR, sessionPaths } from \"../common/paths.js\";\nimport { spawnScript } from \"../common/env.js\";\nimport { SeqCounter } from \"../common/seq-counter.js\";\nimport { createWorkerReader, serializeWorkerMsg, type WorkerMessage } from \"../ipc/ipc-protocol.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { JsonObserver } from \"./json-observer.js\";\nimport type { ProviderHookContext } from \"../providers/index.js\";\nimport type { PermissionBroker, PermissionDecision } from \"./permission-broker.js\";\n\ninterface WorkerRegistryDeps {\n sessionManager: SessionManager;\n permissionBroker: PermissionBroker;\n relayConnection: RelayConnection;\n // JSON 观察通道状态机;forwardEvent / forwardApprovalRequest 据此推状态变迁\n jsonObserver: JsonObserver;\n touchSessionActivity?: (sessionId: string) => boolean;\n getProviderEnv: () => NodeJS.ProcessEnv;\n nextSeq?: (sessionId: string) => number;\n}\n\ninterface SpawnOptions {\n cwd?: string;\n resumeSessionId?: string;\n permissionMode?: string;\n // 开启后 worker spawn claude 带 --include-partial-messages,forwardEvent 处理 stream_event delta;\n // aggregated assistant 的 text/thinking 会被跳过避免和 delta 重复\n streamDelta?: boolean;\n hook?: ProviderHookContext;\n}\n\n// 管理 session → worker socket 的映射,封装全部 worker IO:\n// - spawn / connect / reconnectAll / destroyAll 生命周期入口\n// - send(sessionId, msg) 统一出口\n// - worker_event 路由、worker_approval_request 转发、worker_exit 清理都在内部闭环\nexport class WorkerRegistry {\n private sockets = new Map<string, Socket>();\n private children = new Map<string, ChildProcess>();\n // 记录哪些 session 是 spawn 时带 --stream-delta 的;forwardEvent 据此决定是否跳过 aggregated 去重\n private streamDeltaSessions = new Set<string>();\n\n constructor(private deps: WorkerRegistryDeps) {\n // relay queue 溢出时,被 drop 的 envelope 不会到达 client;若是 tool_use_request,\n // 主动清 pending 审批并回 worker env-failure deny,避免 worker 永挂、permission broker 泄漏。\n deps.relayConnection.on(\"envelope_dropped\", (raw: string) => this.onEnvelopeDropped(raw));\n }\n\n private onEnvelopeDropped(raw: string): void {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return;\n }\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n (parsed as { type?: unknown }).type !== \"tool_use_request\"\n ) {\n return;\n }\n const envelope = parsed as {\n sessionId?: unknown;\n payload?: { toolId?: unknown };\n };\n const sessionId = typeof envelope.sessionId === \"string\" ? envelope.sessionId : null;\n const requestId =\n envelope.payload && typeof envelope.payload.toolId === \"string\"\n ? envelope.payload.toolId\n : null;\n if (!sessionId || !requestId) return;\n if (\n !this.deps.permissionBroker.resolve(requestId, {\n behavior: \"deny\",\n message: \"Approval request was dropped due to relay queue overflow.\",\n })\n ) {\n return;\n }\n\n serviceLogger.warn(\n { sessionId, requestId },\n \"Tool approval request lost to relay queue overflow, denying worker\",\n );\n }\n\n spawn(sessionId: string, options?: SpawnOptions): number {\n const paths = sessionPaths(sessionId);\n const args: string[] = [sessionId, paths.workerSock];\n if (options?.cwd) args.push(\"--cwd\", options.cwd);\n if (options?.resumeSessionId) args.push(\"--resume\", options.resumeSessionId);\n // 远程场景默认 default,每个工具都需审批,覆盖用户全局 claude settings 的 defaultMode\n args.push(\"--permission-mode\", options?.permissionMode ?? \"default\");\n if (options?.streamDelta) {\n args.push(\"--stream-delta\");\n this.streamDeltaSessions.add(sessionId);\n }\n if (options?.hook) {\n args.push(\n \"--hook-provider\",\n options.hook.provider,\n \"--hook-url\",\n options.hook.hookUrl,\n \"--hook-marker\",\n options.hook.marker,\n );\n }\n args.push(\"--\");\n\n const providerEnv = this.deps.getProviderEnv();\n const child = spawnScript(new URL(\"../session-worker\", import.meta.url), args, {\n logger: serviceLogger,\n env: options?.hook\n ? { ...providerEnv, DEV_ANYWHERE_HOOK_TOKEN: options.hook.token }\n : providerEnv,\n });\n const workerPid = child.pid!;\n this.children.set(sessionId, child);\n serviceLogger.info(\n { sessionId, workerPid, cwd: options?.cwd, resume: options?.resumeSessionId },\n \"Worker process spawned\",\n );\n return workerPid;\n }\n\n connect(sessionId: string, sockPath: string): Promise<Socket | null> {\n return new Promise((resolve) => {\n const sock = connect(sockPath);\n sock.on(\"connect\", () => {\n this.sockets.set(sessionId, sock);\n createWorkerReader(sock, (msg) => this.handleWorkerMessage(sessionId, msg));\n sock.on(\"close\", () => this.onDisconnect(sessionId));\n sock.on(\"error\", () => this.onDisconnect(sessionId));\n resolve(sock);\n });\n sock.on(\"error\", () => resolve(null));\n });\n }\n\n // 枚举 DATA_DIR 下所有 session 目录,尝试连接存活的 worker.sock;失败则清理 stale socket。\n async reconnectAll(): Promise<void> {\n if (!existsSync(DATA_DIR)) return;\n\n const dirs = readdirSync(DATA_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());\n\n for (const dir of dirs) {\n const sessionId = dir.name;\n const paths = sessionPaths(sessionId);\n if (!existsSync(paths.workerSock)) continue;\n\n const sock = await this.connect(sessionId, paths.workerSock);\n if (sock) {\n if (!this.deps.sessionManager.getSession(sessionId)) {\n // 两边数据源不一致:DATA_DIR 下的 worker.sock 能连通说明 worker 进程还在跑,\n // 但 SessionManager 的内存 Map(持久化已在 load 时清过)里没这条 session。\n // 成因:sessions.json 被删 / 写盘失败 / 记录丢失而 worker 没跟着退。这类孤儿 worker 清掉。\n serviceLogger.warn(\n { sessionId },\n \"Orphaned worker found without session data, terminating\",\n );\n sock.end();\n this.sockets.delete(sessionId);\n continue;\n }\n serviceLogger.info({ sessionId }, \"Reconnected to existing worker\");\n } else {\n try {\n unlinkSync(paths.workerSock);\n } catch {\n // socket 文件可能已被删除\n }\n serviceLogger.info({ sessionId }, \"Cleaned up stale worker socket\");\n }\n }\n }\n\n has(sessionId: string): boolean {\n return this.sockets.has(sessionId);\n }\n\n delete(sessionId: string): void {\n this.children.delete(sessionId);\n this.sockets.delete(sessionId);\n this.streamDeltaSessions.delete(sessionId);\n }\n\n terminateProcess(sessionId: string, signal: NodeJS.Signals = \"SIGTERM\"): boolean {\n const child = this.children.get(sessionId);\n const sock = this.sockets.get(sessionId);\n sock?.destroy();\n this.sockets.delete(sessionId);\n this.streamDeltaSessions.delete(sessionId);\n this.children.delete(sessionId);\n if (!child || child.killed) return false;\n return child.kill(signal);\n }\n\n // 向指定 session 的 worker 写 WorkerMessage;socket 缺失或不可写返回 false 由 caller 决定日志。\n send(sessionId: string, msg: WorkerMessage): boolean {\n const sock = this.sockets.get(sessionId);\n if (!sock?.writable) return false;\n sock.write(serializeWorkerMsg(msg));\n return true;\n }\n\n destroyAll(): void {\n for (const [, ws] of this.sockets) {\n ws.destroy();\n }\n this.sockets.clear();\n }\n\n private handleWorkerMessage(sessionId: string, msg: WorkerMessage): void {\n switch (msg.type) {\n case \"worker_ready\":\n serviceLogger.info({ sessionId, pid: msg.pid }, \"Worker ready\");\n break;\n\n case \"worker_event\":\n try {\n this.forwardEvent(sessionId, msg.seq, msg.event);\n } catch (err) {\n serviceLogger.debug(\n { sessionId, error: String(err) },\n \"Failed to forward event to relay\",\n );\n }\n serviceLogger.debug({ sessionId, eventType: msg.event.type }, \"JSON session event\");\n break;\n\n case \"worker_exit\":\n this.deps.sessionManager.terminateSession(sessionId);\n this.delete(sessionId);\n serviceLogger.info({ sessionId, exitCode: msg.code }, \"JSON session exited\");\n break;\n\n case \"worker_approval_request\":\n this.forwardApprovalRequest(sessionId, msg);\n break;\n\n case \"worker_claude_session_id\":\n this.deps.sessionManager.setClaudeSessionId(sessionId, msg.sessionId);\n serviceLogger.info(\n { sessionId, claudeSessionId: msg.sessionId },\n \"Claude session ID captured\",\n );\n break;\n }\n }\n\n // worker 连接断开或异常时的统一清理入口。仅记录一份,不再区分 close vs error 语义。\n private onDisconnect(sessionId: string): void {\n this.sockets.delete(sessionId);\n this.deps.permissionBroker.cleanupSession(sessionId, \"Worker disconnected\");\n }\n\n // 对齐 Claude CLI stream-json 输出,按 type 分发:\n // stream_event.content_block_delta → 增量 text/thinking envelope(仅 streamDelta 会话产生)\n // assistant.content[].text → assistant_message envelope(streamDelta 下跳过,避免重复)\n // assistant.content[].thinking → thinking envelope(streamDelta 下跳过)\n // assistant.content[].tool_use → assistant_tool_use envelope\n // user.content[].tool_result → tool_result envelope\n // result → turn_result control + 会话状态回 IDLE\n // system/rate_limit_event/其他 → 静默忽略\n // schema 未识别的 event/block 以 warn 暴露,作为 Claude CLI 协议变化的 runtime canary。\n private forwardEvent(sessionId: string, seq: number, event: Record<string, unknown>): void {\n const relay = this.deps.relayConnection;\n const parsed = StreamJsonEventSchema.safeParse(event);\n if (!parsed.success) {\n const rawType = typeof event.type === \"string\" ? event.type : \"<missing>\";\n if (IGNORED_EVENT_TYPES.has(rawType)) {\n serviceLogger.debug({ sessionId, type: rawType }, \"Dropped ignored stream-json event\");\n return;\n }\n serviceLogger.warn(\n { sessionId, type: rawType, issues: parsed.error.issues.slice(0, 3) },\n \"Unknown stream-json event type; Claude CLI schema may have changed\",\n );\n return;\n }\n const ev = parsed.data;\n this.deps.touchSessionActivity?.(sessionId);\n const isStreamDeltaSession = this.streamDeltaSessions.has(sessionId);\n\n if (ev.type === \"stream_event\") {\n const delta = ContentBlockDeltaSchema.safeParse(ev.event);\n if (!delta.success) return; // 非 content_block_delta 的内层事件(message_start 等)忽略\n const d = delta.data.delta;\n if (d.type === \"text_delta\" && d.text) {\n relay.sendEnvelope(\n buildMessage(\n \"assistant_message\",\n sessionId,\n seq,\n { text: d.text, isPartial: true },\n \"proxy\",\n ),\n );\n } else if (d.type === \"thinking_delta\" && d.thinking) {\n relay.sendEnvelope(buildMessage(\"thinking\", sessionId, seq, { text: d.thinking }, \"proxy\"));\n }\n return;\n }\n\n if (ev.type === \"assistant\") {\n for (const raw of ev.message.content) {\n const blockParse = KnownContentBlockSchema.safeParse(raw);\n if (!blockParse.success) {\n const rawType =\n raw && typeof raw === \"object\"\n ? ((raw as Record<string, unknown>).type as string | undefined)\n : undefined;\n serviceLogger.warn(\n { sessionId, seq, blockType: rawType ?? \"<missing>\" },\n \"Unknown assistant content block; Claude CLI schema may have changed\",\n );\n continue;\n }\n const block = blockParse.data;\n if (block.type === \"text\") {\n // streamDelta 下增量已经发过了,aggregated 全文跳过避免重复\n if (!isStreamDeltaSession && block.text) {\n relay.sendEnvelope(\n buildMessage(\n \"assistant_message\",\n sessionId,\n seq,\n { text: block.text, isPartial: true },\n \"proxy\",\n ),\n );\n }\n } else if (block.type === \"thinking\") {\n // Opus extended thinking 明文被 Anthropic 服务端 redact 时 block.thinking 为空字符串,\n // 不转发;session WORKING 状态已经覆盖\"Claude 在思考\"信号,redacted envelope 无新信息\n if (!isStreamDeltaSession && block.thinking) {\n relay.sendEnvelope(\n buildMessage(\"thinking\", sessionId, seq, { text: block.thinking }, \"proxy\"),\n );\n }\n } else if (block.type === \"tool_use\") {\n relay.sendEnvelope(\n buildMessage(\n \"assistant_tool_use\",\n sessionId,\n seq,\n { toolName: block.name, toolId: block.id, parameters: block.input },\n \"proxy\",\n ),\n );\n }\n }\n return;\n }\n\n if (ev.type === \"user\") {\n for (const raw of ev.message.content) {\n const blockParse = KnownContentBlockSchema.safeParse(raw);\n if (!blockParse.success) continue;\n const block = blockParse.data;\n if (block.type !== \"tool_result\") continue;\n relay.sendEnvelope(\n buildMessage(\n \"tool_result\",\n sessionId,\n seq,\n { toolId: block.tool_use_id, result: block.content, isError: block.is_error ?? false },\n \"proxy\",\n ),\n );\n }\n return;\n }\n\n if (ev.type === \"result\") {\n const resultText = typeof ev.result === \"string\" ? ev.result : undefined;\n relay.sendRaw(\n JSON.stringify({\n type: \"turn_result\",\n sessionId,\n success: ev.subtype === \"success\",\n isError: ev.is_error ?? false,\n ...(resultText ? { result: resultText } : {}),\n }),\n );\n this.deps.jsonObserver.onTurnResult(sessionId);\n }\n }\n\n private forwardApprovalRequest(\n sessionId: string,\n msg: Extract<WorkerMessage, { type: \"worker_approval_request\" }>,\n ): void {\n serviceLogger.info(\n { sessionId, toolName: msg.toolName, requestId: msg.requestId },\n \"Tool approval forwarding to relay\",\n );\n this.deps.jsonObserver.onApprovalRequested(sessionId);\n try {\n const approvalSeq = this.deps.nextSeq?.(sessionId) ?? new SeqCounter(sessionId).next();\n const envelope = buildMessage(\n \"tool_use_request\",\n sessionId,\n approvalSeq,\n {\n toolName: msg.toolName,\n toolId: msg.requestId,\n parameters: msg.input,\n },\n \"proxy\",\n );\n const session = this.deps.sessionManager.getSession(sessionId);\n const registered = this.deps.permissionBroker.registerWorkerRequest(\n {\n requestId: msg.requestId,\n provider: session?.provider ?? \"claude\",\n sessionId,\n toolName: msg.toolName,\n input: msg.input,\n },\n (decision: PermissionDecision) => {\n this.send(sessionId, {\n type: \"worker_approval_response\",\n requestId: msg.requestId,\n behavior: decision.behavior,\n ...(decision.message ? { message: decision.message } : {}),\n });\n },\n );\n if (!registered) return;\n this.deps.relayConnection.sendEnvelope(envelope);\n } catch (err) {\n const resolved = this.deps.permissionBroker.resolve(msg.requestId, {\n behavior: \"deny\",\n message: \"Failed to forward approval request to relay.\",\n });\n if (!resolved) {\n this.send(sessionId, {\n type: \"worker_approval_response\",\n requestId: msg.requestId,\n behavior: \"deny\",\n message: \"Failed to forward approval request to relay.\",\n });\n }\n // envelope 构造失败回 deny,避免 worker 无限等待。\n serviceLogger.warn(\n { sessionId, error: String(err) },\n \"Failed to forward tool approval to relay, denying\",\n );\n }\n }\n}\n","import type { Socket } from \"node:net\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { serializeIpc } from \"../ipc/ipc-protocol.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport type { HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\n\ntype SessionTerminationAction =\n | \"detach_local_terminal\"\n | \"terminate_hosted_pty\"\n | \"terminate_json_worker\"\n | \"not_found\";\n\ninterface TerminateSessionDeps {\n sessionManager: SessionManager;\n workerRegistry: WorkerRegistry;\n controlHandlers: ControlMessageHandlers;\n terminalSockets: Map<string, Socket>;\n hostedPtyRegistry: HostedPtyRegistry;\n agentStatusRegistry: AgentStatusRegistry;\n}\n\nexport function terminateSessionByOwnership(\n deps: TerminateSessionDeps,\n sessionId: string,\n): { success: boolean; action: SessionTerminationAction } {\n const session = deps.sessionManager.getSession(sessionId);\n\n if (session?.mode === \"pty\" && session.ptyOwner === \"local-terminal\") {\n const terminalSocket = deps.terminalSockets.get(sessionId);\n if (terminalSocket?.writable) {\n terminalSocket.write(serializeIpc({ type: \"pty_detach\", sessionId }));\n }\n deps.terminalSockets.delete(sessionId);\n const result = deps.sessionManager.terminateSession(sessionId, {\n preserveProviderHooks: true,\n });\n deps.controlHandlers.cleanup(sessionId);\n deps.agentStatusRegistry.delete(sessionId);\n serviceLogger.info(\n { sessionId, success: result.success },\n \"Local terminal session detached from remote view\",\n );\n return { success: result.success, action: \"detach_local_terminal\" };\n }\n\n if (session?.mode === \"pty\" && session.ptyOwner === \"proxy-hosted\") {\n const success = deps.hostedPtyRegistry.terminate(sessionId);\n serviceLogger.info({ sessionId, success }, \"Hosted PTY termination requested\");\n return { success, action: \"terminate_hosted_pty\" };\n }\n\n if (session?.mode === \"json\") {\n deps.workerRegistry.send(sessionId, { type: \"worker_stop\" });\n deps.workerRegistry.delete(sessionId);\n const result = deps.sessionManager.terminateSession(sessionId);\n deps.controlHandlers.cleanup(sessionId);\n deps.agentStatusRegistry.delete(sessionId);\n serviceLogger.info({ sessionId, success: result.success }, \"JSON worker session terminated\");\n return { success: result.success, action: \"terminate_json_worker\" };\n }\n\n const hostedTerminated = deps.hostedPtyRegistry.terminate(sessionId);\n if (hostedTerminated) {\n return { success: true, action: \"terminate_hosted_pty\" };\n }\n return { success: false, action: \"not_found\" };\n}\n","import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\nimport { nanoid } from \"nanoid\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport { DATA_DIR } from \"../common/paths.js\";\n\nconst MAX_CLIPBOARD_IMAGE_BYTES = 10 * 1024 * 1024;\nconst MAX_CLIPBOARD_IMAGE_BASE64_LENGTH = Math.ceil(MAX_CLIPBOARD_IMAGE_BYTES / 3) * 4;\nconst IMAGE_EXTENSIONS: ReadonlyMap<string, string> = new Map([\n [\"image/png\", \"png\"],\n [\"image/jpeg\", \"jpg\"],\n [\"image/webp\", \"webp\"],\n [\"image/gif\", \"gif\"],\n] as const);\n\nexport type ClipboardImageUploadRequest = {\n sessionId: string;\n mimeType: string;\n dataBase64: string;\n fileName?: string;\n};\n\ntype ClipboardImageUploadResult = {\n success: boolean;\n path: string;\n error?: string;\n errorCode?: ControlErrorCode;\n};\n\ntype ClipboardImageUploadOptions = {\n dataDir?: string;\n cwd?: string;\n now?: () => number;\n randomSuffix?: () => string;\n};\n\nfunction formatTimestamp(ms: number): string {\n const [date, time = \"000000\"] = new Date(ms)\n .toISOString()\n .replace(/\\.\\d{3}Z$/, \"\")\n .split(\"T\");\n return `${date.replace(/-/g, \"\")}-${time.replace(/:/g, \"\")}`;\n}\n\nfunction normalizeBase64(input: string): string {\n return input.replace(/^data:[^;]+;base64,/i, \"\").replace(/\\s/g, \"\");\n}\n\nfunction decodeBase64Image(dataBase64: string): Buffer {\n const normalized = normalizeBase64(dataBase64);\n if (normalized.length > MAX_CLIPBOARD_IMAGE_BASE64_LENGTH) {\n throw new Error(\"图片超过 10MB 限制\");\n }\n if (!normalized || !/^[A-Za-z0-9+/]*={0,2}$/.test(normalized)) {\n throw new Error(\"图片数据不是有效的 base64\");\n }\n const buffer = Buffer.from(normalized, \"base64\");\n if (buffer.length === 0) throw new Error(\"图片数据为空\");\n if (buffer.length > MAX_CLIPBOARD_IMAGE_BYTES) {\n throw new Error(\"图片超过 10MB 限制\");\n }\n return buffer;\n}\n\nfunction resolveChildDir(rootPath: string, ...segments: string[]): string {\n const root = resolve(rootPath);\n const uploadDir = resolve(root, ...segments);\n const relativePath = relative(root, uploadDir);\n if (!relativePath || relativePath.startsWith(\"..\") || isAbsolute(relativePath)) {\n throw new Error(\"会话路径无效\");\n }\n return uploadDir;\n}\n\nfunction resolveSessionClipboardDir(dataDir: string, sessionId: string): string {\n return resolveChildDir(dataDir, sessionId, \"clipboard\");\n}\n\nfunction normalizeGitignoreLine(line: string): string {\n return line.trim().replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nfunction ensureProjectClipboardIgnored(cwd: string): void {\n const gitignorePath = join(cwd, \".gitignore\");\n if (!existsSync(gitignorePath)) return;\n\n try {\n const current = readFileSync(gitignorePath, \"utf-8\");\n const alreadyIgnored = current\n .split(/\\r?\\n/)\n .some((line) => normalizeGitignoreLine(line) === \".dev-anywhere\");\n if (alreadyIgnored) return;\n\n const separator = current.length > 0 && !current.endsWith(\"\\n\") ? \"\\n\" : \"\";\n writeFileSync(gitignorePath, `${current}${separator}.dev-anywhere/\\n`);\n } catch {\n // Ignore-file updates are best-effort; image upload should still succeed.\n }\n}\n\nfunction trySaveProjectClipboardImage(options: {\n cwd?: string;\n sessionId: string;\n fileName: string;\n buffer: Buffer;\n}): ClipboardImageUploadResult | null {\n if (!options.cwd) return null;\n\n try {\n const cwd = resolve(options.cwd);\n if (!statSync(cwd).isDirectory()) return null;\n const clipboardRoot = resolve(cwd, \".dev-anywhere\", \"clipboard\");\n const uploadDir = resolveChildDir(clipboardRoot, options.sessionId);\n const path = join(uploadDir, options.fileName);\n\n mkdirSync(uploadDir, { recursive: true });\n writeFileSync(path, options.buffer, { mode: 0o600 });\n ensureProjectClipboardIgnored(cwd);\n return { success: true, path: relative(cwd, path) };\n } catch {\n return null;\n }\n}\n\nexport function saveClipboardImageUpload(\n request: ClipboardImageUploadRequest,\n options: ClipboardImageUploadOptions = {},\n): ClipboardImageUploadResult {\n const extension = IMAGE_EXTENSIONS.get(request.mimeType);\n if (!extension) {\n return {\n success: false,\n path: \"\",\n error: \"不支持这种图片格式\",\n errorCode: ControlErrorCode.UNKNOWN,\n };\n }\n\n try {\n const buffer = decodeBase64Image(request.dataBase64);\n const now = options.now ?? Date.now;\n const suffix = options.randomSuffix?.() ?? nanoid(6);\n const fileName = `pasted-${formatTimestamp(now())}-${suffix}.${extension}`;\n const projectResult = trySaveProjectClipboardImage({\n cwd: options.cwd,\n sessionId: request.sessionId,\n fileName,\n buffer,\n });\n if (projectResult) return projectResult;\n\n const dataDir = options.dataDir ?? DATA_DIR;\n const uploadDir = resolveSessionClipboardDir(dataDir, request.sessionId);\n const path = join(uploadDir, fileName);\n\n mkdirSync(uploadDir, { recursive: true });\n writeFileSync(path, buffer, { mode: 0o600 });\n return { success: true, path };\n } catch (err) {\n return {\n success: false,\n path: \"\",\n error: err instanceof Error ? err.message : String(err),\n errorCode: ControlErrorCode.UNKNOWN,\n };\n }\n}\n","import { readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { isAbsolute, relative, resolve } from \"node:path\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport type { ControlErrorCode as ControlErrorCodeType } from \"@dev-anywhere/shared\";\nimport { classifyPathError } from \"./path-errors.js\";\n\nconst MAX_IMAGE_PREVIEW_BYTES = 10 * 1024 * 1024;\n\ntype ImagePreviewRequest = {\n sessionId: string;\n path: string;\n};\n\ntype ImagePreviewResult = {\n success: boolean;\n sessionId: string;\n path: string;\n mimeType?: \"image/png\" | \"image/jpeg\" | \"image/webp\" | \"image/gif\";\n dataBase64?: string;\n size?: number;\n error?: string;\n errorCode?: ControlErrorCodeType;\n};\n\ntype ImagePreviewOptions = {\n cwd: string;\n tmpDir?: string;\n previewRoots?: string[];\n maxBytes?: number;\n};\n\nfunction isInsideRoot(realFilePath: string, realRootPath: string): boolean {\n const rel = relative(realRootPath, realFilePath);\n return rel === \"\" || (!rel.startsWith(\"..\") && !isAbsolute(rel));\n}\n\nfunction allowedRoots(options: ImagePreviewOptions): string[] {\n return [options.cwd, options.tmpDir ?? tmpdir(), ...(options.previewRoots ?? [])]\n .map((root) => root.trim())\n .filter(Boolean)\n .flatMap((root) => {\n try {\n return [realpathSync(root)];\n } catch {\n return [];\n }\n });\n}\n\nfunction resolvePreviewPath(rawPath: string, options: ImagePreviewOptions): string {\n const candidate = isAbsolute(rawPath) ? resolve(rawPath) : resolve(options.cwd, rawPath);\n const realCandidate = realpathSync(candidate);\n if (!allowedRoots(options).some((root) => isInsideRoot(realCandidate, root))) {\n throw Object.assign(new Error(\"图片路径不在允许预览的目录内\"), {\n errorCode: ControlErrorCode.INVALID_PATH,\n });\n }\n return realCandidate;\n}\n\nfunction detectImageMime(buffer: Buffer): ImagePreviewResult[\"mimeType\"] | undefined {\n if (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n ) {\n return \"image/png\";\n }\n if (buffer.length >= 3 && buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {\n return \"image/jpeg\";\n }\n if (\n buffer.length >= 12 &&\n buffer.subarray(0, 4).toString(\"ascii\") === \"RIFF\" &&\n buffer.subarray(8, 12).toString(\"ascii\") === \"WEBP\"\n ) {\n return \"image/webp\";\n }\n if (\n buffer.length >= 6 &&\n (buffer.subarray(0, 6).toString(\"ascii\") === \"GIF87a\" ||\n buffer.subarray(0, 6).toString(\"ascii\") === \"GIF89a\")\n ) {\n return \"image/gif\";\n }\n return undefined;\n}\n\nfunction errorCode(err: unknown): ControlErrorCodeType {\n if (\n err instanceof Error &&\n \"errorCode\" in err &&\n typeof (err as { errorCode?: unknown }).errorCode === \"string\"\n ) {\n return (err as { errorCode: ControlErrorCodeType }).errorCode;\n }\n return classifyPathError(err);\n}\n\nexport function loadImagePreview(\n request: ImagePreviewRequest,\n options: ImagePreviewOptions,\n): ImagePreviewResult {\n try {\n const resolvedPath = resolvePreviewPath(request.path, options);\n const stat = statSync(resolvedPath);\n if (!stat.isFile()) {\n return {\n success: false,\n sessionId: request.sessionId,\n path: request.path,\n error: \"路径不是图片文件\",\n errorCode: ControlErrorCode.INVALID_PATH,\n };\n }\n const maxBytes = options.maxBytes ?? MAX_IMAGE_PREVIEW_BYTES;\n if (stat.size > maxBytes) {\n return {\n success: false,\n sessionId: request.sessionId,\n path: request.path,\n error: \"图片超过 10MB 限制\",\n errorCode: ControlErrorCode.UNKNOWN,\n };\n }\n\n const buffer = readFileSync(resolvedPath);\n const mimeType = detectImageMime(buffer);\n if (!mimeType) {\n return {\n success: false,\n sessionId: request.sessionId,\n path: request.path,\n error: \"不支持这种图片格式\",\n errorCode: ControlErrorCode.UNKNOWN,\n };\n }\n\n return {\n success: true,\n sessionId: request.sessionId,\n path: request.path,\n mimeType,\n dataBase64: buffer.toString(\"base64\"),\n size: buffer.length,\n };\n } catch (err) {\n return {\n success: false,\n sessionId: request.sessionId,\n path: request.path,\n error: err instanceof Error ? err.message : String(err),\n errorCode: errorCode(err),\n };\n }\n}\n","import { serializeIpc } from \"../ipc/ipc-protocol.js\";\n\nexport function serializeRawPtyInput(sessionId: string, data: string): string {\n return serializeIpc({ type: \"pty_input\", sessionId, data });\n}\n","import type { Socket } from \"node:net\";\nimport { ControlErrorCode, MessageEnvelopeSchema } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { saveClipboardImageUpload } from \"./clipboard-image-upload.js\";\nimport { loadImagePreview } from \"./image-preview.js\";\nimport { serializeRawPtyInput } from \"./pty-input.js\";\nimport type { HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport type { JsonObserver } from \"./json-observer.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\n\ninterface RelayInputHandlersDeps {\n sessionManager: SessionManager;\n workerRegistry: WorkerRegistry;\n relayConnection: RelayConnection;\n terminalSockets: Map<string, Socket>;\n hostedPtyRegistry: HostedPtyRegistry;\n jsonObserver: JsonObserver;\n previewRoots?: string[];\n}\n\nexport class RelayInputHandlers {\n constructor(private readonly deps: RelayInputHandlersDeps) {}\n\n onUserInput(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n if (!sessionId) return;\n\n const session = this.deps.sessionManager.getSession(sessionId);\n if (!session) {\n serviceLogger.warn({ sessionId }, \"Remote input dropped: session not found\");\n return;\n }\n\n const payload = msg.payload as { text?: string; messageId?: string } | undefined;\n const text = payload?.text ?? \"\";\n\n if (session.mode === \"json\") {\n this.deps.jsonObserver.onTurnStart(sessionId);\n const sent = this.deps.workerRegistry.send(sessionId, {\n type: \"worker_input\",\n content: text,\n });\n if (!sent) {\n serviceLogger.warn({ sessionId }, \"Remote input dropped: JSON worker socket not available\");\n return;\n }\n const timestamp =\n typeof msg.timestamp === \"number\" && Number.isFinite(msg.timestamp)\n ? msg.timestamp\n : Date.now();\n const seq =\n typeof msg.seq === \"number\" && Number.isInteger(msg.seq) && msg.seq >= 0 ? msg.seq : 0;\n const version = typeof msg.version === \"string\" ? msg.version : \"1\";\n const messageId =\n typeof payload?.messageId === \"string\" && payload.messageId.length > 0\n ? payload.messageId\n : `${sessionId}-user-${timestamp}`;\n this.deps.relayConnection.sendEnvelope(\n MessageEnvelopeSchema.parse({\n type: \"user_input\",\n sessionId,\n seq,\n timestamp,\n source: \"proxy\",\n version,\n payload: { text, messageId },\n }),\n );\n serviceLogger.info({ sessionId }, \"Remote input forwarded to JSON worker\");\n return;\n }\n\n serviceLogger.warn(\n { sessionId, mode: session.mode },\n \"Remote batch input dropped: PTY sessions require remote_input_raw\",\n );\n }\n\n onRemoteInputRaw(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const data = msg.data as string | undefined;\n if (!sessionId || data === undefined) return;\n\n const ts = this.deps.terminalSockets.get(sessionId);\n if (!ts?.writable && this.deps.hostedPtyRegistry.write(sessionId, data)) {\n serviceLogger.info(\n { sessionId, bytes: data.length },\n \"Raw PTY input forwarded to hosted PTY\",\n );\n return;\n }\n if (!ts?.writable) {\n serviceLogger.warn({ sessionId }, \"Raw PTY input dropped: terminal socket unavailable\");\n return;\n }\n ts.write(serializeRawPtyInput(sessionId, data));\n serviceLogger.info({ sessionId, bytes: data.length }, \"Raw PTY input forwarded\");\n }\n\n onClipboardImageUpload(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n if (!sessionId) return;\n\n const session = this.deps.sessionManager.getSession(sessionId);\n if (!session) {\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"clipboard_image_upload_response\",\n requestId,\n sessionId,\n success: false,\n path: \"\",\n error: \"会话不存在\",\n errorCode: ControlErrorCode.SESSION_NOT_FOUND,\n }),\n );\n serviceLogger.warn({ sessionId }, \"Clipboard image upload rejected: session not found\");\n return;\n }\n\n const result = saveClipboardImageUpload(\n {\n sessionId,\n mimeType: typeof msg.mimeType === \"string\" ? msg.mimeType : \"\",\n dataBase64: typeof msg.dataBase64 === \"string\" ? msg.dataBase64 : \"\",\n fileName: typeof msg.fileName === \"string\" ? msg.fileName : undefined,\n },\n {\n cwd: session.cwd,\n },\n );\n\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"clipboard_image_upload_response\",\n requestId,\n sessionId,\n ...result,\n }),\n );\n serviceLogger.info({ sessionId, success: result.success }, \"Clipboard image upload handled\");\n }\n\n onImagePreviewRequest(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n const path = msg.path as string | undefined;\n if (!sessionId || !path) return;\n\n const session = this.deps.sessionManager.getSession(sessionId);\n if (!session) {\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"image_preview_response\",\n requestId,\n sessionId,\n success: false,\n path,\n error: \"会话不存在\",\n errorCode: ControlErrorCode.SESSION_NOT_FOUND,\n }),\n );\n serviceLogger.warn({ sessionId }, \"Image preview rejected: session not found\");\n return;\n }\n\n const result = loadImagePreview(\n { sessionId, path },\n {\n cwd: session.cwd,\n previewRoots: this.deps.previewRoots,\n },\n );\n\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"image_preview_response\",\n requestId,\n ...result,\n }),\n );\n serviceLogger.info({ sessionId, success: result.success }, \"Image preview handled\");\n }\n}\n","import { serviceLogger } from \"../common/logger.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\nimport { readSessionMessagesPage } from \"./session-history.js\";\nimport type { SessionManager } from \"./session-manager.js\";\n\ninterface RelayHistoryHandlersDeps {\n relaySend: RelaySend;\n sessionManager: SessionManager;\n permissionBroker: PermissionBroker;\n}\n\nexport class RelayHistoryHandlers {\n constructor(private readonly deps: RelayHistoryHandlersDeps) {}\n\n onSessionMessagesRequest(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n if (!sid) return;\n const requestId = msg.requestId as string | undefined;\n const before = msg.before as string | undefined;\n const limit = msg.limit as number | undefined;\n\n const session = this.deps.sessionManager.getSession(sid);\n if (session?.claudeSessionId) {\n readSessionMessagesPage(session.claudeSessionId, { before, limit })\n .then((page) => {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_history_messages\",\n requestId,\n sessionId: sid,\n ...(before !== undefined ? { before } : {}),\n messages: page.messages,\n hasMore: page.hasMore,\n ...(page.nextBefore !== undefined ? { nextBefore: page.nextBefore } : {}),\n }),\n );\n serviceLogger.info(\n {\n sessionId: sid,\n before,\n hasMore: page.hasMore,\n nextBefore: page.nextBefore,\n messageCount: page.messages.length,\n },\n \"History message page sent on request\",\n );\n })\n .catch((err) => {\n serviceLogger.warn(\n { sessionId: sid, error: String(err) },\n \"Failed to read session history page on request\",\n );\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_history_messages\",\n requestId,\n sessionId: sid,\n ...(before !== undefined ? { before } : {}),\n messages: [],\n hasMore: false,\n }),\n );\n });\n } else {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_history_messages\",\n requestId,\n sessionId: sid,\n ...(before !== undefined ? { before } : {}),\n messages: [],\n hasMore: false,\n }),\n );\n }\n\n const approvals = this.deps.permissionBroker.listSession(sid).map((approval) => ({\n requestId: approval.requestId,\n toolName: approval.toolName,\n input: approval.input,\n }));\n this.deps.relaySend(\n JSON.stringify({ type: \"pending_approvals_push\", sessionId: sid, approvals }),\n );\n serviceLogger.info({ sessionId: sid, count: approvals.length }, \"Pending approvals pushed\");\n }\n}\n","import { serviceLogger } from \"../common/logger.js\";\nimport type { HookEventRouter } from \"./hook-event-router.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\n\ninterface RelayPermissionHandlersDeps {\n relaySend: RelaySend;\n permissionBroker: PermissionBroker;\n hookEventRouter: HookEventRouter;\n workerRegistry: WorkerRegistry;\n}\n\nexport class RelayPermissionHandlers {\n constructor(private readonly deps: RelayPermissionHandlersDeps) {}\n\n onToolApprove(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const payload = msg.payload as { toolId?: string; whitelistTool?: boolean } | undefined;\n if (!sessionId || !payload?.toolId) return;\n\n const pending = this.deps.permissionBroker.get(payload.toolId);\n if (!pending) {\n this.pushPermissionDecisionResult(\n sessionId,\n payload.toolId,\n \"allow\",\n false,\n \"Permission request is no longer pending.\",\n );\n return;\n }\n if (!this.deps.permissionBroker.resolve(payload.toolId, { behavior: \"allow\" })) {\n this.pushPermissionDecisionResult(\n pending.sessionId,\n payload.toolId,\n \"allow\",\n false,\n \"Permission request is no longer pending.\",\n );\n return;\n }\n this.deps.hookEventRouter.onPermissionResolved(\n pending.sessionId,\n pending.provider,\n payload.toolId,\n \"allow\",\n { toolName: pending.toolName, toolInput: pending.input },\n );\n\n if (pending.source === \"worker\" && payload.whitelistTool) {\n const toolName = pending.toolName;\n if (toolName) {\n const whitelisted = this.deps.workerRegistry.send(pending.sessionId, {\n type: \"worker_whitelist_add\",\n toolName,\n });\n if (whitelisted) {\n serviceLogger.info(\n { sessionId: pending.sessionId, toolName },\n \"Tool added to session whitelist via relay\",\n );\n }\n }\n }\n this.pushPermissionDecisionResult(pending.sessionId, payload.toolId, \"allow\", true);\n serviceLogger.info(\n { sessionId, toolId: payload.toolId, whitelistTool: payload.whitelistTool },\n \"Tool approved via relay\",\n );\n }\n\n onToolDeny(msg: Record<string, unknown>): void {\n const sessionId = msg.sessionId as string | undefined;\n const payload = msg.payload as { toolId?: string; reason?: string } | undefined;\n if (!sessionId || !payload?.toolId) return;\n\n const reason = payload.reason ?? \"Denied by remote user\";\n const pending = this.deps.permissionBroker.get(payload.toolId);\n if (!pending) {\n this.pushPermissionDecisionResult(\n sessionId,\n payload.toolId,\n \"deny\",\n false,\n \"Permission request is no longer pending.\",\n );\n return;\n }\n if (\n !this.deps.permissionBroker.resolve(payload.toolId, {\n behavior: \"deny\",\n message: reason,\n })\n ) {\n this.pushPermissionDecisionResult(\n pending.sessionId,\n payload.toolId,\n \"deny\",\n false,\n \"Permission request is no longer pending.\",\n );\n return;\n }\n this.deps.hookEventRouter.onPermissionResolved(\n pending.sessionId,\n pending.provider,\n payload.toolId,\n \"deny\",\n { toolName: pending.toolName, toolInput: pending.input },\n );\n this.pushPermissionDecisionResult(pending.sessionId, payload.toolId, \"deny\", true, reason);\n serviceLogger.info({ sessionId, toolId: payload.toolId }, \"Tool denied via relay\");\n }\n\n onPermissionRequestDelivered(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n if (!sid || !requestId) return;\n const marked = this.deps.permissionBroker.markDelivered(requestId);\n serviceLogger.info({ sessionId: sid, requestId, marked }, \"Permission request delivered\");\n }\n\n private pushPermissionDecisionResult(\n sessionId: string,\n requestId: string,\n outcome: \"allow\" | \"deny\",\n delivered: boolean,\n message?: string,\n ): void {\n this.deps.relaySend(\n JSON.stringify({\n type: \"permission_decision_result\",\n sessionId,\n requestId,\n outcome,\n delivered,\n ...(message ? { message } : {}),\n }),\n );\n }\n}\n","import { homedir } from \"node:os\";\nimport { accessSync, constants, statSync } from \"node:fs\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { saveAgentCliPath } from \"../common/config.js\";\nimport { detectAgentCliStatus } from \"../providers/index.js\";\nimport type { ProviderId } from \"../providers/types.js\";\n\ninterface RelayResourceHandlersDeps {\n relaySend: RelaySend;\n controlHandlers: ControlMessageHandlers;\n sessionManager: SessionManager;\n getProviderEnv: () => NodeJS.ProcessEnv;\n getAgentCliSuggestions: () => Partial<Record<ProviderId, string[]>>;\n setAgentCliPath: (provider: ProviderId, path: string) => void;\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction validateExecutablePath(path: string): string {\n const normalized = path.trim();\n if (!normalized.startsWith(\"/\")) throw new Error(\"CLI 路径必须是绝对路径\");\n const stat = statSync(normalized);\n if (!stat.isFile()) throw new Error(\"CLI 路径不是可执行文件\");\n accessSync(normalized, constants.X_OK);\n return normalized;\n}\n\nexport class RelayResourceHandlers {\n constructor(private readonly deps: RelayResourceHandlersDeps) {}\n\n onProxyInfoRequest(msg: Record<string, unknown>): void {\n this.deps.relaySend(\n JSON.stringify({\n type: \"proxy_info\",\n requestId: msg.requestId as string | undefined,\n homePath: homedir() || \"/\",\n agentCli: detectAgentCliStatus(this.deps.getProviderEnv(), {\n suggestions: this.deps.getAgentCliSuggestions(),\n }),\n }),\n );\n }\n\n onAgentCliConfigUpdate(msg: Record<string, unknown>): void {\n const requestId = msg.requestId as string | undefined;\n const provider = msg.provider as ProviderId | undefined;\n const rawPath = msg.path as string | undefined;\n\n if (provider !== \"claude\" && provider !== \"codex\") {\n this.deps.relaySend(\n JSON.stringify({\n type: \"agent_cli_config_update_response\",\n requestId,\n provider: \"claude\",\n errorCode: ControlErrorCode.PROVIDER_UNSUPPORTED,\n error: \"Unsupported Agent CLI.\",\n }),\n );\n return;\n }\n\n try {\n const path = validateExecutablePath(rawPath ?? \"\");\n saveAgentCliPath(provider, path);\n this.deps.setAgentCliPath(provider, path);\n const agentCli = detectAgentCliStatus(this.deps.getProviderEnv(), {\n suggestions: this.deps.getAgentCliSuggestions(),\n });\n this.deps.relaySend(\n JSON.stringify({\n type: \"agent_cli_config_update_response\",\n requestId,\n provider,\n agentCli,\n }),\n );\n serviceLogger.info({ provider, path }, \"Agent CLI path updated\");\n } catch (err) {\n const error = errorMessage(err);\n this.deps.relaySend(\n JSON.stringify({\n type: \"agent_cli_config_update_response\",\n requestId,\n provider,\n errorCode: ControlErrorCode.INVALID_PATH,\n error,\n }),\n );\n serviceLogger.warn({ provider, path: rawPath, error }, \"Agent CLI path update rejected\");\n }\n }\n\n onDirListRequest(msg: Record<string, unknown>): void {\n this.deps.controlHandlers.handleDirListRequest({\n path: (msg.path as string) ?? \"\",\n requestId: msg.requestId as string | undefined,\n });\n }\n\n onDirCreateRequest(msg: Record<string, unknown>): void {\n this.deps.controlHandlers.handleDirCreateRequest({\n path: (msg.path as string) ?? \"\",\n requestId: msg.requestId as string | undefined,\n });\n }\n\n onSessionResourcesRequest(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n if (!sid) return;\n\n const session = this.deps.sessionManager.getSession(sid);\n if (!session?.cwd) {\n serviceLogger.warn({ sessionId: sid }, \"Session resources request: no cwd available\");\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_resources_response\",\n requestId: msg.requestId as string | undefined,\n sessionId: sid,\n commands: [],\n groups: [],\n errorCode: ControlErrorCode.SESSION_NOT_FOUND,\n error: \"Session not found or cwd unavailable\",\n }),\n );\n return;\n }\n this.deps.controlHandlers.handleSessionResourcesRequest({\n sessionId: sid,\n requestId: msg.requestId as string | undefined,\n workDir: session.cwd,\n });\n serviceLogger.info({ sessionId: sid, cwd: session.cwd }, \"Session resources requested\");\n }\n}\n","import { rmSync, statSync } from \"node:fs\";\nimport { isAbsolute } from \"node:path\";\nimport { nanoid } from \"nanoid\";\nimport { ControlErrorCode } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { sessionPaths, tildify } from \"../common/paths.js\";\nimport type { ProviderHookContext, ProviderId } from \"../providers/index.js\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport { buildHostedPtyArgs, type HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\nimport type { SessionInfo, SessionManager } from \"./session-manager.js\";\nimport { readSessionMessagesPage } from \"./session-history.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport { classifyPathError } from \"./path-errors.js\";\n\ninterface RelaySessionCreateHandlerDeps {\n relaySend: RelaySend;\n workerRegistry: WorkerRegistry;\n sessionManager: SessionManager;\n hostedPtyRegistry: HostedPtyRegistry;\n controlHandlers: ControlMessageHandlers;\n permissionBroker: PermissionBroker;\n agentStatusRegistry: AgentStatusRegistry;\n getProviderEnv: () => NodeJS.ProcessEnv;\n createHookContext: (\n sessionId: string,\n provider: ProviderHookContext[\"provider\"],\n ) => ProviderHookContext;\n cleanupHookContext: (sessionId: string) => void;\n broadcastSessionSync: (session: SessionInfo) => void;\n broadcastSessionList: () => void;\n}\n\ninterface SessionCwdValidationError {\n message: string;\n code: ControlErrorCode;\n}\n\nfunction validateSessionCwd(cwd: unknown): SessionCwdValidationError | null {\n if (typeof cwd !== \"string\" || !cwd.trim()) {\n return { message: \"请输入工作目录\", code: ControlErrorCode.INVALID_PATH };\n }\n const trimmed = cwd.trim();\n if (!isAbsolute(trimmed)) {\n return { message: \"工作目录必须是绝对路径\", code: ControlErrorCode.INVALID_PATH };\n }\n try {\n const stat = statSync(trimmed);\n return stat.isDirectory()\n ? null\n : { message: \"工作目录不是目录\", code: ControlErrorCode.PATH_NOT_DIRECTORY };\n } catch (err) {\n return {\n message: `工作目录不存在或不可访问: ${trimmed}`,\n code: classifyPathError(err),\n };\n }\n}\n\nexport class RelaySessionCreateHandler {\n constructor(private readonly deps: RelaySessionCreateHandlerDeps) {}\n\n onSessionCreate(msg: Record<string, unknown>): void {\n const requestId = msg.requestId as string | undefined;\n const cwd = msg.cwd as string | undefined;\n const cwdError = validateSessionCwd(cwd);\n if (cwdError) {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId,\n sessionId: \"\",\n error: cwdError.message,\n errorCode: cwdError.code,\n }),\n );\n serviceLogger.warn({ cwd }, \"Session create rejected: invalid cwd\");\n return;\n }\n const sessionCwd = typeof cwd === \"string\" ? cwd.trim() : \"\";\n\n const provider = msg.provider as ProviderId | undefined;\n const mode = (msg.mode as \"json\" | \"pty\" | undefined) ?? \"json\";\n const permissionMode = msg.permissionMode as string | undefined;\n if (mode === \"pty\") {\n this.createHostedPtySession(msg, sessionCwd, provider ?? \"claude\", permissionMode);\n return;\n }\n\n if (provider !== \"claude\") {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId,\n sessionId: \"\",\n errorCode: ControlErrorCode.PROVIDER_UNSUPPORTED,\n error:\n provider === \"codex\"\n ? \"Codex chat sessions are not supported yet; start a Codex terminal session instead.\"\n : \"Unsupported provider for JSON session.\",\n }),\n );\n serviceLogger.warn({ provider }, \"JSON session create rejected for unsupported provider\");\n return;\n }\n\n const resumeSessionId = msg.resumeSessionId as string | undefined;\n const streamDelta = msg.streamDelta === true;\n const name = tildify(sessionCwd);\n const pendingId = nanoid();\n const hook = this.deps.createHookContext(pendingId, provider);\n const workerPid = this.deps.workerRegistry.spawn(pendingId, {\n cwd: sessionCwd,\n resumeSessionId,\n permissionMode,\n streamDelta,\n hook,\n });\n\n const paths = sessionPaths(pendingId);\n let attempt = 0;\n const maxRetries = 20;\n const tryConnect = () => {\n attempt++;\n this.deps.workerRegistry.connect(pendingId, paths.workerSock).then((sock) => {\n if (sock) {\n const session = this.deps.sessionManager.createSession(\n \"json\",\n sessionCwd,\n workerPid,\n name,\n pendingId,\n provider,\n );\n if (resumeSessionId) {\n this.deps.sessionManager.setClaudeSessionId(session.id, resumeSessionId);\n }\n this.deps.relaySend(\n JSON.stringify({ type: \"session_create_response\", requestId, sessionId: session.id }),\n );\n if (resumeSessionId) {\n this.pushHistoryMessages(session.id, resumeSessionId);\n }\n serviceLogger.info(\n { sessionId: session.id, cwd: sessionCwd },\n \"JSON session created via relay\",\n );\n this.deps.controlHandlers.pushCommandList(session.id, sessionCwd);\n this.deps.broadcastSessionSync(session);\n this.deps.broadcastSessionList();\n } else if (attempt < maxRetries) {\n setTimeout(tryConnect, Math.min(100 * attempt, 2000));\n } else {\n this.cleanupPendingJsonSession(pendingId);\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId,\n sessionId: pendingId,\n errorCode: ControlErrorCode.WORKER_START_FAILED,\n error: \"Worker failed to start\",\n }),\n );\n serviceLogger.error({ sessionId: pendingId }, \"Worker connection timeout via relay\");\n }\n });\n };\n setTimeout(tryConnect, 100);\n }\n\n private cleanupPendingJsonSession(sessionId: string): void {\n const killed = this.deps.workerRegistry.terminateProcess(sessionId);\n const paths = sessionPaths(sessionId);\n rmSync(paths.dir, { recursive: true, force: true });\n this.deps.cleanupHookContext(sessionId);\n this.deps.permissionBroker.cleanupSession(sessionId, \"Worker failed to start\");\n this.deps.agentStatusRegistry.delete(sessionId);\n serviceLogger.warn(\n { sessionId, killed },\n \"Cleaned up pending JSON session after startup failure\",\n );\n }\n\n private createHostedPtySession(\n msg: Record<string, unknown>,\n cwd: string,\n provider: ProviderId,\n permissionMode?: string,\n ): void {\n if (provider !== \"claude\" && provider !== \"codex\") {\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId: msg.requestId as string | undefined,\n sessionId: \"\",\n errorCode: ControlErrorCode.PROVIDER_UNSUPPORTED,\n error: \"Unsupported provider for PTY session.\",\n }),\n );\n return;\n }\n\n const resumeSessionId = msg.resumeSessionId as string | undefined;\n const pendingId = nanoid();\n const name = tildify(cwd);\n const hook = this.deps.createHookContext(pendingId, provider);\n try {\n const pid = this.deps.hostedPtyRegistry.start({\n sessionId: pendingId,\n provider,\n cwd,\n args: buildHostedPtyArgs(provider, resumeSessionId),\n permissionMode,\n hook,\n });\n const session = this.deps.sessionManager.createSession(\n \"pty\",\n cwd,\n pid,\n name,\n pendingId,\n provider,\n \"proxy-hosted\",\n );\n if (resumeSessionId && provider === \"claude\") {\n this.deps.sessionManager.setClaudeSessionId(session.id, resumeSessionId);\n }\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId: msg.requestId as string | undefined,\n sessionId: session.id,\n mode: \"pty\",\n provider,\n ptyOwner: \"proxy-hosted\",\n }),\n );\n this.deps.controlHandlers.pushCommandList(session.id, cwd);\n this.deps.controlHandlers.pushFileTree(session.id, cwd);\n this.deps.broadcastSessionSync(session);\n this.deps.broadcastSessionList();\n serviceLogger.info({ sessionId: session.id, provider, cwd }, \"Hosted PTY session created\");\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_create_response\",\n requestId: msg.requestId as string | undefined,\n sessionId: \"\",\n errorCode: ControlErrorCode.PROCESS_START_FAILED,\n error,\n }),\n );\n const providerEnv = this.deps.getProviderEnv();\n serviceLogger.warn(\n {\n provider,\n cwd,\n error,\n claudeBin: providerEnv.CLAUDE_BIN,\n codexBin: providerEnv.CODEX_BIN,\n path: providerEnv.PATH,\n },\n \"Hosted PTY session create failed\",\n );\n }\n }\n\n private pushHistoryMessages(sessionId: string, resumeSessionId: string): void {\n readSessionMessagesPage(resumeSessionId)\n .then((page) => {\n if (page.messages.length === 0) return;\n this.deps.relaySend(\n JSON.stringify({\n type: \"session_history_messages\",\n sessionId,\n messages: page.messages,\n hasMore: page.hasMore,\n ...(page.nextBefore !== undefined ? { nextBefore: page.nextBefore } : {}),\n }),\n );\n serviceLogger.info(\n {\n sessionId,\n resumeSessionId,\n messageCount: page.messages.length,\n hasMore: page.hasMore,\n },\n \"History message page sent for resumed session\",\n );\n })\n .catch((err) => {\n serviceLogger.warn(\n { sessionId, error: String(err) },\n \"Failed to read session history page\",\n );\n });\n }\n}\n","import * as pty from \"node-pty\";\nimport type { IPty } from \"node-pty\";\nimport { SessionState } from \"@dev-anywhere/shared\";\nimport pkg from \"@xterm/headless\";\nconst { Terminal: HeadlessTerminal } = pkg;\nimport { SerializeAddon } from \"@xterm/addon-serialize\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport {\n extractOscSequences,\n extractOscSignals,\n type PtySemanticState,\n} from \"../common/osc-extractor.js\";\nimport {\n shouldReleaseApprovalWait,\n stateAfterApprovalRelease,\n} from \"../common/pty-approval-state.js\";\nimport {\n CLAUDE_PROVIDER,\n CODEX_PROVIDER,\n type ProviderAdapter,\n type ProviderHookContext,\n type ProviderId,\n} from \"../providers/index.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { SessionManager } from \"./session-manager.js\";\n\nconst DEFAULT_COLS = 80;\nconst DEFAULT_ROWS = 24;\nconst IDLE_CHECK_INTERVAL_MS = 3_000;\nconst IDLE_THRESHOLD_MS = 3_000;\n\nconst PROVIDERS: Record<ProviderId, ProviderAdapter> = {\n claude: CLAUDE_PROVIDER,\n codex: CODEX_PROVIDER,\n};\n\nconst HOSTED_PTY_TERM = \"xterm-256color\";\nconst HOSTED_PTY_COLORTERM = \"truecolor\";\n\ninterface HostedPtyRegistryDeps {\n sessionManager: SessionManager;\n relayConnection: RelayConnection;\n getProviderEnv: () => NodeJS.ProcessEnv;\n changeSessionState: (sessionId: string, next: SessionState) => boolean;\n touchSessionActivity: (sessionId: string) => boolean;\n onTurnComplete: (sessionId: string) => void;\n onSessionClosed: (sessionId: string) => void;\n}\n\ninterface HostedPtyStartOptions {\n sessionId: string;\n provider: ProviderId;\n cwd: string;\n args: string[];\n permissionMode?: string;\n hook: ProviderHookContext;\n cols?: number;\n rows?: number;\n}\n\ninterface HostedPtySession {\n child: IPty;\n terminal: InstanceType<typeof HeadlessTerminal>;\n serializeAddon: SerializeAddon;\n idleTimer: NodeJS.Timeout;\n lastOutputTime: number;\n currentState: PtySemanticState;\n outputSeq: number;\n}\n\nexport function buildHostedPtyArgs(provider: ProviderId, resumeSessionId?: string): string[] {\n if (!resumeSessionId) return [];\n return provider === \"codex\" ? [\"resume\", resumeSessionId] : [\"--resume\", resumeSessionId];\n}\n\nexport function normalizeHostedPtyEnv(env: NodeJS.ProcessEnv): Record<string, string> {\n const normalized: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (value === undefined) continue;\n normalized[key] = value;\n }\n\n delete normalized.NO_COLOR;\n if (normalized.CLICOLOR === \"0\") {\n delete normalized.CLICOLOR;\n }\n\n normalized.TERM = HOSTED_PTY_TERM;\n normalized.COLORTERM = HOSTED_PTY_COLORTERM;\n normalized.CLICOLOR = \"1\";\n return normalized;\n}\n\nexport class HostedPtyRegistry {\n private sessions = new Map<string, HostedPtySession>();\n\n constructor(private readonly deps: HostedPtyRegistryDeps) {}\n\n start(options: HostedPtyStartOptions): number {\n const provider = PROVIDERS[options.provider];\n const cols = options.cols ?? DEFAULT_COLS;\n const rows = options.rows ?? DEFAULT_ROWS;\n const command = provider.buildTerminalCommand(\n { args: options.args, permissionMode: options.permissionMode, hook: options.hook },\n this.deps.getProviderEnv(),\n );\n const env = normalizeHostedPtyEnv(command.env);\n const child = pty.spawn(command.command, command.args, {\n name: HOSTED_PTY_TERM,\n cols,\n rows,\n cwd: options.cwd,\n env,\n });\n\n const terminal = new HeadlessTerminal({ cols, rows, scrollback: 5000, allowProposedApi: true });\n const serializeAddon = new SerializeAddon();\n terminal.loadAddon(serializeAddon);\n void import(\"@xterm/addon-unicode-graphemes\")\n .then(({ UnicodeGraphemesAddon }) => terminal.loadAddon(new UnicodeGraphemesAddon()))\n .catch((err) => {\n serviceLogger.warn(\n { sessionId: options.sessionId, error: String(err) },\n \"Unicode addon unavailable\",\n );\n });\n\n const hosted: HostedPtySession = {\n child,\n terminal,\n serializeAddon,\n idleTimer: setInterval(() => this.checkIdle(options.sessionId), IDLE_CHECK_INTERVAL_MS),\n lastOutputTime: 0,\n currentState: \"turn_complete\",\n outputSeq: 0,\n };\n this.sessions.set(options.sessionId, hosted);\n\n child.onData((data) => this.handleData(options.sessionId, data));\n child.onExit(({ exitCode, signal }) => {\n const code = signal ? 128 + signal : exitCode;\n serviceLogger.info({ sessionId: options.sessionId, code }, \"Hosted PTY exited\");\n this.close(options.sessionId, { kill: false, notify: true });\n });\n\n serviceLogger.info(\n {\n sessionId: options.sessionId,\n provider: options.provider,\n command: command.command,\n pid: child.pid,\n cwd: options.cwd,\n cols,\n rows,\n },\n \"Hosted PTY started\",\n );\n return child.pid;\n }\n\n has(sessionId: string): boolean {\n return this.sessions.has(sessionId);\n }\n\n write(sessionId: string, data: string): boolean {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return false;\n hosted.child.write(data);\n return true;\n }\n\n resize(sessionId: string, cols: number, rows: number): boolean {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return false;\n hosted.child.resize(cols, rows);\n hosted.terminal.resize(cols, rows);\n this.deps.relayConnection.sendRaw(\n JSON.stringify({ type: \"terminal_resize\", sessionId, cols, rows }),\n );\n serviceLogger.info({ sessionId, cols, rows }, \"Hosted PTY resized\");\n return true;\n }\n\n snapshot(sessionId: string, requestId?: string): boolean {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return false;\n const data = hosted.serializeAddon.serialize();\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"session_snapshot\",\n sessionId,\n cols: hosted.terminal.cols,\n rows: hosted.terminal.rows,\n data,\n outputSeq: hosted.outputSeq,\n requestId,\n }),\n );\n serviceLogger.info(\n { sessionId, cols: hosted.terminal.cols, rows: hosted.terminal.rows, bytes: data.length },\n \"Hosted PTY snapshot sent\",\n );\n return true;\n }\n\n terminate(sessionId: string): boolean {\n return this.close(sessionId, { kill: true, notify: true });\n }\n\n destroyAll(): void {\n for (const sessionId of Array.from(this.sessions.keys())) {\n this.close(sessionId, { kill: true, notify: false });\n }\n }\n\n private handleData(sessionId: string, data: string): void {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return;\n hosted.lastOutputTime = Date.now();\n hosted.outputSeq += 1;\n hosted.terminal.write(data);\n this.deps.touchSessionActivity(sessionId);\n this.sendBinary(sessionId, Buffer.from(data, \"utf-8\"), hosted.outputSeq);\n\n const oscSequences = extractOscSequences(data);\n const session = this.deps.sessionManager.getSession(sessionId);\n const signal = extractOscSignals(data, session?.provider);\n if (oscSequences.length > 0) {\n serviceLogger.debug(\n {\n sessionId,\n oscSequences,\n signal,\n },\n \"Hosted PTY OSC sequences parsed\",\n );\n }\n if (signal?.title) {\n this.sendTerminalTitle(sessionId, signal.title);\n }\n if (signal?.state === \"approval_wait\") {\n hosted.currentState = \"approval_wait\";\n this.deps.changeSessionState(sessionId, SessionState.WAITING_APPROVAL);\n this.sendPtyState(sessionId, \"approval_wait\", { title: signal?.title, tool: signal?.tool });\n return;\n }\n if (\n shouldReleaseApprovalWait({\n currentState: hosted.currentState,\n signalState: signal?.state,\n })\n ) {\n const nextState = stateAfterApprovalRelease(signal?.state);\n hosted.currentState = nextState;\n if (nextState === \"turn_complete\") {\n this.deps.onTurnComplete(sessionId);\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n } else {\n this.deps.changeSessionState(sessionId, SessionState.WORKING);\n }\n this.sendPtyState(sessionId, nextState, { title: signal?.title, tool: signal?.tool });\n return;\n }\n if (\n (session?.state === SessionState.WAITING_APPROVAL ||\n hosted.currentState === \"approval_wait\") &&\n signal?.state !== \"turn_complete\"\n ) {\n hosted.currentState = \"approval_wait\";\n this.sendPtyState(sessionId, \"approval_wait\", { title: signal?.title, tool: signal?.tool });\n return;\n }\n if (signal && signal.state !== \"working\") {\n hosted.currentState = signal.state;\n if (signal.state === \"turn_complete\") {\n this.deps.onTurnComplete(sessionId);\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n }\n this.sendPtyState(sessionId, signal.state, { title: signal.title, tool: signal.tool });\n return;\n }\n if (hosted.currentState !== \"working\") {\n hosted.currentState = \"working\";\n this.deps.changeSessionState(sessionId, SessionState.WORKING);\n this.sendPtyState(sessionId, \"working\");\n }\n }\n\n private checkIdle(sessionId: string): void {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return;\n if (hosted.lastOutputTime === 0 || Date.now() - hosted.lastOutputTime <= IDLE_THRESHOLD_MS) {\n return;\n }\n hosted.lastOutputTime = 0;\n if (hosted.currentState !== \"working\") return;\n hosted.currentState = \"turn_complete\";\n this.deps.onTurnComplete(sessionId);\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n this.sendPtyState(sessionId, \"turn_complete\");\n }\n\n private sendPtyState(\n sessionId: string,\n state: PtySemanticState,\n meta?: { title?: string; tool?: string },\n ): void {\n const payload = {\n state,\n ...(meta?.title !== undefined ? { title: meta.title } : {}),\n ...(meta?.tool !== undefined ? { tool: meta.tool } : {}),\n };\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"pty_state\",\n sessionId,\n payload,\n }),\n );\n const logPayload = { sessionId, ...payload };\n if (state === \"approval_wait\" || state === \"turn_complete\") {\n serviceLogger.info(logPayload, \"Hosted PTY semantic event pushed\");\n } else {\n serviceLogger.debug(logPayload, \"Hosted PTY semantic event pushed\");\n }\n }\n\n private sendTerminalTitle(sessionId: string, title: string): void {\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"terminal_title\",\n sessionId,\n title,\n }),\n );\n }\n\n private sendBinary(sessionId: string, data: Buffer, outputSeq: number): void {\n const sessionIdBuf = Buffer.from(sessionId, \"utf-8\");\n const frame = Buffer.alloc(1 + sessionIdBuf.length + 4 + data.length);\n frame[0] = sessionIdBuf.length;\n sessionIdBuf.copy(frame, 1);\n frame.writeUInt32LE(outputSeq, 1 + sessionIdBuf.length);\n data.copy(frame, 1 + sessionIdBuf.length + 4);\n this.deps.relayConnection.sendBinary(frame);\n }\n\n private close(sessionId: string, options: { kill: boolean; notify: boolean }): boolean {\n const hosted = this.sessions.get(sessionId);\n if (!hosted) return false;\n this.sessions.delete(sessionId);\n clearInterval(hosted.idleTimer);\n if (options.kill) {\n try {\n hosted.child.kill();\n } catch {\n // PTY may already have exited.\n }\n }\n hosted.terminal.dispose();\n if (options.notify) {\n this.sendPtyState(sessionId, \"turn_complete\");\n this.deps.sessionManager.terminateSession(sessionId);\n this.deps.onSessionClosed(sessionId);\n }\n return true;\n }\n}\n","import type { Socket } from \"node:net\";\nimport { SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { serializeIpc } from \"../ipc/ipc-protocol.js\";\nimport type { SessionInfo, SessionManager } from \"./session-manager.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { JsonObserver } from \"./json-observer.js\";\nimport type { ProviderHookContext } from \"../providers/index.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { HookEventRouter } from \"./hook-event-router.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport type { HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport { terminateSessionByOwnership } from \"./session-termination.js\";\nimport { RelayInputHandlers } from \"./relay-input-handlers.js\";\nimport { RelayHistoryHandlers } from \"./relay-history-handlers.js\";\nimport { RelayPermissionHandlers } from \"./relay-permission-handlers.js\";\nimport { RelayResourceHandlers } from \"./relay-resource-handlers.js\";\nimport { RelaySessionCreateHandler } from \"./relay-session-create-handler.js\";\nimport type { RelaySend } from \"./relay-router-types.js\";\n\ninterface RelayRouterDeps {\n sessionManager: SessionManager;\n workerRegistry: WorkerRegistry;\n controlHandlers: ControlMessageHandlers;\n relayConnection: RelayConnection;\n relaySend: RelaySend;\n terminalSockets: Map<string, Socket>;\n hostedPtyRegistry: HostedPtyRegistry;\n broadcastSessionList: () => void;\n broadcastSessionSync: (session: SessionInfo) => void;\n // user_input 注入触发 turn 开始(JSON 观察器)\n jsonObserver: JsonObserver;\n createHookContext: (\n sessionId: string,\n provider: ProviderHookContext[\"provider\"],\n ) => ProviderHookContext;\n cleanupHookContext: (sessionId: string) => void;\n permissionBroker: PermissionBroker;\n hookEventRouter: HookEventRouter;\n agentStatusRegistry: AgentStatusRegistry;\n getProviderEnv: () => NodeJS.ProcessEnv;\n getAgentCliSuggestions: () => Partial<Record<ProviderHookContext[\"provider\"], string[]>>;\n setAgentCliPath: (provider: ProviderHookContext[\"provider\"], path: string) => void;\n getPreviewRoots?: () => string[];\n}\n\n// 按 type 分发入站 relay 消息到独立 handler。未知 type warn 不丢,schema 逐步收紧。\nexport class RelayRouter {\n private readonly historyHandlers: RelayHistoryHandlers;\n private readonly inputHandlers: RelayInputHandlers;\n private readonly permissionHandlers: RelayPermissionHandlers;\n private readonly resourceHandlers: RelayResourceHandlers;\n private readonly sessionCreateHandler: RelaySessionCreateHandler;\n\n constructor(private deps: RelayRouterDeps) {\n this.historyHandlers = new RelayHistoryHandlers({\n relaySend: deps.relaySend,\n sessionManager: deps.sessionManager,\n permissionBroker: deps.permissionBroker,\n });\n this.inputHandlers = new RelayInputHandlers({\n sessionManager: deps.sessionManager,\n workerRegistry: deps.workerRegistry,\n relayConnection: deps.relayConnection,\n terminalSockets: deps.terminalSockets,\n hostedPtyRegistry: deps.hostedPtyRegistry,\n jsonObserver: deps.jsonObserver,\n previewRoots: deps.getPreviewRoots?.(),\n });\n this.resourceHandlers = new RelayResourceHandlers({\n relaySend: deps.relaySend,\n controlHandlers: deps.controlHandlers,\n sessionManager: deps.sessionManager,\n getProviderEnv: deps.getProviderEnv,\n getAgentCliSuggestions: deps.getAgentCliSuggestions,\n setAgentCliPath: deps.setAgentCliPath,\n });\n this.permissionHandlers = new RelayPermissionHandlers({\n relaySend: deps.relaySend,\n permissionBroker: deps.permissionBroker,\n hookEventRouter: deps.hookEventRouter,\n workerRegistry: deps.workerRegistry,\n });\n this.sessionCreateHandler = new RelaySessionCreateHandler({\n relaySend: deps.relaySend,\n workerRegistry: deps.workerRegistry,\n sessionManager: deps.sessionManager,\n hostedPtyRegistry: deps.hostedPtyRegistry,\n controlHandlers: deps.controlHandlers,\n permissionBroker: deps.permissionBroker,\n agentStatusRegistry: deps.agentStatusRegistry,\n getProviderEnv: deps.getProviderEnv,\n createHookContext: deps.createHookContext,\n cleanupHookContext: deps.cleanupHookContext,\n broadcastSessionSync: deps.broadcastSessionSync,\n broadcastSessionList: deps.broadcastSessionList,\n });\n }\n\n handle(parsed: Record<string, unknown>): void {\n const type = parsed.type as string | undefined;\n if (!type) {\n serviceLogger.warn(\"Relay message without type discriminator\");\n return;\n }\n\n const handler = this.handlers[type];\n if (!handler) {\n serviceLogger.warn({ type }, \"Unhandled relay message type\");\n return;\n }\n\n try {\n handler.call(this, parsed);\n } catch (err) {\n serviceLogger.warn({ type, error: String(err) }, \"Relay handler threw\");\n }\n }\n\n private readonly handlers: Record<string, (msg: Record<string, unknown>) => void> = {\n user_input: (msg) => this.inputHandlers.onUserInput(msg),\n remote_input_raw: (msg) => this.inputHandlers.onRemoteInputRaw(msg),\n clipboard_image_upload: (msg) => this.inputHandlers.onClipboardImageUpload(msg),\n image_preview_request: (msg) => this.inputHandlers.onImagePreviewRequest(msg),\n tool_approve: (msg) => this.permissionHandlers.onToolApprove(msg),\n tool_deny: (msg) => this.permissionHandlers.onToolDeny(msg),\n proxy_info_request: (msg) => this.resourceHandlers.onProxyInfoRequest(msg),\n agent_cli_config_update: (msg) => this.resourceHandlers.onAgentCliConfigUpdate(msg),\n dir_list_request: (msg) => this.resourceHandlers.onDirListRequest(msg),\n dir_create_request: (msg) => this.resourceHandlers.onDirCreateRequest(msg),\n session_create: (msg) => this.sessionCreateHandler.onSessionCreate(msg),\n session_messages_request: (msg) => this.historyHandlers.onSessionMessagesRequest(msg),\n session_resources_request: (msg) => this.resourceHandlers.onSessionResourcesRequest(msg),\n agent_status_request: (msg) => this.onAgentStatusRequest(msg),\n permission_request_delivered: (msg) =>\n this.permissionHandlers.onPermissionRequestDelivered(msg),\n session_terminate: (msg) => this.onSessionTerminate(msg),\n session_worker_abort: (msg) => this.onSessionWorkerAbort(msg),\n session_history_request: (msg) =>\n this.deps.controlHandlers.handleSessionHistoryRequest({\n requestId: msg.requestId as string | undefined,\n }),\n session_list: () => this.onSessionList(),\n permission_mode_change: (msg) => this.onPermissionModeChange(msg),\n session_subscribe: (msg) => this.onSessionSubscribe(msg),\n terminal_resize_request: (msg) => this.onTerminalResizeRequest(msg),\n };\n\n private onAgentStatusRequest(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n if (sid) {\n const status = this.deps.agentStatusRegistry.get(sid);\n const statuses =\n status && this.deps.sessionManager.getSession(sid)\n ? [{ sessionId: sid, payload: status }]\n : [];\n this.deps.relaySend(JSON.stringify({ type: \"agent_status_response\", requestId, statuses }));\n serviceLogger.info({ sessionId: sid, count: statuses.length }, \"Agent status snapshot sent\");\n return;\n }\n\n const statuses: Array<{ sessionId: string; payload: AgentStatusPayload }> = [];\n for (const { sessionId, status } of this.deps.agentStatusRegistry.list()) {\n if (!this.deps.sessionManager.getSession(sessionId)) continue;\n statuses.push({ sessionId, payload: status });\n }\n this.deps.relaySend(JSON.stringify({ type: \"agent_status_response\", requestId, statuses }));\n serviceLogger.info({ count: statuses.length }, \"Agent status snapshot sent\");\n }\n\n private onSessionTerminate(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n if (!sid) return;\n\n const result = terminateSessionByOwnership(this.deps, sid);\n serviceLogger.info(\n { sessionId: sid, success: result.success, action: result.action },\n \"Session termination handled via relay\",\n );\n if (result.action !== \"terminate_hosted_pty\") this.deps.broadcastSessionList();\n }\n\n private onSessionWorkerAbort(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n if (!sid) return;\n\n const session = this.deps.sessionManager.getSession(sid);\n if (!session) {\n serviceLogger.warn({ sessionId: sid }, \"session_worker_abort: session not found\");\n return;\n }\n if (session.state === SessionState.TERMINATED) {\n serviceLogger.info({ sessionId: sid }, \"session_worker_abort: already terminated, dropping\");\n return;\n }\n\n if (session.mode === \"pty\") {\n // PTY 会话直接把 Ctrl+C 写入 PTY stdin,避免杀掉 terminal wrapper 进程\n const ts = this.deps.terminalSockets.get(sid);\n if (this.deps.hostedPtyRegistry.write(sid, \"\\x03\")) {\n serviceLogger.info({ sessionId: sid }, \"session_worker_abort: Ctrl+C sent to hosted PTY\");\n } else if (ts?.writable) {\n ts.write(serializeIpc({ type: \"pty_input\", sessionId: sid, data: \"\\x03\" }));\n serviceLogger.info({ sessionId: sid }, \"session_worker_abort: Ctrl+C sent to PTY\");\n } else {\n serviceLogger.warn(\n { sessionId: sid },\n \"session_worker_abort: PTY terminal socket unavailable\",\n );\n }\n return;\n }\n\n try {\n process.kill(session.pid, \"SIGINT\");\n serviceLogger.info(\n { sessionId: sid, pid: session.pid },\n \"session_worker_abort: SIGINT sent to worker\",\n );\n } catch (err) {\n serviceLogger.warn(\n { sessionId: sid, pid: session.pid, error: String(err) },\n \"session_worker_abort: kill failed\",\n );\n }\n }\n\n private onSessionList(): void {\n this.deps.broadcastSessionList();\n serviceLogger.info(\"Session list sent via relay\");\n }\n\n private onPermissionModeChange(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const mode = msg.mode;\n if (!sid) {\n serviceLogger.info(\n { mode },\n \"Permission mode change received via relay (global, no sessionId)\",\n );\n return;\n }\n\n const session = this.deps.sessionManager.getSession(sid);\n if (session?.mode !== \"pty\") {\n serviceLogger.info(\n { sessionId: sid, mode },\n \"Permission mode change received for JSON session (no-op, not supported)\",\n );\n return;\n }\n\n // PTY 会话:发 Shift+Tab (CSI Z) 让 claude CLI 循环 permission mode\n // mode 字段当前保留但不使用 —— Claude CLI 仅支持循环键,无法一键直选档位\n const ts = this.deps.terminalSockets.get(sid);\n if (this.deps.hostedPtyRegistry.write(sid, \"\\x1b[Z\")) {\n serviceLogger.info(\n { sessionId: sid, mode },\n \"Permission mode cycle: Shift+Tab sent to hosted PTY\",\n );\n } else if (ts?.writable) {\n ts.write(serializeIpc({ type: \"pty_input\", sessionId: sid, data: \"\\x1b[Z\" }));\n serviceLogger.info({ sessionId: sid, mode }, \"Permission mode cycle: Shift+Tab sent to PTY\");\n } else {\n serviceLogger.warn(\n { sessionId: sid },\n \"Permission mode cycle: PTY terminal socket unavailable\",\n );\n }\n }\n\n private onSessionSubscribe(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const requestId = msg.requestId as string | undefined;\n if (!sid) return;\n\n const ts = this.deps.terminalSockets.get(sid);\n if (this.deps.hostedPtyRegistry.snapshot(sid, requestId)) {\n serviceLogger.info({ sessionId: sid, requestId }, \"Subscribe handled by hosted PTY\");\n } else if (ts?.writable) {\n ts.write(serializeIpc({ type: \"pty_subscribe\", sessionId: sid, requestId }));\n serviceLogger.info({ sessionId: sid, requestId }, \"Subscribe forwarded to terminal\");\n } else {\n serviceLogger.warn({ sessionId: sid }, \"Subscribe failed: terminal socket not available\");\n }\n }\n\n private onTerminalResizeRequest(msg: Record<string, unknown>): void {\n const sid = msg.sessionId as string | undefined;\n const cols = msg.cols as number | undefined;\n const rows = msg.rows as number | undefined;\n if (!sid || !cols || !rows) return;\n if (!this.deps.hostedPtyRegistry.resize(sid, cols, rows)) {\n serviceLogger.debug({ sessionId: sid, cols, rows }, \"Resize request ignored: not hosted PTY\");\n }\n }\n}\n","import { SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\n\ninterface JsonObserverDeps {\n changeSessionState: (sessionId: string, next: SessionState) => boolean;\n emitAgentStatus?: (sessionId: string, phase: AgentStatusPayload[\"phase\"]) => void;\n}\n\n// JSON 观察通道:把 worker 转发的 stream-json 事件翻译成 SessionState。\n// ERROR 态表达 \"worker 进程活着,但 proxy 观察/控制通道已坏\"(control_response 写入失败、\n// stream 连续 parse 失败、未来可能的 heartbeat 超时等);turn 内部的 is_error=true 不是观察失联,\n// 不触发 ERROR,仍按 onTurnResult 回 IDLE 处理。\nexport class JsonObserver {\n constructor(private deps: JsonObserverDeps) {}\n\n // 用户消息注入 worker(relay-router 收到 user_input)→ 进入 WORKING\n onTurnStart(sessionId: string): void {\n this.deps.changeSessionState(sessionId, SessionState.WORKING);\n this.deps.emitAgentStatus?.(sessionId, \"thinking\");\n }\n\n // stream-json result event 到达 → turn 结束回 IDLE\n onTurnResult(sessionId: string): void {\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n this.deps.emitAgentStatus?.(sessionId, \"idle\");\n }\n\n // control_request event 到达 → worker 阻塞等审批\n onApprovalRequested(sessionId: string): void {\n this.deps.changeSessionState(sessionId, SessionState.WAITING_APPROVAL);\n this.deps.emitAgentStatus?.(sessionId, \"waiting_permission\");\n }\n\n // 观察通道失联 → ERROR,待人工干预或后续 terminate\n onChannelBroken(sessionId: string): void {\n this.deps.changeSessionState(sessionId, SessionState.ERROR);\n }\n}\n","import { serviceLogger } from \"../common/logger.js\";\nimport type { HookProviderId } from \"./hook-registry.js\";\n\ninterface PermissionRequest {\n requestId: string;\n sessionId: string;\n provider: HookProviderId;\n toolName: string;\n input: Record<string, unknown>;\n}\n\nexport interface PermissionDecision {\n behavior: \"allow\" | \"deny\";\n message?: string;\n}\n\ninterface PendingPermission extends PermissionRequest {\n source: \"hook\" | \"worker\";\n resolve: (decision: PermissionDecision) => void;\n createdAt: number;\n deliveredAt?: number;\n}\n\nexport class PermissionBroker {\n private readonly pending = new Map<string, PendingPermission>();\n\n request(request: PermissionRequest): Promise<PermissionDecision> {\n const existing = this.pending.get(request.requestId);\n if (existing) {\n return Promise.resolve({\n behavior: \"deny\",\n message: \"Duplicate permission request id.\",\n });\n }\n\n return new Promise((resolve) => {\n this.pending.set(request.requestId, {\n ...request,\n source: \"hook\",\n resolve,\n createdAt: Date.now(),\n });\n });\n }\n\n registerWorkerRequest(\n request: PermissionRequest,\n onDecision: (decision: PermissionDecision) => void,\n ): boolean {\n const existing = this.pending.get(request.requestId);\n if (existing) {\n onDecision({\n behavior: \"deny\",\n message: \"Duplicate permission request id.\",\n });\n return false;\n }\n\n this.pending.set(request.requestId, {\n ...request,\n source: \"worker\",\n resolve: onDecision,\n createdAt: Date.now(),\n });\n return true;\n }\n\n resolve(requestId: string, decision: PermissionDecision): boolean {\n const pending = this.pending.get(requestId);\n if (!pending) return false;\n this.pending.delete(requestId);\n pending.resolve(decision);\n return true;\n }\n\n markDelivered(requestId: string): boolean {\n const pending = this.pending.get(requestId);\n if (!pending) return false;\n pending.deliveredAt = Date.now();\n return true;\n }\n\n get(requestId: string): {\n requestId: string;\n sessionId: string;\n provider: HookProviderId;\n source: \"hook\" | \"worker\";\n toolName: string;\n input: Record<string, unknown>;\n createdAt: number;\n deliveredAt?: number;\n } | null {\n const pending = this.pending.get(requestId);\n if (!pending) return null;\n return {\n requestId: pending.requestId,\n sessionId: pending.sessionId,\n provider: pending.provider,\n source: pending.source,\n toolName: pending.toolName,\n input: pending.input,\n createdAt: pending.createdAt,\n ...(pending.deliveredAt !== undefined ? { deliveredAt: pending.deliveredAt } : {}),\n };\n }\n\n cleanupSession(sessionId: string, reason: string): void {\n for (const [requestId, pending] of this.pending) {\n if (pending.sessionId !== sessionId) continue;\n this.pending.delete(requestId);\n pending.resolve({ behavior: \"deny\", message: reason });\n serviceLogger.info({ sessionId, requestId, reason }, \"Pending hook permission dropped\");\n }\n }\n\n listSession(sessionId: string): Array<Omit<PendingPermission, \"resolve\">> {\n const out: Array<Omit<PendingPermission, \"resolve\">> = [];\n for (const pending of this.pending.values()) {\n if (pending.sessionId !== sessionId) continue;\n out.push({\n requestId: pending.requestId,\n sessionId: pending.sessionId,\n provider: pending.provider,\n source: pending.source,\n toolName: pending.toolName,\n input: pending.input,\n createdAt: pending.createdAt,\n ...(pending.deliveredAt !== undefined ? { deliveredAt: pending.deliveredAt } : {}),\n });\n }\n return out;\n }\n}\n","import { buildMessage, SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\nimport { SeqCounter } from \"../common/seq-counter.js\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { AuthenticatedHookEvent } from \"./hook-server.js\";\nimport type { HookProviderId } from \"./hook-registry.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\n\ninterface HookEventRouterDeps {\n relayConnection: RelayConnection;\n agentStatusRegistry: AgentStatusRegistry;\n changeSessionState: (sessionId: string, next: SessionState) => boolean;\n nextSeq?: (sessionId: string) => number;\n}\n\nfunction hookPayloadRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nfunction toolNameFromPayload(payload: Record<string, unknown>): string {\n return typeof payload.toolName === \"string\"\n ? payload.toolName\n : typeof payload.tool_name === \"string\"\n ? payload.tool_name\n : \"unknown\";\n}\n\nfunction toolInputFromPayload(payload: Record<string, unknown>): Record<string, unknown> {\n return hookPayloadRecord(payload.input ?? payload.tool_input);\n}\n\nexport class HookEventRouter {\n constructor(private readonly deps: HookEventRouterDeps) {}\n\n handle(event: AuthenticatedHookEvent): void {\n switch (event.event) {\n case \"SessionStart\":\n this.deps.changeSessionState(event.sessionId, SessionState.IDLE);\n this.forwardAgentStatus(event, \"idle\");\n break;\n case \"UserPromptSubmit\":\n this.deps.changeSessionState(event.sessionId, SessionState.WORKING);\n this.forwardAgentStatus(event, \"thinking\");\n break;\n case \"PostToolUse\":\n case \"PostToolUseFailure\":\n this.deps.changeSessionState(event.sessionId, SessionState.WORKING);\n this.forwardAgentStatus(event, \"outputting\");\n break;\n case \"Stop\":\n this.deps.changeSessionState(event.sessionId, SessionState.IDLE);\n this.forwardAgentStatus(event, \"idle\");\n break;\n case \"PermissionRequest\":\n this.forwardPermissionRequest(event);\n break;\n case \"PreToolUse\":\n this.forwardToolUse(event);\n break;\n default:\n serviceLogger.debug(\n { sessionId: event.sessionId, provider: event.provider, event: event.event },\n \"Unknown provider hook event ignored\",\n );\n break;\n }\n }\n\n onPermissionResolved(\n sessionId: string,\n provider: HookProviderId,\n requestId: string,\n outcome: \"allow\" | \"deny\",\n context?: { toolName?: string; toolInput?: Record<string, unknown> },\n ): void {\n this.deps.changeSessionState(sessionId, SessionState.WORKING);\n if (outcome === \"deny\") {\n this.deps.changeSessionState(sessionId, SessionState.IDLE);\n }\n this.forwardAgentStatus(\n {\n sessionId,\n provider,\n event: \"PermissionResolved\",\n requestId,\n payload: {},\n },\n outcome === \"allow\" ? \"tool_use\" : \"idle\",\n {\n toolName: context?.toolName,\n toolInput: context?.toolInput,\n permissionResolution: { requestId, outcome },\n },\n );\n serviceLogger.info({ sessionId, requestId, outcome }, \"Hook permission resolved\");\n }\n\n private forwardPermissionRequest(event: AuthenticatedHookEvent): void {\n const requestId = event.requestId ?? `${event.sessionId}:${Date.now()}`;\n const toolName = toolNameFromPayload(event.payload);\n const input = toolInputFromPayload(event.payload);\n\n this.deps.changeSessionState(event.sessionId, SessionState.WAITING_APPROVAL);\n this.forwardAgentStatus(event, \"waiting_permission\", {\n toolName,\n toolInput: input,\n permissionRequest: {\n requestId,\n toolName,\n input,\n },\n });\n\n const seq = this.deps.nextSeq?.(event.sessionId) ?? new SeqCounter(event.sessionId).next();\n const envelope = buildMessage(\n \"tool_use_request\",\n event.sessionId,\n seq,\n {\n toolName,\n toolId: requestId,\n parameters: input,\n },\n \"proxy\",\n );\n this.deps.relayConnection.sendEnvelope(envelope);\n }\n\n private forwardToolUse(event: AuthenticatedHookEvent): void {\n const toolName = toolNameFromPayload(event.payload);\n const input = toolInputFromPayload(event.payload);\n this.forwardAgentStatus(event, \"tool_use\", {\n toolName,\n toolInput: input,\n });\n }\n\n private forwardAgentStatus(\n event: AuthenticatedHookEvent,\n phase: AgentStatusPayload[\"phase\"],\n extra?: Partial<AgentStatusPayload>,\n ): void {\n const payload: AgentStatusPayload = {\n provider: event.provider,\n phase,\n seq: this.nextSeq(event.sessionId),\n updatedAt: Date.now(),\n ...extra,\n };\n this.deps.agentStatusRegistry.set(event.sessionId, payload);\n this.deps.relayConnection.sendRaw(\n JSON.stringify({\n type: \"agent_status\",\n sessionId: event.sessionId,\n payload,\n }),\n );\n }\n\n private nextSeq(sessionId: string): number {\n return this.deps.nextSeq?.(sessionId) ?? new SeqCounter(sessionId).next();\n }\n}\n","import type { AgentStatusPayload } from \"@dev-anywhere/shared\";\n\nexport class AgentStatusRegistry {\n private readonly statuses = new Map<string, AgentStatusPayload>();\n\n set(sessionId: string, status: AgentStatusPayload): void {\n const current = this.statuses.get(sessionId);\n if (current && current.seq > status.seq) return;\n this.statuses.set(sessionId, status);\n }\n\n get(sessionId: string): AgentStatusPayload | null {\n return this.statuses.get(sessionId) ?? null;\n }\n\n list(): Array<{ sessionId: string; status: AgentStatusPayload }> {\n return Array.from(this.statuses, ([sessionId, status]) => ({ sessionId, status }));\n }\n\n delete(sessionId: string): void {\n this.statuses.delete(sessionId);\n }\n}\n","import { buildMessage, SessionState } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { SessionInfo, SessionManager } from \"./session-manager.js\";\n\nconst ACTIVITY_STATUS_PUSH_INTERVAL_MS = 15_000;\n\nfunction toSessionListPayload(s: SessionInfo) {\n return {\n sessionId: s.id,\n mode: s.mode,\n provider: s.provider,\n ...(s.ptyOwner !== undefined ? { ptyOwner: s.ptyOwner } : {}),\n state: s.state,\n lastActive: s.updatedAt,\n ...(s.name !== undefined ? { name: s.name } : {}),\n };\n}\n\nfunction pushSessionStatus(\n relay: RelayConnection,\n sessionManager: SessionManager,\n sessionId: string,\n): void {\n const session = sessionManager.getSession(sessionId);\n if (!session) return;\n try {\n const envelope = buildMessage(\n \"session_status\",\n session.id,\n Date.now(),\n { sessionId: session.id, state: session.state, lastActive: session.updatedAt },\n \"proxy\",\n );\n relay.sendEnvelope(envelope);\n } catch (err) {\n serviceLogger.debug({ sessionId, error: String(err) }, \"Failed to push session_status\");\n }\n}\n\nexport function broadcastSessionList(relay: RelayConnection, sessionManager: SessionManager): void {\n relay.sendRaw(\n JSON.stringify({\n type: \"session_list\",\n sessionId: \"\",\n seq: 0,\n timestamp: Date.now(),\n source: \"proxy\",\n version: \"1\",\n payload: { sessions: sessionManager.listSessions().map(toSessionListPayload) },\n }),\n );\n}\n\nexport function broadcastSessionSync(relay: RelayConnection, session: SessionInfo): void {\n relay.sendRaw(\n JSON.stringify({\n type: \"session_sync\",\n sessions: [\n {\n id: session.id,\n mode: session.mode,\n provider: session.provider,\n ...(session.ptyOwner !== undefined ? { ptyOwner: session.ptyOwner } : {}),\n state: session.state,\n },\n ],\n }),\n );\n}\n\nexport function changeSessionState(\n sessionManager: SessionManager,\n relay: RelayConnection,\n sessionId: string,\n next: SessionState,\n): boolean {\n if (!sessionManager.getSession(sessionId)) return false;\n const changed = sessionManager.updateState(sessionId, next);\n if (changed) pushSessionStatus(relay, sessionManager, sessionId);\n return changed;\n}\n\nexport function touchSessionActivity(\n sessionManager: SessionManager,\n relay: RelayConnection,\n sessionId: string,\n now: number = Date.now(),\n): boolean {\n const touched = sessionManager.touchSession(sessionId, now, ACTIVITY_STATUS_PUSH_INTERVAL_MS);\n if (touched) pushSessionStatus(relay, sessionManager, sessionId);\n return touched;\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync, readFileSync, unlinkSync } from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { connect, type Socket } from \"node:net\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { DEFAULT_PROXY_PROFILE, PID_PATH, PROFILE_NAME, SOCK_PATH } from \"../common/paths.js\";\n\nfunction tryConnectSocket(sockPath: string): Promise<Socket | null> {\n return new Promise((resolve) => {\n const s = connect(sockPath);\n s.on(\"connect\", () => resolve(s));\n s.on(\"error\", () => resolve(null));\n });\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function cleanupStaleResources(): Promise<void> {\n if (existsSync(SOCK_PATH)) {\n const existing = await tryConnectSocket(SOCK_PATH);\n if (existing) {\n existing.destroy();\n const msg = `Another service is already running on ${SOCK_PATH}`;\n serviceLogger.error(msg);\n console.error(msg);\n process.exit(1);\n }\n unlinkSync(SOCK_PATH);\n serviceLogger.info(\"Removed stale socket file\");\n }\n\n if (existsSync(PID_PATH)) {\n const pidStr = readFileSync(PID_PATH, \"utf-8\").trim();\n const pid = parseInt(pidStr, 10);\n if (!isNaN(pid) && isProcessAlive(pid)) {\n const msg = `Another service is already running with PID ${pid}`;\n serviceLogger.error(msg);\n console.error(msg);\n process.exit(1);\n }\n unlinkSync(PID_PATH);\n serviceLogger.info(\"Removed stale PID file\");\n }\n}\n\nexport function formatProxyNameForProfile(baseName: string, profileName = PROFILE_NAME): string {\n return profileName === DEFAULT_PROXY_PROFILE ? baseName : `${baseName} (${profileName})`;\n}\n\nexport function getProxyName(): string {\n const explicitName = process.env.DEV_ANYWHERE_PROXY_NAME?.trim();\n if (explicitName) return explicitName;\n\n return formatProxyNameForProfile(getComputerName() || hostname());\n}\n\nfunction getComputerName(): string | null {\n try {\n return (\n execSync(\"scutil --get ComputerName\", { stdio: [\"pipe\", \"pipe\", \"ignore\"] })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n","import { SessionState } from \"@dev-anywhere/shared\";\nimport type { SessionInfo } from \"./session-manager.js\";\n\nexport function shouldPromotePtyActivityToWorking(\n session: SessionInfo | undefined,\n pendingApprovalCount: number,\n): boolean {\n if (!session || session.mode !== \"pty\") return false;\n if (pendingApprovalCount > 0) return false;\n return session.state === SessionState.IDLE || session.state === SessionState.WAITING_APPROVAL;\n}\n","import { SessionState } from \"@dev-anywhere/shared\";\nimport type { PtySemanticState } from \"../common/osc-extractor.js\";\n\nexport function resolvePtySemanticSessionTransitions(\n currentState: SessionState | undefined,\n semanticState: PtySemanticState,\n): SessionState[] {\n if (semanticState !== \"turn_complete\") return [];\n\n if (currentState === SessionState.WAITING_APPROVAL) {\n return [SessionState.IDLE];\n }\n\n if (currentState === SessionState.WORKING) {\n return [SessionState.IDLE];\n }\n\n return [];\n}\n","import type { Socket } from \"node:net\";\nimport { SessionState, type AgentStatusPayload } from \"@dev-anywhere/shared\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { createIpcReader, serializeIpc, type IpcMessage } from \"../ipc/ipc-protocol.js\";\nimport type { ProviderHookContext } from \"../providers/index.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport type { ControlMessageHandlers } from \"./handlers/control-messages.js\";\nimport type { HookEventRouter } from \"./hook-event-router.js\";\nimport type { HostedPtyRegistry } from \"./hosted-pty-registry.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport { shouldPromotePtyActivityToWorking } from \"./pty-state-guard.js\";\nimport { resolvePtySemanticSessionTransitions } from \"./pty-semantic-lifecycle.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport {\n broadcastSessionList,\n broadcastSessionSync,\n changeSessionState,\n touchSessionActivity,\n} from \"./session-broadcast.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport { terminateSessionByOwnership } from \"./session-termination.js\";\nimport type { WorkerRegistry } from \"./worker-registry.js\";\nimport { isProcessAlive } from \"./service-files.js\";\n\ninterface TerminalConnectionDeps {\n sessionManager: SessionManager;\n workerRegistry: WorkerRegistry;\n terminalSockets: Map<string, Socket>;\n hostedPtyRegistry: HostedPtyRegistry;\n relayConnection: RelayConnection;\n controlHandlers: ControlMessageHandlers;\n agentStatusRegistry: AgentStatusRegistry;\n permissionBroker: PermissionBroker;\n hookEventRouter: HookEventRouter;\n createHookContext: (\n sessionId: string,\n provider: ProviderHookContext[\"provider\"],\n ) => ProviderHookContext;\n emitAgentStatus: (sessionId: string, phase: AgentStatusPayload[\"phase\"]) => void;\n resolveInterruptedApprovals: (sessionId: string) => void;\n config: Extract<IpcMessage, { type: \"service_status_response\" }>[\"config\"];\n}\n\nexport function handleTerminalConnection(socket: Socket, deps: TerminalConnectionDeps): void {\n const {\n sessionManager,\n workerRegistry,\n terminalSockets,\n hostedPtyRegistry,\n relayConnection,\n controlHandlers,\n agentStatusRegistry,\n permissionBroker,\n createHookContext,\n emitAgentStatus,\n resolveInterruptedApprovals,\n config,\n } = deps;\n\n createIpcReader(\n socket,\n (msg: IpcMessage) => {\n switch (msg.type) {\n case \"session_create_request\": {\n if (msg.mode !== \"pty\") {\n socket.write(\n serializeIpc({\n type: \"session_create_response\",\n sessionId: \"\",\n error: `Unsupported mode via IPC: ${msg.mode}`,\n }),\n );\n break;\n }\n const provider = msg.provider;\n const existing = msg.sessionId ? sessionManager.getSession(msg.sessionId) : undefined;\n const session =\n existing ??\n sessionManager.createSession(\n \"pty\",\n msg.cwd,\n msg.pid,\n msg.name,\n msg.sessionId,\n provider,\n \"local-terminal\",\n );\n if (existing) {\n sessionManager.setPid(session.id, msg.pid);\n }\n socket.write(\n serializeIpc({\n type: \"session_create_response\",\n sessionId: session.id,\n hook: createHookContext(session.id, provider),\n }),\n );\n serviceLogger.info(\n { sessionId: session.id, mode: \"pty\", provider },\n \"PTY session created\",\n );\n break;\n }\n\n case \"service_status_request\": {\n const relayStatus = relayConnection.getStatus();\n const sessions = sessionManager.listSessions();\n socket.write(\n serializeIpc({\n type: \"service_status_response\",\n config,\n relay: relayStatus,\n sessions: sessions.map((s) => ({\n id: s.id,\n mode: s.mode,\n provider: s.provider,\n state: s.state,\n createdAt: new Date(s.createdAt).toISOString(),\n ...(s.name !== undefined ? { name: s.name } : {}),\n hasWorker: workerRegistry.has(s.id),\n })),\n }),\n );\n break;\n }\n\n case \"pty_title_change\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"terminal_title\",\n sessionId: msg.sessionId,\n title: msg.title,\n }),\n );\n break;\n }\n\n case \"pty_semantic_event\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n const logPayload = {\n sessionId: msg.sessionId,\n state: msg.state,\n ...(msg.title !== undefined ? { title: msg.title } : {}),\n ...(msg.tool !== undefined ? { tool: msg.tool } : {}),\n };\n if (msg.state === \"approval_wait\" || msg.state === \"turn_complete\") {\n serviceLogger.info(logPayload, \"PTY semantic event received\");\n } else {\n serviceLogger.debug(logPayload, \"PTY semantic event received\");\n }\n if (msg.state === \"approval_wait\") {\n changeSessionState(\n sessionManager,\n relayConnection,\n msg.sessionId,\n SessionState.WAITING_APPROVAL,\n );\n } else if (msg.state === \"working\" || msg.state === \"mid_pause\") {\n const session = sessionManager.getSession(msg.sessionId);\n const pendingApprovals = permissionBroker.listSession(msg.sessionId);\n if (shouldPromotePtyActivityToWorking(session, pendingApprovals.length)) {\n changeSessionState(\n sessionManager,\n relayConnection,\n msg.sessionId,\n SessionState.WORKING,\n );\n } else if (session?.state === SessionState.WAITING_APPROVAL) {\n serviceLogger.debug(\n {\n sessionId: msg.sessionId,\n ptyState: msg.state,\n pendingApprovals: pendingApprovals.length,\n },\n \"PTY working signal ignored while permission approval is pending\",\n );\n }\n }\n\n if (msg.state === \"turn_complete\") {\n resolveInterruptedApprovals(msg.sessionId);\n const session = sessionManager.getSession(msg.sessionId);\n const transitions = resolvePtySemanticSessionTransitions(session?.state, msg.state);\n for (const next of transitions) {\n changeSessionState(sessionManager, relayConnection, msg.sessionId, next);\n }\n emitAgentStatus(msg.sessionId, \"idle\");\n }\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"pty_state\",\n sessionId: msg.sessionId,\n payload: {\n state: msg.state,\n ...(msg.title !== undefined ? { title: msg.title } : {}),\n ...(msg.tool !== undefined ? { tool: msg.tool } : {}),\n },\n }),\n );\n break;\n }\n\n case \"pty_resize\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"terminal_resize\",\n sessionId: msg.sessionId,\n cols: msg.cols,\n rows: msg.rows,\n }),\n );\n break;\n }\n\n case \"session_terminate_request\": {\n const result = terminateSessionByOwnership(\n {\n sessionManager,\n workerRegistry,\n controlHandlers,\n terminalSockets,\n hostedPtyRegistry,\n agentStatusRegistry,\n },\n msg.sessionId,\n );\n socket.write(\n serializeIpc({\n type: \"session_terminate_response\",\n sessionId: msg.sessionId,\n success: result.success,\n }),\n );\n serviceLogger.info(\n { sessionId: msg.sessionId, success: result.success, action: result.action },\n \"Session termination request handled\",\n );\n break;\n }\n\n case \"pty_register\": {\n if (!sessionManager.getSession(msg.sessionId)) {\n serviceLogger.warn(\n { sessionId: msg.sessionId },\n \"PTY register ignored: session missing\",\n );\n break;\n }\n sessionManager.setPid(msg.sessionId, msg.pid);\n terminalSockets.set(msg.sessionId, socket);\n socket.write(\n serializeIpc({\n type: \"bridge_status\",\n connected: relayConnection.getStatus().connected,\n }),\n );\n const session = sessionManager.getSession(msg.sessionId);\n if (session) {\n broadcastSessionSync(relayConnection, session);\n }\n broadcastSessionList(relayConnection, sessionManager);\n serviceLogger.info({ sessionId: msg.sessionId }, \"PTY session registered\");\n break;\n }\n\n case \"pty_deregister\": {\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"pty_state\",\n sessionId: msg.sessionId,\n payload: { state: \"turn_complete\" },\n }),\n );\n sessionManager.terminateSession(msg.sessionId);\n terminalSockets.delete(msg.sessionId);\n\n controlHandlers.cleanup(msg.sessionId);\n agentStatusRegistry.delete(msg.sessionId);\n broadcastSessionList(relayConnection, sessionManager);\n serviceLogger.info({ sessionId: msg.sessionId }, \"PTY session deregistered\");\n break;\n }\n\n case \"pty_input\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n const targetSocket = terminalSockets.get(msg.sessionId);\n if (hostedPtyRegistry.write(msg.sessionId, msg.data)) {\n break;\n }\n if (targetSocket?.writable) {\n targetSocket.write(\n serializeIpc({\n type: \"pty_input\",\n sessionId: msg.sessionId,\n data: msg.data,\n }),\n );\n }\n break;\n }\n\n case \"session_status_update\": {\n changeSessionState(sessionManager, relayConnection, msg.sessionId, msg.state);\n break;\n }\n\n case \"pty_snapshot\": {\n if (!sessionManager.getSession(msg.sessionId)) break;\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"session_snapshot\",\n sessionId: msg.sessionId,\n cols: msg.cols,\n rows: msg.rows,\n data: msg.data,\n outputSeq: msg.outputSeq,\n requestId: msg.requestId,\n }),\n );\n serviceLogger.info(\n { sessionId: msg.sessionId, cols: msg.cols, rows: msg.rows },\n \"Session snapshot forwarded to relay\",\n );\n break;\n }\n\n default: {\n serviceLogger.warn({ type: (msg as IpcMessage).type }, \"Unhandled IPC message type\");\n }\n }\n },\n (sessionId, data, outputSeq) => {\n if (!sessionManager.getSession(sessionId)) return;\n touchSessionActivity(sessionManager, relayConnection, sessionId);\n const sessionIdBuf = Buffer.from(sessionId, \"utf-8\");\n const wsFrame = Buffer.alloc(1 + sessionIdBuf.length + 4 + data.length);\n wsFrame[0] = sessionIdBuf.length;\n sessionIdBuf.copy(wsFrame, 1);\n wsFrame.writeUInt32LE(outputSeq, 1 + sessionIdBuf.length);\n data.copy(wsFrame, 1 + sessionIdBuf.length + 4);\n relayConnection.sendBinary(wsFrame);\n },\n );\n\n socket.on(\"close\", () => {\n for (const [sessionId, terminalSocket] of terminalSockets) {\n if (terminalSocket === socket) {\n terminalSockets.delete(sessionId);\n const session = sessionManager.getSession(sessionId);\n if (!session) {\n serviceLogger.info({ sessionId }, \"Terminal socket closed, session already cleaned\");\n continue;\n }\n if (session.mode === \"pty\" && session.pid && isProcessAlive(session.pid)) {\n serviceLogger.info(\n { sessionId, pid: session.pid },\n \"Terminal socket closed but process alive, skipping cleanup\",\n );\n continue;\n }\n relayConnection.sendRaw(\n JSON.stringify({\n type: \"pty_state\",\n sessionId,\n payload: { state: \"turn_complete\" },\n }),\n );\n sessionManager.terminateSession(sessionId);\n controlHandlers.cleanup(sessionId);\n agentStatusRegistry.delete(sessionId);\n broadcastSessionList(relayConnection, sessionManager);\n serviceLogger.info(\n { sessionId },\n \"PTY session cleaned up on socket close (crash fallback)\",\n );\n }\n }\n });\n\n socket.on(\"error\", (err) => {\n serviceLogger.warn({ error: String(err) }, \"Client socket error\");\n });\n}\n","import { createHash, randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { z } from \"zod\";\nimport { serviceLogger } from \"../common/logger.js\";\n\nexport type HookProviderId = \"claude\" | \"codex\";\n\ninterface HookSessionBinding {\n sessionId: string;\n provider: HookProviderId;\n marker: string;\n tokenHash: string;\n createdAt: number;\n expiresAt?: number;\n}\n\ninterface HookSessionCredentials {\n sessionId: string;\n provider: HookProviderId;\n marker: string;\n token: string;\n}\n\ninterface VerifyOptions {\n sessionId: string;\n marker: string;\n token: string;\n provider?: HookProviderId;\n now?: number;\n}\n\ninterface HookRegistryOptions {\n persistPath?: string;\n}\n\nconst PersistedHookSessionBindingSchema = z.object({\n sessionId: z.string(),\n provider: z.enum([\"claude\", \"codex\"]),\n marker: z.string(),\n tokenHash: z.string(),\n createdAt: z.number(),\n expiresAt: z.number().optional(),\n});\n\nconst PersistedHookRegistrySchema = z.object({\n version: z.literal(1),\n bindings: z.array(PersistedHookSessionBindingSchema),\n});\n\nfunction hashToken(token: string): string {\n return createHash(\"sha256\").update(token).digest(\"hex\");\n}\n\nfunction randomSecret(): string {\n return randomBytes(32).toString(\"base64url\");\n}\n\nexport class HookRegistry {\n private readonly bindingsBySession = new Map<string, HookSessionBinding>();\n private readonly persistPath?: string;\n\n constructor(options: HookRegistryOptions = {}) {\n this.persistPath = options.persistPath;\n this.load();\n }\n\n registerSession(\n sessionId: string,\n provider: HookProviderId,\n options: { ttlMs?: number; now?: number } = {},\n ): HookSessionCredentials {\n const now = options.now ?? Date.now();\n const token = randomSecret();\n const marker = randomSecret();\n this.bindingsBySession.set(sessionId, {\n sessionId,\n provider,\n marker,\n tokenHash: hashToken(token),\n createdAt: now,\n ...(options.ttlMs ? { expiresAt: now + options.ttlMs } : {}),\n });\n this.save();\n return { sessionId, provider, marker, token };\n }\n\n verify(options: VerifyOptions): HookSessionBinding | null {\n const binding = this.bindingsBySession.get(options.sessionId);\n if (!binding) return null;\n if (options.provider && binding.provider !== options.provider) return null;\n if (binding.marker !== options.marker) return null;\n if (binding.tokenHash !== hashToken(options.token)) return null;\n if (binding.expiresAt && (options.now ?? Date.now()) > binding.expiresAt) return null;\n return binding;\n }\n\n getSession(sessionId: string): HookSessionBinding | null {\n return this.bindingsBySession.get(sessionId) ?? null;\n }\n\n unregisterSession(sessionId: string): void {\n if (this.bindingsBySession.delete(sessionId)) {\n this.save();\n }\n }\n\n private load(): void {\n if (!this.persistPath || !existsSync(this.persistPath)) return;\n try {\n const parsed = PersistedHookRegistrySchema.parse(\n JSON.parse(readFileSync(this.persistPath, \"utf8\")),\n );\n this.bindingsBySession.clear();\n for (const binding of parsed.bindings) {\n this.bindingsBySession.set(binding.sessionId, binding);\n }\n } catch (err) {\n serviceLogger.warn(\n { path: this.persistPath, error: String(err) },\n \"Failed to load hook registry state\",\n );\n }\n }\n\n private save(): void {\n if (!this.persistPath) return;\n try {\n mkdirSync(dirname(this.persistPath), { recursive: true });\n const tmpPath = `${this.persistPath}.${process.pid}.${Date.now()}.tmp`;\n writeFileSync(\n tmpPath,\n JSON.stringify(\n {\n version: 1,\n bindings: Array.from(this.bindingsBySession.values()),\n },\n null,\n 2,\n ),\n );\n renameSync(tmpPath, this.persistPath);\n } catch (err) {\n serviceLogger.warn(\n { path: this.persistPath, error: String(err) },\n \"Failed to persist hook registry state\",\n );\n }\n }\n}\n","import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { serviceLogger } from \"../common/logger.js\";\nimport { HookRegistry, type HookProviderId } from \"./hook-registry.js\";\nimport { PermissionBroker } from \"./permission-broker.js\";\n\ninterface HookServerOptions {\n port: number;\n registry: HookRegistry;\n permissionBroker: PermissionBroker;\n host?: string;\n maxBodyBytes?: number;\n isSessionActive?: (sessionId: string) => boolean;\n onEvent?: (event: AuthenticatedHookEvent) => void;\n}\n\nexport interface AuthenticatedHookEvent {\n sessionId: string;\n provider: HookProviderId;\n event: string;\n requestId?: string;\n payload: Record<string, unknown>;\n}\n\ninterface HookRequestBody {\n sessionId?: unknown;\n provider?: unknown;\n marker?: unknown;\n event?: unknown;\n requestId?: unknown;\n payload?: unknown;\n}\n\nfunction getBearerToken(req: IncomingMessage): string | null {\n const header = req.headers.authorization;\n if (!header?.startsWith(\"Bearer \")) return null;\n return header.slice(\"Bearer \".length).trim() || null;\n}\n\nfunction asProvider(value: unknown): HookProviderId | null {\n return value === \"claude\" || value === \"codex\" ? value : null;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nexport class HookServer {\n private server: Server | null = null;\n private readonly host: string;\n private readonly maxBodyBytes: number;\n\n constructor(private readonly options: HookServerOptions) {\n this.host = options.host ?? \"127.0.0.1\";\n this.maxBodyBytes = options.maxBodyBytes ?? 1024 * 1024;\n }\n\n start(): Promise<void> {\n if (this.server) return Promise.resolve();\n this.server = createServer((req, res) => {\n this.handle(req, res).catch((err) => {\n serviceLogger.error({ err: String(err) }, \"Hook request failed\");\n this.writeJson(res, 500, { error: \"internal_error\" });\n });\n });\n\n return new Promise((resolve, reject) => {\n const onError = (err: Error) => {\n this.server?.off(\"listening\", onListening);\n reject(err);\n };\n const onListening = () => {\n this.server?.off(\"error\", onError);\n serviceLogger.info({ host: this.host, port: this.options.port }, \"Hook server listening\");\n resolve();\n };\n this.server!.once(\"error\", onError);\n this.server!.once(\"listening\", onListening);\n this.server!.listen(this.options.port, this.host);\n });\n }\n\n close(): Promise<void> {\n if (!this.server) return Promise.resolve();\n const server = this.server;\n this.server = null;\n return new Promise((resolve, reject) => {\n server.close((err) => (err ? reject(err) : resolve()));\n });\n }\n\n getListeningPort(): number | null {\n const address = this.server?.address();\n if (!address || typeof address === \"string\") return null;\n return (address as AddressInfo).port;\n }\n\n private async handle(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (req.method !== \"POST\" || req.url !== \"/hook\") {\n this.writeJson(res, 404, { error: \"not_found\" });\n return;\n }\n\n const token = getBearerToken(req);\n if (!token) {\n this.writeJson(res, 401, { error: \"missing_token\" });\n return;\n }\n\n const body = await this.readBody(req);\n const parsed = JSON.parse(body) as HookRequestBody;\n const provider = asProvider(parsed.provider);\n if (\n typeof parsed.sessionId !== \"string\" ||\n typeof parsed.marker !== \"string\" ||\n typeof parsed.event !== \"string\" ||\n !provider\n ) {\n this.writeJson(res, 400, { error: \"invalid_hook_payload\" });\n return;\n }\n\n const binding = this.options.registry.verify({\n sessionId: parsed.sessionId,\n marker: parsed.marker,\n token,\n provider,\n });\n if (!binding) {\n this.writeJson(res, 403, { error: \"invalid_hook_credentials\" });\n return;\n }\n if (this.options.isSessionActive && !this.options.isSessionActive(binding.sessionId)) {\n serviceLogger.info(\n { sessionId: binding.sessionId, provider: binding.provider, event: parsed.event },\n \"Provider hook ignored for inactive session\",\n );\n this.writeProviderResponse(res, this.toNeutralProviderResponse(provider, parsed.event));\n return;\n }\n\n const payload = asRecord(parsed.payload);\n const requestId =\n typeof parsed.requestId === \"string\"\n ? parsed.requestId\n : typeof payload.tool_use_id === \"string\"\n ? payload.tool_use_id\n : undefined;\n const event: AuthenticatedHookEvent = {\n sessionId: binding.sessionId,\n provider: binding.provider,\n event: parsed.event,\n ...(requestId !== undefined ? { requestId } : {}),\n payload,\n };\n\n if (event.event === \"PermissionRequest\") {\n await this.handlePermissionRequest(event, res);\n return;\n }\n\n this.options.onEvent?.(event);\n this.writeProviderResponse(res, this.toNeutralProviderResponse(event.provider, event.event));\n }\n\n private async handlePermissionRequest(\n event: AuthenticatedHookEvent,\n res: ServerResponse,\n ): Promise<void> {\n const requestId =\n event.requestId ??\n (typeof event.payload.tool_use_id === \"string\" ? event.payload.tool_use_id : undefined) ??\n `${event.sessionId}:${Date.now()}`;\n const toolName =\n typeof event.payload.toolName === \"string\"\n ? event.payload.toolName\n : typeof event.payload.tool_name === \"string\"\n ? event.payload.tool_name\n : \"unknown\";\n const input = asRecord(event.payload.input ?? event.payload.tool_input);\n\n this.options.onEvent?.({ ...event, requestId });\n const decision = await this.options.permissionBroker.request({\n requestId,\n sessionId: event.sessionId,\n provider: event.provider,\n toolName,\n input,\n });\n this.writeJson(res, 200, this.toProviderDecision(event.event, decision));\n }\n\n private toProviderDecision(\n eventName: string,\n decision: { behavior: \"allow\" | \"deny\"; message?: string },\n ): object {\n if (eventName === \"PreToolUse\") {\n return {\n hookSpecificOutput: {\n hookEventName: \"PreToolUse\",\n permissionDecision: decision.behavior,\n ...(decision.message ? { permissionDecisionReason: decision.message } : {}),\n },\n };\n }\n\n return {\n hookSpecificOutput: {\n hookEventName: \"PermissionRequest\",\n decision,\n },\n };\n }\n\n private toNeutralProviderResponse(provider: HookProviderId, eventName: string): object | null {\n if (eventName === \"PreToolUse\") {\n if (provider === \"codex\") {\n return null;\n }\n return {\n hookSpecificOutput: {\n hookEventName: \"PreToolUse\",\n permissionDecision: \"defer\",\n },\n };\n }\n\n return null;\n }\n\n private writeProviderResponse(res: ServerResponse, payload: object | null): void {\n if (res.headersSent) return;\n if (payload === null) {\n res.writeHead(200);\n res.end();\n return;\n }\n this.writeJson(res, 200, payload);\n }\n\n private readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n let body = \"\";\n let size = 0;\n req.setEncoding(\"utf8\");\n req.on(\"data\", (chunk: string) => {\n size += Buffer.byteLength(chunk);\n if (size > this.maxBodyBytes) {\n reject(new Error(\"hook body too large\"));\n req.destroy();\n return;\n }\n body += chunk;\n });\n req.on(\"end\", () => resolve(body));\n req.on(\"error\", reject);\n });\n }\n\n private writeJson(res: ServerResponse, statusCode: number, payload: object): void {\n if (res.headersSent) return;\n res.writeHead(statusCode, { \"content-type\": \"application/json; charset=utf-8\" });\n res.end(JSON.stringify(payload));\n }\n}\n","import { serviceLogger } from \"../common/logger.js\";\nimport { HOOK_REGISTRY_PATH } from \"../common/paths.js\";\nimport type { ProviderHookContext } from \"../providers/index.js\";\nimport type { AgentStatusRegistry } from \"./agent-status-registry.js\";\nimport { HookEventRouter } from \"./hook-event-router.js\";\nimport { HookRegistry } from \"./hook-registry.js\";\nimport { HookServer } from \"./hook-server.js\";\nimport type { PermissionBroker } from \"./permission-broker.js\";\nimport type { RelayConnection } from \"./relay-connection.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { SessionState } from \"@dev-anywhere/shared\";\n\ninterface ProviderHookRuntimeOptions {\n hookPort?: number;\n permissionBroker: PermissionBroker;\n sessionManager: SessionManager;\n relayConnection: RelayConnection;\n agentStatusRegistry: AgentStatusRegistry;\n changeSessionState: (sessionId: string, next: SessionState) => boolean;\n}\n\ninterface ProviderHookRuntime {\n hookRegistry: HookRegistry;\n hookEventRouter: HookEventRouter;\n hookServer: HookServer;\n createHookContext: (\n sessionId: string,\n provider: ProviderHookContext[\"provider\"],\n ) => ProviderHookContext;\n}\n\nexport async function createProviderHookRuntime(\n options: ProviderHookRuntimeOptions,\n): Promise<ProviderHookRuntime> {\n const hookRegistry = new HookRegistry({ persistPath: HOOK_REGISTRY_PATH });\n const hookEventRouter = new HookEventRouter({\n relayConnection: options.relayConnection,\n agentStatusRegistry: options.agentStatusRegistry,\n changeSessionState: options.changeSessionState,\n });\n const port = options.hookPort ?? 17654;\n const hookServer = new HookServer({\n port,\n registry: hookRegistry,\n permissionBroker: options.permissionBroker,\n isSessionActive: (sessionId) => !!options.sessionManager.getSession(sessionId),\n onEvent: (event) => {\n serviceLogger.info(\n {\n sessionId: event.sessionId,\n provider: event.provider,\n event: event.event,\n requestId: event.requestId,\n },\n \"Provider hook event received\",\n );\n hookEventRouter.handle(event);\n },\n });\n\n try {\n await hookServer.start();\n } catch (err) {\n const msg = `Failed to start hook server on 127.0.0.1:${port}: ${String(err)}`;\n serviceLogger.error(msg);\n console.error(msg);\n process.exit(1);\n }\n\n const hookUrl = `http://127.0.0.1:${hookServer.getListeningPort() ?? port}/hook`;\n const createHookContext: ProviderHookRuntime[\"createHookContext\"] = (sessionId, provider) => {\n const credentials = hookRegistry.registerSession(sessionId, provider);\n return {\n provider,\n sessionId,\n hookUrl,\n marker: credentials.marker,\n token: credentials.token,\n };\n };\n\n return {\n hookRegistry,\n hookEventRouter,\n hookServer,\n createHookContext,\n };\n}\n"],"mappings":"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","names":["createServer","unlinkSync","writeFileSync","rmSync","readFileSync","writeFileSync","mkdirSync","existsSync","dirname","nanoid","existsSync","readFileSync","nanoid","dirname","mkdirSync","writeFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","readdir","join","isAbsolute","join","homedir","resolve","join","readFileSync","homedir","join","isAbsolute","readdir","join","existsSync","readdirSync","resolve","existsSync","readdirSync","existsSync","mkdirSync","readFileSync","writeFileSync","isAbsolute","join","nanoid","isAbsolute","join","existsSync","readFileSync","writeFileSync","mkdirSync","nanoid","readFileSync","statSync","isAbsolute","relative","resolve","relative","isAbsolute","resolve","stat","statSync","readFileSync","homedir","statSync","stat","statSync","homedir","statSync","isAbsolute","nanoid","isAbsolute","stat","statSync","nanoid","statuses","resolve","existsSync","readFileSync","unlinkSync","connect","resolve","connect","existsSync","unlinkSync","readFileSync","resolveInterruptedApprovals","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","renameSync","resolve","unlinkSync","rmSync","createServer","writeFileSync"]}
|