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,277 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test"
|
|
2
|
+
import {
|
|
3
|
+
runnerHeartbeatSubject,
|
|
4
|
+
runnerCmdSubject,
|
|
5
|
+
runnerEventsSubject,
|
|
6
|
+
RUNNER_REGISTRY_BUCKET,
|
|
7
|
+
RUNNER_EVENTS_STREAM,
|
|
8
|
+
ALL_RUNNER_EVENTS,
|
|
9
|
+
PROTOCOL_VERSION,
|
|
10
|
+
SUPPORTED_RANGE,
|
|
11
|
+
isProtocolSupported,
|
|
12
|
+
runnerLivenessState,
|
|
13
|
+
LIVENESS_DEGRADED_MS,
|
|
14
|
+
LIVENESS_OFFLINE_MS,
|
|
15
|
+
type RunnerTurnEvent,
|
|
16
|
+
type StartTurnCommand,
|
|
17
|
+
type CancelTurnCommand,
|
|
18
|
+
type RespondToolCommand,
|
|
19
|
+
type ShutdownCommand,
|
|
20
|
+
type RunnerRegistration,
|
|
21
|
+
type RunnerHeartbeat,
|
|
22
|
+
} from "./runner-protocol"
|
|
23
|
+
|
|
24
|
+
describe("runner protocol subjects", () => {
|
|
25
|
+
test("heartbeat subject", () => {
|
|
26
|
+
expect(runnerHeartbeatSubject("r1")).toBe("runtime.runner.heartbeat.r1")
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test("command subjects", () => {
|
|
30
|
+
expect(runnerCmdSubject("r1", "start_turn")).toBe("runtime.runner.cmd.r1.start_turn")
|
|
31
|
+
expect(runnerCmdSubject("r1", "cancel_turn")).toBe("runtime.runner.cmd.r1.cancel_turn")
|
|
32
|
+
expect(runnerCmdSubject("r1", "respond_tool")).toBe("runtime.runner.cmd.r1.respond_tool")
|
|
33
|
+
expect(runnerCmdSubject("r1", "shutdown")).toBe("runtime.runner.cmd.r1.shutdown")
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("events subject", () => {
|
|
37
|
+
expect(runnerEventsSubject("chat-123")).toBe("runtime.runner.evt.chat-123")
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test("registry bucket constant", () => {
|
|
41
|
+
expect(RUNNER_REGISTRY_BUCKET).toBe("runtime_runner_registry")
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test("stream constants", () => {
|
|
45
|
+
expect(RUNNER_EVENTS_STREAM).toBe("KANNA_RUNNER_EVENTS")
|
|
46
|
+
expect(ALL_RUNNER_EVENTS).toBe("runtime.runner.evt.>")
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// ── PR4 Stage 1 audit: StartTurnCommand secret boundary ─────────────
|
|
51
|
+
|
|
52
|
+
describe("StartTurnCommand PR4 shape audit", () => {
|
|
53
|
+
const SECRET_PATTERN = /API_KEY|TOKEN|SECRET|Bearer|sk-/i
|
|
54
|
+
|
|
55
|
+
function hasSecretShapedKey(obj: Record<string, string>): boolean {
|
|
56
|
+
return Object.keys(obj).some((k) => SECRET_PATTERN.test(k))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function hasSecretShapedValue(obj: Record<string, string>): boolean {
|
|
60
|
+
return Object.values(obj).some((v) => SECRET_PATTERN.test(v))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test("StartTurnCommand type has no binaryPath field", () => {
|
|
64
|
+
// This is a type-level check enforced via the shape of a representative command.
|
|
65
|
+
// If binaryPath were re-introduced, the spread below would surface it.
|
|
66
|
+
const cmd: StartTurnCommand = {
|
|
67
|
+
chatId: "c1",
|
|
68
|
+
provider: "claude",
|
|
69
|
+
content: "hello",
|
|
70
|
+
model: "claude-sonnet-4-6",
|
|
71
|
+
planMode: false,
|
|
72
|
+
appendUserPrompt: true,
|
|
73
|
+
workspaceLocalPath: "/tmp/ws",
|
|
74
|
+
sessionToken: null,
|
|
75
|
+
chatTitle: "New Chat",
|
|
76
|
+
existingMessageCount: 0,
|
|
77
|
+
workspaceId: "p1",
|
|
78
|
+
extraEnv: { NODE_ENV: "production" },
|
|
79
|
+
}
|
|
80
|
+
// Serialise as the server would send it on the wire.
|
|
81
|
+
const wire = JSON.parse(JSON.stringify(cmd)) as Record<string, unknown>
|
|
82
|
+
expect("binaryPath" in wire).toBe(false)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test("resolveProfileOverrides returns no binaryPath in its shape (env only)", () => {
|
|
86
|
+
// We represent the server output by constructing the object it would spread.
|
|
87
|
+
// This mirrors the server calling resolveProfileOverrides and spreading into StartTurnCommand.
|
|
88
|
+
const profileOverrides: { extraEnv?: Record<string, string> } = {
|
|
89
|
+
extraEnv: { SOME_TEAM_FLAG: "1" },
|
|
90
|
+
}
|
|
91
|
+
const wire = JSON.parse(JSON.stringify(profileOverrides)) as Record<string, unknown>
|
|
92
|
+
expect("binaryPath" in wire).toBe(false)
|
|
93
|
+
expect("extraEnv" in wire).toBe(true)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
test("extraEnv with no secret-shaped keys passes the audit guard", () => {
|
|
97
|
+
const safeEnv: Record<string, string> = {
|
|
98
|
+
NODE_ENV: "production",
|
|
99
|
+
SOME_TEAM_FLAG: "1",
|
|
100
|
+
LOG_LEVEL: "info",
|
|
101
|
+
}
|
|
102
|
+
expect(hasSecretShapedKey(safeEnv)).toBe(false)
|
|
103
|
+
expect(hasSecretShapedValue(safeEnv)).toBe(false)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test("extraEnv with secret-shaped keys is detected by the audit guard", () => {
|
|
107
|
+
const leakyEnv: Record<string, string> = {
|
|
108
|
+
ANTHROPIC_API_KEY: "sk-ant-abc123",
|
|
109
|
+
NODE_ENV: "production",
|
|
110
|
+
}
|
|
111
|
+
expect(hasSecretShapedKey(leakyEnv)).toBe(true)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
test("extraEnv with Bearer-prefixed value is detected by the audit guard", () => {
|
|
115
|
+
const leakyEnv: Record<string, string> = {
|
|
116
|
+
AUTH_HEADER: "Bearer eyJhbGci...",
|
|
117
|
+
}
|
|
118
|
+
expect(hasSecretShapedValue(leakyEnv)).toBe(true)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test("a representative wire-serialised StartTurnCommand contains no binaryPath and no secret-shaped values", () => {
|
|
122
|
+
const cmd: StartTurnCommand = {
|
|
123
|
+
chatId: "c-audit",
|
|
124
|
+
provider: "codex",
|
|
125
|
+
content: "implement feature X",
|
|
126
|
+
model: "gpt-5.4",
|
|
127
|
+
planMode: false,
|
|
128
|
+
appendUserPrompt: true,
|
|
129
|
+
workspaceLocalPath: "/home/user/project",
|
|
130
|
+
sessionToken: null,
|
|
131
|
+
chatTitle: "Feature chat",
|
|
132
|
+
existingMessageCount: 0,
|
|
133
|
+
workspaceId: "ws-1",
|
|
134
|
+
extraEnv: { TEAM_FLAG: "on", NODE_ENV: "production" },
|
|
135
|
+
}
|
|
136
|
+
const wire = JSON.parse(JSON.stringify(cmd)) as Record<string, unknown>
|
|
137
|
+
|
|
138
|
+
expect("binaryPath" in wire).toBe(false)
|
|
139
|
+
|
|
140
|
+
const env = wire.extraEnv as Record<string, string> | undefined
|
|
141
|
+
if (env) {
|
|
142
|
+
expect(hasSecretShapedKey(env)).toBe(false)
|
|
143
|
+
expect(hasSecretShapedValue(env)).toBe(false)
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
describe("runner protocol types", () => {
|
|
149
|
+
test("RunnerTurnEvent discriminated union covers all event types", () => {
|
|
150
|
+
const events: RunnerTurnEvent[] = [
|
|
151
|
+
{ type: "transcript", chatId: "c1", entry: { _id: "e1", kind: "assistant_text", text: "hi", createdAt: 1 } as any },
|
|
152
|
+
{ type: "session_token", chatId: "c1", sessionToken: "tok" },
|
|
153
|
+
{ type: "status_change", chatId: "c1", status: "running" as any },
|
|
154
|
+
{ type: "pending_tool", chatId: "c1", tool: null },
|
|
155
|
+
{ type: "turn_finished", chatId: "c1" },
|
|
156
|
+
{ type: "turn_failed", chatId: "c1", error: "oops" },
|
|
157
|
+
{ type: "turn_cancelled", chatId: "c1" },
|
|
158
|
+
{ type: "title_generated", chatId: "c1", title: "My Chat" },
|
|
159
|
+
{ type: "plan_mode_set", chatId: "c1", planMode: true },
|
|
160
|
+
{ type: "provider_set", chatId: "c1", provider: "claude" },
|
|
161
|
+
{ type: "context_cleared", chatId: "c1" },
|
|
162
|
+
]
|
|
163
|
+
expect(events).toHaveLength(11)
|
|
164
|
+
// Verify each type is unique
|
|
165
|
+
const types = events.map(e => e.type)
|
|
166
|
+
expect(new Set(types).size).toBe(11)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
test("StartTurnCommand has required fields", () => {
|
|
170
|
+
const cmd: StartTurnCommand = {
|
|
171
|
+
chatId: "c1", provider: "claude", content: "hello",
|
|
172
|
+
delegatedContext: "Forked parent chat context:\nUser: earlier work",
|
|
173
|
+
isSpawned: true,
|
|
174
|
+
model: "claude-sonnet-4-6", planMode: false, appendUserPrompt: true,
|
|
175
|
+
workspaceLocalPath: "/tmp", sessionToken: null, chatTitle: "New Chat",
|
|
176
|
+
existingMessageCount: 0, workspaceId: "p1",
|
|
177
|
+
}
|
|
178
|
+
expect(cmd.chatId).toBe("c1")
|
|
179
|
+
expect(cmd.provider).toBe("claude")
|
|
180
|
+
expect(cmd.delegatedContext).toContain("Forked parent chat context:")
|
|
181
|
+
expect(cmd.isSpawned).toBe(true)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
test("CancelTurnCommand has required fields", () => {
|
|
185
|
+
const cmd: CancelTurnCommand = { chatId: "c1" }
|
|
186
|
+
expect(cmd.chatId).toBe("c1")
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test("RespondToolCommand has required fields", () => {
|
|
190
|
+
const cmd: RespondToolCommand = { chatId: "c1", toolUseId: "t1", result: "approved" }
|
|
191
|
+
expect(cmd.chatId).toBe("c1")
|
|
192
|
+
expect(cmd.toolUseId).toBe("t1")
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
test("ShutdownCommand has required fields", () => {
|
|
196
|
+
const cmd: ShutdownCommand = { reason: "user_requested" }
|
|
197
|
+
expect(cmd.reason).toBe("user_requested")
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
test("RunnerRegistration has required fields", () => {
|
|
201
|
+
const reg: RunnerRegistration = {
|
|
202
|
+
runnerId: "r1", pid: 123, startedAt: Date.now(), providers: ["claude", "codex"],
|
|
203
|
+
protocolVersion: 1,
|
|
204
|
+
}
|
|
205
|
+
expect(reg.runnerId).toBe("r1")
|
|
206
|
+
expect(reg.protocolVersion).toBe(1)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
test("RunnerHeartbeat has required fields", () => {
|
|
210
|
+
const hb: RunnerHeartbeat = {
|
|
211
|
+
runnerId: "r1", activeChatIds: ["c1", "c2"], ts: Date.now(),
|
|
212
|
+
}
|
|
213
|
+
expect(hb.runnerId).toBe("r1")
|
|
214
|
+
expect(hb.activeChatIds).toHaveLength(2)
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
describe("protocol version constants", () => {
|
|
219
|
+
test("PROTOCOL_VERSION is 1", () => {
|
|
220
|
+
expect(PROTOCOL_VERSION).toBe(1)
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
test("SUPPORTED_RANGE min=max=PROTOCOL_VERSION", () => {
|
|
224
|
+
expect(SUPPORTED_RANGE.min).toBe(PROTOCOL_VERSION)
|
|
225
|
+
expect(SUPPORTED_RANGE.max).toBe(PROTOCOL_VERSION)
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
describe("isProtocolSupported", () => {
|
|
230
|
+
test("returns true for v1 (current)", () => {
|
|
231
|
+
expect(isProtocolSupported(1)).toBe(true)
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
test("returns false for v0 (below range)", () => {
|
|
235
|
+
expect(isProtocolSupported(0)).toBe(false)
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
test("returns false for v2 (above range)", () => {
|
|
239
|
+
expect(isProtocolSupported(2)).toBe(false)
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
test("returns false for negative version", () => {
|
|
243
|
+
expect(isProtocolSupported(-1)).toBe(false)
|
|
244
|
+
})
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
describe("runnerLivenessState", () => {
|
|
248
|
+
const NOW = 1_000_000
|
|
249
|
+
|
|
250
|
+
test("null lastHeartbeatAt → offline", () => {
|
|
251
|
+
expect(runnerLivenessState(null, NOW)).toBe("offline")
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test("age=0 → online", () => {
|
|
255
|
+
expect(runnerLivenessState(NOW, NOW)).toBe("online")
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
test("age=24_999 (just under LIVENESS_DEGRADED_MS) → online", () => {
|
|
259
|
+
expect(runnerLivenessState(NOW - (LIVENESS_DEGRADED_MS - 1), NOW)).toBe("online")
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
test("age=25_000 (at LIVENESS_DEGRADED_MS) → degraded", () => {
|
|
263
|
+
expect(runnerLivenessState(NOW - LIVENESS_DEGRADED_MS, NOW)).toBe("degraded")
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
test("age=59_999 (just under LIVENESS_OFFLINE_MS) → degraded", () => {
|
|
267
|
+
expect(runnerLivenessState(NOW - (LIVENESS_OFFLINE_MS - 1), NOW)).toBe("degraded")
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
test("age=60_000 (at LIVENESS_OFFLINE_MS) → offline", () => {
|
|
271
|
+
expect(runnerLivenessState(NOW - LIVENESS_OFFLINE_MS, NOW)).toBe("offline")
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
test("age=100_000 (well above LIVENESS_OFFLINE_MS) → offline", () => {
|
|
275
|
+
expect(runnerLivenessState(NOW - 100_000, NOW)).toBe("offline")
|
|
276
|
+
})
|
|
277
|
+
})
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type { AgentProvider, TranscriptEntry, SessionStatus, PendingToolSnapshot } from "./types"
|
|
2
|
+
|
|
3
|
+
// ── Protocol versioning ──────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/** Current protocol version emitted by this runner build. */
|
|
6
|
+
export const PROTOCOL_VERSION = 1
|
|
7
|
+
|
|
8
|
+
/** Server-side supported protocol range. Runners outside [min, max] are incompatible. */
|
|
9
|
+
export const SUPPORTED_RANGE: { min: number; max: number } = { min: 1, max: 1 }
|
|
10
|
+
|
|
11
|
+
/** Returns true if v is within the supported protocol range. */
|
|
12
|
+
export function isProtocolSupported(v: number): boolean {
|
|
13
|
+
return v >= SUPPORTED_RANGE.min && v <= SUPPORTED_RANGE.max
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ── Liveness ─────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
/** Age threshold below which a runner is considered online (ms). */
|
|
19
|
+
export const LIVENESS_DEGRADED_MS = 25_000
|
|
20
|
+
|
|
21
|
+
/** Age threshold at-or-above which a runner is considered offline (ms). */
|
|
22
|
+
export const LIVENESS_OFFLINE_MS = 60_000
|
|
23
|
+
|
|
24
|
+
export type RunnerLivenessState = "online" | "degraded" | "offline"
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Compute liveness state from last heartbeat timestamp and current time.
|
|
28
|
+
* Pure function — no I/O or side effects.
|
|
29
|
+
*/
|
|
30
|
+
export function runnerLivenessState(
|
|
31
|
+
lastHeartbeatAt: number | null,
|
|
32
|
+
now: number,
|
|
33
|
+
): RunnerLivenessState {
|
|
34
|
+
if (lastHeartbeatAt === null) return "offline"
|
|
35
|
+
const age = now - lastHeartbeatAt
|
|
36
|
+
if (age < LIVENESS_DEGRADED_MS) return "online"
|
|
37
|
+
if (age < LIVENESS_OFFLINE_MS) return "degraded"
|
|
38
|
+
return "offline"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── Subject helpers ──────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
const PREFIX = "runtime.runner"
|
|
44
|
+
|
|
45
|
+
export function runnerHeartbeatSubject(runnerId: string): string {
|
|
46
|
+
return `${PREFIX}.heartbeat.${runnerId}`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function runnerCmdSubject(runnerId: string, cmd: string): string {
|
|
50
|
+
return `${PREFIX}.cmd.${runnerId}.${cmd}`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function runnerEventsSubject(chatId: string): string {
|
|
54
|
+
return `${PREFIX}.evt.${chatId}`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── Constants ────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
/** KV bucket name for runner registration entries */
|
|
60
|
+
export const RUNNER_REGISTRY_BUCKET = "runtime_runner_registry"
|
|
61
|
+
|
|
62
|
+
/** JetStream stream name for runner turn events */
|
|
63
|
+
export const RUNNER_EVENTS_STREAM = "KANNA_RUNNER_EVENTS"
|
|
64
|
+
|
|
65
|
+
/** Wildcard: all runner events */
|
|
66
|
+
export const ALL_RUNNER_EVENTS = `${PREFIX}.evt.>`
|
|
67
|
+
|
|
68
|
+
// ── Command types ────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
export interface StartTurnCommand {
|
|
71
|
+
chatId: string
|
|
72
|
+
provider: AgentProvider
|
|
73
|
+
content: string
|
|
74
|
+
delegatedContext?: string
|
|
75
|
+
isSpawned?: boolean
|
|
76
|
+
model: string
|
|
77
|
+
planMode: boolean
|
|
78
|
+
appendUserPrompt: boolean
|
|
79
|
+
workspaceLocalPath: string
|
|
80
|
+
sessionToken: string | null
|
|
81
|
+
chatTitle: string
|
|
82
|
+
existingMessageCount: number
|
|
83
|
+
workspaceId: string
|
|
84
|
+
/**
|
|
85
|
+
* Non-secret team env vars from the provider profile. The runner merges
|
|
86
|
+
* these with its own process.env (process.env wins on collision). Must
|
|
87
|
+
* NOT contain secrets (API keys, tokens, OAuth credentials) — secrets are
|
|
88
|
+
* resolved runner-side from local env and the OAuth pool and never transit
|
|
89
|
+
* the server↔runner boundary.
|
|
90
|
+
*/
|
|
91
|
+
extraEnv?: Record<string, string>
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface CancelTurnCommand {
|
|
95
|
+
chatId: string
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface StopChatPtyCommand {
|
|
99
|
+
chatId: string
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface RespondToolCommand {
|
|
103
|
+
chatId: string
|
|
104
|
+
toolUseId: string
|
|
105
|
+
result: string
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface ShutdownCommand {
|
|
109
|
+
reason: string
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ── Turn event discriminated union ───────────────────────────────────
|
|
113
|
+
|
|
114
|
+
interface RunnerTurnEventBase {
|
|
115
|
+
chatId: string
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface TranscriptEvent extends RunnerTurnEventBase {
|
|
119
|
+
type: "transcript"
|
|
120
|
+
entry: TranscriptEntry
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface SessionTokenEvent extends RunnerTurnEventBase {
|
|
124
|
+
type: "session_token"
|
|
125
|
+
sessionToken: string
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
interface StatusChangeEvent extends RunnerTurnEventBase {
|
|
129
|
+
type: "status_change"
|
|
130
|
+
status: SessionStatus
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface PendingToolEvent extends RunnerTurnEventBase {
|
|
134
|
+
type: "pending_tool"
|
|
135
|
+
tool: PendingToolSnapshot | null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
interface TurnFinishedEvent extends RunnerTurnEventBase {
|
|
139
|
+
type: "turn_finished"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface TurnFailedEvent extends RunnerTurnEventBase {
|
|
143
|
+
type: "turn_failed"
|
|
144
|
+
error: string
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface TurnCancelledEvent extends RunnerTurnEventBase {
|
|
148
|
+
type: "turn_cancelled"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface TitleGeneratedEvent extends RunnerTurnEventBase {
|
|
152
|
+
type: "title_generated"
|
|
153
|
+
title: string
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
interface PlanModeSetEvent extends RunnerTurnEventBase {
|
|
157
|
+
type: "plan_mode_set"
|
|
158
|
+
planMode: boolean
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
interface ProviderSetEvent extends RunnerTurnEventBase {
|
|
162
|
+
type: "provider_set"
|
|
163
|
+
provider: AgentProvider
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
interface ContextClearedEvent extends RunnerTurnEventBase {
|
|
167
|
+
type: "context_cleared"
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export type RunnerTurnEvent =
|
|
171
|
+
| TranscriptEvent
|
|
172
|
+
| SessionTokenEvent
|
|
173
|
+
| StatusChangeEvent
|
|
174
|
+
| PendingToolEvent
|
|
175
|
+
| TurnFinishedEvent
|
|
176
|
+
| TurnFailedEvent
|
|
177
|
+
| TurnCancelledEvent
|
|
178
|
+
| TitleGeneratedEvent
|
|
179
|
+
| PlanModeSetEvent
|
|
180
|
+
| ProviderSetEvent
|
|
181
|
+
| ContextClearedEvent
|
|
182
|
+
|
|
183
|
+
// ── Registration & heartbeat ─────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
export interface RunnerCapabilities {
|
|
186
|
+
providers: AgentProvider[]
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface RunnerRegistration {
|
|
190
|
+
runnerId: string
|
|
191
|
+
pid: number
|
|
192
|
+
startedAt: number
|
|
193
|
+
providers: AgentProvider[]
|
|
194
|
+
/** Protocol version reported by the runner. Missing → treated as incompatible. */
|
|
195
|
+
protocolVersion: number
|
|
196
|
+
/** Optional capability probe (shape only; rich probe added in PR4). */
|
|
197
|
+
capabilities?: RunnerCapabilities
|
|
198
|
+
/**
|
|
199
|
+
* Timestamp (ms since epoch) of the runner's last KV self-write, piggybacked on
|
|
200
|
+
* the heartbeat loop. Used by the discover path (no live heartbeat subscription)
|
|
201
|
+
* to judge liveness via runnerLivenessState. Not written by the server.
|
|
202
|
+
*/
|
|
203
|
+
lastSeenAt?: number
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface RunnerHeartbeat {
|
|
207
|
+
runnerId: string
|
|
208
|
+
activeChatIds: string[]
|
|
209
|
+
ts: number
|
|
210
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runner team types (US-RTN).
|
|
3
|
+
*
|
|
4
|
+
* Operator-managed, display-only metadata for remote runners:
|
|
5
|
+
* - TeamMember: a flat "member" the single operator manages (names only — no
|
|
6
|
+
* auth, no accounts, no permissions).
|
|
7
|
+
* - RunnerLabel: a human name + optional member assignment, keyed by runnerId.
|
|
8
|
+
*
|
|
9
|
+
* Persisted as EventStore events (see events.ts `RunnerTeamEvent`), mirroring
|
|
10
|
+
* provider profiles. This is intentionally separate from the runner-owned NATS
|
|
11
|
+
* KV registry (`runtime_runner_registry`), which the runner rewrites on every
|
|
12
|
+
* heartbeat and would clobber any server-set fields. Routing/eligibility never
|
|
13
|
+
* reads this data.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** A member of the operator's local "team". Names only — not an authenticated user. */
|
|
17
|
+
export interface TeamMember {
|
|
18
|
+
id: string
|
|
19
|
+
name: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Human label + member assignment for a single runner. Upserted by runnerId. */
|
|
23
|
+
export interface RunnerLabel {
|
|
24
|
+
runnerId: string
|
|
25
|
+
/** Operator-given runner name. null ⇒ UI falls back to the short runnerId. */
|
|
26
|
+
name: string | null
|
|
27
|
+
/** Assigned member id, or null when unassigned. */
|
|
28
|
+
memberId: string | null
|
|
29
|
+
/** Unix epoch ms of the last label write. */
|
|
30
|
+
updatedAt: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Stored runner-label record (currently identical to RunnerLabel; kept distinct for parity with ProviderProfileRecord). */
|
|
34
|
+
export type RunnerLabelRecord = RunnerLabel
|
|
35
|
+
|
|
36
|
+
/** Snapshot broadcast on the `runner-teams` subscription topic. */
|
|
37
|
+
export interface RunnerTeamSnapshot {
|
|
38
|
+
members: TeamMember[]
|
|
39
|
+
runners: RunnerLabel[]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a runner's display name: the operator label when set, else a short
|
|
44
|
+
* form of the runnerId (last two dash-separated segments). Pure — unit-tested.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveRunnerName(
|
|
47
|
+
runnerId: string,
|
|
48
|
+
labels: ReadonlyMap<string, RunnerLabel> | readonly RunnerLabel[],
|
|
49
|
+
): string {
|
|
50
|
+
const label = Array.isArray(labels)
|
|
51
|
+
? labels.find((l) => l.runnerId === runnerId)
|
|
52
|
+
: (labels as ReadonlyMap<string, RunnerLabel>).get(runnerId)
|
|
53
|
+
const name = label?.name?.trim()
|
|
54
|
+
if (name) return name
|
|
55
|
+
const parts = runnerId.split("-")
|
|
56
|
+
return parts.length > 1 ? parts.slice(-2).join("-") : runnerId
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Resolve the member assigned to a runner, or null. Pure. */
|
|
60
|
+
export function resolveRunnerMember(
|
|
61
|
+
runnerId: string,
|
|
62
|
+
labels: ReadonlyMap<string, RunnerLabel> | readonly RunnerLabel[],
|
|
63
|
+
members: ReadonlyMap<string, TeamMember> | readonly TeamMember[],
|
|
64
|
+
): TeamMember | null {
|
|
65
|
+
const label = Array.isArray(labels)
|
|
66
|
+
? labels.find((l) => l.runnerId === runnerId)
|
|
67
|
+
: (labels as ReadonlyMap<string, RunnerLabel>).get(runnerId)
|
|
68
|
+
if (!label?.memberId) return null
|
|
69
|
+
const memberId = label.memberId
|
|
70
|
+
return Array.isArray(members)
|
|
71
|
+
? (members.find((m) => m.id === memberId) ?? null)
|
|
72
|
+
: ((members as ReadonlyMap<string, TeamMember>).get(memberId) ?? null)
|
|
73
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type RuntimeSource = "managed" | "system"
|
|
2
|
+
|
|
3
|
+
export interface RuntimeEntry {
|
|
4
|
+
provider: "claude" | "codex"
|
|
5
|
+
version: string
|
|
6
|
+
source: RuntimeSource
|
|
7
|
+
binaryPath: string
|
|
8
|
+
installedAt: number
|
|
9
|
+
packageName: string
|
|
10
|
+
capabilities?: RuntimeCapabilities
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface RuntimeHealthStatus {
|
|
14
|
+
provider: string
|
|
15
|
+
version: string
|
|
16
|
+
binaryPath: string
|
|
17
|
+
status: "healthy" | "degraded" | "unavailable"
|
|
18
|
+
lastChecked: number
|
|
19
|
+
error?: string
|
|
20
|
+
latencyMs: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DiscoveredModel {
|
|
24
|
+
value: string
|
|
25
|
+
displayName: string
|
|
26
|
+
description: string
|
|
27
|
+
supportsEffort?: boolean
|
|
28
|
+
supportedEffortLevels?: string[]
|
|
29
|
+
supportsAdaptiveThinking?: boolean
|
|
30
|
+
supportsFastMode?: boolean
|
|
31
|
+
supportsAutoMode?: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface RuntimeCapabilities {
|
|
35
|
+
models: DiscoveredModel[]
|
|
36
|
+
probedAt: number
|
|
37
|
+
runtimeVersion: string
|
|
38
|
+
error?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface RuntimeRegistryState {
|
|
42
|
+
entries: RuntimeEntry[]
|
|
43
|
+
defaults: Record<string, string>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface RuntimeSnapshot {
|
|
47
|
+
runtimes: (RuntimeEntry & { health: RuntimeHealthStatus })[]
|
|
48
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type SandboxStatus = "creating" | "running" | "stopped" | "error"
|
|
2
|
+
|
|
3
|
+
export interface ResourceLimits {
|
|
4
|
+
cpuShares: number
|
|
5
|
+
memoryMb: number
|
|
6
|
+
diskMb: number
|
|
7
|
+
pidsLimit: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_RESOURCE_LIMITS: ResourceLimits = {
|
|
11
|
+
cpuShares: 512,
|
|
12
|
+
memoryMb: 2048,
|
|
13
|
+
diskMb: 10240,
|
|
14
|
+
pidsLimit: 256,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface SandboxRecord {
|
|
18
|
+
id: string
|
|
19
|
+
workspaceId: string
|
|
20
|
+
containerId: string | null
|
|
21
|
+
status: SandboxStatus
|
|
22
|
+
resourceLimits: ResourceLimits
|
|
23
|
+
natsUrl: string
|
|
24
|
+
createdAt: number
|
|
25
|
+
updatedAt: number
|
|
26
|
+
lastHealthCheck: number | null
|
|
27
|
+
error: string | null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface SandboxHealthReport {
|
|
31
|
+
sandboxId: string
|
|
32
|
+
workspaceId: string
|
|
33
|
+
status: "healthy" | "unhealthy" | "unreachable"
|
|
34
|
+
uptimeMs: number
|
|
35
|
+
memoryUsageMb: number
|
|
36
|
+
cpuPercent: number
|
|
37
|
+
natsConnected: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ContainerInspect {
|
|
41
|
+
id: string
|
|
42
|
+
status: string
|
|
43
|
+
running: boolean
|
|
44
|
+
startedAt: string
|
|
45
|
+
memoryUsage: number
|
|
46
|
+
cpuPercent: number
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface SandboxSnapshot {
|
|
50
|
+
workspaceId: string
|
|
51
|
+
sandbox: SandboxRecord | null
|
|
52
|
+
health: SandboxHealthReport | null
|
|
53
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
|
|
3
|
+
const INDEX_CSS_PATH = new URL("../index.css", import.meta.url)
|
|
4
|
+
|
|
5
|
+
describe("tailwind build entry", () => {
|
|
6
|
+
test('constrains Tailwind source scanning to the app source tree', async () => {
|
|
7
|
+
const css = await Bun.file(INDEX_CSS_PATH).text()
|
|
8
|
+
|
|
9
|
+
expect(css).toContain('@import "tailwindcss" source(".");')
|
|
10
|
+
expect(css).not.toContain('@import "tailwindcss";')
|
|
11
|
+
})
|
|
12
|
+
})
|