airaknit 1.1.2-rc.9
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/LICENSE +84 -0
- package/README.md +202 -0
- package/bin/airaknit +9 -0
- package/bin/airaknit-project +14 -0
- package/bin/kanna +9 -0
- package/dist/client/assets/CompactSummaryMessage-Yw0BDWEJ.js +1 -0
- package/dist/client/assets/ExitPlanModeMessage-DIdkQ4uF.js +1 -0
- package/dist/client/assets/LocalFilePreviewDialog-DQx2eiCc.js +3 -0
- package/dist/client/assets/LocalProjectsSection-C4xlWkgS.js +1 -0
- package/dist/client/assets/TextMessage-B5G39DEJ.js +1 -0
- package/dist/client/assets/UserMessage-CIkWk-0L.js +1 -0
- package/dist/client/assets/_basePickBy-CVrAFfnZ.js +1 -0
- package/dist/client/assets/_baseUniq-JL-aaF4P.js +1 -0
- package/dist/client/assets/arc-B07zg7ol.js +1 -0
- package/dist/client/assets/architecture-YZFGNWBL-PSLVJL3p.js +1 -0
- package/dist/client/assets/architectureDiagram-Q4EWVU46-DfWIF1G_.js +36 -0
- package/dist/client/assets/array-BGFCBI0e.js +1 -0
- package/dist/client/assets/blockDiagram-DXYQGD6D-CzwIeo_B.js +132 -0
- package/dist/client/assets/bundle-mjs-BDE2gWbQ.js +1 -0
- package/dist/client/assets/button-DO50qOGv.js +1 -0
- package/dist/client/assets/c4Diagram-AHTNJAMY-CR8DCQRE.js +10 -0
- package/dist/client/assets/channel-Dj-UUfaF.js +1 -0
- package/dist/client/assets/chunk-2KRD3SAO-dznP-cn8.js +1 -0
- package/dist/client/assets/chunk-336JU56O-Dqss5Vu6.js +2 -0
- package/dist/client/assets/chunk-426QAEUC-CEKis_0_.js +1 -0
- package/dist/client/assets/chunk-4BX2VUAB-BYOv0Gm1.js +1 -0
- package/dist/client/assets/chunk-4TB4RGXK-BxzubH5S.js +206 -0
- package/dist/client/assets/chunk-55IACEB6-BSlTj03a.js +1 -0
- package/dist/client/assets/chunk-5FUZZQ4R-9Au93Bi1.js +62 -0
- package/dist/client/assets/chunk-5PVQY5BW-BhksHFEZ.js +2 -0
- package/dist/client/assets/chunk-67CJDMHE-BFwhz-8t.js +1 -0
- package/dist/client/assets/chunk-7N4EOEYR-BDUPds87.js +1 -0
- package/dist/client/assets/chunk-AA7GKIK3-CEWTdyXO.js +1 -0
- package/dist/client/assets/chunk-BO2N2NFS-D0LvxnhU.js +103 -0
- package/dist/client/assets/chunk-BSJP7CBP-BNJnK6sq.js +1 -0
- package/dist/client/assets/chunk-Bj-mKKzh.js +1 -0
- package/dist/client/assets/chunk-CIAEETIT-CYhfoCeN.js +1 -0
- package/dist/client/assets/chunk-EDXVE4YY-C5ovJLc0.js +1 -0
- package/dist/client/assets/chunk-ENJZ2VHE-HOhYaeGr.js +10 -0
- package/dist/client/assets/chunk-FMBD7UC4-BLCiKcAQ.js +15 -0
- package/dist/client/assets/chunk-FOC6F5B3-B6GtY2ek.js +1 -0
- package/dist/client/assets/chunk-ICPOFSXX-DPoIZoC5.js +122 -0
- package/dist/client/assets/chunk-K5T4RW27-BsKN63rv.js +94 -0
- package/dist/client/assets/chunk-KGLVRYIC-BUGn9uuY.js +1 -0
- package/dist/client/assets/chunk-LIHQZDEY-DhaZyo03.js +1 -0
- package/dist/client/assets/chunk-ORNJ4GCN-DlpeeJyi.js +1 -0
- package/dist/client/assets/chunk-OYMX7WX6-Dc9q7aYA.js +231 -0
- package/dist/client/assets/chunk-QZHKN3VN-BEdrPoSb.js +1 -0
- package/dist/client/assets/chunk-U2HBQHQK-CIB3Bjjd.js +70 -0
- package/dist/client/assets/chunk-X2U36JSP-CtB-o8Yp.js +1 -0
- package/dist/client/assets/chunk-XPW4576I-C6iHhX_8.js +32 -0
- package/dist/client/assets/chunk-YZCP3GAM-CTmKr6ZH.js +1 -0
- package/dist/client/assets/chunk-ZZ45TVLE-BgU8A2RF.js +1 -0
- package/dist/client/assets/classDiagram-6PBFFD2Q-Bqk5e679.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-6pSaZOkC.js +1 -0
- package/dist/client/assets/client-BrKWI4CM.js +1 -0
- package/dist/client/assets/client-CGgNRU9w.js +1 -0
- package/dist/client/assets/client-DMSLRzg9.js +6 -0
- package/dist/client/assets/clone-DWcL7whJ.js +1 -0
- package/dist/client/assets/cose-bilkent-S5V4N54A-CrV5wsV_.js +1 -0
- package/dist/client/assets/cytoscape.esm--aLzKuep.js +321 -0
- package/dist/client/assets/dagre-CuRxWcrj.js +1 -0
- package/dist/client/assets/dagre-KV5264BT-BIDiVnkA.js +4 -0
- package/dist/client/assets/defaultLocale-CRZydyG6.js +1 -0
- package/dist/client/assets/diagram-5BDNPKRD-i1kjKRCB.js +10 -0
- package/dist/client/assets/diagram-G4DWMVQ6-9ZSLuhbl.js +24 -0
- package/dist/client/assets/diagram-MMDJMWI5-B4_CUjgv.js +43 -0
- package/dist/client/assets/diagram-TYMM5635-Ct5eTGS8.js +24 -0
- package/dist/client/assets/dist-CuB4kiSK.js +1 -0
- package/dist/client/assets/erDiagram-SMLLAGMA-Cy38ercc.js +85 -0
- package/dist/client/assets/flowDiagram-DWJPFMVM-CZKuYl0V.js +162 -0
- package/dist/client/assets/ganttDiagram-T4ZO3ILL-DLPjCh7a.js +292 -0
- package/dist/client/assets/gitGraph-7Q5UKJZL-DqbrtEp9.js +1 -0
- package/dist/client/assets/gitGraphDiagram-UUTBAWPF-BoRBkDhQ.js +106 -0
- package/dist/client/assets/graphlib-BcQ6qlQh.js +1 -0
- package/dist/client/assets/highlighted-body-OFNGDK62-BEpBVDTX.js +1 -0
- package/dist/client/assets/index-CetCiuqP.js +105 -0
- package/dist/client/assets/index-N29Mip7A.css +1 -0
- package/dist/client/assets/info-OMHHGYJF-D98DRBJX.js +1 -0
- package/dist/client/assets/infoDiagram-42DDH7IO-BAcdTWbt.js +2 -0
- package/dist/client/assets/init-B8gtcn7T.js +1 -0
- package/dist/client/assets/isArrayLikeObject-D8SJFmkN.js +1 -0
- package/dist/client/assets/isEmpty-BF3YX5Jk.js +1 -0
- package/dist/client/assets/ishikawaDiagram-UXIWVN3A-Ynu2VKdC.js +70 -0
- package/dist/client/assets/journeyDiagram-VCZTEJTY-BjfhQaN3.js +139 -0
- package/dist/client/assets/jsx-runtime-CyI9ICYU.js +1 -0
- package/dist/client/assets/kanban-definition-6JOO6SKY-JLXH9zUJ.js +89 -0
- package/dist/client/assets/katex-B94qP8b6.js +265 -0
- package/dist/client/assets/lib--QVjyxmL.js +29 -0
- package/dist/client/assets/lib-B6rgJiZ9.js +1 -0
- package/dist/client/assets/line-DCrYfLBn.js +1 -0
- package/dist/client/assets/linear-_4upLmeo.js +1 -0
- package/dist/client/assets/mermaid-GHXKKRXX-rwJHYUmW.js +1 -0
- package/dist/client/assets/mermaid-parser.core-KZinfW8o.js +4 -0
- package/dist/client/assets/mermaid.core-QqY9gSNe.js +11 -0
- package/dist/client/assets/mindmap-definition-QFDTVHPH-TWgHDAzp.js +96 -0
- package/dist/client/assets/ordinal-CCj7PWgZ.js +1 -0
- package/dist/client/assets/packet-4T2RLAQJ-DEvfkn3F.js +1 -0
- package/dist/client/assets/path-DZF-JdEe.js +1 -0
- package/dist/client/assets/pie-ZZUOXDRM-72e6WVjb.js +1 -0
- package/dist/client/assets/pieDiagram-DEJITSTG-Cl8PCsoj.js +30 -0
- package/dist/client/assets/preload-helper-rov5CBGT.js +1 -0
- package/dist/client/assets/pty-client-DZ27IS00.js +1 -0
- package/dist/client/assets/ptyInstancesStore-D9ag7SYd.js +1 -0
- package/dist/client/assets/quadrantDiagram-34T5L4WZ-CHyVGp9E.js +7 -0
- package/dist/client/assets/radar-PYXPWWZC-Cp7xd_EY.js +1 -0
- package/dist/client/assets/react-CClhXMB2.js +1 -0
- package/dist/client/assets/react-Dd6D81m0.js +1 -0
- package/dist/client/assets/react-dom--G6_6fQ_.js +1 -0
- package/dist/client/assets/requirementDiagram-MS252O5E-DaanG2iM.js +84 -0
- package/dist/client/assets/rough.esm-BsmKo2S5.js +1 -0
- package/dist/client/assets/sankeyDiagram-XADWPNL6-B_fhLY36.js +10 -0
- package/dist/client/assets/sequenceDiagram-FGHM5R23-C5FNrveI.js +157 -0
- package/dist/client/assets/src-DeTlMJAU.js +1 -0
- package/dist/client/assets/stateDiagram-FHFEXIEX-nTTcdjjQ.js +1 -0
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-Dw0632j_.js +1 -0
- package/dist/client/assets/timeline-definition-GMOUNBTQ-DkQV1yP8.js +120 -0
- package/dist/client/assets/treeView-SZITEDCU-ZLIgC7_K.js +1 -0
- package/dist/client/assets/treemap-W4RFUUIX-BqaMbB6N.js +1 -0
- package/dist/client/assets/uiIdentityOverlay-Ba7GNj7m.js +1 -0
- package/dist/client/assets/vennDiagram-DHZGUBPP-DbZ2xgs6.js +34 -0
- package/dist/client/assets/wardley-RL74JXVD-DXQS8zf4.js +1 -0
- package/dist/client/assets/wardleyDiagram-NUSXRM2D-BzCJ6MAu.js +20 -0
- package/dist/client/assets/xychartDiagram-5P7HB3ND-BSlFecop.js +7 -0
- package/dist/client/favicon.png +0 -0
- package/dist/client/favicon.svg +15 -0
- package/dist/client/fonts/body-medium.woff2 +0 -0
- package/dist/client/fonts/body-regular-italic.woff2 +0 -0
- package/dist/client/fonts/body-regular.woff2 +0 -0
- package/dist/client/fonts/body-semibold.woff2 +0 -0
- package/dist/client/index.html +31 -0
- package/dist/client/manifest.webmanifest +12 -0
- package/dist/client/sw.js +32 -0
- package/package.json +122 -0
- package/src/nats/auth-callout/callout-config.test.ts +93 -0
- package/src/nats/auth-callout/callout-config.ts +109 -0
- package/src/nats/auth-callout/callout.integration.test.ts +332 -0
- package/src/nats/auth-callout/keys.ts +103 -0
- package/src/nats/auth-callout/responder.ts +241 -0
- package/src/nats/auth-callout/scope-policy.test.ts +159 -0
- package/src/nats/auth-callout/scope-policy.ts +210 -0
- package/src/nats/auth-callout/token.test.ts +163 -0
- package/src/nats/auth-callout/token.ts +157 -0
- package/src/nats/nats-daemon-callout.ts +194 -0
- package/src/nats/nats-daemon.test.ts +77 -0
- package/src/nats/nats-daemon.ts +50 -0
- package/src/nats/nats-token.test.ts +61 -0
- package/src/nats/nats-token.ts +59 -0
- package/src/runner/coordination-mcp-integration.test.ts +134 -0
- package/src/runner/nats-coordination-client.test.ts +49 -0
- package/src/runner/nats-coordination-client.ts +94 -0
- package/src/runner/runner-agent.test.ts +469 -0
- package/src/runner/runner-agent.ts +453 -0
- package/src/runner/runner-credential.test.ts +93 -0
- package/src/runner/runner-credential.ts +82 -0
- package/src/runner/runner-nats.test.ts +495 -0
- package/src/runner/runner-nats.ts +323 -0
- package/src/runner/runner-pair.test.ts +107 -0
- package/src/runner/runner-pair.ts +81 -0
- package/src/runner/runner.test.ts +135 -0
- package/src/runner/runner.ts +212 -0
- package/src/runner/turn-factories.test.ts +97 -0
- package/src/runner/turn-factories.ts +475 -0
- package/src/server/agent-config-journey.test.ts +106 -0
- package/src/server/agent.ts +8 -0
- package/src/server/auto-continue/auth-error-detector.ts +66 -0
- package/src/server/auto-continue/limit-detector.ts +194 -0
- package/src/server/bm25.test.ts +92 -0
- package/src/server/bm25.ts +101 -0
- package/src/server/chat-events-jetstream.test.ts +135 -0
- package/src/server/claude-harness.ts +360 -0
- package/src/server/claude-pty/agent-normalizers.ts +309 -0
- package/src/server/claude-pty/auth.test.ts +38 -0
- package/src/server/claude-pty/auth.ts +32 -0
- package/src/server/claude-pty/claude-session-registry.adapter.ts +81 -0
- package/src/server/claude-pty/claude-session-registry.test.ts +149 -0
- package/src/server/claude-pty/driver.test.ts +902 -0
- package/src/server/claude-pty/driver.ts +807 -0
- package/src/server/claude-pty/jsonl-path.adapter.ts +57 -0
- package/src/server/claude-pty/jsonl-path.test.ts +114 -0
- package/src/server/claude-pty/jsonl-to-event.test.ts +241 -0
- package/src/server/claude-pty/jsonl-to-event.ts +174 -0
- package/src/server/claude-pty/output-ring.test.ts +35 -0
- package/src/server/claude-pty/output-ring.ts +25 -0
- package/src/server/claude-pty/parity-matrix.test.ts +227 -0
- package/src/server/claude-pty/pid-registry.adapter.ts +135 -0
- package/src/server/claude-pty/pid-registry.test.ts +122 -0
- package/src/server/claude-pty/preflight/binary-fingerprint.adapter.ts +20 -0
- package/src/server/claude-pty/preflight/binary-fingerprint.test.ts +32 -0
- package/src/server/claude-pty/pty-instance-registry.test.ts +177 -0
- package/src/server/claude-pty/pty-instance-registry.ts +166 -0
- package/src/server/claude-pty/pty-memory-sampler.adapter.test.ts +103 -0
- package/src/server/claude-pty/pty-memory-sampler.adapter.ts +85 -0
- package/src/server/claude-pty/pty-process.adapter.ts +66 -0
- package/src/server/claude-pty/pty-process.test.ts +49 -0
- package/src/server/claude-pty/resolve-binary.adapter.ts +106 -0
- package/src/server/claude-pty/resolve-binary.test.ts +118 -0
- package/src/server/claude-pty/runtime-dir.adapter.ts +19 -0
- package/src/server/claude-pty/settings-writer.adapter.ts +27 -0
- package/src/server/claude-pty/settings-writer.test.ts +22 -0
- package/src/server/claude-pty/smoke-test-io.adapter.ts +28 -0
- package/src/server/claude-pty/smoke-test.test.ts +191 -0
- package/src/server/claude-pty/smoke-test.ts +185 -0
- package/src/server/claude-pty/subagent-orchestrator.ts +887 -0
- package/src/server/claude-pty/tool-callback.ts +274 -0
- package/src/server/claude-pty/tui-control.test.ts +272 -0
- package/src/server/claude-pty/tui-control.ts +182 -0
- package/src/server/claude-pty/tui-source.adapter.test.ts +360 -0
- package/src/server/claude-pty/tui-source.adapter.ts +343 -0
- package/src/server/claude-pty/tunnel-gateway.ts +12 -0
- package/src/server/claude-pty-mcp/canonical-args.ts +15 -0
- package/src/server/claude-pty-mcp/fs-stat.adapter.ts +8 -0
- package/src/server/claude-pty-mcp/history-primer.ts +90 -0
- package/src/server/claude-pty-mcp/http-server.adapter.ts +33 -0
- package/src/server/claude-pty-mcp/mcp-http.ts +177 -0
- package/src/server/claude-pty-mcp/mcp.ts +412 -0
- package/src/server/claude-pty-mcp/mention-parser.ts +25 -0
- package/src/server/claude-pty-mcp/paths.ts +24 -0
- package/src/server/claude-pty-mcp/permission-gate.ts +243 -0
- package/src/server/claude-pty-mcp/terminal-pid-registry.adapter.ts +107 -0
- package/src/server/claude-pty-mcp/tools/ask-user-question.test.ts +119 -0
- package/src/server/claude-pty-mcp/tools/ask-user-question.ts +61 -0
- package/src/server/claude-pty-mcp/tools/bash.adapter.ts +76 -0
- package/src/server/claude-pty-mcp/tools/bash.test.ts +56 -0
- package/src/server/claude-pty-mcp/tools/delegate-subagent.test.ts +155 -0
- package/src/server/claude-pty-mcp/tools/delegate-subagent.ts +111 -0
- package/src/server/claude-pty-mcp/tools/edit.adapter.ts +95 -0
- package/src/server/claude-pty-mcp/tools/edit.test.ts +93 -0
- package/src/server/claude-pty-mcp/tools/exit-plan-mode.test.ts +61 -0
- package/src/server/claude-pty-mcp/tools/exit-plan-mode.ts +50 -0
- package/src/server/claude-pty-mcp/tools/glob.adapter.ts +86 -0
- package/src/server/claude-pty-mcp/tools/glob.test.ts +61 -0
- package/src/server/claude-pty-mcp/tools/grep.adapter.ts +126 -0
- package/src/server/claude-pty-mcp/tools/grep.test.ts +62 -0
- package/src/server/claude-pty-mcp/tools/read.adapter.ts +58 -0
- package/src/server/claude-pty-mcp/tools/read.test.ts +62 -0
- package/src/server/claude-pty-mcp/tools/tool-callback-shim.ts +42 -0
- package/src/server/claude-pty-mcp/tools/webfetch.test.ts +81 -0
- package/src/server/claude-pty-mcp/tools/webfetch.ts +82 -0
- package/src/server/claude-pty-mcp/tools/websearch.test.ts +40 -0
- package/src/server/claude-pty-mcp/tools/websearch.ts +42 -0
- package/src/server/claude-pty-mcp/tools/write.adapter.ts +60 -0
- package/src/server/claude-pty-mcp/tools/write.test.ts +52 -0
- package/src/server/claude-pty-mcp/uploads.adapter.ts +98 -0
- package/src/server/claude-pty-mcp/uploads.ts +38 -0
- package/src/server/claude-turn.test.ts +176 -0
- package/src/server/cli-runtime.test.ts +456 -0
- package/src/server/cli-runtime.ts +374 -0
- package/src/server/cli-supervisor.ts +81 -0
- package/src/server/cli.ts +78 -0
- package/src/server/client-log-forwarder.test.ts +74 -0
- package/src/server/client-log-forwarder.ts +75 -0
- package/src/server/codex-app-server-protocol.ts +449 -0
- package/src/server/codex-app-server.test.ts +2990 -0
- package/src/server/codex-app-server.ts +1713 -0
- package/src/server/coordination-integration.test.ts +63 -0
- package/src/server/coordination-mcp.test.ts +149 -0
- package/src/server/coordination-mcp.ts +197 -0
- package/src/server/delegation-coordinator.test.ts +675 -0
- package/src/server/delegation-coordinator.ts +454 -0
- package/src/server/discovery.test.ts +211 -0
- package/src/server/discovery.ts +301 -0
- package/src/server/event-store-agent-config.test.ts +124 -0
- package/src/server/event-store-coordination.test.ts +149 -0
- package/src/server/event-store-profile.test.ts +132 -0
- package/src/server/event-store-repo.test.ts +154 -0
- package/src/server/event-store-runner-team.test.ts +104 -0
- package/src/server/event-store.test.ts +342 -0
- package/src/server/event-store.ts +2208 -0
- package/src/server/events.ts +379 -0
- package/src/server/extension-router.test.ts +183 -0
- package/src/server/extension-router.ts +114 -0
- package/src/server/extensions/agents/server.test.ts +191 -0
- package/src/server/extensions/agents/server.ts +108 -0
- package/src/server/extensions/c3/server.test.ts +284 -0
- package/src/server/extensions/c3/server.ts +212 -0
- package/src/server/extensions/code/server.test.ts +200 -0
- package/src/server/extensions/code/server.ts +150 -0
- package/src/server/extensions.config.ts +10 -0
- package/src/server/external-open.ts +69 -0
- package/src/server/generate-fork-context.ts +58 -0
- package/src/server/generate-merge-context.test.ts +290 -0
- package/src/server/generate-merge-context.ts +141 -0
- package/src/server/generate-title.ts +36 -0
- package/src/server/git-clone-policy.test.ts +138 -0
- package/src/server/git-clone-policy.ts +27 -0
- package/src/server/harness-types.ts +1 -0
- package/src/server/journey-verification.test.ts +640 -0
- package/src/server/journey-verification.ts +195 -0
- package/src/server/machine-name.ts +22 -0
- package/src/server/nats-auth.test.ts +92 -0
- package/src/server/nats-auth.ts +6 -0
- package/src/server/nats-bind-guard.test.ts +71 -0
- package/src/server/nats-bind-guard.ts +42 -0
- package/src/server/nats-bridge.test.ts +141 -0
- package/src/server/nats-bridge.ts +111 -0
- package/src/server/nats-connector.test.ts +56 -0
- package/src/server/nats-connector.ts +71 -0
- package/src/server/nats-daemon-manager.test.ts +76 -0
- package/src/server/nats-daemon-manager.ts +174 -0
- package/src/server/nats-publisher.test.ts +356 -0
- package/src/server/nats-publisher.ts +271 -0
- package/src/server/nats-responders.test.ts +1018 -0
- package/src/server/nats-responders.ts +925 -0
- package/src/server/nats-streams.test.ts +112 -0
- package/src/server/nats-streams.ts +129 -0
- package/src/server/oauth-pool/oauth-responders.ts +185 -0
- package/src/server/oauth-pool/oauth-settings-store.ts +173 -0
- package/src/server/oauth-pool/oauth-token-pool.ts +303 -0
- package/src/server/orchestration.test.ts +1063 -0
- package/src/server/orchestration.ts +716 -0
- package/src/server/pairing-endpoints.test.ts +171 -0
- package/src/server/pairing-store.test.ts +154 -0
- package/src/server/pairing-store.ts +124 -0
- package/src/server/paths.ts +27 -0
- package/src/server/pr3-liveness.test.ts +252 -0
- package/src/server/process-utils.ts +10 -0
- package/src/server/project-cli.ts +180 -0
- package/src/server/provider-catalog.test.ts +177 -0
- package/src/server/provider-catalog.ts +146 -0
- package/src/server/pty-responders.ts +345 -0
- package/src/server/push-notifications.test.ts +234 -0
- package/src/server/push-notifications.ts +188 -0
- package/src/server/quick-response.test.ts +196 -0
- package/src/server/quick-response.ts +154 -0
- package/src/server/read-models-agent-config.test.ts +59 -0
- package/src/server/read-models-coordination.test.ts +69 -0
- package/src/server/read-models.test.ts +332 -0
- package/src/server/read-models.ts +258 -0
- package/src/server/repo-journey.test.ts +96 -0
- package/src/server/repo-manager.test.ts +118 -0
- package/src/server/repo-manager.ts +97 -0
- package/src/server/repo-status.test.ts +54 -0
- package/src/server/repo-status.ts +82 -0
- package/src/server/restart.test.ts +27 -0
- package/src/server/restart.ts +30 -0
- package/src/server/runner-incompatible-gate.test.ts +383 -0
- package/src/server/runner-manager.test.ts +72 -0
- package/src/server/runner-manager.ts +312 -0
- package/src/server/runner-pairing-urls.test.ts +59 -0
- package/src/server/runner-pairing-urls.ts +67 -0
- package/src/server/runner-proxy.test.ts +456 -0
- package/src/server/runner-proxy.ts +494 -0
- package/src/server/runner-router.test.ts +429 -0
- package/src/server/runner-router.ts +212 -0
- package/src/server/runner-routing.test.ts +584 -0
- package/src/server/runtime-registry.test.ts +436 -0
- package/src/server/runtime-registry.ts +307 -0
- package/src/server/sandbox-health.test.ts +127 -0
- package/src/server/sandbox-health.ts +94 -0
- package/src/server/sandbox-journey.test.ts +232 -0
- package/src/server/sandbox-manager.test.ts +146 -0
- package/src/server/sandbox-manager.ts +159 -0
- package/src/server/server.test.ts +287 -0
- package/src/server/server.ts +1108 -0
- package/src/server/session-discovery.test.ts +129 -0
- package/src/server/session-discovery.ts +475 -0
- package/src/server/session-index.test.ts +362 -0
- package/src/server/session-index.ts +119 -0
- package/src/server/session-seed.ts +288 -0
- package/src/server/share.test.ts +108 -0
- package/src/server/share.ts +113 -0
- package/src/server/skill-discovery.test.ts +201 -0
- package/src/server/skill-discovery.ts +77 -0
- package/src/server/storage/test-helpers.ts +67 -0
- package/src/server/terminal-manager.test.ts +309 -0
- package/src/server/terminal-manager.ts +354 -0
- package/src/server/transcript-consumer.test.ts +339 -0
- package/src/server/transcript-consumer.ts +162 -0
- package/src/server/transcript-search.test.ts +193 -0
- package/src/server/transcript-search.ts +83 -0
- package/src/server/transcript-utils.ts +52 -0
- package/src/server/update-manager.test.ts +107 -0
- package/src/server/update-manager.ts +230 -0
- package/src/server/workflow-engine.test.ts +251 -0
- package/src/server/workflow-engine.ts +169 -0
- package/src/server/workflow-mcp.ts +49 -0
- package/src/server/workflow-store.test.ts +155 -0
- package/src/server/workflow-store.ts +139 -0
- package/src/server/workspace-agent-integration.test.ts +167 -0
- package/src/server/workspace-agent-routes.test.ts +127 -0
- package/src/server/workspace-agent-routes.ts +89 -0
- package/src/server/workspace-agent.test.ts +103 -0
- package/src/server/workspace-agent.ts +102 -0
- package/src/server/workspace-cli.test.ts +79 -0
- package/src/server/workspace-config-manager.test.ts +109 -0
- package/src/server/workspace-config-manager.ts +83 -0
- package/src/server/workspace-directory-policy.test.ts +109 -0
- package/src/server/workspace-directory-policy.ts +56 -0
- package/src/shared/agent-config-types.ts +25 -0
- package/src/shared/branding.test.ts +42 -0
- package/src/shared/branding.ts +54 -0
- package/src/shared/compression.test.ts +85 -0
- package/src/shared/compression.ts +42 -0
- package/src/shared/coordination-store.test.ts +24 -0
- package/src/shared/coordination-store.ts +26 -0
- package/src/shared/dev-ports.test.ts +84 -0
- package/src/shared/dev-ports.ts +100 -0
- package/src/shared/extension-types.ts +45 -0
- package/src/shared/fork-presets.ts +54 -0
- package/src/shared/harness-types.test.ts +15 -0
- package/src/shared/harness-types.ts +21 -0
- package/src/shared/log-sink.test.ts +112 -0
- package/src/shared/log-sink.ts +185 -0
- package/src/shared/mention-pattern.ts +7 -0
- package/src/shared/merge-presets.ts +41 -0
- package/src/shared/nats-subjects.test.ts +61 -0
- package/src/shared/nats-subjects.ts +131 -0
- package/src/shared/permission-policy.ts +136 -0
- package/src/shared/ports.ts +3 -0
- package/src/shared/preset-types.ts +15 -0
- package/src/shared/profile-types.ts +49 -0
- package/src/shared/projectFileUrl.ts +36 -0
- package/src/shared/protocol.ts +153 -0
- package/src/shared/pty-instance.ts +43 -0
- package/src/shared/puggy/diagnostics/result.ts +18 -0
- package/src/shared/puggy/expressions/evaluate.ts +292 -0
- package/src/shared/puggy/index.test.ts +101 -0
- package/src/shared/puggy/index.ts +69 -0
- package/src/shared/puggy/parser/ast.ts +110 -0
- package/src/shared/puggy/parser/parser.ts +624 -0
- package/src/shared/puggy/renderer/html.ts +447 -0
- package/src/shared/runner-protocol.test.ts +277 -0
- package/src/shared/runner-protocol.ts +210 -0
- package/src/shared/runner-team-types.ts +73 -0
- package/src/shared/runtime-types.ts +48 -0
- package/src/shared/sandbox-types.ts +53 -0
- package/src/shared/tailwind-build.test.ts +12 -0
- package/src/shared/tinkaria-system-prompt.ts +101 -0
- package/src/shared/tools.test.ts +335 -0
- package/src/shared/tools.ts +397 -0
- package/src/shared/transcript-entries.ts +27 -0
- package/src/shared/transcript-render.test.ts +225 -0
- package/src/shared/transcript-render.ts +467 -0
- package/src/shared/types.ts +1031 -0
- package/src/shared/vite-config.test.ts +47 -0
- package/src/shared/web-context.test.ts +110 -0
- package/src/shared/web-context.ts +76 -0
- package/src/shared/workflow-types.ts +51 -0
- package/src/shared/workspace-types.ts +100 -0
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk"
|
|
2
|
+
import { z } from "zod/v4"
|
|
3
|
+
import type { AgentProvider, DelegationMode, DelegationResumeMode, OrchestrationChildNode, OrchestrationChildStatus, OrchestrationHierarchySnapshot, TranscriptEntry, SessionStatus } from "../shared/types"
|
|
4
|
+
import type { DelegationCoordinator } from "./delegation-coordinator"
|
|
5
|
+
import { LOG_PREFIX } from "../shared/branding"
|
|
6
|
+
import { normalizeServerModel } from "./provider-catalog"
|
|
7
|
+
import { toTranscriptLine } from "./transcript-utils"
|
|
8
|
+
|
|
9
|
+
interface OriginRecord {
|
|
10
|
+
originChatId: string
|
|
11
|
+
depth: number
|
|
12
|
+
instruction: string
|
|
13
|
+
spawnedAt: number
|
|
14
|
+
lastStatus: OrchestrationChildStatus
|
|
15
|
+
lastStatusAt: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface OrchestratorCoordinator {
|
|
19
|
+
activeTurns: { has(key: string): boolean }
|
|
20
|
+
getActiveStatuses(): Map<string, SessionStatus>
|
|
21
|
+
startTurnForChat(args: {
|
|
22
|
+
chatId: string
|
|
23
|
+
provider: AgentProvider
|
|
24
|
+
content: string
|
|
25
|
+
delegatedContext?: string
|
|
26
|
+
isSpawned?: boolean
|
|
27
|
+
model: string
|
|
28
|
+
effort?: string
|
|
29
|
+
planMode: boolean
|
|
30
|
+
appendUserPrompt: boolean
|
|
31
|
+
}): Promise<void>
|
|
32
|
+
queue(args: {
|
|
33
|
+
type: "chat.queue"
|
|
34
|
+
chatId: string
|
|
35
|
+
provider?: AgentProvider
|
|
36
|
+
content: string
|
|
37
|
+
model?: string
|
|
38
|
+
effort?: string
|
|
39
|
+
planMode?: boolean
|
|
40
|
+
}): Promise<{ chatId: string; queued: boolean }>
|
|
41
|
+
cancel(chatId: string): Promise<void>
|
|
42
|
+
disposeChat(chatId: string): Promise<void>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface OrchestratorStore {
|
|
46
|
+
createChat(workspaceId: string): Promise<{ id: string; workspaceId: string }>
|
|
47
|
+
requireChat(chatId: string): { id: string; workspaceId: string; provider: AgentProvider | null }
|
|
48
|
+
getProject(workspaceId: string): { id: string; localPath: string } | null
|
|
49
|
+
listChatsByProject(workspaceId: string): Array<{ id: string }>
|
|
50
|
+
getMessages(chatId: string): Promise<TranscriptEntry[]>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface SessionOrchestratorArgs {
|
|
54
|
+
store: OrchestratorStore
|
|
55
|
+
coordinator: OrchestratorCoordinator
|
|
56
|
+
delegationCoordinator?: DelegationCoordinator
|
|
57
|
+
onMessageAppended?: (chatId: string, entry: TranscriptEntry) => void
|
|
58
|
+
maxDepth?: number
|
|
59
|
+
maxConcurrency?: number
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface PendingWaiter {
|
|
63
|
+
resolve: (value: { result: string; isError: boolean }) => void
|
|
64
|
+
reject: (reason: Error) => void
|
|
65
|
+
timer: ReturnType<typeof setTimeout>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface ExternalAgentStateRecord {
|
|
69
|
+
chatId: string
|
|
70
|
+
status: OrchestrationChildStatus
|
|
71
|
+
spawnedAt: number
|
|
72
|
+
lastStatusAt: number
|
|
73
|
+
instruction: string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const MAX_DELEGATED_CONTEXT_ENTRIES = 24
|
|
77
|
+
const MAX_DELEGATED_CONTEXT_CHARS = 12_000
|
|
78
|
+
const MAX_DELEGATED_CONTEXT_LINE_CHARS = 600
|
|
79
|
+
|
|
80
|
+
function entryToDelegatedContextLine(entry: TranscriptEntry): string | null {
|
|
81
|
+
return toTranscriptLine(entry, MAX_DELEGATED_CONTEXT_LINE_CHARS)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function buildDelegatedContext(entries: TranscriptEntry[]): string | undefined {
|
|
85
|
+
const relevantEntries = entries
|
|
86
|
+
.map(entryToDelegatedContextLine)
|
|
87
|
+
.filter((line): line is string => Boolean(line))
|
|
88
|
+
|
|
89
|
+
if (relevantEntries.length === 0) return undefined
|
|
90
|
+
|
|
91
|
+
const selected = relevantEntries.slice(-MAX_DELEGATED_CONTEXT_ENTRIES)
|
|
92
|
+
const omittedCount = relevantEntries.length - selected.length
|
|
93
|
+
const headerLines = [
|
|
94
|
+
"Forked parent chat context:",
|
|
95
|
+
"Treat this as background context copied from the spawning chat before your task starts.",
|
|
96
|
+
"Do not re-answer it directly unless the new task asks you to.",
|
|
97
|
+
]
|
|
98
|
+
if (omittedCount > 0) {
|
|
99
|
+
headerLines.push(`Older transcript lines omitted: ${omittedCount}.`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const lines = [...headerLines, ...selected]
|
|
103
|
+
let serialized = lines.join("\n")
|
|
104
|
+
|
|
105
|
+
if (serialized.length <= MAX_DELEGATED_CONTEXT_CHARS) {
|
|
106
|
+
return serialized
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const trimmedSelected: string[] = []
|
|
110
|
+
let remaining = MAX_DELEGATED_CONTEXT_CHARS - headerLines.join("\n").length - 1
|
|
111
|
+
for (let index = selected.length - 1; index >= 0; index -= 1) {
|
|
112
|
+
const line = selected[index]!
|
|
113
|
+
const cost = line.length + 1
|
|
114
|
+
if (remaining - cost < 0) break
|
|
115
|
+
trimmedSelected.unshift(line)
|
|
116
|
+
remaining -= cost
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (trimmedSelected.length === 0) {
|
|
120
|
+
return headerLines.join("\n")
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return [...headerLines, ...trimmedSelected].join("\n")
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export class SessionOrchestrator {
|
|
127
|
+
private readonly store: OrchestratorStore
|
|
128
|
+
private readonly coordinator: OrchestratorCoordinator
|
|
129
|
+
private readonly delegationCoordinator?: DelegationCoordinator
|
|
130
|
+
private readonly maxDepth: number
|
|
131
|
+
private readonly maxConcurrency: number
|
|
132
|
+
private readonly origins = new Map<string, OriginRecord>()
|
|
133
|
+
private readonly children = new Map<string, Set<string>>()
|
|
134
|
+
private readonly waiters = new Map<string, PendingWaiter>()
|
|
135
|
+
private readonly externalChildren = new Map<string, Map<string, ExternalAgentStateRecord>>()
|
|
136
|
+
|
|
137
|
+
constructor(args: SessionOrchestratorArgs) {
|
|
138
|
+
this.store = args.store
|
|
139
|
+
this.coordinator = args.coordinator
|
|
140
|
+
this.delegationCoordinator = args.delegationCoordinator
|
|
141
|
+
this.maxDepth = args.maxDepth ?? 3
|
|
142
|
+
this.maxConcurrency = args.maxConcurrency ?? 10
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async spawnAgent(
|
|
146
|
+
callerChatId: string,
|
|
147
|
+
args: {
|
|
148
|
+
instruction: string
|
|
149
|
+
provider?: AgentProvider
|
|
150
|
+
model?: string
|
|
151
|
+
forkContext?: boolean
|
|
152
|
+
mode?: DelegationMode
|
|
153
|
+
resume?: DelegationResumeMode
|
|
154
|
+
resumeHint?: string
|
|
155
|
+
},
|
|
156
|
+
): Promise<{ chatId: string; delegationId?: string }> {
|
|
157
|
+
const callerChat = this.store.requireChat(callerChatId)
|
|
158
|
+
const provider = args.provider ?? callerChat.provider ?? "claude"
|
|
159
|
+
const callerDepth = this.origins.get(callerChatId)?.depth ?? 0
|
|
160
|
+
|
|
161
|
+
const newDepth = callerDepth + 1
|
|
162
|
+
if (newDepth > this.maxDepth) {
|
|
163
|
+
if (callerDepth > 0) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Circular orchestration detected: spawned session at depth ${callerDepth} cannot spawn (max depth ${this.maxDepth})`,
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Max orchestration depth (${this.maxDepth}) exceeded — cannot spawn at depth ${newDepth}`,
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const activeSteered = this.countActiveSteered(callerChat.workspaceId)
|
|
174
|
+
if (activeSteered >= this.maxConcurrency) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`Max concurrency (${this.maxConcurrency}) reached for project ${callerChat.workspaceId}`,
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const newChat = await this.store.createChat(callerChat.workspaceId)
|
|
181
|
+
const now = Date.now()
|
|
182
|
+
this.origins.set(newChat.id, {
|
|
183
|
+
originChatId: callerChatId,
|
|
184
|
+
depth: newDepth,
|
|
185
|
+
instruction: args.instruction.slice(0, 120),
|
|
186
|
+
spawnedAt: now,
|
|
187
|
+
lastStatus: "spawning",
|
|
188
|
+
lastStatusAt: now,
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
let siblings = this.children.get(callerChatId)
|
|
192
|
+
if (!siblings) {
|
|
193
|
+
siblings = new Set()
|
|
194
|
+
this.children.set(callerChatId, siblings)
|
|
195
|
+
}
|
|
196
|
+
siblings.add(newChat.id)
|
|
197
|
+
|
|
198
|
+
const model = args.model ?? normalizeServerModel(provider)
|
|
199
|
+
const delegatedContext = args.forkContext
|
|
200
|
+
? buildDelegatedContext(await this.store.getMessages(callerChatId))
|
|
201
|
+
: undefined
|
|
202
|
+
|
|
203
|
+
// Create durable delegation record if coordinator is present
|
|
204
|
+
let delegationId: string | undefined
|
|
205
|
+
if (this.delegationCoordinator) {
|
|
206
|
+
const mode = args.mode ?? "blocking"
|
|
207
|
+
const resume = args.resume ?? "gate"
|
|
208
|
+
const parentMessages = await this.store.getMessages(callerChatId)
|
|
209
|
+
const resumeHint = args.resumeHint ?? this.delegationCoordinator.generateResumeHint(parentMessages)
|
|
210
|
+
|
|
211
|
+
const result = await this.delegationCoordinator.createDelegation({
|
|
212
|
+
workspaceId: callerChat.workspaceId,
|
|
213
|
+
parentChatId: callerChatId,
|
|
214
|
+
childChatId: newChat.id,
|
|
215
|
+
childProvider: provider,
|
|
216
|
+
instructionPreview: args.instruction,
|
|
217
|
+
mode,
|
|
218
|
+
resume,
|
|
219
|
+
depth: newDepth,
|
|
220
|
+
resumeHint,
|
|
221
|
+
})
|
|
222
|
+
delegationId = result.delegationId
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
console.warn(`${LOG_PREFIX} spawnAgent: ${callerChatId} -> ${newChat.id} (depth=${newDepth}, provider=${provider})`)
|
|
226
|
+
|
|
227
|
+
await this.coordinator.startTurnForChat({
|
|
228
|
+
chatId: newChat.id,
|
|
229
|
+
provider,
|
|
230
|
+
content: args.instruction,
|
|
231
|
+
delegatedContext,
|
|
232
|
+
isSpawned: true,
|
|
233
|
+
model,
|
|
234
|
+
planMode: false,
|
|
235
|
+
appendUserPrompt: true,
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
const result: { chatId: string; delegationId?: string } = { chatId: newChat.id }
|
|
239
|
+
if (delegationId) result.delegationId = delegationId
|
|
240
|
+
return result
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async sendInput(
|
|
244
|
+
callerChatId: string,
|
|
245
|
+
args: { targetChatId: string; content: string; model?: string },
|
|
246
|
+
): Promise<void> {
|
|
247
|
+
this.requireOwnedTarget(callerChatId, args.targetChatId)
|
|
248
|
+
const targetChat = this.store.requireChat(args.targetChatId)
|
|
249
|
+
const provider = targetChat.provider ?? "claude"
|
|
250
|
+
const model = args.model ?? normalizeServerModel(provider)
|
|
251
|
+
|
|
252
|
+
if (this.coordinator.activeTurns.has(args.targetChatId)) {
|
|
253
|
+
await this.coordinator.queue({
|
|
254
|
+
type: "chat.queue",
|
|
255
|
+
chatId: args.targetChatId,
|
|
256
|
+
provider,
|
|
257
|
+
content: args.content,
|
|
258
|
+
model,
|
|
259
|
+
planMode: false,
|
|
260
|
+
})
|
|
261
|
+
return
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
await this.coordinator.startTurnForChat({
|
|
265
|
+
chatId: args.targetChatId,
|
|
266
|
+
provider,
|
|
267
|
+
content: args.content,
|
|
268
|
+
model,
|
|
269
|
+
planMode: false,
|
|
270
|
+
appendUserPrompt: true,
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async waitForResult(
|
|
275
|
+
callerChatId: string,
|
|
276
|
+
args: { targetChatId: string; timeoutMs?: number },
|
|
277
|
+
): Promise<{ result: string; isError: boolean }> {
|
|
278
|
+
this.requireOwnedTarget(callerChatId, args.targetChatId)
|
|
279
|
+
const timeoutMs = args.timeoutMs ?? 120_000
|
|
280
|
+
|
|
281
|
+
return new Promise<{ result: string; isError: boolean }>((resolve, reject) => {
|
|
282
|
+
const timer = setTimeout(() => {
|
|
283
|
+
this.waiters.delete(args.targetChatId)
|
|
284
|
+
void this.coordinator.cancel(args.targetChatId).catch(() => undefined)
|
|
285
|
+
reject(new Error(`Timed out waiting for result from ${args.targetChatId} after ${timeoutMs}ms`))
|
|
286
|
+
}, timeoutMs)
|
|
287
|
+
|
|
288
|
+
this.waiters.set(args.targetChatId, { resolve, reject, timer })
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
onMessageAppended(chatId: string, entry: TranscriptEntry): void {
|
|
293
|
+
const waiter = this.waiters.get(chatId)
|
|
294
|
+
if (waiter && entry.kind === "result") {
|
|
295
|
+
this.waiters.delete(chatId)
|
|
296
|
+
clearTimeout(waiter.timer)
|
|
297
|
+
waiter.resolve({ result: entry.result, isError: entry.isError })
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
this.updateExternalHierarchy(chatId, entry)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async closeAgent(
|
|
304
|
+
callerChatId: string,
|
|
305
|
+
args: { targetChatId: string },
|
|
306
|
+
): Promise<void> {
|
|
307
|
+
this.requireOwnedTarget(callerChatId, args.targetChatId)
|
|
308
|
+
// Mark as closed tombstone first (visible in hierarchy)
|
|
309
|
+
const origin = this.origins.get(args.targetChatId)
|
|
310
|
+
if (origin) {
|
|
311
|
+
origin.lastStatus = "closed"
|
|
312
|
+
origin.lastStatusAt = Date.now()
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Clear any pending waiter
|
|
316
|
+
const waiter = this.waiters.get(args.targetChatId)
|
|
317
|
+
if (waiter) {
|
|
318
|
+
clearTimeout(waiter.timer)
|
|
319
|
+
this.waiters.delete(args.targetChatId)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Dispose the underlying chat (async)
|
|
323
|
+
await this.coordinator.disposeChat(args.targetChatId)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
pruneTombstones(): void {
|
|
327
|
+
const toRemove: string[] = []
|
|
328
|
+
for (const [chatId, origin] of this.origins) {
|
|
329
|
+
if (origin.lastStatus === "closed") {
|
|
330
|
+
toRemove.push(chatId)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
for (const chatId of toRemove) {
|
|
334
|
+
this.cleanup(chatId)
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
destroy(): void {
|
|
339
|
+
for (const [, waiter] of this.waiters) {
|
|
340
|
+
clearTimeout(waiter.timer)
|
|
341
|
+
waiter.reject(new Error("Orchestrator disposed"))
|
|
342
|
+
}
|
|
343
|
+
this.waiters.clear()
|
|
344
|
+
this.origins.clear()
|
|
345
|
+
this.children.clear()
|
|
346
|
+
this.externalChildren.clear()
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
getHierarchy(chatId: string): OrchestrationHierarchySnapshot {
|
|
350
|
+
const childSet = this.children.get(chatId)
|
|
351
|
+
const externalChildren = this.externalChildren.get(chatId)
|
|
352
|
+
if ((!childSet || childSet.size === 0) && (!externalChildren || externalChildren.size === 0)) {
|
|
353
|
+
return { children: [] }
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const statuses = this.coordinator.getActiveStatuses()
|
|
357
|
+
const internalChildren = childSet
|
|
358
|
+
? [...childSet].map((childId) => this.buildChildNode(childId, statuses))
|
|
359
|
+
: []
|
|
360
|
+
const seenIds = new Set(internalChildren.map((child) => child.chatId))
|
|
361
|
+
const externalNodes = externalChildren
|
|
362
|
+
? [...externalChildren.values()]
|
|
363
|
+
.filter((child) => !seenIds.has(child.chatId))
|
|
364
|
+
.map((child) => ({
|
|
365
|
+
chatId: child.chatId,
|
|
366
|
+
externalSessionId: child.chatId,
|
|
367
|
+
status: child.status,
|
|
368
|
+
spawnedAt: child.spawnedAt,
|
|
369
|
+
lastStatusAt: child.lastStatusAt,
|
|
370
|
+
instruction: child.instruction,
|
|
371
|
+
children: [],
|
|
372
|
+
}))
|
|
373
|
+
: []
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
children: [...internalChildren, ...externalNodes],
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
listAgents(chatId: string): OrchestrationHierarchySnapshot {
|
|
381
|
+
return this.getHierarchy(chatId)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private buildChildNode(
|
|
385
|
+
childId: string,
|
|
386
|
+
statuses: Map<string, SessionStatus>,
|
|
387
|
+
): OrchestrationChildNode {
|
|
388
|
+
const origin = this.origins.get(childId)
|
|
389
|
+
const now = Date.now()
|
|
390
|
+
|
|
391
|
+
if (!origin) {
|
|
392
|
+
return {
|
|
393
|
+
chatId: childId,
|
|
394
|
+
status: "closed",
|
|
395
|
+
spawnedAt: now,
|
|
396
|
+
lastStatusAt: now,
|
|
397
|
+
instruction: "",
|
|
398
|
+
children: [],
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const resolvedStatus = this.resolveChildStatus(childId, origin, statuses)
|
|
403
|
+
if (resolvedStatus !== origin.lastStatus) {
|
|
404
|
+
origin.lastStatus = resolvedStatus
|
|
405
|
+
origin.lastStatusAt = now
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const nestedChildren = this.children.get(childId)
|
|
409
|
+
return {
|
|
410
|
+
chatId: childId,
|
|
411
|
+
status: origin.lastStatus,
|
|
412
|
+
spawnedAt: origin.spawnedAt,
|
|
413
|
+
lastStatusAt: origin.lastStatusAt,
|
|
414
|
+
instruction: origin.instruction,
|
|
415
|
+
children: nestedChildren
|
|
416
|
+
? [...nestedChildren].map((id) => this.buildChildNode(id, statuses))
|
|
417
|
+
: [],
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private resolveChildStatus(
|
|
422
|
+
_childId: string,
|
|
423
|
+
origin: OriginRecord,
|
|
424
|
+
statuses: Map<string, SessionStatus>,
|
|
425
|
+
): OrchestrationChildStatus {
|
|
426
|
+
if (origin.lastStatus === "closed") return "closed"
|
|
427
|
+
|
|
428
|
+
const tinkariaStatus = statuses.get(_childId)
|
|
429
|
+
if (!tinkariaStatus) {
|
|
430
|
+
return "completed"
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
switch (tinkariaStatus) {
|
|
434
|
+
case "starting":
|
|
435
|
+
case "running":
|
|
436
|
+
return "running"
|
|
437
|
+
case "waiting_for_user":
|
|
438
|
+
return "waiting"
|
|
439
|
+
case "failed":
|
|
440
|
+
return "failed"
|
|
441
|
+
default:
|
|
442
|
+
return "running"
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
async cancelWithCascade(chatId: string): Promise<void> {
|
|
447
|
+
const childSet = this.children.get(chatId)
|
|
448
|
+
if (childSet) {
|
|
449
|
+
for (const childId of childSet) {
|
|
450
|
+
await this.cancelWithCascade(childId)
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
await this.coordinator.cancel(chatId)
|
|
454
|
+
this.cleanup(chatId)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
private countActiveSteered(workspaceId: string): number {
|
|
458
|
+
const statuses = this.coordinator.getActiveStatuses()
|
|
459
|
+
let count = 0
|
|
460
|
+
for (const [chatId, origin] of this.origins) {
|
|
461
|
+
try {
|
|
462
|
+
const chat = this.store.requireChat(chatId)
|
|
463
|
+
if (chat.workspaceId !== workspaceId) continue
|
|
464
|
+
const status = this.resolveChildStatus(chatId, origin, statuses)
|
|
465
|
+
if (status === "spawning" || status === "running" || status === "waiting") {
|
|
466
|
+
count += 1
|
|
467
|
+
}
|
|
468
|
+
} catch (error) {
|
|
469
|
+
void (error instanceof Error ? error.message : String(error))
|
|
470
|
+
// Chat may have been disposed — skip
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return count
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
private cleanup(chatId: string): void {
|
|
477
|
+
const origin = this.origins.get(chatId)
|
|
478
|
+
if (origin) {
|
|
479
|
+
this.children.get(origin.originChatId)?.delete(chatId)
|
|
480
|
+
}
|
|
481
|
+
this.origins.delete(chatId)
|
|
482
|
+
this.children.delete(chatId)
|
|
483
|
+
|
|
484
|
+
const waiter = this.waiters.get(chatId)
|
|
485
|
+
if (waiter) {
|
|
486
|
+
clearTimeout(waiter.timer)
|
|
487
|
+
this.waiters.delete(chatId)
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
private updateExternalHierarchy(chatId: string, entry: TranscriptEntry): void {
|
|
492
|
+
const payload = this.extractCollabPayload(entry)
|
|
493
|
+
if (!payload) return
|
|
494
|
+
|
|
495
|
+
const receiverIds = this.extractReceiverThreadIds(payload)
|
|
496
|
+
if (receiverIds.length === 0) return
|
|
497
|
+
|
|
498
|
+
let children = this.externalChildren.get(chatId)
|
|
499
|
+
if (!children) {
|
|
500
|
+
children = new Map()
|
|
501
|
+
this.externalChildren.set(chatId, children)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const now = Date.now()
|
|
505
|
+
const instruction = this.extractExternalInstruction(payload)
|
|
506
|
+
const entryIsError = entry.kind === "tool_result" ? Boolean(entry.isError) : false
|
|
507
|
+
for (const receiverId of receiverIds) {
|
|
508
|
+
const existing = children.get(receiverId)
|
|
509
|
+
children.set(receiverId, {
|
|
510
|
+
chatId: receiverId,
|
|
511
|
+
status: this.resolveExternalStatus(payload, receiverId, entryIsError, existing?.status),
|
|
512
|
+
spawnedAt: existing?.spawnedAt ?? entry.createdAt ?? now,
|
|
513
|
+
lastStatusAt: now,
|
|
514
|
+
instruction: instruction ?? existing?.instruction ?? "Delegated task",
|
|
515
|
+
})
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
private extractCollabPayload(entry: TranscriptEntry): Record<string, unknown> | null {
|
|
520
|
+
if (entry.kind === "tool_call" && entry.tool.toolKind === "subagent_task") {
|
|
521
|
+
return entry.tool.rawInput ?? null
|
|
522
|
+
}
|
|
523
|
+
if (entry.kind === "tool_result" && entry.content && typeof entry.content === "object" && !Array.isArray(entry.content)) {
|
|
524
|
+
const record = entry.content as Record<string, unknown>
|
|
525
|
+
if (Array.isArray(record.receiverThreadIds)) {
|
|
526
|
+
return record
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return null
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
private extractReceiverThreadIds(payload: Record<string, unknown>): string[] {
|
|
533
|
+
const rawReceiverIds = payload.receiverThreadIds
|
|
534
|
+
if (!Array.isArray(rawReceiverIds)) return []
|
|
535
|
+
return rawReceiverIds.filter((value): value is string => typeof value === "string")
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private extractExternalInstruction(payload: Record<string, unknown>): string | null {
|
|
539
|
+
const prompt = payload.prompt
|
|
540
|
+
if (typeof prompt !== "string" || prompt.length === 0) return null
|
|
541
|
+
return prompt.slice(0, 120)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
private resolveExternalStatus(
|
|
545
|
+
payload: Record<string, unknown>,
|
|
546
|
+
receiverId: string,
|
|
547
|
+
isError: boolean,
|
|
548
|
+
previousStatus?: OrchestrationChildStatus,
|
|
549
|
+
): OrchestrationChildStatus {
|
|
550
|
+
if (isError) return "failed"
|
|
551
|
+
|
|
552
|
+
const toolName = typeof payload.tool === "string" ? payload.tool : null
|
|
553
|
+
const agentStates = payload.agentsStates
|
|
554
|
+
const stateRecord = agentStates && typeof agentStates === "object" && !Array.isArray(agentStates)
|
|
555
|
+
? (agentStates as Record<string, unknown>)[receiverId]
|
|
556
|
+
: null
|
|
557
|
+
const stateStatus = stateRecord && typeof stateRecord === "object" && !Array.isArray(stateRecord)
|
|
558
|
+
? (stateRecord as Record<string, unknown>).status
|
|
559
|
+
: null
|
|
560
|
+
const normalizedState = this.normalizeExternalStatus(typeof stateStatus === "string" ? stateStatus : null)
|
|
561
|
+
if (normalizedState) return normalizedState
|
|
562
|
+
|
|
563
|
+
if (toolName === "closeAgent") return "closed"
|
|
564
|
+
if (toolName === "wait") return previousStatus === "failed" ? "failed" : "completed"
|
|
565
|
+
if (toolName === "spawnAgent") {
|
|
566
|
+
return this.normalizeExternalStatus(typeof payload.status === "string" ? payload.status : null) ?? "spawning"
|
|
567
|
+
}
|
|
568
|
+
if (toolName === "sendInput" || toolName === "resumeAgent") return "running"
|
|
569
|
+
|
|
570
|
+
return this.normalizeExternalStatus(typeof payload.status === "string" ? payload.status : null) ?? previousStatus ?? "running"
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private normalizeExternalStatus(status: string | null): OrchestrationChildStatus | null {
|
|
574
|
+
if (!status) return null
|
|
575
|
+
switch (status.toLowerCase()) {
|
|
576
|
+
case "pending":
|
|
577
|
+
case "queued":
|
|
578
|
+
case "created":
|
|
579
|
+
case "starting":
|
|
580
|
+
case "spawning":
|
|
581
|
+
return "spawning"
|
|
582
|
+
case "running":
|
|
583
|
+
case "inprogress":
|
|
584
|
+
case "in_progress":
|
|
585
|
+
case "working":
|
|
586
|
+
return "running"
|
|
587
|
+
case "waiting":
|
|
588
|
+
case "waiting_for_user":
|
|
589
|
+
case "paused":
|
|
590
|
+
return "waiting"
|
|
591
|
+
case "completed":
|
|
592
|
+
case "done":
|
|
593
|
+
case "success":
|
|
594
|
+
return "completed"
|
|
595
|
+
case "failed":
|
|
596
|
+
case "error":
|
|
597
|
+
return "failed"
|
|
598
|
+
case "closed":
|
|
599
|
+
case "cancelled":
|
|
600
|
+
case "interrupted":
|
|
601
|
+
return "closed"
|
|
602
|
+
default:
|
|
603
|
+
return null
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
private requireOwnedTarget(callerChatId: string, targetChatId: string): OriginRecord {
|
|
608
|
+
const origin = this.origins.get(targetChatId)
|
|
609
|
+
if (!origin) {
|
|
610
|
+
throw new Error(`Target chat ${targetChatId} is not a spawned agent`)
|
|
611
|
+
}
|
|
612
|
+
if (origin.originChatId !== callerChatId) {
|
|
613
|
+
throw new Error(`Caller ${callerChatId} does not own spawned agent ${targetChatId}`)
|
|
614
|
+
}
|
|
615
|
+
return origin
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Creates an in-process MCP server with orchestration tools for a specific session.
|
|
621
|
+
* Each Claude turn gets its own server instance scoped to the caller's chatId.
|
|
622
|
+
*/
|
|
623
|
+
export function createOrchestrationMcpServer(
|
|
624
|
+
orchestrator: SessionOrchestrator,
|
|
625
|
+
callerChatId: string,
|
|
626
|
+
) {
|
|
627
|
+
return createSdkMcpServer({
|
|
628
|
+
name: "session-orchestration",
|
|
629
|
+
tools: [
|
|
630
|
+
tool(
|
|
631
|
+
"spawn_agent",
|
|
632
|
+
"Spawn a new agent session in the same project. Returns the new session's chatId and delegationId. " +
|
|
633
|
+
"Delegation persists across session boundaries: blocking children auto-resume the parent when done; " +
|
|
634
|
+
"background children inject results passively. Use wait_agent for synchronous result, or rely on auto-resume for durable async workflows.",
|
|
635
|
+
{
|
|
636
|
+
instruction: z.string().describe("Task instruction for the new agent"),
|
|
637
|
+
provider: z.enum(["claude", "codex"]).optional().describe("AI provider — defaults to caller's provider"),
|
|
638
|
+
fork_context: z.boolean().optional().describe(
|
|
639
|
+
"When true, seed the new agent with a bounded snapshot of the current chat transcript before its first task message.",
|
|
640
|
+
),
|
|
641
|
+
mode: z
|
|
642
|
+
.enum(["blocking", "background"])
|
|
643
|
+
.optional()
|
|
644
|
+
.describe(
|
|
645
|
+
"Delegation mode. 'blocking' (default): parent auto-resumes when child completes. " +
|
|
646
|
+
"'background': fire-and-forget — result injected into parent transcript but no auto-resume.",
|
|
647
|
+
),
|
|
648
|
+
resume: z
|
|
649
|
+
.enum(["immediate", "gate"])
|
|
650
|
+
.optional()
|
|
651
|
+
.describe(
|
|
652
|
+
"Multi-child resume strategy. 'gate' (default): parent resumes only after ALL blocking children complete. " +
|
|
653
|
+
"'immediate': parent resumes after EACH child completes.",
|
|
654
|
+
),
|
|
655
|
+
},
|
|
656
|
+
async (args) => {
|
|
657
|
+
const result = await orchestrator.spawnAgent(callerChatId, {
|
|
658
|
+
instruction: args.instruction,
|
|
659
|
+
provider: args.provider as AgentProvider | undefined,
|
|
660
|
+
forkContext: args.fork_context,
|
|
661
|
+
mode: args.mode,
|
|
662
|
+
resume: args.resume,
|
|
663
|
+
})
|
|
664
|
+
return { content: [{ type: "text" as const, text: JSON.stringify(result) }] }
|
|
665
|
+
},
|
|
666
|
+
),
|
|
667
|
+
tool(
|
|
668
|
+
"list_agents",
|
|
669
|
+
"List the current caller's spawned agent tree and statuses.",
|
|
670
|
+
{},
|
|
671
|
+
async () => {
|
|
672
|
+
const result = orchestrator.listAgents(callerChatId)
|
|
673
|
+
return { content: [{ type: "text" as const, text: JSON.stringify(result) }] }
|
|
674
|
+
},
|
|
675
|
+
),
|
|
676
|
+
tool(
|
|
677
|
+
"send_input",
|
|
678
|
+
"Send a follow-up message to an existing steered session. Use this to steer a child after its first turn, request additional work, or accumulate incremental results across multiple exchanges. The child resumes with its full conversation context preserved.",
|
|
679
|
+
{
|
|
680
|
+
targetChatId: z.string().describe("The chatId of the target session"),
|
|
681
|
+
content: z.string().describe("Message content to send"),
|
|
682
|
+
},
|
|
683
|
+
async (args) => {
|
|
684
|
+
await orchestrator.sendInput(callerChatId, args)
|
|
685
|
+
return { content: [{ type: "text" as const, text: "Input sent" }] }
|
|
686
|
+
},
|
|
687
|
+
),
|
|
688
|
+
tool(
|
|
689
|
+
"wait_agent",
|
|
690
|
+
"Block until a steered session completes its current turn. Returns the result text.",
|
|
691
|
+
{
|
|
692
|
+
targetChatId: z.string().describe("The chatId of the session to wait for"),
|
|
693
|
+
timeoutMs: z.number().optional().describe("Max wait time in milliseconds (default: 120000)"),
|
|
694
|
+
},
|
|
695
|
+
async (args) => {
|
|
696
|
+
const result = await orchestrator.waitForResult(callerChatId, args)
|
|
697
|
+
return {
|
|
698
|
+
content: [{ type: "text" as const, text: JSON.stringify(result) }],
|
|
699
|
+
isError: result.isError,
|
|
700
|
+
}
|
|
701
|
+
},
|
|
702
|
+
),
|
|
703
|
+
tool(
|
|
704
|
+
"close_agent",
|
|
705
|
+
"Dispose a steered session and free resources.",
|
|
706
|
+
{
|
|
707
|
+
targetChatId: z.string().describe("The chatId of the session to close"),
|
|
708
|
+
},
|
|
709
|
+
async (args) => {
|
|
710
|
+
await orchestrator.closeAgent(callerChatId, args)
|
|
711
|
+
return { content: [{ type: "text" as const, text: "Agent closed" }] }
|
|
712
|
+
},
|
|
713
|
+
),
|
|
714
|
+
],
|
|
715
|
+
})
|
|
716
|
+
}
|