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,494 @@
|
|
|
1
|
+
import type { NatsConnection } from "@nats-io/transport-node"
|
|
2
|
+
import type { ClientCommand } from "../shared/protocol"
|
|
3
|
+
import type { ProviderProfileRecord } from "../shared/profile-types"
|
|
4
|
+
import { resolveProfile } from "../shared/profile-types"
|
|
5
|
+
import type { AgentProvider, SessionStatus, PendingToolSnapshot } from "../shared/types"
|
|
6
|
+
import { resolveClaudeApiModelId } from "../shared/types"
|
|
7
|
+
import { runnerCmdSubject, SUPPORTED_RANGE, type RunnerCapabilities, type StartTurnCommand } from "../shared/runner-protocol"
|
|
8
|
+
import type { EventStore } from "./event-store"
|
|
9
|
+
import type { RuntimeRegistry } from "./runtime-registry"
|
|
10
|
+
import type { RunnerRouter } from "./runner-router"
|
|
11
|
+
import {
|
|
12
|
+
deriveServerProviderCatalog,
|
|
13
|
+
getServerProviderCatalog,
|
|
14
|
+
normalizeClaudeModelOptions,
|
|
15
|
+
normalizeServerModel,
|
|
16
|
+
} from "./provider-catalog"
|
|
17
|
+
|
|
18
|
+
// ── RunnerPickRequired ────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Thrown by `resolveRunnerForChat` when selection returns `needs_pick` with
|
|
22
|
+
* non-empty candidates. The WS layer converts this to a `chat.runnerPickRequired`
|
|
23
|
+
* event so the client can render a picker.
|
|
24
|
+
*/
|
|
25
|
+
export class RunnerPickRequired extends Error {
|
|
26
|
+
readonly chatId: string
|
|
27
|
+
readonly candidates: import("./runner-router").RunnerDescriptor[]
|
|
28
|
+
readonly reason: "ambiguous" | "sticky_offline"
|
|
29
|
+
|
|
30
|
+
constructor(args: {
|
|
31
|
+
chatId: string
|
|
32
|
+
candidates: import("./runner-router").RunnerDescriptor[]
|
|
33
|
+
reason: "ambiguous" | "sticky_offline"
|
|
34
|
+
}) {
|
|
35
|
+
super(`Runner pick required for chat ${args.chatId}: ${args.reason}`)
|
|
36
|
+
this.name = "RunnerPickRequired"
|
|
37
|
+
this.chatId = args.chatId
|
|
38
|
+
this.candidates = args.candidates
|
|
39
|
+
this.reason = args.reason
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const encoder = new TextEncoder()
|
|
44
|
+
const decoder = new TextDecoder()
|
|
45
|
+
|
|
46
|
+
type ChatSendCommand = Extract<ClientCommand, { type: "chat.send" }>
|
|
47
|
+
type ChatQueueCommand = Extract<ClientCommand, { type: "chat.queue" }>
|
|
48
|
+
|
|
49
|
+
export interface RunnerProxyOptions {
|
|
50
|
+
nc: NatsConnection
|
|
51
|
+
store: EventStore
|
|
52
|
+
runnerId: string
|
|
53
|
+
getActiveStatuses: () => Map<string, SessionStatus>
|
|
54
|
+
getPendingTool?: (chatId: string) => PendingToolSnapshot | null
|
|
55
|
+
runtimeRegistry?: RuntimeRegistry | null
|
|
56
|
+
/** Optional: called before start_turn dispatch to enforce the protocol-version + capability gate.
|
|
57
|
+
* When `router` is provided the signature becomes `(runnerId: string) => {...}` so each runner
|
|
58
|
+
* can be checked individually. A zero-arg `() => ({...})` (as existing tests pass) is still
|
|
59
|
+
* assignable in TS — the parameter is simply ignored in the legacy path. */
|
|
60
|
+
getRunnerReadiness?: (runnerId: string) => { incompatible: boolean; protocolVersion: number | null; capabilities?: RunnerCapabilities | null }
|
|
61
|
+
/** PR5: optional router for per-session runner selection. When absent the proxy
|
|
62
|
+
* behaves exactly as before — always dispatching to `this.runnerId`. */
|
|
63
|
+
router?: RunnerRouter
|
|
64
|
+
/** PR5: returns the current shared/fallback runner id. Defaults to `() => this.runnerId`. */
|
|
65
|
+
sharedRunnerId?: () => string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class RunnerProxy {
|
|
69
|
+
private readonly nc: NatsConnection
|
|
70
|
+
private readonly store: EventStore
|
|
71
|
+
private readonly runnerId: string
|
|
72
|
+
private readonly _getActiveStatuses: () => Map<string, SessionStatus>
|
|
73
|
+
private readonly runtimeRegistry: RuntimeRegistry | null
|
|
74
|
+
private readonly _getRunnerReadiness: ((runnerId: string) => { incompatible: boolean; protocolVersion: number | null; capabilities?: RunnerCapabilities | null }) | null
|
|
75
|
+
private readonly recentlyStartedChats = new Set<string>()
|
|
76
|
+
private readonly router: RunnerRouter | null
|
|
77
|
+
private readonly _sharedRunnerId: () => string
|
|
78
|
+
|
|
79
|
+
/** Orchestration compatibility: check if a chat has an active turn */
|
|
80
|
+
readonly activeTurns: { has(chatId: string): boolean }
|
|
81
|
+
|
|
82
|
+
constructor(options: RunnerProxyOptions) {
|
|
83
|
+
this.nc = options.nc
|
|
84
|
+
this.store = options.store
|
|
85
|
+
this.runnerId = options.runnerId
|
|
86
|
+
this._getActiveStatuses = options.getActiveStatuses
|
|
87
|
+
this.runtimeRegistry = options.runtimeRegistry ?? null
|
|
88
|
+
this._getRunnerReadiness = options.getRunnerReadiness ?? null
|
|
89
|
+
this.router = options.router ?? null
|
|
90
|
+
this._sharedRunnerId = options.sharedRunnerId ?? (() => this.runnerId)
|
|
91
|
+
this.activeTurns = {
|
|
92
|
+
has: (chatId: string) => this.hasActiveOrJustStartedTurn(chatId),
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolve profile overrides for a workspace+provider into non-secret extraEnv.
|
|
98
|
+
* Binary resolution is done runner-side; the server no longer sets binaryPath.
|
|
99
|
+
*/
|
|
100
|
+
private resolveProfileOverrides(workspaceId: string, provider: AgentProvider): { extraEnv?: Record<string, string> } {
|
|
101
|
+
// Find all profiles for this provider
|
|
102
|
+
const profiles = [...this.store.state.providerProfiles.values()]
|
|
103
|
+
.filter((r: ProviderProfileRecord) => r.profile.provider === provider)
|
|
104
|
+
|
|
105
|
+
if (profiles.length === 0) return {}
|
|
106
|
+
|
|
107
|
+
// Use the first matching profile (TODO: workspace-level default selection)
|
|
108
|
+
const record = profiles[0]
|
|
109
|
+
const wsOverrides = this.store.state.workspaceProfileOverrides.get(workspaceId)
|
|
110
|
+
const override = wsOverrides?.get(record.id)
|
|
111
|
+
const resolved = resolveProfile(record.profile, override?.overrides)
|
|
112
|
+
|
|
113
|
+
// Runtime secret-boundary guard: extraEnv transits the server → the runner,
|
|
114
|
+
// so it must carry NO secrets. Drop (and warn on) any secret-shaped key/value
|
|
115
|
+
// before it leaves the server — secrets are resolved runner-side only.
|
|
116
|
+
const SECRET_PATTERN = /API_KEY|TOKEN|SECRET|Bearer|sk-/i
|
|
117
|
+
const safe: Record<string, string> = {}
|
|
118
|
+
for (const [k, v] of Object.entries(resolved.env ?? {})) {
|
|
119
|
+
if (SECRET_PATTERN.test(k) || SECRET_PATTERN.test(v)) {
|
|
120
|
+
console.warn(`[RunnerProxy] dropping secret-shaped env "${k}" from extraEnv — secrets must stay runner-side`)
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
safe[k] = v
|
|
124
|
+
}
|
|
125
|
+
return { extraEnv: Object.keys(safe).length > 0 ? safe : undefined }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getActiveStatuses(): Map<string, SessionStatus> {
|
|
129
|
+
return this._getActiveStatuses()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private hasObservedActiveTurn(chatId: string): boolean {
|
|
133
|
+
return this._getActiveStatuses().has(chatId)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private hasActiveOrJustStartedTurn(chatId: string): boolean {
|
|
137
|
+
return this.hasObservedActiveTurn(chatId) || this.recentlyStartedChats.has(chatId)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private async sendCommand(cmd: string, payload: unknown, runnerId: string): Promise<unknown> {
|
|
141
|
+
// Gate: incompatible runners must not receive start_turn — fail fast with a clear message.
|
|
142
|
+
// Fail CLOSED: if no readiness source is wired we cannot prove compatibility, so refuse
|
|
143
|
+
// rather than silently dispatching to a possibly-incompatible runner.
|
|
144
|
+
if (cmd === "start_turn") {
|
|
145
|
+
if (!this._getRunnerReadiness) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`RunnerProxy ${runnerId}: getRunnerReadiness not provided — refusing start_turn (cannot enforce the compatibility gate)`,
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
const { incompatible, protocolVersion, capabilities } = this._getRunnerReadiness(runnerId)
|
|
151
|
+
if (incompatible) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Runner ${runnerId} is incompatible (protocol v${protocolVersion ?? "unknown"}, server supports v${SUPPORTED_RANGE.min}–${SUPPORTED_RANGE.max}) — run tinkaria-runner upgrade`,
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
// Capability gate: if the runner advertised capabilities, verify the
|
|
157
|
+
// requested provider is installed. If capabilities is null/undefined (not
|
|
158
|
+
// yet probed — e.g. pre-PR4 runner), skip and allow (fail open for
|
|
159
|
+
// backward compat with runners that haven't registered capabilities yet).
|
|
160
|
+
if (capabilities) {
|
|
161
|
+
const turn = payload as { provider?: AgentProvider }
|
|
162
|
+
const requestedProvider = turn.provider
|
|
163
|
+
if (requestedProvider && !capabilities.providers.includes(requestedProvider)) {
|
|
164
|
+
const installed = capabilities.providers.join(", ") || "none"
|
|
165
|
+
console.warn(
|
|
166
|
+
`[RunnerProxy] capability gate: runner ${runnerId} cannot run provider="${requestedProvider}" (installed: ${installed})`,
|
|
167
|
+
)
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Runner ${runnerId} cannot run ${requestedProvider} (installed: ${installed}) — install it on the runner or pick another`,
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// A claude-pty first turn runs a one-time PTY spawn + security smoke-probe
|
|
176
|
+
// that can legitimately take up to ~65s on a cold cache. The runner only
|
|
177
|
+
// replies once startTurn (and thus the spawn) resolves, so the default 10s
|
|
178
|
+
// window expires while the runner is still spawning — the request then
|
|
179
|
+
// fails with a generic NATS "timeout" even though the turn proceeds and
|
|
180
|
+
// streams via events. Give claude-pty start_turn a window that covers the
|
|
181
|
+
// worst-case probe so the real outcome (success or the actual refusal
|
|
182
|
+
// reason) propagates. Other providers/commands keep fast failure detection.
|
|
183
|
+
const isPtyStartTurn = cmd === "start_turn"
|
|
184
|
+
&& (payload as { provider?: string } | null)?.provider === "claude-pty"
|
|
185
|
+
const timeoutMs = isPtyStartTurn ? 90_000 : 10_000
|
|
186
|
+
const subject = runnerCmdSubject(runnerId, cmd)
|
|
187
|
+
// Observability (decision 0012): the dispatch path was previously silent, so a
|
|
188
|
+
// start_turn that timed out left no server-side trace of which runner it went
|
|
189
|
+
// to. Log the dispatch and its outcome (timeout vs not-ok reply).
|
|
190
|
+
const provider = (payload as { provider?: string } | null)?.provider
|
|
191
|
+
console.warn(`[RunnerProxy] dispatch cmd=${cmd} runnerId=${runnerId} provider=${provider ?? "-"} subject=${subject} timeoutMs=${timeoutMs}`)
|
|
192
|
+
let reply
|
|
193
|
+
try {
|
|
194
|
+
reply = await this.nc.request(
|
|
195
|
+
subject,
|
|
196
|
+
encoder.encode(JSON.stringify(payload)),
|
|
197
|
+
{ timeout: timeoutMs },
|
|
198
|
+
)
|
|
199
|
+
} catch (error) {
|
|
200
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
201
|
+
console.warn(`[RunnerProxy] cmd=${cmd} runnerId=${runnerId} request FAILED (no reply within ${timeoutMs}ms): ${message}`)
|
|
202
|
+
throw error
|
|
203
|
+
}
|
|
204
|
+
const response = JSON.parse(decoder.decode(reply.data))
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
console.warn(`[RunnerProxy] cmd=${cmd} runnerId=${runnerId} runner replied not-ok: ${response.error ?? "(no error)"}`)
|
|
207
|
+
throw new Error(response.error ?? "Runner command failed")
|
|
208
|
+
}
|
|
209
|
+
return response.result
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* PR5: Resolve which runner should handle the next turn for this chat.
|
|
214
|
+
*
|
|
215
|
+
* - No router → legacy single-runner path: return `{ runnerId: this.runnerId, shouldPersist: false }`.
|
|
216
|
+
* - Router present → consult it with the chat's sticky pin (if any):
|
|
217
|
+
* - `selected` → return `{ runnerId, shouldPersist: runnerId !== chat.runnerId }`.
|
|
218
|
+
* - `needs_pick` with no candidates → fail-fast (no eligible runners at all).
|
|
219
|
+
* - `needs_pick` with candidates → throw RunnerPickRequired for the picker.
|
|
220
|
+
* - `unavailable` → fail-fast Error.
|
|
221
|
+
*
|
|
222
|
+
* NOTE: does NOT persist the pin — callers must call `store.setChatRunner` after
|
|
223
|
+
* a successful dispatch when `shouldPersist` is true.
|
|
224
|
+
*/
|
|
225
|
+
private async resolveRunnerForChat(chatId: string, provider: AgentProvider): Promise<{ runnerId: string; shouldPersist: boolean }> {
|
|
226
|
+
if (!this.router) {
|
|
227
|
+
return { runnerId: this.runnerId, shouldPersist: false }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const chat = this.store.requireChat(chatId)
|
|
231
|
+
const preferred = chat.runnerId ?? null
|
|
232
|
+
const sel = await this.router.select({ provider, preferredRunnerId: preferred })
|
|
233
|
+
|
|
234
|
+
if (sel.kind === "selected") {
|
|
235
|
+
const shouldPersist = sel.runnerId !== (chat.runnerId ?? null)
|
|
236
|
+
return { runnerId: sel.runnerId, shouldPersist }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (sel.kind === "needs_pick") {
|
|
240
|
+
if (sel.candidates.length === 0) {
|
|
241
|
+
throw new Error(
|
|
242
|
+
`No eligible runners for provider "${provider}" — start or pair a runner`,
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
throw new RunnerPickRequired({ chatId, candidates: sel.candidates, reason: sel.reason })
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// unavailable
|
|
249
|
+
throw new Error(sel.reason)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* For non-start commands (cancel, respond_tool, stop_chat_pty) the runner
|
|
254
|
+
* MUST be the already-pinned one — never re-route mid-session. If the chat
|
|
255
|
+
* has no pin yet (e.g. being disposed before any turn) fall back to the
|
|
256
|
+
* shared/default runner.
|
|
257
|
+
*/
|
|
258
|
+
private pinnedRunnerForChat(chatId: string): string {
|
|
259
|
+
const chat = this.store.requireChat(chatId)
|
|
260
|
+
return chat.runnerId ?? this._sharedRunnerId()
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Send a chat message — creates chat if needed, delegates turn to runner */
|
|
264
|
+
async send(command: ChatSendCommand): Promise<{ chatId: string }> {
|
|
265
|
+
let chatId = command.chatId
|
|
266
|
+
if (!chatId) {
|
|
267
|
+
if (!command.workspaceId) throw new Error("Missing workspaceId for new chat")
|
|
268
|
+
const created = await this.store.createChat(command.workspaceId)
|
|
269
|
+
chatId = created.id
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const chat = this.store.requireChat(chatId)
|
|
273
|
+
const provider = chat.provider ?? command.provider ?? "claude"
|
|
274
|
+
|
|
275
|
+
const dynamicCatalog = this.runtimeRegistry
|
|
276
|
+
? deriveServerProviderCatalog(this.runtimeRegistry.getProviderCapabilities("claude"))
|
|
277
|
+
: undefined
|
|
278
|
+
const catalog = getServerProviderCatalog(provider)
|
|
279
|
+
let model: string
|
|
280
|
+
let planMode: boolean
|
|
281
|
+
|
|
282
|
+
if (provider === "claude") {
|
|
283
|
+
model = normalizeServerModel(provider, command.model, dynamicCatalog)
|
|
284
|
+
const modelOptions = normalizeClaudeModelOptions(model, command.modelOptions, command.effort)
|
|
285
|
+
model = resolveClaudeApiModelId(model, modelOptions.contextWindow)
|
|
286
|
+
planMode = catalog.supportsPlanMode ? Boolean(command.planMode) : false
|
|
287
|
+
} else {
|
|
288
|
+
model = normalizeServerModel(provider, command.model, dynamicCatalog)
|
|
289
|
+
planMode = catalog.supportsPlanMode ? Boolean(command.planMode) : false
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const project = this.store.getProject(chat.workspaceId)
|
|
293
|
+
if (!project) throw new Error("Project not found")
|
|
294
|
+
|
|
295
|
+
const existingMessages = await this.store.getMessages(chatId)
|
|
296
|
+
const profileOverrides = this.resolveProfileOverrides(chat.workspaceId, provider)
|
|
297
|
+
|
|
298
|
+
const startCmd: StartTurnCommand = {
|
|
299
|
+
chatId,
|
|
300
|
+
provider,
|
|
301
|
+
content: command.content,
|
|
302
|
+
model,
|
|
303
|
+
planMode,
|
|
304
|
+
appendUserPrompt: true,
|
|
305
|
+
workspaceLocalPath: project.localPath,
|
|
306
|
+
sessionToken: chat.sessionToken,
|
|
307
|
+
chatTitle: chat.title,
|
|
308
|
+
existingMessageCount: existingMessages.length,
|
|
309
|
+
workspaceId: chat.workspaceId,
|
|
310
|
+
...profileOverrides,
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (chat.provider !== provider) {
|
|
314
|
+
if (chat.sessionToken) {
|
|
315
|
+
await this.store.setSessionToken(chatId, null)
|
|
316
|
+
}
|
|
317
|
+
await this.store.setChatProvider(chatId, provider)
|
|
318
|
+
}
|
|
319
|
+
await this.store.setChatModel(chatId, model)
|
|
320
|
+
await this.store.setPlanMode(chatId, planMode)
|
|
321
|
+
|
|
322
|
+
const { runnerId, shouldPersist } = await this.resolveRunnerForChat(chatId, provider)
|
|
323
|
+
await this.sendCommand("start_turn", startCmd, runnerId)
|
|
324
|
+
if (shouldPersist) await this.store.setChatRunner(chatId, runnerId)
|
|
325
|
+
this.recentlyStartedChats.add(chatId)
|
|
326
|
+
return { chatId }
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async queue(command: ChatQueueCommand): Promise<{ chatId: string; queued: boolean }> {
|
|
330
|
+
if (!this.hasActiveOrJustStartedTurn(command.chatId)) {
|
|
331
|
+
await this.send({
|
|
332
|
+
...command,
|
|
333
|
+
type: "chat.send",
|
|
334
|
+
})
|
|
335
|
+
return { chatId: command.chatId, queued: false }
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
await this.store.enqueueQueuedTurn({
|
|
339
|
+
chatId: command.chatId,
|
|
340
|
+
provider: command.provider,
|
|
341
|
+
content: command.content,
|
|
342
|
+
model: command.model,
|
|
343
|
+
modelOptions: command.modelOptions,
|
|
344
|
+
effort: command.effort,
|
|
345
|
+
planMode: command.planMode,
|
|
346
|
+
})
|
|
347
|
+
return { chatId: command.chatId, queued: true }
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
async drainQueuedTurn(chatId: string): Promise<boolean> {
|
|
351
|
+
this.recentlyStartedChats.delete(chatId)
|
|
352
|
+
if (this.hasObservedActiveTurn(chatId)) return false
|
|
353
|
+
|
|
354
|
+
const queued = this.store.getQueuedTurn(chatId)
|
|
355
|
+
if (!queued) return false
|
|
356
|
+
|
|
357
|
+
await this.store.clearQueuedTurn(chatId)
|
|
358
|
+
try {
|
|
359
|
+
await this.send({
|
|
360
|
+
type: "chat.send",
|
|
361
|
+
chatId,
|
|
362
|
+
provider: queued.provider,
|
|
363
|
+
content: queued.content,
|
|
364
|
+
model: queued.model,
|
|
365
|
+
modelOptions: queued.modelOptions,
|
|
366
|
+
effort: queued.effort,
|
|
367
|
+
planMode: queued.planMode,
|
|
368
|
+
})
|
|
369
|
+
return true
|
|
370
|
+
} catch (error) {
|
|
371
|
+
await this.store.enqueueQueuedTurn(queued)
|
|
372
|
+
throw error
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** Resume parent chat after a delegated child agent completes */
|
|
377
|
+
async drainDelegationResult(chatId: string, delegationId: string): Promise<boolean> {
|
|
378
|
+
if (this.hasObservedActiveTurn(chatId)) return false
|
|
379
|
+
|
|
380
|
+
const queued = this.store.getQueuedTurn(chatId)
|
|
381
|
+
if (queued) return false
|
|
382
|
+
|
|
383
|
+
const chat = this.store.requireChat(chatId)
|
|
384
|
+
const project = this.store.getProject(chat.workspaceId)
|
|
385
|
+
if (!project) throw new Error("Project not found")
|
|
386
|
+
|
|
387
|
+
const provider = chat.provider ?? "claude"
|
|
388
|
+
const profileOverrides = this.resolveProfileOverrides(chat.workspaceId, provider)
|
|
389
|
+
const existingMessages = await this.store.getMessages(chatId)
|
|
390
|
+
|
|
391
|
+
const startCmd: StartTurnCommand = {
|
|
392
|
+
chatId,
|
|
393
|
+
provider,
|
|
394
|
+
content: `[Delegation result ready] The delegated agent has completed. Review the agent_result entry above and continue.`,
|
|
395
|
+
model: chat.model ?? "sonnet",
|
|
396
|
+
planMode: chat.planMode ?? false,
|
|
397
|
+
appendUserPrompt: false,
|
|
398
|
+
workspaceLocalPath: project.localPath,
|
|
399
|
+
sessionToken: chat.sessionToken,
|
|
400
|
+
chatTitle: chat.title,
|
|
401
|
+
existingMessageCount: existingMessages.length,
|
|
402
|
+
workspaceId: chat.workspaceId,
|
|
403
|
+
...profileOverrides,
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const { runnerId, shouldPersist } = await this.resolveRunnerForChat(chatId, provider)
|
|
407
|
+
await this.sendCommand("start_turn", startCmd, runnerId)
|
|
408
|
+
if (shouldPersist) await this.store.setChatRunner(chatId, runnerId)
|
|
409
|
+
this.recentlyStartedChats.add(chatId)
|
|
410
|
+
return true
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** Start a turn for a specific chat — used by orchestration */
|
|
414
|
+
async startTurnForChat(args: {
|
|
415
|
+
chatId: string
|
|
416
|
+
provider: AgentProvider
|
|
417
|
+
content: string
|
|
418
|
+
delegatedContext?: string
|
|
419
|
+
isSpawned?: boolean
|
|
420
|
+
model: string
|
|
421
|
+
effort?: string
|
|
422
|
+
serviceTier?: "fast"
|
|
423
|
+
planMode: boolean
|
|
424
|
+
appendUserPrompt: boolean
|
|
425
|
+
}): Promise<void> {
|
|
426
|
+
const chat = this.store.requireChat(args.chatId)
|
|
427
|
+
const project = this.store.getProject(chat.workspaceId)
|
|
428
|
+
if (!project) throw new Error("Project not found")
|
|
429
|
+
|
|
430
|
+
if (chat.provider !== args.provider) {
|
|
431
|
+
if (chat.sessionToken) {
|
|
432
|
+
await this.store.setSessionToken(args.chatId, null)
|
|
433
|
+
}
|
|
434
|
+
await this.store.setChatProvider(args.chatId, args.provider)
|
|
435
|
+
}
|
|
436
|
+
await this.store.setChatModel(args.chatId, args.model)
|
|
437
|
+
await this.store.setPlanMode(args.chatId, args.planMode)
|
|
438
|
+
|
|
439
|
+
const profileOverrides = this.resolveProfileOverrides(chat.workspaceId, args.provider)
|
|
440
|
+
const startCmd: StartTurnCommand = {
|
|
441
|
+
chatId: args.chatId,
|
|
442
|
+
provider: args.provider,
|
|
443
|
+
content: args.content,
|
|
444
|
+
delegatedContext: args.delegatedContext,
|
|
445
|
+
isSpawned: args.isSpawned,
|
|
446
|
+
model: args.model,
|
|
447
|
+
planMode: args.planMode,
|
|
448
|
+
appendUserPrompt: args.appendUserPrompt,
|
|
449
|
+
workspaceLocalPath: project.localPath,
|
|
450
|
+
sessionToken: chat.sessionToken,
|
|
451
|
+
chatTitle: chat.title,
|
|
452
|
+
existingMessageCount: (await this.store.getMessages(args.chatId)).length,
|
|
453
|
+
workspaceId: chat.workspaceId,
|
|
454
|
+
...profileOverrides,
|
|
455
|
+
}
|
|
456
|
+
const { runnerId, shouldPersist } = await this.resolveRunnerForChat(args.chatId, args.provider)
|
|
457
|
+
await this.sendCommand("start_turn", startCmd, runnerId)
|
|
458
|
+
if (shouldPersist) await this.store.setChatRunner(args.chatId, runnerId)
|
|
459
|
+
this.recentlyStartedChats.add(args.chatId)
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async cancel(chatId: string): Promise<void> {
|
|
463
|
+
const runnerId = this.pinnedRunnerForChat(chatId)
|
|
464
|
+
await this.sendCommand("cancel_turn", { chatId }, runnerId)
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
async respondTool(command: Extract<ClientCommand, { type: "chat.respondTool" }>): Promise<void> {
|
|
468
|
+
const runnerId = this.pinnedRunnerForChat(command.chatId)
|
|
469
|
+
await this.sendCommand("respond_tool", {
|
|
470
|
+
chatId: command.chatId,
|
|
471
|
+
toolUseId: command.toolUseId,
|
|
472
|
+
result: command.result,
|
|
473
|
+
}, runnerId)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
async disposeChat(chatId: string): Promise<void> {
|
|
477
|
+
const runnerId = this.pinnedRunnerForChat(chatId)
|
|
478
|
+
try {
|
|
479
|
+
await this.sendCommand("cancel_turn", { chatId }, runnerId)
|
|
480
|
+
} catch (_error) {
|
|
481
|
+
// Chat might not be running — swallow
|
|
482
|
+
}
|
|
483
|
+
// Tear down any long-lived claude-pty session for this chat. Cancel
|
|
484
|
+
// above only sends ^C to the active turn (preserving the session for
|
|
485
|
+
// a follow-up prompt). A chat being deleted must release the claude
|
|
486
|
+
// CLI child + MCP HTTP server + file watcher + memory sampler + OAuth
|
|
487
|
+
// pool reservation. Mirrors kanna's `closeChat` discipline.
|
|
488
|
+
try {
|
|
489
|
+
await this.sendCommand("stop_chat_pty", { chatId }, runnerId)
|
|
490
|
+
} catch (_error) {
|
|
491
|
+
// Runner may have already cleared the session — swallow
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|