@iowarp/clio-coder 0.3.9 → 0.4.1
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 +92 -0
- package/NOTICE +33 -0
- package/README.md +121 -16
- package/dist/{acp-7LOELQFP.js → acp-ZILU3AUO.js} +19 -18
- package/dist/{agents-FIBG2SHA.js → agents-HYWGBGQR.js} +53 -39
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-OI4LIH2I.js → auth-N3QT7CBO.js} +24 -21
- package/dist/{builtins-AD25UL3C.js → builtins-UJLMOVOV.js} +6 -6
- package/dist/{chunk-I4HZDVNP.js → chunk-2LEAKD4C.js} +2 -3
- package/dist/{chunk-465CC7FK.js → chunk-2NM363SV.js} +60 -64
- package/dist/{chunk-4H6ULJ3H.js → chunk-2VG7KLYV.js} +1046 -1370
- package/dist/{chunk-SST6Z5JA.js → chunk-336NSSKI.js} +1 -1
- package/dist/{chunk-NZU6YDNV.js → chunk-3I5NY75V.js} +5 -5
- package/dist/{chunk-47CMYGET.js → chunk-3QSOM6PA.js} +2 -2
- package/dist/chunk-42FMPA75.js +101 -0
- package/dist/{chunk-HAY4ZE2P.js → chunk-5PSMVOLM.js} +2 -2
- package/dist/{chunk-IHKBWSXF.js → chunk-5QIAJV2D.js} +3 -3
- package/dist/chunk-5YHDIDBP.js +97 -0
- package/dist/chunk-6CCS4G3W.js +1529 -0
- package/dist/{chunk-2JDWVJND.js → chunk-6DWBAZ5U.js} +2 -2
- package/dist/{chunk-BVDVID7E.js → chunk-6FN3E6KX.js} +6 -6
- package/dist/{chunk-DG4M6ZUE.js → chunk-6HMJX2VU.js} +59 -59
- package/dist/{chunk-3MRC2YSQ.js → chunk-6I5ILFOF.js} +3 -2
- package/dist/chunk-6NJQITNH.js +1412 -0
- package/dist/chunk-6VC4OV3Z.js +365 -0
- package/dist/{chunk-LU7P4LHA.js → chunk-72GZI5EV.js} +2 -2
- package/dist/{chunk-5T7RBWN2.js → chunk-74YWRRU5.js} +9 -8
- package/dist/{chunk-VPTUJU4P.js → chunk-7EPLI7VL.js} +2 -2
- package/dist/{chunk-CA42X6KT.js → chunk-7OBGU7UB.js} +7 -7
- package/dist/{chunk-56KB5IJP.js → chunk-7PWAODYW.js} +3 -3
- package/dist/chunk-7RY5VZPH.js +573 -0
- package/dist/{chunk-OEDBCISO.js → chunk-ABLSQ6JX.js} +3 -3
- package/dist/{chunk-5HFBWUMU.js → chunk-AFKWHWXF.js} +13 -23
- package/dist/{chunk-FWDFM5ZU.js → chunk-AK5XEFVZ.js} +3 -3
- package/dist/{chunk-WXCJ7VME.js → chunk-AKB4GYDL.js} +7 -7
- package/dist/chunk-AP73CFDC.js +308 -0
- package/dist/{chunk-4LJX2PUC.js → chunk-BBTJOK6Y.js} +5 -5
- package/dist/{chunk-QQ7EKM72.js → chunk-BDPT6GTK.js} +13 -61
- package/dist/chunk-BJGUKIG4.js +302 -0
- package/dist/chunk-BMS5RKQY.js +27 -0
- package/dist/{chunk-TD7UE2L5.js → chunk-BTGG6BG2.js} +81 -40
- package/dist/chunk-BTK3SSSK.js +67 -0
- package/dist/{chunk-M6L6IDJG.js → chunk-BWH6N36D.js} +1 -1
- package/dist/chunk-BWW4HLO4.js +301 -0
- package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
- package/dist/{chunk-HJB5IUKP.js → chunk-C537JADH.js} +18 -18
- package/dist/{chunk-774ILSRL.js → chunk-CDNVLKUX.js} +5 -4
- package/dist/{chunk-HPCTNZM2.js → chunk-CTJ4RNAA.js} +4 -4
- package/dist/{chunk-AEYBF3TB.js → chunk-CWVRRIEI.js} +2 -2
- package/dist/chunk-D4CJV46V.js +462 -0
- package/dist/chunk-D7E7WCDF.js +27 -0
- package/dist/{chunk-5PVQ4SRS.js → chunk-E67WX76H.js} +10 -126
- package/dist/{chunk-FQ4SKYE4.js → chunk-EBY63B7G.js} +2 -5
- package/dist/chunk-EIMVLWB3.js +1842 -0
- package/dist/{chunk-AMKHQW3C.js → chunk-FEFIFZTL.js} +3 -3
- package/dist/{chunk-RAPCMZL4.js → chunk-FSP7CMNU.js} +9 -1
- package/dist/{chunk-3DUR4WUA.js → chunk-FYUN5KZ3.js} +25 -25
- package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
- package/dist/chunk-GIZNH63R.js +40 -0
- package/dist/chunk-GPPB3JBE.js +688 -0
- package/dist/{chunk-B5XRQOLB.js → chunk-GVQJ5CCZ.js} +17 -11
- package/dist/chunk-HHV2GANA.js +88 -0
- package/dist/chunk-HJWWJ6IL.js +184 -0
- package/dist/{chunk-RKRLDWD3.js → chunk-HLW2MRKE.js} +1 -1
- package/dist/chunk-HRQMFLJP.js +75 -0
- package/dist/{chunk-AD7Y7STJ.js → chunk-HUAS7ITX.js} +107 -97
- package/dist/{chunk-O6I4CIEU.js → chunk-I66EAJFY.js} +6 -6
- package/dist/{chunk-S4COXYBG.js → chunk-IG7BCQBA.js} +129 -106
- package/dist/{chunk-N3PBVRTZ.js → chunk-IXJT6DCX.js} +9 -7
- package/dist/chunk-J4HBWF6Y.js +2635 -0
- package/dist/chunk-J5LZHVIT.js +284 -0
- package/dist/{chunk-GAYUJ7LE.js → chunk-JA5QWE4Z.js} +544 -227
- package/dist/{chunk-B5CSFE7B.js → chunk-JIEGK6UF.js} +6 -174
- package/dist/{chunk-VKBMFOYV.js → chunk-JZWT5J3Y.js} +23 -27
- package/dist/chunk-K6BF4U2H.js +1785 -0
- package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
- package/dist/{chunk-YSEHGPCT.js → chunk-MA3H6DM5.js} +6 -6
- package/dist/{chunk-EBOC7MT3.js → chunk-MOPSG2X7.js} +9 -9
- package/dist/{chunk-KV2AOLDF.js → chunk-MQXIVJ35.js} +18 -29
- package/dist/{chunk-P3JGPQFL.js → chunk-N5UK64DP.js} +4 -4
- package/dist/chunk-NDDGJUXD.js +81 -0
- package/dist/chunk-NEKRRTYW.js +56 -0
- package/dist/{chunk-4ZG3XFUR.js → chunk-NLFAQR7Z.js} +12 -1
- package/dist/{chunk-VO2LKSTM.js → chunk-O42A54GG.js} +2 -2
- package/dist/{chunk-T3Z6VAAF.js → chunk-OJTRZGR3.js} +53 -92
- package/dist/{chunk-5DQRIYDZ.js → chunk-PBP4B7XR.js} +3 -3
- package/dist/{chunk-NQ6UCCOD.js → chunk-PJJ6MY27.js} +8 -8
- package/dist/chunk-PMZCIOCJ.js +25 -0
- package/dist/{chunk-ZGVHUX3M.js → chunk-PMZVFWSR.js} +2 -2
- package/dist/{chunk-7C6RYZGQ.js → chunk-PVAMAVBB.js} +5 -4
- package/dist/chunk-QDC3K2U3.js +262 -0
- package/dist/{chunk-JEQQR47K.js → chunk-QKIFBZKT.js} +173 -14
- package/dist/{chunk-R7LNVMCS.js → chunk-QMXC4JB7.js} +70 -78
- package/dist/chunk-QSNYB6ZV.js +195 -0
- package/dist/chunk-QTFGO774.js +644 -0
- package/dist/{chunk-ODFEOB4F.js → chunk-R23Z6K6I.js} +27 -9
- package/dist/{chunk-3UUY7R3Z.js → chunk-R32CLGZ6.js} +14 -14
- package/dist/chunk-R346GLFC.js +31 -0
- package/dist/chunk-RKSR6VSF.js +132 -0
- package/dist/{chunk-N5XKWMDW.js → chunk-SCYB3HA4.js} +73 -27
- package/dist/{chunk-PZ4I4JE2.js → chunk-SINK3QR6.js} +135 -125
- package/dist/{chunk-5QKCQQ3E.js → chunk-SUW5DORT.js} +2 -2
- package/dist/chunk-T56WDKA5.js +183 -0
- package/dist/{chunk-ECUO3KDP.js → chunk-TD3PGPQA.js} +87 -26
- package/dist/{chunk-HKO36JWF.js → chunk-THYWACCR.js} +31 -3
- package/dist/{chunk-LXPJXFM5.js → chunk-TVH4ONAM.js} +18 -12
- package/dist/chunk-TVHHYFHE.js +255 -0
- package/dist/chunk-U2WB7TZS.js +271 -0
- package/dist/{chunk-NNNWO6F2.js → chunk-UAPGZHYC.js} +237 -33
- package/dist/{chunk-MIX5N5AC.js → chunk-UEDMSP56.js} +415 -160
- package/dist/{chunk-WIE7ZOSW.js → chunk-UXN6JT4W.js} +3 -3
- package/dist/{chunk-CMZWFGD2.js → chunk-VAVR4IJY.js} +19 -15
- package/dist/{chunk-MV2VUEJC.js → chunk-VEGN6WIQ.js} +2 -2
- package/dist/chunk-VKFQTNDV.js +66 -0
- package/dist/{chunk-FALJGAWU.js → chunk-VKRH2TCS.js} +2 -2
- package/dist/{chunk-A2NJGIB3.js → chunk-VN3SHNBN.js} +2 -2
- package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
- package/dist/{chunk-UOSL25KY.js → chunk-VXMFAE2W.js} +1 -1
- package/dist/{chunk-EQ63NRB7.js → chunk-WNP7O5WZ.js} +3 -3
- package/dist/chunk-WR6U3OVP.js +45 -0
- package/dist/{chunk-TEO2TLVN.js → chunk-XKA2ICR3.js} +1051 -1196
- package/dist/{chunk-3V5AYSEQ.js → chunk-Y45G3AXC.js} +72 -65
- package/dist/{chunk-J5Q24KAG.js → chunk-Y4CAGMM6.js} +2 -2
- package/dist/chunk-YAKGTXEV.js +17 -0
- package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
- package/dist/{chunk-YW7UVM5V.js → chunk-ZAZB4JMW.js} +55 -11
- package/dist/{chunk-HCBCAYZU.js → chunk-ZJLUDYFY.js} +11 -11
- package/dist/{chunk-HKIYEGME.js → chunk-ZTJUVLTU.js} +2 -2
- package/dist/{chunk-IFBNV6H6.js → chunk-ZW55JB7N.js} +3 -3
- package/dist/cli/index.js +48 -37
- package/dist/clio-IT3G3VQH.js +25 -0
- package/dist/{code-nav-LMW275PA.js → code-nav-RK6S7F6E.js} +8 -8
- package/dist/codewiki/build-worker.js +1 -1
- package/dist/{compile-cache-CVJMMODC.js → compile-cache-OQAVB7Y5.js} +3 -5
- package/dist/{components-ZFA3SAER.js → components-UBWCQSRW.js} +6 -6
- package/dist/{config-RXS5T3JT.js → config-3QZRWZJF.js} +73 -61
- package/dist/configure-FL7Y3KJF.js +54 -0
- package/dist/{context-MVOORGMF.js → context-5HE7ODYK.js} +61 -49
- package/dist/{context-I3BTOTCS.js → context-KYQFRVDC.js} +11 -11
- package/dist/{context-PALKKQYL.js → context-XNHL75JV.js} +43 -28
- package/dist/{context-clear-N2WOYZ2K.js → context-clear-N545L53A.js} +60 -48
- package/dist/{context-working-set-MIEVECVZ.js → context-working-set-QHKXSV2F.js} +15 -13
- package/dist/{dispatch-runner-VVA4SRRH.js → dispatch-runner-RGIE5PCT.js} +109 -72
- package/dist/{docs-7LQ23DLM.js → docs-5NAF6AU7.js} +7 -13
- package/dist/doctor-ZGPEGHIP.js +772 -0
- package/dist/{eval-IJ5VEZDJ.js → eval-GXLL44RD.js} +106 -86
- package/dist/eval-inventory-HBWSWQOK.js +315 -0
- package/dist/{evidence-L5APPXNV.js → evidence-HWLBRH3Q.js} +209 -51
- package/dist/{evolve-RGNKFJ52.js → evolve-FTZBMNVW.js} +57 -45
- package/dist/{extensions-7WYWUX5A.js → extensions-VHRBEID7.js} +7 -7
- package/dist/{fleet-6CNVBZZP.js → fleet-CKZHJWZJ.js} +215 -114
- package/dist/{fleet-commands-L2SXSYEI.js → fleet-commands-EXDXBMV6.js} +13 -12
- package/dist/fleet-decisions-OTHB6KRL.js +157 -0
- package/dist/{fleet-graph-2J3OOIPO.js → fleet-graph-YTEZUCUT.js} +20 -17
- package/dist/fleet-inspect-SS6YMDCK.js +445 -0
- package/dist/{fleet-preflight-CZRJ4JP5.js → fleet-preflight-PBY4VYOM.js} +6 -9
- package/dist/{fleet-validate-C5RI6DP7.js → fleet-validate-KMEM5L3S.js} +25 -20
- package/dist/fleet-verify-QD5M7E7Q.js +178 -0
- package/dist/fleet-view-WAMJYNDT.js +94 -0
- package/dist/{init-VBN2ACVA.js → init-5XQRBOFV.js} +79 -66
- package/dist/install-NKNG7KD4.js +13 -0
- package/dist/interop-34TVO25M.js +116 -0
- package/dist/{library-JHGUMLY2.js → library-3QY6KF57.js} +25 -21
- package/dist/{memory-K4OQIYWG.js → memory-L4UTIIIW.js} +59 -47
- package/dist/{models-2NCZUWDD.js → models-ZVX3QOWE.js} +47 -37
- package/dist/{monitor-MMVTJABD.js → monitor-CEKVSYTS.js} +67 -57
- package/dist/{orchestrator-ZKBPCHW6.js → orchestrator-77BAP6BC.js} +7633 -7699
- package/dist/panes-7STHOAUJ.js +103 -0
- package/dist/panes-SHAUIRXY.js +60 -0
- package/dist/{paths-DBXMZMDU.js → paths-L7LGY6RN.js} +6 -6
- package/dist/{reset-DD5JGOY3.js → reset-EOLM7GVE.js} +15 -14
- package/dist/resources-74GKTLSF.js +115 -0
- package/dist/{run-QEGNX7FL.js → run-HBAUJNNZ.js} +139 -98
- package/dist/{share-JKD3BQMW.js → share-G3APVLVP.js} +25 -21
- package/dist/{skills-LMQIKDOZ.js → skills-35HHUKCR.js} +37 -27
- package/dist/{skills-eval-I7X2774U.js → skills-eval-QN4HSHDC.js} +80 -73
- package/dist/skills-inventory-J357J34F.js +129 -0
- package/dist/slash-commands-JZZCQA32.js +79 -0
- package/dist/{steer-CF5TDANS.js → steer-XAVHJM22.js} +4 -4
- package/dist/{support-I7LOJLIF.js → support-U7QOWY26.js} +7 -7
- package/dist/{targets-RUSR6B5Z.js → targets-DSM6CY3M.js} +67 -59
- package/dist/{terminal-lease-QYVORFR4.js → terminal-lease-JOPFUVEM.js} +15 -10
- package/dist/tools-MKNWVPBH.js +29 -0
- package/dist/{trace-ODOQIVIW.js → trace-ECQ7TIYZ.js} +194 -7
- package/dist/tui-primitives-K5PASC3O.js +17 -0
- package/dist/{uninstall-ZJF5H5ZN.js → uninstall-N34PCTGJ.js} +6 -8
- package/dist/{upgrade-XANW3FXB.js → upgrade-H7TOM7YL.js} +37 -62
- package/dist/{usage-4H7ZRXQT.js → usage-X52N3IDJ.js} +70 -59
- package/dist/{verifiers-UZXNBZEB.js → verifiers-EJTVVSMA.js} +174 -14
- package/dist/{verify-BVKWTNDL.js → verify-YJL6XET2.js} +12 -11
- package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-MPIFL3LL.js} +3 -4
- package/dist/{wiki-generate-MY7WV2QI.js → wiki-generate-4NDZTQ4B.js} +86 -75
- package/dist/with-panes-OBOBFIIR.js +818 -0
- package/dist/worker/entry.js +131 -91
- package/docs/README.md +3 -2
- package/docs/acp.md +25 -4
- 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 +40 -32
- package/docs/capacity-and-scheduling.md +43 -5
- package/docs/commands-and-modes.md +39 -4
- package/docs/config-knobs-audit.md +3 -0
- package/docs/configuration-and-targets.md +138 -167
- 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 +3 -1
- 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 +3 -1
- package/docs/extensions-and-sharing.md +25 -1
- package/docs/fleet-demo-runbook.md +6 -3
- package/docs/fleet-dispatch.md +30 -7
- package/docs/installation-and-lifecycle.md +16 -3
- 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/release-cut-checklist.md +164 -177
- 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 +16 -11
- package/docs/troubleshooting.md +2 -2
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/evals/README.md +5 -0
- package/evals/behavioral-corpus-grader.mjs +103 -0
- package/evals/behavioral-machinery-baseline.json +2276 -0
- package/evals/behavioral-machinery-driver.ts +250 -0
- package/evals/behavioral-machinery-support.ts +253 -0
- package/evals/behavioral-machinery.yaml +614 -0
- package/evals/behavioral-model-negative-control.yaml +68 -0
- package/evals/behavioral-model.yaml +216 -0
- package/evals/fixtures/behavioral-facts.txt +3 -0
- package/evals/fixtures/behavioral-main.ts +7 -0
- package/evals/fixtures/decoy/note.txt +2 -0
- package/evals/fixtures/private/credentials.txt +1 -0
- package/evals/tracked-metrics-baseline.yaml +229 -0
- package/evals/tracked-metrics-grader.mjs +129 -0
- package/package.json +8 -16
- package/skills/README.md +6 -6
- package/skills/coding/ast-grep/SKILL.md +8 -2
- package/skills/coding/coding-standards/SKILL.md +8 -2
- package/skills/coding/prototype/SKILL.md +8 -2
- package/skills/coding/tdd/SKILL.md +8 -2
- package/skills/context/context-handoff/SKILL.md +12 -3
- package/skills/context/context-handoff/evals.md +3 -3
- package/skills/context/context-prime/SKILL.md +8 -2
- package/skills/context/context-prime/evals.md +2 -2
- package/skills/git/file-ticket/SKILL.md +9 -4
- package/skills/git/file-ticket/evals.md +2 -2
- package/skills/git/fix-issue/SKILL.md +12 -5
- package/skills/git/fix-issue/evals.md +4 -4
- package/skills/git/resolve-merge-conflicts/SKILL.md +8 -2
- package/skills/git/resolve-merge-conflicts/evals.md +2 -2
- package/skills/git/ship/SKILL.md +9 -3
- package/skills/git/ship/evals.md +4 -4
- package/skills/git/worktree-create/SKILL.md +7 -2
- package/skills/git/worktree-create/evals.md +6 -6
- package/skills/git/worktree-merge/SKILL.md +7 -2
- package/skills/git/worktree-merge/evals.md +6 -6
- package/skills/meta/{clio-dev → clio-coder-dev}/SKILL.md +14 -8
- package/skills/meta/{clio-dev → clio-coder-dev}/evals.md +3 -3
- package/skills/meta/{clio-test → clio-coder-test}/SKILL.md +11 -5
- package/skills/meta/{clio-test → clio-coder-test}/evals.md +1 -1
- package/skills/meta/credentials/SKILL.md +9 -2
- package/skills/meta/find-skills/SKILL.md +8 -2
- package/skills/meta/herdr/SKILL.md +8 -2
- package/skills/meta/skill-craft/SKILL.md +21 -4
- package/skills/planning/architecture/SKILL.md +9 -3
- package/skills/planning/backlog/SKILL.md +8 -2
- package/skills/planning/prd/SKILL.md +8 -2
- package/skills/planning/product-intent/SKILL.md +8 -2
- package/skills/planning/tech-spec/SKILL.md +9 -3
- package/skills/registry.yaml +66 -66
- package/skills/research/arxiv-literature/SKILL.md +8 -2
- package/skills/research/experiment-protocol/SKILL.md +9 -2
- package/skills/research/scientific-debugging/SKILL.md +9 -2
- package/skills/research/scientific-debugging/evals.md +2 -2
- package/skills/research/scientific-modernization/SKILL.md +9 -2
- package/skills/skill-marketplace.json +257 -38
- package/skills/workflow/cut-it/SKILL.md +10 -2
- package/skills/workflow/design-council/SKILL.md +11 -2
- package/skills/workflow/grill-me/SKILL.md +8 -2
- package/skills/workflow/workflow-distiller/SKILL.md +8 -2
- package/src/cli/acp.ts +8 -4
- package/src/cli/argv.ts +25 -0
- package/src/cli/auth.ts +2 -2
- package/src/cli/bootstrap-generate.ts +5 -5
- package/src/cli/clio.ts +6 -1
- package/src/cli/config-inspect.ts +3 -3
- package/src/cli/configure-interop.ts +1 -1
- package/src/cli/configure.ts +50 -48
- package/src/cli/default-target.ts +1 -1
- package/src/cli/docs.ts +6 -6
- package/src/cli/doctor-naming.ts +323 -0
- package/src/cli/doctor-panes.ts +156 -0
- package/src/cli/doctor-toolchain.ts +78 -0
- package/src/cli/doctor.ts +34 -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-preflight.ts +1 -1
- package/src/cli/fleet-verify.ts +133 -0
- package/src/cli/fleet-view.ts +827 -0
- package/src/cli/fleet.ts +154 -40
- 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/models.ts +3 -3
- package/src/cli/modes/print.ts +1 -1
- package/src/cli/panes.ts +35 -0
- package/src/cli/reset.ts +6 -3
- package/src/cli/run.ts +67 -13
- package/src/cli/share.ts +1 -1
- package/src/cli/skills-eval.ts +11 -11
- package/src/cli/skills-inventory.ts +185 -0
- package/src/cli/skills.ts +16 -13
- package/src/cli/targets.ts +23 -24
- package/src/cli/tools.ts +321 -0
- package/src/cli/trace-inspect.ts +252 -0
- package/src/cli/trace.ts +64 -2
- package/src/cli/uninstall.ts +2 -2
- package/src/cli/upgrade.ts +29 -34
- package/src/cli/usage.ts +2 -2
- package/src/cli/validate-model.ts +1 -1
- package/src/cli/verifiers-inspect.ts +347 -0
- package/src/cli/verifiers.ts +9 -0
- package/src/cli/wiki-generate.ts +5 -5
- package/src/core/bash-exec.ts +1 -1
- package/src/core/boot-trace.ts +3 -3
- package/src/core/bus-events.ts +4 -0
- package/src/core/bus-trace.ts +2 -2
- package/src/core/compile-cache.ts +1 -1
- package/src/core/config.ts +1070 -845
- package/src/core/defaults.ts +342 -463
- package/src/core/domain-loader.ts +6 -4
- package/src/core/event-bus.ts +1 -1
- package/src/core/file-references.ts +78 -88
- package/src/core/git-commit-attribution.ts +3 -9
- package/src/core/guardrails.ts +24 -4
- package/src/core/naming-compat.ts +45 -0
- package/src/core/naming-events.ts +62 -0
- package/src/core/recent-models.ts +1 -7
- package/src/core/residency-protection.ts +4 -8
- package/src/core/resolve-config-value.ts +1 -1
- package/src/core/response-model-id.ts +0 -14
- package/src/core/response-schema.ts +44 -4
- package/src/core/session-routing.ts +84 -74
- package/src/core/skill-activation.ts +18 -0
- package/src/core/termination.ts +4 -4
- package/src/core/theme-token-hex.ts +43 -0
- package/src/core/timers.ts +2 -12
- package/src/core/tool-names.ts +2 -1
- package/src/core/xdg.ts +1 -1
- package/src/domains/agents/catalog.ts +2 -12
- package/src/domains/agents/extension.ts +3 -3
- package/src/domains/agents/fleets/build-review.md +0 -3
- package/src/domains/agents/fleets/build-test.md +0 -3
- package/src/domains/agents/registry.ts +7 -7
- package/src/domains/agents/result-contract-filesystem.ts +32 -0
- package/src/domains/agents/result-contract.ts +165 -36
- package/src/domains/agents/spec.ts +0 -11
- package/src/domains/config/classify.ts +37 -46
- package/src/domains/config/extension.ts +5 -5
- package/src/domains/config/keybindings.ts +48 -47
- package/src/domains/config/watcher.ts +1 -1
- package/src/domains/context/codewiki/indexer.ts +1 -1
- package/src/domains/context/extension.ts +3 -3
- package/src/domains/context/prompt-context.ts +1 -1
- package/src/domains/context/wiki/assemble.ts +2 -2
- package/src/domains/context/working-set/replay/metrics.ts +0 -4
- package/src/domains/context/working-set/replay/report.ts +1 -1
- package/src/domains/context/working-set/replay/synthetic.ts +2 -2
- package/src/domains/dispatch/active-route-planner.ts +2 -2
- package/src/domains/dispatch/admission-error.ts +9 -0
- package/src/domains/dispatch/admission.ts +22 -21
- package/src/domains/dispatch/agent-candidates.ts +1 -1
- package/src/domains/dispatch/agent-ledger-store.ts +1 -1
- package/src/domains/dispatch/agent-ledger.ts +1 -1
- package/src/domains/dispatch/assignment.ts +5 -5
- package/src/domains/dispatch/capacity-lease.ts +23 -6
- package/src/domains/dispatch/code-step.ts +1 -1
- package/src/domains/dispatch/contract.ts +2 -2
- package/src/domains/dispatch/council-topology.ts +398 -0
- package/src/domains/dispatch/extension.ts +287 -111
- package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
- package/src/domains/dispatch/fleet-plan.ts +7 -2
- package/src/domains/dispatch/fleet-preflight.ts +8 -17
- package/src/domains/dispatch/fleet-run.ts +59 -3
- package/src/domains/dispatch/gate-decisions.ts +36 -15
- 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/joint-route-resolver.ts +1 -1
- package/src/domains/dispatch/path-scope.ts +0 -61
- package/src/domains/dispatch/placement.ts +2 -2
- package/src/domains/dispatch/receipt-findings.ts +1 -1
- package/src/domains/dispatch/receipt-integrity.ts +20 -8
- package/src/domains/dispatch/reservation-store.ts +24 -27
- package/src/domains/dispatch/route-decision.ts +1 -1
- package/src/domains/dispatch/route-history.ts +1 -1
- package/src/domains/dispatch/route-policy.ts +1 -1
- package/src/domains/dispatch/route-readiness.ts +0 -28
- package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
- package/src/domains/dispatch/run-event-journal.ts +599 -0
- package/src/domains/dispatch/state.ts +45 -1
- package/src/domains/dispatch/tool-stats.ts +1 -1
- package/src/domains/dispatch/transport.ts +2 -19
- package/src/domains/dispatch/types.ts +16 -3
- package/src/domains/dispatch/validation.ts +33 -8
- package/src/domains/dispatch/worker-protocol.ts +2 -2
- package/src/domains/eval/artifacts/store.ts +5 -4
- package/src/domains/eval/compare/compare.ts +3 -16
- package/src/domains/eval/compare/thresholds.ts +0 -8
- package/src/domains/eval/execution-provenance.ts +1 -1
- package/src/domains/eval/inventory.ts +113 -0
- package/src/domains/eval/metrics/token-stream.ts +0 -7
- package/src/domains/eval/report.ts +1 -1
- package/src/domains/eval/runner.ts +1 -1
- package/src/domains/eval/runners/clio-run.ts +7 -6
- package/src/domains/eval/runners/external-command.ts +4 -3
- package/src/domains/eval/schema/artifact.ts +1 -1
- package/src/domains/eval/schema/behavioral-metrics.ts +3 -2
- package/src/domains/eval/schema/behavioral.ts +7 -6
- package/src/domains/eval/schema/execution-envelope.ts +4 -2
- package/src/domains/eval/schema/naming.ts +10 -0
- package/src/domains/eval/schema/serving.ts +31 -0
- package/src/domains/eval/schema/suite.ts +2 -2
- package/src/domains/eval/schema/validate.ts +9 -5
- package/src/domains/eval/schema/verdict.ts +4 -2
- package/src/domains/eval/store.ts +12 -2
- package/src/domains/eval/suites/run.ts +12 -6
- package/src/domains/eval/types.ts +1 -1
- package/src/domains/eval/workspaces/git.ts +1 -1
- package/src/domains/eval/workspaces/temp-copy.ts +1 -1
- package/src/domains/evidence/build.ts +13 -5
- package/src/domains/evidence/store.ts +6 -0
- package/src/domains/interop/consent.ts +7 -7
- package/src/domains/interop/extension.ts +1 -1
- package/src/domains/lifecycle/doctor.ts +27 -21
- package/src/domains/lifecycle/migrations/2026-09-01-clio-coder-naming.ts +155 -0
- package/src/domains/lifecycle/migrations/2026-09-01-retire-panes-knobs.ts +59 -0
- package/src/domains/lifecycle/migrations/2026-09-01-settings-v2.ts +338 -0
- package/src/domains/lifecycle/migrations/index.ts +20 -1
- package/src/domains/lifecycle/naming-history.ts +153 -0
- package/src/domains/lifecycle/naming-mutable-state.ts +104 -0
- package/src/domains/lifecycle/naming-resources.ts +261 -0
- package/src/domains/lifecycle/naming-tool-markers.ts +139 -0
- package/src/domains/lifecycle/naming-yazi.ts +81 -0
- package/src/domains/lifecycle/upgrade-notice.ts +1 -1
- package/src/domains/memory/index.ts +0 -1
- package/src/domains/memory/task-memory-handoff.ts +6 -3
- package/src/domains/memory/task-memory-policy.ts +6 -10
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- package/src/domains/middleware/index.ts +7 -0
- package/src/domains/middleware/marketplace-offer.ts +339 -0
- package/src/domains/middleware/memory-intervention.ts +33 -21
- package/src/domains/middleware/runtime.ts +2 -2
- package/src/domains/mux/contract.ts +566 -0
- package/src/domains/mux/detect.ts +182 -0
- package/src/domains/mux/dock-controller.ts +365 -0
- package/src/domains/mux/extension.ts +53 -0
- package/src/domains/mux/index.ts +116 -0
- package/src/domains/mux/manifest.ts +6 -0
- package/src/domains/mux/operations.ts +192 -0
- package/src/domains/mux/pane-registry.ts +90 -0
- package/src/domains/mux/protocol.ts +62 -0
- package/src/domains/mux/socket-client.ts +964 -0
- package/src/domains/mux/types.ts +265 -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 +182 -0
- package/src/domains/mux/yazi/profile.ts +299 -0
- package/src/domains/mux/yazi/session.ts +251 -0
- package/src/domains/mux/yazi/theme.ts +30 -0
- package/src/domains/observability/cost.ts +21 -0
- package/src/domains/observability/extension.ts +1 -1
- package/src/domains/observability/index.ts +2 -0
- package/src/domains/observability/out-of-turn-usage.ts +2 -2
- package/src/domains/observability/projection.ts +1 -1
- package/src/domains/observability/trace-store.ts +63 -11
- package/src/domains/prompts/compiler.ts +2 -2
- package/src/domains/prompts/extension.ts +3 -3
- package/src/domains/prompts/fragments/identity/clio-worker.md +1 -1
- package/src/domains/prompts/fragments/operating/skills.md +25 -18
- 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 +25 -8
- package/src/domains/providers/index.ts +22 -0
- package/src/domains/providers/knowledge-base-path.ts +1 -1
- package/src/domains/providers/model-runtime-capabilities.ts +46 -2
- package/src/domains/providers/models/cloud-models/alcf.yaml +1 -1
- package/src/domains/providers/models/local-models/{clio-local-coding-targets.yaml → clio-coder-local-coding-targets.yaml} +4 -4
- package/src/domains/providers/plugins.ts +1 -1
- package/src/domains/providers/resolver.ts +1 -1
- package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -0
- package/src/domains/providers/runtimes/cloud/alcf.ts +4 -4
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +1 -5
- package/src/domains/providers/runtimes/common/local-synth.ts +3 -3
- package/src/domains/providers/runtimes/common/probe-helpers.ts +2 -2
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +2 -9
- package/src/domains/providers/runtimes/protocol/litellm.ts +285 -0
- package/src/domains/providers/support.ts +1 -0
- package/src/domains/providers/target-model-cache.ts +124 -0
- package/src/domains/providers/types/knowledge-base.ts +13 -0
- package/src/domains/providers/types/local-model-quirks.ts +2 -2
- package/src/domains/providers/types/target-descriptor.ts +3 -3
- package/src/domains/resources/extension.ts +1 -1
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/library.ts +6 -6
- package/src/domains/resources/prompts/loader.ts +1 -1
- package/src/domains/resources/skills/content-hash.ts +7 -6
- package/src/domains/resources/skills/evals.ts +1 -1
- package/src/domains/resources/skills/install.ts +36 -12
- package/src/domains/resources/skills/loader.ts +72 -13
- package/src/domains/resources/skills/marketplace.ts +21 -2
- package/src/domains/resources/skills/promotion.ts +214 -0
- package/src/domains/safety/action-classifier.ts +6 -0
- package/src/domains/safety/audit.ts +2 -2
- package/src/domains/safety/finish-contract.ts +2 -1
- package/src/domains/safety/run-effects.ts +1 -1
- package/src/domains/scheduling/extension.ts +4 -4
- package/src/domains/session/archive-readers.ts +9 -1
- package/src/domains/session/compaction/branch-summary.ts +4 -0
- package/src/domains/session/compaction/compact.ts +1 -1
- package/src/domains/session/compaction/tokens.ts +4 -0
- package/src/domains/session/context-accounting.ts +1 -1
- package/src/domains/session/decision-board.ts +1 -1
- package/src/domains/session/extension.ts +1 -1
- package/src/domains/session/handoff.ts +2 -2
- package/src/domains/session/prompt-manifest.ts +0 -5
- package/src/domains/session/protected-artifact-journal.ts +12 -6
- package/src/domains/session/retry.ts +1 -1
- package/src/domains/share/archive.ts +85 -36
- 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/adapter.ts +3 -3
- package/src/engine/acp/event-mapper.ts +3 -3
- package/src/engine/acp/server.ts +440 -96
- package/src/engine/acp/tool-mediator.ts +2 -2
- package/src/engine/acp/types.ts +20 -2
- package/src/engine/alcf-oauth.ts +5 -5
- package/src/engine/antigravity/subprocess-runtime.ts +2 -2
- package/src/engine/api-registry.ts +1 -1
- package/src/engine/apis/llamacpp-residency.ts +1 -19
- package/src/engine/apis/lmstudio.ts +1 -6
- package/src/engine/apis/ollama-native.ts +3 -3
- package/src/engine/apis/openai-completions.ts +2 -2
- package/src/engine/apis/residency.ts +3 -9
- package/src/engine/claude/sdk-module.ts +87 -0
- package/src/engine/claude/sdk-runtime.ts +25 -17
- package/src/engine/claude/subprocess-runtime.ts +1 -1
- package/src/engine/claude/tool-safety.ts +4 -4
- package/src/engine/loop-guard.ts +0 -5
- package/src/engine/session.ts +14 -7
- package/src/engine/tui-primitives.ts +21 -0
- package/src/engine/tui.ts +1 -0
- package/src/engine/worker-events.ts +6 -6
- package/src/engine/worker-runtime.ts +16 -26
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +207 -90
- package/src/entry/panes-activation.ts +31 -0
- package/src/entry/with-panes.ts +20 -0
- package/src/interactive/application-controller.ts +21 -21
- package/src/interactive/bus-notices.ts +2 -2
- package/src/interactive/chat-loop.ts +8 -8
- package/src/interactive/chat-panel.ts +1 -1
- package/src/interactive/clio-editor.ts +105 -1
- package/src/interactive/context-activity.ts +8 -6
- package/src/interactive/context-meter.ts +3 -6
- package/src/interactive/context-overlay.ts +2 -1
- package/src/interactive/cost-overlay.ts +3 -1
- package/src/interactive/council-grid.ts +3 -5
- package/src/interactive/council.ts +11 -0
- package/src/interactive/dispatch-board.ts +56 -49
- package/src/interactive/editor-bash.ts +21 -0
- package/src/interactive/editor-steer.ts +9 -4
- package/src/interactive/editor-submit.ts +24 -18
- package/src/interactive/external-editor.ts +1 -1
- package/src/interactive/file-reference-completion.ts +360 -0
- package/src/interactive/footer/dashboard.ts +15 -17
- package/src/interactive/footer/notifications.ts +14 -8
- package/src/interactive/footer/widgets.ts +2 -44
- package/src/interactive/interactive-application.ts +229 -62
- package/src/interactive/interactive-event-projection.ts +1 -1
- package/src/interactive/interactive-input-runtime.ts +9 -2
- package/src/interactive/interactive-presentation.ts +21 -16
- package/src/interactive/interactive-shell.ts +2 -2
- package/src/interactive/interactive-slash-runtime.ts +99 -23
- package/src/interactive/interactive-subscriptions.ts +1 -1
- package/src/interactive/interactive-tickers.ts +1 -1
- package/src/interactive/keybinding-manager.ts +4 -4
- package/src/interactive/layout.ts +1 -1
- package/src/interactive/memory-overlay.ts +3 -2
- package/src/interactive/modal-marker.ts +151 -0
- package/src/interactive/mutation-preview.ts +1 -1
- package/src/interactive/mux-bridge.ts +214 -0
- package/src/interactive/overlay-frame.ts +62 -14
- package/src/interactive/overlay-general-openers.ts +7 -2
- package/src/interactive/overlay-key-routing.ts +21 -10
- package/src/interactive/overlay-lifecycle.ts +20 -4
- package/src/interactive/overlay-model-selectors.ts +43 -6
- package/src/interactive/overlay-permission-lifecycle.ts +90 -22
- package/src/interactive/overlay-transitions.ts +18 -4
- package/src/interactive/overlays/agents.ts +3 -2
- package/src/interactive/overlays/ask-user.ts +161 -41
- package/src/interactive/overlays/auth-dialog.ts +1 -0
- package/src/interactive/overlays/context-reset.ts +29 -4
- package/src/interactive/overlays/cwd-fallback.ts +29 -4
- package/src/interactive/overlays/decisions.ts +15 -13
- package/src/interactive/overlays/extensions.ts +1 -0
- package/src/interactive/overlays/fleet-run-approval.ts +4 -3
- package/src/interactive/overlays/handoff-review.ts +3 -2
- package/src/interactive/overlays/help-reference.ts +2 -0
- package/src/interactive/overlays/interop.ts +2 -1
- package/src/interactive/overlays/library-install-confirm.ts +2 -1
- 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 +2 -1
- package/src/interactive/overlays/model-scope.ts +86 -0
- package/src/interactive/overlays/model-selector.ts +40 -31
- package/src/interactive/overlays/prompts.ts +11 -4
- package/src/interactive/overlays/session-selector.ts +3 -2
- package/src/interactive/overlays/settings-sections.ts +30 -0
- package/src/interactive/overlays/settings.ts +849 -268
- package/src/interactive/overlays/side-question.ts +3 -2
- package/src/interactive/overlays/skills-hub.ts +11 -19
- package/src/interactive/overlays/tree-selector.ts +3 -2
- package/src/interactive/pane-policy.ts +46 -0
- package/src/interactive/panes-runtime.ts +318 -0
- package/src/interactive/permission-overlay.ts +2 -2
- package/src/interactive/renderers/compaction-summary.ts +29 -0
- package/src/interactive/renderers/retry-status.ts +12 -4
- package/src/interactive/renderers/tool-execution.ts +4 -4
- package/src/interactive/renderers/worker-entry.ts +122 -14
- package/src/interactive/session-transcript.ts +3 -3
- package/src/interactive/slash-autocomplete.ts +454 -165
- package/src/interactive/slash-commands.ts +521 -189
- package/src/interactive/slash-spec.ts +160 -17
- package/src/interactive/status/controller.ts +2 -2
- package/src/interactive/stream-pacing-policy.ts +1 -1
- package/src/interactive/tasks-overlay.ts +21 -13
- package/src/interactive/terminal-lease.ts +6 -7
- package/src/interactive/theme/tokens.ts +3 -14
- package/src/interactive/turn-context.ts +58 -13
- package/src/interactive/turn-persistence.ts +2 -2
- package/src/interactive/turn-prewarm.ts +2 -2
- package/src/interactive/turn-runtime.ts +8 -8
- package/src/interactive/turn-state.ts +1 -1
- package/src/interactive/view/artifacts.ts +120 -9
- package/src/interactive/view/view-overlay.ts +14 -10
- package/src/interactive/watch-pane.ts +180 -0
- package/src/interactive/welcome-dashboard.ts +15 -15
- package/src/interactive/worker-progress.ts +11 -5
- package/src/interactive/worker-receipts.ts +20 -2
- package/src/interactive/worker-stream.ts +6 -4
- package/src/interactive/yazi-bridge.ts +451 -0
- package/src/tools/ask-user.ts +3 -3
- package/src/tools/bash.ts +1 -1
- package/src/tools/bootstrap.ts +26 -2
- package/src/tools/builtin-tool-catalog.ts +16 -1
- package/src/tools/compete-worktrees.ts +108 -17
- package/src/tools/context/index.ts +15 -1
- package/src/tools/core-bootstrap.ts +2 -1
- package/src/tools/dispatch-admission.ts +18 -5
- package/src/tools/dispatch-arguments.ts +21 -21
- package/src/tools/dispatch-plan.ts +0 -11
- package/src/tools/dispatch-run-events.ts +145 -28
- package/src/tools/dispatch-runner.ts +40 -13
- package/src/tools/dispatch-types.ts +15 -3
- package/src/tools/dispatch.ts +2 -2
- package/src/tools/executables.ts +17 -14
- package/src/tools/find.ts +1 -6
- package/src/tools/monitor.ts +4 -4
- package/src/tools/observation.ts +54 -4
- package/src/tools/observers.ts +0 -33
- 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/src/tools/task-worktree.ts +28 -7
- package/src/tools/verify/authoring.ts +3 -6
- package/src/tools/verify/frontend.ts +1 -1
- package/src/tools/web-fetch.ts +1 -1
- package/src/worker/entry.ts +4 -3
- package/src/worker/protocol.ts +16 -14
- package/src/worker/spec-contract.ts +2 -2
- package/src/worker/stdin-demux.ts +2 -2
- package/dist/chunk-D73KXYPF.js +0 -37
- package/dist/chunk-MLOK6ZOS.js +0 -2888
- package/dist/chunk-PNY46YEY.js +0 -1581
- package/dist/chunk-XDOQXGFO.js +0 -515
- package/dist/chunk-YKOFT37S.js +0 -279
- package/dist/clio-LT5V7SSZ.js +0 -26
- package/dist/configure-2WYWSCSD.js +0 -49
- package/dist/doctor-TWBWFK5V.js +0 -165
- package/src/engine/apis/degraded-inference.ts +0 -95
- /package/skills/meta/{clio-test → clio-coder-test}/references/harness.md +0 -0
- /package/skills/meta/{clio-test → clio-coder-test}/references/test-map.md +0 -0
|
@@ -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";
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one migration and refusal policy for typed dispatch intent.
|
|
3
|
+
*
|
|
4
|
+
* Typed intent (#155) is authoritative for policy-bearing scope (#158) and the
|
|
5
|
+
* legacy prose-inference path (#159) survives beside it. Those three landed the
|
|
6
|
+
* mechanism; this module owns the lifecycle question they left open: for any
|
|
7
|
+
* dispatch producer, what happens when intent is omitted, partially declared,
|
|
8
|
+
* carries a version this build does not speak, or contradicts another field on
|
|
9
|
+
* the same request.
|
|
10
|
+
*
|
|
11
|
+
* Every answer here is one of three decisions, and the boundary between them is
|
|
12
|
+
* the load-bearing rule:
|
|
13
|
+
*
|
|
14
|
+
* - `accept`: the request is unambiguous. Nothing is reported.
|
|
15
|
+
* - `warn`: the request is compatible but its policy-bearing scope was resolved
|
|
16
|
+
* from something weaker than a declaration. The dispatch proceeds with the
|
|
17
|
+
* authority it would have had anyway; the warning exists so the weaker basis
|
|
18
|
+
* is visible before execution and countable afterwards.
|
|
19
|
+
* - `refuse`: the request states two incompatible things about authority, or
|
|
20
|
+
* states one this build cannot interpret. The dispatch never runs.
|
|
21
|
+
*
|
|
22
|
+
* A `warn` may never be the difference between a narrow and a wide grant. That
|
|
23
|
+
* is the invariant every rule below is written to preserve: no path through this
|
|
24
|
+
* module widens read, write, or verification authority to resolve an ambiguity.
|
|
25
|
+
* When the compatible reading and the declared reading disagree about what a
|
|
26
|
+
* worker may touch, the answer is a refusal, never the union.
|
|
27
|
+
*
|
|
28
|
+
* The module is pure: no filesystem, no clock, no package-layout lookup. A
|
|
29
|
+
* source checkout and an installed package classify identical input identically,
|
|
30
|
+
* which is what makes the version rules verifiable rather than environmental.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { pathBoundaryCovers, resolvePathBoundary } from "../../core/path-boundary.js";
|
|
34
|
+
import { type DispatchIntent, isDispatchIntent } from "./intent.js";
|
|
35
|
+
|
|
36
|
+
/** The intent shape this build speaks. Bump with the `DispatchIntent` interface. */
|
|
37
|
+
export const DISPATCH_INTENT_VERSION = 2;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Every intent version this build accepts. Deliberately not a range: a reader
|
|
41
|
+
* that accepts "2 or newer" accepts fields it cannot interpret, and a reader
|
|
42
|
+
* that accepts "2 or older" reads a v1 declaration under v2 rules. Membership in
|
|
43
|
+
* this list is the whole test.
|
|
44
|
+
*/
|
|
45
|
+
export const DISPATCH_INTENT_SUPPORTED_VERSIONS: ReadonlyArray<number> = [DISPATCH_INTENT_VERSION];
|
|
46
|
+
|
|
47
|
+
export type DispatchIntentCompatibilityDecision = "accept" | "warn" | "refuse";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Stable reason codes. These are a contract: they appear in refusal messages,
|
|
51
|
+
* diagnostics, and contract tests, and callers may branch on them. Renaming one
|
|
52
|
+
* is a breaking change to every surface that reports dispatch admission.
|
|
53
|
+
*/
|
|
54
|
+
export type DispatchIntentCompatibilityCode =
|
|
55
|
+
/** No typed intent at all; policy-bearing scope came from legacy inference. */
|
|
56
|
+
| "intent_absent_legacy_inference"
|
|
57
|
+
/** Typed intent declared paths but no verification requirement. */
|
|
58
|
+
| "intent_partial_verification_absent"
|
|
59
|
+
/** `intent.version` names a version this build does not speak. */
|
|
60
|
+
| "intent_version_unsupported"
|
|
61
|
+
/** Present but not a normalized intent for a reason other than its version. */
|
|
62
|
+
| "intent_malformed"
|
|
63
|
+
/** Declared `intent.write_roots` and legacy `writeRoots` name different trees. */
|
|
64
|
+
| "intent_write_roots_contradiction"
|
|
65
|
+
/** A declared expected output lies outside every declared write root. */
|
|
66
|
+
| "intent_outputs_outside_write_roots"
|
|
67
|
+
/** Write roots declared on a request whose autonomy cannot write. */
|
|
68
|
+
| "intent_write_without_authority"
|
|
69
|
+
/** A narrowed intent reaches outside the intent it is supposed to narrow. */
|
|
70
|
+
| "intent_scope_widening";
|
|
71
|
+
|
|
72
|
+
export interface DispatchIntentCompatibilityFinding {
|
|
73
|
+
code: DispatchIntentCompatibilityCode;
|
|
74
|
+
decision: DispatchIntentCompatibilityDecision;
|
|
75
|
+
/** Operator-facing text, prefixed with the code and naming the fix. */
|
|
76
|
+
message: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface DispatchIntentCompatibilityInput {
|
|
80
|
+
/** The request's `intent` field exactly as the producer set it. */
|
|
81
|
+
intent?: unknown;
|
|
82
|
+
/** The request's legacy `writeRoots` field exactly as the producer set it. */
|
|
83
|
+
writeRoots?: unknown;
|
|
84
|
+
/** Request-level autonomy narrowing, when the producer set one. */
|
|
85
|
+
autonomy?: unknown;
|
|
86
|
+
/** Job cwd used to compare the two write declarations on one footing. */
|
|
87
|
+
cwd?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function finding(
|
|
91
|
+
code: DispatchIntentCompatibilityCode,
|
|
92
|
+
decision: DispatchIntentCompatibilityDecision,
|
|
93
|
+
detail: string,
|
|
94
|
+
): DispatchIntentCompatibilityFinding {
|
|
95
|
+
return { code, decision, message: `${code}: ${detail}` };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
99
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function declaredVersion(value: Record<string, unknown>): number | null {
|
|
103
|
+
return typeof value.version === "number" && Number.isInteger(value.version) ? value.version : null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Whether an intent-shaped value carries a version this build can interpret. */
|
|
107
|
+
export function isSupportedDispatchIntentVersion(value: unknown): boolean {
|
|
108
|
+
if (!isRecord(value)) return false;
|
|
109
|
+
const version = declaredVersion(value);
|
|
110
|
+
return version !== null && DISPATCH_INTENT_SUPPORTED_VERSIONS.includes(version);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function versionFinding(value: Record<string, unknown>): DispatchIntentCompatibilityFinding {
|
|
114
|
+
const version = declaredVersion(value);
|
|
115
|
+
const supported = DISPATCH_INTENT_SUPPORTED_VERSIONS.join(", ");
|
|
116
|
+
if (version === null) {
|
|
117
|
+
return finding(
|
|
118
|
+
"intent_version_unsupported",
|
|
119
|
+
"refuse",
|
|
120
|
+
`intent carries no integer version; this build speaks dispatch intent version ${supported}. Re-declare the intent through the dispatch tool rather than replaying a stored object.`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return finding(
|
|
124
|
+
"intent_version_unsupported",
|
|
125
|
+
"refuse",
|
|
126
|
+
`intent declares version ${version}; this build speaks dispatch intent version ${supported}. A stored plan or spec at another version is refused rather than migrated: re-declare read_roots, write_roots, relevant_paths, expected_outputs, and verification on a fresh dispatch call.`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function legacyWriteRoots(value: unknown): string[] | null {
|
|
131
|
+
if (!Array.isArray(value)) return null;
|
|
132
|
+
const roots = value.filter((entry): entry is string => typeof entry === "string" && entry.length > 0);
|
|
133
|
+
return roots.length === value.length ? roots : null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function writeRootsContradiction(
|
|
137
|
+
intent: DispatchIntent,
|
|
138
|
+
writeRoots: ReadonlyArray<string>,
|
|
139
|
+
cwd: string,
|
|
140
|
+
): DispatchIntentCompatibilityFinding | null {
|
|
141
|
+
const resolve = (roots: ReadonlyArray<string>): string =>
|
|
142
|
+
JSON.stringify([...new Set(roots.map((root) => resolvePathBoundary(cwd, root)))].sort());
|
|
143
|
+
if (resolve(writeRoots) === resolve(intent.writeRoots)) return null;
|
|
144
|
+
return finding(
|
|
145
|
+
"intent_write_roots_contradiction",
|
|
146
|
+
"refuse",
|
|
147
|
+
`legacy writeRoots [${[...writeRoots].sort().join(", ")}] and intent.write_roots [${intent.writeRoots.join(", ")}] name different trees. Neither the union nor the legacy field wins: drop writeRoots and declare the exact write scope once in intent.write_roots.`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function outputsOutsideWriteRoots(intent: DispatchIntent): DispatchIntentCompatibilityFinding | null {
|
|
152
|
+
if (intent.writeRoots.length === 0 || intent.expectedOutputs.length === 0) return null;
|
|
153
|
+
const outside = intent.expectedOutputs.filter((output) => !pathBoundaryCovers(intent.writeRoots, output));
|
|
154
|
+
if (outside.length === 0) return null;
|
|
155
|
+
return finding(
|
|
156
|
+
"intent_outputs_outside_write_roots",
|
|
157
|
+
"refuse",
|
|
158
|
+
`expected_outputs [${outside.join(", ")}] lie outside intent.write_roots [${intent.writeRoots.join(", ")}]. The write boundary would block exactly the outputs the task is required to produce, so add each output's root to write_roots or drop the output from the declaration.`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function writeWithoutAuthority(intent: DispatchIntent, autonomy: unknown): DispatchIntentCompatibilityFinding | null {
|
|
163
|
+
if (intent.writeRoots.length === 0 || autonomy !== "read-only") return null;
|
|
164
|
+
return finding(
|
|
165
|
+
"intent_write_without_authority",
|
|
166
|
+
"refuse",
|
|
167
|
+
`intent.write_roots [${intent.writeRoots.join(", ")}] was declared on a read-only request. A read-only worker cannot be granted the declared trees and the declaration cannot be silently dropped, because dropping it would leave the request claiming a write scope nothing enforces. Declare write_roots only on a writing request.`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Classify one dispatch request's intent against the compatibility rules.
|
|
173
|
+
*
|
|
174
|
+
* Findings are returned in a stable order: version and shape first (a value this
|
|
175
|
+
* build cannot read makes every later question meaningless), then the
|
|
176
|
+
* contradictions between intent and its neighbouring fields, then the
|
|
177
|
+
* lower-confidence notices. Callers treat any `refuse` as terminal.
|
|
178
|
+
*/
|
|
179
|
+
export function classifyDispatchIntentCompatibility(
|
|
180
|
+
input: DispatchIntentCompatibilityInput,
|
|
181
|
+
): DispatchIntentCompatibilityFinding[] {
|
|
182
|
+
const findings: DispatchIntentCompatibilityFinding[] = [];
|
|
183
|
+
if (input.intent === undefined) {
|
|
184
|
+
findings.push(
|
|
185
|
+
finding(
|
|
186
|
+
"intent_absent_legacy_inference",
|
|
187
|
+
"warn",
|
|
188
|
+
"no typed intent was declared, so policy-bearing scope was resolved from legacy writeRoots plus path-like task and briefing tokens. Inferred paths select project rules and worker context only; they never widen write or verification authority. Declare intent.read_roots, intent.write_roots, and intent.relevant_paths to make the scope exact.",
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
return findings;
|
|
192
|
+
}
|
|
193
|
+
if (!isRecord(input.intent)) {
|
|
194
|
+
findings.push(
|
|
195
|
+
finding(
|
|
196
|
+
"intent_malformed",
|
|
197
|
+
"refuse",
|
|
198
|
+
"intent must be an object carrying normalized read_roots, write_roots, relevant_paths, expected_outputs, and verification.",
|
|
199
|
+
),
|
|
200
|
+
);
|
|
201
|
+
return findings;
|
|
202
|
+
}
|
|
203
|
+
if (!isSupportedDispatchIntentVersion(input.intent)) {
|
|
204
|
+
findings.push(versionFinding(input.intent));
|
|
205
|
+
return findings;
|
|
206
|
+
}
|
|
207
|
+
if (!isDispatchIntent(input.intent)) {
|
|
208
|
+
findings.push(
|
|
209
|
+
finding(
|
|
210
|
+
"intent_malformed",
|
|
211
|
+
"refuse",
|
|
212
|
+
`intent declares supported version ${DISPATCH_INTENT_VERSION} but is not a normalized intent: path lists must be deduplicated and sorted, pathProvenance must match the declared fields exactly, and every verification entry must name a declared check with an integer timeout. Re-declare it through the dispatch tool rather than hand-building the normalized object.`,
|
|
213
|
+
),
|
|
214
|
+
);
|
|
215
|
+
return findings;
|
|
216
|
+
}
|
|
217
|
+
const intent = input.intent;
|
|
218
|
+
const cwd = typeof input.cwd === "string" && input.cwd.length > 0 ? input.cwd : process.cwd();
|
|
219
|
+
const legacy = input.writeRoots === undefined ? null : legacyWriteRoots(input.writeRoots);
|
|
220
|
+
if (legacy !== null && legacy.length > 0 && intent.writeRoots.length > 0) {
|
|
221
|
+
const contradiction = writeRootsContradiction(intent, legacy, cwd);
|
|
222
|
+
if (contradiction !== null) findings.push(contradiction);
|
|
223
|
+
}
|
|
224
|
+
const outputs = outputsOutsideWriteRoots(intent);
|
|
225
|
+
if (outputs !== null) findings.push(outputs);
|
|
226
|
+
const authority = writeWithoutAuthority(intent, input.autonomy);
|
|
227
|
+
if (authority !== null) findings.push(authority);
|
|
228
|
+
if (intent.verification.length === 0 && (intent.writeRoots.length > 0 || intent.expectedOutputs.length > 0)) {
|
|
229
|
+
findings.push(
|
|
230
|
+
finding(
|
|
231
|
+
"intent_partial_verification_absent",
|
|
232
|
+
"warn",
|
|
233
|
+
"intent declares work that changes the tree but no verification requirement, so nothing the orchestrator runs proves the change is sound. Add intent.verification entries naming declared check ids from package scripts or .clio-coder/verifiers.yaml.",
|
|
234
|
+
),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
return findings;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Every terminal refusal in a classification, in reporting order. */
|
|
241
|
+
export function dispatchIntentRefusals(
|
|
242
|
+
findings: ReadonlyArray<DispatchIntentCompatibilityFinding>,
|
|
243
|
+
): DispatchIntentCompatibilityFinding[] {
|
|
244
|
+
return findings.filter((entry) => entry.decision === "refuse");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Whether a narrowed intent stays inside the intent it narrows.
|
|
249
|
+
*
|
|
250
|
+
* Batch tasks, agent profiles, and fleet contracts may all restate scope more
|
|
251
|
+
* tightly than the call that contains them. Narrowing is monotonic: a per-task
|
|
252
|
+
* declaration may shrink the ceiling and may never reach outside it. Read scope
|
|
253
|
+
* is checked against reads plus writes because a declared write root is
|
|
254
|
+
* necessarily readable; write scope is checked against writes alone.
|
|
255
|
+
*/
|
|
256
|
+
export function dispatchIntentScopeWidening(
|
|
257
|
+
ceiling: Pick<DispatchIntent, "readRoots" | "writeRoots" | "relevantPaths">,
|
|
258
|
+
narrowed: Pick<DispatchIntent, "readRoots" | "writeRoots" | "relevantPaths">,
|
|
259
|
+
): DispatchIntentCompatibilityFinding | null {
|
|
260
|
+
const ceilings = {
|
|
261
|
+
readRoots: [...ceiling.readRoots, ...ceiling.writeRoots],
|
|
262
|
+
writeRoots: [...ceiling.writeRoots],
|
|
263
|
+
relevantPaths: [...ceiling.readRoots, ...ceiling.writeRoots, ...ceiling.relevantPaths],
|
|
264
|
+
} as const;
|
|
265
|
+
for (const field of ["readRoots", "writeRoots", "relevantPaths"] as const) {
|
|
266
|
+
const outside = narrowed[field].find((candidate) => !pathBoundaryCovers(ceilings[field], candidate));
|
|
267
|
+
if (outside === undefined) continue;
|
|
268
|
+
return finding(
|
|
269
|
+
"intent_scope_widening",
|
|
270
|
+
"refuse",
|
|
271
|
+
`${field} entry '${outside}' is outside the enclosing intent ceiling [${ceilings[field].join(", ") || "empty"}]. A narrower scope may shrink the ceiling and never reach outside it; add the path to the enclosing declaration or drop it here.`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* The retirement criterion for the legacy inference fallback.
|
|
279
|
+
*
|
|
280
|
+
* `pathScope.mode` is sealed on every receipt, so the share of dispatches still
|
|
281
|
+
* resolving policy-bearing scope from prose is measurable from evidence rather
|
|
282
|
+
* than estimated. Removal stays a separate, explicit issue; this is the gate
|
|
283
|
+
* that issue has to clear before it can be opened.
|
|
284
|
+
*/
|
|
285
|
+
export const DISPATCH_INTENT_RETIREMENT_MAX_LEGACY_SHARE = 0.02;
|
|
286
|
+
|
|
287
|
+
/** Receipts below this count cannot decide the criterion either way. */
|
|
288
|
+
export const DISPATCH_INTENT_RETIREMENT_MIN_SAMPLE = 200;
|
|
289
|
+
|
|
290
|
+
export interface DispatchIntentAdoption {
|
|
291
|
+
/** Receipts carrying a resolved path scope; receipts without one are not evidence. */
|
|
292
|
+
measured: number;
|
|
293
|
+
declared: number;
|
|
294
|
+
legacyInferred: number;
|
|
295
|
+
/** `null` when nothing was measured, so an empty window never reads as full adoption. */
|
|
296
|
+
legacyShare: number | null;
|
|
297
|
+
/** True only when the sample is large enough and the legacy share is at or under the bound. */
|
|
298
|
+
retirementReady: boolean;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Measure typed-intent adoption from sealed receipts.
|
|
303
|
+
*
|
|
304
|
+
* Reads only `pathScope.mode`. No task text, briefing prose, or declared path
|
|
305
|
+
* ever enters the aggregate, so the measurement is safe to report from a fleet
|
|
306
|
+
* whose receipts this caller may count but must not quote.
|
|
307
|
+
*/
|
|
308
|
+
export function dispatchIntentAdoption(
|
|
309
|
+
receipts: ReadonlyArray<{ pathScope?: { mode: "declared" | "legacy-inferred" } }>,
|
|
310
|
+
): DispatchIntentAdoption {
|
|
311
|
+
let declared = 0;
|
|
312
|
+
let legacyInferred = 0;
|
|
313
|
+
for (const receipt of receipts) {
|
|
314
|
+
if (receipt.pathScope === undefined) continue;
|
|
315
|
+
if (receipt.pathScope.mode === "declared") declared += 1;
|
|
316
|
+
else legacyInferred += 1;
|
|
317
|
+
}
|
|
318
|
+
const measured = declared + legacyInferred;
|
|
319
|
+
const legacyShare = measured === 0 ? null : legacyInferred / measured;
|
|
320
|
+
return {
|
|
321
|
+
measured,
|
|
322
|
+
declared,
|
|
323
|
+
legacyInferred,
|
|
324
|
+
legacyShare,
|
|
325
|
+
retirementReady:
|
|
326
|
+
measured >= DISPATCH_INTENT_RETIREMENT_MIN_SAMPLE &&
|
|
327
|
+
legacyShare !== null &&
|
|
328
|
+
legacyShare <= DISPATCH_INTENT_RETIREMENT_MAX_LEGACY_SHARE,
|
|
329
|
+
};
|
|
330
|
+
}
|