@code-yeongyu/senpi 2026.8.31 → 2026.9.2

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.
Files changed (93) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts +6 -0
  3. package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts.map +1 -1
  4. package/dist/core/extensions/builtin/compaction/context-pipeline.js +11 -0
  5. package/dist/core/extensions/builtin/compaction/context-pipeline.js.map +1 -1
  6. package/dist/core/extensions/builtin/compaction/index.js +4 -4
  7. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  8. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.d.ts +3 -0
  9. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.d.ts.map +1 -0
  10. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js +108 -0
  11. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js.map +1 -0
  12. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  13. package/dist/core/extensions/builtin/prompt-preset/presets.js +11 -0
  14. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  15. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  16. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  17. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
  18. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  19. package/dist/core/extensions/builtin/recommended-models/index.d.ts +1 -1
  20. package/dist/core/extensions/builtin/recommended-models/index.d.ts.map +1 -1
  21. package/dist/core/extensions/builtin/recommended-models/index.js +1 -1
  22. package/dist/core/extensions/builtin/recommended-models/index.js.map +1 -1
  23. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  24. package/dist/core/retry-fallback/settings.js +1 -0
  25. package/dist/core/retry-fallback/settings.js.map +1 -1
  26. package/dist/main.d.ts +4 -4
  27. package/dist/main.d.ts.map +1 -1
  28. package/dist/main.js +10 -6
  29. package/dist/main.js.map +1 -1
  30. package/dist/modes/app-server/daemon/process.d.ts +13 -2
  31. package/dist/modes/app-server/daemon/process.d.ts.map +1 -1
  32. package/dist/modes/app-server/daemon/process.js +58 -12
  33. package/dist/modes/app-server/daemon/process.js.map +1 -1
  34. package/dist/modes/app-server/daemon.js +62 -4
  35. package/dist/modes/app-server/daemon.js.map +1 -1
  36. package/dist/modes/interactive/interactive-mode.d.ts +11 -1
  37. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  38. package/dist/modes/interactive/interactive-mode.js +35 -6
  39. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  40. package/dist/modes/interactive/tips/catalog/ethos-tips.js +1 -1
  41. package/dist/modes/interactive/tips/catalog/ethos-tips.js.map +1 -1
  42. package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
  43. package/dist/modes/rpc/connection-handler.js +8 -3
  44. package/dist/modes/rpc/connection-handler.js.map +1 -1
  45. package/dist/modes/rpc/custom-capability.d.ts +1 -0
  46. package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
  47. package/dist/modes/rpc/custom-capability.js +1 -0
  48. package/dist/modes/rpc/custom-capability.js.map +1 -1
  49. package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
  50. package/dist/modes/rpc/host-ensure.js +93 -17
  51. package/dist/modes/rpc/host-ensure.js.map +1 -1
  52. package/dist/modes/rpc/host-lifecycle.d.ts +15 -0
  53. package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
  54. package/dist/modes/rpc/host-lifecycle.js +180 -55
  55. package/dist/modes/rpc/host-lifecycle.js.map +1 -1
  56. package/dist/modes/rpc/host-watchdog.d.ts +2 -2
  57. package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
  58. package/dist/modes/rpc/host-watchdog.js +89 -21
  59. package/dist/modes/rpc/host-watchdog.js.map +1 -1
  60. package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
  61. package/dist/modes/rpc/multi-session-host.js +94 -56
  62. package/dist/modes/rpc/multi-session-host.js.map +1 -1
  63. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  64. package/dist/modes/rpc/rpc-client.js +8 -1
  65. package/dist/modes/rpc/rpc-client.js.map +1 -1
  66. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  67. package/dist/modes/rpc/session-command-router.js +7 -2
  68. package/dist/modes/rpc/session-command-router.js.map +1 -1
  69. package/dist/modes/rpc/socket-transport.d.ts +13 -0
  70. package/dist/modes/rpc/socket-transport.d.ts.map +1 -0
  71. package/dist/modes/rpc/socket-transport.js +92 -0
  72. package/dist/modes/rpc/socket-transport.js.map +1 -0
  73. package/docs/extensions.md +1 -1
  74. package/docs/rpc.md +5 -1
  75. package/docs/settings.md +4 -4
  76. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
  77. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  78. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  79. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  80. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  81. package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -1
  82. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  83. package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
  84. package/node_modules/@earendil-works/pi-ai/dist/providers/data/groq.json +1 -1
  85. package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
  86. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.json +1 -1
  87. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  88. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  89. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  90. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  91. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  92. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  93. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"session-command-router.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-command-router.ts"],"names":[],"mappings":"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","sourcesContent":["import { VERSION } from \"../../config.ts\";\nimport { buildRpcSessionState } from \"./connection-handler.ts\";\nimport type { RpcCommand, RpcResponse } from \"./rpc-types.ts\";\nimport {\n\tRPC_ERROR_MISSING_SESSION_ID,\n\tRPC_ERROR_OPEN_FAILED,\n\tRPC_ERROR_SESSION_CLOSING,\n\tRPC_ERROR_UNKNOWN_SESSION,\n} from \"./rpc-types.ts\";\nimport { createRpcSessionBinding, type RpcSessionBinding } from \"./session-binding.ts\";\nimport type { SessionEventWriter } from \"./session-event-writer.ts\";\nimport type {\n\tOpenRpcSession,\n\tRpcSessionEntry,\n\tRpcSessionLaunchProfile,\n\tRpcSessionRegistry,\n} from \"./session-registry.ts\";\nimport { RpcSessionRegistryError } from \"./session-registry.ts\";\n\nconst controls = new Set([\"get_protocol_info\", \"open_session\", \"close_session\", \"list_sessions\"]);\n\n/** Binding factory seam, injectable so host wiring is testable without a full runtime stack. */\nexport type RpcBindingFactory = typeof createRpcSessionBinding;\n\n/**\n * Occupancy policy for the shared multi-session host. All fields are opt-in:\n * a router constructed without a policy keeps today's behavior (sessions live\n * until close_session; the host never self-exits).\n */\nexport interface RpcSessionIdlePolicy {\n\t/** Injectable clock (defaults to Date.now) for deterministic tests. */\n\tnow?: () => number;\n\t/** Evict open sessions whose last routed command or session-owned work settled longer ago than this. */\n\tidleEvictionMs?: number;\n\t/** Invoke onEmptyExit once the registry has stayed empty for this long. */\n\temptyExitMs?: number;\n\t/** Host shutdown hook fired by the empty-exit window; called at most once. */\n\tonEmptyExit?: () => void;\n\t/**\n\t * Consulted every tick before the empty-exit window advances. Returning false\n\t * both blocks the exit and resets the window, so a host with a connected but\n\t * sessionless client stays up instead of exiting under its supervisor.\n\t */\n\tcanExitWhenEmpty?: () => boolean;\n}\n\nfunction error(id: string | undefined, command: string, code: string): RpcResponse {\n\treturn { id, type: \"response\", command, success: false, error: code };\n}\n\n/** Routes control messages and enforces a routing handle for every session command. */\nexport class SessionCommandRouter {\n\tprivate readonly bindings = new Map<string, RpcSessionBinding>();\n\t/** Session handles opened by each connection, with one count per attachment. */\n\tprivate readonly sessionsByConnection = new Map<string, Map<string, number>>();\n\t/** Opens currently awaiting runtime/binding setup, keyed by connection. */\n\tprivate readonly opensByConnection = new Map<string, Set<Promise<void>>>();\n\t/** Connections whose socket has already been detached. */\n\tprivate readonly releasedConnections = new Set<string>();\n\tprivate readonly registry: RpcSessionRegistry;\n\tprivate readonly writer: SessionEventWriter;\n\tprivate readonly defaults: Pick<\n\t\tRpcSessionLaunchProfile,\n\t\t\"cwd\" | \"permissionPreset\" | \"creationModel\" | \"initialThinkingLevel\"\n\t>;\n\tprivate readonly createBinding: typeof createRpcSessionBinding;\n\tprivate readonly connectionOptions: Parameters<typeof createRpcSessionBinding>[4];\n\tprivate readonly widths = new Map<string, Map<string, number>>();\n\tprivate readonly pendingCapabilities = new Map<string, string[]>();\n\tprivate readonly idleNow: () => number;\n\tprivate readonly idleEvictionMs: number;\n\tprivate readonly emptyExitMs: number;\n\tprivate readonly onEmptyExit?: () => void;\n\tprivate readonly canExitWhenEmpty?: () => boolean;\n\tprivate sweepTimer: ReturnType<typeof setInterval> | undefined;\n\tprivate emptySince: number | undefined;\n\n\tconstructor(\n\t\tregistry: RpcSessionRegistry,\n\t\twriter: SessionEventWriter,\n\t\tdefaults: Pick<RpcSessionLaunchProfile, \"cwd\" | \"permissionPreset\" | \"creationModel\" | \"initialThinkingLevel\">,\n\t\tcreateBinding: typeof createRpcSessionBinding = createRpcSessionBinding,\n\t\tconnectionOptions: Parameters<typeof createRpcSessionBinding>[4] = {},\n\t\tidle?: RpcSessionIdlePolicy,\n\t) {\n\t\tthis.registry = registry;\n\t\tthis.writer = writer;\n\t\tthis.defaults = defaults;\n\t\tthis.createBinding = createBinding;\n\t\tthis.connectionOptions = connectionOptions;\n\t\tthis.idleNow = idle?.now ?? Date.now;\n\t\tthis.idleEvictionMs = idle?.idleEvictionMs ?? Number.POSITIVE_INFINITY;\n\t\tthis.emptyExitMs = idle?.emptyExitMs ?? Number.POSITIVE_INFINITY;\n\t\tthis.onEmptyExit = idle?.onEmptyExit;\n\t\tthis.canExitWhenEmpty = idle?.canExitWhenEmpty;\n\t\tif (Number.isFinite(this.idleEvictionMs) || Number.isFinite(this.emptyExitMs)) {\n\t\t\t// Unref'd: occupancy hygiene must never be the reason the event loop stays open.\n\t\t\tconst tickMs = Math.max(20, Math.min(5_000, Math.min(this.idleEvictionMs, this.emptyExitMs) / 4));\n\t\t\tthis.sweepTimer = setInterval(() => this.sweepIdleSessions(), tickMs);\n\t\t\tthis.sweepTimer.unref?.();\n\t\t}\n\t}\n\n\tasync handle(command: RpcCommand): Promise<RpcResponse | undefined> {\n\t\tif (command.type === \"get_protocol_info\") {\n\t\t\tconst capabilities = new Set([\"multi_session\", ...(this.connectionOptions?.capabilities ?? [])]);\n\t\t\treturn {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"get_protocol_info\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tprotocolVersion: 1,\n\t\t\t\t\tserverVersion: VERSION,\n\t\t\t\t\tcapabilities: [...capabilities],\n\t\t\t\t\tmode: \"multi\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (command.type === \"list_sessions\")\n\t\t\treturn {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"list_sessions\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: { sessions: this.registry.list() },\n\t\t\t};\n\t\tif (command.type === \"open_session\") return this.openWithBarrier(command);\n\t\tif (command.type === \"close_session\") return this.close(command);\n\t\tif (command.type === \"set_client_info\" && !command.sessionId) {\n\t\t\tconst connection = this.writer.currentConnection();\n\t\t\tif (connection !== undefined) {\n\t\t\t\tthis.pendingCapabilities.set(connection, command.capabilities ?? []);\n\t\t\t\tthis.writer.setConnectionCapabilities(connection, command.capabilities ?? []);\n\t\t\t}\n\t\t\treturn { id: command.id, type: \"response\", command: \"set_client_info\", success: true } as RpcResponse;\n\t\t}\n\t\tif (controls.has(command.type)) return undefined;\n\t\tif (!command.sessionId) return error(command.id, command.type, RPC_ERROR_MISSING_SESSION_ID);\n\t\ttry {\n\t\t\tthis.registry.getForCommand(command.sessionId, command.type);\n\t\t\tconst binding = this.bindings.get(command.sessionId);\n\t\t\tif (!binding) return error(command.id, command.type, RPC_ERROR_UNKNOWN_SESSION);\n\t\t\tawait binding.handle(command);\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\treturn error(command.id, command.type, this.code(cause));\n\t\t}\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tthis.stopSweep();\n\t\tawait Promise.all(\n\t\t\t[...this.bindings.entries()].map(async ([sessionId, binding]) => {\n\t\t\t\tlet entry: RpcSessionEntry | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tentry = this.registry.beginClose(sessionId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tif (entry.state === \"open\") {\n\t\t\t\t\t\twhile (entry.state === \"open\") entry = this.registry.beginClose(sessionId);\n\t\t\t\t\t}\n\t\t\t\t\tawait binding.dispose();\n\t\t\t\t} finally {\n\t\t\t\t\tthis.bindings.delete(sessionId);\n\t\t\t\t\tif (entry.state === \"closing\") await this.registry.closeMarked(sessionId);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t\tthis.bindings.clear();\n\t}\n\n\t/**\n\t * One occupancy sweep. Evicts open sessions idle longer than idleEvictionMs,\n\t * where \"idle\" is the COMPLETE session-owned activity contract\n\t * (`AgentSession.isSessionBusy`: agent run, bash, background terminal jobs and\n\t * other published wake sources, compaction, barrier-held session work) - busy\n\t * sessions restart their idle clock instead, so work that outlives a turn is\n\t * never killed. Fires onEmptyExit once the registry has STAYED empty for\n\t * emptyExitMs with the exit permitted; any live session or connected client\n\t * resets that window. Runs on an unref'd interval and is safe to call directly.\n\t */\n\tsweepIdleSessions(): void {\n\t\tconst now = this.idleNow();\n\t\tif (Number.isFinite(this.idleEvictionMs)) {\n\t\t\tfor (const { sessionId, status } of this.registry.list()) {\n\t\t\t\tif (status !== \"open\") continue;\n\t\t\t\tconst entry = this.registry.peek(sessionId);\n\t\t\t\tif (!entry) continue;\n\t\t\t\tif (entry.runtime?.session.isSessionBusy) {\n\t\t\t\t\t// Session-owned work defers eviction; the window restarts when it settles.\n\t\t\t\t\tentry.lastCommandAt = now;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (now - entry.lastCommandAt >= this.idleEvictionMs) void this.evictIdleSession(sessionId);\n\t\t\t}\n\t\t}\n\t\tif (Number.isFinite(this.emptyExitMs)) {\n\t\t\tif (this.registry.size === 0 && (this.canExitWhenEmpty?.() ?? true)) {\n\t\t\t\tif (this.emptySince === undefined) this.emptySince = now;\n\t\t\t\telse if (now - this.emptySince >= this.emptyExitMs) {\n\t\t\t\t\tthis.stopSweep();\n\t\t\t\t\tthis.onEmptyExit?.();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.emptySince = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Idle-session eviction: the same refcounted close sequence as an explicit\n\t * close_session, draining every attachment because eviction ends the shared\n\t * session, not one client's claim. Races with concurrent lifecycle paths are\n\t * tolerated the same way releaseOwnedSession tolerates them.\n\t */\n\tprivate async evictIdleSession(sessionId: string): Promise<void> {\n\t\tlet entry: RpcSessionEntry;\n\t\ttry {\n\t\t\tentry = this.registry.beginClose(sessionId);\n\t\t\twhile (entry.state === \"open\") entry = this.registry.beginClose(sessionId);\n\t\t} catch {\n\t\t\t// Raced with an explicit close; that path owns the entry now.\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tthis.bindings.get(sessionId)?.cancelPendingExtensionUiRequests?.();\n\t\t\tawait this.bindings.get(sessionId)?.dispose();\n\t\t} finally {\n\t\t\tthis.bindings.delete(sessionId);\n\t\t\tthis.forgetSessionOwnership(sessionId);\n\t\t\tif (entry.state === \"closing\") await this.registry.closeMarked(sessionId);\n\t\t\tthis.writer.closeSession(sessionId, {\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"close_session\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {},\n\t\t\t});\n\t\t\t// The runtime is disposed and routing handles are unique per process\n\t\t\t// epoch, so nothing can emit under this id again: drop the writer's\n\t\t\t// per-session bookkeeping instead of retaining it for the host's life.\n\t\t\tthis.writer.forgetSession(sessionId);\n\t\t}\n\t}\n\n\t/** Drops per-connection records for a handle the host closed on its own. */\n\tprivate forgetSessionOwnership(sessionId: string): void {\n\t\tfor (const [connection, owned] of this.sessionsByConnection) {\n\t\t\towned.delete(sessionId);\n\t\t\tif (owned.size === 0) this.sessionsByConnection.delete(connection);\n\t\t}\n\t\tthis.widths.delete(sessionId);\n\t}\n\n\tprivate stopSweep(): void {\n\t\tif (this.sweepTimer === undefined) return;\n\t\tclearInterval(this.sweepTimer);\n\t\tthis.sweepTimer = undefined;\n\t}\n\n\tprivate openWithBarrier(command: Extract<RpcCommand, { type: \"open_session\" }>): Promise<RpcResponse | undefined> {\n\t\tconst owner = this.writer.currentConnection();\n\t\tif (owner === undefined) return this.open(command);\n\t\tlet resolveBarrier!: () => void;\n\t\tconst barrier = new Promise<void>((resolve) => {\n\t\t\tresolveBarrier = resolve;\n\t\t});\n\t\tconst opens = this.opensByConnection.get(owner) ?? new Set<Promise<void>>();\n\t\topens.add(barrier);\n\t\tthis.opensByConnection.set(owner, opens);\n\t\treturn this.open(command, owner).finally(() => {\n\t\t\tresolveBarrier();\n\t\t\topens.delete(barrier);\n\t\t\tif (opens.size === 0) this.opensByConnection.delete(owner);\n\t\t});\n\t}\n\n\tprivate async open(\n\t\tcommand: Extract<RpcCommand, { type: \"open_session\" }>,\n\t\towner?: string,\n\t): Promise<RpcResponse | undefined> {\n\t\tlet opened: OpenRpcSession | undefined;\n\t\ttry {\n\t\t\topened = await this.registry.openSession({\n\t\t\t\tcwd: command.cwd ?? this.defaults.cwd,\n\t\t\t\tsessionPath: command.sessionPath,\n\t\t\t\tpermissionPreset: command.permissionPreset ?? this.defaults.permissionPreset,\n\t\t\t\tcreationModel:\n\t\t\t\t\tcommand.provider && command.modelId\n\t\t\t\t\t\t? { provider: command.provider, modelId: command.modelId }\n\t\t\t\t\t\t: this.defaults.creationModel,\n\t\t\t\tinitialThinkingLevel: command.thinkingLevel ?? this.defaults.initialThinkingLevel,\n\t\t\t});\n\t\t\tconst openedSession = opened;\n\t\t\tconst entry = this.registry.getForCommand(openedSession.sessionId, \"open_session\");\n\t\t\tif (owner !== undefined) {\n\t\t\t\tif (!this.writer.hasRegisteredConnectionCapabilities(owner))\n\t\t\t\t\tthis.writer.setConnectionCapabilities(\n\t\t\t\t\t\towner,\n\t\t\t\t\t\tthis.pendingCapabilities.get(owner) ?? this.connectionOptions?.capabilities ?? [],\n\t\t\t\t\t);\n\t\t\t\tthis.writer.attachConnectionToSession(owner, openedSession.sessionId);\n\t\t\t}\n\t\t\t// A client that dies without close_session (terminal closed, SIGKILL, dropped\n\t\t\t// SSH) still holds this handle's attachment and its path reservation. Remember\n\t\t\t// which connection owns it so releaseConnection() can close exactly that.\n\t\t\tif (owner !== undefined) {\n\t\t\t\tconst owned = this.sessionsByConnection.get(owner) ?? new Map<string, number>();\n\t\t\t\towned.set(openedSession.sessionId, (owned.get(openedSession.sessionId) ?? 0) + 1);\n\t\t\t\tthis.sessionsByConnection.set(owner, owned);\n\t\t\t}\n\t\t\tif (!this.bindings.has(openedSession.sessionId)) {\n\t\t\t\tthis.bindings.set(\n\t\t\t\t\topenedSession.sessionId,\n\t\t\t\t\tawait this.createBinding(\n\t\t\t\t\t\topenedSession.sessionId,\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tthis.writer,\n\t\t\t\t\t\t() => void this.close({ type: \"close_session\", sessionId: openedSession.sessionId }),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t...this.connectionOptions,\n\t\t\t\t\t\t\tcapabilities:\n\t\t\t\t\t\t\t\towner !== undefined\n\t\t\t\t\t\t\t\t\t? (this.pendingCapabilities.get(owner) ?? [])\n\t\t\t\t\t\t\t\t\t: this.connectionOptions?.capabilities,\n\t\t\t\t\t\t\tsharedWidth: {\n\t\t\t\t\t\t\t\tgetWidth: () => {\n\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId);\n\t\t\t\t\t\t\t\t\treturn widths?.size ? Math.min(...widths.values()) : 80;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsetWidth: (connectionId, width) => {\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) {\n\t\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId) ?? new Map<string, number>();\n\t\t\t\t\t\t\t\t\t\twidths.set(connectionId, width);\n\t\t\t\t\t\t\t\t\t\tthis.widths.set(openedSession.sessionId, widths);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tclearWidth: (connectionId) => {\n\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId);\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) widths?.delete(connectionId);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsetCapabilities: (connectionId, capabilities) => {\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) {\n\t\t\t\t\t\t\t\t\t\tthis.writer.setConnectionCapabilities(connectionId, capabilities);\n\t\t\t\t\t\t\t\t\t\tthis.pendingCapabilities.set(connectionId, [...capabilities]);\n\t\t\t\t\t\t\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\thasRenderedComponents: (sessionId) => this.writer.hasCapableConnection(sessionId),\n\n\t\t\t\t\t\t\t\tconnectionId: () => this.writer.currentConnection(),\n\t\t\t\t\t\t\t\tonChange: () => {\n\t\t\t\t\t\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (owner !== undefined && this.releasedConnections.has(owner)) {\n\t\t\t\tawait this.releaseOwnedSession(openedSession.sessionId);\n\t\t\t}\n\t\t\tconst state = entry.runtime!.session;\n\t\t\tthis.writer.enqueue(opened.sessionId, {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"open_session\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tsessionId: opened.sessionId,\n\t\t\t\t\tstate: buildRpcSessionState(state),\n\t\t\t\t\t...(opened.attached ? { attached: true } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\tif (opened) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.registry.close(opened.sessionId);\n\t\t\t\t} catch {\n\t\t\t\t\t/* The open rollback has already removed the entry. */\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn error(command.id, \"open_session\", this.code(cause));\n\t\t}\n\t}\n\n\t/**\n\t * Releases every session a dropped connection still owned. Each handle goes through\n\t * the same refcounted close as an explicit close_session, so a session another\n\t * connection is still attached to keeps running and only the last owner tears it down.\n\t */\n\tasync releaseConnection(connectionId: string): Promise<void> {\n\t\tthis.releasedConnections.add(connectionId);\n\t\tthis.writer.clearConnectionCapabilities(connectionId);\n\t\tfor (const sessionId of this.sessionsByConnection.get(connectionId)?.keys() ?? [])\n\t\t\tthis.writer.detachConnectionFromSession(connectionId, sessionId);\n\t\tfor (const widths of this.widths.values()) widths.delete(connectionId);\n\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\tconst opens = this.opensByConnection.get(connectionId);\n\t\tif (opens) await Promise.all([...opens]);\n\t\tconst owned = this.sessionsByConnection.get(connectionId);\n\t\tthis.sessionsByConnection.delete(connectionId);\n\t\tif (owned === undefined) {\n\t\t\tthis.releasedConnections.delete(connectionId);\n\t\t\treturn;\n\t\t}\n\t\tfor (const [sessionId, count] of owned) {\n\t\t\tthis.bindings.get(sessionId)?.cancelPendingExtensionUiRequests?.();\n\t\t\tfor (let attachment = 0; attachment < count; attachment++) {\n\t\t\t\t// Headless completion contract: a turn survives its client's death and\n\t\t\t\t// runs to settlement (the host lifecycle keeps the process alive on\n\t\t\t\t// active turns even with zero connections). Releasing mid-turn aborts\n\t\t\t\t// the run and seals the session before agent_settled reaches the\n\t\t\t\t// lifecycle observer, leaking the busy counter so the host never\n\t\t\t\t// idle-exits. Defer - never skip - the release until the turn settles,\n\t\t\t\t// so the dropped owner's reservation still frees afterwards.\n\t\t\t\tconst live = this.registry.peek(sessionId);\n\t\t\t\tconst session = live?.state === \"open\" ? live.runtime?.session : undefined;\n\t\t\t\tif (session?.isStreaming) {\n\t\t\t\t\tlet released = false;\n\t\t\t\t\tconst unsubscribe = session.subscribe((event) => {\n\t\t\t\t\t\tif (event.type !== \"agent_settled\" && event.type !== \"agent_idle\") return;\n\t\t\t\t\t\tif (released) return;\n\t\t\t\t\t\treleased = true;\n\t\t\t\t\t\tunsubscribe();\n\t\t\t\t\t\tvoid this.releaseOwnedSession(sessionId).catch((cause) => {\n\t\t\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t\t\t`senpi rpc deferred release for session ${sessionId} failed: ${String(cause)}\\n`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tawait this.releaseOwnedSession(sessionId);\n\t\t\t}\n\t\t}\n\t\tthis.releasedConnections.delete(connectionId);\n\t}\n\n\t/**\n\t * One owned handle's refcounted close: the same sequence as an explicit\n\t * close_session, tolerant of races with other lifecycle paths (an entry\n\t * already closed or claimed elsewhere is simply skipped). Disposal and\n\t * binding removal happen only when this was the LAST attachment (the entry\n\t * transitioned to \"closing\"): surviving attachments keep the shared binding\n\t * and their event stream.\n\t */\n\tprivate async releaseOwnedSession(sessionId: string): Promise<void> {\n\t\tlet entry: RpcSessionEntry | undefined;\n\t\ttry {\n\t\t\tentry = this.registry.beginClose(sessionId);\n\t\t} catch {\n\t\t\t// Already closed or claimed by another lifecycle path; nothing to release.\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tif (entry.state === \"closing\") await this.bindings.get(sessionId)?.dispose();\n\t\t} finally {\n\t\t\tif (entry.state === \"closing\") {\n\t\t\t\tthis.bindings.delete(sessionId);\n\t\t\t\tawait this.registry.closeMarked(sessionId);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async close(command: Extract<RpcCommand, { type: \"close_session\" }>): Promise<RpcResponse | undefined> {\n\t\ttry {\n\t\t\t// This must be the first operation: binding.dispose() awaits teardown and\n\t\t\t// otherwise leaves a window where commands can enter the old handler.\n\t\t\tconst entry = this.registry.beginClose(command.sessionId);\n\t\t\tconst owner = this.writer.currentConnection();\n\t\t\tif (owner !== undefined) {\n\t\t\t\tthis.widths.get(command.sessionId)?.delete(owner);\n\t\t\t\tthis.writer.detachConnectionFromSession(owner, command.sessionId);\n\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t}\n\t\t\tif (owner !== undefined) {\n\t\t\t\tconst owned = this.sessionsByConnection.get(owner);\n\t\t\t\tconst count = owned?.get(command.sessionId);\n\t\t\t\tif (owned && count !== undefined) {\n\t\t\t\t\tif (count === 1) owned.delete(command.sessionId);\n\t\t\t\t\telse owned.set(command.sessionId, count - 1);\n\t\t\t\t\tif (owned.size === 0) this.sessionsByConnection.delete(owner);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst response = {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\" as const,\n\t\t\t\tcommand: \"close_session\" as const,\n\t\t\t\tsuccess: true as const,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tif (entry.state === \"closing\") await this.bindings.get(command.sessionId)?.dispose();\n\t\t\t} finally {\n\t\t\t\tif (entry.state === \"closing\") {\n\t\t\t\t\tthis.bindings.delete(command.sessionId);\n\t\t\t\t\tawait this.registry.closeMarked(command.sessionId);\n\t\t\t\t\tthis.writer.closeSession(command.sessionId, response);\n\t\t\t\t} else {\n\t\t\t\t\tthis.writer.enqueue(command.sessionId, response);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\treturn error(command.id, \"close_session\", this.code(cause));\n\t\t}\n\t}\n\n\tprivate code(cause: unknown): string {\n\t\tif (cause instanceof RpcSessionRegistryError) {\n\t\t\treturn cause.code === RPC_ERROR_OPEN_FAILED ? cause.message : cause.code;\n\t\t}\n\t\tif (cause instanceof Error && [RPC_ERROR_UNKNOWN_SESSION, RPC_ERROR_SESSION_CLOSING].includes(cause.message)) {\n\t\t\treturn cause.message;\n\t\t}\n\t\treturn cause instanceof Error && cause.message\n\t\t\t? `${RPC_ERROR_OPEN_FAILED}: ${cause.message}`\n\t\t\t: RPC_ERROR_UNKNOWN_SESSION;\n\t}\n}\n"]}
1
+ {"version":3,"file":"session-command-router.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-command-router.ts"],"names":[],"mappings":"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","sourcesContent":["import { VERSION } from \"../../config.ts\";\nimport { buildRpcSessionState } from \"./connection-handler.ts\";\nimport { AUTO_TITLE_SESSIONS_CAPABILITY } from \"./custom-capability.ts\";\nimport type { RpcCommand, RpcResponse } from \"./rpc-types.ts\";\nimport {\n\tRPC_ERROR_MISSING_SESSION_ID,\n\tRPC_ERROR_OPEN_FAILED,\n\tRPC_ERROR_SESSION_CLOSING,\n\tRPC_ERROR_UNKNOWN_SESSION,\n} from \"./rpc-types.ts\";\nimport { createRpcSessionBinding, type RpcSessionBinding } from \"./session-binding.ts\";\nimport type { SessionEventWriter } from \"./session-event-writer.ts\";\nimport type {\n\tOpenRpcSession,\n\tRpcSessionEntry,\n\tRpcSessionLaunchProfile,\n\tRpcSessionRegistry,\n} from \"./session-registry.ts\";\nimport { RpcSessionRegistryError } from \"./session-registry.ts\";\n\nconst controls = new Set([\"get_protocol_info\", \"open_session\", \"close_session\", \"list_sessions\"]);\n\n/** Binding factory seam, injectable so host wiring is testable without a full runtime stack. */\nexport type RpcBindingFactory = typeof createRpcSessionBinding;\n\n/**\n * Occupancy policy for the shared multi-session host. All fields are opt-in:\n * a router constructed without a policy keeps today's behavior (sessions live\n * until close_session; the host never self-exits).\n */\nexport interface RpcSessionIdlePolicy {\n\t/** Injectable clock (defaults to Date.now) for deterministic tests. */\n\tnow?: () => number;\n\t/** Evict open sessions whose last routed command or session-owned work settled longer ago than this. */\n\tidleEvictionMs?: number;\n\t/** Invoke onEmptyExit once the registry has stayed empty for this long. */\n\temptyExitMs?: number;\n\t/** Host shutdown hook fired by the empty-exit window; called at most once. */\n\tonEmptyExit?: () => void;\n\t/**\n\t * Consulted every tick before the empty-exit window advances. Returning false\n\t * both blocks the exit and resets the window, so a host with a connected but\n\t * sessionless client stays up instead of exiting under its supervisor.\n\t */\n\tcanExitWhenEmpty?: () => boolean;\n}\n\nfunction error(id: string | undefined, command: string, code: string): RpcResponse {\n\treturn { id, type: \"response\", command, success: false, error: code };\n}\n\n/** Routes control messages and enforces a routing handle for every session command. */\nexport class SessionCommandRouter {\n\tprivate readonly bindings = new Map<string, RpcSessionBinding>();\n\t/** Session handles opened by each connection, with one count per attachment. */\n\tprivate readonly sessionsByConnection = new Map<string, Map<string, number>>();\n\t/** Opens currently awaiting runtime/binding setup, keyed by connection. */\n\tprivate readonly opensByConnection = new Map<string, Set<Promise<void>>>();\n\t/** Connections whose socket has already been detached. */\n\tprivate readonly releasedConnections = new Set<string>();\n\tprivate readonly registry: RpcSessionRegistry;\n\tprivate readonly writer: SessionEventWriter;\n\tprivate readonly defaults: Pick<\n\t\tRpcSessionLaunchProfile,\n\t\t\"cwd\" | \"permissionPreset\" | \"creationModel\" | \"initialThinkingLevel\"\n\t>;\n\tprivate readonly createBinding: typeof createRpcSessionBinding;\n\tprivate readonly connectionOptions: Parameters<typeof createRpcSessionBinding>[4];\n\tprivate readonly widths = new Map<string, Map<string, number>>();\n\tprivate readonly pendingCapabilities = new Map<string, string[]>();\n\tprivate readonly idleNow: () => number;\n\tprivate readonly idleEvictionMs: number;\n\tprivate readonly emptyExitMs: number;\n\tprivate readonly onEmptyExit?: () => void;\n\tprivate readonly canExitWhenEmpty?: () => boolean;\n\tprivate sweepTimer: ReturnType<typeof setInterval> | undefined;\n\tprivate emptySince: number | undefined;\n\n\tconstructor(\n\t\tregistry: RpcSessionRegistry,\n\t\twriter: SessionEventWriter,\n\t\tdefaults: Pick<RpcSessionLaunchProfile, \"cwd\" | \"permissionPreset\" | \"creationModel\" | \"initialThinkingLevel\">,\n\t\tcreateBinding: typeof createRpcSessionBinding = createRpcSessionBinding,\n\t\tconnectionOptions: Parameters<typeof createRpcSessionBinding>[4] = {},\n\t\tidle?: RpcSessionIdlePolicy,\n\t) {\n\t\tthis.registry = registry;\n\t\tthis.writer = writer;\n\t\tthis.defaults = defaults;\n\t\tthis.createBinding = createBinding;\n\t\tthis.connectionOptions = connectionOptions;\n\t\tthis.idleNow = idle?.now ?? Date.now;\n\t\tthis.idleEvictionMs = idle?.idleEvictionMs ?? Number.POSITIVE_INFINITY;\n\t\tthis.emptyExitMs = idle?.emptyExitMs ?? Number.POSITIVE_INFINITY;\n\t\tthis.onEmptyExit = idle?.onEmptyExit;\n\t\tthis.canExitWhenEmpty = idle?.canExitWhenEmpty;\n\t\tif (Number.isFinite(this.idleEvictionMs) || Number.isFinite(this.emptyExitMs)) {\n\t\t\t// Unref'd: occupancy hygiene must never be the reason the event loop stays open.\n\t\t\tconst tickMs = Math.max(20, Math.min(5_000, Math.min(this.idleEvictionMs, this.emptyExitMs) / 4));\n\t\t\tthis.sweepTimer = setInterval(() => this.sweepIdleSessions(), tickMs);\n\t\t\tthis.sweepTimer.unref?.();\n\t\t}\n\t}\n\n\tasync handle(command: RpcCommand): Promise<RpcResponse | undefined> {\n\t\tif (command.type === \"get_protocol_info\") {\n\t\t\tconst capabilities = new Set([\n\t\t\t\t\"multi_session\",\n\t\t\t\tAUTO_TITLE_SESSIONS_CAPABILITY,\n\t\t\t\t...(this.connectionOptions?.capabilities ?? []),\n\t\t\t]);\n\t\t\treturn {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"get_protocol_info\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tprotocolVersion: 1,\n\t\t\t\t\tserverVersion: VERSION,\n\t\t\t\t\tcapabilities: [...capabilities],\n\t\t\t\t\tmode: \"multi\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (command.type === \"list_sessions\")\n\t\t\treturn {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"list_sessions\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: { sessions: this.registry.list() },\n\t\t\t};\n\t\tif (command.type === \"open_session\") return this.openWithBarrier(command);\n\t\tif (command.type === \"close_session\") return this.close(command);\n\t\tif (command.type === \"set_client_info\" && !command.sessionId) {\n\t\t\tconst connection = this.writer.currentConnection();\n\t\t\tif (connection !== undefined) {\n\t\t\t\tthis.pendingCapabilities.set(connection, command.capabilities ?? []);\n\t\t\t\tthis.writer.setConnectionCapabilities(connection, command.capabilities ?? []);\n\t\t\t}\n\t\t\treturn { id: command.id, type: \"response\", command: \"set_client_info\", success: true } as RpcResponse;\n\t\t}\n\t\tif (controls.has(command.type)) return undefined;\n\t\tif (!command.sessionId) return error(command.id, command.type, RPC_ERROR_MISSING_SESSION_ID);\n\t\ttry {\n\t\t\tthis.registry.getForCommand(command.sessionId, command.type);\n\t\t\tconst binding = this.bindings.get(command.sessionId);\n\t\t\tif (!binding) return error(command.id, command.type, RPC_ERROR_UNKNOWN_SESSION);\n\t\t\tawait binding.handle(command);\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\treturn error(command.id, command.type, this.code(cause));\n\t\t}\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tthis.stopSweep();\n\t\tawait Promise.all(\n\t\t\t[...this.bindings.entries()].map(async ([sessionId, binding]) => {\n\t\t\t\tlet entry: RpcSessionEntry | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tentry = this.registry.beginClose(sessionId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tif (entry.state === \"open\") {\n\t\t\t\t\t\twhile (entry.state === \"open\") entry = this.registry.beginClose(sessionId);\n\t\t\t\t\t}\n\t\t\t\t\tawait binding.dispose();\n\t\t\t\t} finally {\n\t\t\t\t\tthis.bindings.delete(sessionId);\n\t\t\t\t\tif (entry.state === \"closing\") await this.registry.closeMarked(sessionId);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t\tthis.bindings.clear();\n\t}\n\n\t/**\n\t * One occupancy sweep. Evicts open sessions idle longer than idleEvictionMs,\n\t * where \"idle\" is the COMPLETE session-owned activity contract\n\t * (`AgentSession.isSessionBusy`: agent run, bash, background terminal jobs and\n\t * other published wake sources, compaction, barrier-held session work) - busy\n\t * sessions restart their idle clock instead, so work that outlives a turn is\n\t * never killed. Fires onEmptyExit once the registry has STAYED empty for\n\t * emptyExitMs with the exit permitted; any live session or connected client\n\t * resets that window. Runs on an unref'd interval and is safe to call directly.\n\t */\n\tsweepIdleSessions(): void {\n\t\tconst now = this.idleNow();\n\t\tif (Number.isFinite(this.idleEvictionMs)) {\n\t\t\tfor (const { sessionId, status } of this.registry.list()) {\n\t\t\t\tif (status !== \"open\") continue;\n\t\t\t\tconst entry = this.registry.peek(sessionId);\n\t\t\t\tif (!entry) continue;\n\t\t\t\tif (entry.runtime?.session.isSessionBusy) {\n\t\t\t\t\t// Session-owned work defers eviction; the window restarts when it settles.\n\t\t\t\t\tentry.lastCommandAt = now;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (now - entry.lastCommandAt >= this.idleEvictionMs) void this.evictIdleSession(sessionId);\n\t\t\t}\n\t\t}\n\t\tif (Number.isFinite(this.emptyExitMs)) {\n\t\t\tif (this.registry.size === 0 && (this.canExitWhenEmpty?.() ?? true)) {\n\t\t\t\tif (this.emptySince === undefined) this.emptySince = now;\n\t\t\t\telse if (now - this.emptySince >= this.emptyExitMs) {\n\t\t\t\t\tthis.stopSweep();\n\t\t\t\t\tthis.onEmptyExit?.();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.emptySince = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Idle-session eviction: the same refcounted close sequence as an explicit\n\t * close_session, draining every attachment because eviction ends the shared\n\t * session, not one client's claim. Races with concurrent lifecycle paths are\n\t * tolerated the same way releaseOwnedSession tolerates them.\n\t */\n\tprivate async evictIdleSession(sessionId: string): Promise<void> {\n\t\tlet entry: RpcSessionEntry;\n\t\ttry {\n\t\t\tentry = this.registry.beginClose(sessionId);\n\t\t\twhile (entry.state === \"open\") entry = this.registry.beginClose(sessionId);\n\t\t} catch {\n\t\t\t// Raced with an explicit close; that path owns the entry now.\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tthis.bindings.get(sessionId)?.cancelPendingExtensionUiRequests?.();\n\t\t\tawait this.bindings.get(sessionId)?.dispose();\n\t\t} finally {\n\t\t\tthis.bindings.delete(sessionId);\n\t\t\tthis.forgetSessionOwnership(sessionId);\n\t\t\tif (entry.state === \"closing\") await this.registry.closeMarked(sessionId);\n\t\t\tthis.writer.closeSession(sessionId, {\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"close_session\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {},\n\t\t\t});\n\t\t\t// The runtime is disposed and routing handles are unique per process\n\t\t\t// epoch, so nothing can emit under this id again: drop the writer's\n\t\t\t// per-session bookkeeping instead of retaining it for the host's life.\n\t\t\tthis.writer.forgetSession(sessionId);\n\t\t}\n\t}\n\n\t/** Drops per-connection records for a handle the host closed on its own. */\n\tprivate forgetSessionOwnership(sessionId: string): void {\n\t\tfor (const [connection, owned] of this.sessionsByConnection) {\n\t\t\towned.delete(sessionId);\n\t\t\tif (owned.size === 0) this.sessionsByConnection.delete(connection);\n\t\t}\n\t\tthis.widths.delete(sessionId);\n\t}\n\n\tprivate stopSweep(): void {\n\t\tif (this.sweepTimer === undefined) return;\n\t\tclearInterval(this.sweepTimer);\n\t\tthis.sweepTimer = undefined;\n\t}\n\n\tprivate openWithBarrier(command: Extract<RpcCommand, { type: \"open_session\" }>): Promise<RpcResponse | undefined> {\n\t\tconst owner = this.writer.currentConnection();\n\t\tif (owner === undefined) return this.open(command);\n\t\tlet resolveBarrier!: () => void;\n\t\tconst barrier = new Promise<void>((resolve) => {\n\t\t\tresolveBarrier = resolve;\n\t\t});\n\t\tconst opens = this.opensByConnection.get(owner) ?? new Set<Promise<void>>();\n\t\topens.add(barrier);\n\t\tthis.opensByConnection.set(owner, opens);\n\t\treturn this.open(command, owner).finally(() => {\n\t\t\tresolveBarrier();\n\t\t\topens.delete(barrier);\n\t\t\tif (opens.size === 0) this.opensByConnection.delete(owner);\n\t\t});\n\t}\n\n\tprivate async open(\n\t\tcommand: Extract<RpcCommand, { type: \"open_session\" }>,\n\t\towner?: string,\n\t): Promise<RpcResponse | undefined> {\n\t\tlet opened: OpenRpcSession | undefined;\n\t\ttry {\n\t\t\topened = await this.registry.openSession({\n\t\t\t\tcwd: command.cwd ?? this.defaults.cwd,\n\t\t\t\tsessionPath: command.sessionPath,\n\t\t\t\tpermissionPreset: command.permissionPreset ?? this.defaults.permissionPreset,\n\t\t\t\tcreationModel:\n\t\t\t\t\tcommand.provider && command.modelId\n\t\t\t\t\t\t? { provider: command.provider, modelId: command.modelId }\n\t\t\t\t\t\t: this.defaults.creationModel,\n\t\t\t\tinitialThinkingLevel: command.thinkingLevel ?? this.defaults.initialThinkingLevel,\n\t\t\t});\n\t\t\tconst openedSession = opened;\n\t\t\tconst entry = this.registry.getForCommand(openedSession.sessionId, \"open_session\");\n\t\t\tif (owner !== undefined) {\n\t\t\t\tif (!this.writer.hasRegisteredConnectionCapabilities(owner))\n\t\t\t\t\tthis.writer.setConnectionCapabilities(\n\t\t\t\t\t\towner,\n\t\t\t\t\t\tthis.pendingCapabilities.get(owner) ?? this.connectionOptions?.capabilities ?? [],\n\t\t\t\t\t);\n\t\t\t\tthis.writer.attachConnectionToSession(owner, openedSession.sessionId);\n\t\t\t}\n\t\t\t// A client that dies without close_session (terminal closed, SIGKILL, dropped\n\t\t\t// SSH) still holds this handle's attachment and its path reservation. Remember\n\t\t\t// which connection owns it so releaseConnection() can close exactly that.\n\t\t\tif (owner !== undefined) {\n\t\t\t\tconst owned = this.sessionsByConnection.get(owner) ?? new Map<string, number>();\n\t\t\t\towned.set(openedSession.sessionId, (owned.get(openedSession.sessionId) ?? 0) + 1);\n\t\t\t\tthis.sessionsByConnection.set(owner, owned);\n\t\t\t}\n\t\t\tif (!this.bindings.has(openedSession.sessionId)) {\n\t\t\t\tthis.bindings.set(\n\t\t\t\t\topenedSession.sessionId,\n\t\t\t\t\tawait this.createBinding(\n\t\t\t\t\t\topenedSession.sessionId,\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tthis.writer,\n\t\t\t\t\t\t() => void this.close({ type: \"close_session\", sessionId: openedSession.sessionId }),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t...this.connectionOptions,\n\t\t\t\t\t\t\tcapabilities:\n\t\t\t\t\t\t\t\towner !== undefined\n\t\t\t\t\t\t\t\t\t? (this.pendingCapabilities.get(owner) ?? this.connectionOptions?.capabilities ?? [])\n\t\t\t\t\t\t\t\t\t: this.connectionOptions?.capabilities,\n\t\t\t\t\t\t\tsharedWidth: {\n\t\t\t\t\t\t\t\tgetWidth: () => {\n\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId);\n\t\t\t\t\t\t\t\t\treturn widths?.size ? Math.min(...widths.values()) : 80;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsetWidth: (connectionId, width) => {\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) {\n\t\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId) ?? new Map<string, number>();\n\t\t\t\t\t\t\t\t\t\twidths.set(connectionId, width);\n\t\t\t\t\t\t\t\t\t\tthis.widths.set(openedSession.sessionId, widths);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tclearWidth: (connectionId) => {\n\t\t\t\t\t\t\t\t\tconst widths = this.widths.get(openedSession.sessionId);\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) widths?.delete(connectionId);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsetCapabilities: (connectionId, capabilities) => {\n\t\t\t\t\t\t\t\t\tif (connectionId !== undefined) {\n\t\t\t\t\t\t\t\t\t\tthis.writer.setConnectionCapabilities(connectionId, capabilities);\n\t\t\t\t\t\t\t\t\t\tthis.pendingCapabilities.set(connectionId, [...capabilities]);\n\t\t\t\t\t\t\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\thasRenderedComponents: (sessionId) => this.writer.hasCapableConnection(sessionId),\n\n\t\t\t\t\t\t\t\tconnectionId: () => this.writer.currentConnection(),\n\t\t\t\t\t\t\t\tonChange: () => {\n\t\t\t\t\t\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (owner !== undefined && this.releasedConnections.has(owner)) {\n\t\t\t\tawait this.releaseOwnedSession(openedSession.sessionId);\n\t\t\t}\n\t\t\tconst state = entry.runtime!.session;\n\t\t\tthis.writer.enqueue(opened.sessionId, {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"open_session\",\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tsessionId: opened.sessionId,\n\t\t\t\t\tstate: buildRpcSessionState(state),\n\t\t\t\t\t...(opened.attached ? { attached: true } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\tif (opened) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.registry.close(opened.sessionId);\n\t\t\t\t} catch {\n\t\t\t\t\t/* The open rollback has already removed the entry. */\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn error(command.id, \"open_session\", this.code(cause));\n\t\t}\n\t}\n\n\t/**\n\t * Releases every session a dropped connection still owned. Each handle goes through\n\t * the same refcounted close as an explicit close_session, so a session another\n\t * connection is still attached to keeps running and only the last owner tears it down.\n\t */\n\tasync releaseConnection(connectionId: string): Promise<void> {\n\t\tthis.releasedConnections.add(connectionId);\n\t\tthis.writer.clearConnectionCapabilities(connectionId);\n\t\tfor (const sessionId of this.sessionsByConnection.get(connectionId)?.keys() ?? [])\n\t\t\tthis.writer.detachConnectionFromSession(connectionId, sessionId);\n\t\tfor (const widths of this.widths.values()) widths.delete(connectionId);\n\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\tconst opens = this.opensByConnection.get(connectionId);\n\t\tif (opens) await Promise.all([...opens]);\n\t\tconst owned = this.sessionsByConnection.get(connectionId);\n\t\tthis.sessionsByConnection.delete(connectionId);\n\t\tif (owned === undefined) {\n\t\t\tthis.releasedConnections.delete(connectionId);\n\t\t\treturn;\n\t\t}\n\t\tfor (const [sessionId, count] of owned) {\n\t\t\tthis.bindings.get(sessionId)?.cancelPendingExtensionUiRequests?.();\n\t\t\tfor (let attachment = 0; attachment < count; attachment++) {\n\t\t\t\t// Headless completion contract: a turn survives its client's death and\n\t\t\t\t// runs to settlement (the host lifecycle keeps the process alive on\n\t\t\t\t// active turns even with zero connections). Releasing mid-turn aborts\n\t\t\t\t// the run and seals the session before agent_settled reaches the\n\t\t\t\t// lifecycle observer, leaking the busy counter so the host never\n\t\t\t\t// idle-exits. Defer - never skip - the release until the turn settles,\n\t\t\t\t// so the dropped owner's reservation still frees afterwards.\n\t\t\t\tconst live = this.registry.peek(sessionId);\n\t\t\t\tconst session = live?.state === \"open\" ? live.runtime?.session : undefined;\n\t\t\t\tif (session?.isStreaming) {\n\t\t\t\t\tlet released = false;\n\t\t\t\t\tconst unsubscribe = session.subscribe((event) => {\n\t\t\t\t\t\tif (event.type !== \"agent_settled\" && event.type !== \"agent_idle\") return;\n\t\t\t\t\t\tif (released) return;\n\t\t\t\t\t\treleased = true;\n\t\t\t\t\t\tunsubscribe();\n\t\t\t\t\t\tvoid this.releaseOwnedSession(sessionId).catch((cause) => {\n\t\t\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t\t\t`senpi rpc deferred release for session ${sessionId} failed: ${String(cause)}\\n`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tawait this.releaseOwnedSession(sessionId);\n\t\t\t}\n\t\t}\n\t\tthis.releasedConnections.delete(connectionId);\n\t}\n\n\t/**\n\t * One owned handle's refcounted close: the same sequence as an explicit\n\t * close_session, tolerant of races with other lifecycle paths (an entry\n\t * already closed or claimed elsewhere is simply skipped). Disposal and\n\t * binding removal happen only when this was the LAST attachment (the entry\n\t * transitioned to \"closing\"): surviving attachments keep the shared binding\n\t * and their event stream.\n\t */\n\tprivate async releaseOwnedSession(sessionId: string): Promise<void> {\n\t\tlet entry: RpcSessionEntry | undefined;\n\t\ttry {\n\t\t\tentry = this.registry.beginClose(sessionId);\n\t\t} catch {\n\t\t\t// Already closed or claimed by another lifecycle path; nothing to release.\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tif (entry.state === \"closing\") await this.bindings.get(sessionId)?.dispose();\n\t\t} finally {\n\t\t\tif (entry.state === \"closing\") {\n\t\t\t\tthis.bindings.delete(sessionId);\n\t\t\t\tawait this.registry.closeMarked(sessionId);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async close(command: Extract<RpcCommand, { type: \"close_session\" }>): Promise<RpcResponse | undefined> {\n\t\ttry {\n\t\t\t// This must be the first operation: binding.dispose() awaits teardown and\n\t\t\t// otherwise leaves a window where commands can enter the old handler.\n\t\t\tconst entry = this.registry.beginClose(command.sessionId);\n\t\t\tconst owner = this.writer.currentConnection();\n\t\t\tif (owner !== undefined) {\n\t\t\t\tthis.widths.get(command.sessionId)?.delete(owner);\n\t\t\t\tthis.writer.detachConnectionFromSession(owner, command.sessionId);\n\t\t\t\tfor (const binding of this.bindings.values()) binding.rerenderComponents?.();\n\t\t\t}\n\t\t\tif (owner !== undefined) {\n\t\t\t\tconst owned = this.sessionsByConnection.get(owner);\n\t\t\t\tconst count = owned?.get(command.sessionId);\n\t\t\t\tif (owned && count !== undefined) {\n\t\t\t\t\tif (count === 1) owned.delete(command.sessionId);\n\t\t\t\t\telse owned.set(command.sessionId, count - 1);\n\t\t\t\t\tif (owned.size === 0) this.sessionsByConnection.delete(owner);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst response = {\n\t\t\t\tid: command.id,\n\t\t\t\ttype: \"response\" as const,\n\t\t\t\tcommand: \"close_session\" as const,\n\t\t\t\tsuccess: true as const,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tif (entry.state === \"closing\") await this.bindings.get(command.sessionId)?.dispose();\n\t\t\t} finally {\n\t\t\t\tif (entry.state === \"closing\") {\n\t\t\t\t\tthis.bindings.delete(command.sessionId);\n\t\t\t\t\tawait this.registry.closeMarked(command.sessionId);\n\t\t\t\t\tthis.writer.closeSession(command.sessionId, response);\n\t\t\t\t} else {\n\t\t\t\t\tthis.writer.enqueue(command.sessionId, response);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t} catch (cause) {\n\t\t\treturn error(command.id, \"close_session\", this.code(cause));\n\t\t}\n\t}\n\n\tprivate code(cause: unknown): string {\n\t\tif (cause instanceof RpcSessionRegistryError) {\n\t\t\treturn cause.code === RPC_ERROR_OPEN_FAILED ? cause.message : cause.code;\n\t\t}\n\t\tif (cause instanceof Error && [RPC_ERROR_UNKNOWN_SESSION, RPC_ERROR_SESSION_CLOSING].includes(cause.message)) {\n\t\t\treturn cause.message;\n\t\t}\n\t\treturn cause instanceof Error && cause.message\n\t\t\t? `${RPC_ERROR_OPEN_FAILED}: ${cause.message}`\n\t\t\t: RPC_ERROR_UNKNOWN_SESSION;\n\t}\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import type { Socket } from "node:net";
2
+ export declare const SOCKET_SECRET_BYTES = 32;
3
+ export declare const SOCKET_SECRET_SUFFIX = ".secret";
4
+ export declare const SOCKET_SECRET_FILE_ENV = "SENPI_RPC_SOCKET_SECRET_FILE";
5
+ export declare const SOCKET_HANDSHAKE_TIMEOUT_MS = 2000;
6
+ export declare function socketSecretPath(logicalPath: string): string;
7
+ export declare function ensureSocketSecret(path: string): Promise<Buffer>;
8
+ export declare function createSocketSecret(path: string): Promise<Buffer>;
9
+ export declare function readSocketSecret(path: string): Promise<Buffer>;
10
+ export declare function resolveSocketTransportAddress(socketPath: string, platform: NodeJS.Platform, secret?: Uint8Array): string;
11
+ export declare function authenticateSocket(socket: Socket, secret: Uint8Array, onAuthenticated: () => void): void;
12
+ export declare function sendSocketHandshake(socket: Socket, secret: Uint8Array): void;
13
+ //# sourceMappingURL=socket-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket-transport.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/socket-transport.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAIvC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAC9C,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AACrE,eAAO,MAAM,2BAA2B,OAAQ,CAAC;AAEjD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAO5D;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQtE;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtE;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIpE;AAED,wBAAgB,6BAA6B,CAC5C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,MAAM,CAAC,EAAE,UAAU,GACjB,MAAM,CAUR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,IAAI,GAAG,IAAI,CA8BxG;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAE5E"}
@@ -0,0 +1,92 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
+ import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { dirname, win32 } from "node:path";
4
+ const WINDOWS_PIPE_PREFIX = "\\\\.\\pipe\\senpi-rpc-";
5
+ export const SOCKET_SECRET_BYTES = 32;
6
+ export const SOCKET_SECRET_SUFFIX = ".secret";
7
+ export const SOCKET_SECRET_FILE_ENV = "SENPI_RPC_SOCKET_SECRET_FILE";
8
+ export const SOCKET_HANDSHAKE_TIMEOUT_MS = 2_000;
9
+ export function socketSecretPath(logicalPath) {
10
+ if (logicalPath.toLowerCase().startsWith("\\\\.\\pipe\\")) {
11
+ throw new Error(`Windows RPC named-pipe addresses need a logical filesystem path for their secret: ${logicalPath}`);
12
+ }
13
+ return `${logicalPath}${SOCKET_SECRET_SUFFIX}`;
14
+ }
15
+ export async function ensureSocketSecret(path) {
16
+ try {
17
+ const existing = await readFile(path);
18
+ if (existing.length === SOCKET_SECRET_BYTES)
19
+ return existing;
20
+ }
21
+ catch (error) {
22
+ if (!isNodeErrorCode(error, "ENOENT"))
23
+ throw error;
24
+ }
25
+ return createSocketSecret(path);
26
+ }
27
+ export async function createSocketSecret(path) {
28
+ await mkdir(dirname(path), { recursive: true });
29
+ const secret = randomBytes(SOCKET_SECRET_BYTES);
30
+ await writeFile(path, secret, { mode: 0o600 });
31
+ await chmod(path, 0o600);
32
+ return secret;
33
+ }
34
+ export async function readSocketSecret(path) {
35
+ const secret = await readFile(path);
36
+ if (secret.length !== SOCKET_SECRET_BYTES)
37
+ throw new Error(`invalid RPC socket secret: ${path}`);
38
+ return secret;
39
+ }
40
+ export function resolveSocketTransportAddress(socketPath, platform, secret) {
41
+ if (platform !== "win32")
42
+ return socketPath;
43
+ if (socketPath.toLowerCase().startsWith("\\\\.\\pipe\\"))
44
+ return socketPath;
45
+ if (!/^[a-zA-Z]:[\\/]/.test(socketPath) && !/^\\\\[^/]/.test(socketPath)) {
46
+ throw new Error(`Windows RPC socket path must be drive-qualified or UNC: ${socketPath}`);
47
+ }
48
+ const canonical = win32.normalize(socketPath).toLowerCase();
49
+ const identity = Buffer.concat([Buffer.from(canonical, "utf8"), Buffer.from(secret ?? [])]);
50
+ const name = createHash("sha256").update(identity).digest("hex").slice(0, 32);
51
+ return `${WINDOWS_PIPE_PREFIX}${name}`;
52
+ }
53
+ export function authenticateSocket(socket, secret, onAuthenticated) {
54
+ let received = Buffer.alloc(0);
55
+ const finish = () => {
56
+ clearTimeout(timer);
57
+ socket.off("data", onData);
58
+ socket.off("error", onError);
59
+ };
60
+ const onError = () => {
61
+ finish();
62
+ socket.destroy();
63
+ };
64
+ const timer = setTimeout(() => {
65
+ finish();
66
+ socket.destroy();
67
+ }, SOCKET_HANDSHAKE_TIMEOUT_MS);
68
+ const onData = (chunk) => {
69
+ received = Buffer.concat([received, chunk]);
70
+ if (received.length < secret.length)
71
+ return;
72
+ finish();
73
+ if (!timingSafeEqual(received.subarray(0, secret.length), Buffer.from(secret))) {
74
+ socket.destroy();
75
+ return;
76
+ }
77
+ const remainder = received.subarray(secret.length);
78
+ if (remainder.length > 0)
79
+ socket.unshift(remainder);
80
+ onAuthenticated();
81
+ };
82
+ socket.on("data", onData);
83
+ socket.once("error", onError);
84
+ socket.once("close", finish);
85
+ }
86
+ export function sendSocketHandshake(socket, secret) {
87
+ socket.write(Buffer.from(secret));
88
+ }
89
+ function isNodeErrorCode(error, code) {
90
+ return error instanceof Error && "code" in error && error.code === code;
91
+ }
92
+ //# sourceMappingURL=socket-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket-transport.js","sourceRoot":"","sources":["../../../src/modes/rpc/socket-transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { chmod, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport type { Socket } from \"node:net\";\nimport { dirname, win32 } from \"node:path\";\n\nconst WINDOWS_PIPE_PREFIX = \"\\\\\\\\.\\\\pipe\\\\senpi-rpc-\";\nexport const SOCKET_SECRET_BYTES = 32;\nexport const SOCKET_SECRET_SUFFIX = \".secret\";\nexport const SOCKET_SECRET_FILE_ENV = \"SENPI_RPC_SOCKET_SECRET_FILE\";\nexport const SOCKET_HANDSHAKE_TIMEOUT_MS = 2_000;\n\nexport function socketSecretPath(logicalPath: string): string {\n\tif (logicalPath.toLowerCase().startsWith(\"\\\\\\\\.\\\\pipe\\\\\")) {\n\t\tthrow new Error(\n\t\t\t`Windows RPC named-pipe addresses need a logical filesystem path for their secret: ${logicalPath}`,\n\t\t);\n\t}\n\treturn `${logicalPath}${SOCKET_SECRET_SUFFIX}`;\n}\n\nexport async function ensureSocketSecret(path: string): Promise<Buffer> {\n\ttry {\n\t\tconst existing = await readFile(path);\n\t\tif (existing.length === SOCKET_SECRET_BYTES) return existing;\n\t} catch (error: unknown) {\n\t\tif (!isNodeErrorCode(error, \"ENOENT\")) throw error;\n\t}\n\treturn createSocketSecret(path);\n}\n\nexport async function createSocketSecret(path: string): Promise<Buffer> {\n\tawait mkdir(dirname(path), { recursive: true });\n\tconst secret = randomBytes(SOCKET_SECRET_BYTES);\n\tawait writeFile(path, secret, { mode: 0o600 });\n\tawait chmod(path, 0o600);\n\treturn secret;\n}\n\nexport async function readSocketSecret(path: string): Promise<Buffer> {\n\tconst secret = await readFile(path);\n\tif (secret.length !== SOCKET_SECRET_BYTES) throw new Error(`invalid RPC socket secret: ${path}`);\n\treturn secret;\n}\n\nexport function resolveSocketTransportAddress(\n\tsocketPath: string,\n\tplatform: NodeJS.Platform,\n\tsecret?: Uint8Array,\n): string {\n\tif (platform !== \"win32\") return socketPath;\n\tif (socketPath.toLowerCase().startsWith(\"\\\\\\\\.\\\\pipe\\\\\")) return socketPath;\n\tif (!/^[a-zA-Z]:[\\\\/]/.test(socketPath) && !/^\\\\\\\\[^/]/.test(socketPath)) {\n\t\tthrow new Error(`Windows RPC socket path must be drive-qualified or UNC: ${socketPath}`);\n\t}\n\tconst canonical = win32.normalize(socketPath).toLowerCase();\n\tconst identity = Buffer.concat([Buffer.from(canonical, \"utf8\"), Buffer.from(secret ?? [])]);\n\tconst name = createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 32);\n\treturn `${WINDOWS_PIPE_PREFIX}${name}`;\n}\n\nexport function authenticateSocket(socket: Socket, secret: Uint8Array, onAuthenticated: () => void): void {\n\tlet received = Buffer.alloc(0);\n\tconst finish = (): void => {\n\t\tclearTimeout(timer);\n\t\tsocket.off(\"data\", onData);\n\t\tsocket.off(\"error\", onError);\n\t};\n\tconst onError = (): void => {\n\t\tfinish();\n\t\tsocket.destroy();\n\t};\n\tconst timer = setTimeout(() => {\n\t\tfinish();\n\t\tsocket.destroy();\n\t}, SOCKET_HANDSHAKE_TIMEOUT_MS);\n\tconst onData = (chunk: Buffer): void => {\n\t\treceived = Buffer.concat([received, chunk]);\n\t\tif (received.length < secret.length) return;\n\t\tfinish();\n\t\tif (!timingSafeEqual(received.subarray(0, secret.length), Buffer.from(secret))) {\n\t\t\tsocket.destroy();\n\t\t\treturn;\n\t\t}\n\t\tconst remainder = received.subarray(secret.length);\n\t\tif (remainder.length > 0) socket.unshift(remainder);\n\t\tonAuthenticated();\n\t};\n\tsocket.on(\"data\", onData);\n\tsocket.once(\"error\", onError);\n\tsocket.once(\"close\", finish);\n}\n\nexport function sendSocketHandshake(socket: Socket, secret: Uint8Array): void {\n\tsocket.write(Buffer.from(secret));\n}\n\nfunction isNodeErrorCode(error: unknown, code: string): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === code;\n}\n"]}
@@ -116,7 +116,7 @@ The bundled `model-fallback` extension registers `/fallback` to manage global pe
116
116
  Use the quick-set form in scripts or any non-TUI mode:
117
117
 
118
118
  ```text
119
- /fallback anthropic/claude-fable-5 ccapi/kimi-k3:max
119
+ /fallback anthropic/claude-fable-5-1 ccapi/kimi-k3:max
120
120
  ```
121
121
 
122
122
  The first argument is the exact primary model selector; each later argument is an ordered fallback selector. Quick-set validates selectors before saving. At least one fallback is required:
package/docs/rpc.md CHANGED
@@ -49,7 +49,7 @@ Multi-session mode lets one `senpi --mode rpc` process serve several independent
49
49
  # Shared JSONL over stdio (legacy multi-session host)
50
50
  senpi --mode rpc --multi-session [options]
51
51
 
52
- # One shared host over a Unix socket; each accepted connection has its own JSONL feed
52
+ # One shared host over a local socket; each accepted connection has its own JSONL feed
53
53
  senpi --mode rpc --listen unix:///tmp/senpi-rpc.sock [options]
54
54
  senpi --mode rpc --listen /tmp/senpi-rpc.sock [options]
55
55
  ```
@@ -58,6 +58,10 @@ senpi --mode rpc --listen /tmp/senpi-rpc.sock [options]
58
58
  `unix://@name` where supported by the host platform. Socket mode accepts concurrent connections while retaining one
59
59
  process-global session registry.
60
60
 
61
+ On Windows, listeners and clients deterministically map the logical socket path to
62
+ `\\.\pipe\senpi-rpc-<sha256[:32]>`. Callers keep using the same `unix://` CLI value; the logical path remains the
63
+ ownership and settings identity, and callers never construct the pipe name themselves.
64
+
61
65
  Socket event visibility is an all-sessions broadcast: every connected client receives lifecycle and agent events from
62
66
  every open session, each tagged with its routing `sessionId`. Correlated responses and extension UI requests are sent
63
67
  only to the connection that issued the command. This lets a non-owner observe a foreign turn without requiring a
package/docs/settings.md CHANGED
@@ -87,7 +87,7 @@ Permission rules are a confirmation policy, not a sandbox. Senpi, extensions, pa
87
87
  | `modelThinkingLevels` | object | - | Per-model reasoning effort memory (`"provider/id": "level"`) |
88
88
  | `modelLastOnThinkingLevels` | object | - | Per-model last non-off reasoning level, used by `/reasoning on` to restore the previous effort |
89
89
  | `modelServiceTiers` | object | - | Per-model service tier memory (`"provider/id": "auto" \| "priority"`) |
90
- | `promptPreset` | string | `"auto"` | Force a system prompt preset: `"auto"`, `"kimi-k2-6"`, `"kimi-k2-7"`, `"kimi-k3"`, `"glm-5.2"`, `"glm-5.3"`, `"grok-4.5"`, `"grok-4.6"`, `"claude-fable-5"`, `"claude-opus-5"`, `"claude-opus-4-5"`, `"claude-opus-4-6"`, `"claude-opus-4-7"`, `"claude-opus-4-8"`, `"deepseek-v4-flash"`, `"deepseek-v4-flash-0731"`, `"deepseek-v4-pro"`, `"gpt-5"`, `"gpt-5.2"`, `"gpt-5.3-codex"`, `"gpt-5.4"`, `"gpt-5.5"`, or `"gpt-5.6"` |
90
+ | `promptPreset` | string | `"auto"` | Force a system prompt preset: `"auto"`, `"kimi-k2-6"`, `"kimi-k2-7"`, `"kimi-k3"`, `"glm-5.2"`, `"glm-5.3"`, `"grok-4.5"`, `"grok-4.6"`, `"claude-fable-5"`, `"claude-fable-5-1"`, `"claude-opus-5"`, `"claude-opus-4-5"`, `"claude-opus-4-6"`, `"claude-opus-4-7"`, `"claude-opus-4-8"`, `"deepseek-v4-flash"`, `"deepseek-v4-flash-0731"`, `"deepseek-v4-pro"`, `"gpt-5"`, `"gpt-5.2"`, `"gpt-5.3-codex"`, `"gpt-5.4"`, `"gpt-5.5"`, or `"gpt-5.6"` |
91
91
  | `hideThinkingBlock` | boolean | `false` | Hide thinking blocks in output |
92
92
  | `showCacheMissNotices` | boolean | `false` | Show transcript notices for significant prompt-cache misses and compaction or branch-summary usage |
93
93
  | `thinkingBudgets` | object | - | Custom token budgets per thinking level. Anthropic, Google, and Bedrock use these natively. OpenAI-compatible models use them when `compat.thinkingTokenBudgetField` (or `supportsThinkingTokenBudget`) is set. |
@@ -251,14 +251,14 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
251
251
 
252
252
  #### Model fallback chains
253
253
 
254
- `retry.fallbackChains` maps a primary-model selector to an ordered list of fallback selectors. A selector is `provider/model` with an optional `:thinking-level` suffix, or a bare `model` id that applies to every provider serving that model family. Bare selectors expand against the models you actually have: providers holding an OAuth credential are preferred, then a fixed precedence order, and OpenRouter is never chosen by expansion. Senpi ships a bare default chain for `claude-fable-5`, so Fable 5 keeps a fallback chain whichever provider serves it; set that key to `[]` to opt out entirely, or set one `provider/claude-fable-5` key to override just that provider. For example, this switches Fable 5 to Kimi K3 at `max` thinking when an eligible failure occurs:
254
+ `retry.fallbackChains` maps a primary-model selector to an ordered list of fallback selectors. A selector is `provider/model` with an optional `:thinking-level` suffix, or a bare `model` id that applies to every provider serving that model family. Bare selectors expand against the models you actually have: providers holding an OAuth credential are preferred, then a fixed precedence order, and OpenRouter is never chosen by expansion. Senpi ships bare default chains for `claude-fable-5-1` and `claude-fable-5`, so Fable 5.1 and Fable 5 keep a fallback chain whichever provider serves them; set a key to `[]` to opt out entirely, or set one `provider/claude-fable-5-1` key to override just that provider. For example, this switches Fable 5.1 to Kimi K3 at `max` thinking when an eligible failure occurs:
255
255
 
256
256
  ```json
257
257
  {
258
258
  "retry": {
259
259
  "modelFallback": true,
260
260
  "fallbackChains": {
261
- "anthropic/claude-fable-5": ["ccapi/kimi-k3:max"]
261
+ "anthropic/claude-fable-5-1": ["ccapi/kimi-k3:max"]
262
262
  },
263
263
  "fallbackRevertPolicy": "cooldown-expiry"
264
264
  }
@@ -488,7 +488,7 @@ When multiple sources specify a session directory, precedence is `--session-dir`
488
488
  {
489
489
  "modelThinkingLevels": {
490
490
  "openai-codex/gpt-5.6-sol": "xhigh",
491
- "anthropic/claude-fable-5": "high"
491
+ "anthropic/claude-fable-5-1": "high"
492
492
  },
493
493
  "modelServiceTiers": {
494
494
  "openai-codex/gpt-5.6-sol": "priority"
@@ -12,6 +12,18 @@
12
12
 
13
13
  ### Removed
14
14
 
15
+ ## [2026.9.2] - 2026-09-02
16
+
17
+ ### Breaking Changes
18
+
19
+ ### Added
20
+
21
+ ### Changed
22
+
23
+ ### Fixed
24
+
25
+ ### Removed
26
+
15
27
  ## [2026.8.31] - 2026-08-31
16
28
 
17
29
  ### Breaking Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-codemode",
3
- "version": "2026.8.31",
3
+ "version": "2026.9.2",
4
4
  "private": true,
5
5
  "description": "Source-only senpi extension package for codemode evaluation tools",
6
6
  "type": "module",
@@ -31,14 +31,14 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@babel/parser": "8.0.4",
34
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.31",
34
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.2",
35
35
  "typebox": "1.3.18"
36
36
  },
37
37
  "peerDependencies": {
38
- "@code-yeongyu/senpi": "2026.8.31"
38
+ "@code-yeongyu/senpi": "2026.9.2"
39
39
  },
40
40
  "devDependencies": {
41
- "@code-yeongyu/senpi": "2026.8.31"
41
+ "@code-yeongyu/senpi": "2026.9.2"
42
42
  },
43
43
  "keywords": [
44
44
  "senpi",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-agent-core",
3
- "version": "2026.8.31",
3
+ "version": "2026.9.2",
4
4
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,8 +35,8 @@
35
35
  "prepublishOnly": "npm run build"
36
36
  },
37
37
  "dependencies": {
38
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.31",
39
- "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.8.31",
38
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.2",
39
+ "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.9.2",
40
40
  "diff": "9.0.0",
41
41
  "ignore": "7.0.6",
42
42
  "typebox": "1.3.18",
@@ -1 +1 @@
1
- {"schemaVersion":3,"generatedAt":"2026-08-31T10:39:26.168Z","structureHash":"42a16ca3140cc92369bae0cb178bc2cf49393735be1b4c2f50d4ba77fa25b38c","files":{"alibaba-token-plan.json":"9f9e8f88b1faa2e4134a0d8bcda600531d4d044d64b7ec3d2373f1db46dcf452","amazon-bedrock.json":"eb1770cb9edee5efb9646da27043a83cc80fa5e186dce60fcafa681222b794c2","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"8c1136a83a3b1ff0e61ab461ee221b1de7680784e774a60e1520af14a44bb0f1","azure-openai-responses.json":"37d12c5cbfc29bfd9a802a0516f5d3209320bd4aa8ef9cd7c219af208244afa3","baseten.json":"e4d1ec84e8180a53e21c1511b8d78e497784515c33ba8397382ac3450c8b126e","cerebras.json":"38272a7525d6680c71bb4bb3c4085e871768b400832e2013b0e7fd92f8fd4f05","cloudflare-ai-gateway.json":"eea26bf03ac54766119422ebfe05306b1878ae1cd36dac6a60fe35fe81505139","cloudflare-workers-ai.json":"07ef63208ff7517fd1a80962f18143e21de399640423329490b157f459ccf995","deepseek.json":"e3106724723fd82d48a3ff685da9908a3a7b7b4fd84cc3cfe97a6a23067b6029","fireworks.json":"8fb5603f5ae17716c4f6ed5bba6c7f298a12018a219f57625634f762895e3b2a","github-copilot.json":"61dec9e46df61a9b0bf6c7618651f97bfa9ae609d4c216b5725f014942ca3001","google-vertex.json":"fb7586fc955da7b7d7d11d641954f496fbbb42cf3e4cbba66d7116ea3b37d5ed","google.json":"b5572904165d37ab594eafc3ab7f29774e35747b5dd211144ec01532db9217c1","groq.json":"f1eb899453e70b5e4479fe6eb78869ee99121fa6d4a019a5a05ab42d2ada8992","huggingface.json":"7616a851e53d254e375b760abe2b6148e8961a102bd5c7af31829a0f2dc8e5c5","kimi-coding.json":"88150f8970f83e17968b02f3b33fac803b96ebf1474e76437689b7d0f1b69363","minimax-cn.json":"65d37e55a6d9585855f94b3fb7739308d107fe248ebd9e1001d1c5d4606ad2c4","minimax.json":"c7dc5765995ae77242916430929c7cc9a782589f7e483e13f7e01663190d028e","mistral.json":"e3a109306644bf2f2fa38fece50b2d3ce1dbe3b87b1f1b9e2d70cce7eb5c0ea1","moonshotai-cn.json":"dbf1b71ee36812fe64b014177ff455809a8dd852bbbd584422645beb85635127","moonshotai.json":"2d7518b4769e97ac900366175c8b60ff86a02675bb6f6cc2fffcc6761fda6faa","nvidia.json":"62fa810bece1c90454b481db5a3ff78bc66dc28dab9c65a655397eb1dfe2de73","openai-codex.json":"4e4afe2929b2b20a751f2453b219deae4e5b9fd85e147bd0403601f183cfc15f","openai.json":"b014fb0676fec97264eb13b367b0ed73b99915f45410a3dd9a7397a0360c2a4b","opencode-go.json":"a8dc563e15a0b6b5e18b0461d5fe11493d6c6a30f49ea7d156bf20fbe70063d2","opencode.json":"130ffcf96618d0fea5309fe33409a166d666bdb003d24035e91db1c69adc10f8","opengateway.json":"1702a5df9877110c4d71a6ff3760cd10b378bfbd32d6322c05ce59dc1cc0f8e4","openrouter.json":"0d3fb223ecefe1b3e1eda21cc946cf5a751b355be0f68742cd4c2d81aab9604d","qwen-token-plan-cn.json":"e62dde34edb603376a1dc60b2a74a9c2605b9e81d81df55cc259796c45aa4793","qwen-token-plan-individual.json":"5649fd4075ada766ec65a7a162cd65f096a7ecc29960ace04b2e6a6a4a995a41","qwen-token-plan.json":"fe914313157ff41ab2f71977f0fdcfedb3a8a205d1092e3180f6799e5d7942fd","together.json":"6010980c9b0af72c60965ae325dbdb21e67c91844a7f7f6f7d71d363f1325f56","vercel-ai-gateway.json":"01092cf08d1d1e416183cb6e5c5170fa32c27ee9d24577105bfbeea3e3c6d492","xai.json":"9973aae022723732b8a7ea12107e6fb8b3f1d0e087ec6bbc2ee18f0820595e19","xiaomi-token-plan-ams.json":"568b9992cf320536a65826e26a414afa5c0d17f083a01af4bd96658d9dd3e705","xiaomi-token-plan-cn.json":"c423857d0bbb0b126394eaf1ebb2a91bf2d1193cc5a4fe77843ff0f4536a0a80","xiaomi-token-plan-sgp.json":"008f1eb41037e93c5ae478f12815cd67bac1978f131ffefa602775bb60b63fea","xiaomi.json":"37acf451bb4364bdca2ecea6b7d962590d9974a87e80cfe34bb800be6a95c13b","zai-coding-cn.json":"d3c969020a7ab978497837a3301c7bca364d704082832221cfe61e6596333e56","zai.json":"f42790c77fb4681a656897a9d860b939916c0ddf979a5f16856bce9573cdf64e"}}
1
+ {"schemaVersion":3,"generatedAt":"2026-09-02T01:24:02.206Z","structureHash":"51f715c896ccbb82371f283a7c7ce3b89e3a56f25e773de098b77153b157b2cc","files":{"alibaba-token-plan.json":"9f9e8f88b1faa2e4134a0d8bcda600531d4d044d64b7ec3d2373f1db46dcf452","amazon-bedrock.json":"c86cdf3eb28122f8682415543012feee0a84dd4a30f03b784dfffde92b0d69f4","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"c5c043d7daef4e179d0c1288683b63e52a88efa581edc9201f327ddefd27265c","azure-openai-responses.json":"37d12c5cbfc29bfd9a802a0516f5d3209320bd4aa8ef9cd7c219af208244afa3","baseten.json":"e4d1ec84e8180a53e21c1511b8d78e497784515c33ba8397382ac3450c8b126e","cerebras.json":"38272a7525d6680c71bb4bb3c4085e871768b400832e2013b0e7fd92f8fd4f05","cloudflare-ai-gateway.json":"eea26bf03ac54766119422ebfe05306b1878ae1cd36dac6a60fe35fe81505139","cloudflare-workers-ai.json":"07ef63208ff7517fd1a80962f18143e21de399640423329490b157f459ccf995","deepseek.json":"e3106724723fd82d48a3ff685da9908a3a7b7b4fd84cc3cfe97a6a23067b6029","fireworks.json":"9f5e2459853520d1892a2d262a51448f12f12fb8a45286b2db52e6228ba29699","github-copilot.json":"61dec9e46df61a9b0bf6c7618651f97bfa9ae609d4c216b5725f014942ca3001","google-vertex.json":"fb7586fc955da7b7d7d11d641954f496fbbb42cf3e4cbba66d7116ea3b37d5ed","google.json":"229ae10bd6964cb3dc567270117c8bbd0bfa28075a516041fb5d78836a6ecfbf","groq.json":"e4728fd72e358cd8f25e9a518e9b49a521ef44523d3debe38a7db9e0663c4077","huggingface.json":"7616a851e53d254e375b760abe2b6148e8961a102bd5c7af31829a0f2dc8e5c5","kimi-coding.json":"88150f8970f83e17968b02f3b33fac803b96ebf1474e76437689b7d0f1b69363","minimax-cn.json":"65d37e55a6d9585855f94b3fb7739308d107fe248ebd9e1001d1c5d4606ad2c4","minimax.json":"c7dc5765995ae77242916430929c7cc9a782589f7e483e13f7e01663190d028e","mistral.json":"e3a109306644bf2f2fa38fece50b2d3ce1dbe3b87b1f1b9e2d70cce7eb5c0ea1","moonshotai-cn.json":"dbf1b71ee36812fe64b014177ff455809a8dd852bbbd584422645beb85635127","moonshotai.json":"2d7518b4769e97ac900366175c8b60ff86a02675bb6f6cc2fffcc6761fda6faa","nvidia.json":"ebb630b4a43d4a30d4163a23d6d49bd60c661c2b8f8c1d5b4862ad5b77ece28f","openai-codex.json":"4e4afe2929b2b20a751f2453b219deae4e5b9fd85e147bd0403601f183cfc15f","openai.json":"b014fb0676fec97264eb13b367b0ed73b99915f45410a3dd9a7397a0360c2a4b","opencode-go.json":"a8dc563e15a0b6b5e18b0461d5fe11493d6c6a30f49ea7d156bf20fbe70063d2","opencode.json":"130ffcf96618d0fea5309fe33409a166d666bdb003d24035e91db1c69adc10f8","opengateway.json":"2b1e34bf67f5e43a89a68188d39fe4c8fc4d83f5f7c6ef4b3348836fa867d3e0","openrouter.json":"4dd66ae03a49f9e626ea38c2288b0d685513f5bc73699eb972050fd71f2cdb9a","qwen-token-plan-cn.json":"e62dde34edb603376a1dc60b2a74a9c2605b9e81d81df55cc259796c45aa4793","qwen-token-plan-individual.json":"5649fd4075ada766ec65a7a162cd65f096a7ecc29960ace04b2e6a6a4a995a41","qwen-token-plan.json":"fe914313157ff41ab2f71977f0fdcfedb3a8a205d1092e3180f6799e5d7942fd","together.json":"6010980c9b0af72c60965ae325dbdb21e67c91844a7f7f6f7d71d363f1325f56","vercel-ai-gateway.json":"8391f60b55890c8ea07aae15887e04539c1fdc089b2bf2eeaaccb39eb4ea8d9e","xai.json":"9973aae022723732b8a7ea12107e6fb8b3f1d0e087ec6bbc2ee18f0820595e19","xiaomi-token-plan-ams.json":"568b9992cf320536a65826e26a414afa5c0d17f083a01af4bd96658d9dd3e705","xiaomi-token-plan-cn.json":"c423857d0bbb0b126394eaf1ebb2a91bf2d1193cc5a4fe77843ff0f4536a0a80","xiaomi-token-plan-sgp.json":"008f1eb41037e93c5ae478f12815cd67bac1978f131ffefa602775bb60b63fea","xiaomi.json":"37acf451bb4364bdca2ecea6b7d962590d9974a87e80cfe34bb800be6a95c13b","zai-coding-cn.json":"d3c969020a7ab978497837a3301c7bca364d704082832221cfe61e6596333e56","zai.json":"f42790c77fb4681a656897a9d860b939916c0ddf979a5f16856bce9573cdf64e"}}