@iowarp/clio-coder 0.3.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/NOTICE +33 -0
- package/README.md +7 -2
- package/dist/{acp-7LOELQFP.js → acp-G5WJBNCT.js} +13 -12
- package/dist/{agents-FIBG2SHA.js → agents-FMV2Q5G4.js} +39 -36
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-OI4LIH2I.js → auth-3IDSJEIK.js} +16 -15
- package/dist/{builtins-AD25UL3C.js → builtins-XCZWXSC7.js} +3 -3
- package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
- package/dist/{chunk-56KB5IJP.js → chunk-2OQE55CK.js} +3 -3
- package/dist/{chunk-N3PBVRTZ.js → chunk-32KWKNSF.js} +9 -7
- package/dist/{chunk-VKBMFOYV.js → chunk-36EJLSQQ.js} +23 -27
- package/dist/{chunk-465CC7FK.js → chunk-3BT2XMV4.js} +16 -13
- package/dist/{chunk-NQ6UCCOD.js → chunk-3URVFKWK.js} +7 -7
- package/dist/{chunk-WIE7ZOSW.js → chunk-3XML7CDN.js} +2 -2
- package/dist/chunk-42FMPA75.js +101 -0
- package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
- package/dist/{chunk-HAY4ZE2P.js → chunk-5PSMVOLM.js} +2 -2
- package/dist/{chunk-JEQQR47K.js → chunk-6DB53AJS.js} +168 -9
- package/dist/{chunk-KV2AOLDF.js → chunk-76ONBSIA.js} +5 -25
- package/dist/{chunk-FALJGAWU.js → chunk-7MCTRUCE.js} +2 -2
- package/dist/{chunk-5T7RBWN2.js → chunk-AB44T6BB.js} +5 -5
- package/dist/chunk-B7OBL7PK.js +1405 -0
- package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
- package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
- package/dist/{chunk-O6I4CIEU.js → chunk-BKFJHQCA.js} +6 -6
- package/dist/chunk-BKFM6EJV.js +462 -0
- package/dist/chunk-BMS5RKQY.js +27 -0
- package/dist/{chunk-MV2VUEJC.js → chunk-BPKCPIL7.js} +2 -2
- package/dist/{chunk-TEO2TLVN.js → chunk-BUMFYQFY.js} +964 -1120
- package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
- package/dist/chunk-C2LTL2W6.js +2447 -0
- package/dist/{chunk-EBOC7MT3.js → chunk-CODPRO7Q.js} +8 -8
- package/dist/{chunk-HPCTNZM2.js → chunk-CTJ4RNAA.js} +4 -4
- package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
- package/dist/{chunk-MIX5N5AC.js → chunk-DQITNCXG.js} +394 -154
- package/dist/{chunk-S4COXYBG.js → chunk-DYJP44XW.js} +129 -106
- package/dist/{chunk-N5XKWMDW.js → chunk-F4CKPOEQ.js} +6 -6
- package/dist/{chunk-AMKHQW3C.js → chunk-FEFIFZTL.js} +3 -3
- package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
- package/dist/{chunk-7C6RYZGQ.js → chunk-GKF55TAZ.js} +3 -3
- package/dist/{chunk-B5XRQOLB.js → chunk-GR5G2PVF.js} +9 -8
- package/dist/{chunk-XDOQXGFO.js → chunk-GXNLGKAB.js} +64 -8
- package/dist/chunk-HHV2GANA.js +88 -0
- package/dist/{chunk-774ILSRL.js → chunk-HI63TFOG.js} +4 -3
- package/dist/{chunk-R7LNVMCS.js → chunk-HJJTYUHX.js} +64 -72
- package/dist/{chunk-RKRLDWD3.js → chunk-HLW2MRKE.js} +1 -1
- package/dist/{chunk-CA42X6KT.js → chunk-HWHKMHUA.js} +6 -6
- package/dist/chunk-HZHHCK24.js +1631 -0
- package/dist/{chunk-HJB5IUKP.js → chunk-I5VEOC6I.js} +12 -12
- package/dist/chunk-IBEBSCYA.js +564 -0
- package/dist/chunk-IQ7KR472.js +362 -0
- package/dist/{chunk-4H6ULJ3H.js → chunk-J4W7KFM7.js} +921 -990
- package/dist/{chunk-4LJX2PUC.js → chunk-JDG2WCRO.js} +5 -5
- package/dist/{chunk-NZU6YDNV.js → chunk-K5C3NCBD.js} +4 -4
- package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
- package/dist/{chunk-NNNWO6F2.js → chunk-KFZI4NIL.js} +93 -3
- package/dist/chunk-KMVISBZR.js +132 -0
- package/dist/{chunk-BVDVID7E.js → chunk-LDQ2ZF2M.js} +2 -2
- package/dist/{chunk-OEDBCISO.js → chunk-LQ3DZAMX.js} +2 -2
- package/dist/{chunk-PZ4I4JE2.js → chunk-LY4S7GJC.js} +124 -116
- package/dist/{chunk-3DUR4WUA.js → chunk-MLKNTWH2.js} +19 -19
- package/dist/chunk-NEKRRTYW.js +56 -0
- package/dist/{chunk-5DQRIYDZ.js → chunk-NHCZP4K7.js} +2 -2
- package/dist/chunk-NHLBIGRH.js +1506 -0
- package/dist/chunk-NQQH3YT7.js +302 -0
- package/dist/chunk-NYS75XW5.js +15 -0
- package/dist/{chunk-TD7UE2L5.js → chunk-O4XIVISU.js} +7 -7
- package/dist/{chunk-WXCJ7VME.js → chunk-O6TL7WWY.js} +6 -6
- package/dist/chunk-OQBA45DZ.js +97 -0
- package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
- package/dist/chunk-PMZCIOCJ.js +25 -0
- package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
- package/dist/{chunk-HKO36JWF.js → chunk-QBJA7R7N.js} +31 -3
- package/dist/chunk-QDC3K2U3.js +262 -0
- package/dist/{chunk-5HFBWUMU.js → chunk-QLFS5GO2.js} +4 -4
- package/dist/{chunk-GAYUJ7LE.js → chunk-QLL7ILRG.js} +41 -32
- package/dist/{chunk-LXPJXFM5.js → chunk-QREDIESB.js} +7 -7
- package/dist/chunk-QSNYB6ZV.js +195 -0
- package/dist/chunk-R346GLFC.js +31 -0
- package/dist/{chunk-VPTUJU4P.js → chunk-SJ5ZKQ4S.js} +2 -2
- package/dist/{chunk-QQ7EKM72.js → chunk-SP2RXXYO.js} +6 -54
- package/dist/chunk-SUCTJL45.js +45 -0
- package/dist/{chunk-5QKCQQ3E.js → chunk-SUW5DORT.js} +2 -2
- package/dist/chunk-T56WDKA5.js +183 -0
- package/dist/chunk-TVHHYFHE.js +255 -0
- package/dist/{chunk-IHKBWSXF.js → chunk-TZ3SGWZZ.js} +2 -2
- package/dist/{chunk-ECUO3KDP.js → chunk-U77AMWDL.js} +47 -7
- package/dist/{chunk-3UUY7R3Z.js → chunk-ULC6OTWO.js} +7 -7
- package/dist/{chunk-AEYBF3TB.js → chunk-UM7N4G5A.js} +2 -2
- package/dist/{chunk-3V5AYSEQ.js → chunk-UXMFQ54G.js} +43 -36
- package/dist/{chunk-YW7UVM5V.js → chunk-V5DHCITQ.js} +34 -1
- package/dist/{chunk-47CMYGET.js → chunk-VAZSBTKF.js} +2 -2
- package/dist/{chunk-3MRC2YSQ.js → chunk-VEO4AP2K.js} +2 -2
- package/dist/{chunk-PNY46YEY.js → chunk-VFA6GDY5.js} +47 -3
- package/dist/chunk-VO67MWHC.js +75 -0
- package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
- package/dist/{chunk-AD7Y7STJ.js → chunk-VYMXRQI6.js} +36 -22
- package/dist/{chunk-T3Z6VAAF.js → chunk-W5VSYASO.js} +19 -17
- package/dist/{chunk-5PVQ4SRS.js → chunk-WZR7K7ZX.js} +7 -123
- package/dist/{chunk-DG4M6ZUE.js → chunk-X3YGUTOB.js} +4 -4
- package/dist/chunk-X75E3D2N.js +686 -0
- package/dist/{chunk-P3JGPQFL.js → chunk-YDFRH54B.js} +4 -4
- package/dist/chunk-YJX4SHTD.js +40 -0
- package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
- package/dist/{chunk-YSEHGPCT.js → chunk-Z2RR6MAK.js} +3 -3
- package/dist/{chunk-HCBCAYZU.js → chunk-Z4TXYIEG.js} +5 -5
- package/dist/cli/index.js +47 -36
- package/dist/{clio-LT5V7SSZ.js → clio-2JXHBBY5.js} +7 -7
- package/dist/{code-nav-LMW275PA.js → code-nav-3YYRMYNF.js} +6 -6
- package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
- package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
- package/dist/{config-RXS5T3JT.js → config-QZPCMYSO.js} +58 -50
- package/dist/{configure-2WYWSCSD.js → configure-TEGEBYCA.js} +21 -19
- package/dist/{context-I3BTOTCS.js → context-AV7OEZ4D.js} +11 -11
- package/dist/{context-MVOORGMF.js → context-E6H5RNMC.js} +49 -41
- package/dist/{context-PALKKQYL.js → context-GSXUE4CT.js} +25 -23
- package/dist/{context-clear-N2WOYZ2K.js → context-clear-SHIBYK6T.js} +48 -40
- package/dist/{context-working-set-MIEVECVZ.js → context-working-set-5ZGKPGZQ.js} +11 -10
- package/dist/{dispatch-runner-VVA4SRRH.js → dispatch-runner-EFMJT4LD.js} +88 -60
- package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
- package/dist/doctor-QOA5FNY5.js +313 -0
- package/dist/{eval-IJ5VEZDJ.js → eval-TFBYQH4H.js} +66 -64
- package/dist/eval-inventory-SXH7PDKX.js +316 -0
- package/dist/{evidence-L5APPXNV.js → evidence-ERGESKGN.js} +198 -44
- package/dist/{evolve-RGNKFJ52.js → evolve-VDXTSYCJ.js} +46 -38
- package/dist/{extensions-7WYWUX5A.js → extensions-7BGBHN57.js} +6 -6
- package/dist/{fleet-6CNVBZZP.js → fleet-2RRVDF2V.js} +189 -101
- package/dist/{fleet-commands-L2SXSYEI.js → fleet-commands-VJ726XIA.js} +10 -10
- package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
- package/dist/{fleet-graph-2J3OOIPO.js → fleet-graph-JF5QOATM.js} +16 -15
- package/dist/fleet-inspect-VLY4S7QM.js +442 -0
- package/dist/{fleet-preflight-CZRJ4JP5.js → fleet-preflight-AIZUEJOY.js} +6 -5
- package/dist/{fleet-validate-C5RI6DP7.js → fleet-validate-AJRPDMDV.js} +20 -18
- package/dist/fleet-verify-JFEL2L3H.js +175 -0
- package/dist/fleet-view-ZCON35AG.js +102 -0
- package/dist/{init-VBN2ACVA.js → init-DN2WWLFE.js} +64 -56
- package/dist/install-XGLBQY5E.js +13 -0
- package/dist/interop-OZBKXAYL.js +114 -0
- package/dist/{library-JHGUMLY2.js → library-YWZG7IMW.js} +19 -18
- package/dist/{memory-K4OQIYWG.js → memory-I4C4HMLW.js} +48 -40
- package/dist/{models-2NCZUWDD.js → models-CEYXJBO6.js} +30 -28
- package/dist/{monitor-MMVTJABD.js → monitor-NZ6GCI3P.js} +53 -47
- package/dist/{orchestrator-ZKBPCHW6.js → orchestrator-GCGQ4N5I.js} +6311 -7145
- package/dist/panes-HMABYVO4.js +58 -0
- package/dist/panes-KY6W3V2E.js +103 -0
- package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
- package/dist/{reset-DD5JGOY3.js → reset-DQ6FGCSH.js} +13 -11
- package/dist/resources-BB3MVJMD.js +111 -0
- package/dist/{run-QEGNX7FL.js → run-H2GQDUER.js} +113 -82
- package/dist/{share-JKD3BQMW.js → share-GTJN6A5O.js} +18 -17
- package/dist/{skills-LMQIKDOZ.js → skills-L55TEW6R.js} +31 -24
- package/dist/{skills-eval-I7X2774U.js → skills-eval-XVXPH2JI.js} +61 -52
- package/dist/skills-inventory-S4MXPJFV.js +126 -0
- package/dist/slash-commands-ZSGASKJC.js +77 -0
- package/dist/{steer-CF5TDANS.js → steer-RZGSCY4R.js} +3 -3
- package/dist/{support-I7LOJLIF.js → support-PKEUNNQL.js} +4 -4
- package/dist/{targets-RUSR6B5Z.js → targets-NCPZ644J.js} +31 -29
- package/dist/{terminal-lease-QYVORFR4.js → terminal-lease-44SV3YCN.js} +4 -4
- package/dist/tools-DAF3DI3C.js +27 -0
- package/dist/{trace-ODOQIVIW.js → trace-FYVW2MQA.js} +149 -7
- package/dist/tui-primitives-2AKXQNZK.js +13 -0
- package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
- package/dist/{upgrade-XANW3FXB.js → upgrade-3XPP6OQL.js} +26 -24
- package/dist/{usage-4H7ZRXQT.js → usage-3NLHGTU2.js} +57 -49
- package/dist/{verifiers-UZXNBZEB.js → verifiers-SSQONKRT.js} +171 -12
- package/dist/{verify-BVKWTNDL.js → verify-3U6J7FZI.js} +9 -9
- package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
- package/dist/{wiki-generate-MY7WV2QI.js → wiki-generate-CEHYGPGQ.js} +67 -59
- package/dist/with-panes-MKB46MPQ.js +782 -0
- package/dist/worker/entry.js +101 -66
- package/docs/README.md +3 -2
- package/docs/acp.md +24 -3
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +4 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +43 -5
- package/docs/commands-and-modes.md +31 -2
- package/docs/configuration-and-targets.md +40 -10
- package/docs/context-engine.md +1 -1
- package/docs/development-pipeline.md +19 -0
- package/docs/dispatch-typed-intent.md +385 -0
- package/docs/documentation-coverage.md +2 -2
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +1 -0
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +2 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +25 -1
- package/docs/fleet-dispatch.md +22 -1
- package/docs/installation-and-lifecycle.md +15 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +10 -1
- package/docs/observability.md +3 -3
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +1 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +18 -8
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +4 -2
- package/src/cli/acp.ts +6 -2
- package/src/cli/argv.ts +25 -0
- package/src/cli/configure.ts +23 -21
- package/src/cli/doctor-panes.ts +124 -0
- package/src/cli/doctor-toolchain.ts +57 -0
- package/src/cli/doctor.ts +20 -1
- package/src/cli/eval-inventory.ts +436 -0
- package/src/cli/eval.ts +13 -0
- package/src/cli/evidence-detail.ts +88 -0
- package/src/cli/evidence-inventory.ts +183 -0
- package/src/cli/evidence.ts +30 -5
- package/src/cli/fleet-decisions.ts +69 -0
- package/src/cli/fleet-inspect.ts +334 -0
- package/src/cli/fleet-verify.ts +133 -0
- package/src/cli/fleet-view.ts +810 -0
- package/src/cli/fleet.ts +148 -37
- package/src/cli/index.ts +14 -2
- package/src/cli/interop-inspect.ts +128 -0
- package/src/cli/interop.ts +34 -0
- package/src/cli/panes.ts +35 -0
- package/src/cli/reset.ts +5 -2
- package/src/cli/run.ts +58 -0
- package/src/cli/skills-inventory.ts +185 -0
- package/src/cli/skills.ts +16 -13
- package/src/cli/tools.ts +321 -0
- package/src/cli/trace-inspect.ts +252 -0
- package/src/cli/trace.ts +23 -2
- package/src/cli/verifiers-inspect.ts +347 -0
- package/src/cli/verifiers.ts +9 -0
- package/src/core/bus-events.ts +4 -0
- package/src/core/config.ts +49 -0
- package/src/core/defaults.ts +93 -7
- package/src/core/response-schema.ts +44 -4
- package/src/core/theme-token-hex.ts +43 -0
- package/src/core/tool-names.ts +2 -1
- package/src/core/xdg.ts +1 -1
- package/src/domains/agents/fleets/build-review.md +0 -3
- package/src/domains/agents/fleets/build-test.md +0 -3
- package/src/domains/agents/result-contract-filesystem.ts +32 -0
- package/src/domains/agents/result-contract.ts +164 -35
- package/src/domains/config/classify.ts +3 -0
- package/src/domains/dispatch/admission-error.ts +9 -0
- package/src/domains/dispatch/admission.ts +22 -21
- package/src/domains/dispatch/capacity-lease.ts +21 -1
- package/src/domains/dispatch/council-topology.ts +398 -0
- package/src/domains/dispatch/extension.ts +222 -50
- package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
- package/src/domains/dispatch/fleet-plan.ts +7 -2
- package/src/domains/dispatch/fleet-run.ts +64 -1
- package/src/domains/dispatch/gate-decisions.ts +11 -1
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/gate-topology.ts +289 -0
- package/src/domains/dispatch/index.ts +19 -0
- package/src/domains/dispatch/intent-compatibility.ts +330 -0
- package/src/domains/dispatch/intent.ts +85 -1
- package/src/domains/dispatch/reservation-store.ts +24 -4
- package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
- package/src/domains/dispatch/run-event-journal.ts +598 -0
- package/src/domains/dispatch/state.ts +45 -1
- package/src/domains/dispatch/types.ts +13 -0
- package/src/domains/dispatch/validation.ts +33 -8
- package/src/domains/eval/compare/compare.ts +3 -16
- package/src/domains/eval/inventory.ts +113 -0
- package/src/domains/eval/schema/serving.ts +31 -0
- package/src/domains/evidence/store.ts +6 -0
- package/src/domains/memory/index.ts +0 -1
- package/src/domains/memory/task-memory-policy.ts +6 -10
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +33 -21
- package/src/domains/mux/contract.ts +434 -0
- package/src/domains/mux/detect.ts +158 -0
- package/src/domains/mux/extension.ts +47 -0
- package/src/domains/mux/index.ts +96 -0
- package/src/domains/mux/manifest.ts +6 -0
- package/src/domains/mux/operations.ts +164 -0
- package/src/domains/mux/pane-registry.ts +90 -0
- package/src/domains/mux/protocol.ts +49 -0
- package/src/domains/mux/socket-client.ts +816 -0
- package/src/domains/mux/types.ts +222 -0
- package/src/domains/mux/viewer-command.ts +59 -0
- package/src/domains/mux/yazi/assets/init.lua +2 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
- package/src/domains/mux/yazi/assets/yazi.toml +17 -0
- package/src/domains/mux/yazi/event-stream.ts +180 -0
- package/src/domains/mux/yazi/profile.ts +299 -0
- package/src/domains/mux/yazi/session.ts +228 -0
- package/src/domains/mux/yazi/theme.ts +30 -0
- package/src/domains/observability/cost.ts +21 -0
- package/src/domains/observability/index.ts +2 -0
- package/src/domains/observability/trace-store.ts +42 -0
- package/src/domains/providers/endpoint-capacity.ts +154 -22
- package/src/domains/providers/endpoint-slots-store.ts +189 -0
- package/src/domains/providers/extension.ts +20 -3
- package/src/domains/providers/index.ts +22 -0
- package/src/domains/providers/model-runtime-capabilities.ts +32 -0
- package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -0
- package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
- package/src/domains/providers/support.ts +1 -0
- package/src/domains/providers/target-model-cache.ts +124 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/skills/loader.ts +33 -0
- package/src/domains/safety/action-classifier.ts +6 -0
- package/src/domains/toolchain/archive.ts +175 -0
- package/src/domains/toolchain/contract.ts +28 -0
- package/src/domains/toolchain/extension.ts +47 -0
- package/src/domains/toolchain/index.ts +39 -0
- package/src/domains/toolchain/install.ts +327 -0
- package/src/domains/toolchain/manifest.ts +8 -0
- package/src/domains/toolchain/paths.ts +34 -0
- package/src/domains/toolchain/registry.ts +265 -0
- package/src/domains/toolchain/remove.ts +218 -0
- package/src/domains/toolchain/resolve.ts +182 -0
- package/src/domains/toolchain/types.ts +113 -0
- package/src/domains/toolchain/version.ts +88 -0
- package/src/engine/acp/server.ts +413 -70
- package/src/engine/acp/types.ts +19 -1
- package/src/engine/claude/sdk-module.ts +98 -0
- package/src/engine/claude/sdk-runtime.ts +19 -11
- package/src/engine/tui-primitives.ts +21 -0
- package/src/engine/tui.ts +1 -0
- package/src/engine/worker-runtime.ts +2 -13
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +103 -5
- package/src/entry/panes-activation.ts +31 -0
- package/src/entry/with-panes.ts +20 -0
- package/src/interactive/context-overlay.ts +1 -0
- package/src/interactive/cost-overlay.ts +2 -0
- package/src/interactive/council-grid.ts +1 -3
- package/src/interactive/council.ts +11 -0
- package/src/interactive/dispatch-board.ts +26 -16
- package/src/interactive/interactive-application.ts +153 -6
- package/src/interactive/interactive-input-runtime.ts +7 -0
- package/src/interactive/interactive-slash-runtime.ts +36 -6
- package/src/interactive/memory-overlay.ts +1 -0
- package/src/interactive/modal-marker.ts +170 -0
- package/src/interactive/mux-bridge.ts +214 -0
- package/src/interactive/overlay-frame.ts +58 -2
- package/src/interactive/overlay-general-openers.ts +1 -0
- package/src/interactive/overlay-key-routing.ts +14 -3
- package/src/interactive/overlay-lifecycle.ts +19 -3
- package/src/interactive/overlay-model-selectors.ts +40 -3
- package/src/interactive/overlay-permission-lifecycle.ts +90 -22
- package/src/interactive/overlay-transitions.ts +18 -4
- package/src/interactive/overlays/agents.ts +1 -0
- package/src/interactive/overlays/ask-user.ts +136 -30
- package/src/interactive/overlays/auth-dialog.ts +1 -0
- package/src/interactive/overlays/context-reset.ts +1 -0
- package/src/interactive/overlays/cwd-fallback.ts +1 -0
- package/src/interactive/overlays/decisions.ts +11 -11
- package/src/interactive/overlays/extensions.ts +1 -0
- package/src/interactive/overlays/fleet-run-approval.ts +1 -0
- package/src/interactive/overlays/handoff-review.ts +1 -0
- package/src/interactive/overlays/help-reference.ts +2 -0
- package/src/interactive/overlays/interop.ts +1 -0
- package/src/interactive/overlays/library-install-confirm.ts +1 -0
- package/src/interactive/overlays/library-tabs.ts +28 -0
- package/src/interactive/overlays/list-overlay.ts +10 -1
- package/src/interactive/overlays/message-picker.ts +1 -0
- package/src/interactive/overlays/model-scope.ts +86 -0
- package/src/interactive/overlays/model-selector.ts +1 -0
- package/src/interactive/overlays/prompts.ts +1 -0
- package/src/interactive/overlays/session-selector.ts +1 -0
- package/src/interactive/overlays/settings-sections.ts +30 -0
- package/src/interactive/overlays/settings.ts +579 -44
- package/src/interactive/overlays/side-question.ts +1 -0
- package/src/interactive/overlays/skills-hub.ts +3 -11
- package/src/interactive/overlays/tree-selector.ts +1 -0
- package/src/interactive/pane-policy.ts +46 -0
- package/src/interactive/panes-runtime.ts +292 -0
- package/src/interactive/renderers/compaction-summary.ts +29 -0
- package/src/interactive/renderers/worker-entry.ts +122 -14
- package/src/interactive/slash-commands.ts +251 -15
- package/src/interactive/tasks-overlay.ts +1 -0
- package/src/interactive/theme/tokens.ts +3 -14
- package/src/interactive/turn-context.ts +47 -2
- package/src/interactive/view/artifacts.ts +109 -1
- package/src/interactive/view/view-overlay.ts +1 -0
- package/src/interactive/watch-pane.ts +152 -0
- package/src/interactive/worker-progress.ts +7 -1
- package/src/interactive/worker-receipts.ts +19 -1
- package/src/interactive/worker-stream.ts +5 -0
- package/src/interactive/yazi-bridge.ts +444 -0
- package/src/tools/bootstrap.ts +26 -2
- package/src/tools/builtin-tool-catalog.ts +15 -0
- package/src/tools/compete-worktrees.ts +83 -2
- package/src/tools/core-bootstrap.ts +2 -1
- package/src/tools/dispatch-admission.ts +14 -3
- package/src/tools/dispatch-arguments.ts +20 -20
- package/src/tools/dispatch-run-events.ts +134 -19
- package/src/tools/dispatch-runner.ts +29 -7
- package/src/tools/dispatch-types.ts +15 -3
- package/src/tools/dispatch.ts +1 -1
- package/src/tools/executables.ts +17 -14
- package/src/tools/observation.ts +54 -4
- package/src/tools/panes-surface.ts +38 -0
- package/src/tools/panes.ts +112 -0
- package/src/tools/policy.ts +10 -1
- package/src/tools/presentation.ts +1 -0
- package/dist/chunk-D73KXYPF.js +0 -37
- package/dist/chunk-MLOK6ZOS.js +0 -2888
- package/dist/chunk-YKOFT37S.js +0 -279
- package/dist/doctor-TWBWFK5V.js +0 -165
|
@@ -21,6 +21,8 @@ import type { FleetCommandRegistry } from "../agents/fleet-commands.js";
|
|
|
21
21
|
import type { FleetContract } from "../agents/fleet-contract.js";
|
|
22
22
|
import { resultContractAuthorship } from "../agents/result-contract.js";
|
|
23
23
|
import type { AgentSpec } from "../agents/spec.js";
|
|
24
|
+
import { aggregateCostAmounts, type CostAggregate, renderCostAmount } from "../observability/cost.js";
|
|
25
|
+
import type { CostProvenance } from "../providers/index.js";
|
|
24
26
|
import { claimAssignmentVerdict, recordAssignmentAttempt, settleStoredAssignment } from "./assignment-store.js";
|
|
25
27
|
import { runCodeStep } from "./code-step.js";
|
|
26
28
|
import { codeStepDir, writeCodeStepRecord } from "./code-step-store.js";
|
|
@@ -43,6 +45,7 @@ import {
|
|
|
43
45
|
materializePendingGateDecision,
|
|
44
46
|
stagePendingGateDecision,
|
|
45
47
|
} from "./gate-decisions.js";
|
|
48
|
+
import { type DispatchIntent, declaredScopeIntent } from "./intent.js";
|
|
46
49
|
import { verifyReceiptIntegrity } from "./receipt-integrity.js";
|
|
47
50
|
import { type FleetRunRecord, writeFleetRun } from "./state.js";
|
|
48
51
|
import type { RunReceipt } from "./types.js";
|
|
@@ -83,6 +86,15 @@ export interface FleetRunStepOutcome extends FleetRunStepEvent {
|
|
|
83
86
|
/** Terminal run id, which is the receipt id for an agent step. */
|
|
84
87
|
terminalRunId: string;
|
|
85
88
|
costUsd: number;
|
|
89
|
+
/**
|
|
90
|
+
* Where the number in `costUsd` came from, carried beside it because the two
|
|
91
|
+
* are one fact. A gateway-routed run seals `costUsd: 0` with `unknown`: its
|
|
92
|
+
* tokens were measured and nobody priced them. A renderer that reads the
|
|
93
|
+
* amount without this prints `$0.0000` and turns unpriced work into a
|
|
94
|
+
* measured zero. `known_free` on a deterministic step is the honest reading:
|
|
95
|
+
* no model ran, so the zero is something code observed rather than missed.
|
|
96
|
+
*/
|
|
97
|
+
costProvenance: CostProvenance;
|
|
86
98
|
/** The sealed agent receipt when this was an agent step. */
|
|
87
99
|
receipt?: RunReceipt;
|
|
88
100
|
/** The durable code-step record when this was a deterministic step. */
|
|
@@ -192,7 +204,18 @@ export interface FleetRunOutcome {
|
|
|
192
204
|
planHash: string;
|
|
193
205
|
result: ExecutionPlanResult;
|
|
194
206
|
receipts: ReadonlyArray<RunReceipt>;
|
|
207
|
+
/**
|
|
208
|
+
* The bare sum of every receipt's `costUsd`, which adds unpriced zeros to
|
|
209
|
+
* priced dollars and so cannot be rendered on its own. Retained for the
|
|
210
|
+
* interactive fleet overlay, which still reads it. Render `totalCost`.
|
|
211
|
+
*/
|
|
195
212
|
totalCostUsd: number;
|
|
213
|
+
/**
|
|
214
|
+
* The fold that keeps unpriced calls distinguishable from priced ones, so a
|
|
215
|
+
* run whose every receipt came back `unknown` renders as not measured rather
|
|
216
|
+
* than as a total of zero dollars.
|
|
217
|
+
*/
|
|
218
|
+
totalCost: CostAggregate;
|
|
196
219
|
/** Steps that ran unconditionally, excluding nodes a resolved loop skipped. */
|
|
197
220
|
requiredStepCount: number;
|
|
198
221
|
succeededStepCount: number;
|
|
@@ -217,6 +240,24 @@ function fleetGateCorrelation(subject: RunReceipt, decider: RunReceipt): GateDec
|
|
|
217
240
|
return { agent, target, modelFamily, runtime, node, independent };
|
|
218
241
|
}
|
|
219
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Typed scope for one fleet step, drawn from the boundary its contract already
|
|
245
|
+
* declared. Returns null when the contract declared nothing for this position,
|
|
246
|
+
* which is every step of a pre-v4 contract and every readonly step: those keep
|
|
247
|
+
* the legacy inference path rather than being handed an empty declaration that
|
|
248
|
+
* would silently switch off path-scoped rule selection for them.
|
|
249
|
+
*
|
|
250
|
+
* A contract whose declared paths do not survive the boundary grammar is a
|
|
251
|
+
* compile-time authoring bug, not a dispatch-time one, so a malformed entry
|
|
252
|
+
* falls back to inference here rather than aborting a run mid-wave; the
|
|
253
|
+
* contract loader is the surface that refuses it.
|
|
254
|
+
*/
|
|
255
|
+
function fleetStepIntent(writes: ReadonlyArray<string> | undefined): DispatchIntent | null {
|
|
256
|
+
if (writes === undefined || writes.length === 0) return null;
|
|
257
|
+
const built = declaredScopeIntent({ relevantPaths: writes });
|
|
258
|
+
return built.ok ? built.intent : null;
|
|
259
|
+
}
|
|
260
|
+
|
|
220
261
|
export function fleetPlanWaveIndex(plan: ExecutionPlan, stepId: string): number {
|
|
221
262
|
return plan.waves.findIndex((wave) => wave.includes(stepId));
|
|
222
263
|
}
|
|
@@ -338,6 +379,9 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
|
|
|
338
379
|
succeeded: true,
|
|
339
380
|
terminalRunId: replayedResult.terminalRunId,
|
|
340
381
|
costUsd: receiptsByStep.get(stepId)?.costUsd ?? 0,
|
|
382
|
+
// A replay whose receipt no longer exists on disk has no cost claim at
|
|
383
|
+
// all, which is `unknown` rather than a zero the projection invented.
|
|
384
|
+
costProvenance: receiptsByStep.get(stepId)?.costProvenance ?? "unknown",
|
|
341
385
|
result: replayedResult,
|
|
342
386
|
});
|
|
343
387
|
await fileStepAttempt(replayedResult.terminalRunId);
|
|
@@ -434,11 +478,24 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
|
|
|
434
478
|
// The fleet write boundary is deliberately enforced after the step. The enforcer in
|
|
435
479
|
// write-boundary-enforcer.ts snapshots and verifies the step window. Pre-emptive
|
|
436
480
|
// confinement for declared commands would require a command sandbox, which does not exist.
|
|
481
|
+
//
|
|
482
|
+
// That enforcement split is exactly why a step's declared `writes:` reaches
|
|
483
|
+
// typed intent as `relevant_paths` rather than as `write_roots`. The
|
|
484
|
+
// contract already said what this position may change and the enforcer
|
|
485
|
+
// already holds it; restating it as intent write roots would mint a second
|
|
486
|
+
// grant enforced at the per-tool worker seam, which refuses outright on the
|
|
487
|
+
// subprocess and ACP runtimes a fleet may legitimately route a step to.
|
|
488
|
+
// Carrying it as declared scope changes no authority and gets the
|
|
489
|
+
// contract's own paths into project-rule selection and worker context,
|
|
490
|
+
// where prose tokens scraped from the rendered prompt were standing in for
|
|
491
|
+
// a declaration the contract had already made.
|
|
492
|
+
const stepIntent = fleetStepIntent(step.writes);
|
|
437
493
|
const request: DispatchRequest = {
|
|
438
494
|
agentId: step.agentId,
|
|
439
495
|
executionRole: step.executionRole,
|
|
440
496
|
task: step.task,
|
|
441
497
|
cwd: workspaceRoot,
|
|
498
|
+
...(stepIntent === null ? {} : { intent: stepIntent }),
|
|
442
499
|
predecessorHandoffs: handoffs,
|
|
443
500
|
requestOrigin: "user",
|
|
444
501
|
lineage: {
|
|
@@ -591,11 +648,12 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
|
|
|
591
648
|
succeeded: stepSucceeded,
|
|
592
649
|
terminalRunId: receipt.runId,
|
|
593
650
|
costUsd: receipt.costUsd,
|
|
651
|
+
costProvenance: receipt.costProvenance,
|
|
594
652
|
receipt,
|
|
595
653
|
...(failureReason !== undefined ? { failureReason } : {}),
|
|
596
654
|
});
|
|
597
655
|
notice(
|
|
598
|
-
`step ${step.id} ${step.agentId}: ${stepSucceeded ? "succeeded" : "failed"}${failureReason !== undefined ? ` reason=${failureReason}` : ""} assignment=${handle.runId} terminal-run=${receipt.runId} cost
|
|
656
|
+
`step ${step.id} ${step.agentId}: ${stepSucceeded ? "succeeded" : "failed"}${failureReason !== undefined ? ` reason=${failureReason}` : ""} assignment=${handle.runId} terminal-run=${receipt.runId} cost=${renderCostAmount(receipt.costUsd, receipt.costProvenance)}`,
|
|
599
657
|
);
|
|
600
658
|
return {
|
|
601
659
|
stepId: step.id,
|
|
@@ -658,6 +716,8 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
|
|
|
658
716
|
succeeded: outcome.report.passed,
|
|
659
717
|
terminalRunId: outcome.record.runId,
|
|
660
718
|
costUsd: 0,
|
|
719
|
+
// No model ran, so nothing needed pricing. This zero was observed.
|
|
720
|
+
costProvenance: "known_free",
|
|
661
721
|
codeStep: outcome.record,
|
|
662
722
|
recordPath,
|
|
663
723
|
});
|
|
@@ -803,6 +863,9 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
|
|
|
803
863
|
result,
|
|
804
864
|
receipts,
|
|
805
865
|
totalCostUsd: receipts.reduce((sum, receipt) => sum + receipt.costUsd, 0),
|
|
866
|
+
totalCost: aggregateCostAmounts(
|
|
867
|
+
receipts.map((receipt) => ({ usd: receipt.costUsd, provenance: receipt.costProvenance })),
|
|
868
|
+
),
|
|
806
869
|
requiredStepCount: required.length,
|
|
807
870
|
succeededStepCount,
|
|
808
871
|
resolvedLoopCount: result.loops.length - failedLoops.length,
|
|
@@ -298,10 +298,20 @@ export interface StagePendingGateDecisionOptions {
|
|
|
298
298
|
stateDir?: string;
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
|
|
301
|
+
/**
|
|
302
|
+
* Where the durable decision artifacts live.
|
|
303
|
+
*
|
|
304
|
+
* Exported so a read-only projection can bound its own scan without duplicating
|
|
305
|
+
* the layout. Nothing outside this module may compose an artifact path from it.
|
|
306
|
+
*/
|
|
307
|
+
export function gateDecisionsDirectory(stateDir = clioStateDir()): string {
|
|
302
308
|
return join(stateDir, "gate-decisions");
|
|
303
309
|
}
|
|
304
310
|
|
|
311
|
+
function decisionsDirectory(stateDir = clioStateDir()): string {
|
|
312
|
+
return gateDecisionsDirectory(stateDir);
|
|
313
|
+
}
|
|
314
|
+
|
|
305
315
|
function pendingDecisionsDirectory(stateDir = clioStateDir()): string {
|
|
306
316
|
return join(decisionsDirectory(stateDir), "pending");
|
|
307
317
|
}
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
import { COUNCIL_BALLOT_SHAPE, COUNCIL_BALLOT_VERDICT_MAX_BYTES } from "../agents/result-contract.js";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Roster bounds for a council. Two is the point of the topology: one seated
|
|
7
|
+
* agent is a plain dispatch, and there is nothing to compare. Capacity denials
|
|
8
|
+
* quote the floor because it is the reason a council cannot answer saturation
|
|
9
|
+
* by dispatching fewer members.
|
|
10
|
+
*/
|
|
11
|
+
export const COUNCIL_MIN_MEMBERS = 2;
|
|
12
|
+
export const COUNCIL_MAX_MEMBERS = 5;
|
|
13
|
+
|
|
5
14
|
export const REVIEWER_GATE_PROMPT = [
|
|
6
15
|
"You are a strict, read-only reviewer of one implementation run.",
|
|
7
16
|
"Inspect the supplied result and repository state with read-only tools.",
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only projection of the durable coordinator gate decisions.
|
|
3
|
+
*
|
|
4
|
+
* Unlike a council, a gate has a record of its own. A reviewer verdict and a
|
|
5
|
+
* judge's winner cannot be written back into the subject receipts without
|
|
6
|
+
* invalidating them, so the coordinator seals a separate integrity-covered
|
|
7
|
+
* artifact per decision that links the decider receipt to every subject
|
|
8
|
+
* receipt. {@link gate-decisions.ts} owns writing and verifying those; this
|
|
9
|
+
* module reads a bounded newest-first window of them and projects the shape.
|
|
10
|
+
*
|
|
11
|
+
* Two things stay behind. The decision `detail` is free prose that interpolates
|
|
12
|
+
* a thrown message, a pipeline failure reason, a protected artifact list, or a
|
|
13
|
+
* plan hash, so it is classified against a closed set and never quoted. And the
|
|
14
|
+
* receipt digests are omitted outright: a verified artifact carries one per
|
|
15
|
+
* subject by construction, so repeating them would be a fingerprint that tells
|
|
16
|
+
* a reader nothing the run id does not.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { clioStateDir } from "../../core/xdg.js";
|
|
22
|
+
import type { GateRouteCorrelation } from "./execution-role.js";
|
|
23
|
+
import {
|
|
24
|
+
type GateDecisionArtifact,
|
|
25
|
+
type GateDecisionOutcome,
|
|
26
|
+
gateDecisionsDirectory,
|
|
27
|
+
verifyGateDecisionArtifact,
|
|
28
|
+
} from "./gate-decisions.js";
|
|
29
|
+
|
|
30
|
+
/** How many decisions one projection reports, newest first. */
|
|
31
|
+
export const GATE_TOPOLOGY_MAX_DECISIONS = 8;
|
|
32
|
+
|
|
33
|
+
/** Subject receipts named per decision. A compete gate judges at most four. */
|
|
34
|
+
export const GATE_TOPOLOGY_MAX_SUBJECTS = 6;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* How many artifact files one listing will open.
|
|
38
|
+
*
|
|
39
|
+
* The directory is unbounded and a decision id sorts by its group before its
|
|
40
|
+
* timestamp, so the newest decision is only discoverable by reading each file's
|
|
41
|
+
* `createdAt`. The cap keeps the scan proportional on an installation that has
|
|
42
|
+
* accumulated gates for months, at the cost of missing a decision older than
|
|
43
|
+
* the cap. That is the right trade here, the same one {@link listFleetRuns}
|
|
44
|
+
* takes, because this window only ever wants the recent end.
|
|
45
|
+
*/
|
|
46
|
+
export const GATE_TOPOLOGY_MAX_SCAN = 128;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Why a gate ended the way it did, as a closed set.
|
|
50
|
+
*
|
|
51
|
+
* Every member is the coordinator's own classification of its own branch. The
|
|
52
|
+
* durable `detail` string those branches write is not repeated: several
|
|
53
|
+
* interpolate a receipt's failure reason, the names of protected artifacts a
|
|
54
|
+
* candidate touched, or an approval request id, and any of the three would
|
|
55
|
+
* carry prose across a boundary that exists to stop exactly that. Anything this
|
|
56
|
+
* classifier does not recognise becomes `unclassified` rather than crossing.
|
|
57
|
+
*/
|
|
58
|
+
export type GateDecisionReason =
|
|
59
|
+
| "all-candidates-failed"
|
|
60
|
+
| "builder-run-failed"
|
|
61
|
+
| "reviewer-run-failed"
|
|
62
|
+
| "reviewer-checks-failed"
|
|
63
|
+
| "reviewer-report-invalid"
|
|
64
|
+
| "judge-run-failed"
|
|
65
|
+
| "judge-result-invalid"
|
|
66
|
+
| "judge-winner-out-of-range"
|
|
67
|
+
| "judge-picked-failed-candidate"
|
|
68
|
+
| "winner-touches-protected-artifact"
|
|
69
|
+
| "operator-confirmed-winner"
|
|
70
|
+
| "full-auto-applied-winner"
|
|
71
|
+
| "unclassified";
|
|
72
|
+
|
|
73
|
+
export const GATE_DECISION_REASONS: ReadonlyArray<GateDecisionReason> = [
|
|
74
|
+
"all-candidates-failed",
|
|
75
|
+
"builder-run-failed",
|
|
76
|
+
"reviewer-run-failed",
|
|
77
|
+
"reviewer-checks-failed",
|
|
78
|
+
"reviewer-report-invalid",
|
|
79
|
+
"judge-run-failed",
|
|
80
|
+
"judge-result-invalid",
|
|
81
|
+
"judge-winner-out-of-range",
|
|
82
|
+
"judge-picked-failed-candidate",
|
|
83
|
+
"winner-touches-protected-artifact",
|
|
84
|
+
"operator-confirmed-winner",
|
|
85
|
+
"full-auto-applied-winner",
|
|
86
|
+
"unclassified",
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Prefix rules, first match wins, ordered so no rule shadows another.
|
|
91
|
+
*
|
|
92
|
+
* These are matched against the exact strings the coordinator writes. A rule
|
|
93
|
+
* failing to match costs its decision the specific reason and nothing else,
|
|
94
|
+
* because `unclassified` is a real answer here: the operator still learns that
|
|
95
|
+
* the gate ended and how, just not which branch produced the text.
|
|
96
|
+
*/
|
|
97
|
+
const REASON_RULES: ReadonlyArray<readonly [string, GateDecisionReason]> = [
|
|
98
|
+
["every candidate builder failed", "all-candidates-failed"],
|
|
99
|
+
["builder ended ", "builder-run-failed"],
|
|
100
|
+
["reviewer ended ", "reviewer-run-failed"],
|
|
101
|
+
["reviewer reported ", "reviewer-checks-failed"],
|
|
102
|
+
["reviewer did not return a valid verifier report", "reviewer-report-invalid"],
|
|
103
|
+
["judge ended ", "judge-run-failed"],
|
|
104
|
+
["judge result must", "judge-result-invalid"],
|
|
105
|
+
["judge result has unknown fields", "judge-result-invalid"],
|
|
106
|
+
["judge winner must be an integer", "judge-winner-out-of-range"],
|
|
107
|
+
["judge picked failed or missing candidate", "judge-picked-failed-candidate"],
|
|
108
|
+
["judge-selected candidate ", "winner-touches-protected-artifact"],
|
|
109
|
+
["operator confirmation ", "operator-confirmed-winner"],
|
|
110
|
+
["full-auto applied ", "full-auto-applied-winner"],
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The identifier shape the decision store already guarantees for both its ids
|
|
115
|
+
* and, transitively, its groups.
|
|
116
|
+
*
|
|
117
|
+
* A decision id is minted from a sanitized group plus a timestamp and random
|
|
118
|
+
* suffix, and a group is a coordinator-minted gate id. Re-enforcing the shape
|
|
119
|
+
* here means whatever wrote the file, the identifiers this projection reports
|
|
120
|
+
* can carry no separator, space, quote, or control byte.
|
|
121
|
+
*/
|
|
122
|
+
const SAFE_GATE_IDENTIFIER = /^[A-Za-z0-9._:-]{1,128}$/u;
|
|
123
|
+
|
|
124
|
+
/** The independence facts sealed on the decision, exactly as the artifact holds them. */
|
|
125
|
+
export type GateDecisionCorrelationFacts = Pick<
|
|
126
|
+
GateRouteCorrelation,
|
|
127
|
+
"agent" | "target" | "modelFamily" | "runtime" | "node" | "independent"
|
|
128
|
+
>;
|
|
129
|
+
|
|
130
|
+
export interface GateTopologyWinner {
|
|
131
|
+
/** 1-based candidate ordinal the judge picked. */
|
|
132
|
+
readonly index: number;
|
|
133
|
+
readonly runId: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface GateTopologyDecision {
|
|
137
|
+
readonly id: string;
|
|
138
|
+
readonly group: string;
|
|
139
|
+
readonly topology: "review" | "compete";
|
|
140
|
+
readonly cycle: number;
|
|
141
|
+
readonly outcome: GateDecisionOutcome;
|
|
142
|
+
readonly decidedAt: string;
|
|
143
|
+
/** Runs this decision graded, in the order the coordinator sealed them. */
|
|
144
|
+
readonly subjects: readonly string[];
|
|
145
|
+
readonly subjectsTruncated: boolean;
|
|
146
|
+
/** The run that produced the verdict, or null when none ran. */
|
|
147
|
+
readonly decider: string | null;
|
|
148
|
+
/** Present exactly when a decider ran; the store requires the pair. */
|
|
149
|
+
readonly correlation: GateDecisionCorrelationFacts | null;
|
|
150
|
+
readonly winner: GateTopologyWinner | null;
|
|
151
|
+
/** A prior judge decision this one confirmed, by id. */
|
|
152
|
+
readonly confirms: string | null;
|
|
153
|
+
readonly reason: GateDecisionReason | null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface GateTopologyResult {
|
|
157
|
+
/**
|
|
158
|
+
* Whether this installation has a decision store at all.
|
|
159
|
+
*
|
|
160
|
+
* An installation that has never run a gate and one whose gates all aged out
|
|
161
|
+
* both report no decisions, and they are different operator states, so the
|
|
162
|
+
* fact is read rather than inferred from an empty list.
|
|
163
|
+
*/
|
|
164
|
+
readonly present: boolean;
|
|
165
|
+
readonly decisions: readonly GateTopologyDecision[];
|
|
166
|
+
/** True when the scanned window held decisions older than the reported ones. */
|
|
167
|
+
readonly truncated: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Files in the scanned window whose integrity did not verify.
|
|
170
|
+
*
|
|
171
|
+
* The store's own read API drops these silently, which is right for a
|
|
172
|
+
* consumer that must not act on untrusted evidence and wrong for an operator
|
|
173
|
+
* surface: a gate artifact that no longer authenticates is exactly the thing
|
|
174
|
+
* worth knowing about. Counted, never opened for content.
|
|
175
|
+
*/
|
|
176
|
+
readonly unverifiable: number;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function classifyReason(detail: unknown): GateDecisionReason | null {
|
|
180
|
+
if (typeof detail !== "string" || detail.length === 0) return null;
|
|
181
|
+
return REASON_RULES.find(([prefix]) => detail.startsWith(prefix))?.[1] ?? "unclassified";
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function safeIdentifier(value: unknown): string | null {
|
|
185
|
+
return typeof value === "string" && SAFE_GATE_IDENTIFIER.test(value) ? value : null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Newest decision first. An unparseable stamp sorts oldest rather than throwing. */
|
|
189
|
+
function byNewest(a: GateDecisionArtifact, b: GateDecisionArtifact): number {
|
|
190
|
+
return (Date.parse(b.createdAt) || 0) - (Date.parse(a.createdAt) || 0);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Read a bounded window of verified decision artifacts, counting the rest.
|
|
195
|
+
*
|
|
196
|
+
* Reads defensively per file for the same reason the ledger scan does: one
|
|
197
|
+
* artifact written by another build, half-written, or removed between the
|
|
198
|
+
* listing and the open must cost that decision its row, never the whole
|
|
199
|
+
* listing. A file that parses but fails its own integrity check is a different
|
|
200
|
+
* state and is counted rather than dropped.
|
|
201
|
+
*/
|
|
202
|
+
function readDecisionWindow(stateDir: string): {
|
|
203
|
+
present: boolean;
|
|
204
|
+
artifacts: GateDecisionArtifact[];
|
|
205
|
+
unverifiable: number;
|
|
206
|
+
} {
|
|
207
|
+
const directory = gateDecisionsDirectory(stateDir);
|
|
208
|
+
if (!existsSync(directory)) return { present: false, artifacts: [], unverifiable: 0 };
|
|
209
|
+
let entries: string[];
|
|
210
|
+
try {
|
|
211
|
+
entries = readdirSync(directory).filter((name) => name.endsWith(".json"));
|
|
212
|
+
} catch {
|
|
213
|
+
// The directory is there and unreadable, which is not the same as absent.
|
|
214
|
+
return { present: true, artifacts: [], unverifiable: 0 };
|
|
215
|
+
}
|
|
216
|
+
const artifacts: GateDecisionArtifact[] = [];
|
|
217
|
+
let unverifiable = 0;
|
|
218
|
+
for (const name of entries.slice(0, GATE_TOPOLOGY_MAX_SCAN)) {
|
|
219
|
+
let artifact: GateDecisionArtifact;
|
|
220
|
+
try {
|
|
221
|
+
artifact = JSON.parse(readFileSync(join(directory, name), "utf8")) as GateDecisionArtifact;
|
|
222
|
+
} catch {
|
|
223
|
+
unverifiable += 1;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (verifyGateDecisionArtifact(artifact).ok) artifacts.push(artifact);
|
|
227
|
+
else unverifiable += 1;
|
|
228
|
+
}
|
|
229
|
+
artifacts.sort(byNewest);
|
|
230
|
+
return { present: true, artifacts, unverifiable };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function projectDecision(artifact: GateDecisionArtifact): GateTopologyDecision | null {
|
|
234
|
+
const id = safeIdentifier(artifact.id);
|
|
235
|
+
const group = safeIdentifier(artifact.group);
|
|
236
|
+
// The store mints both and already refuses either outside this shape, so a
|
|
237
|
+
// stored value failing it means something else wrote the file. A decision
|
|
238
|
+
// this projection cannot name is one it will not report.
|
|
239
|
+
if (id === null || group === null) return null;
|
|
240
|
+
const allSubjects = artifact.subjects.map((subject) => safeIdentifier(subject.runId));
|
|
241
|
+
if (allSubjects.some((runId) => runId === null)) return null;
|
|
242
|
+
const subjects = (allSubjects as string[]).slice(0, GATE_TOPOLOGY_MAX_SUBJECTS);
|
|
243
|
+
const decider = artifact.decider === undefined ? null : safeIdentifier(artifact.decider.runId);
|
|
244
|
+
if (artifact.decider !== undefined && decider === null) return null;
|
|
245
|
+
let winner: GateTopologyWinner | null = null;
|
|
246
|
+
if (artifact.winner !== undefined) {
|
|
247
|
+
const runId = safeIdentifier(artifact.winner.subject.runId);
|
|
248
|
+
if (runId === null) return null;
|
|
249
|
+
winner = { index: artifact.winner.index, runId };
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
id,
|
|
253
|
+
group,
|
|
254
|
+
topology: artifact.topology,
|
|
255
|
+
cycle: artifact.cycle,
|
|
256
|
+
outcome: artifact.outcome,
|
|
257
|
+
decidedAt: new Date(artifact.createdAt).toISOString(),
|
|
258
|
+
subjects,
|
|
259
|
+
subjectsTruncated: allSubjects.length > subjects.length,
|
|
260
|
+
decider,
|
|
261
|
+
correlation: artifact.correlation === undefined ? null : { ...artifact.correlation },
|
|
262
|
+
winner,
|
|
263
|
+
confirms: artifact.confirmation === undefined ? null : safeIdentifier(artifact.confirmation.id),
|
|
264
|
+
reason: classifyReason(artifact.detail),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Bounded newest-first coordinator gate decisions.
|
|
270
|
+
*
|
|
271
|
+
* Selected by this function, never by a caller's argument, so a host that
|
|
272
|
+
* invokes the command behind it knows the process cannot be steered into a
|
|
273
|
+
* different window.
|
|
274
|
+
*/
|
|
275
|
+
export function gateTopology(stateDir: string = clioStateDir()): GateTopologyResult {
|
|
276
|
+
const { present, artifacts, unverifiable } = readDecisionWindow(stateDir);
|
|
277
|
+
const window = artifacts.slice(0, GATE_TOPOLOGY_MAX_DECISIONS);
|
|
278
|
+
const decisions: GateTopologyDecision[] = [];
|
|
279
|
+
for (const artifact of window) {
|
|
280
|
+
const decision = projectDecision(artifact);
|
|
281
|
+
if (decision !== null) decisions.push(decision);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
present,
|
|
285
|
+
decisions,
|
|
286
|
+
truncated: artifacts.length > window.length || decisions.length !== window.length,
|
|
287
|
+
unverifiable,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
@@ -124,9 +124,28 @@ export {
|
|
|
124
124
|
DISPATCH_INTENT_PATH_LIST_CAP,
|
|
125
125
|
DISPATCH_INTENT_TIMEOUT_MIN_MS,
|
|
126
126
|
DISPATCH_INTENT_VERIFICATION_CAP,
|
|
127
|
+
declaredScopeIntent,
|
|
127
128
|
isDispatchIntent,
|
|
129
|
+
narrowDispatchIntentToReadOnly,
|
|
128
130
|
normalizeDispatchIntent,
|
|
129
131
|
} from "./intent.js";
|
|
132
|
+
export type {
|
|
133
|
+
DispatchIntentAdoption,
|
|
134
|
+
DispatchIntentCompatibilityCode,
|
|
135
|
+
DispatchIntentCompatibilityDecision,
|
|
136
|
+
DispatchIntentCompatibilityFinding,
|
|
137
|
+
} from "./intent-compatibility.js";
|
|
138
|
+
export {
|
|
139
|
+
classifyDispatchIntentCompatibility,
|
|
140
|
+
DISPATCH_INTENT_RETIREMENT_MAX_LEGACY_SHARE,
|
|
141
|
+
DISPATCH_INTENT_RETIREMENT_MIN_SAMPLE,
|
|
142
|
+
DISPATCH_INTENT_SUPPORTED_VERSIONS,
|
|
143
|
+
DISPATCH_INTENT_VERSION,
|
|
144
|
+
dispatchIntentAdoption,
|
|
145
|
+
dispatchIntentRefusals,
|
|
146
|
+
dispatchIntentScopeWidening,
|
|
147
|
+
isSupportedDispatchIntentVersion,
|
|
148
|
+
} from "./intent-compatibility.js";
|
|
130
149
|
export { DispatchManifest } from "./manifest.js";
|
|
131
150
|
export { verifyReceiptIntegrity } from "./receipt-integrity.js";
|
|
132
151
|
export { createRouteHistoryStore } from "./route-history.js";
|