@code-yeongyu/senpi 2026.9.17-2 → 2026.9.17-4
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/CHANGELOG.md +49 -0
- package/dist/bundle/chunks/{app-server-command-XSPV6BRF.js → app-server-command-RTISWAJY.js} +1 -1
- package/dist/bundle/chunks/{chunk-PLUQUK3T.js → chunk-IM4UIHPI.js} +15 -15
- package/dist/bundle/chunks/{chunk-ESZHT7IE.js → chunk-IMTGM3RJ.js} +1 -1
- package/dist/bundle/chunks/chunk-OQGI752B.js +2 -0
- package/dist/bundle/chunks/{chunk-Z56RXBL6.js → chunk-QDR3GME3.js} +2 -2
- package/dist/bundle/chunks/{chunk-ZPO5FWHM.js → chunk-QILSJ5PQ.js} +2 -2
- package/dist/bundle/chunks/{chunk-IGKWKAMN.js → chunk-XHTF6VKZ.js} +4 -3
- package/dist/bundle/chunks/chunk-YD5QZXAK.js +8 -0
- package/dist/bundle/chunks/{cli-main-L7WQP5V6.js → cli-main-TO3O4TUE.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-O6MBSNMK.js → help-fast-path-LFGHCIWO.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-AI7NH6ZO.js → host-lifecycle-YPVGQSGS.js} +1 -1
- package/dist/bundle/chunks/{interactive-host-runtime-DKJKH5DU.js → interactive-host-runtime-KZLF3AZD.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-FUW5LNKL.js → interactive-mode-ARGRH6QZ.js} +1 -1
- package/dist/bundle/chunks/multi-session-host-HIZZTSYU.js +20 -0
- package/dist/bundle/chunks/{package-manager-cli-J26DB6GM.js → package-manager-cli-544JIWNJ.js} +1 -1
- package/dist/bundle/chunks/rotation-stream-FSZVBG2T.js +2 -0
- package/dist/bundle/chunks/{rpc-mode-A3U63XX7.js → rpc-mode-S3IEBFEB.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +71 -68
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts +19 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +27 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +14 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/auth-storage.js +2 -2
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/credential-pool/rotation-stream.d.ts.map +1 -1
- package/dist/core/credential-pool/rotation-stream.js +10 -5
- package/dist/core/credential-pool/rotation-stream.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/index.js +11 -0
- package/dist/core/extensions/builtin/mcp/index.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.d.ts +9 -0
- package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.js +14 -1
- package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/startup-race.d.ts +20 -0
- package/dist/core/extensions/builtin/mcp/startup-race.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/startup-race.js +38 -1
- package/dist/core/extensions/builtin/mcp/startup-race.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +9 -4
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +20 -9
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +37 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +8 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +2 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +21 -35
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +3 -2
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-runtime.d.ts +4 -2
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +9 -5
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/provider-api-key-auth.js +3 -3
- package/dist/core/provider-api-key-auth.js.map +1 -1
- package/dist/core/provider-composer.d.ts +9 -3
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +7 -4
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/resolve-config-command.d.ts +10 -0
- package/dist/core/resolve-config-command.d.ts.map +1 -0
- package/dist/core/resolve-config-command.js +106 -0
- package/dist/core/resolve-config-command.js.map +1 -0
- package/dist/core/resolve-config-value.d.ts +4 -8
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +16 -105
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +7 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +13 -9
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/main.d.ts +5 -3
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +25 -11
- package/dist/main.js.map +1 -1
- package/dist/modes/rpc/child-reaper-syscalls.d.ts +18 -0
- package/dist/modes/rpc/child-reaper-syscalls.d.ts.map +1 -0
- package/dist/modes/rpc/child-reaper-syscalls.js +136 -0
- package/dist/modes/rpc/child-reaper-syscalls.js.map +1 -0
- package/dist/modes/rpc/child-reaper.d.ts +56 -0
- package/dist/modes/rpc/child-reaper.d.ts.map +1 -0
- package/dist/modes/rpc/child-reaper.js +140 -0
- package/dist/modes/rpc/child-reaper.js.map +1 -0
- package/dist/modes/rpc/custom-capability.d.ts +16 -0
- package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
- package/dist/modes/rpc/custom-capability.js +16 -0
- package/dist/modes/rpc/custom-capability.js.map +1 -1
- package/dist/modes/rpc/host-memory-sampler.d.ts +48 -0
- package/dist/modes/rpc/host-memory-sampler.d.ts.map +1 -0
- package/dist/modes/rpc/host-memory-sampler.js +72 -0
- package/dist/modes/rpc/host-memory-sampler.js.map +1 -0
- package/dist/modes/rpc/loop-lag-watchdog.d.ts +51 -0
- package/dist/modes/rpc/loop-lag-watchdog.d.ts.map +1 -0
- package/dist/modes/rpc/loop-lag-watchdog.js +78 -0
- package/dist/modes/rpc/loop-lag-watchdog.js.map +1 -0
- package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +34 -0
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +4 -2
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +2 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.d.ts +28 -0
- package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.js +63 -0
- package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +18 -5
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +18 -5
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +79 -2
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +6 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-attribution.d.ts +57 -0
- package/dist/modes/rpc/session-attribution.d.ts.map +1 -0
- package/dist/modes/rpc/session-attribution.js +132 -0
- package/dist/modes/rpc/session-attribution.js.map +1 -0
- package/dist/modes/rpc/session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/session-binding.js +19 -8
- package/dist/modes/rpc/session-binding.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts +26 -3
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +95 -19
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-event-fanout.d.ts +2 -0
- package/dist/modes/rpc/session-event-fanout.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-fanout.js +6 -0
- package/dist/modes/rpc/session-event-fanout.js.map +1 -1
- package/dist/modes/rpc/session-event-writer.d.ts +29 -0
- package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-writer.js +57 -0
- package/dist/modes/rpc/session-event-writer.js.map +1 -1
- package/dist/modes/rpc/session-registry.d.ts +42 -9
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js +49 -3
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/dist/modes/rpc/worker-session-registry.d.ts +2 -10
- package/dist/modes/rpc/worker-session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/worker-session-registry.js +6 -2
- package/dist/modes/rpc/worker-session-registry.js.map +1 -1
- package/docs/rpc.md +126 -20
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@earendil-works/pi-agent-core/assets/tree-sitter/javascript.wasm +0 -0
- package/node_modules/@earendil-works/pi-agent-core/assets/tree-sitter/provenance.json +22 -0
- package/node_modules/@earendil-works/pi-agent-core/assets/tree-sitter/web-tree-sitter.wasm +0 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/dist/bundle/chunks/chunk-3Q5PD4KW.js +0 -8
- package/dist/bundle/chunks/chunk-YLYLKL7X.js +0 -2
- package/dist/bundle/chunks/multi-session-host-SMNZXFPT.js +0 -18
- package/dist/bundle/chunks/rotation-stream-SCVFIQ2O.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-event-writer.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-event-writer.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { MEDIA_PLACEHOLDERS_CAPABILITY } from \"./custom-capability.ts\";\nimport { serializeJsonLine } from \"./jsonl.ts\";\nimport { omitInlineMedia } from \"./media-placeholders.ts\";\nimport {\n\tRENDERED_COMPONENT_RECORD,\n\tSessionEventFanout,\n\ttype SessionEventWriterConnection,\n} from \"./session-event-fanout.ts\";\nimport type { SocketEventSinkActor } from \"./socket-event-fanout.ts\";\n\nexport { RENDERED_COMPONENT_RECORD, type SessionEventWriterConnection } from \"./session-event-fanout.ts\";\n\n/** Await every actor's drain; a failed actor is a cut peer, not a writer failure. */\nconst settleActors = (actors: readonly SocketEventSinkActor[]): Promise<void> =>\n\tPromise.all(actors.map((actor) => actor.flush().catch(() => undefined))).then(() => undefined);\n\n/** Await every actor's ACCEPTANCE of what it was given; never the peer's kernel drain. */\nconst acceptActors = (actors: readonly SocketEventSinkActor[]): Promise<void> =>\n\tPromise.all(actors.map((actor) => actor.waitForAcceptance())).then(() => undefined);\n\ntype RawWriter = (chunk: string) => void;\ntype BackpressureWaiter = () => Promise<void>;\ntype FlushScheduler = (flush: () => Promise<void>) => void;\ntype RpcRecord = Record<string, unknown>;\ntype CompactDeltaType = \"text_delta\" | \"thinking_delta\" | \"toolcall_delta\";\n\ntype QueueNode = {\n\tvalue: RpcRecord;\n\tkey?: string;\n\tprevious?: QueueNode;\n\tnext?: QueueNode;\n\tresolve?: () => void;\n\treject?: (cause: unknown) => void;\n};\n\ntype RecordQueue = {\n\tsessionId?: string;\n\ttargetId?: string;\n\thead?: QueueNode;\n\ttail?: QueueNode;\n\tlatestByKey: Map<string, QueueNode>;\n\tready: boolean;\n};\n\nexport const MAX_SHARED_STDIO_QUEUE_BYTES = 64 * 1024 * 1024;\nexport const MAX_SHARED_STDIO_QUEUE_RECORDS = 4096;\n\nconst MESSAGE_KEY = \"message\";\nconst COMPACT_DELTA_TYPES = new Set<CompactDeltaType>([\"text_delta\", \"thinking_delta\", \"toolcall_delta\"]);\n\nfunction compactDelta(value: RpcRecord): { type: CompactDeltaType; contentIndex: number; delta: string } | undefined {\n\tif (value.type !== \"message_update\" || !Object.hasOwn(value, \"message\")) return undefined;\n\tconst event = value.assistantMessageEvent;\n\tif (typeof event !== \"object\" || event === null) return undefined;\n\tconst typedEvent = event as Record<string, unknown>;\n\tif (\n\t\ttypeof typedEvent.type !== \"string\" ||\n\t\t!COMPACT_DELTA_TYPES.has(typedEvent.type as CompactDeltaType) ||\n\t\ttypeof typedEvent.contentIndex !== \"number\" ||\n\t\ttypeof typedEvent.delta !== \"string\"\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\ttype: typedEvent.type as CompactDeltaType,\n\t\tcontentIndex: typedEvent.contentIndex,\n\t\tdelta: typedEvent.delta,\n\t};\n}\n\n/** The delta-only form of a compact message_update: cumulative snapshot fields blanked, delta kept. */\nfunction demoteToDeltaOnly(value: RpcRecord): RpcRecord {\n\tconst event = value.assistantMessageEvent as Record<string, unknown>;\n\treturn { ...value, message: null, assistantMessageEvent: { ...event, partial: null } };\n}\n\nfunction toolUpdateKey(value: RpcRecord): string | undefined {\n\treturn value.type === \"tool_execution_update\" && typeof value.toolCallId === \"string\"\n\t\t? `tool:${value.toolCallId}`\n\t\t: undefined;\n}\n\n/**\n * Process-wide stdout scheduler for multi-session RPC mode.\n *\n * Each queue contains complete structured JSONL records for one routing handle.\n * Draining takes one record per queue in round-robin order and waits for stdout\n * backpressure before selecting the next one. A record is deliberately written\n * by itself: coalescing records from different sessions would obscure the\n * scheduling boundary and violate D9.\n */\nexport class SessionEventWriter {\n\tprivate readonly queues = new Map<string, RecordQueue>();\n\tprivate readonly fanout = new SessionEventFanout();\n\tprivate readonly connectionContext = new AsyncLocalStorage<string>();\n\tprivate readonly controlQueue: RecordQueue = { latestByKey: new Map(), ready: false };\n\tprivate readonly readyQueues: RecordQueue[] = [];\n\tprivate readonly sealedSessions = new Set<string>();\n\tprivate readonly writeRaw: RawWriter;\n\tprivate readonly waitForBackpressure?: BackpressureWaiter;\n\tprivate readonly scheduleFlush: FlushScheduler;\n\tprivate flushScheduled = false;\n\tprivate drainPromise?: Promise<void>;\n\tprivate inFlight?: { queue: RecordQueue; node: QueueNode };\n\tprivate failure?: unknown;\n\tprivate controlOverflowReported = false;\n\tprivate closeOverflowReported = false;\n\tprivate readonly closeOverflowActors = new WeakSet<SocketEventSinkActor>();\n\tprivate reservedCloseRecords = 0;\n\tprivate reservedCloseBytes = 0;\n\n\tget pendingCloseRecordCount(): number {\n\t\treturn this.reservedCloseRecords;\n\t}\n\n\tget pendingCloseByteLength(): number {\n\t\treturn this.reservedCloseBytes;\n\t}\n\n\tconstructor(writeRaw: RawWriter, scheduleFlush?: FlushScheduler);\n\tconstructor(writeRaw: RawWriter, waitForBackpressure: BackpressureWaiter, scheduleFlush?: FlushScheduler);\n\tconstructor(\n\t\twriteRaw: RawWriter,\n\t\twaitOrSchedule?: BackpressureWaiter | FlushScheduler,\n\t\tscheduleFlush?: FlushScheduler,\n\t) {\n\t\tthis.writeRaw = writeRaw;\n\t\tif (waitOrSchedule && scheduleFlush === undefined && waitOrSchedule.length > 0) {\n\t\t\tthis.scheduleFlush = waitOrSchedule as FlushScheduler;\n\t\t} else {\n\t\t\tthis.waitForBackpressure = waitOrSchedule as BackpressureWaiter | undefined;\n\t\t\tthis.scheduleFlush = scheduleFlush ?? ((flush) => queueMicrotask(() => void flush()));\n\t\t}\n\t}\n\n\tget bufferedRecordCount(): number {\n\t\tlet count = this.inFlight ? 1 : 0;\n\t\tfor (const queue of this.allQueues()) {\n\t\t\tfor (let node = queue.head; node; node = node.next) count++;\n\t\t}\n\t\treturn count;\n\t}\n\n\tget bufferedByteLength(): number {\n\t\tlet bytes = this.inFlight ? Buffer.byteLength(serializeJsonLine(this.inFlight.node.value)) : 0;\n\t\tfor (const queue of this.allQueues()) {\n\t\t\tfor (let node = queue.head; node; node = node.next) {\n\t\t\t\tbytes += Buffer.byteLength(serializeJsonLine(node.value));\n\t\t\t}\n\t\t}\n\t\treturn bytes;\n\t}\n\n\tregisterConnection(\n\t\tid: string,\n\t\tconnection: SessionEventWriterConnection,\n\t\toptions: { readonly maxQueueBytes?: number; readonly stallMs?: number } = {},\n\t): void {\n\t\tthis.fanout.registerConnection(id, connection, options);\n\t}\n\n\tunregisterConnection(id: string): void {\n\t\tthis.fanout.unregisterConnection(id);\n\t}\n\n\tattachConnectionToSession(id: string, sessionId: string): void {\n\t\tthis.fanout.attachConnectionToSession(id, sessionId);\n\t}\n\n\tdetachConnectionFromSession(id: string, sessionId: string): void {\n\t\tthis.fanout.detachConnectionFromSession(id, sessionId);\n\t}\n\n\tsetConnectionCapabilities(id: string, capabilities: readonly string[]): void {\n\t\tthis.fanout.setConnectionCapabilities(id, capabilities);\n\t}\n\n\tclearConnectionCapabilities(id: string): void {\n\t\tthis.fanout.clearConnectionCapabilities(id);\n\t}\n\n\thasRegisteredConnectionCapabilities(id: string): boolean {\n\t\treturn this.fanout.hasRegisteredConnectionCapabilities(id);\n\t}\n\n\tgetConnectionCapabilities(id: string): readonly string[] | undefined {\n\t\treturn this.fanout.getConnectionCapabilities(id);\n\t}\n\n\thasCapableConnection(sessionId: string): boolean {\n\t\treturn this.fanout.hasCapableConnection(sessionId);\n\t}\n\n\t/** Execute a connection's command with its response destination in context. */\n\twithConnection<T>(id: string, task: () => T): T {\n\t\treturn this.connectionContext.run(id, task);\n\t}\n\n\t/** Connection id of the command currently being dispatched, when one owns it. */\n\tcurrentConnection(): string | undefined {\n\t\treturn this.connectionContext.getStore();\n\t}\n\n\t/** Queue a session record. Content events target connections attached to the session. */\n\tenqueue(sessionId: string, value: object): boolean {\n\t\tif (this.sealedSessions.has(sessionId)) return false;\n\t\tconst targetId = this.connectionContext.getStore();\n\t\tconst record = value as RpcRecord;\n\t\tconst isTargeted =\n\t\t\trecord.type === \"response\" ||\n\t\t\trecord.type === \"bash_execution_update\" ||\n\t\t\t(record.type === \"extension_ui_request\" &&\n\t\t\t\t[\"select\", \"confirm\", \"input\", \"editor\"].includes(String(record.method)));\n\t\tconst tagged = { ...value, sessionId } as RpcRecord;\n\t\tconst { [RENDERED_COMPONENT_RECORD]: _rendered, ...wireTagged } = tagged;\n\t\tconst line = serializeJsonLine(wireTagged);\n\t\tif (this.fanout.isEmpty() && this.exceedsStdioCapacity(line)) {\n\t\t\tthis.closeSession(sessionId, {\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"close_session\",\n\t\t\t\tsuccess: false,\n\t\t\t\terror: \"session_output_overflow, resync required\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tconst targets = this.fanout.targets(\n\t\t\tsessionId,\n\t\t\ttargetId,\n\t\t\tisTargeted,\n\t\t\trecord[RENDERED_COMPONENT_RECORD] === true,\n\t\t\trecord.type,\n\t\t);\n\t\t// A record is only walked and re-serialized when a target asked for placeholders;\n\t\t// otherwise this is byte-for-byte today's path, with serializeJsonLine called once.\n\t\tconst hasPlaceholderTarget = targets.some((target) =>\n\t\t\tthis.fanout.connectionHas(target, MEDIA_PLACEHOLDERS_CAPABILITY),\n\t\t);\n\t\tconst redacted = hasPlaceholderTarget ? omitInlineMedia(wireTagged) : wireTagged;\n\t\tconst placeholderLine = redacted === wireTagged ? undefined : serializeJsonLine(redacted);\n\t\tif (!isTargeted) this.fanout.rememberSnapshot(sessionId, tagged, line, placeholderLine, wireTagged);\n\t\tfor (const target of targets) {\n\t\t\tif (target !== undefined && !this.fanout.get(target)) continue;\n\t\t\tconst registered = target === undefined ? undefined : this.fanout.get(target);\n\t\t\tconst wants =\n\t\t\t\tplaceholderLine !== undefined && this.fanout.connectionHas(target, MEDIA_PLACEHOLDERS_CAPABILITY);\n\t\t\tif (registered) {\n\t\t\t\tconst keyed = compactDelta(tagged) !== undefined && tagged.message !== null;\n\t\t\t\tregistered.actor.enqueue(\n\t\t\t\t\twants ? placeholderLine : line,\n\t\t\t\t\tkeyed ? MESSAGE_KEY : undefined,\n\t\t\t\t\tundefined,\n\t\t\t\t\tkeyed ? serializeJsonLine(demoteToDeltaOnly(wireTagged)) : undefined,\n\t\t\t\t);\n\t\t\t} else this.appendSessionRecord(sessionId, wants ? (redacted as RpcRecord) : wireTagged, target);\n\t\t}\n\t\tthis.requestFlush();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Return worker credit once this session's destinations have ACCEPTED the record\n\t * into their bounded queues - never when the slowest peer's kernel has drained it.\n\t * A client that is merely busy would otherwise pace the producing worker into\n\t * session_worker_credit_timeout and force the dead-peer budget under\n\t * SESSION_WORKER_LIMITS.controlMs (#1774). Delivery stays bounded by each queue's\n\t * maxQueueBytes and its dead-peer cut. A destination that failed (byte overflow or\n\t * stall) was already cut and closed by the fanout's onFailure; it is a cut peer,\n\t * not a writer failure. The shared stdio lane keeps its stdout backpressure wait.\n\t */\n\twaitForSessionBackpressure(sessionId: string): Promise<void> {\n\t\tif (this.fanout.isEmpty()) return this.flush();\n\t\treturn acceptActors(this.sessionActors(sessionId));\n\t}\n\n\t/** Registered actors this session's records are delivered to, plus the caller's own. */\n\tprivate sessionActors(sessionId: string): SocketEventSinkActor[] {\n\t\tconst targets = new Set([\n\t\t\t...this.fanout.targets(sessionId, this.currentConnection(), false, false, undefined),\n\t\t\tthis.currentConnection(),\n\t\t]);\n\t\treturn [...targets].flatMap((target) => {\n\t\t\tconst registered = target === undefined ? undefined : this.fanout.get(target);\n\t\t\treturn registered ? [registered.actor] : [];\n\t\t});\n\t}\n\n\t/** Queue one untagged host-control response for the current connection. */\n\tenqueueControl(value: object): Promise<void> {\n\t\tif (this.failure !== undefined) return Promise.reject(this.failure);\n\t\tconst targetId = this.connectionContext.getStore();\n\t\tconst registered = targetId === undefined ? undefined : this.fanout.get(targetId);\n\t\tif (registered) {\n\t\t\tregistered.actor.enqueue(serializeJsonLine(value));\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tif (this.exceedsStdioCapacity(serializeJsonLine(value))) {\n\t\t\tif (!this.controlOverflowReported) {\n\t\t\t\tthis.controlOverflowReported = true;\n\t\t\t\tthis.append(this.controlQueue, { type: \"overflow\", error: \"rpc_control_output_overflow, resync required\" });\n\t\t\t\tthis.markReady(this.controlQueue);\n\t\t\t\tthis.requestFlush();\n\t\t\t}\n\t\t\treturn Promise.reject(new Error(\"rpc_control_output_overflow, resync required\"));\n\t\t}\n\t\tconst queue = targetId === undefined ? this.controlQueue : this.connectionQueue(targetId);\n\t\tconst completion = new Promise<void>((resolve, reject) => {\n\t\t\tthis.append(queue, { ...value }, undefined, resolve, reject);\n\t\t});\n\t\tthis.markReady(queue);\n\t\tthis.requestFlush();\n\t\treturn completion;\n\t}\n\n\t/**\n\t * Prevent subsequent records for a session and append its terminal response.\n\t * Existing records retain FIFO order; this response is therefore that\n\t * session's final stdout record.\n\t */\n\tcloseSession(sessionId: string, response: object): void {\n\t\tif (this.sealedSessions.has(sessionId)) return;\n\t\tthis.sealedSessions.add(sessionId);\n\t\tthis.fanout.forgetSession(sessionId);\n\t\tconst targetId = this.connectionContext.getStore();\n\t\tconst lifecycle = { type: \"session_closed\", sessionId };\n\t\tif (this.fanout.isEmpty()) this.appendSessionRecord(sessionId, lifecycle);\n\t\telse this.fanout.broadcast(serializeJsonLine(lifecycle));\n\t\tconst taggedResponse = { ...response, sessionId };\n\t\tconst registered = targetId === undefined ? undefined : this.fanout.get(targetId);\n\t\tif (registered) registered.actor.enqueue(serializeJsonLine(taggedResponse));\n\t\telse this.appendSessionRecord(sessionId, taggedResponse, targetId);\n\t\tthis.requestFlush();\n\t}\n\n\t/**\n\t * Admit reply debt before routing can mutate attachments or await finalization.\n\t * Reserve the lifecycle as well: the claimant's role is not known yet. Rejected\n\t * closes do not wait, retain their ids, or create per-request stderr output.\n\t */\n\treserveCloseResponse(\n\t\tsessionId: string,\n\t\tresponse: object,\n\t\trecords = 2,\n\t): { release: () => void; complete: (terminal: boolean) => void } | undefined {\n\t\tconst bytes =\n\t\t\tBuffer.byteLength(serializeJsonLine({ ...response, sessionId })) +\n\t\t\t(records === 2 ? Buffer.byteLength(serializeJsonLine({ type: \"session_closed\", sessionId })) : 0);\n\t\tif (\n\t\t\tthis.bufferedRecordCount + this.reservedCloseRecords + records > MAX_SHARED_STDIO_QUEUE_RECORDS ||\n\t\t\tthis.bufferedByteLength + this.reservedCloseBytes + bytes > MAX_SHARED_STDIO_QUEUE_BYTES\n\t\t) {\n\t\t\tconst overflow = {\n\t\t\t\ttype: \"overflow\",\n\t\t\t\tcommand: \"close_session\",\n\t\t\t\terror: \"rpc_close_output_overflow, resync required\",\n\t\t\t};\n\t\t\tconst targetId = this.currentConnection();\n\t\t\tif (targetId !== undefined) {\n\t\t\t\tconst actor = this.fanout.get(targetId)?.actor;\n\t\t\t\tif (actor && !this.closeOverflowActors.has(actor)) {\n\t\t\t\t\tthis.closeOverflowActors.add(actor);\n\t\t\t\t\t// One outstanding notice per sink, released only on consumption.\n\t\t\t\t\t// Actor identity isolates reconnects and does not retain dead sinks.\n\t\t\t\t\tactor.enqueue(serializeJsonLine(overflow), undefined, () => this.closeOverflowActors.delete(actor));\n\t\t\t\t}\n\t\t\t} else if (!this.closeOverflowReported) {\n\t\t\t\tthis.closeOverflowReported = true;\n\t\t\t\tthis.append(this.controlQueue, overflow);\n\t\t\t\tthis.markReady(this.controlQueue);\n\t\t\t\tthis.requestFlush();\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tthis.reservedCloseRecords += records;\n\t\tthis.reservedCloseBytes += bytes;\n\t\tlet active = true;\n\t\tconst release = () => {\n\t\t\tif (!active) return;\n\t\t\tactive = false;\n\t\t\tthis.reservedCloseRecords -= records;\n\t\t\tthis.reservedCloseBytes -= bytes;\n\t\t};\n\t\treturn {\n\t\t\trelease,\n\t\t\tcomplete: (terminal) => {\n\t\t\t\tif (!active) return;\n\t\t\t\trelease();\n\t\t\t\tif (terminal) this.closeSession(sessionId, response);\n\t\t\t\telse this.appendClosedResponse(sessionId, response);\n\t\t\t},\n\t\t};\n\t}\n\n\t/** Queue a joined close only after admitting its noncompactable reply. */\n\tenqueueClosedResponse(sessionId: string, response: object): void {\n\t\tthis.reserveCloseResponse(sessionId, response, 1)?.complete(false);\n\t}\n\n\tprivate appendClosedResponse(sessionId: string, response: object): void {\n\t\tconst targetId = this.connectionContext.getStore();\n\t\tconst taggedResponse = { ...response, sessionId };\n\t\tconst registered = targetId === undefined ? undefined : this.fanout.get(targetId);\n\t\tif (registered) registered.actor.enqueue(serializeJsonLine(taggedResponse));\n\t\telse this.appendSessionRecord(sessionId, taggedResponse, targetId);\n\t\tthis.requestFlush();\n\t}\n\n\t/**\n\t * Drops per-session bookkeeping for a handle whose runtime is fully disposed.\n\t * Routing handles are unique per process epoch, so nothing can legitimately\n\t * emit under this id again; without this every host-closed session would\n\t * leave a permanent sealed-handle (and snapshot) entry behind.\n\t */\n\tforgetSession(sessionId: string): void {\n\t\tthis.sealedSessions.delete(sessionId);\n\t\tthis.fanout.forgetSession(sessionId);\n\t}\n\n\t/** Drain every retained lane and the current in-flight record. */\n\tflush(): Promise<void> {\n\t\tif (this.failure !== undefined) return Promise.reject(this.failure);\n\t\tthis.flushScheduled = false;\n\t\tif (this.drainPromise) return this.drainPromise;\n\t\tif (this.readyQueues.length === 0) return settleActors([...this.fanout.values()].map(({ actor }) => actor));\n\t\tlet resolveDrain!: () => void;\n\t\tlet rejectDrain!: (cause: unknown) => void;\n\t\tconst drain = new Promise<void>((resolve, reject) => {\n\t\t\tresolveDrain = resolve;\n\t\t\trejectDrain = reject;\n\t\t});\n\t\tthis.drainPromise = drain;\n\t\tvoid this.drainUntilEmpty().then(resolveDrain, rejectDrain);\n\t\tvoid drain.then(\n\t\t\t() => {\n\t\t\t\tif (this.drainPromise === drain) this.drainPromise = undefined;\n\t\t\t\tif (this.readyQueues.length > 0) this.requestFlush();\n\t\t\t},\n\t\t\t(cause) => {\n\t\t\t\tif (this.drainPromise === drain) this.drainPromise = undefined;\n\t\t\t\tthis.fail(cause);\n\t\t\t},\n\t\t);\n\t\treturn drain;\n\t}\n\n\tprivate async drainUntilEmpty(): Promise<void> {\n\t\tdo {\n\t\t\tawait this.drainReadyQueues();\n\t\t} while (this.readyQueues.length > 0);\n\t\t// Per-connection failures are handled by the fanout (cut + close); only the\n\t\t// shared stdio lane may fail this writer.\n\t\tawait settleActors([...this.fanout.values()].map(({ actor }) => actor));\n\t\tthis.controlOverflowReported = false;\n\t\tif (this.reservedCloseRecords === 0) this.closeOverflowReported = false;\n\t}\n\n\tprivate async drainReadyQueues(): Promise<void> {\n\t\twhile (this.readyQueues.length > 0) {\n\t\t\tconst queue = this.readyQueues.shift()!;\n\t\t\tqueue.ready = false;\n\t\t\tconst node = queue.head;\n\t\t\tif (!node) continue;\n\n\t\t\tthis.unlink(queue, node);\n\t\t\tthis.inFlight = { queue, node };\n\t\t\ttry {\n\t\t\t\t// D9: exactly one complete record per raw write. The next lane is not\n\t\t\t\t// selected until this record has cleared stdout backpressure.\n\t\t\t\tconst connection = queue.targetId ? this.fanout.get(queue.targetId)?.connection : undefined;\n\t\t\t\tconst writeRaw = connection?.writeRaw ?? this.writeRaw;\n\t\t\t\tconst waitForBackpressure = connection?.waitForBackpressure ?? this.waitForBackpressure;\n\t\t\t\tif (!connection && queue.targetId) {\n\t\t\t\t\tnode.resolve?.();\n\t\t\t\t} else {\n\t\t\t\t\twriteRaw(serializeJsonLine(node.value));\n\t\t\t\t\tif (waitForBackpressure) await waitForBackpressure();\n\t\t\t\t\tnode.resolve?.();\n\t\t\t\t}\n\t\t\t} catch (cause) {\n\t\t\t\tnode.reject?.(cause);\n\t\t\t\tthrow cause;\n\t\t\t} finally {\n\t\t\t\tthis.inFlight = undefined;\n\t\t\t}\n\n\t\t\tif (queue.head) {\n\t\t\t\tthis.markReady(queue);\n\t\t\t} else if (queue.sessionId || queue.targetId) {\n\t\t\t\tfor (const [key, candidate] of this.queues) {\n\t\t\t\t\tif (candidate === queue) this.queues.delete(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate exceedsStdioCapacity(line: string): boolean {\n\t\treturn (\n\t\t\tthis.bufferedRecordCount + this.reservedCloseRecords >= MAX_SHARED_STDIO_QUEUE_RECORDS ||\n\t\t\tthis.bufferedByteLength + this.reservedCloseBytes + Buffer.byteLength(line) > MAX_SHARED_STDIO_QUEUE_BYTES\n\t\t);\n\t}\n\n\tprivate connectionQueue(targetId: string): RecordQueue {\n\t\tconst key = `connection:${targetId}`;\n\t\tlet queue = this.queues.get(key);\n\t\tif (!queue) {\n\t\t\tqueue = { targetId, latestByKey: new Map(), ready: false };\n\t\t\tthis.queues.set(key, queue);\n\t\t}\n\t\treturn queue;\n\t}\n\n\tprivate appendSessionRecord(sessionId: string, value: RpcRecord, targetId?: string): void {\n\t\tconst key = `${targetId ?? \"default\"}:${sessionId}`;\n\t\tlet queue = this.queues.get(key);\n\t\tif (!queue) {\n\t\t\tqueue = { sessionId, targetId, latestByKey: new Map(), ready: false };\n\t\t\tthis.queues.set(key, queue);\n\t\t}\n\n\t\tconst delta = compactDelta(value);\n\t\tif (delta) {\n\t\t\tconst previousFull = queue.latestByKey.get(MESSAGE_KEY);\n\t\t\tif (previousFull) this.demoteAndMerge(queue, previousFull);\n\t\t\tconst node = this.append(queue, value, MESSAGE_KEY);\n\t\t\tqueue.latestByKey.set(MESSAGE_KEY, node);\n\t\t\tthis.markReady(queue);\n\t\t\treturn;\n\t\t}\n\n\t\tconst toolKey = toolUpdateKey(value);\n\t\tif (toolKey) {\n\t\t\tconst previous = queue.latestByKey.get(toolKey);\n\t\t\tif (previous) this.unlink(queue, previous);\n\t\t\tconst node = this.append(queue, value, toolKey);\n\t\t\tqueue.latestByKey.set(toolKey, node);\n\t\t\tthis.markReady(queue);\n\t\t\treturn;\n\t\t}\n\n\t\t// All non-compactable records are ordering barriers. In particular this\n\t\t// includes delta-only/full non-delta message updates, protocol responses,\n\t\t// extension UI requests, errors, retries, lifecycle, and unknown records.\n\t\tqueue.latestByKey.clear();\n\t\tthis.append(queue, value);\n\t\tthis.markReady(queue);\n\t}\n\n\tprivate demoteAndMerge(queue: RecordQueue, node: QueueNode): void {\n\t\tnode.value = demoteToDeltaOnly(node.value);\n\t\tconst current = compactDelta(node.value);\n\t\tconst preceding = node.previous;\n\t\tconst previous = preceding ? compactDelta(preceding.value) : undefined;\n\t\tif (\n\t\t\tpreceding &&\n\t\t\tprevious &&\n\t\t\tcurrent &&\n\t\t\tpreceding.value.message === null &&\n\t\t\tprevious.type === current.type &&\n\t\t\tprevious.contentIndex === current.contentIndex\n\t\t) {\n\t\t\tconst precedingEvent = preceding.value.assistantMessageEvent as Record<string, unknown>;\n\t\t\tpreceding.value = {\n\t\t\t\t...preceding.value,\n\t\t\t\tassistantMessageEvent: { ...precedingEvent, delta: previous.delta + current.delta },\n\t\t\t};\n\t\t\tthis.unlink(queue, node);\n\t\t}\n\t}\n\n\tprivate append(\n\t\tqueue: RecordQueue,\n\t\tvalue: RpcRecord,\n\t\tkey?: string,\n\t\tresolve?: () => void,\n\t\treject?: (cause: unknown) => void,\n\t): QueueNode {\n\t\tconst node: QueueNode = { value, key, previous: queue.tail, resolve, reject };\n\t\tif (queue.tail) queue.tail.next = node;\n\t\telse queue.head = node;\n\t\tqueue.tail = node;\n\t\treturn node;\n\t}\n\n\tprivate unlink(queue: RecordQueue, node: QueueNode): void {\n\t\tif (node.previous) node.previous.next = node.next;\n\t\telse queue.head = node.next;\n\t\tif (node.next) node.next.previous = node.previous;\n\t\telse queue.tail = node.previous;\n\t\tif (node.key && queue.latestByKey.get(node.key) === node) queue.latestByKey.delete(node.key);\n\t\tnode.previous = undefined;\n\t\tnode.next = undefined;\n\t}\n\n\tprivate markReady(queue: RecordQueue): void {\n\t\tif (queue.ready || this.inFlight?.queue === queue || !queue.head) return;\n\t\tqueue.ready = true;\n\t\tthis.readyQueues.push(queue);\n\t}\n\n\tprivate requestFlush(): void {\n\t\tif (this.failure !== undefined || this.flushScheduled || this.drainPromise) return;\n\t\tthis.flushScheduled = true;\n\t\tthis.scheduleFlush(() => this.flush());\n\t}\n\n\tprivate fail(cause: unknown): void {\n\t\tif (this.failure !== undefined) return;\n\t\tthis.failure = cause;\n\t\tfor (const queue of this.allQueues()) {\n\t\t\tfor (let node = queue.head; node; node = node.next) node.reject?.(cause);\n\t\t}\n\t}\n\n\tprivate *allQueues(): Iterable<RecordQueue> {\n\t\tyield* this.queues.values();\n\t\tyield this.controlQueue;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-event-writer.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-event-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,EACN,yBAAyB,EACzB,kBAAkB,GAElB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,yBAAyB,EAAqC,MAAM,2BAA2B,CAAC;AAEzG,qFAAqF;AACrF,MAAM,YAAY,GAAG,CAAC,MAAuC,EAAiB,EAAE,CAC/E,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;AAEhG,0FAA0F;AAC1F,MAAM,YAAY,GAAG,CAAC,MAAuC,EAAiB,EAAE,CAC/E,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;AA0BrF,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAC7D,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAEnD,MAAM,WAAW,GAAG,SAAS,CAAC;AAC9B,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAmB,CAAC,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAE1G,SAAS,YAAY,CAAC,KAAgB;IACrC,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1F,MAAM,KAAK,GAAG,KAAK,CAAC,qBAAqB,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAClE,MAAM,UAAU,GAAG,KAAgC,CAAC;IACpD,IACC,OAAO,UAAU,CAAC,IAAI,KAAK,QAAQ;QACnC,CAAC,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAwB,CAAC;QAC7D,OAAO,UAAU,CAAC,YAAY,KAAK,QAAQ;QAC3C,OAAO,UAAU,CAAC,KAAK,KAAK,QAAQ,EACnC,CAAC;QACF,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO;QACN,IAAI,EAAE,UAAU,CAAC,IAAwB;QACzC,YAAY,EAAE,UAAU,CAAC,YAAY;QACrC,KAAK,EAAE,UAAU,CAAC,KAAK;KACvB,CAAC;AACH,CAAC;AAED,uGAAuG;AACvG,SAAS,iBAAiB,CAAC,KAAgB;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,qBAAgD,CAAC;IACrE,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;AACxF,CAAC;AAED,SAAS,aAAa,CAAC,KAAgB;IACtC,OAAO,KAAK,CAAC,IAAI,KAAK,uBAAuB,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ;QACpF,CAAC,CAAC,QAAQ,KAAK,CAAC,UAAU,EAAE;QAC5B,CAAC,CAAC,SAAS,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,kBAAkB;IAsB9B,IAAI,uBAAuB;QAC1B,OAAO,IAAI,CAAC,oBAAoB,CAAC;IAClC,CAAC;IAED,IAAI,sBAAsB;QACzB,OAAO,IAAI,CAAC,kBAAkB,CAAC;IAChC,CAAC;IAID,YACC,QAAmB,EACnB,cAAoD,EACpD,aAA8B;QAlCd,WAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;QACxC,WAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QAClC,sBAAiB,GAAG,IAAI,iBAAiB,EAAU,CAAC;QACpD,iBAAY,GAAgB,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACrE,gBAAW,GAAkB,EAAE,CAAC;QAChC,mBAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACpD,8FAA8F;QAC7E,mBAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QAI5C,mBAAc,GAAG,KAAK,CAAC;QAIvB,4BAAuB,GAAG,KAAK,CAAC;QAChC,0BAAqB,GAAG,KAAK,CAAC;QACrB,wBAAmB,GAAG,IAAI,OAAO,EAAwB,CAAC;QACnE,yBAAoB,GAAG,CAAC,CAAC;QACzB,uBAAkB,GAAG,CAAC,CAAC;QAiB9B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,cAAc,IAAI,aAAa,KAAK,SAAS,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChF,IAAI,CAAC,aAAa,GAAG,cAAgC,CAAC;QACvD,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,mBAAmB,GAAG,cAAgD,CAAC;YAC5E,IAAI,CAAC,aAAa,GAAG,aAAa,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;QACvF,CAAC;IACF,CAAC;IAED,IAAI,mBAAmB;QACtB,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,IAAI;gBAAE,KAAK,EAAE,CAAC;QAC7D,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,kBAAkB;QACrB,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/F,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBACpD,KAAK,IAAI,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3D,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,kBAAkB,CACjB,EAAU,EACV,UAAwC,EACxC,OAAO,GAAmE,EAAE;QAE5E,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;IAED,oBAAoB,CAAC,EAAU;QAC9B,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,yBAAyB,CAAC,EAAU,EAAE,SAAiB;QACtD,IAAI,CAAC,MAAM,CAAC,yBAAyB,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IACtD,CAAC;IAED,2BAA2B,CAAC,EAAU,EAAE,SAAiB;QACxD,IAAI,CAAC,MAAM,CAAC,2BAA2B,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC;IAED,yBAAyB,CAAC,EAAU,EAAE,YAA+B;QACpE,IAAI,CAAC,MAAM,CAAC,yBAAyB,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IACzD,CAAC;IAED,2BAA2B,CAAC,EAAU;QACrC,IAAI,CAAC,MAAM,CAAC,2BAA2B,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,mCAAmC,CAAC,EAAU;QAC7C,OAAO,IAAI,CAAC,MAAM,CAAC,mCAAmC,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,yBAAyB,CAAC,EAAU;QACnC,OAAO,IAAI,CAAC,MAAM,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,oBAAoB,CAAC,SAAiB;QACrC,OAAO,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAED;;;;;OAKG;IACH,cAAc,CAAC,SAAiB,EAAE,IAAiB;QAClD,IAAI,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;;YACrD,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IAED,+EAA+E;IAC/E,cAAc,CAAI,EAAU,EAAE,IAAa;QAC1C,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,iFAAiF;IACjF,iBAAiB;QAChB,OAAO,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;IAC1C,CAAC;IAED,yFAAyF;IACzF,OAAO,CAAC,SAAiB,EAAE,KAAa;QACvC,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,KAAkB,CAAC;QAClC,MAAM,UAAU,GACf,MAAM,CAAC,IAAI,KAAK,UAAU;YAC1B,MAAM,CAAC,IAAI,KAAK,uBAAuB;YACvC,CAAC,MAAM,CAAC,IAAI,KAAK,sBAAsB;gBACtC,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,SAAS,EAAe,CAAC;QACpD,MAAM,EAAE,CAAC,yBAAyB,CAAC,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,GAAG,MAAM,CAAC;QACzE,MAAM,IAAI,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE;gBAC5B,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,eAAe;gBACxB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,0CAA0C;aACjD,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAClC,SAAS,EACT,QAAQ,EACR,UAAU,EACV,MAAM,CAAC,yBAAyB,CAAC,KAAK,IAAI,EAC1C,MAAM,CAAC,IAAI,CACX,CAAC;QACF,kFAAkF;QAClF,oFAAoF;QACpF,MAAM,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CACpD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAChE,CAAC;QACF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,CAAC,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QACjF,MAAM,eAAe,GAAG,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC1F,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC;QACpG,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC9B,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,SAAS;YAC/D,MAAM,UAAU,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC9E,MAAM,KAAK,GACV,eAAe,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;YACnG,IAAI,UAAU,EAAE,CAAC;gBAChB,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC;gBAC5E,UAAU,CAAC,KAAK,CAAC,OAAO,CACvB,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,EAC9B,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,EAC/B,SAAS,EACT,KAAK,CAAC,CAAC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CACpE,CAAC;YACH,CAAC;;gBAAM,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAE,QAAsB,CAAC,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAClG,CAAC;QACD,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;;;;;;OASG;IACH,0BAA0B,CAAC,SAAiB;QAC3C,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YAAE,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/C,OAAO,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,wFAAwF;IAChF,aAAa,CAAC,SAAiB;QACtC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC;YACvB,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC;YACpF,IAAI,CAAC,iBAAiB,EAAE;SACxB,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YACtC,MAAM,UAAU,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC9E,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,2EAA2E;IAC3E,cAAc,CAAC,KAAa;QAC3B,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;QACnD,MAAM,UAAU,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClF,IAAI,UAAU,EAAE,CAAC;YAChB,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;YACnD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;QACD,IAAI,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACzD,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC;gBACnC,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC;gBACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,8CAA8C,EAAE,CAAC,CAAC;gBAC5G,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAClC,IAAI,CAAC,YAAY,EAAE,CAAC;YACrB,CAAC;YACD,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC1F,MAAM,UAAU,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,UAAU,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,mBAAmB,CAAC,MAAc;QACjC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;YAC9C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACnC,CAAC;;YAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,YAAY,EAAE,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,SAAiB,EAAE,QAAgB;QAC/C,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO;QAC/C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;QACnD,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC;QACxD,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YAAE,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;aACrE,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;;YAClE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;QACzD,MAAM,cAAc,GAAG,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClF,IAAI,UAAU;YAAE,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC;;YACvE,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;QACnE,IAAI,CAAC,YAAY,EAAE,CAAC;IACrB,CAAC;IAED;;;;;;;;;;OAUG;IACH,WAAW,CAAC,SAAiB,EAAE,WAAmB;QACjD,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO;QAC/C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QACrC,MAAM,SAAS,GAA0B,EAAE,IAAI,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;QAC5F,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YAAE,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;aACrE,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;;YAClE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,YAAY,EAAE,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACH,oBAAoB,CACnB,SAAiB,EACjB,QAAgB,EAChB,OAAO,GAAG,CAAC;QAEX,MAAM,KAAK,GACV,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAChE,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnG,IACC,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,oBAAoB,GAAG,OAAO,GAAG,8BAA8B;YAC/F,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,GAAG,KAAK,GAAG,4BAA4B,EACvF,CAAC;YACF,MAAM,QAAQ,GAAG;gBAChB,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,eAAe;gBACxB,KAAK,EAAE,4CAA4C;aACnD,CAAC;YACF,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC1C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;gBAC/C,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBACpC,iEAAiE;oBACjE,qEAAqE;oBACrE,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBACrG,CAAC;YACF,CAAC;iBAAM,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBACxC,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC;gBAClC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;gBACzC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAClC,IAAI,CAAC,YAAY,EAAE,CAAC;YACrB,CAAC;YACD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,oBAAoB,IAAI,OAAO,CAAC;QACrC,IAAI,CAAC,kBAAkB,IAAI,KAAK,CAAC;QACjC,IAAI,MAAM,GAAG,IAAI,CAAC;QAClB,MAAM,OAAO,GAAG,GAAG,EAAE;YACpB,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,MAAM,GAAG,KAAK,CAAC;YACf,IAAI,CAAC,oBAAoB,IAAI,OAAO,CAAC;YACrC,IAAI,CAAC,kBAAkB,IAAI,KAAK,CAAC;QAClC,CAAC,CAAC;QACF,OAAO;YACN,OAAO;YACP,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE;gBACtB,IAAI,CAAC,MAAM;oBAAE,OAAO;gBACpB,OAAO,EAAE,CAAC;gBACV,IAAI,QAAQ;oBAAE,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;;oBAChD,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YACrD,CAAC;SACD,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,qBAAqB,CAAC,SAAiB,EAAE,QAAgB;QACxD,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC;IAEO,oBAAoB,CAAC,SAAiB,EAAE,QAAgB;QAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;QACnD,MAAM,cAAc,GAAG,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClF,IAAI,UAAU;YAAE,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC;;YACvE,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;QACnE,IAAI,CAAC,YAAY,EAAE,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,aAAa,CAAC,SAAiB;QAC9B,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,kEAAkE;IAClE,KAAK;QACJ,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpE,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC,YAAY,CAAC;QAChD,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5G,IAAI,YAAyB,CAAC;QAC9B,IAAI,WAAsC,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnD,YAAY,GAAG,OAAO,CAAC;YACvB,WAAW,GAAG,MAAM,CAAC;QACtB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,KAAK,IAAI,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAC5D,KAAK,KAAK,CAAC,IAAI,CACd,GAAG,EAAE;YACJ,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK;gBAAE,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;YAC/D,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;gBAAE,IAAI,CAAC,YAAY,EAAE,CAAC;QACtD,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;YACT,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK;gBAAE,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;YAC/D,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC,CACD,CAAC;QACF,OAAO,KAAK,CAAC;IACd,CAAC;IAEO,KAAK,CAAC,eAAe;QAC5B,GAAG,CAAC;YACH,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC/B,CAAC,QAAQ,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;QACtC,4EAA4E;QAC5E,0CAA0C;QAC1C,MAAM,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC,uBAAuB,GAAG,KAAK,CAAC;QACrC,IAAI,IAAI,CAAC,oBAAoB,KAAK,CAAC;YAAE,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;IACzE,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC7B,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAG,CAAC;YACxC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;YACpB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YACxB,IAAI,CAAC,IAAI;gBAAE,SAAS;YAEpB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACzB,IAAI,CAAC,QAAQ,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC;gBACJ,sEAAsE;gBACtE,8DAA8D;gBAC9D,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5F,MAAM,QAAQ,GAAG,UAAU,EAAE,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC;gBACvD,MAAM,mBAAmB,GAAG,UAAU,EAAE,mBAAmB,IAAI,IAAI,CAAC,mBAAmB,CAAC;gBACxF,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACnC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;gBAClB,CAAC;qBAAM,CAAC;oBACP,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;oBACxC,IAAI,mBAAmB;wBAAE,MAAM,mBAAmB,EAAE,CAAC;oBACrD,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;gBAClB,CAAC;YACF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;gBACrB,MAAM,KAAK,CAAC;YACb,CAAC;oBAAS,CAAC;gBACV,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;YAC3B,CAAC;YAED,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBAChB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBAC5C,IAAI,SAAS,KAAK,KAAK;wBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAClD,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAEO,oBAAoB,CAAC,IAAY;QACxC,OAAO,CACN,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,oBAAoB,IAAI,8BAA8B;YACtF,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,4BAA4B,CAC1G,CAAC;IACH,CAAC;IAEO,eAAe,CAAC,QAAgB;QACvC,MAAM,GAAG,GAAG,cAAc,QAAQ,EAAE,CAAC;QACrC,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,KAAK,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;YAC3D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAEO,mBAAmB,CAAC,SAAiB,EAAE,KAAgB,EAAE,QAAiB;QACjF,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,SAAS,IAAI,SAAS,EAAE,CAAC;QACpD,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,KAAK,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;YACtE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QAED,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,KAAK,EAAE,CAAC;YACX,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACxD,IAAI,YAAY;gBAAE,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;YAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;YACpD,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACtB,OAAO;QACR,CAAC;QAED,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAChD,IAAI,QAAQ;gBAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YAChD,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACtB,OAAO;QACR,CAAC;QAED,wEAAwE;QACxE,0EAA0E;QAC1E,0EAA0E;QAC1E,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAEO,cAAc,CAAC,KAAkB,EAAE,IAAe;QACzD,IAAI,CAAC,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;QAChC,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACvE,IACC,SAAS;YACT,QAAQ;YACR,OAAO;YACP,SAAS,CAAC,KAAK,CAAC,OAAO,KAAK,IAAI;YAChC,QAAQ,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI;YAC9B,QAAQ,CAAC,YAAY,KAAK,OAAO,CAAC,YAAY,EAC7C,CAAC;YACF,MAAM,cAAc,GAAG,SAAS,CAAC,KAAK,CAAC,qBAAgD,CAAC;YACxF,SAAS,CAAC,KAAK,GAAG;gBACjB,GAAG,SAAS,CAAC,KAAK;gBAClB,qBAAqB,EAAE,EAAE,GAAG,cAAc,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE;aACnF,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1B,CAAC;IACF,CAAC;IAEO,MAAM,CACb,KAAkB,EAClB,KAAgB,EAChB,GAAY,EACZ,OAAoB,EACpB,MAAiC;QAEjC,MAAM,IAAI,GAAc,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAC9E,IAAI,KAAK,CAAC,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;;YAClC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;QACvB,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;QAClB,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,MAAM,CAAC,KAAkB,EAAE,IAAe;QACjD,IAAI,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;;YAC7C,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAC5B,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;;YAC7C,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;QAChC,IAAI,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI;YAAE,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7F,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;IACvB,CAAC;IAEO,SAAS,CAAC,KAAkB;QACnC,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI;YAAE,OAAO;QACzE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAEO,YAAY;QACnB,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO;QACnF,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACxC,CAAC;IAEO,IAAI,CAAC,KAAc;QAC1B,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO;QACvC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;QAC1E,CAAC;IACF,CAAC;IAEO,CAAC,SAAS;QACjB,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,IAAI,CAAC,YAAY,CAAC;IACzB,CAAC;CACD","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { SessionKind } from \"../../core/extensions/types.ts\";\nimport { MEDIA_PLACEHOLDERS_CAPABILITY } from \"./custom-capability.ts\";\nimport { serializeJsonLine } from \"./jsonl.ts\";\nimport { omitInlineMedia } from \"./media-placeholders.ts\";\nimport type { RpcSessionParkedEvent } from \"./rpc-types.ts\";\nimport {\n\tRENDERED_COMPONENT_RECORD,\n\tSessionEventFanout,\n\ttype SessionEventWriterConnection,\n} from \"./session-event-fanout.ts\";\nimport type { SocketEventSinkActor } from \"./socket-event-fanout.ts\";\n\nexport { RENDERED_COMPONENT_RECORD, type SessionEventWriterConnection } from \"./session-event-fanout.ts\";\n\n/** Await every actor's drain; a failed actor is a cut peer, not a writer failure. */\nconst settleActors = (actors: readonly SocketEventSinkActor[]): Promise<void> =>\n\tPromise.all(actors.map((actor) => actor.flush().catch(() => undefined))).then(() => undefined);\n\n/** Await every actor's ACCEPTANCE of what it was given; never the peer's kernel drain. */\nconst acceptActors = (actors: readonly SocketEventSinkActor[]): Promise<void> =>\n\tPromise.all(actors.map((actor) => actor.waitForAcceptance())).then(() => undefined);\n\ntype RawWriter = (chunk: string) => void;\ntype BackpressureWaiter = () => Promise<void>;\ntype FlushScheduler = (flush: () => Promise<void>) => void;\ntype RpcRecord = Record<string, unknown>;\ntype CompactDeltaType = \"text_delta\" | \"thinking_delta\" | \"toolcall_delta\";\n\ntype QueueNode = {\n\tvalue: RpcRecord;\n\tkey?: string;\n\tprevious?: QueueNode;\n\tnext?: QueueNode;\n\tresolve?: () => void;\n\treject?: (cause: unknown) => void;\n};\n\ntype RecordQueue = {\n\tsessionId?: string;\n\ttargetId?: string;\n\thead?: QueueNode;\n\ttail?: QueueNode;\n\tlatestByKey: Map<string, QueueNode>;\n\tready: boolean;\n};\n\nexport const MAX_SHARED_STDIO_QUEUE_BYTES = 64 * 1024 * 1024;\nexport const MAX_SHARED_STDIO_QUEUE_RECORDS = 4096;\n\nconst MESSAGE_KEY = \"message\";\nconst COMPACT_DELTA_TYPES = new Set<CompactDeltaType>([\"text_delta\", \"thinking_delta\", \"toolcall_delta\"]);\n\nfunction compactDelta(value: RpcRecord): { type: CompactDeltaType; contentIndex: number; delta: string } | undefined {\n\tif (value.type !== \"message_update\" || !Object.hasOwn(value, \"message\")) return undefined;\n\tconst event = value.assistantMessageEvent;\n\tif (typeof event !== \"object\" || event === null) return undefined;\n\tconst typedEvent = event as Record<string, unknown>;\n\tif (\n\t\ttypeof typedEvent.type !== \"string\" ||\n\t\t!COMPACT_DELTA_TYPES.has(typedEvent.type as CompactDeltaType) ||\n\t\ttypeof typedEvent.contentIndex !== \"number\" ||\n\t\ttypeof typedEvent.delta !== \"string\"\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\ttype: typedEvent.type as CompactDeltaType,\n\t\tcontentIndex: typedEvent.contentIndex,\n\t\tdelta: typedEvent.delta,\n\t};\n}\n\n/** The delta-only form of a compact message_update: cumulative snapshot fields blanked, delta kept. */\nfunction demoteToDeltaOnly(value: RpcRecord): RpcRecord {\n\tconst event = value.assistantMessageEvent as Record<string, unknown>;\n\treturn { ...value, message: null, assistantMessageEvent: { ...event, partial: null } };\n}\n\nfunction toolUpdateKey(value: RpcRecord): string | undefined {\n\treturn value.type === \"tool_execution_update\" && typeof value.toolCallId === \"string\"\n\t\t? `tool:${value.toolCallId}`\n\t\t: undefined;\n}\n\n/**\n * Process-wide stdout scheduler for multi-session RPC mode.\n *\n * Each queue contains complete structured JSONL records for one routing handle.\n * Draining takes one record per queue in round-robin order and waits for stdout\n * backpressure before selecting the next one. A record is deliberately written\n * by itself: coalescing records from different sessions would obscure the\n * scheduling boundary and violate D9.\n */\nexport class SessionEventWriter {\n\tprivate readonly queues = new Map<string, RecordQueue>();\n\tprivate readonly fanout = new SessionEventFanout();\n\tprivate readonly connectionContext = new AsyncLocalStorage<string>();\n\tprivate readonly controlQueue: RecordQueue = { latestByKey: new Map(), ready: false };\n\tprivate readonly readyQueues: RecordQueue[] = [];\n\tprivate readonly sealedSessions = new Set<string>();\n\t/** Sessions whose lifecycle records stay on their attached connections (`kind: \"worker\"`). */\n\tprivate readonly workerSessions = new Set<string>();\n\tprivate readonly writeRaw: RawWriter;\n\tprivate readonly waitForBackpressure?: BackpressureWaiter;\n\tprivate readonly scheduleFlush: FlushScheduler;\n\tprivate flushScheduled = false;\n\tprivate drainPromise?: Promise<void>;\n\tprivate inFlight?: { queue: RecordQueue; node: QueueNode };\n\tprivate failure?: unknown;\n\tprivate controlOverflowReported = false;\n\tprivate closeOverflowReported = false;\n\tprivate readonly closeOverflowActors = new WeakSet<SocketEventSinkActor>();\n\tprivate reservedCloseRecords = 0;\n\tprivate reservedCloseBytes = 0;\n\n\tget pendingCloseRecordCount(): number {\n\t\treturn this.reservedCloseRecords;\n\t}\n\n\tget pendingCloseByteLength(): number {\n\t\treturn this.reservedCloseBytes;\n\t}\n\n\tconstructor(writeRaw: RawWriter, scheduleFlush?: FlushScheduler);\n\tconstructor(writeRaw: RawWriter, waitForBackpressure: BackpressureWaiter, scheduleFlush?: FlushScheduler);\n\tconstructor(\n\t\twriteRaw: RawWriter,\n\t\twaitOrSchedule?: BackpressureWaiter | FlushScheduler,\n\t\tscheduleFlush?: FlushScheduler,\n\t) {\n\t\tthis.writeRaw = writeRaw;\n\t\tif (waitOrSchedule && scheduleFlush === undefined && waitOrSchedule.length > 0) {\n\t\t\tthis.scheduleFlush = waitOrSchedule as FlushScheduler;\n\t\t} else {\n\t\t\tthis.waitForBackpressure = waitOrSchedule as BackpressureWaiter | undefined;\n\t\t\tthis.scheduleFlush = scheduleFlush ?? ((flush) => queueMicrotask(() => void flush()));\n\t\t}\n\t}\n\n\tget bufferedRecordCount(): number {\n\t\tlet count = this.inFlight ? 1 : 0;\n\t\tfor (const queue of this.allQueues()) {\n\t\t\tfor (let node = queue.head; node; node = node.next) count++;\n\t\t}\n\t\treturn count;\n\t}\n\n\tget bufferedByteLength(): number {\n\t\tlet bytes = this.inFlight ? Buffer.byteLength(serializeJsonLine(this.inFlight.node.value)) : 0;\n\t\tfor (const queue of this.allQueues()) {\n\t\t\tfor (let node = queue.head; node; node = node.next) {\n\t\t\t\tbytes += Buffer.byteLength(serializeJsonLine(node.value));\n\t\t\t}\n\t\t}\n\t\treturn bytes;\n\t}\n\n\tregisterConnection(\n\t\tid: string,\n\t\tconnection: SessionEventWriterConnection,\n\t\toptions: { readonly maxQueueBytes?: number; readonly stallMs?: number } = {},\n\t): void {\n\t\tthis.fanout.registerConnection(id, connection, options);\n\t}\n\n\tunregisterConnection(id: string): void {\n\t\tthis.fanout.unregisterConnection(id);\n\t}\n\n\tattachConnectionToSession(id: string, sessionId: string): void {\n\t\tthis.fanout.attachConnectionToSession(id, sessionId);\n\t}\n\n\tdetachConnectionFromSession(id: string, sessionId: string): void {\n\t\tthis.fanout.detachConnectionFromSession(id, sessionId);\n\t}\n\n\tsetConnectionCapabilities(id: string, capabilities: readonly string[]): void {\n\t\tthis.fanout.setConnectionCapabilities(id, capabilities);\n\t}\n\n\tclearConnectionCapabilities(id: string): void {\n\t\tthis.fanout.clearConnectionCapabilities(id);\n\t}\n\n\thasRegisteredConnectionCapabilities(id: string): boolean {\n\t\treturn this.fanout.hasRegisteredConnectionCapabilities(id);\n\t}\n\n\tgetConnectionCapabilities(id: string): readonly string[] | undefined {\n\t\treturn this.fanout.getConnectionCapabilities(id);\n\t}\n\n\thasCapableConnection(sessionId: string): boolean {\n\t\treturn this.fanout.hasCapableConnection(sessionId);\n\t}\n\n\t/**\n\t * Records a session's visibility class. A worker session is machine-driven work that\n\t * only its attached connections track, so its lifecycle records are delivered to them\n\t * instead of broadcast; an interactive session keeps the broadcast every client (the\n\t * desktop mirror, the supervisor's idle observer) relies on.\n\t */\n\tsetSessionKind(sessionId: string, kind: SessionKind): void {\n\t\tif (kind === \"worker\") this.workerSessions.add(sessionId);\n\t\telse this.workerSessions.delete(sessionId);\n\t}\n\n\t/** Execute a connection's command with its response destination in context. */\n\twithConnection<T>(id: string, task: () => T): T {\n\t\treturn this.connectionContext.run(id, task);\n\t}\n\n\t/** Connection id of the command currently being dispatched, when one owns it. */\n\tcurrentConnection(): string | undefined {\n\t\treturn this.connectionContext.getStore();\n\t}\n\n\t/** Queue a session record. Content events target connections attached to the session. */\n\tenqueue(sessionId: string, value: object): boolean {\n\t\tif (this.sealedSessions.has(sessionId)) return false;\n\t\tconst targetId = this.connectionContext.getStore();\n\t\tconst record = value as RpcRecord;\n\t\tconst isTargeted =\n\t\t\trecord.type === \"response\" ||\n\t\t\trecord.type === \"bash_execution_update\" ||\n\t\t\t(record.type === \"extension_ui_request\" &&\n\t\t\t\t[\"select\", \"confirm\", \"input\", \"editor\"].includes(String(record.method)));\n\t\tconst tagged = { ...value, sessionId } as RpcRecord;\n\t\tconst { [RENDERED_COMPONENT_RECORD]: _rendered, ...wireTagged } = tagged;\n\t\tconst line = serializeJsonLine(wireTagged);\n\t\tif (this.fanout.isEmpty() && this.exceedsStdioCapacity(line)) {\n\t\t\tthis.closeSession(sessionId, {\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"close_session\",\n\t\t\t\tsuccess: false,\n\t\t\t\terror: \"session_output_overflow, resync required\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tconst targets = this.fanout.targets(\n\t\t\tsessionId,\n\t\t\ttargetId,\n\t\t\tisTargeted,\n\t\t\trecord[RENDERED_COMPONENT_RECORD] === true,\n\t\t\trecord.type,\n\t\t);\n\t\t// A record is only walked and re-serialized when a target asked for placeholders;\n\t\t// otherwise this is byte-for-byte today's path, with serializeJsonLine called once.\n\t\tconst hasPlaceholderTarget = targets.some((target) =>\n\t\t\tthis.fanout.connectionHas(target, MEDIA_PLACEHOLDERS_CAPABILITY),\n\t\t);\n\t\tconst redacted = hasPlaceholderTarget ? omitInlineMedia(wireTagged) : wireTagged;\n\t\tconst placeholderLine = redacted === wireTagged ? undefined : serializeJsonLine(redacted);\n\t\tif (!isTargeted) this.fanout.rememberSnapshot(sessionId, tagged, line, placeholderLine, wireTagged);\n\t\tfor (const target of targets) {\n\t\t\tif (target !== undefined && !this.fanout.get(target)) continue;\n\t\t\tconst registered = target === undefined ? undefined : this.fanout.get(target);\n\t\t\tconst wants =\n\t\t\t\tplaceholderLine !== undefined && this.fanout.connectionHas(target, MEDIA_PLACEHOLDERS_CAPABILITY);\n\t\t\tif (registered) {\n\t\t\t\tconst keyed = compactDelta(tagged) !== undefined && tagged.message !== null;\n\t\t\t\tregistered.actor.enqueue(\n\t\t\t\t\twants ? placeholderLine : line,\n\t\t\t\t\tkeyed ? MESSAGE_KEY : undefined,\n\t\t\t\t\tundefined,\n\t\t\t\t\tkeyed ? serializeJsonLine(demoteToDeltaOnly(wireTagged)) : undefined,\n\t\t\t\t);\n\t\t\t} else this.appendSessionRecord(sessionId, wants ? (redacted as RpcRecord) : wireTagged, target);\n\t\t}\n\t\tthis.requestFlush();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Return worker credit once this session's destinations have ACCEPTED the record\n\t * into their bounded queues - never when the slowest peer's kernel has drained it.\n\t * A client that is merely busy would otherwise pace the producing worker into\n\t * session_worker_credit_timeout and force the dead-peer budget under\n\t * SESSION_WORKER_LIMITS.controlMs (#1774). Delivery stays bounded by each queue's\n\t * maxQueueBytes and its dead-peer cut. A destination that failed (byte overflow or\n\t * stall) was already cut and closed by the fanout's onFailure; it is a cut peer,\n\t * not a writer failure. The shared stdio lane keeps its stdout backpressure wait.\n\t */\n\twaitForSessionBackpressure(sessionId: string): Promise<void> {\n\t\tif (this.fanout.isEmpty()) return this.flush();\n\t\treturn acceptActors(this.sessionActors(sessionId));\n\t}\n\n\t/** Registered actors this session's records are delivered to, plus the caller's own. */\n\tprivate sessionActors(sessionId: string): SocketEventSinkActor[] {\n\t\tconst targets = new Set([\n\t\t\t...this.fanout.targets(sessionId, this.currentConnection(), false, false, undefined),\n\t\t\tthis.currentConnection(),\n\t\t]);\n\t\treturn [...targets].flatMap((target) => {\n\t\t\tconst registered = target === undefined ? undefined : this.fanout.get(target);\n\t\t\treturn registered ? [registered.actor] : [];\n\t\t});\n\t}\n\n\t/** Queue one untagged host-control response for the current connection. */\n\tenqueueControl(value: object): Promise<void> {\n\t\tif (this.failure !== undefined) return Promise.reject(this.failure);\n\t\tconst targetId = this.connectionContext.getStore();\n\t\tconst registered = targetId === undefined ? undefined : this.fanout.get(targetId);\n\t\tif (registered) {\n\t\t\tregistered.actor.enqueue(serializeJsonLine(value));\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tif (this.exceedsStdioCapacity(serializeJsonLine(value))) {\n\t\t\tif (!this.controlOverflowReported) {\n\t\t\t\tthis.controlOverflowReported = true;\n\t\t\t\tthis.append(this.controlQueue, { type: \"overflow\", error: \"rpc_control_output_overflow, resync required\" });\n\t\t\t\tthis.markReady(this.controlQueue);\n\t\t\t\tthis.requestFlush();\n\t\t\t}\n\t\t\treturn Promise.reject(new Error(\"rpc_control_output_overflow, resync required\"));\n\t\t}\n\t\tconst queue = targetId === undefined ? this.controlQueue : this.connectionQueue(targetId);\n\t\tconst completion = new Promise<void>((resolve, reject) => {\n\t\t\tthis.append(queue, { ...value }, undefined, resolve, reject);\n\t\t});\n\t\tthis.markReady(queue);\n\t\tthis.requestFlush();\n\t\treturn completion;\n\t}\n\n\t/**\n\t * Queue one HOST-level lifecycle record for every registered connection, or the\n\t * shared stdio lane when none is registered. Unlike session records it is not tagged\n\t * with a routing handle by the writer: `host_stalled` carries the handle it blames,\n\t * and `host_memory_pressure` belongs to the process, not to a session.\n\t */\n\tbroadcastHostRecord(record: object): void {\n\t\tif (this.fanout.isEmpty()) {\n\t\t\tthis.append(this.controlQueue, { ...record });\n\t\t\tthis.markReady(this.controlQueue);\n\t\t} else this.fanout.broadcast(serializeJsonLine(record));\n\t\tthis.requestFlush();\n\t}\n\n\t/**\n\t * Prevent subsequent records for a session and append its terminal response.\n\t * Existing records retain FIFO order; this response is therefore that\n\t * session's final stdout record.\n\t */\n\tcloseSession(sessionId: string, response: object): void {\n\t\tif (this.sealedSessions.has(sessionId)) return;\n\t\tthis.sealedSessions.add(sessionId);\n\t\tthis.fanout.forgetSession(sessionId);\n\t\tconst targetId = this.connectionContext.getStore();\n\t\tconst lifecycle = { type: \"session_closed\", sessionId };\n\t\tif (this.fanout.isEmpty()) this.appendSessionRecord(sessionId, lifecycle);\n\t\telse if (this.workerSessions.has(sessionId))\n\t\t\tthis.fanout.deliverToSession(sessionId, serializeJsonLine(lifecycle));\n\t\telse this.fanout.broadcast(serializeJsonLine(lifecycle));\n\t\tconst taggedResponse = { ...response, sessionId };\n\t\tconst registered = targetId === undefined ? undefined : this.fanout.get(targetId);\n\t\tif (registered) registered.actor.enqueue(serializeJsonLine(taggedResponse));\n\t\telse this.appendSessionRecord(sessionId, taggedResponse, targetId);\n\t\tthis.requestFlush();\n\t}\n\n\t/**\n\t * Seal a session the host PARKED and publish `session_parked`.\n\t *\n\t * Parking is the idle sweep putting a RETAINED session back on disk: the routing\n\t * handle ends exactly as a close ends it, but the session survives and reopens with\n\t * `open_session { sessionPath }`, so the record a client dispatches on must say so\n\t * instead of claiming the session ended. Delivery follows the `session_closed` rule -\n\t * a worker session's record reaches only its attached connections, an interactive\n\t * session's reaches every connection. No client asked for this teardown, so there is\n\t * no close response to answer.\n\t */\n\tparkSession(sessionId: string, sessionPath: string): void {\n\t\tif (this.sealedSessions.has(sessionId)) return;\n\t\tthis.sealedSessions.add(sessionId);\n\t\tthis.fanout.forgetSession(sessionId);\n\t\tconst lifecycle: RpcSessionParkedEvent = { type: \"session_parked\", sessionId, sessionPath };\n\t\tif (this.fanout.isEmpty()) this.appendSessionRecord(sessionId, lifecycle);\n\t\telse if (this.workerSessions.has(sessionId))\n\t\t\tthis.fanout.deliverToSession(sessionId, serializeJsonLine(lifecycle));\n\t\telse this.fanout.broadcast(serializeJsonLine(lifecycle));\n\t\tthis.requestFlush();\n\t}\n\n\t/**\n\t * Admit reply debt before routing can mutate attachments or await finalization.\n\t * Reserve the lifecycle as well: the claimant's role is not known yet. Rejected\n\t * closes do not wait, retain their ids, or create per-request stderr output.\n\t */\n\treserveCloseResponse(\n\t\tsessionId: string,\n\t\tresponse: object,\n\t\trecords = 2,\n\t): { release: () => void; complete: (terminal: boolean) => void } | undefined {\n\t\tconst bytes =\n\t\t\tBuffer.byteLength(serializeJsonLine({ ...response, sessionId })) +\n\t\t\t(records === 2 ? Buffer.byteLength(serializeJsonLine({ type: \"session_closed\", sessionId })) : 0);\n\t\tif (\n\t\t\tthis.bufferedRecordCount + this.reservedCloseRecords + records > MAX_SHARED_STDIO_QUEUE_RECORDS ||\n\t\t\tthis.bufferedByteLength + this.reservedCloseBytes + bytes > MAX_SHARED_STDIO_QUEUE_BYTES\n\t\t) {\n\t\t\tconst overflow = {\n\t\t\t\ttype: \"overflow\",\n\t\t\t\tcommand: \"close_session\",\n\t\t\t\terror: \"rpc_close_output_overflow, resync required\",\n\t\t\t};\n\t\t\tconst targetId = this.currentConnection();\n\t\t\tif (targetId !== undefined) {\n\t\t\t\tconst actor = this.fanout.get(targetId)?.actor;\n\t\t\t\tif (actor && !this.closeOverflowActors.has(actor)) {\n\t\t\t\t\tthis.closeOverflowActors.add(actor);\n\t\t\t\t\t// One outstanding notice per sink, released only on consumption.\n\t\t\t\t\t// Actor identity isolates reconnects and does not retain dead sinks.\n\t\t\t\t\tactor.enqueue(serializeJsonLine(overflow), undefined, () => this.closeOverflowActors.delete(actor));\n\t\t\t\t}\n\t\t\t} else if (!this.closeOverflowReported) {\n\t\t\t\tthis.closeOverflowReported = true;\n\t\t\t\tthis.append(this.controlQueue, overflow);\n\t\t\t\tthis.markReady(this.controlQueue);\n\t\t\t\tthis.requestFlush();\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\tthis.reservedCloseRecords += records;\n\t\tthis.reservedCloseBytes += bytes;\n\t\tlet active = true;\n\t\tconst release = () => {\n\t\t\tif (!active) return;\n\t\t\tactive = false;\n\t\t\tthis.reservedCloseRecords -= records;\n\t\t\tthis.reservedCloseBytes -= bytes;\n\t\t};\n\t\treturn {\n\t\t\trelease,\n\t\t\tcomplete: (terminal) => {\n\t\t\t\tif (!active) return;\n\t\t\t\trelease();\n\t\t\t\tif (terminal) this.closeSession(sessionId, response);\n\t\t\t\telse this.appendClosedResponse(sessionId, response);\n\t\t\t},\n\t\t};\n\t}\n\n\t/** Queue a joined close only after admitting its noncompactable reply. */\n\tenqueueClosedResponse(sessionId: string, response: object): void {\n\t\tthis.reserveCloseResponse(sessionId, response, 1)?.complete(false);\n\t}\n\n\tprivate appendClosedResponse(sessionId: string, response: object): void {\n\t\tconst targetId = this.connectionContext.getStore();\n\t\tconst taggedResponse = { ...response, sessionId };\n\t\tconst registered = targetId === undefined ? undefined : this.fanout.get(targetId);\n\t\tif (registered) registered.actor.enqueue(serializeJsonLine(taggedResponse));\n\t\telse this.appendSessionRecord(sessionId, taggedResponse, targetId);\n\t\tthis.requestFlush();\n\t}\n\n\t/**\n\t * Drops per-session bookkeeping for a handle whose runtime is fully disposed.\n\t * Routing handles are unique per process epoch, so nothing can legitimately\n\t * emit under this id again; without this every host-closed session would\n\t * leave a permanent sealed-handle (and snapshot) entry behind.\n\t */\n\tforgetSession(sessionId: string): void {\n\t\tthis.sealedSessions.delete(sessionId);\n\t\tthis.workerSessions.delete(sessionId);\n\t\tthis.fanout.forgetSession(sessionId);\n\t}\n\n\t/** Drain every retained lane and the current in-flight record. */\n\tflush(): Promise<void> {\n\t\tif (this.failure !== undefined) return Promise.reject(this.failure);\n\t\tthis.flushScheduled = false;\n\t\tif (this.drainPromise) return this.drainPromise;\n\t\tif (this.readyQueues.length === 0) return settleActors([...this.fanout.values()].map(({ actor }) => actor));\n\t\tlet resolveDrain!: () => void;\n\t\tlet rejectDrain!: (cause: unknown) => void;\n\t\tconst drain = new Promise<void>((resolve, reject) => {\n\t\t\tresolveDrain = resolve;\n\t\t\trejectDrain = reject;\n\t\t});\n\t\tthis.drainPromise = drain;\n\t\tvoid this.drainUntilEmpty().then(resolveDrain, rejectDrain);\n\t\tvoid drain.then(\n\t\t\t() => {\n\t\t\t\tif (this.drainPromise === drain) this.drainPromise = undefined;\n\t\t\t\tif (this.readyQueues.length > 0) this.requestFlush();\n\t\t\t},\n\t\t\t(cause) => {\n\t\t\t\tif (this.drainPromise === drain) this.drainPromise = undefined;\n\t\t\t\tthis.fail(cause);\n\t\t\t},\n\t\t);\n\t\treturn drain;\n\t}\n\n\tprivate async drainUntilEmpty(): Promise<void> {\n\t\tdo {\n\t\t\tawait this.drainReadyQueues();\n\t\t} while (this.readyQueues.length > 0);\n\t\t// Per-connection failures are handled by the fanout (cut + close); only the\n\t\t// shared stdio lane may fail this writer.\n\t\tawait settleActors([...this.fanout.values()].map(({ actor }) => actor));\n\t\tthis.controlOverflowReported = false;\n\t\tif (this.reservedCloseRecords === 0) this.closeOverflowReported = false;\n\t}\n\n\tprivate async drainReadyQueues(): Promise<void> {\n\t\twhile (this.readyQueues.length > 0) {\n\t\t\tconst queue = this.readyQueues.shift()!;\n\t\t\tqueue.ready = false;\n\t\t\tconst node = queue.head;\n\t\t\tif (!node) continue;\n\n\t\t\tthis.unlink(queue, node);\n\t\t\tthis.inFlight = { queue, node };\n\t\t\ttry {\n\t\t\t\t// D9: exactly one complete record per raw write. The next lane is not\n\t\t\t\t// selected until this record has cleared stdout backpressure.\n\t\t\t\tconst connection = queue.targetId ? this.fanout.get(queue.targetId)?.connection : undefined;\n\t\t\t\tconst writeRaw = connection?.writeRaw ?? this.writeRaw;\n\t\t\t\tconst waitForBackpressure = connection?.waitForBackpressure ?? this.waitForBackpressure;\n\t\t\t\tif (!connection && queue.targetId) {\n\t\t\t\t\tnode.resolve?.();\n\t\t\t\t} else {\n\t\t\t\t\twriteRaw(serializeJsonLine(node.value));\n\t\t\t\t\tif (waitForBackpressure) await waitForBackpressure();\n\t\t\t\t\tnode.resolve?.();\n\t\t\t\t}\n\t\t\t} catch (cause) {\n\t\t\t\tnode.reject?.(cause);\n\t\t\t\tthrow cause;\n\t\t\t} finally {\n\t\t\t\tthis.inFlight = undefined;\n\t\t\t}\n\n\t\t\tif (queue.head) {\n\t\t\t\tthis.markReady(queue);\n\t\t\t} else if (queue.sessionId || queue.targetId) {\n\t\t\t\tfor (const [key, candidate] of this.queues) {\n\t\t\t\t\tif (candidate === queue) this.queues.delete(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate exceedsStdioCapacity(line: string): boolean {\n\t\treturn (\n\t\t\tthis.bufferedRecordCount + this.reservedCloseRecords >= MAX_SHARED_STDIO_QUEUE_RECORDS ||\n\t\t\tthis.bufferedByteLength + this.reservedCloseBytes + Buffer.byteLength(line) > MAX_SHARED_STDIO_QUEUE_BYTES\n\t\t);\n\t}\n\n\tprivate connectionQueue(targetId: string): RecordQueue {\n\t\tconst key = `connection:${targetId}`;\n\t\tlet queue = this.queues.get(key);\n\t\tif (!queue) {\n\t\t\tqueue = { targetId, latestByKey: new Map(), ready: false };\n\t\t\tthis.queues.set(key, queue);\n\t\t}\n\t\treturn queue;\n\t}\n\n\tprivate appendSessionRecord(sessionId: string, value: RpcRecord, targetId?: string): void {\n\t\tconst key = `${targetId ?? \"default\"}:${sessionId}`;\n\t\tlet queue = this.queues.get(key);\n\t\tif (!queue) {\n\t\t\tqueue = { sessionId, targetId, latestByKey: new Map(), ready: false };\n\t\t\tthis.queues.set(key, queue);\n\t\t}\n\n\t\tconst delta = compactDelta(value);\n\t\tif (delta) {\n\t\t\tconst previousFull = queue.latestByKey.get(MESSAGE_KEY);\n\t\t\tif (previousFull) this.demoteAndMerge(queue, previousFull);\n\t\t\tconst node = this.append(queue, value, MESSAGE_KEY);\n\t\t\tqueue.latestByKey.set(MESSAGE_KEY, node);\n\t\t\tthis.markReady(queue);\n\t\t\treturn;\n\t\t}\n\n\t\tconst toolKey = toolUpdateKey(value);\n\t\tif (toolKey) {\n\t\t\tconst previous = queue.latestByKey.get(toolKey);\n\t\t\tif (previous) this.unlink(queue, previous);\n\t\t\tconst node = this.append(queue, value, toolKey);\n\t\t\tqueue.latestByKey.set(toolKey, node);\n\t\t\tthis.markReady(queue);\n\t\t\treturn;\n\t\t}\n\n\t\t// All non-compactable records are ordering barriers. In particular this\n\t\t// includes delta-only/full non-delta message updates, protocol responses,\n\t\t// extension UI requests, errors, retries, lifecycle, and unknown records.\n\t\tqueue.latestByKey.clear();\n\t\tthis.append(queue, value);\n\t\tthis.markReady(queue);\n\t}\n\n\tprivate demoteAndMerge(queue: RecordQueue, node: QueueNode): void {\n\t\tnode.value = demoteToDeltaOnly(node.value);\n\t\tconst current = compactDelta(node.value);\n\t\tconst preceding = node.previous;\n\t\tconst previous = preceding ? compactDelta(preceding.value) : undefined;\n\t\tif (\n\t\t\tpreceding &&\n\t\t\tprevious &&\n\t\t\tcurrent &&\n\t\t\tpreceding.value.message === null &&\n\t\t\tprevious.type === current.type &&\n\t\t\tprevious.contentIndex === current.contentIndex\n\t\t) {\n\t\t\tconst precedingEvent = preceding.value.assistantMessageEvent as Record<string, unknown>;\n\t\t\tpreceding.value = {\n\t\t\t\t...preceding.value,\n\t\t\t\tassistantMessageEvent: { ...precedingEvent, delta: previous.delta + current.delta },\n\t\t\t};\n\t\t\tthis.unlink(queue, node);\n\t\t}\n\t}\n\n\tprivate append(\n\t\tqueue: RecordQueue,\n\t\tvalue: RpcRecord,\n\t\tkey?: string,\n\t\tresolve?: () => void,\n\t\treject?: (cause: unknown) => void,\n\t): QueueNode {\n\t\tconst node: QueueNode = { value, key, previous: queue.tail, resolve, reject };\n\t\tif (queue.tail) queue.tail.next = node;\n\t\telse queue.head = node;\n\t\tqueue.tail = node;\n\t\treturn node;\n\t}\n\n\tprivate unlink(queue: RecordQueue, node: QueueNode): void {\n\t\tif (node.previous) node.previous.next = node.next;\n\t\telse queue.head = node.next;\n\t\tif (node.next) node.next.previous = node.previous;\n\t\telse queue.tail = node.previous;\n\t\tif (node.key && queue.latestByKey.get(node.key) === node) queue.latestByKey.delete(node.key);\n\t\tnode.previous = undefined;\n\t\tnode.next = undefined;\n\t}\n\n\tprivate markReady(queue: RecordQueue): void {\n\t\tif (queue.ready || this.inFlight?.queue === queue || !queue.head) return;\n\t\tqueue.ready = true;\n\t\tthis.readyQueues.push(queue);\n\t}\n\n\tprivate requestFlush(): void {\n\t\tif (this.failure !== undefined || this.flushScheduled || this.drainPromise) return;\n\t\tthis.flushScheduled = true;\n\t\tthis.scheduleFlush(() => this.flush());\n\t}\n\n\tprivate fail(cause: unknown): void {\n\t\tif (this.failure !== undefined) return;\n\t\tthis.failure = cause;\n\t\tfor (const queue of this.allQueues()) {\n\t\t\tfor (let node = queue.head; node; node = node.next) node.reject?.(cause);\n\t\t}\n\t}\n\n\tprivate *allQueues(): Iterable<RecordQueue> {\n\t\tyield* this.queues.values();\n\t\tyield this.controlQueue;\n\t}\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ProviderScope } from "@earendil-works/pi-ai/node/provider-scope";
|
|
2
2
|
import { type AgentSessionLaunchProfile, AgentSessionRuntime, type CreateAgentSessionRuntimeFactory } from "../../core/agent-session-runtime.ts";
|
|
3
|
+
import type { SessionContext, SessionKind } from "../../core/extensions/types.ts";
|
|
3
4
|
import type { SessionWorkerClient } from "./session-worker-client.ts";
|
|
4
5
|
/** The immutable flags selected when a routing session is opened. */
|
|
5
6
|
export interface RpcSessionLaunchProfile extends AgentSessionLaunchProfile {
|
|
@@ -11,6 +12,10 @@ export interface RpcSessionEntry {
|
|
|
11
12
|
state: RpcSessionState;
|
|
12
13
|
runtime?: SessionRuntime;
|
|
13
14
|
worker?: SessionWorkerClient;
|
|
15
|
+
/** Visibility class chosen by the open, frozen for the entry's life. */
|
|
16
|
+
readonly kind: SessionKind;
|
|
17
|
+
/** Frozen opaque labels the open attached; `{}` when it attached none. */
|
|
18
|
+
readonly context: SessionContext;
|
|
14
19
|
/** Resolves replacement against the runtime currently owned by this entry. */
|
|
15
20
|
switchSession?: SessionRuntime["switchSession"];
|
|
16
21
|
/** Rebind callback installed by the shared RPC connection handler. */
|
|
@@ -58,6 +63,18 @@ export interface RpcSessionOpenOptions {
|
|
|
58
63
|
/** Keep the session alive when its last client disconnects (`open_session.retain_on_disconnect`). */
|
|
59
64
|
retainOnDisconnect?: boolean;
|
|
60
65
|
}
|
|
66
|
+
/** One `list_sessions` row. `context` is published only to a listing that asked for workers. */
|
|
67
|
+
export interface RpcSessionRow {
|
|
68
|
+
sessionId: string;
|
|
69
|
+
durableSessionId?: string;
|
|
70
|
+
sessionPath?: string;
|
|
71
|
+
cwd: string;
|
|
72
|
+
name?: string;
|
|
73
|
+
status: Exclude<RpcSessionState, "quarantined">;
|
|
74
|
+
attachments: number;
|
|
75
|
+
kind: SessionKind;
|
|
76
|
+
context: SessionContext;
|
|
77
|
+
}
|
|
61
78
|
export interface OpenRpcSession {
|
|
62
79
|
sessionId: string;
|
|
63
80
|
durableSessionId: string;
|
|
@@ -65,6 +82,17 @@ export interface OpenRpcSession {
|
|
|
65
82
|
/** True when this open attached to an already-open session instead of creating one. */
|
|
66
83
|
attached?: boolean;
|
|
67
84
|
}
|
|
85
|
+
/** Freezes an open's launch inputs, including the nested objects a client supplied. */
|
|
86
|
+
export declare function frozenProfile(profile: RpcSessionLaunchProfile): Readonly<RpcSessionLaunchProfile>;
|
|
87
|
+
/**
|
|
88
|
+
* The visibility class and labels an entry keeps for its life, normalized once here so no
|
|
89
|
+
* lifecycle, listing or delivery decision has to re-apply the defaults. Reads the already
|
|
90
|
+
* frozen profile, so the entry and the runtime share one frozen context object.
|
|
91
|
+
*/
|
|
92
|
+
export declare function sessionIdentity(profile: Readonly<RpcSessionLaunchProfile>): {
|
|
93
|
+
readonly kind: SessionKind;
|
|
94
|
+
readonly context: SessionContext;
|
|
95
|
+
};
|
|
68
96
|
/** Process-local lifecycle owner for multi-session RPC runtimes. */
|
|
69
97
|
export declare class RpcSessionRegistry {
|
|
70
98
|
private readonly entries;
|
|
@@ -78,6 +106,19 @@ export declare class RpcSessionRegistry {
|
|
|
78
106
|
/** Number of live entries, including ones still opening or closing. */
|
|
79
107
|
get size(): number;
|
|
80
108
|
openSession(profile: RpcSessionLaunchProfile, options?: RpcSessionOpenOptions): Promise<OpenRpcSession>;
|
|
109
|
+
/**
|
|
110
|
+
* Waits out a teardown already in flight for this path before the open decides.
|
|
111
|
+
*
|
|
112
|
+
* A close FREES the path, but the entry keeps its reservation until its runtime is
|
|
113
|
+
* disposed, so an open landing inside that window used to be refused with
|
|
114
|
+
* `session_path_in_use` for a session that no longer exists - making "reopen the
|
|
115
|
+
* path I just closed" a race against disposal latency, which no client can time.
|
|
116
|
+
* The open now waits for the teardown it would have been refused by and then opens
|
|
117
|
+
* the file fresh. Bounded by the same grace window that bounds the teardown itself
|
|
118
|
+
* (`closeMarkedSession` force-releases at that deadline), so a wedged disposal
|
|
119
|
+
* still ends in the ordinary refusal instead of an open that never answers.
|
|
120
|
+
*/
|
|
121
|
+
private settleClosingReservation;
|
|
81
122
|
/**
|
|
82
123
|
* Read-only lookup with no state transitions or attachment accounting.
|
|
83
124
|
* Exists so lifecycle decisions (e.g. deferring a dropped connection's
|
|
@@ -97,15 +138,7 @@ export declare class RpcSessionRegistry {
|
|
|
97
138
|
close(handle: string): Promise<void>;
|
|
98
139
|
/** Completes a close previously made visible by beginClose(). */
|
|
99
140
|
closeMarked(handle: string): Promise<void>;
|
|
100
|
-
list():
|
|
101
|
-
sessionId: string;
|
|
102
|
-
durableSessionId?: string;
|
|
103
|
-
sessionPath?: string;
|
|
104
|
-
cwd: string;
|
|
105
|
-
name?: string;
|
|
106
|
-
status: Exclude<RpcSessionState, "quarantined">;
|
|
107
|
-
attachments: number;
|
|
108
|
-
}>;
|
|
141
|
+
list(): RpcSessionRow[];
|
|
109
142
|
/** Reconcile path and durable identity after runtime replacement. */
|
|
110
143
|
private syncRuntimeMetadata;
|
|
111
144
|
private validateProfile;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/session-registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAwB,MAAM,2CAA2C,CAAC;AAChG,OAAO,EACN,KAAK,yBAAyB,EAC9B,mBAAmB,EACnB,KAAK,gCAAgC,EAErC,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/session-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { existsSync, realpathSync } from "node:fs";
|
|
|
2
2
|
import { basename, dirname, isAbsolute, resolve } from "node:path";
|
|
3
3
|
import { ProviderScope, runWithProviderScope } from "@earendil-works/pi-ai/node/provider-scope";
|
|
4
4
|
import { AgentSessionRuntime, createAgentSessionRuntime, } from "../../core/agent-session-runtime.js";
|
|
5
|
+
import { EMPTY_SESSION_CONTEXT } from "../../core/extensions/types.js";
|
|
5
6
|
import { SessionManager } from "../../core/session-manager.js";
|
|
6
7
|
import { beginSessionClose, closeMarkedSession, closeSession } from "./session-teardown.js";
|
|
7
8
|
export class RpcSessionRegistryError extends Error {
|
|
@@ -17,12 +18,22 @@ function canonicalPath(path) {
|
|
|
17
18
|
return realpathSync(absolutePath);
|
|
18
19
|
return `${realpathSync(dirname(absolutePath))}/${basename(absolutePath)}`;
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
/** Freezes an open's launch inputs, including the nested objects a client supplied. */
|
|
22
|
+
export function frozenProfile(profile) {
|
|
21
23
|
return Object.freeze({
|
|
22
24
|
...profile,
|
|
23
25
|
...(profile.creationModel ? { creationModel: Object.freeze({ ...profile.creationModel }) } : {}),
|
|
26
|
+
...(profile.sessionContext ? { sessionContext: Object.freeze({ ...profile.sessionContext }) } : {}),
|
|
24
27
|
});
|
|
25
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* The visibility class and labels an entry keeps for its life, normalized once here so no
|
|
31
|
+
* lifecycle, listing or delivery decision has to re-apply the defaults. Reads the already
|
|
32
|
+
* frozen profile, so the entry and the runtime share one frozen context object.
|
|
33
|
+
*/
|
|
34
|
+
export function sessionIdentity(profile) {
|
|
35
|
+
return { kind: profile.sessionKind ?? "interactive", context: profile.sessionContext ?? EMPTY_SESSION_CONTEXT };
|
|
36
|
+
}
|
|
26
37
|
/** Process-local lifecycle owner for multi-session RPC runtimes. */
|
|
27
38
|
export class RpcSessionRegistry {
|
|
28
39
|
constructor(options) {
|
|
@@ -48,11 +59,13 @@ export class RpcSessionRegistry {
|
|
|
48
59
|
this.validateProfile(profile);
|
|
49
60
|
this.syncRuntimeMetadata();
|
|
50
61
|
const sessionPath = profile.sessionPath ? canonicalPath(profile.sessionPath) : undefined;
|
|
62
|
+
if (sessionPath)
|
|
63
|
+
await this.settleClosingReservation(sessionPath);
|
|
51
64
|
if (sessionPath && this.reservations.has(sessionPath)) {
|
|
52
65
|
// Attach-on-open: a live session outlives individual client attachments, so a
|
|
53
66
|
// resume (or a second surface) for an already-hosted path joins the existing
|
|
54
|
-
// runtime instead of failing.
|
|
55
|
-
//
|
|
67
|
+
// runtime instead of failing. An entry still opening keeps the exclusive
|
|
68
|
+
// reservation and rejects as before.
|
|
56
69
|
const existing = [...this.entries].find(([, entry]) => entry.reservationKey === sessionPath && entry.state === "open");
|
|
57
70
|
if (!existing)
|
|
58
71
|
throw new RpcSessionRegistryError("session_path_in_use");
|
|
@@ -96,6 +109,7 @@ export class RpcSessionRegistry {
|
|
|
96
109
|
state: "opening",
|
|
97
110
|
scope: new ProviderScope(),
|
|
98
111
|
profile: storedProfile,
|
|
112
|
+
...sessionIdentity(storedProfile),
|
|
99
113
|
sessionPath,
|
|
100
114
|
reservationKey: sessionPath,
|
|
101
115
|
cwd: storedProfile.cwd,
|
|
@@ -171,6 +185,36 @@ export class RpcSessionRegistry {
|
|
|
171
185
|
throw new RpcSessionRegistryError("open_failed", error instanceof Error ? error.message : undefined);
|
|
172
186
|
}
|
|
173
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Waits out a teardown already in flight for this path before the open decides.
|
|
190
|
+
*
|
|
191
|
+
* A close FREES the path, but the entry keeps its reservation until its runtime is
|
|
192
|
+
* disposed, so an open landing inside that window used to be refused with
|
|
193
|
+
* `session_path_in_use` for a session that no longer exists - making "reopen the
|
|
194
|
+
* path I just closed" a race against disposal latency, which no client can time.
|
|
195
|
+
* The open now waits for the teardown it would have been refused by and then opens
|
|
196
|
+
* the file fresh. Bounded by the same grace window that bounds the teardown itself
|
|
197
|
+
* (`closeMarkedSession` force-releases at that deadline), so a wedged disposal
|
|
198
|
+
* still ends in the ordinary refusal instead of an open that never answers.
|
|
199
|
+
*/
|
|
200
|
+
async settleClosingReservation(sessionPath) {
|
|
201
|
+
const closing = [...this.entries.values()].find((entry) => entry.reservationKey === sessionPath && entry.state === "closing");
|
|
202
|
+
if (!closing?.closeCompletion)
|
|
203
|
+
return;
|
|
204
|
+
let deadline;
|
|
205
|
+
try {
|
|
206
|
+
await Promise.race([
|
|
207
|
+
closing.closeCompletion,
|
|
208
|
+
new Promise((resolve) => {
|
|
209
|
+
deadline = setTimeout(resolve, this.closeGraceMs);
|
|
210
|
+
}),
|
|
211
|
+
]);
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
if (deadline)
|
|
215
|
+
clearTimeout(deadline);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
174
218
|
/**
|
|
175
219
|
* Read-only lookup with no state transitions or attachment accounting.
|
|
176
220
|
* Exists so lifecycle decisions (e.g. deferring a dropped connection's
|
|
@@ -218,6 +262,8 @@ export class RpcSessionRegistry {
|
|
|
218
262
|
sessionPath: entry.sessionPath,
|
|
219
263
|
cwd: entry.cwd,
|
|
220
264
|
name: entry.runtime?.session.sessionManager.getSessionName(),
|
|
265
|
+
kind: entry.kind,
|
|
266
|
+
context: entry.context,
|
|
221
267
|
// A closing entry has already released its last attachment; never publish that as negative.
|
|
222
268
|
attachments: Math.max(0, entry.attachments),
|
|
223
269
|
status: entry.state === "quarantined" ? "closing" : entry.state,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, realpathSync } from \"node:fs\";\nimport { basename, dirname, isAbsolute, resolve } from \"node:path\";\nimport { ProviderScope, runWithProviderScope } from \"@earendil-works/pi-ai/node/provider-scope\";\nimport {\n\ttype AgentSessionLaunchProfile,\n\tAgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\tcreateAgentSessionRuntime,\n} from \"../../core/agent-session-runtime.ts\";\nimport type { SessionStartEvent } from \"../../core/extensions/types.ts\";\nimport { SessionManager } from \"../../core/session-manager.ts\";\nimport { beginSessionClose, closeMarkedSession, closeSession, type SessionTeardownHost } from \"./session-teardown.ts\";\nimport type { SessionWorkerClient } from \"./session-worker-client.ts\";\n\n/** The immutable flags selected when a routing session is opened. */\nexport interface RpcSessionLaunchProfile extends AgentSessionLaunchProfile {\n\tsessionPath?: string;\n}\n\nexport type SessionRuntime = AgentSessionRuntime;\nexport type RpcSessionState = \"opening\" | \"open\" | \"closing\" | \"quarantined\" | \"closed\";\n\nexport interface RpcSessionEntry {\n\tstate: RpcSessionState;\n\truntime?: SessionRuntime;\n\tworker?: SessionWorkerClient;\n\t/** Resolves replacement against the runtime currently owned by this entry. */\n\tswitchSession?: SessionRuntime[\"switchSession\"];\n\t/** Rebind callback installed by the shared RPC connection handler. */\n\trebindSession?: Parameters<SessionRuntime[\"setRebindSession\"]>[0];\n\tscope: ProviderScope;\n\tprofile: Readonly<RpcSessionLaunchProfile>;\n\tdurableSessionId?: string;\n\tsessionPath?: string;\n\t/** Canonical reservation key for path-opened sessions; matches the reservations set. */\n\treservationKey?: string;\n\t/** Key granted for the spelling this session was opened with; cleared once superseded. */\n\trequestedPathKey?: string;\n\t/** Current runtime cwd, which can change when a session is replaced. */\n\tcwd: string;\n\t/** Live attachments (open + later attaches). The runtime is disposed only when the last one closes. */\n\tattachments: number;\n\t/**\n\t * Opt-in retention: a dropped connection only DETACHES from this session. The\n\t * entry stays open at zero attachments (still listed, still running its turn,\n\t * still holding its path) until an explicit close_session or idle eviction.\n\t * Requested per `open_session`; an attach may turn it on, never off.\n\t */\n\tretainOnDisconnect?: boolean;\n\t/** Timestamp of the last routed command / observed activity; drives idle eviction. */\n\tlastCommandAt: number;\n\tlifecycleMutex: Promise<void>;\n\tcloseCompletion?: Promise<void>;\n\tcloseResolve?: () => void;\n\tcloseStarted?: boolean;\n}\n\nexport class RpcSessionRegistryError extends Error {\n\treadonly code:\n\t\t| \"unknown_session\"\n\t\t| \"session_closing\"\n\t\t| \"session_path_in_use\"\n\t\t| \"session_reservation_limit\"\n\t\t| \"invalid_path\"\n\t\t| \"open_failed\";\n\n\tconstructor(code: RpcSessionRegistryError[\"code\"], reason?: string) {\n\t\tsuper(code === \"open_failed\" && reason ? `${code}: ${reason}` : code);\n\t\tthis.code = code;\n\t\tthis.name = \"RpcSessionRegistryError\";\n\t}\n}\n\nexport interface RpcSessionRegistryOptions {\n\tagentDir: string;\n\tcreateRuntime: CreateAgentSessionRuntimeFactory;\n\t/** Injectable clock (defaults to Date.now) so idle bookkeeping is testable. */\n\tnow?: () => number;\n\t/** Maximum time to wait for graceful runtime teardown before forced release. */\n\tcloseGraceMs?: number;\n}\n\n/** Host-side lifecycle policy for one `open_session`, distinct from the session's launch profile. */\nexport interface RpcSessionOpenOptions {\n\t/** Keep the session alive when its last client disconnects (`open_session.retain_on_disconnect`). */\n\tretainOnDisconnect?: boolean;\n}\n\nexport interface OpenRpcSession {\n\tsessionId: string;\n\tdurableSessionId: string;\n\tsessionPath?: string;\n\t/** True when this open attached to an already-open session instead of creating one. */\n\tattached?: boolean;\n}\n\nfunction canonicalPath(path: string): string {\n\tconst absolutePath = resolve(path);\n\tif (existsSync(absolutePath)) return realpathSync(absolutePath);\n\treturn `${realpathSync(dirname(absolutePath))}/${basename(absolutePath)}`;\n}\n\nfunction frozenProfile(profile: RpcSessionLaunchProfile): Readonly<RpcSessionLaunchProfile> {\n\treturn Object.freeze({\n\t\t...profile,\n\t\t...(profile.creationModel ? { creationModel: Object.freeze({ ...profile.creationModel }) } : {}),\n\t});\n}\n\n/** Process-local lifecycle owner for multi-session RPC runtimes. */\nexport class RpcSessionRegistry {\n\tprivate readonly entries = new Map<string, RpcSessionEntry>();\n\tprivate readonly reservations = new Set<string>();\n\tprivate readonly teardownHost: SessionTeardownHost;\n\tprivate nextHandle = 0;\n\tprivate readonly options: RpcSessionRegistryOptions;\n\tprivate readonly now: () => number;\n\treadonly closeGraceMs: number;\n\n\tconstructor(options: RpcSessionRegistryOptions) {\n\t\tthis.options = options;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.closeGraceMs = options.closeGraceMs ?? 10_000;\n\t\tthis.teardownHost = {\n\t\t\tcloseGraceMs: this.closeGraceMs,\n\t\t\tget: (handle) => this.entries.get(handle),\n\t\t\tdelete: (handle) => this.entries.delete(handle),\n\t\t\treleaseReservation: (key) => this.reservations.delete(key),\n\t\t\tsync: () => this.syncRuntimeMetadata(),\n\t\t};\n\t}\n\n\t/** Number of live entries, including ones still opening or closing. */\n\tget size(): number {\n\t\treturn this.entries.size;\n\t}\n\n\tasync openSession(profile: RpcSessionLaunchProfile, options?: RpcSessionOpenOptions): Promise<OpenRpcSession> {\n\t\tthis.validateProfile(profile);\n\t\tthis.syncRuntimeMetadata();\n\t\tconst sessionPath = profile.sessionPath ? canonicalPath(profile.sessionPath) : undefined;\n\t\tif (sessionPath && this.reservations.has(sessionPath)) {\n\t\t\t// Attach-on-open: a live session outlives individual client attachments, so a\n\t\t\t// resume (or a second surface) for an already-hosted path joins the existing\n\t\t\t// runtime instead of failing. Entries still opening or closing keep the\n\t\t\t// exclusive reservation and reject as before.\n\t\t\tconst existing = [...this.entries].find(\n\t\t\t\t([, entry]) => entry.reservationKey === sessionPath && entry.state === \"open\",\n\t\t\t);\n\t\t\tif (!existing) throw new RpcSessionRegistryError(\"session_path_in_use\");\n\t\t\tconst [handle, entry] = existing;\n\t\t\tentry.attachments += 1;\n\t\t\t// Retention is a property of the live session: any attach may ask for it, and\n\t\t\t// no attach may revoke it for the clients that already rely on it.\n\t\t\tif (options?.retainOnDisconnect) entry.retainOnDisconnect = true;\n\t\t\tif (!entry.durableSessionId) throw new RpcSessionRegistryError(\"session_path_in_use\");\n\t\t\tentry.lastCommandAt = this.now();\n\t\t\treturn {\n\t\t\t\tsessionId: handle,\n\t\t\t\tdurableSessionId: entry.durableSessionId,\n\t\t\t\tsessionPath: entry.sessionPath,\n\t\t\t\tattached: true,\n\t\t\t};\n\t\t}\n\t\tif (sessionPath) this.reservations.add(sessionPath);\n\n\t\t// Resume vs create parity (D1 + omo SenpiSessionRuntime.ts:198-200):\n\t\t// Create-only launch semantics mirror classic startup flags. A resumed\n\t\t// session restores its persisted model and thinking level instead of being\n\t\t// overridden by the new open_session request.\n\t\tconst isResume = sessionPath !== undefined && existsSync(sessionPath);\n\t\t// Re-opening an existing session file is a resume, exactly like interactive\n\t\t// /resume (AgentSessionRuntime.switchSession). Without the event the session\n\t\t// starts with reason \"startup\" and every extension that only rebuilds state\n\t\t// on a resume - the ask-user dangling-question hook - stays unreachable from\n\t\t// the RPC restart path. A session created by this open stays \"startup\".\n\t\tconst sessionStartEvent: SessionStartEvent | undefined = isResume\n\t\t\t? { type: \"session_start\", reason: \"resume\" }\n\t\t\t: undefined;\n\t\tconst storedProfile = frozenProfile({ ...profile, ...(sessionPath ? { sessionPath } : {}) });\n\t\tconst runtimeProfile = isResume\n\t\t\t? frozenProfile({ ...storedProfile, creationModel: undefined, initialThinkingLevel: undefined })\n\t\t\t: storedProfile;\n\n\t\tconst handle = `rpc-${++this.nextHandle}`;\n\t\tconst entry: RpcSessionEntry = {\n\t\t\tstate: \"opening\",\n\t\t\tscope: new ProviderScope(),\n\t\t\tprofile: storedProfile,\n\t\t\tsessionPath,\n\t\t\treservationKey: sessionPath,\n\t\t\tcwd: storedProfile.cwd,\n\t\t\tattachments: 1,\n\t\t\tretainOnDisconnect: options?.retainOnDisconnect === true,\n\t\t\tlastCommandAt: this.now(),\n\t\t\tlifecycleMutex: Promise.resolve(),\n\t\t};\n\t\tentry.switchSession = (sessionPath, options) => {\n\t\t\tconst operation = entry.lifecycleMutex.then(async () => {\n\t\t\t\tif (entry.state !== \"open\" || !entry.runtime) {\n\t\t\t\t\tthrow new RpcSessionRegistryError(\"unknown_session\");\n\t\t\t\t}\n\t\t\t\tconst runtime = entry.runtime;\n\t\t\t\tconst cwdOverride = options?.cwdOverride;\n\t\t\t\tconst cwdChanged = cwdOverride !== undefined && runtime.session.sessionManager.getCwd() !== cwdOverride;\n\t\t\t\tconst result = await runtime.switchSession(sessionPath, options);\n\t\t\t\tif (result.cancelled || !cwdChanged) return result;\n\n\t\t\t\t// A multi-session binding outlives an individual replacement. Keep the\n\t\t\t\t// entry's runtime object aligned with the replacement so every attached\n\t\t\t\t// client resolves getters and future commands against the new cwd-bound\n\t\t\t\t// runtime, not the object created during open_session.\n\t\t\t\tconst replacement = new AgentSessionRuntime(\n\t\t\t\t\truntime.session,\n\t\t\t\t\truntime.services,\n\t\t\t\t\tthis.options.createRuntime,\n\t\t\t\t\t[...runtime.diagnostics],\n\t\t\t\t\truntime.modelFallbackMessage,\n\t\t\t\t\truntime.launchProfile,\n\t\t\t\t);\n\t\t\t\treplacement.setRebindSession(entry.rebindSession);\n\t\t\t\tentry.runtime = replacement;\n\t\t\t\tthis.syncRuntimeMetadata();\n\t\t\t\treturn result;\n\t\t\t});\n\t\t\tentry.lifecycleMutex = operation.then(\n\t\t\t\t() => undefined,\n\t\t\t\t() => undefined,\n\t\t\t);\n\t\t\treturn operation;\n\t\t};\n\t\tthis.entries.set(handle, entry);\n\t\ttry {\n\t\t\tconst manager = sessionPath\n\t\t\t\t? SessionManager.open(sessionPath, undefined, storedProfile.cwd)\n\t\t\t\t: SessionManager.create(storedProfile.cwd);\n\t\t\tentry.runtime = await runWithProviderScope(entry.scope, () =>\n\t\t\t\tcreateAgentSessionRuntime(this.options.createRuntime, {\n\t\t\t\t\tcwd: manager.getCwd(),\n\t\t\t\t\tagentDir: this.options.agentDir,\n\t\t\t\t\tsessionManager: manager,\n\t\t\t\t\tsessionStartEvent,\n\t\t\t\t\tlaunchProfile: runtimeProfile,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tentry.durableSessionId = manager.getSessionId();\n\t\t\tentry.sessionPath ??= manager.getSessionFile();\n\t\t\tentry.state = \"open\";\n\t\t\treturn { sessionId: handle, durableSessionId: entry.durableSessionId, sessionPath: entry.sessionPath };\n\t\t} catch (error) {\n\t\t\t// Runtime construction may have started extensions, watchers, and provider\n\t\t\t// registrations before it rejects. Keep the reservation and entry private\n\t\t\t// until all of those resources have been torn down, then release them as\n\t\t\t// one rollback so the path can immediately be opened again.\n\t\t\ttry {\n\t\t\t\tawait entry.runtime?.dispose();\n\t\t\t} catch {\n\t\t\t\t// The original construction error remains the externally visible cause.\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tawait entry.scope.close?.();\n\t\t\t\t} finally {\n\t\t\t\t\tthis.entries.delete(handle);\n\t\t\t\t\tif (sessionPath) this.reservations.delete(sessionPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (error instanceof RpcSessionRegistryError) throw error;\n\t\t\tthrow new RpcSessionRegistryError(\"open_failed\", error instanceof Error ? error.message : undefined);\n\t\t}\n\t}\n\n\t/**\n\t * Read-only lookup with no state transitions or attachment accounting.\n\t * Exists so lifecycle decisions (e.g. deferring a dropped connection's\n\t * release while a turn is still streaming) can inspect the live entry\n\t * without claiming it.\n\t */\n\tpeek(handle: string): RpcSessionEntry | undefined {\n\t\treturn this.entries.get(handle);\n\t}\n\n\tgetForCommand(handle: string, command: string): RpcSessionEntry {\n\t\tconst entry = this.entries.get(handle);\n\t\tif (!entry) throw new RpcSessionRegistryError(\"unknown_session\");\n\t\tif (\n\t\t\tentry.state === \"closing\" &&\n\t\t\t![\"abort\", \"abort_bash\", \"extension_ui_response\", \"extension_ui_progress\"].includes(command)\n\t\t) {\n\t\t\tthrow new RpcSessionRegistryError(\"session_closing\");\n\t\t}\n\t\tif (entry.state !== \"open\" && entry.state !== \"closing\") throw new RpcSessionRegistryError(\"unknown_session\");\n\t\t// Every routed command counts as activity for idle eviction. Lookups that\n\t\t// must not refresh idleness (sweeps, listing) use peek()/list() instead.\n\t\tentry.lastCommandAt = this.now();\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Starts a close synchronously and returns the live entry for routing decisions.\n\t * `detach` marks a client going away rather than the session ending, which a\n\t * retained entry answers by staying open at zero attachments.\n\t */\n\tbeginClose(handle: string, onRole?: (finalizer: boolean) => void, options?: { detach?: boolean }): RpcSessionEntry {\n\t\treturn beginSessionClose(this.teardownHost, handle, onRole, options);\n\t}\n\n\tasync close(handle: string): Promise<void> {\n\t\treturn closeSession(this.teardownHost, handle);\n\t}\n\n\t/** Completes a close previously made visible by beginClose(). */\n\tasync closeMarked(handle: string): Promise<void> {\n\t\treturn closeMarkedSession(this.teardownHost, handle);\n\t}\n\n\tlist(): Array<{\n\t\tsessionId: string;\n\t\tdurableSessionId?: string;\n\t\tsessionPath?: string;\n\t\tcwd: string;\n\t\tname?: string;\n\t\tstatus: Exclude<RpcSessionState, \"quarantined\">;\n\t\tattachments: number;\n\t}> {\n\t\tthis.syncRuntimeMetadata();\n\t\treturn [...this.entries].map(([sessionId, entry]) => ({\n\t\t\tsessionId,\n\t\t\tdurableSessionId: entry.durableSessionId,\n\t\t\tsessionPath: entry.sessionPath,\n\t\t\tcwd: entry.cwd,\n\t\t\tname: entry.runtime?.session.sessionManager.getSessionName(),\n\t\t\t// A closing entry has already released its last attachment; never publish that as negative.\n\t\t\tattachments: Math.max(0, entry.attachments),\n\t\t\tstatus: entry.state === \"quarantined\" ? \"closing\" : entry.state,\n\t\t}));\n\t}\n\n\t/** Reconcile path and durable identity after runtime replacement. */\n\tprivate syncRuntimeMetadata(): void {\n\t\tfor (const entry of this.entries.values()) {\n\t\t\tconst manager = entry.runtime?.session.sessionManager;\n\t\t\tif (!manager) continue;\n\t\t\tconst currentPath = manager.getSessionFile();\n\t\t\t// Preserve the originally canonicalized key while the runtime still points at\n\t\t\t// the same path. SessionManager may expose a symlink-resolved spelling after\n\t\t\t// opening a file that did not exist yet; treating that as replacement would\n\t\t\t// break ordinary attach-on-open aliases.\n\t\t\tif (currentPath !== entry.sessionPath) {\n\t\t\t\tconst currentKey = currentPath ? canonicalPath(currentPath) : undefined;\n\t\t\t\tif (entry.reservationKey) this.reservations.delete(entry.reservationKey);\n\t\t\t\tif (currentKey) this.reservations.add(currentKey);\n\t\t\t\tentry.reservationKey = currentKey;\n\t\t\t\tentry.sessionPath = currentPath;\n\t\t\t}\n\t\t\tentry.durableSessionId = manager.getSessionId();\n\t\t\tentry.cwd = manager.getCwd();\n\t\t}\n\t}\n\n\tprivate validateProfile(profile: RpcSessionLaunchProfile): void {\n\t\tif (!isAbsolute(profile.cwd) || (profile.sessionPath !== undefined && !isAbsolute(profile.sessionPath))) {\n\t\t\tthrow new RpcSessionRegistryError(\"invalid_path\");\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, realpathSync } from \"node:fs\";\nimport { basename, dirname, isAbsolute, resolve } from \"node:path\";\nimport { ProviderScope, runWithProviderScope } from \"@earendil-works/pi-ai/node/provider-scope\";\nimport {\n\ttype AgentSessionLaunchProfile,\n\tAgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\tcreateAgentSessionRuntime,\n} from \"../../core/agent-session-runtime.ts\";\nimport type { SessionContext, SessionKind, SessionStartEvent } from \"../../core/extensions/types.ts\";\nimport { EMPTY_SESSION_CONTEXT } from \"../../core/extensions/types.ts\";\nimport { SessionManager } from \"../../core/session-manager.ts\";\nimport { beginSessionClose, closeMarkedSession, closeSession, type SessionTeardownHost } from \"./session-teardown.ts\";\nimport type { SessionWorkerClient } from \"./session-worker-client.ts\";\n\n/** The immutable flags selected when a routing session is opened. */\nexport interface RpcSessionLaunchProfile extends AgentSessionLaunchProfile {\n\tsessionPath?: string;\n}\n\nexport type SessionRuntime = AgentSessionRuntime;\nexport type RpcSessionState = \"opening\" | \"open\" | \"closing\" | \"quarantined\" | \"closed\";\n\nexport interface RpcSessionEntry {\n\tstate: RpcSessionState;\n\truntime?: SessionRuntime;\n\tworker?: SessionWorkerClient;\n\t/** Visibility class chosen by the open, frozen for the entry's life. */\n\treadonly kind: SessionKind;\n\t/** Frozen opaque labels the open attached; `{}` when it attached none. */\n\treadonly context: SessionContext;\n\t/** Resolves replacement against the runtime currently owned by this entry. */\n\tswitchSession?: SessionRuntime[\"switchSession\"];\n\t/** Rebind callback installed by the shared RPC connection handler. */\n\trebindSession?: Parameters<SessionRuntime[\"setRebindSession\"]>[0];\n\tscope: ProviderScope;\n\tprofile: Readonly<RpcSessionLaunchProfile>;\n\tdurableSessionId?: string;\n\tsessionPath?: string;\n\t/** Canonical reservation key for path-opened sessions; matches the reservations set. */\n\treservationKey?: string;\n\t/** Key granted for the spelling this session was opened with; cleared once superseded. */\n\trequestedPathKey?: string;\n\t/** Current runtime cwd, which can change when a session is replaced. */\n\tcwd: string;\n\t/** Live attachments (open + later attaches). The runtime is disposed only when the last one closes. */\n\tattachments: number;\n\t/**\n\t * Opt-in retention: a dropped connection only DETACHES from this session. The\n\t * entry stays open at zero attachments (still listed, still running its turn,\n\t * still holding its path) until an explicit close_session or idle eviction.\n\t * Requested per `open_session`; an attach may turn it on, never off.\n\t */\n\tretainOnDisconnect?: boolean;\n\t/** Timestamp of the last routed command / observed activity; drives idle eviction. */\n\tlastCommandAt: number;\n\tlifecycleMutex: Promise<void>;\n\tcloseCompletion?: Promise<void>;\n\tcloseResolve?: () => void;\n\tcloseStarted?: boolean;\n}\n\nexport class RpcSessionRegistryError extends Error {\n\treadonly code:\n\t\t| \"unknown_session\"\n\t\t| \"session_closing\"\n\t\t| \"session_path_in_use\"\n\t\t| \"session_reservation_limit\"\n\t\t| \"invalid_path\"\n\t\t| \"open_failed\";\n\n\tconstructor(code: RpcSessionRegistryError[\"code\"], reason?: string) {\n\t\tsuper(code === \"open_failed\" && reason ? `${code}: ${reason}` : code);\n\t\tthis.code = code;\n\t\tthis.name = \"RpcSessionRegistryError\";\n\t}\n}\n\nexport interface RpcSessionRegistryOptions {\n\tagentDir: string;\n\tcreateRuntime: CreateAgentSessionRuntimeFactory;\n\t/** Injectable clock (defaults to Date.now) so idle bookkeeping is testable. */\n\tnow?: () => number;\n\t/** Maximum time to wait for graceful runtime teardown before forced release. */\n\tcloseGraceMs?: number;\n}\n\n/** Host-side lifecycle policy for one `open_session`, distinct from the session's launch profile. */\nexport interface RpcSessionOpenOptions {\n\t/** Keep the session alive when its last client disconnects (`open_session.retain_on_disconnect`). */\n\tretainOnDisconnect?: boolean;\n}\n\n/** One `list_sessions` row. `context` is published only to a listing that asked for workers. */\nexport interface RpcSessionRow {\n\tsessionId: string;\n\tdurableSessionId?: string;\n\tsessionPath?: string;\n\tcwd: string;\n\tname?: string;\n\tstatus: Exclude<RpcSessionState, \"quarantined\">;\n\tattachments: number;\n\tkind: SessionKind;\n\tcontext: SessionContext;\n}\n\nexport interface OpenRpcSession {\n\tsessionId: string;\n\tdurableSessionId: string;\n\tsessionPath?: string;\n\t/** True when this open attached to an already-open session instead of creating one. */\n\tattached?: boolean;\n}\n\nfunction canonicalPath(path: string): string {\n\tconst absolutePath = resolve(path);\n\tif (existsSync(absolutePath)) return realpathSync(absolutePath);\n\treturn `${realpathSync(dirname(absolutePath))}/${basename(absolutePath)}`;\n}\n\n/** Freezes an open's launch inputs, including the nested objects a client supplied. */\nexport function frozenProfile(profile: RpcSessionLaunchProfile): Readonly<RpcSessionLaunchProfile> {\n\treturn Object.freeze({\n\t\t...profile,\n\t\t...(profile.creationModel ? { creationModel: Object.freeze({ ...profile.creationModel }) } : {}),\n\t\t...(profile.sessionContext ? { sessionContext: Object.freeze({ ...profile.sessionContext }) } : {}),\n\t});\n}\n\n/**\n * The visibility class and labels an entry keeps for its life, normalized once here so no\n * lifecycle, listing or delivery decision has to re-apply the defaults. Reads the already\n * frozen profile, so the entry and the runtime share one frozen context object.\n */\nexport function sessionIdentity(profile: Readonly<RpcSessionLaunchProfile>): {\n\treadonly kind: SessionKind;\n\treadonly context: SessionContext;\n} {\n\treturn { kind: profile.sessionKind ?? \"interactive\", context: profile.sessionContext ?? EMPTY_SESSION_CONTEXT };\n}\n\n/** Process-local lifecycle owner for multi-session RPC runtimes. */\nexport class RpcSessionRegistry {\n\tprivate readonly entries = new Map<string, RpcSessionEntry>();\n\tprivate readonly reservations = new Set<string>();\n\tprivate readonly teardownHost: SessionTeardownHost;\n\tprivate nextHandle = 0;\n\tprivate readonly options: RpcSessionRegistryOptions;\n\tprivate readonly now: () => number;\n\treadonly closeGraceMs: number;\n\n\tconstructor(options: RpcSessionRegistryOptions) {\n\t\tthis.options = options;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.closeGraceMs = options.closeGraceMs ?? 10_000;\n\t\tthis.teardownHost = {\n\t\t\tcloseGraceMs: this.closeGraceMs,\n\t\t\tget: (handle) => this.entries.get(handle),\n\t\t\tdelete: (handle) => this.entries.delete(handle),\n\t\t\treleaseReservation: (key) => this.reservations.delete(key),\n\t\t\tsync: () => this.syncRuntimeMetadata(),\n\t\t};\n\t}\n\n\t/** Number of live entries, including ones still opening or closing. */\n\tget size(): number {\n\t\treturn this.entries.size;\n\t}\n\n\tasync openSession(profile: RpcSessionLaunchProfile, options?: RpcSessionOpenOptions): Promise<OpenRpcSession> {\n\t\tthis.validateProfile(profile);\n\t\tthis.syncRuntimeMetadata();\n\t\tconst sessionPath = profile.sessionPath ? canonicalPath(profile.sessionPath) : undefined;\n\t\tif (sessionPath) await this.settleClosingReservation(sessionPath);\n\t\tif (sessionPath && this.reservations.has(sessionPath)) {\n\t\t\t// Attach-on-open: a live session outlives individual client attachments, so a\n\t\t\t// resume (or a second surface) for an already-hosted path joins the existing\n\t\t\t// runtime instead of failing. An entry still opening keeps the exclusive\n\t\t\t// reservation and rejects as before.\n\t\t\tconst existing = [...this.entries].find(\n\t\t\t\t([, entry]) => entry.reservationKey === sessionPath && entry.state === \"open\",\n\t\t\t);\n\t\t\tif (!existing) throw new RpcSessionRegistryError(\"session_path_in_use\");\n\t\t\tconst [handle, entry] = existing;\n\t\t\tentry.attachments += 1;\n\t\t\t// Retention is a property of the live session: any attach may ask for it, and\n\t\t\t// no attach may revoke it for the clients that already rely on it.\n\t\t\tif (options?.retainOnDisconnect) entry.retainOnDisconnect = true;\n\t\t\tif (!entry.durableSessionId) throw new RpcSessionRegistryError(\"session_path_in_use\");\n\t\t\tentry.lastCommandAt = this.now();\n\t\t\treturn {\n\t\t\t\tsessionId: handle,\n\t\t\t\tdurableSessionId: entry.durableSessionId,\n\t\t\t\tsessionPath: entry.sessionPath,\n\t\t\t\tattached: true,\n\t\t\t};\n\t\t}\n\t\tif (sessionPath) this.reservations.add(sessionPath);\n\n\t\t// Resume vs create parity (D1 + omo SenpiSessionRuntime.ts:198-200):\n\t\t// Create-only launch semantics mirror classic startup flags. A resumed\n\t\t// session restores its persisted model and thinking level instead of being\n\t\t// overridden by the new open_session request.\n\t\tconst isResume = sessionPath !== undefined && existsSync(sessionPath);\n\t\t// Re-opening an existing session file is a resume, exactly like interactive\n\t\t// /resume (AgentSessionRuntime.switchSession). Without the event the session\n\t\t// starts with reason \"startup\" and every extension that only rebuilds state\n\t\t// on a resume - the ask-user dangling-question hook - stays unreachable from\n\t\t// the RPC restart path. A session created by this open stays \"startup\".\n\t\tconst sessionStartEvent: SessionStartEvent | undefined = isResume\n\t\t\t? { type: \"session_start\", reason: \"resume\" }\n\t\t\t: undefined;\n\t\tconst storedProfile = frozenProfile({ ...profile, ...(sessionPath ? { sessionPath } : {}) });\n\t\tconst runtimeProfile = isResume\n\t\t\t? frozenProfile({ ...storedProfile, creationModel: undefined, initialThinkingLevel: undefined })\n\t\t\t: storedProfile;\n\n\t\tconst handle = `rpc-${++this.nextHandle}`;\n\t\tconst entry: RpcSessionEntry = {\n\t\t\tstate: \"opening\",\n\t\t\tscope: new ProviderScope(),\n\t\t\tprofile: storedProfile,\n\t\t\t...sessionIdentity(storedProfile),\n\t\t\tsessionPath,\n\t\t\treservationKey: sessionPath,\n\t\t\tcwd: storedProfile.cwd,\n\t\t\tattachments: 1,\n\t\t\tretainOnDisconnect: options?.retainOnDisconnect === true,\n\t\t\tlastCommandAt: this.now(),\n\t\t\tlifecycleMutex: Promise.resolve(),\n\t\t};\n\t\tentry.switchSession = (sessionPath, options) => {\n\t\t\tconst operation = entry.lifecycleMutex.then(async () => {\n\t\t\t\tif (entry.state !== \"open\" || !entry.runtime) {\n\t\t\t\t\tthrow new RpcSessionRegistryError(\"unknown_session\");\n\t\t\t\t}\n\t\t\t\tconst runtime = entry.runtime;\n\t\t\t\tconst cwdOverride = options?.cwdOverride;\n\t\t\t\tconst cwdChanged = cwdOverride !== undefined && runtime.session.sessionManager.getCwd() !== cwdOverride;\n\t\t\t\tconst result = await runtime.switchSession(sessionPath, options);\n\t\t\t\tif (result.cancelled || !cwdChanged) return result;\n\n\t\t\t\t// A multi-session binding outlives an individual replacement. Keep the\n\t\t\t\t// entry's runtime object aligned with the replacement so every attached\n\t\t\t\t// client resolves getters and future commands against the new cwd-bound\n\t\t\t\t// runtime, not the object created during open_session.\n\t\t\t\tconst replacement = new AgentSessionRuntime(\n\t\t\t\t\truntime.session,\n\t\t\t\t\truntime.services,\n\t\t\t\t\tthis.options.createRuntime,\n\t\t\t\t\t[...runtime.diagnostics],\n\t\t\t\t\truntime.modelFallbackMessage,\n\t\t\t\t\truntime.launchProfile,\n\t\t\t\t);\n\t\t\t\treplacement.setRebindSession(entry.rebindSession);\n\t\t\t\tentry.runtime = replacement;\n\t\t\t\tthis.syncRuntimeMetadata();\n\t\t\t\treturn result;\n\t\t\t});\n\t\t\tentry.lifecycleMutex = operation.then(\n\t\t\t\t() => undefined,\n\t\t\t\t() => undefined,\n\t\t\t);\n\t\t\treturn operation;\n\t\t};\n\t\tthis.entries.set(handle, entry);\n\t\ttry {\n\t\t\tconst manager = sessionPath\n\t\t\t\t? SessionManager.open(sessionPath, undefined, storedProfile.cwd)\n\t\t\t\t: SessionManager.create(storedProfile.cwd);\n\t\t\tentry.runtime = await runWithProviderScope(entry.scope, () =>\n\t\t\t\tcreateAgentSessionRuntime(this.options.createRuntime, {\n\t\t\t\t\tcwd: manager.getCwd(),\n\t\t\t\t\tagentDir: this.options.agentDir,\n\t\t\t\t\tsessionManager: manager,\n\t\t\t\t\tsessionStartEvent,\n\t\t\t\t\tlaunchProfile: runtimeProfile,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tentry.durableSessionId = manager.getSessionId();\n\t\t\tentry.sessionPath ??= manager.getSessionFile();\n\t\t\tentry.state = \"open\";\n\t\t\treturn { sessionId: handle, durableSessionId: entry.durableSessionId, sessionPath: entry.sessionPath };\n\t\t} catch (error) {\n\t\t\t// Runtime construction may have started extensions, watchers, and provider\n\t\t\t// registrations before it rejects. Keep the reservation and entry private\n\t\t\t// until all of those resources have been torn down, then release them as\n\t\t\t// one rollback so the path can immediately be opened again.\n\t\t\ttry {\n\t\t\t\tawait entry.runtime?.dispose();\n\t\t\t} catch {\n\t\t\t\t// The original construction error remains the externally visible cause.\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tawait entry.scope.close?.();\n\t\t\t\t} finally {\n\t\t\t\t\tthis.entries.delete(handle);\n\t\t\t\t\tif (sessionPath) this.reservations.delete(sessionPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (error instanceof RpcSessionRegistryError) throw error;\n\t\t\tthrow new RpcSessionRegistryError(\"open_failed\", error instanceof Error ? error.message : undefined);\n\t\t}\n\t}\n\n\t/**\n\t * Waits out a teardown already in flight for this path before the open decides.\n\t *\n\t * A close FREES the path, but the entry keeps its reservation until its runtime is\n\t * disposed, so an open landing inside that window used to be refused with\n\t * `session_path_in_use` for a session that no longer exists - making \"reopen the\n\t * path I just closed\" a race against disposal latency, which no client can time.\n\t * The open now waits for the teardown it would have been refused by and then opens\n\t * the file fresh. Bounded by the same grace window that bounds the teardown itself\n\t * (`closeMarkedSession` force-releases at that deadline), so a wedged disposal\n\t * still ends in the ordinary refusal instead of an open that never answers.\n\t */\n\tprivate async settleClosingReservation(sessionPath: string): Promise<void> {\n\t\tconst closing = [...this.entries.values()].find(\n\t\t\t(entry) => entry.reservationKey === sessionPath && entry.state === \"closing\",\n\t\t);\n\t\tif (!closing?.closeCompletion) return;\n\t\tlet deadline: ReturnType<typeof setTimeout> | undefined;\n\t\ttry {\n\t\t\tawait Promise.race([\n\t\t\t\tclosing.closeCompletion,\n\t\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\t\tdeadline = setTimeout(resolve, this.closeGraceMs);\n\t\t\t\t}),\n\t\t\t]);\n\t\t} finally {\n\t\t\tif (deadline) clearTimeout(deadline);\n\t\t}\n\t}\n\n\t/**\n\t * Read-only lookup with no state transitions or attachment accounting.\n\t * Exists so lifecycle decisions (e.g. deferring a dropped connection's\n\t * release while a turn is still streaming) can inspect the live entry\n\t * without claiming it.\n\t */\n\tpeek(handle: string): RpcSessionEntry | undefined {\n\t\treturn this.entries.get(handle);\n\t}\n\n\tgetForCommand(handle: string, command: string): RpcSessionEntry {\n\t\tconst entry = this.entries.get(handle);\n\t\tif (!entry) throw new RpcSessionRegistryError(\"unknown_session\");\n\t\tif (\n\t\t\tentry.state === \"closing\" &&\n\t\t\t![\"abort\", \"abort_bash\", \"extension_ui_response\", \"extension_ui_progress\"].includes(command)\n\t\t) {\n\t\t\tthrow new RpcSessionRegistryError(\"session_closing\");\n\t\t}\n\t\tif (entry.state !== \"open\" && entry.state !== \"closing\") throw new RpcSessionRegistryError(\"unknown_session\");\n\t\t// Every routed command counts as activity for idle eviction. Lookups that\n\t\t// must not refresh idleness (sweeps, listing) use peek()/list() instead.\n\t\tentry.lastCommandAt = this.now();\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Starts a close synchronously and returns the live entry for routing decisions.\n\t * `detach` marks a client going away rather than the session ending, which a\n\t * retained entry answers by staying open at zero attachments.\n\t */\n\tbeginClose(handle: string, onRole?: (finalizer: boolean) => void, options?: { detach?: boolean }): RpcSessionEntry {\n\t\treturn beginSessionClose(this.teardownHost, handle, onRole, options);\n\t}\n\n\tasync close(handle: string): Promise<void> {\n\t\treturn closeSession(this.teardownHost, handle);\n\t}\n\n\t/** Completes a close previously made visible by beginClose(). */\n\tasync closeMarked(handle: string): Promise<void> {\n\t\treturn closeMarkedSession(this.teardownHost, handle);\n\t}\n\n\tlist(): RpcSessionRow[] {\n\t\tthis.syncRuntimeMetadata();\n\t\treturn [...this.entries].map(([sessionId, entry]) => ({\n\t\t\tsessionId,\n\t\t\tdurableSessionId: entry.durableSessionId,\n\t\t\tsessionPath: entry.sessionPath,\n\t\t\tcwd: entry.cwd,\n\t\t\tname: entry.runtime?.session.sessionManager.getSessionName(),\n\t\t\tkind: entry.kind,\n\t\t\tcontext: entry.context,\n\t\t\t// A closing entry has already released its last attachment; never publish that as negative.\n\t\t\tattachments: Math.max(0, entry.attachments),\n\t\t\tstatus: entry.state === \"quarantined\" ? \"closing\" : entry.state,\n\t\t}));\n\t}\n\n\t/** Reconcile path and durable identity after runtime replacement. */\n\tprivate syncRuntimeMetadata(): void {\n\t\tfor (const entry of this.entries.values()) {\n\t\t\tconst manager = entry.runtime?.session.sessionManager;\n\t\t\tif (!manager) continue;\n\t\t\tconst currentPath = manager.getSessionFile();\n\t\t\t// Preserve the originally canonicalized key while the runtime still points at\n\t\t\t// the same path. SessionManager may expose a symlink-resolved spelling after\n\t\t\t// opening a file that did not exist yet; treating that as replacement would\n\t\t\t// break ordinary attach-on-open aliases.\n\t\t\tif (currentPath !== entry.sessionPath) {\n\t\t\t\tconst currentKey = currentPath ? canonicalPath(currentPath) : undefined;\n\t\t\t\tif (entry.reservationKey) this.reservations.delete(entry.reservationKey);\n\t\t\t\tif (currentKey) this.reservations.add(currentKey);\n\t\t\t\tentry.reservationKey = currentKey;\n\t\t\t\tentry.sessionPath = currentPath;\n\t\t\t}\n\t\t\tentry.durableSessionId = manager.getSessionId();\n\t\t\tentry.cwd = manager.getCwd();\n\t\t}\n\t}\n\n\tprivate validateProfile(profile: RpcSessionLaunchProfile): void {\n\t\tif (!isAbsolute(profile.cwd) || (profile.sessionPath !== undefined && !isAbsolute(profile.sessionPath))) {\n\t\t\tthrow new RpcSessionRegistryError(\"invalid_path\");\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CliRuntimeConfiguration } from "../../main.ts";
|
|
2
|
-
import { type OpenRpcSession, type RpcSessionEntry, type RpcSessionLaunchProfile, type RpcSessionOpenOptions } from "./session-registry.ts";
|
|
2
|
+
import { type OpenRpcSession, type RpcSessionEntry, type RpcSessionLaunchProfile, type RpcSessionOpenOptions, type RpcSessionRow } from "./session-registry.ts";
|
|
3
3
|
/** Transport-side lifecycle owner. Caller paths are never inspected on this event loop. */
|
|
4
4
|
export declare class WorkerSessionRegistry {
|
|
5
5
|
private readonly entries;
|
|
@@ -22,15 +22,7 @@ export declare class WorkerSessionRegistry {
|
|
|
22
22
|
}): RpcSessionEntry;
|
|
23
23
|
close(handle: string): Promise<void>;
|
|
24
24
|
closeMarked(handle: string): Promise<void>;
|
|
25
|
-
list():
|
|
26
|
-
sessionId: string;
|
|
27
|
-
durableSessionId?: string;
|
|
28
|
-
sessionPath?: string;
|
|
29
|
-
cwd: string;
|
|
30
|
-
name?: string;
|
|
31
|
-
status: Exclude<RpcSessionEntry["state"], "quarantined">;
|
|
32
|
-
attachments: number;
|
|
33
|
-
}>;
|
|
25
|
+
list(): RpcSessionRow[];
|
|
34
26
|
/** Only compare spellings already tied to a granted identity; do not inspect caller paths here. */
|
|
35
27
|
private knownReservationKey;
|
|
36
28
|
private attach;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-session-registry.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/worker-session-registry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAM7D,OAAO,
|
|
1
|
+
{"version":3,"file":"worker-session-registry.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/worker-session-registry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAM7D,OAAO,EAEN,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAE1B,KAAK,aAAa,EAElB,MAAM,uBAAuB,CAAC;AAI/B,2FAA2F;AAC3F,qBAAa,qBAAqB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAC9D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAC9D,OAAO,CAAC,MAAM,CAAK;IACnB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsF;IAE9G,YAAY,OAAO,EAAE;QAAE,aAAa,EAAE,uBAAuB,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,MAAM,CAAA;KAAE,EAIvG;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEK,WAAW,CAAC,OAAO,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAgE5G;IAED,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEhD;IAED,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAY9D;IAED,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,eAAe,CAsBjH;IAED,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnC;IAEK,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/C;IAED,IAAI,IAAI,aAAa,EAAE,CAgBtB;IAED,mGAAmG;IACnG,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,MAAM;IAad,wFAAwF;IACxF,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAED,OAAO,CAAC,OAAO;IAQf;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAUjB,mGAAmG;IACnG,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,UAAU;CAKlB"}
|