@iowarp/clio-coder 0.4.0 → 0.4.2
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 +131 -0
- package/CONTRIBUTING.md +59 -36
- package/README.md +407 -375
- package/SECURITY.md +2 -1
- package/dist/{acp-G5WJBNCT.js → acp-TMDQZDIG.js} +14 -14
- package/dist/{agents-FMV2Q5G4.js → agents-5N5NG3XG.js} +45 -34
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-3IDSJEIK.js → auth-Z5CCBXKQ.js} +22 -21
- package/dist/{builtins-XCZWXSC7.js → builtins-K6TNDT24.js} +6 -6
- package/dist/{chunk-GR5G2PVF.js → chunk-2HFQNRV3.js} +15 -10
- package/dist/{chunk-PQEFIJ36.js → chunk-2LEAKD4C.js} +1 -2
- package/dist/{chunk-HJJTYUHX.js → chunk-2NHR3NAY.js} +168 -1406
- package/dist/chunk-2X4RYJTJ.js +39 -0
- package/dist/{chunk-UXMFQ54G.js → chunk-2Z2IKEXI.js} +39 -43
- package/dist/{chunk-SST6Z5JA.js → chunk-336NSSKI.js} +1 -1
- package/dist/chunk-34BHNEE3.js +1846 -0
- package/dist/{chunk-YJX4SHTD.js → chunk-35MSIRKH.js} +9 -4
- package/dist/chunk-3EBYEESD.js +314 -0
- package/dist/{chunk-CTJ4RNAA.js → chunk-3F7VUY77.js} +2 -2
- package/dist/chunk-3KIPBMUA.js +308 -0
- package/dist/chunk-3M6DQK6S.js +362 -0
- package/dist/{chunk-BPKCPIL7.js → chunk-462T4EGZ.js} +3 -3
- package/dist/{chunk-QLFS5GO2.js → chunk-4JDLP6ZS.js} +44 -37
- package/dist/{chunk-LDQ2ZF2M.js → chunk-4O6MANBS.js} +6 -6
- package/dist/{chunk-O6TL7WWY.js → chunk-54ODD65L.js} +6 -6
- package/dist/{chunk-JDG2WCRO.js → chunk-5KW52TEP.js} +5 -5
- package/dist/{chunk-NHLBIGRH.js → chunk-5PFYMY2V.js} +41 -18
- package/dist/{chunk-P3FOHJT4.js → chunk-72GZI5EV.js} +2 -2
- package/dist/chunk-77QIVUZB.js +1334 -0
- package/dist/{chunk-HWHKMHUA.js → chunk-7BHIY2MW.js} +9 -15
- package/dist/{chunk-FWDFM5ZU.js → chunk-AK5XEFVZ.js} +3 -3
- package/dist/{chunk-VAZSBTKF.js → chunk-AZ4WMN4W.js} +2 -2
- package/dist/{chunk-B7OBL7PK.js → chunk-B74PXLU7.js} +21 -11
- package/dist/{chunk-CY6FY24N.js → chunk-B7HM5Z7T.js} +15 -15
- package/dist/{chunk-ULC6OTWO.js → chunk-BO7Y52RY.js} +88 -27
- package/dist/chunk-BTK3SSSK.js +67 -0
- package/dist/{chunk-M6L6IDJG.js → chunk-BWH6N36D.js} +1 -1
- package/dist/{chunk-DQITNCXG.js → chunk-BYMNWQ7O.js} +149 -159
- package/dist/{chunk-HI63TFOG.js → chunk-CDNVLKUX.js} +3 -3
- package/dist/{chunk-Z4TXYIEG.js → chunk-CRFOIAX3.js} +10 -10
- package/dist/{chunk-UM7N4G5A.js → chunk-CWVRRIEI.js} +2 -2
- package/dist/{chunk-3BT2XMV4.js → chunk-CYZW7JHJ.js} +53 -60
- package/dist/{chunk-BKFM6EJV.js → chunk-D4CJV46V.js} +2 -2
- package/dist/chunk-D7E7WCDF.js +27 -0
- package/dist/{chunk-X3YGUTOB.js → chunk-DYHAXKHD.js} +90 -62
- package/dist/{chunk-QBJA7R7N.js → chunk-DZAW46HP.js} +3 -3
- package/dist/{chunk-MLKNTWH2.js → chunk-DZEK6CJN.js} +22 -22
- package/dist/{chunk-K5C3NCBD.js → chunk-E7GT7O5N.js} +5 -5
- package/dist/{chunk-FQ4SKYE4.js → chunk-EBY63B7G.js} +2 -5
- package/dist/chunk-F2I26BDK.js +66 -0
- package/dist/{chunk-HLW2MRKE.js → chunk-F4EKGO4N.js} +3 -1
- package/dist/{chunk-RAPCMZL4.js → chunk-FSP7CMNU.js} +9 -1
- package/dist/{chunk-32KWKNSF.js → chunk-FVDGR2ZL.js} +4 -4
- package/dist/{chunk-TZSKNMZG.js → chunk-GTUD2WMY.js} +2 -1
- package/dist/{chunk-SJ5ZKQ4S.js → chunk-HIICAHCJ.js} +2 -2
- package/dist/chunk-HJWWJ6IL.js +184 -0
- package/dist/{chunk-WZR7K7ZX.js → chunk-HKMD33FO.js} +32 -83
- package/dist/chunk-HLAFFSEK.js +360 -0
- package/dist/{chunk-VO67MWHC.js → chunk-HRQMFLJP.js} +3 -3
- package/dist/{chunk-KFZI4NIL.js → chunk-I64IFBLB.js} +152 -31
- package/dist/{chunk-BKFJHQCA.js → chunk-I66EAJFY.js} +2 -2
- package/dist/{chunk-BUMFYQFY.js → chunk-I66ZTYNP.js} +543 -267
- package/dist/{chunk-2OQE55CK.js → chunk-I7XBWTYH.js} +2 -2
- package/dist/{chunk-GKF55TAZ.js → chunk-IDNA72AH.js} +104 -3
- package/dist/{chunk-GCSMB2KY.js → chunk-IKOZFYBN.js} +1 -1
- package/dist/{chunk-J4W7KFM7.js → chunk-IKSLQ4XV.js} +5439 -3475
- package/dist/{chunk-6DB53AJS.js → chunk-IMXMHHMQ.js} +171 -30
- package/dist/{chunk-AB44T6BB.js → chunk-JBCS7CRR.js} +8 -7
- package/dist/{chunk-BBVJUZHB.js → chunk-JIEGK6UF.js} +5 -173
- package/dist/{chunk-SP2RXXYO.js → chunk-JWJGP5DQ.js} +10 -10
- package/dist/{chunk-HZHHCK24.js → chunk-KKOJXO6R.js} +527 -325
- package/dist/chunk-KPXDY6QF.js +47 -0
- package/dist/{chunk-LQ3DZAMX.js → chunk-LJID3DYZ.js} +8 -2
- package/dist/{chunk-7MCTRUCE.js → chunk-M2DAX4F6.js} +2 -2
- package/dist/{chunk-VEO4AP2K.js → chunk-M2WXEHER.js} +4 -3
- package/dist/{chunk-YPI3QQCF.js → chunk-MCEPRMZW.js} +2 -4
- package/dist/{chunk-YDFRH54B.js → chunk-MCMZMDAC.js} +4 -4
- package/dist/{chunk-J5Q24KAG.js → chunk-MNJGS2IN.js} +5 -6
- package/dist/{chunk-76ONBSIA.js → chunk-MQXIVJ35.js} +14 -5
- package/dist/chunk-NDDGJUXD.js +81 -0
- package/dist/{chunk-TVHHYFHE.js → chunk-NEDJ26B5.js} +2 -2
- package/dist/chunk-NMJXSHBJ.js +283 -0
- package/dist/{chunk-VYMXRQI6.js → chunk-O3YUNJZ2.js} +88 -100
- package/dist/{chunk-VO2LKSTM.js → chunk-O42A54GG.js} +2 -2
- package/dist/{chunk-Z2RR6MAK.js → chunk-P75RZCJW.js} +28 -6
- package/dist/{chunk-NHCZP4K7.js → chunk-PBP4B7XR.js} +2 -2
- package/dist/{chunk-DYJP44XW.js → chunk-PGF63K6I.js} +2 -2
- package/dist/chunk-PJX3WQUQ.js +42 -0
- package/dist/{chunk-ZGVHUX3M.js → chunk-PMZVFWSR.js} +2 -2
- package/dist/{chunk-2JDWVJND.js → chunk-Q4XWMHX6.js} +5 -7
- package/dist/{chunk-W5VSYASO.js → chunk-QQLGQY2A.js} +46 -87
- package/dist/{chunk-KMVISBZR.js → chunk-RKSR6VSF.js} +1 -1
- package/dist/{chunk-C2LTL2W6.js → chunk-RLYRBIYQ.js} +463 -180
- package/dist/{chunk-4ZG3XFUR.js → chunk-S66XZJOF.js} +14 -23
- package/dist/{chunk-I5VEOC6I.js → chunk-SSEYRH53.js} +13 -14
- package/dist/chunk-SZAA6XDG.js +30 -0
- package/dist/{chunk-CODPRO7Q.js → chunk-TPEQIQIE.js} +7 -7
- package/dist/{chunk-QLL7ILRG.js → chunk-UBRFI4HS.js} +1151 -614
- package/dist/{chunk-O4XIVISU.js → chunk-UH347SHR.js} +227 -47
- package/dist/{chunk-OQBA45DZ.js → chunk-UH632ZYL.js} +2 -2
- package/dist/chunk-UXCU4E3T.js +303 -0
- package/dist/{chunk-CMZWFGD2.js → chunk-VAVR4IJY.js} +19 -15
- package/dist/{chunk-IQ7KR472.js → chunk-VIA6RFQZ.js} +8 -13
- package/dist/{chunk-V5DHCITQ.js → chunk-VKPAQYEB.js} +49 -19
- package/dist/{chunk-5LXZXPKX.js → chunk-VN3SHNBN.js} +2 -2
- package/dist/{chunk-UOSL25KY.js → chunk-VXMFAE2W.js} +1 -1
- package/dist/{chunk-3XML7CDN.js → chunk-W4YEMFBX.js} +3 -3
- package/dist/{chunk-U77AMWDL.js → chunk-W6NIE6OW.js} +44 -23
- package/dist/{chunk-BBVYXMFO.js → chunk-WNP7O5WZ.js} +2 -2
- package/dist/{chunk-QREDIESB.js → chunk-X7IARSHT.js} +15 -9
- package/dist/{chunk-3URVFKWK.js → chunk-XE3PCIXH.js} +5 -5
- package/dist/{chunk-FEFIFZTL.js → chunk-XGDPUNND.js} +2 -2
- package/dist/{chunk-F4CKPOEQ.js → chunk-XOXV5GKE.js} +119 -38
- package/dist/chunk-XQRY4DTA.js +657 -0
- package/dist/{chunk-NYS75XW5.js → chunk-YAKGTXEV.js} +5 -3
- package/dist/{chunk-NQQH3YT7.js → chunk-YJISEZKC.js} +3 -3
- package/dist/{chunk-X75E3D2N.js → chunk-ZGNYYXQ6.js} +18 -16
- package/dist/{chunk-LY4S7GJC.js → chunk-ZNT2M6TG.js} +20 -18
- package/dist/{chunk-HKIYEGME.js → chunk-ZTJUVLTU.js} +2 -2
- package/dist/{chunk-IBEBSCYA.js → chunk-ZW4HH5JJ.js} +43 -34
- package/dist/{chunk-2ANTL7MR.js → chunk-ZW55JB7N.js} +2 -2
- package/dist/cli/index.js +38 -37
- package/dist/{clio-2JXHBBY5.js → clio-7VB377CC.js} +12 -13
- package/dist/{code-nav-3YYRMYNF.js → code-nav-YVLCYA7V.js} +86 -18
- package/dist/codewiki/build-worker.js +1 -1
- package/dist/{compile-cache-7FPE6PS3.js → compile-cache-OQAVB7Y5.js} +2 -4
- package/dist/{components-RYZV4JGP.js → components-UBWCQSRW.js} +4 -4
- package/dist/{config-QZPCMYSO.js → config-4HVOS65E.js} +112 -63
- package/dist/{configure-TEGEBYCA.js → configure-PIWO7B24.js} +25 -22
- package/dist/{context-E6H5RNMC.js → context-IYEHL3WQ.js} +53 -47
- package/dist/{context-GSXUE4CT.js → context-KQYIWPWT.js} +68 -42
- package/dist/{context-AV7OEZ4D.js → context-N6ZE3LGJ.js} +11 -11
- package/dist/{context-clear-SHIBYK6T.js → context-clear-G4OGZJDS.js} +53 -47
- package/dist/{context-working-set-5ZGKPGZQ.js → context-working-set-BWLF6LJP.js} +12 -11
- package/dist/{dispatch-runner-EFMJT4LD.js → dispatch-runner-2QQAITS3.js} +67 -58
- package/dist/{docs-23KQS3XK.js → docs-PD3EXDKU.js} +20 -25
- package/dist/doctor-LHBD36VU.js +773 -0
- package/dist/{eval-TFBYQH4H.js → eval-C45FYRJ6.js} +68 -49
- package/dist/{eval-inventory-SXH7PDKX.js → eval-inventory-6DEJPLBF.js} +7 -8
- package/dist/{evidence-ERGESKGN.js → evidence-6SHONYAF.js} +50 -44
- package/dist/{evolve-VDXTSYCJ.js → evolve-KRKMV72X.js} +49 -43
- package/dist/{extensions-7BGBHN57.js → extensions-KPZ2UHBB.js} +8 -6
- package/dist/{fleet-2RRVDF2V.js → fleet-IVTCKDHT.js} +93 -79
- package/dist/{fleet-commands-VJ726XIA.js → fleet-commands-EDWL3IT7.js} +10 -9
- package/dist/{fleet-decisions-EPAPM3XJ.js → fleet-decisions-YP3YEFGK.js} +6 -6
- package/dist/{fleet-graph-JF5QOATM.js → fleet-graph-ZFWKHY2M.js} +19 -15
- package/dist/{fleet-inspect-VLY4S7QM.js → fleet-inspect-FVUNCBML.js} +50 -45
- package/dist/{fleet-preflight-AIZUEJOY.js → fleet-preflight-UN5XED4R.js} +5 -9
- package/dist/{fleet-validate-AJRPDMDV.js → fleet-validate-XOWC4HSX.js} +22 -17
- package/dist/{fleet-verify-JFEL2L3H.js → fleet-verify-UN3SODEL.js} +48 -43
- package/dist/fleet-view-TWHJKCN6.js +96 -0
- package/dist/{init-DN2WWLFE.js → init-T2QORQ3Y.js} +72 -66
- package/dist/{install-XGLBQY5E.js → install-NKNG7KD4.js} +2 -2
- package/dist/{interop-OZBKXAYL.js → interop-IN5I2A66.js} +13 -11
- package/dist/{library-YWZG7IMW.js → library-LSCATDLZ.js} +23 -18
- package/dist/{memory-I4C4HMLW.js → memory-HYOKAGGJ.js} +51 -45
- package/dist/{models-CEYXJBO6.js → models-2GPMFYCM.js} +42 -33
- package/dist/{monitor-NZ6GCI3P.js → monitor-E4ASVUJH.js} +56 -50
- package/dist/{orchestrator-GCGQ4N5I.js → orchestrator-DDMPR3PY.js} +2676 -1507
- package/dist/{panes-KY6W3V2E.js → panes-E3RUXOW5.js} +5 -5
- package/dist/panes-IXKLOKA2.js +75 -0
- package/dist/{paths-II4K7DNR.js → paths-L7LGY6RN.js} +4 -4
- package/dist/{reset-DQ6FGCSH.js → reset-OAQP3W4O.js} +7 -8
- package/dist/{resources-BB3MVJMD.js → resources-OTRSN34L.js} +23 -17
- package/dist/{run-H2GQDUER.js → run-5DEYH5QK.js} +95 -84
- package/dist/{share-GTJN6A5O.js → share-IHWTLO3M.js} +26 -19
- package/dist/{skills-L55TEW6R.js → skills-IYMXMKW4.js} +25 -20
- package/dist/{skills-eval-XVXPH2JI.js → skills-eval-DROHSJAR.js} +63 -65
- package/dist/{skills-inventory-S4MXPJFV.js → skills-inventory-D7X4L4ZX.js} +21 -16
- package/dist/{slash-commands-ZSGASKJC.js → slash-commands-QBM7UZ3B.js} +38 -33
- package/dist/{steer-RZGSCY4R.js → steer-Z5DO23FJ.js} +3 -3
- package/dist/{support-PKEUNNQL.js → support-U7QOWY26.js} +6 -6
- package/dist/{targets-NCPZ644J.js → targets-P2FUC4IL.js} +64 -61
- package/dist/{terminal-lease-44SV3YCN.js → terminal-lease-YREJ3JX2.js} +15 -10
- package/dist/{tools-DAF3DI3C.js → tools-5B7RO6MV.js} +10 -8
- package/dist/{trace-FYVW2MQA.js → trace-YMGMUM6A.js} +101 -8
- package/dist/{tui-primitives-2AKXQNZK.js → tui-primitives-K5PASC3O.js} +8 -4
- package/dist/{uninstall-DW2PNOIC.js → uninstall-N34PCTGJ.js} +4 -6
- package/dist/{upgrade-3XPP6OQL.js → upgrade-PXK3S2YM.js} +36 -61
- package/dist/{usage-3NLHGTU2.js → usage-ME5MPXGX.js} +58 -53
- package/dist/{verifiers-SSQONKRT.js → verifiers-BVZ7IWOO.js} +10 -9
- package/dist/{verify-3U6J7FZI.js → verify-5K7ZKQFC.js} +9 -8
- package/dist/{web-fetch-S7RR6GZ7.js → web-fetch-MPARV2K7.js} +2 -3
- package/dist/{wiki-generate-CEHYGPGQ.js → wiki-generate-F5W5QTYY.js} +74 -70
- package/dist/{with-panes-MKB46MPQ.js → with-panes-BYOJCLAM.js} +78 -246
- package/dist/worker/entry.js +83 -63
- package/docs/README.md +176 -81
- package/docs/{acp.md → architecture/acp.md} +36 -20
- package/docs/{alcf-provider.md → architecture/alcf-provider.md} +8 -5
- package/docs/{architecture.md → architecture/architecture.md} +43 -22
- package/docs/{artifact-placement.md → architecture/artifact-placement.md} +26 -23
- package/docs/architecture/artifact-versions.md +90 -0
- package/docs/{capacity-and-scheduling.md → architecture/capacity-and-scheduling.md} +26 -13
- package/docs/{context-engine.md → architecture/context-engine.md} +25 -25
- package/docs/{context-working-set.md → architecture/context-working-set.md} +13 -10
- package/docs/{dispatch-architecture-rationale.md → architecture/dispatch-architecture-rationale.md} +12 -9
- package/docs/{dispatch-typed-intent.md → architecture/dispatch-typed-intent.md} +68 -46
- package/docs/{evidence-and-memory.md → architecture/evidence-and-memory.md} +23 -16
- package/docs/{middleware-and-components.md → architecture/middleware-and-components.md} +11 -5
- package/docs/{model-catalog.md → architecture/model-catalog.md} +40 -17
- package/docs/{observability.md → architecture/observability.md} +26 -13
- package/docs/{pi-boundary.md → architecture/pi-boundary.md} +24 -11
- package/docs/{prompt-envelope-and-tools.md → architecture/prompt-envelope-and-tools.md} +55 -20
- package/docs/{provider-adapter-cookbook.md → architecture/provider-adapter-cookbook.md} +35 -24
- package/docs/{safety-model.md → architecture/safety-model.md} +20 -15
- package/docs/{session-lifecycle.md → architecture/session-lifecycle.md} +8 -5
- package/docs/architecture/time-conventions.md +125 -0
- package/docs/{trace-store.md → architecture/trace-store.md} +26 -13
- package/docs/{tui-design.md → architecture/tui-design.md} +13 -13
- package/docs/{worker-dispatch-mechanics.md → architecture/worker-dispatch-mechanics.md} +27 -30
- package/docs/{built-in-agents.md → guide/built-in-agents.md} +70 -46
- package/docs/{commands-and-modes.md → guide/commands-and-modes.md} +73 -62
- package/docs/{configuration-and-targets.md → guide/configuration-and-targets.md} +323 -444
- package/docs/guide/configuration-reference.md +1158 -0
- package/docs/{environment-variables.md → guide/environment-variables.md} +31 -27
- package/docs/{exit-codes-and-output.md → guide/exit-codes-and-output.md} +8 -3
- package/docs/{extensions-and-sharing.md → guide/extensions-and-sharing.md} +41 -14
- package/docs/{fleet-dispatch.md → guide/fleet-dispatch.md} +47 -49
- package/docs/{glossary.md → guide/glossary.md} +14 -11
- package/docs/{installation-and-lifecycle.md → guide/installation-and-lifecycle.md} +45 -14
- package/docs/guide/panes-and-files.md +290 -0
- package/docs/{proactive-memory.md → guide/proactive-memory.md} +79 -66
- package/docs/{resource-library.md → guide/resource-library.md} +13 -4
- package/docs/{skills-marketplace.md → guide/skills-marketplace.md} +7 -3
- package/docs/{tool-usage.md → guide/tool-usage.md} +87 -23
- package/docs/{troubleshooting.md → guide/troubleshooting.md} +10 -5
- package/docs/{config-knobs-audit.md → history/config-knobs-audit.md} +13 -10
- package/docs/history/release-cut-checklist.md +207 -0
- package/docs/{development-pipeline.md → process/development-pipeline.md} +24 -26
- package/docs/process/documentation-coverage.md +100 -0
- package/docs/process/documentation-guide.md +187 -0
- package/docs/{eval-runner.md → process/eval-runner.md} +41 -50
- package/docs/{evals-internal.md → process/evals-internal.md} +10 -10
- package/docs/{evolution.md → process/evolution.md} +2 -2
- package/docs/{fleet-demo-runbook.md → process/fleet-demo-runbook.md} +17 -10
- package/docs/{git-commit-provenance.md → process/git-commit-provenance.md} +11 -4
- package/docs/{performance-methodology.md → process/performance-methodology.md} +87 -69
- package/docs/{scientific-validation.md → process/scientific-validation.md} +4 -4
- 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 +13 -21
- package/skills/README.md +51 -42
- package/skills/coding/ast-grep/SKILL.md +9 -3
- package/skills/coding/coding-standards/SKILL.md +9 -3
- package/skills/coding/prototype/SKILL.md +9 -3
- package/skills/coding/tdd/SKILL.md +9 -3
- package/skills/context/context-handoff/SKILL.md +13 -4
- package/skills/context/context-handoff/evals.md +3 -3
- package/skills/context/context-prime/SKILL.md +9 -3
- package/skills/context/context-prime/evals.md +2 -2
- package/skills/git/file-ticket/SKILL.md +10 -5
- 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 +9 -3
- package/skills/git/resolve-merge-conflicts/evals.md +2 -2
- package/skills/git/ship/SKILL.md +10 -4
- package/skills/git/ship/evals.md +4 -4
- package/skills/git/worktree-create/SKILL.md +8 -3
- package/skills/git/worktree-create/evals.md +6 -6
- package/skills/git/worktree-merge/SKILL.md +8 -3
- package/skills/git/worktree-merge/evals.md +6 -6
- package/skills/meta/{clio-dev → clio-coder-dev}/SKILL.md +22 -12
- package/skills/meta/{clio-dev → clio-coder-dev}/evals.md +5 -4
- package/skills/meta/clio-coder-test/SKILL.md +146 -0
- package/skills/meta/{clio-test → clio-coder-test}/evals.md +10 -5
- package/skills/meta/clio-coder-test/references/harness.md +102 -0
- package/skills/meta/clio-coder-test/references/test-map.md +96 -0
- package/skills/meta/credentials/SKILL.md +10 -3
- package/skills/meta/find-skills/SKILL.md +9 -3
- package/skills/meta/herdr/SKILL.md +9 -3
- package/skills/meta/skill-craft/SKILL.md +39 -16
- package/skills/planning/architecture/SKILL.md +9 -3
- package/skills/planning/backlog/SKILL.md +9 -3
- package/skills/planning/prd/SKILL.md +9 -3
- package/skills/planning/product-intent/SKILL.md +9 -3
- package/skills/planning/tech-spec/SKILL.md +9 -3
- package/skills/registry.yaml +66 -66
- package/skills/research/arxiv-literature/SKILL.md +9 -3
- package/skills/research/experiment-protocol/SKILL.md +10 -3
- package/skills/research/scientific-debugging/SKILL.md +10 -3
- package/skills/research/scientific-debugging/evals.md +2 -2
- package/skills/research/scientific-modernization/SKILL.md +10 -3
- package/skills/skill-marketplace.json +285 -66
- package/skills/workflow/cut-it/SKILL.md +11 -3
- package/skills/workflow/design-council/SKILL.md +12 -3
- package/skills/workflow/grill-me/SKILL.md +9 -3
- package/skills/workflow/workflow-distiller/SKILL.md +9 -3
- package/src/cli/acp.ts +2 -2
- package/src/cli/args.ts +2 -2
- package/src/cli/auth.ts +2 -2
- package/src/cli/bootstrap-generate.ts +6 -6
- package/src/cli/clio.ts +6 -1
- package/src/cli/config-inspect.ts +68 -15
- package/src/cli/configure-interop.ts +1 -1
- package/src/cli/configure.ts +27 -31
- package/src/cli/default-target.ts +1 -1
- package/src/cli/docs.ts +28 -20
- package/src/cli/doctor-naming.ts +323 -0
- package/src/cli/doctor-panes.ts +46 -14
- package/src/cli/doctor-toolchain.ts +31 -10
- package/src/cli/doctor.ts +15 -1
- package/src/cli/eval-inventory.ts +8 -8
- package/src/cli/eval.ts +1 -2
- package/src/cli/evidence-detail.ts +1 -1
- package/src/cli/evidence-inventory.ts +1 -1
- package/src/cli/extensions.ts +2 -1
- package/src/cli/fleet-decisions.ts +1 -1
- package/src/cli/fleet-inspect.ts +1 -1
- package/src/cli/fleet-preflight.ts +1 -1
- package/src/cli/fleet-verify.ts +1 -1
- package/src/cli/fleet-view.ts +40 -23
- package/src/cli/fleet.ts +9 -6
- package/src/cli/index.ts +2 -1
- package/src/cli/internal-dispatch.ts +3 -4
- package/src/cli/interop-inspect.ts +2 -2
- package/src/cli/models.ts +3 -3
- package/src/cli/modes/print.ts +1 -1
- package/src/cli/panes.ts +19 -5
- package/src/cli/reset.ts +1 -1
- package/src/cli/run.ts +13 -17
- package/src/cli/share.ts +6 -2
- package/src/cli/skills-eval.ts +14 -14
- package/src/cli/targets.ts +25 -30
- package/src/cli/trace-inspect.ts +1 -1
- package/src/cli/trace.ts +96 -4
- 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 +1 -1
- package/src/cli/wiki-generate.ts +6 -6
- package/src/core/artifact-paths.ts +1 -1
- package/src/core/bash-exec.ts +132 -87
- package/src/core/boot-trace.ts +3 -3
- package/src/core/bus-events.ts +51 -6
- package/src/core/bus-trace.ts +2 -2
- package/src/core/compile-cache.ts +1 -1
- package/src/core/config.ts +1066 -886
- package/src/core/defaults.ts +326 -530
- package/src/core/dispatch-outcome.ts +16 -0
- 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 +33 -52
- package/src/core/naming-compat.ts +45 -0
- package/src/core/naming-events.ts +62 -0
- package/src/core/prompt-hint.ts +9 -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/session-routing.ts +84 -74
- package/src/core/skill-activation.ts +18 -0
- package/src/core/termination.ts +4 -4
- package/src/core/timers.ts +2 -12
- package/src/domains/agents/builtins/architect.md +2 -3
- package/src/domains/agents/builtins/coder.md +3 -2
- package/src/domains/agents/builtins/debugger.md +2 -2
- package/src/domains/agents/builtins/documenter.md +2 -2
- package/src/domains/agents/builtins/git-master.md +1 -1
- package/src/domains/agents/builtins/oracle.md +1 -1
- package/src/domains/agents/builtins/provenance.md +1 -1
- package/src/domains/agents/builtins/researcher.md +1 -1
- package/src/domains/agents/builtins/scout.md +1 -1
- package/src/domains/agents/builtins/tester.md +2 -2
- package/src/domains/agents/builtins/verifier.md +2 -2
- package/src/domains/agents/builtins/wiki-writer.md +1 -1
- package/src/domains/agents/catalog.ts +14 -26
- package/src/domains/agents/contract.ts +2 -0
- package/src/domains/agents/extension.ts +26 -4
- package/src/domains/agents/registry.ts +7 -7
- package/src/domains/agents/result-contract.ts +1 -1
- package/src/domains/agents/spec.ts +0 -11
- package/src/domains/config/classify.ts +35 -47
- package/src/domains/config/extension.ts +5 -5
- package/src/domains/config/keybindings.ts +56 -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 -6
- package/src/domains/context/prompt-context.ts +1 -1
- package/src/domains/context/wiki/assemble.ts +2 -2
- package/src/domains/context/working-set/path-index.ts +1 -0
- 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/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/capability-match.ts +10 -0
- package/src/domains/dispatch/capacity-lease.ts +2 -5
- package/src/domains/dispatch/code-step.ts +1 -1
- package/src/domains/dispatch/contract.ts +2 -2
- package/src/domains/dispatch/extension.ts +169 -82
- package/src/domains/dispatch/fleet-node-prompt.ts +1 -1
- package/src/domains/dispatch/fleet-preflight.ts +8 -17
- package/src/domains/dispatch/fleet-run.ts +0 -7
- package/src/domains/dispatch/gate-decisions.ts +25 -14
- package/src/domains/dispatch/host-verification.ts +435 -39
- package/src/domains/dispatch/intent-requirements.ts +10 -0
- package/src/domains/dispatch/intent.ts +18 -1
- package/src/domains/dispatch/joint-route-resolver.ts +1 -1
- package/src/domains/dispatch/path-scope.ts +220 -70
- 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 +0 -23
- 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.ts +9 -19
- package/src/domains/dispatch/state.ts +2 -3
- package/src/domains/dispatch/tool-stats.ts +1 -1
- package/src/domains/dispatch/transport.ts +47 -40
- package/src/domains/dispatch/types.ts +58 -6
- package/src/domains/dispatch/worker-protocol.ts +2 -2
- package/src/domains/eval/artifacts/store.ts +10 -4
- package/src/domains/eval/compare/thresholds.ts +0 -8
- package/src/domains/eval/execution-provenance.ts +1 -1
- 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/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 +20 -3
- 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/trust-status.ts +10 -1
- package/src/domains/extensions/contract.ts +15 -1
- package/src/domains/extensions/discovery.ts +238 -41
- package/src/domains/extensions/extension.ts +105 -6
- package/src/domains/extensions/index.ts +24 -0
- package/src/domains/extensions/integrity.ts +189 -0
- package/src/domains/extensions/manager.ts +17 -1
- package/src/domains/extensions/resource-path.ts +27 -0
- package/src/domains/extensions/resources.ts +18 -38
- package/src/domains/extensions/snapshot-store.ts +39 -0
- package/src/domains/extensions/snapshot.ts +180 -0
- package/src/domains/extensions/state.ts +385 -57
- package/src/domains/extensions/types.ts +118 -1
- 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-extension-install-digests.ts +27 -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 +22 -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 +276 -0
- package/src/domains/lifecycle/naming-tool-markers.ts +139 -0
- package/src/domains/lifecycle/naming-yazi.ts +86 -0
- package/src/domains/lifecycle/upgrade-notice.ts +1 -1
- package/src/domains/memory/task-memory-handoff.ts +6 -3
- package/src/domains/middleware/contract.ts +26 -0
- package/src/domains/middleware/extension.ts +24 -24
- package/src/domains/middleware/hook-receipts.ts +27 -4
- package/src/domains/middleware/hooks-io.ts +65 -32
- package/src/domains/middleware/hooks.ts +64 -0
- package/src/domains/middleware/index.ts +35 -4
- package/src/domains/middleware/marketplace-offer.ts +339 -0
- package/src/domains/middleware/registrations.ts +326 -0
- package/src/domains/middleware/runtime.ts +30 -2
- package/src/domains/middleware/snapshot.ts +20 -7
- package/src/domains/mux/contract.ts +195 -25
- package/src/domains/mux/detect.ts +23 -6
- package/src/domains/mux/dock-controller.ts +365 -0
- package/src/domains/mux/extension.ts +7 -1
- package/src/domains/mux/index.ts +21 -1
- package/src/domains/mux/operations.ts +72 -5
- package/src/domains/mux/protocol.ts +19 -6
- package/src/domains/mux/socket-client.ts +167 -19
- package/src/domains/mux/types.ts +49 -6
- package/src/domains/mux/yazi/assets/yazi.toml +2 -2
- package/src/domains/mux/yazi/event-stream.ts +6 -4
- package/src/domains/mux/yazi/profile.ts +1 -1
- package/src/domains/mux/yazi/session.ts +79 -7
- package/src/domains/mux/yazi/theme.ts +117 -17
- package/src/domains/observability/contract.ts +10 -11
- package/src/domains/observability/extension.ts +12 -4
- package/src/domains/observability/out-of-turn-usage.ts +2 -2
- package/src/domains/observability/projection.ts +15 -91
- package/src/domains/observability/trace-store.ts +65 -19
- package/src/domains/prompts/compiler.ts +75 -55
- package/src/domains/prompts/contract.ts +15 -3
- package/src/domains/prompts/extension.ts +100 -12
- package/src/domains/prompts/fragments/identity/clio-worker.md +2 -4
- package/src/domains/prompts/fragments/identity/clio.md +6 -12
- package/src/domains/prompts/fragments/identity/docs-routing.md +1 -2
- package/src/domains/prompts/fragments/identity/self-awareness.md +3 -11
- package/src/domains/prompts/fragments/operating/contract.md +7 -15
- package/src/domains/prompts/fragments/operating/delegation.md +32 -34
- package/src/domains/prompts/fragments/operating/skills.md +11 -18
- package/src/domains/prompts/fragments/operating/worker.md +1 -8
- package/src/domains/providers/extension.ts +5 -5
- package/src/domains/providers/index.ts +1 -1
- package/src/domains/providers/knowledge-base-path.ts +1 -1
- package/src/domains/providers/model-runtime-capabilities.ts +99 -23
- 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} +671 -106
- package/src/domains/providers/plugins.ts +1 -1
- package/src/domains/providers/resolver.ts +1 -1
- package/src/domains/providers/runtime-resolution.ts +31 -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 +9 -4
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +9 -1
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +2 -9
- package/src/domains/providers/runtimes/protocol/litellm.ts +1 -91
- package/src/domains/providers/types/cost-provenance.ts +19 -0
- package/src/domains/providers/types/knowledge-base.ts +13 -0
- package/src/domains/providers/types/local-model-quirks.ts +87 -39
- package/src/domains/providers/types/target-descriptor.ts +3 -3
- package/src/domains/resources/extension.ts +1 -1
- 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 +41 -18
- package/src/domains/resources/skills/marketplace.ts +21 -2
- package/src/domains/resources/skills/promotion.ts +214 -0
- package/src/domains/safety/audit.ts +2 -2
- package/src/domains/safety/call-target.ts +1 -1
- package/src/domains/safety/finish-contract.ts +2 -1
- package/src/domains/safety/loop-detector.ts +7 -4
- 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/session/task-board.ts +10 -9
- package/src/domains/share/archive.ts +249 -43
- package/src/domains/toolchain/install.ts +1 -1
- package/src/engine/acp/adapter.ts +3 -3
- package/src/engine/acp/event-mapper.ts +3 -3
- package/src/engine/acp/server.ts +89 -35
- package/src/engine/acp/tool-mediator.ts +2 -2
- package/src/engine/acp/types.ts +1 -1
- 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 +4 -23
- package/src/engine/apis/lmstudio.ts +4 -9
- package/src/engine/apis/ollama-native.ts +9 -9
- package/src/engine/apis/openai-completions.ts +30 -27
- package/src/engine/apis/output-budget.ts +8 -18
- package/src/engine/apis/residency.ts +10 -35
- package/src/engine/claude/sdk-module.ts +1 -12
- package/src/engine/claude/sdk-runtime.ts +6 -6
- package/src/engine/claude/subprocess-runtime.ts +1 -1
- package/src/engine/claude/tool-safety.ts +4 -4
- package/src/engine/gemma-channel-filter.ts +19 -0
- package/src/engine/loop-guard.ts +92 -17
- package/src/engine/session.ts +14 -7
- package/src/engine/tui-primitives.ts +1 -1
- package/src/engine/worker-events.ts +6 -6
- package/src/engine/worker-runtime.ts +54 -24
- package/src/engine/worker-tools.ts +3 -1
- package/src/entry/extension-hook-sources.ts +28 -0
- package/src/entry/extension-reload.ts +309 -0
- package/src/entry/orchestrator.ts +163 -120
- package/src/interactive/application-controller.ts +23 -22
- package/src/interactive/bus-notices.ts +10 -3
- package/src/interactive/chat-loop-messages.ts +3 -13
- package/src/interactive/chat-loop.ts +18 -9
- package/src/interactive/chat-panel.ts +37 -14
- package/src/interactive/chat-renderer.ts +71 -7
- 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 +1 -1
- package/src/interactive/cost-overlay.ts +1 -1
- package/src/interactive/council-grid.ts +2 -2
- package/src/interactive/dispatch-board.ts +36 -44
- 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 +15 -44
- package/src/interactive/interactive-application.ts +116 -61
- package/src/interactive/interactive-event-projection.ts +1 -1
- package/src/interactive/interactive-input-runtime.ts +6 -2
- package/src/interactive/interactive-presentation.ts +22 -17
- package/src/interactive/interactive-shell.ts +2 -2
- package/src/interactive/interactive-slash-runtime.ts +65 -17
- 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 +2 -2
- package/src/interactive/modal-marker.ts +2 -21
- package/src/interactive/mutation-preview.ts +1 -1
- package/src/interactive/overlay-frame.ts +4 -12
- package/src/interactive/overlay-general-openers.ts +6 -2
- package/src/interactive/overlay-key-routing.ts +7 -7
- package/src/interactive/overlay-lifecycle.ts +1 -1
- package/src/interactive/overlay-model-selectors.ts +3 -3
- package/src/interactive/overlays/agents.ts +2 -2
- package/src/interactive/overlays/ask-user.ts +25 -11
- package/src/interactive/overlays/context-reset.ts +28 -4
- package/src/interactive/overlays/cwd-fallback.ts +28 -4
- package/src/interactive/overlays/decisions.ts +4 -2
- package/src/interactive/overlays/extensions.ts +9 -1
- package/src/interactive/overlays/fleet-run-approval.ts +3 -3
- package/src/interactive/overlays/handoff-review.ts +2 -2
- package/src/interactive/overlays/help-reference.ts +13 -0
- package/src/interactive/overlays/interop.ts +1 -1
- package/src/interactive/overlays/library-install-confirm.ts +1 -1
- package/src/interactive/overlays/message-picker.ts +1 -1
- package/src/interactive/overlays/model-selector.ts +39 -31
- package/src/interactive/overlays/prompts.ts +10 -4
- package/src/interactive/overlays/session-selector.ts +2 -2
- package/src/interactive/overlays/settings.ts +360 -303
- package/src/interactive/overlays/side-question.ts +2 -2
- package/src/interactive/overlays/skills-hub.ts +8 -8
- package/src/interactive/overlays/tree-selector.ts +2 -2
- package/src/interactive/panes-runtime.ts +145 -43
- package/src/interactive/permission-overlay.ts +2 -2
- package/src/interactive/prompt-cache-identity.ts +88 -0
- package/src/interactive/renderers/retry-status.ts +12 -4
- package/src/interactive/renderers/tool-execution.ts +4 -4
- package/src/interactive/session-transcript.ts +3 -3
- package/src/interactive/slash-autocomplete.ts +454 -165
- package/src/interactive/slash-commands.ts +401 -190
- package/src/interactive/slash-spec.ts +160 -17
- package/src/interactive/status/controller.ts +2 -2
- package/src/interactive/stream-pacing-policy.ts +1 -24
- package/src/interactive/tasks-overlay.ts +20 -13
- package/src/interactive/terminal-lease.ts +6 -7
- package/src/interactive/turn-context.ts +41 -26
- 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 +12 -9
- package/src/interactive/view/view-overlay.ts +13 -10
- package/src/interactive/watch-pane.ts +38 -10
- package/src/interactive/welcome-dashboard.ts +15 -15
- package/src/interactive/worker-progress.ts +4 -4
- package/src/interactive/worker-receipts.ts +1 -1
- package/src/interactive/worker-stream.ts +1 -4
- package/src/interactive/yazi-bridge.ts +72 -11
- package/src/tools/agent-tools.ts +30 -1
- package/src/tools/artifact.ts +2 -2
- package/src/tools/ask-user.ts +6 -6
- package/src/tools/bash.ts +2 -2
- package/src/tools/bootstrap.ts +4 -0
- package/src/tools/builtin-tool-catalog.ts +52 -22
- package/src/tools/codewiki/code-nav-surface.ts +6 -0
- package/src/tools/codewiki/code-nav.ts +99 -13
- package/src/tools/compete-worktrees.ts +27 -17
- package/src/tools/context/docs-engine.ts +20 -7
- package/src/tools/context/index.ts +44 -13
- package/src/tools/core-bootstrap.ts +28 -6
- package/src/tools/credential-present.ts +1 -2
- package/src/tools/dispatch-admission.ts +4 -2
- package/src/tools/dispatch-arguments.ts +6 -2
- package/src/tools/dispatch-plan.ts +48 -15
- package/src/tools/dispatch-run-events.ts +13 -11
- package/src/tools/dispatch-runner.ts +11 -6
- package/src/tools/dispatch-schema.ts +338 -0
- package/src/tools/dispatch-types.ts +3 -0
- package/src/tools/dispatch.ts +9 -254
- package/src/tools/find.ts +1 -6
- package/src/tools/ledger.ts +3 -5
- package/src/tools/monitor-surface.ts +5 -13
- package/src/tools/monitor.ts +4 -4
- package/src/tools/observation.ts +4 -5
- package/src/tools/observers.ts +0 -33
- package/src/tools/panes-surface.ts +4 -11
- package/src/tools/panes.ts +4 -2
- package/src/tools/policy.ts +15 -2
- package/src/tools/read.ts +5 -6
- package/src/tools/registry.ts +30 -7
- package/src/tools/result-shaping.ts +18 -14
- package/src/tools/steer-surface.ts +1 -1
- package/src/tools/task-worktree.ts +28 -7
- package/src/tools/tasks.ts +1 -1
- package/src/tools/truncate.ts +6 -5
- package/src/tools/verify/authoring.ts +3 -6
- package/src/tools/verify/frontend.ts +1 -1
- package/src/tools/verify/surface.ts +6 -12
- package/src/tools/web-fetch-surface.ts +1 -3
- 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-36EJLSQQ.js +0 -814
- package/dist/chunk-GXNLGKAB.js +0 -571
- package/dist/chunk-K7VKOLQQ.js +0 -15
- package/dist/chunk-PMZCIOCJ.js +0 -25
- package/dist/chunk-SUCTJL45.js +0 -45
- package/dist/chunk-SUW5DORT.js +0 -819
- package/dist/chunk-TZ3SGWZZ.js +0 -48
- package/dist/chunk-UOV2BYIW.js +0 -107
- package/dist/chunk-VFA6GDY5.js +0 -1625
- package/dist/doctor-QOA5FNY5.js +0 -313
- package/dist/fleet-view-ZCON35AG.js +0 -102
- package/dist/panes-HMABYVO4.js +0 -58
- package/docs/artifact-versions.md +0 -67
- package/docs/documentation-coverage.md +0 -46
- package/docs/documentation-guide.md +0 -167
- package/docs/release-cut-checklist.md +0 -193
- package/docs/time-conventions.md +0 -101
- package/skills/meta/clio-test/SKILL.md +0 -133
- package/skills/meta/clio-test/references/harness.md +0 -126
- package/skills/meta/clio-test/references/test-map.md +0 -69
- package/src/engine/apis/degraded-inference.ts +0 -95
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
SKILL_INSTALL_OFFER_OPTION_NEVER,
|
|
4
|
+
SKILL_INSTALL_OFFER_OPTION_NOT_NOW,
|
|
5
|
+
SKILL_INSTALL_OFFER_OPTION_PROJECT,
|
|
6
|
+
SKILL_INSTALL_OFFER_OPTION_USER,
|
|
7
|
+
} from "../../core/skill-activation.js";
|
|
8
|
+
import { ToolNames } from "../../core/tool-names.js";
|
|
9
|
+
import type { MarketplaceSkill } from "../resources/skills/marketplace.js";
|
|
10
|
+
import {
|
|
11
|
+
assertPromotionInstallSource,
|
|
12
|
+
declineKey,
|
|
13
|
+
matchMarketplaceSkills,
|
|
14
|
+
type PromotionMatch,
|
|
15
|
+
readPromotionDeclines,
|
|
16
|
+
recordPromotionNeverDecline,
|
|
17
|
+
} from "../resources/skills/promotion.js";
|
|
18
|
+
import type { AutonomyLevel } from "../safety/autonomy.js";
|
|
19
|
+
import type { MiddlewareHookRegistration } from "./runtime.js";
|
|
20
|
+
import { isSubstantiveUserTurn } from "./skills-reminder.js";
|
|
21
|
+
import { type MiddlewareEffect, type MiddlewareHookInput, metadataNumber } from "./types.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Marketplace self-promotion offer. When the operator's request needs
|
|
25
|
+
* expertise no installed skill covers and the local marketplace has a match,
|
|
26
|
+
* this registration teaches the model to put one tight ask_user question to
|
|
27
|
+
* the operator; the after_tool observer then acts on the answer — a consented
|
|
28
|
+
* install runs harness-side through the injected installer, "Not now" is a
|
|
29
|
+
* session-only decline, and "Never offer this skill" persists.
|
|
30
|
+
*
|
|
31
|
+
* Firing is need-driven, not count-budgeted: any substantive turn whose text
|
|
32
|
+
* matches an uninstalled, undeclined marketplace skill may fire, but each
|
|
33
|
+
* skill is offered at most once per session so a repeated request never
|
|
34
|
+
* becomes a nag. Detection is the local lexical matcher in
|
|
35
|
+
* resources/skills/promotion.ts — no request text leaves the machine.
|
|
36
|
+
*
|
|
37
|
+
* At full-auto the offer collapses into an autonomous install, but ONLY from
|
|
38
|
+
* Clio's own marketplace: every promotion-flow install (consented or
|
|
39
|
+
* autonomous) passes `assertPromotionInstallSource`, the hard runtime gate
|
|
40
|
+
* that rejects public registries in code rather than prompt text.
|
|
41
|
+
*
|
|
42
|
+
* Coordinator-only by wiring: this registration is created in the
|
|
43
|
+
* orchestrator entry and never in a dispatch worker's loop, so workers can
|
|
44
|
+
* neither see nor trigger offers.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
export const MARKETPLACE_OFFER_REGISTRATION_ID = "observer.marketplace-offer";
|
|
48
|
+
|
|
49
|
+
export interface MarketplaceOfferInstallResult {
|
|
50
|
+
path: string;
|
|
51
|
+
/** The source the skill was fetched from; surfaced so an autonomous install stays auditable. */
|
|
52
|
+
sourceUrl: string;
|
|
53
|
+
/** Normalized content hash of what was written; the integrity record the consent overlay would have shown. */
|
|
54
|
+
installedHash: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface MarketplaceOfferDeps {
|
|
58
|
+
/** Installed skill names the matcher must exclude. */
|
|
59
|
+
listInstalledSkillNames(): ReadonlyArray<string>;
|
|
60
|
+
/** The local marketplace lookup (catalog + index); already local-only. */
|
|
61
|
+
listMarketplaceEntries(): ReadonlyArray<MarketplaceSkill>;
|
|
62
|
+
/** The session's effective autonomy at evaluation time. */
|
|
63
|
+
getAutonomy(): AutonomyLevel;
|
|
64
|
+
/** Perform the install; the registration gates the source before calling. */
|
|
65
|
+
installEntry(entry: MarketplaceSkill, scope: "user" | "project"): MarketplaceOfferInstallResult;
|
|
66
|
+
/** Decline persistence; defaults to the promotion module's config-dir store. Keyed by name+version. */
|
|
67
|
+
declines?: {
|
|
68
|
+
readNever(): Readonly<Record<string, string>>;
|
|
69
|
+
recordNever(name: string, version?: string): void;
|
|
70
|
+
};
|
|
71
|
+
/** Per-offer binding tag source; injectable for deterministic tests. Defaults to a random id. */
|
|
72
|
+
newOfferTag?: () => string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const NO_EFFECTS: ReadonlyArray<MiddlewareEffect> = [];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The tag the model must echo verbatim in its ask_user question so the harness
|
|
79
|
+
* binds the answer to this specific offer and nothing else. The tag lives only
|
|
80
|
+
* in a system reminder (a trusted channel), so prompt-injected user or file
|
|
81
|
+
* content cannot forge it onto an unrelated question.
|
|
82
|
+
*/
|
|
83
|
+
export function offerBindingTag(offerTag: string): string {
|
|
84
|
+
return `[clio-install:${offerTag}]`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function marketplaceOfferReminder(entry: MarketplaceSkill, offerTag: string): string {
|
|
88
|
+
return (
|
|
89
|
+
`[Marketplace] This request may need expertise no installed skill covers. The local marketplace has ` +
|
|
90
|
+
`"${entry.name}" (not installed): ${entry.description} ` +
|
|
91
|
+
`First check the installed side with context(scope="skills"); if ${entry.name} is genuinely the right fit ` +
|
|
92
|
+
`and nothing installed serves, ask the operator with ask_user (mode=single_question, header "Install skill") ` +
|
|
93
|
+
`whether to install ${entry.name}, offering exactly these options in this order: ` +
|
|
94
|
+
`"${SKILL_INSTALL_OFFER_OPTION_PROJECT}", "${SKILL_INSTALL_OFFER_OPTION_USER}", ` +
|
|
95
|
+
`"${SKILL_INSTALL_OFFER_OPTION_NOT_NOW}", "${SKILL_INSTALL_OFFER_OPTION_NEVER}". ` +
|
|
96
|
+
`Include the exact tag ${offerBindingTag(offerTag)} verbatim in that question's text so the harness can bind ` +
|
|
97
|
+
`the answer to this offer; the harness acts only on an answer carrying this tag. ` +
|
|
98
|
+
`Then continue the task in the same turn. The harness handles the answer; never install or load a skill yourself. ` +
|
|
99
|
+
`If it is not actually needed, do not mention it.`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function marketplaceAutoInstallReminder(entry: MarketplaceSkill, result: MarketplaceOfferInstallResult): string {
|
|
104
|
+
// Full-auto skips the operator's yes/no, never the integrity record. The
|
|
105
|
+
// consent overlay states the source and the SHA-256 of what it writes; the
|
|
106
|
+
// autonomous path computes the same hash and must surface it here, so an
|
|
107
|
+
// install nobody was asked about is still traceable to its source and bytes.
|
|
108
|
+
return (
|
|
109
|
+
`[Marketplace] Installed skill "${entry.name}" from Clio's own local marketplace (full-auto) to ${result.path}. ` +
|
|
110
|
+
`Source ${result.sourceUrl}, sha256 ${result.installedHash}. ${entry.description} ` +
|
|
111
|
+
`It is installed but not active — activation stays operator-gated. If it fits this task, ` +
|
|
112
|
+
`suggest /skill ${entry.name} to the operator; never load it yourself.`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
interface AnswerLike {
|
|
117
|
+
question: string;
|
|
118
|
+
answer: string;
|
|
119
|
+
options?: ReadonlyArray<string>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function answersFromDetails(details: Readonly<Record<string, unknown>> | undefined): AnswerLike[] {
|
|
123
|
+
const raw = details?.answers;
|
|
124
|
+
if (!Array.isArray(raw)) return [];
|
|
125
|
+
return raw.filter(
|
|
126
|
+
(entry): entry is AnswerLike =>
|
|
127
|
+
typeof entry === "object" &&
|
|
128
|
+
entry !== null &&
|
|
129
|
+
typeof (entry as AnswerLike).question === "string" &&
|
|
130
|
+
typeof (entry as AnswerLike).answer === "string",
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** The offer option this answer chose, matched by exact label in options or by label substring in the one-line answer. */
|
|
135
|
+
function chosenOfferOption(answer: AnswerLike): string | null {
|
|
136
|
+
const labels = [
|
|
137
|
+
SKILL_INSTALL_OFFER_OPTION_PROJECT,
|
|
138
|
+
SKILL_INSTALL_OFFER_OPTION_USER,
|
|
139
|
+
SKILL_INSTALL_OFFER_OPTION_NOT_NOW,
|
|
140
|
+
SKILL_INSTALL_OFFER_OPTION_NEVER,
|
|
141
|
+
];
|
|
142
|
+
for (const label of labels) {
|
|
143
|
+
if (answer.options?.includes(label)) return label;
|
|
144
|
+
}
|
|
145
|
+
for (const label of labels) {
|
|
146
|
+
if (answer.answer.includes(label)) return label;
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function createMarketplaceOfferRegistration(deps: MarketplaceOfferDeps): MiddlewareHookRegistration {
|
|
152
|
+
const declines = deps.declines ?? {
|
|
153
|
+
readNever: () => readPromotionDeclines().never,
|
|
154
|
+
recordNever: (name: string, version?: string) => recordPromotionNeverDecline(name, version),
|
|
155
|
+
};
|
|
156
|
+
const newOfferTag = deps.newOfferTag ?? (() => randomUUID());
|
|
157
|
+
// Per-session state, reset on a session id change (same adoption rule as
|
|
158
|
+
// the skills reminder: a fresh session's opening turn fires with a null id
|
|
159
|
+
// that the created session then fills in).
|
|
160
|
+
let lastSeenSessionId: string | null | undefined;
|
|
161
|
+
let offeredNames = new Set<string>();
|
|
162
|
+
let sessionDeclines = new Set<string>();
|
|
163
|
+
// Discovery parses and hashes every installed/catalog SKILL.md. On a real
|
|
164
|
+
// home with 31 entries per side that cost 36-92ms on every turn_start, while
|
|
165
|
+
// the lexical match itself stayed below 2ms. Inventory is stable within a
|
|
166
|
+
// session except for installs, so keep one session snapshot and revalidate
|
|
167
|
+
// installed names only when cached data is about to produce an offer.
|
|
168
|
+
let installedNamesCache: Set<string> | null = null;
|
|
169
|
+
let marketplaceEntriesCache: ReadonlyArray<MarketplaceSkill> | null = null;
|
|
170
|
+
// The offer put to the operator, consumed by the ask_user after_tool
|
|
171
|
+
// observer. Each offer carries a unique binding tag the model must echo in
|
|
172
|
+
// its question; the observer acts only on an answer whose question carries
|
|
173
|
+
// that tag, so an unrelated (or prompt-injected) ask_user answer can never
|
|
174
|
+
// bind the pending offer.
|
|
175
|
+
let pendingOffer: { entry: MarketplaceSkill; tag: string } | null = null;
|
|
176
|
+
|
|
177
|
+
const trackSession = (input: MiddlewareHookInput): void => {
|
|
178
|
+
const sessionId = input.sessionId ?? null;
|
|
179
|
+
if (lastSeenSessionId === undefined || (lastSeenSessionId === null && sessionId !== null)) {
|
|
180
|
+
lastSeenSessionId = sessionId;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (sessionId !== lastSeenSessionId) {
|
|
184
|
+
lastSeenSessionId = sessionId;
|
|
185
|
+
offeredNames = new Set<string>();
|
|
186
|
+
sessionDeclines = new Set<string>();
|
|
187
|
+
pendingOffer = null;
|
|
188
|
+
installedNamesCache = null;
|
|
189
|
+
marketplaceEntriesCache = null;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const bestMatch = (text: string): PromotionMatch | null => {
|
|
194
|
+
const installedWasCached = installedNamesCache !== null;
|
|
195
|
+
let never: Readonly<Record<string, string>>;
|
|
196
|
+
try {
|
|
197
|
+
installedNamesCache ??= new Set(deps.listInstalledSkillNames());
|
|
198
|
+
marketplaceEntriesCache ??= deps.listMarketplaceEntries();
|
|
199
|
+
never = declines.readNever();
|
|
200
|
+
} catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
// offeredNames caps to one offer per skill per session, regardless of
|
|
204
|
+
// version. Declines are version-scoped: a "never"/"not now" on one catalog
|
|
205
|
+
// version does not suppress a later version of the same skill.
|
|
206
|
+
const declinedKeys = new Set<string>([...Object.keys(never), ...sessionDeclines]);
|
|
207
|
+
const findMatch = (): PromotionMatch | null =>
|
|
208
|
+
matchMarketplaceSkills(
|
|
209
|
+
text,
|
|
210
|
+
marketplaceEntriesCache ?? [],
|
|
211
|
+
new Set<string>([...(installedNamesCache ?? []), ...offeredNames]),
|
|
212
|
+
).find((candidate) => !declinedKeys.has(declineKey(candidate.entry.name, candidate.entry.version))) ?? null;
|
|
213
|
+
let match = findMatch();
|
|
214
|
+
if (match && installedWasCached) {
|
|
215
|
+
// A skills-hub or external install can happen after the session snapshot.
|
|
216
|
+
// Pay the installed-tree refresh only on the rare path that would surface
|
|
217
|
+
// an offer, then match again so an already-installed skill is never nagged.
|
|
218
|
+
try {
|
|
219
|
+
installedNamesCache = new Set(deps.listInstalledSkillNames());
|
|
220
|
+
} catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
match = findMatch();
|
|
224
|
+
}
|
|
225
|
+
return match;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const installGated = (entry: MarketplaceSkill, scope: "user" | "project"): MarketplaceOfferInstallResult => {
|
|
229
|
+
assertPromotionInstallSource(entry);
|
|
230
|
+
const result = deps.installEntry(entry, scope);
|
|
231
|
+
installedNamesCache?.add(entry.name);
|
|
232
|
+
return result;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const evaluateAskUserAnswers = (input: MiddlewareHookInput): ReadonlyArray<MiddlewareEffect> => {
|
|
236
|
+
const offer = pendingOffer;
|
|
237
|
+
if (!offer) return NO_EFFECTS;
|
|
238
|
+
const marker = offerBindingTag(offer.tag);
|
|
239
|
+
if (input.toolResultDetails?.cancelled === true) {
|
|
240
|
+
// A cancelled interview carries no question text, so it cannot be
|
|
241
|
+
// attributed to this offer. Do not bind it: an unrelated cancel must
|
|
242
|
+
// not decline our offer, and the offer stays armed for a later answer.
|
|
243
|
+
return NO_EFFECTS;
|
|
244
|
+
}
|
|
245
|
+
for (const answer of answersFromDetails(input.toolResultDetails)) {
|
|
246
|
+
// The answer binds only when its question carries this offer's tag.
|
|
247
|
+
if (!answer.question.includes(marker)) continue;
|
|
248
|
+
const option = chosenOfferOption(answer);
|
|
249
|
+
if (option === null) continue;
|
|
250
|
+
pendingOffer = null;
|
|
251
|
+
const offerKey = declineKey(offer.entry.name, offer.entry.version);
|
|
252
|
+
if (option === SKILL_INSTALL_OFFER_OPTION_NOT_NOW) {
|
|
253
|
+
sessionDeclines.add(offerKey);
|
|
254
|
+
return NO_EFFECTS;
|
|
255
|
+
}
|
|
256
|
+
if (option === SKILL_INSTALL_OFFER_OPTION_NEVER) {
|
|
257
|
+
sessionDeclines.add(offerKey);
|
|
258
|
+
try {
|
|
259
|
+
declines.recordNever(offer.entry.name, offer.entry.version);
|
|
260
|
+
} catch {
|
|
261
|
+
// Persistence failure degrades to a session decline.
|
|
262
|
+
}
|
|
263
|
+
return NO_EFFECTS;
|
|
264
|
+
}
|
|
265
|
+
const scope = option === SKILL_INSTALL_OFFER_OPTION_USER ? "user" : "project";
|
|
266
|
+
try {
|
|
267
|
+
const result = installGated(offer.entry, scope);
|
|
268
|
+
return [
|
|
269
|
+
{
|
|
270
|
+
kind: "annotate_tool_result",
|
|
271
|
+
severity: "info",
|
|
272
|
+
message:
|
|
273
|
+
`[Marketplace] Installed skill "${offer.entry.name}" (${scope} scope) to ${result.path}. ` +
|
|
274
|
+
`It is installed but not active; the operator activates it with /skill ${offer.entry.name}.`,
|
|
275
|
+
},
|
|
276
|
+
];
|
|
277
|
+
} catch (error) {
|
|
278
|
+
sessionDeclines.add(offerKey);
|
|
279
|
+
return [
|
|
280
|
+
{
|
|
281
|
+
kind: "annotate_tool_result",
|
|
282
|
+
severity: "warn",
|
|
283
|
+
message: `[Marketplace] Install of "${offer.entry.name}" failed: ${
|
|
284
|
+
error instanceof Error ? error.message : String(error)
|
|
285
|
+
}. Continue the task without it.`,
|
|
286
|
+
},
|
|
287
|
+
];
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return NO_EFFECTS;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
id: MARKETPLACE_OFFER_REGISTRATION_ID,
|
|
295
|
+
description:
|
|
296
|
+
"offers an uninstalled marketplace skill via ask_user when the request matches it; consented installs run gated to Clio's own marketplace, declines are remembered",
|
|
297
|
+
hooks: ["turn_start", "after_tool"],
|
|
298
|
+
evaluate(input): ReadonlyArray<MiddlewareEffect> {
|
|
299
|
+
trackSession(input);
|
|
300
|
+
// The offer is deliberately NOT cleared at turn_end. The reminder asks
|
|
301
|
+
// the model to put the ask_user question in the same turn, but it often
|
|
302
|
+
// defers a turn; clearing here dropped that deferred answer on the floor,
|
|
303
|
+
// so the operator's "Install" installed nothing and the model got no
|
|
304
|
+
// signal to correct a likely success claim. The offer now stays armed
|
|
305
|
+
// until a tag-carrying answer binds it, a newer offer replaces it, or the
|
|
306
|
+
// session ends — safe because only a tagged answer can bind (see H4).
|
|
307
|
+
if (input.hook === "after_tool") {
|
|
308
|
+
return input.toolName === ToolNames.AskUser ? evaluateAskUserAnswers(input) : NO_EFFECTS;
|
|
309
|
+
}
|
|
310
|
+
if (input.hook !== "turn_start") return NO_EFFECTS;
|
|
311
|
+
if (!isSubstantiveUserTurn(input.text)) return NO_EFFECTS;
|
|
312
|
+
// The operator already chose a skill for this turn; an offer on top of
|
|
313
|
+
// that choice is noise.
|
|
314
|
+
const pendingSkillRequests = metadataNumber(input, "pendingSkillRequests");
|
|
315
|
+
if (pendingSkillRequests !== null && pendingSkillRequests > 0) return NO_EFFECTS;
|
|
316
|
+
const match = bestMatch(input.text ?? "");
|
|
317
|
+
if (!match) return NO_EFFECTS;
|
|
318
|
+
offeredNames.add(match.entry.name);
|
|
319
|
+
if (deps.getAutonomy() === "full-auto") {
|
|
320
|
+
try {
|
|
321
|
+
const result = installGated(match.entry, "project");
|
|
322
|
+
return [
|
|
323
|
+
{
|
|
324
|
+
kind: "inject_reminder",
|
|
325
|
+
severity: "info",
|
|
326
|
+
message: marketplaceAutoInstallReminder(match.entry, result),
|
|
327
|
+
},
|
|
328
|
+
];
|
|
329
|
+
} catch {
|
|
330
|
+
// Gate refusal or install failure: fall back to the consent offer
|
|
331
|
+
// so the operator still hears about the match.
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const tag = newOfferTag();
|
|
335
|
+
pendingOffer = { entry: match.entry, tag };
|
|
336
|
+
return [{ kind: "inject_reminder", severity: "info", message: marketplaceOfferReminder(match.entry, tag) }];
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ordered, copy-on-write registration table behind a middleware contract.
|
|
3
|
+
*
|
|
4
|
+
* Three tiers share one id namespace and one evaluation list:
|
|
5
|
+
*
|
|
6
|
+
* - fixed: declarative rules (builtin plus composition-root definitions),
|
|
7
|
+
* immutable for the life of the contract and always evaluated first;
|
|
8
|
+
* - host: coded registrations appended by the composition root through
|
|
9
|
+
* registerHook, append-only, first id wins;
|
|
10
|
+
* - owned: registration sets replaced as one unit by an owner under a
|
|
11
|
+
* strictly increasing generation. Today the only owner is "user-hooks".
|
|
12
|
+
*
|
|
13
|
+
* The whole table is one immutable state object held behind a single
|
|
14
|
+
* reference. Every writer computes a complete next state and publishes it
|
|
15
|
+
* with one assignment; readers capture the reference once per evaluation, so
|
|
16
|
+
* an evaluation that started before a publish finishes against the state it
|
|
17
|
+
* started with, including across an await. Preparation never runs user code:
|
|
18
|
+
* conflicts are returned as frozen data and a caller emits them through the
|
|
19
|
+
* diagnostic sink only after publication.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { MiddlewareDiagnostic, MiddlewareDiagnosticSink, MiddlewareHookRegistration } from "./runtime.js";
|
|
23
|
+
|
|
24
|
+
export const MIDDLEWARE_REGISTRATION_OWNERS = ["user-hooks"] as const;
|
|
25
|
+
|
|
26
|
+
export type MiddlewareRegistrationOwner = (typeof MIDDLEWARE_REGISTRATION_OWNERS)[number];
|
|
27
|
+
|
|
28
|
+
export type MiddlewareRegistrationConflictTier = "builtin" | "host" | "owned";
|
|
29
|
+
|
|
30
|
+
export interface MiddlewareRegistrationConflict {
|
|
31
|
+
id: string;
|
|
32
|
+
conflictsWith: MiddlewareRegistrationConflictTier;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type ReplaceRegistrationsRejection = "stale" | "unknown-owner";
|
|
36
|
+
|
|
37
|
+
export type RegistrationConflictDiagnostic = Extract<MiddlewareDiagnostic, { kind: "registration_conflict" }>;
|
|
38
|
+
|
|
39
|
+
export interface ReplaceRegistrationsReport {
|
|
40
|
+
applied: boolean;
|
|
41
|
+
owner: MiddlewareRegistrationOwner;
|
|
42
|
+
/** Generation active for the owner after the call. */
|
|
43
|
+
activeGeneration: number;
|
|
44
|
+
reason?: ReplaceRegistrationsRejection;
|
|
45
|
+
/** Offered registrations dropped for colliding with a builtin, host, or earlier owned id. */
|
|
46
|
+
dropped: ReadonlyArray<MiddlewareRegistrationConflict>;
|
|
47
|
+
/**
|
|
48
|
+
* Remove this generation's registrations if the owner still holds it. A
|
|
49
|
+
* disposer for a superseded generation is a no-op, so a late disposal can
|
|
50
|
+
* never remove a newer generation's registrations.
|
|
51
|
+
*/
|
|
52
|
+
dispose(): void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A validated replacement whose complete next table state is already built.
|
|
57
|
+
* `publish` is one reference assignment: it does not validate, refuse,
|
|
58
|
+
* throw, or call out. The caller checks `current()` on the same stack
|
|
59
|
+
* immediately before publishing, then emits `conflicts` afterwards.
|
|
60
|
+
*/
|
|
61
|
+
export interface MiddlewareRegistrationReplacement {
|
|
62
|
+
owner: MiddlewareRegistrationOwner;
|
|
63
|
+
generation: number;
|
|
64
|
+
dropped: ReadonlyArray<MiddlewareRegistrationConflict>;
|
|
65
|
+
/** Diagnostics for `dropped`, as data. Nothing was emitted during preparation. */
|
|
66
|
+
conflicts: ReadonlyArray<RegistrationConflictDiagnostic>;
|
|
67
|
+
/** Registrations that will be active for the owner after publish. */
|
|
68
|
+
size: number;
|
|
69
|
+
/** True while the table state this replacement was prepared against is still the live one. */
|
|
70
|
+
current(): boolean;
|
|
71
|
+
/** Assignment-only publication of the prepared state. */
|
|
72
|
+
publish(): void;
|
|
73
|
+
/** Send `conflicts` to the diagnostic sink. Call only after publication. */
|
|
74
|
+
emitConflicts(): void;
|
|
75
|
+
/** Remove this generation's registrations if the owner still holds it. */
|
|
76
|
+
dispose(): void;
|
|
77
|
+
discard(): void;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type PrepareRegistrationReplacementResult =
|
|
81
|
+
| { status: "prepared"; replacement: MiddlewareRegistrationReplacement }
|
|
82
|
+
| {
|
|
83
|
+
status: "rejected";
|
|
84
|
+
owner: MiddlewareRegistrationOwner;
|
|
85
|
+
reason: ReplaceRegistrationsRejection;
|
|
86
|
+
activeGeneration: number;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export interface MiddlewareRegistrationTable {
|
|
90
|
+
/** The current frozen evaluation list. Capture once per evaluation. */
|
|
91
|
+
list(): ReadonlyArray<MiddlewareHookRegistration>;
|
|
92
|
+
registerHook(registration: MiddlewareHookRegistration): void;
|
|
93
|
+
prepareReplacement(
|
|
94
|
+
owner: MiddlewareRegistrationOwner,
|
|
95
|
+
generation: number,
|
|
96
|
+
registrations: ReadonlyArray<MiddlewareHookRegistration>,
|
|
97
|
+
): PrepareRegistrationReplacementResult;
|
|
98
|
+
replaceRegistrations(
|
|
99
|
+
owner: MiddlewareRegistrationOwner,
|
|
100
|
+
generation: number,
|
|
101
|
+
registrations: ReadonlyArray<MiddlewareHookRegistration>,
|
|
102
|
+
): ReplaceRegistrationsReport;
|
|
103
|
+
ownedGeneration(owner: MiddlewareRegistrationOwner): number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface OwnerSlot {
|
|
107
|
+
generation: number;
|
|
108
|
+
registrations: ReadonlyArray<MiddlewareHookRegistration>;
|
|
109
|
+
/** Host index the slot sits before; fixed at the owner's first replacement. */
|
|
110
|
+
anchor: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** One immutable table state. Replaced wholesale, never mutated. */
|
|
114
|
+
interface TableState {
|
|
115
|
+
host: ReadonlyArray<MiddlewareHookRegistration>;
|
|
116
|
+
hostIds: ReadonlySet<string>;
|
|
117
|
+
slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>;
|
|
118
|
+
list: ReadonlyArray<MiddlewareHookRegistration>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface MiddlewareRegistrationTableOptions {
|
|
122
|
+
fixed: ReadonlyArray<MiddlewareHookRegistration>;
|
|
123
|
+
/** Resolved per emission so the composition root can swap the sink later. */
|
|
124
|
+
diagnosticSink: () => MiddlewareDiagnosticSink;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function isRegistrationOwner(value: string): value is MiddlewareRegistrationOwner {
|
|
128
|
+
return (MIDDLEWARE_REGISTRATION_OWNERS as ReadonlyArray<string>).includes(value);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function createMiddlewareRegistrationTable(
|
|
132
|
+
options: MiddlewareRegistrationTableOptions,
|
|
133
|
+
): MiddlewareRegistrationTable {
|
|
134
|
+
const fixed = Object.freeze([...options.fixed]);
|
|
135
|
+
const fixedIds = new Set(fixed.map((registration) => registration.id));
|
|
136
|
+
|
|
137
|
+
const buildList = (
|
|
138
|
+
host: ReadonlyArray<MiddlewareHookRegistration>,
|
|
139
|
+
slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>,
|
|
140
|
+
): ReadonlyArray<MiddlewareHookRegistration> => {
|
|
141
|
+
const list: MiddlewareHookRegistration[] = [...fixed];
|
|
142
|
+
const slotAt = (index: number): void => {
|
|
143
|
+
for (const owner of MIDDLEWARE_REGISTRATION_OWNERS) {
|
|
144
|
+
const slot = slots.get(owner);
|
|
145
|
+
if (slot !== undefined && slot.anchor === index) list.push(...slot.registrations);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
for (let index = 0; index < host.length; index += 1) {
|
|
149
|
+
slotAt(index);
|
|
150
|
+
list.push(host[index] as MiddlewareHookRegistration);
|
|
151
|
+
}
|
|
152
|
+
slotAt(host.length);
|
|
153
|
+
return Object.freeze(list);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const makeState = (
|
|
157
|
+
host: ReadonlyArray<MiddlewareHookRegistration>,
|
|
158
|
+
slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>,
|
|
159
|
+
): TableState =>
|
|
160
|
+
Object.freeze({
|
|
161
|
+
host: Object.freeze([...host]),
|
|
162
|
+
hostIds: new Set(host.map((registration) => registration.id)),
|
|
163
|
+
slots: new Map(slots),
|
|
164
|
+
list: buildList(host, slots),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// The single live reference. Every publish below is `state = next`.
|
|
168
|
+
let state: TableState = makeState([], new Map());
|
|
169
|
+
|
|
170
|
+
const emit = (diagnostic: MiddlewareDiagnostic): void => {
|
|
171
|
+
try {
|
|
172
|
+
options.diagnosticSink()(diagnostic);
|
|
173
|
+
} catch {
|
|
174
|
+
// A diagnostics sink must never affect registration bookkeeping.
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const slotFor = (base: TableState, owner: MiddlewareRegistrationOwner): OwnerSlot =>
|
|
179
|
+
base.slots.get(owner) ?? { generation: 0, registrations: [], anchor: base.host.length };
|
|
180
|
+
|
|
181
|
+
const disposeGeneration = (owner: MiddlewareRegistrationOwner, generation: number): void => {
|
|
182
|
+
const base = state;
|
|
183
|
+
const held = base.slots.get(owner);
|
|
184
|
+
if (held === undefined || held.generation !== generation || held.registrations.length === 0) return;
|
|
185
|
+
const slots = new Map(base.slots);
|
|
186
|
+
slots.set(owner, { ...held, registrations: Object.freeze([]) });
|
|
187
|
+
state = makeState(base.host, slots);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const table: MiddlewareRegistrationTable = {
|
|
191
|
+
list: () => state.list,
|
|
192
|
+
registerHook(registration) {
|
|
193
|
+
const base = state;
|
|
194
|
+
if (fixedIds.has(registration.id) || base.hostIds.has(registration.id)) return;
|
|
195
|
+
const evictions: RegistrationConflictDiagnostic[] = [];
|
|
196
|
+
const slots = new Map(base.slots);
|
|
197
|
+
for (const [owner, slot] of base.slots) {
|
|
198
|
+
if (!slot.registrations.some((entry) => entry.id === registration.id)) continue;
|
|
199
|
+
slots.set(owner, {
|
|
200
|
+
...slot,
|
|
201
|
+
registrations: Object.freeze(slot.registrations.filter((entry) => entry.id !== registration.id)),
|
|
202
|
+
});
|
|
203
|
+
evictions.push({
|
|
204
|
+
kind: "registration_conflict",
|
|
205
|
+
registrationId: registration.id,
|
|
206
|
+
owner,
|
|
207
|
+
generation: slot.generation,
|
|
208
|
+
conflictsWith: "host",
|
|
209
|
+
action: "evicted",
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
state = makeState([...base.host, registration], slots);
|
|
213
|
+
// Diagnostics only after the publish; a sink that registers another
|
|
214
|
+
// host hook re-enters against the already-published state.
|
|
215
|
+
for (const eviction of evictions) emit(eviction);
|
|
216
|
+
},
|
|
217
|
+
prepareReplacement(owner, generation, registrations) {
|
|
218
|
+
if (!isRegistrationOwner(owner)) {
|
|
219
|
+
return { status: "rejected", owner, reason: "unknown-owner", activeGeneration: 0 };
|
|
220
|
+
}
|
|
221
|
+
const base = state;
|
|
222
|
+
const slot = slotFor(base, owner);
|
|
223
|
+
if (!Number.isInteger(generation) || generation <= slot.generation) {
|
|
224
|
+
return { status: "rejected", owner, reason: "stale", activeGeneration: slot.generation };
|
|
225
|
+
}
|
|
226
|
+
const dropped: MiddlewareRegistrationConflict[] = [];
|
|
227
|
+
const conflicts: RegistrationConflictDiagnostic[] = [];
|
|
228
|
+
const accepted: MiddlewareHookRegistration[] = [];
|
|
229
|
+
const seen = new Set<string>();
|
|
230
|
+
for (const registration of registrations) {
|
|
231
|
+
const conflictsWith: MiddlewareRegistrationConflictTier | null = fixedIds.has(registration.id)
|
|
232
|
+
? "builtin"
|
|
233
|
+
: base.hostIds.has(registration.id)
|
|
234
|
+
? "host"
|
|
235
|
+
: seen.has(registration.id)
|
|
236
|
+
? "owned"
|
|
237
|
+
: null;
|
|
238
|
+
if (conflictsWith !== null) {
|
|
239
|
+
dropped.push({ id: registration.id, conflictsWith });
|
|
240
|
+
conflicts.push({
|
|
241
|
+
kind: "registration_conflict",
|
|
242
|
+
registrationId: registration.id,
|
|
243
|
+
owner,
|
|
244
|
+
generation,
|
|
245
|
+
conflictsWith,
|
|
246
|
+
action: "dropped",
|
|
247
|
+
});
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
seen.add(registration.id);
|
|
251
|
+
accepted.push(registration);
|
|
252
|
+
}
|
|
253
|
+
const slots = new Map(base.slots);
|
|
254
|
+
slots.set(owner, { generation, registrations: Object.freeze(accepted), anchor: slot.anchor });
|
|
255
|
+
const prepared = makeState(base.host, slots);
|
|
256
|
+
let settled = false;
|
|
257
|
+
const frozenDropped = Object.freeze(dropped);
|
|
258
|
+
const frozenConflicts = Object.freeze(conflicts);
|
|
259
|
+
const replacement: MiddlewareRegistrationReplacement = {
|
|
260
|
+
owner,
|
|
261
|
+
generation,
|
|
262
|
+
dropped: frozenDropped,
|
|
263
|
+
conflicts: frozenConflicts,
|
|
264
|
+
size: accepted.length,
|
|
265
|
+
// Reference identity on the base state covers every kind of
|
|
266
|
+
// intervening change: host appends, other replacements, disposals.
|
|
267
|
+
current: () => !settled && state === base,
|
|
268
|
+
publish() {
|
|
269
|
+
settled = true;
|
|
270
|
+
state = prepared;
|
|
271
|
+
},
|
|
272
|
+
emitConflicts() {
|
|
273
|
+
for (const conflict of frozenConflicts) emit(conflict);
|
|
274
|
+
},
|
|
275
|
+
dispose() {
|
|
276
|
+
disposeGeneration(owner, generation);
|
|
277
|
+
},
|
|
278
|
+
discard() {
|
|
279
|
+
settled = true;
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
return { status: "prepared", replacement };
|
|
283
|
+
},
|
|
284
|
+
replaceRegistrations(owner, generation, registrations) {
|
|
285
|
+
const prepared = table.prepareReplacement(owner, generation, registrations);
|
|
286
|
+
if (prepared.status === "rejected") {
|
|
287
|
+
return {
|
|
288
|
+
applied: false,
|
|
289
|
+
owner: prepared.owner,
|
|
290
|
+
activeGeneration: prepared.activeGeneration,
|
|
291
|
+
reason: prepared.reason,
|
|
292
|
+
dropped: [],
|
|
293
|
+
dispose: () => undefined,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
const replacement = prepared.replacement;
|
|
297
|
+
// Nothing ran between prepare and here, so current() holds; the
|
|
298
|
+
// check is kept so the one-call form has the same shape as a caller
|
|
299
|
+
// that validates on its own stack.
|
|
300
|
+
if (!replacement.current()) {
|
|
301
|
+
replacement.discard();
|
|
302
|
+
return {
|
|
303
|
+
applied: false,
|
|
304
|
+
owner,
|
|
305
|
+
activeGeneration: table.ownedGeneration(owner),
|
|
306
|
+
reason: "stale",
|
|
307
|
+
dropped: replacement.dropped,
|
|
308
|
+
dispose: () => undefined,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
replacement.publish();
|
|
312
|
+
replacement.emitConflicts();
|
|
313
|
+
return {
|
|
314
|
+
applied: true,
|
|
315
|
+
owner,
|
|
316
|
+
activeGeneration: generation,
|
|
317
|
+
dropped: replacement.dropped,
|
|
318
|
+
dispose: () => replacement.dispose(),
|
|
319
|
+
};
|
|
320
|
+
},
|
|
321
|
+
ownedGeneration(owner) {
|
|
322
|
+
return state.slots.get(owner)?.generation ?? 0;
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
return table;
|
|
326
|
+
}
|