@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
|
@@ -1,46 +1,53 @@
|
|
|
1
1
|
import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
hashToolCall
|
|
4
|
-
} from "./chunk-UOV2BYIW.js";
|
|
5
2
|
import {
|
|
6
3
|
TASK_MEMORY_DEFAULT_PROCEDURAL_CAP,
|
|
7
4
|
TASK_MEMORY_POLICY_DEFAULT_TIMEOUT_MS,
|
|
8
5
|
runTaskMemoryPolicy,
|
|
9
6
|
taskMemoryBankDelta
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-I66EAJFY.js";
|
|
11
8
|
import {
|
|
12
9
|
isTerminalRunEnvelope
|
|
13
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-IKSLQ4XV.js";
|
|
14
11
|
import {
|
|
15
12
|
taskBoardCounts
|
|
16
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-Q4XWMHX6.js";
|
|
14
|
+
import {
|
|
15
|
+
hashToolCall
|
|
16
|
+
} from "./chunk-IDNA72AH.js";
|
|
17
17
|
import {
|
|
18
|
+
SKILL_INSTALL_OFFER_OPTION_NEVER,
|
|
19
|
+
SKILL_INSTALL_OFFER_OPTION_NOT_NOW,
|
|
20
|
+
SKILL_INSTALL_OFFER_OPTION_PROJECT,
|
|
21
|
+
SKILL_INSTALL_OFFER_OPTION_USER,
|
|
18
22
|
SKILL_SUGGESTION_ANCHOR,
|
|
19
23
|
SKILL_SUGGESTION_PREFIX
|
|
20
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-FSP7CMNU.js";
|
|
21
25
|
import {
|
|
22
26
|
legacyToolResultDigest,
|
|
23
27
|
sanitizeToolResultDigest
|
|
24
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-B7HM5Z7T.js";
|
|
25
29
|
import {
|
|
26
30
|
ToolNames
|
|
27
31
|
} from "./chunk-K6BSR66V.js";
|
|
28
32
|
import {
|
|
29
33
|
registerForegroundStream
|
|
30
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-BYMNWQ7O.js";
|
|
31
35
|
import {
|
|
32
36
|
ceilChars
|
|
33
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-CWVRRIEI.js";
|
|
34
38
|
import {
|
|
35
39
|
BusChannels
|
|
36
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-F4EKGO4N.js";
|
|
37
41
|
import {
|
|
38
42
|
reportCommitAttributionDiagnostic,
|
|
39
43
|
withManagedGitCommitAttributionEnvironment
|
|
40
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-JIEGK6UF.js";
|
|
41
45
|
import {
|
|
42
46
|
require_dist
|
|
43
47
|
} from "./chunk-APJ265NV.js";
|
|
48
|
+
import {
|
|
49
|
+
clioConfigDir
|
|
50
|
+
} from "./chunk-BYP5D4HI.js";
|
|
44
51
|
import {
|
|
45
52
|
safeResourceWrite
|
|
46
53
|
} from "./chunk-WEPFGWHJ.js";
|
|
@@ -424,19 +431,27 @@ function cloneRuleDefinition(definition) {
|
|
|
424
431
|
function writeMiddlewareDiagnosticToStderr(diagnostic) {
|
|
425
432
|
if (diagnostic.kind === "hook_failed") {
|
|
426
433
|
process.stderr.write(
|
|
427
|
-
`[clio:middleware] registration '${diagnostic.registrationId}' failed on '${diagnostic.hook}': ${diagnostic.message}
|
|
434
|
+
`[clio-coder:middleware] registration '${diagnostic.registrationId}' failed on '${diagnostic.hook}': ${diagnostic.message}
|
|
428
435
|
`
|
|
429
436
|
);
|
|
430
437
|
return;
|
|
431
438
|
}
|
|
439
|
+
if (diagnostic.kind === "registration_conflict") {
|
|
440
|
+
process.stderr.write(`[clio-coder:middleware] ${formatRegistrationConflict(diagnostic)}
|
|
441
|
+
`);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
432
444
|
if (!diagnostic.steadyStateWarn && process.env.CLIO_CODER_HOOK_BUDGET_DEBUG !== "1") return;
|
|
433
445
|
const stats = diagnostic.stats;
|
|
434
446
|
const trend = stats.window > 0 ? ` (slow on ${stats.overCount}/${stats.window} recent ${diagnostic.hook} calls, p95 ${stats.p95Ms.toFixed(1)}ms)` : "";
|
|
435
447
|
process.stderr.write(
|
|
436
|
-
`[clio:middleware] registration '${diagnostic.registrationId}' exceeded budget on '${diagnostic.hook}': ${diagnostic.elapsedMs.toFixed(1)}ms > ${diagnostic.budgetMs}ms${trend}
|
|
448
|
+
`[clio-coder:middleware] registration '${diagnostic.registrationId}' exceeded budget on '${diagnostic.hook}': ${diagnostic.elapsedMs.toFixed(1)}ms > ${diagnostic.budgetMs}ms${trend}
|
|
437
449
|
`
|
|
438
450
|
);
|
|
439
451
|
}
|
|
452
|
+
function formatRegistrationConflict(diagnostic) {
|
|
453
|
+
return diagnostic.action === "dropped" ? `${diagnostic.owner} registration '${diagnostic.registrationId}' (generation ${diagnostic.generation}) dropped: id is held by a ${diagnostic.conflictsWith} registration` : `${diagnostic.owner} registration '${diagnostic.registrationId}' (generation ${diagnostic.generation}) evicted by a ${diagnostic.conflictsWith} registration with the same id`;
|
|
454
|
+
}
|
|
440
455
|
function registrationFromRuleDefinition(definition) {
|
|
441
456
|
const registration = {
|
|
442
457
|
id: definition.rule.id,
|
|
@@ -899,6 +914,7 @@ function createDetachedDispatchNudgeRegistration(options) {
|
|
|
899
914
|
|
|
900
915
|
// src/domains/middleware/hook-receipts.ts
|
|
901
916
|
init_esm_shims();
|
|
917
|
+
import { readFileSync } from "node:fs";
|
|
902
918
|
var HOOK_RECEIPT_LOG_CAPACITY = 200;
|
|
903
919
|
var PERSIST_THROTTLE_MS = 2e3;
|
|
904
920
|
function createHookReceiptLog(options = {}) {
|
|
@@ -936,456 +952,432 @@ function createHookReceiptLog(options = {}) {
|
|
|
936
952
|
}
|
|
937
953
|
};
|
|
938
954
|
}
|
|
955
|
+
function readPersistedHookReceipts(persistPath) {
|
|
956
|
+
let raw;
|
|
957
|
+
try {
|
|
958
|
+
raw = readFileSync(persistPath, "utf8");
|
|
959
|
+
} catch (error) {
|
|
960
|
+
if (error.code === "ENOENT") return [];
|
|
961
|
+
throw error;
|
|
962
|
+
}
|
|
963
|
+
const parsed = JSON.parse(raw);
|
|
964
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.receipts)) {
|
|
965
|
+
throw new Error(`${persistPath}: unrecognized hook receipt log shape`);
|
|
966
|
+
}
|
|
967
|
+
return parsed.receipts;
|
|
968
|
+
}
|
|
939
969
|
|
|
940
|
-
// src/domains/middleware/
|
|
970
|
+
// src/domains/middleware/skills-reminder.ts
|
|
941
971
|
init_esm_shims();
|
|
942
|
-
var
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
972
|
+
var SKILLS_REMINDER_REGISTRATION_ID = "observer.skills-reminder";
|
|
973
|
+
function skillsReminderMessage(installed, installable = 0) {
|
|
974
|
+
const counts = installable > 0 ? `${installed} installed, ${installable} installable from the marketplace` : `${installed} installed`;
|
|
975
|
+
return `[Skills] ${counts}. Start this task by listing them with context(scope="skills") and checking for a match; if one matches, open your reply with the line \`${SKILL_SUGGESTION_ANCHOR}\` (a comma-separated sequence, in order, when several compose) and then continue the task in the same turn without the skill. Only the operator loads a skill, and a marketplace skill is offered for install when the operator runs it. If none match, do not mention skills and continue with the task.`;
|
|
976
|
+
}
|
|
977
|
+
var NO_EFFECTS = [];
|
|
978
|
+
var GREETING_WORDS = /* @__PURE__ */ new Set([
|
|
979
|
+
"hi",
|
|
980
|
+
"hello",
|
|
981
|
+
"hey",
|
|
982
|
+
"heya",
|
|
983
|
+
"hiya",
|
|
984
|
+
"howdy",
|
|
985
|
+
"yo",
|
|
986
|
+
"sup",
|
|
987
|
+
"hola",
|
|
988
|
+
"greetings",
|
|
989
|
+
"gm",
|
|
990
|
+
"gn",
|
|
991
|
+
"morning",
|
|
992
|
+
"afternoon",
|
|
993
|
+
"evening",
|
|
994
|
+
"good",
|
|
995
|
+
"day",
|
|
996
|
+
"night",
|
|
997
|
+
"there",
|
|
998
|
+
"you",
|
|
999
|
+
"clio",
|
|
1000
|
+
"thanks",
|
|
1001
|
+
"thank",
|
|
1002
|
+
"thankyou",
|
|
1003
|
+
"thx",
|
|
1004
|
+
"ty",
|
|
1005
|
+
"ok",
|
|
1006
|
+
"okay",
|
|
1007
|
+
"k",
|
|
1008
|
+
"cool",
|
|
1009
|
+
"nice",
|
|
1010
|
+
"test",
|
|
1011
|
+
"testing",
|
|
1012
|
+
"ping",
|
|
1013
|
+
"pong"
|
|
1014
|
+
]);
|
|
1015
|
+
function isSubstantiveUserTurn(text) {
|
|
1016
|
+
const normalized = (text ?? "").toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ").trim();
|
|
1017
|
+
if (normalized.length === 0) return false;
|
|
1018
|
+
const tokens = normalized.split(" ");
|
|
1019
|
+
if (tokens.length > 4) return true;
|
|
1020
|
+
return tokens.some((token) => !GREETING_WORDS.has(token));
|
|
1021
|
+
}
|
|
1022
|
+
function createSkillsReminderRegistration(deps) {
|
|
1023
|
+
let lastSeenSessionId;
|
|
1024
|
+
let spentForActiveSession = false;
|
|
1025
|
+
let observedFreshStart = false;
|
|
1026
|
+
let observedAnyTurn = false;
|
|
1027
|
+
return {
|
|
1028
|
+
id: SKILLS_REMINDER_REGISTRATION_ID,
|
|
1029
|
+
description: "once per session, on the first substantive turn, teaches the skill-suggestion reply protocol; keeps a turn going that stopped on the suggestion",
|
|
1030
|
+
hooks: ["turn_start", "turn_end"],
|
|
1031
|
+
evaluate(input) {
|
|
1032
|
+
if (input.hook === "turn_end") {
|
|
1033
|
+
return isSkillSuggestionWait(input) ? [{ kind: "request_continuation", message: SKILL_SUGGESTION_WAIT_CONTINUATION_MESSAGE }] : NO_EFFECTS;
|
|
1034
|
+
}
|
|
1035
|
+
const sessionId = input.sessionId ?? null;
|
|
1036
|
+
if (lastSeenSessionId === void 0) {
|
|
1037
|
+
lastSeenSessionId = sessionId;
|
|
1038
|
+
} else if (lastSeenSessionId === null && sessionId !== null) {
|
|
1039
|
+
lastSeenSessionId = sessionId;
|
|
1040
|
+
} else if (sessionId !== lastSeenSessionId) {
|
|
1041
|
+
lastSeenSessionId = sessionId;
|
|
1042
|
+
spentForActiveSession = false;
|
|
1043
|
+
observedFreshStart = false;
|
|
1044
|
+
observedAnyTurn = false;
|
|
1045
|
+
}
|
|
1046
|
+
if (spentForActiveSession) return NO_EFFECTS;
|
|
1047
|
+
const conversationMessages = metadataNumber(input, "conversationMessages");
|
|
1048
|
+
if (!observedAnyTurn) {
|
|
1049
|
+
observedAnyTurn = true;
|
|
1050
|
+
if (conversationMessages === null || conversationMessages > 0) {
|
|
1051
|
+
spentForActiveSession = true;
|
|
1052
|
+
return NO_EFFECTS;
|
|
1053
|
+
}
|
|
1054
|
+
observedFreshStart = true;
|
|
1055
|
+
}
|
|
1056
|
+
if (!observedFreshStart) {
|
|
1057
|
+
spentForActiveSession = true;
|
|
1058
|
+
return NO_EFFECTS;
|
|
1059
|
+
}
|
|
1060
|
+
if (!isSubstantiveUserTurn(input.text)) return NO_EFFECTS;
|
|
1061
|
+
spentForActiveSession = true;
|
|
1062
|
+
const pendingSkillRequests = metadataNumber(input, "pendingSkillRequests");
|
|
1063
|
+
if (pendingSkillRequests !== null && pendingSkillRequests > 0) return NO_EFFECTS;
|
|
1064
|
+
let installed = 0;
|
|
1065
|
+
let installable = 0;
|
|
1066
|
+
try {
|
|
1067
|
+
installed = deps.countModelVisibleSkills();
|
|
1068
|
+
installable = deps.countInstallableSkills?.() ?? 0;
|
|
1069
|
+
} catch {
|
|
1070
|
+
return NO_EFFECTS;
|
|
1071
|
+
}
|
|
1072
|
+
if (installed <= 0 && installable <= 0) return NO_EFFECTS;
|
|
1073
|
+
return [{ kind: "inject_reminder", severity: "info", message: skillsReminderMessage(installed, installable) }];
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
946
1077
|
|
|
947
|
-
// src/domains/middleware/
|
|
1078
|
+
// src/domains/middleware/marketplace-offer.ts
|
|
948
1079
|
init_esm_shims();
|
|
949
|
-
import {
|
|
950
|
-
import { isAbsolute, resolve } from "node:path";
|
|
1080
|
+
import { randomUUID } from "node:crypto";
|
|
951
1081
|
|
|
952
|
-
// src/domains/
|
|
1082
|
+
// src/domains/resources/skills/promotion.ts
|
|
953
1083
|
init_esm_shims();
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
function
|
|
994
|
-
|
|
995
|
-
const message = readRequiredString(record, `${path}.message`, issues);
|
|
996
|
-
const severity = readOptionalString(record, `${path}.severity`, issues);
|
|
997
|
-
if (severity !== void 0 && !isMiddlewareReminderSeverity(severity)) {
|
|
998
|
-
issues.push({ path: `${path}.severity`, message: "expected info, advisory, warn, or hard-block" });
|
|
999
|
-
}
|
|
1000
|
-
if (message === null) return null;
|
|
1001
|
-
const effect = { kind: "inject_reminder", message };
|
|
1002
|
-
if (severity !== void 0 && isMiddlewareReminderSeverity(severity)) effect.severity = severity;
|
|
1003
|
-
return effect;
|
|
1084
|
+
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
1085
|
+
import path from "node:path";
|
|
1086
|
+
var TOKEN_STOPWORDS = /* @__PURE__ */ new Set([
|
|
1087
|
+
"the",
|
|
1088
|
+
"a",
|
|
1089
|
+
"an",
|
|
1090
|
+
"and",
|
|
1091
|
+
"or",
|
|
1092
|
+
"for",
|
|
1093
|
+
"with",
|
|
1094
|
+
"this",
|
|
1095
|
+
"that",
|
|
1096
|
+
"when",
|
|
1097
|
+
"what",
|
|
1098
|
+
"how",
|
|
1099
|
+
"into",
|
|
1100
|
+
"from",
|
|
1101
|
+
"use",
|
|
1102
|
+
"used",
|
|
1103
|
+
"using",
|
|
1104
|
+
"one",
|
|
1105
|
+
"not",
|
|
1106
|
+
"skill",
|
|
1107
|
+
"skills",
|
|
1108
|
+
"clio",
|
|
1109
|
+
"please",
|
|
1110
|
+
"can",
|
|
1111
|
+
"you",
|
|
1112
|
+
"should",
|
|
1113
|
+
"would",
|
|
1114
|
+
"about",
|
|
1115
|
+
"need",
|
|
1116
|
+
"want",
|
|
1117
|
+
"help",
|
|
1118
|
+
"make",
|
|
1119
|
+
"file",
|
|
1120
|
+
"files",
|
|
1121
|
+
"code"
|
|
1122
|
+
]);
|
|
1123
|
+
function normalize(text) {
|
|
1124
|
+
return text.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ").trim();
|
|
1004
1125
|
}
|
|
1005
|
-
function
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
if (severity !== void 0 && !isMiddlewareAnnotationSeverity(severity)) {
|
|
1010
|
-
issues.push({ path: `${path}.severity`, message: "expected info or warn" });
|
|
1011
|
-
}
|
|
1012
|
-
if (message === null) return null;
|
|
1013
|
-
const effect = { kind: "annotate_tool_result", message };
|
|
1014
|
-
if (severity !== void 0 && isMiddlewareAnnotationSeverity(severity)) effect.severity = severity;
|
|
1015
|
-
return effect;
|
|
1126
|
+
function distinctiveTokens(text) {
|
|
1127
|
+
return new Set(
|
|
1128
|
+
normalize(text).split(" ").filter((token) => token.length >= 4 && !TOKEN_STOPWORDS.has(token))
|
|
1129
|
+
);
|
|
1016
1130
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
const
|
|
1021
|
-
if (
|
|
1022
|
-
|
|
1131
|
+
var TRIGGER_SCORE = 4;
|
|
1132
|
+
var TOKEN_FIRE_THRESHOLD = 3;
|
|
1133
|
+
function scorePromotionEntry(userText, entry) {
|
|
1134
|
+
const haystack = ` ${normalize(userText)} `;
|
|
1135
|
+
if (haystack.trim().length === 0) return null;
|
|
1136
|
+
for (const trigger of entry.triggers ?? []) {
|
|
1137
|
+
const phrase = normalize(trigger);
|
|
1138
|
+
if (phrase.length >= 4 && haystack.includes(` ${phrase} `)) {
|
|
1139
|
+
return { entry, score: TRIGGER_SCORE, matchedTrigger: trigger };
|
|
1140
|
+
}
|
|
1023
1141
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1142
|
+
const requestTokens = distinctiveTokens(userText);
|
|
1143
|
+
if (requestTokens.size === 0) return null;
|
|
1144
|
+
const entryTokens = distinctiveTokens(`${entry.name.replace(/-/g, " ")} ${entry.description}`);
|
|
1145
|
+
let overlap = 0;
|
|
1146
|
+
for (const token of requestTokens) if (entryTokens.has(token)) overlap += 1;
|
|
1147
|
+
return overlap >= TOKEN_FIRE_THRESHOLD ? { entry, score: overlap } : null;
|
|
1148
|
+
}
|
|
1149
|
+
function matchMarketplaceSkills(userText, entries, excludedNames) {
|
|
1150
|
+
const matches = [];
|
|
1151
|
+
for (const entry of entries) {
|
|
1152
|
+
if (entry.kind !== "skill" || excludedNames.has(entry.name)) continue;
|
|
1153
|
+
const match = scorePromotionEntry(userText, entry);
|
|
1154
|
+
if (match) matches.push(match);
|
|
1155
|
+
}
|
|
1156
|
+
return matches.sort((a, b) => b.score - a.score || a.entry.name.localeCompare(b.entry.name));
|
|
1157
|
+
}
|
|
1158
|
+
var OWN_MARKETPLACE_URL_PREFIX = "https://github.com/iowarp/clio-coder/";
|
|
1159
|
+
function isOwnMarketplaceSource(entry) {
|
|
1160
|
+
const source = entry.sourceUrl.trim();
|
|
1161
|
+
if (/^(?:https?:\/\/|git@)/.test(source)) return source.startsWith(OWN_MARKETPLACE_URL_PREFIX);
|
|
1162
|
+
return entry.origin === "catalog" && path.isAbsolute(source);
|
|
1163
|
+
}
|
|
1164
|
+
function assertPromotionInstallSource(entry) {
|
|
1165
|
+
if (isOwnMarketplaceSource(entry)) return;
|
|
1166
|
+
throw new Error(
|
|
1167
|
+
`skill promotion: refusing to install "${entry.name}" from ${entry.sourceUrl}; promotion installs only from Clio's own marketplace (local catalog or ${OWN_MARKETPLACE_URL_PREFIX}). Install manually with clio-coder skills install if intended.`
|
|
1168
|
+
);
|
|
1033
1169
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
if (message === null) return null;
|
|
1038
|
-
return { kind: "request_continuation", message };
|
|
1170
|
+
var PROMOTION_DECLINES_FILE = "skill-promotion-declines.json";
|
|
1171
|
+
function declineKey(name, version) {
|
|
1172
|
+
return `${name}@${version ?? ""}`;
|
|
1039
1173
|
}
|
|
1040
|
-
function
|
|
1041
|
-
|
|
1042
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1043
|
-
issues.push({ path, message: "expected non-empty string" });
|
|
1044
|
-
return null;
|
|
1045
|
-
}
|
|
1046
|
-
return value;
|
|
1174
|
+
function declinesPath(configDir) {
|
|
1175
|
+
return path.join(configDir ?? clioConfigDir(), PROMOTION_DECLINES_FILE);
|
|
1047
1176
|
}
|
|
1048
|
-
function
|
|
1049
|
-
const
|
|
1050
|
-
if (!
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1177
|
+
function readPromotionDeclines(configDir) {
|
|
1178
|
+
const file = declinesPath(configDir);
|
|
1179
|
+
if (!existsSync(file)) return { never: {} };
|
|
1180
|
+
try {
|
|
1181
|
+
const parsed = JSON.parse(readFileSync2(file, "utf8"));
|
|
1182
|
+
const never = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed.never : void 0;
|
|
1183
|
+
if (never && typeof never === "object" && !Array.isArray(never)) {
|
|
1184
|
+
const entries = Object.entries(never).filter(
|
|
1185
|
+
(pair) => typeof pair[1] === "string"
|
|
1186
|
+
);
|
|
1187
|
+
return { never: Object.fromEntries(entries) };
|
|
1188
|
+
}
|
|
1189
|
+
} catch {
|
|
1055
1190
|
}
|
|
1056
|
-
return
|
|
1191
|
+
return { never: {} };
|
|
1057
1192
|
}
|
|
1058
|
-
function
|
|
1059
|
-
const
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1193
|
+
function recordPromotionNeverDecline(name, version, configDir) {
|
|
1194
|
+
const store = readPromotionDeclines(configDir);
|
|
1195
|
+
store.never[declineKey(name, version)] = (/* @__PURE__ */ new Date()).toISOString();
|
|
1196
|
+
safeResourceWrite(declinesPath(configDir), `${JSON.stringify(store, null, 2)}
|
|
1197
|
+
`, { encoding: "utf8" });
|
|
1063
1198
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1199
|
+
|
|
1200
|
+
// src/domains/middleware/marketplace-offer.ts
|
|
1201
|
+
var MARKETPLACE_OFFER_REGISTRATION_ID = "observer.marketplace-offer";
|
|
1202
|
+
var NO_EFFECTS2 = [];
|
|
1203
|
+
function offerBindingTag(offerTag) {
|
|
1204
|
+
return `[clio-install:${offerTag}]`;
|
|
1066
1205
|
}
|
|
1067
|
-
function
|
|
1068
|
-
return
|
|
1206
|
+
function marketplaceOfferReminder(entry, offerTag) {
|
|
1207
|
+
return `[Marketplace] This request may need expertise no installed skill covers. The local marketplace has "${entry.name}" (not installed): ${entry.description} First check the installed side with context(scope="skills"); if ${entry.name} is genuinely the right fit and nothing installed serves, ask the operator with ask_user (mode=single_question, header "Install skill") whether to install ${entry.name}, offering exactly these options in this order: "${SKILL_INSTALL_OFFER_OPTION_PROJECT}", "${SKILL_INSTALL_OFFER_OPTION_USER}", "${SKILL_INSTALL_OFFER_OPTION_NOT_NOW}", "${SKILL_INSTALL_OFFER_OPTION_NEVER}". Include the exact tag ${offerBindingTag(offerTag)} verbatim in that question's text so the harness can bind the answer to this offer; the harness acts only on an answer carrying this tag. Then continue the task in the same turn. The harness handles the answer; never install or load a skill yourself. If it is not actually needed, do not mention it.`;
|
|
1069
1208
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
var USER_HOOK_ORIGIN_ORDER = ["extension", "user", "project", "project.local"];
|
|
1073
|
-
var USER_HOOK_COMMAND_TIMEOUT_DEFAULT_MS = 2e3;
|
|
1074
|
-
var USER_HOOK_COMMAND_TIMEOUT_MIN_MS = 100;
|
|
1075
|
-
var USER_HOOK_COMMAND_TIMEOUT_MAX_MS = 5e3;
|
|
1076
|
-
var USER_HOOK_COMMAND_OUTPUT_MAX_CHARS = 4e3;
|
|
1077
|
-
var USER_HOOK_PROMPT_MAX_CHARS = 2e3;
|
|
1078
|
-
function isRecord2(value) {
|
|
1079
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1209
|
+
function marketplaceAutoInstallReminder(entry, result) {
|
|
1210
|
+
return `[Marketplace] Installed skill "${entry.name}" from Clio's own local marketplace (full-auto) to ${result.path}. Source ${result.sourceUrl}, sha256 ${result.installedHash}. ${entry.description} It is installed but not active \u2014 activation stays operator-gated. If it fits this task, suggest /skill ${entry.name} to the operator; never load it yourself.`;
|
|
1080
1211
|
}
|
|
1081
|
-
function
|
|
1082
|
-
|
|
1212
|
+
function answersFromDetails(details) {
|
|
1213
|
+
const raw = details?.answers;
|
|
1214
|
+
if (!Array.isArray(raw)) return [];
|
|
1215
|
+
return raw.filter(
|
|
1216
|
+
(entry) => typeof entry === "object" && entry !== null && typeof entry.question === "string" && typeof entry.answer === "string"
|
|
1217
|
+
);
|
|
1083
1218
|
}
|
|
1084
|
-
function
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1219
|
+
function chosenOfferOption(answer) {
|
|
1220
|
+
const labels = [
|
|
1221
|
+
SKILL_INSTALL_OFFER_OPTION_PROJECT,
|
|
1222
|
+
SKILL_INSTALL_OFFER_OPTION_USER,
|
|
1223
|
+
SKILL_INSTALL_OFFER_OPTION_NOT_NOW,
|
|
1224
|
+
SKILL_INSTALL_OFFER_OPTION_NEVER
|
|
1225
|
+
];
|
|
1226
|
+
for (const label of labels) {
|
|
1227
|
+
if (answer.options?.includes(label)) return label;
|
|
1089
1228
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
function readStringArray(value) {
|
|
1093
|
-
if (!Array.isArray(value)) return null;
|
|
1094
|
-
const out = [];
|
|
1095
|
-
for (const item of value) {
|
|
1096
|
-
if (typeof item !== "string" || item.length === 0) return null;
|
|
1097
|
-
out.push(item);
|
|
1229
|
+
for (const label of labels) {
|
|
1230
|
+
if (answer.answer.includes(label)) return label;
|
|
1098
1231
|
}
|
|
1099
|
-
return
|
|
1232
|
+
return null;
|
|
1100
1233
|
}
|
|
1101
|
-
function
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
return null;
|
|
1106
|
-
}
|
|
1107
|
-
const spec = {
|
|
1108
|
-
kind: "command",
|
|
1109
|
-
argv,
|
|
1110
|
-
cwd: resolve(options.workspaceRoot),
|
|
1111
|
-
timeoutMs: USER_HOOK_COMMAND_TIMEOUT_DEFAULT_MS,
|
|
1112
|
-
as: "annotate"
|
|
1234
|
+
function createMarketplaceOfferRegistration(deps) {
|
|
1235
|
+
const declines = deps.declines ?? {
|
|
1236
|
+
readNever: () => readPromotionDeclines().never,
|
|
1237
|
+
recordNever: (name, version) => recordPromotionNeverDecline(name, version)
|
|
1113
1238
|
};
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1239
|
+
const newOfferTag = deps.newOfferTag ?? (() => randomUUID());
|
|
1240
|
+
let lastSeenSessionId;
|
|
1241
|
+
let offeredNames = /* @__PURE__ */ new Set();
|
|
1242
|
+
let sessionDeclines = /* @__PURE__ */ new Set();
|
|
1243
|
+
let installedNamesCache = null;
|
|
1244
|
+
let marketplaceEntriesCache = null;
|
|
1245
|
+
let pendingOffer = null;
|
|
1246
|
+
const trackSession = (input) => {
|
|
1247
|
+
const sessionId = input.sessionId ?? null;
|
|
1248
|
+
if (lastSeenSessionId === void 0 || lastSeenSessionId === null && sessionId !== null) {
|
|
1249
|
+
lastSeenSessionId = sessionId;
|
|
1250
|
+
return;
|
|
1118
1251
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1252
|
+
if (sessionId !== lastSeenSessionId) {
|
|
1253
|
+
lastSeenSessionId = sessionId;
|
|
1254
|
+
offeredNames = /* @__PURE__ */ new Set();
|
|
1255
|
+
sessionDeclines = /* @__PURE__ */ new Set();
|
|
1256
|
+
pendingOffer = null;
|
|
1257
|
+
installedNamesCache = null;
|
|
1258
|
+
marketplaceEntriesCache = null;
|
|
1123
1259
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1260
|
+
};
|
|
1261
|
+
const bestMatch = (text) => {
|
|
1262
|
+
const installedWasCached = installedNamesCache !== null;
|
|
1263
|
+
let never;
|
|
1264
|
+
try {
|
|
1265
|
+
installedNamesCache ??= new Set(deps.listInstalledSkillNames());
|
|
1266
|
+
marketplaceEntriesCache ??= deps.listMarketplaceEntries();
|
|
1267
|
+
never = declines.readNever();
|
|
1268
|
+
} catch {
|
|
1129
1269
|
return null;
|
|
1130
1270
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1271
|
+
const declinedKeys = /* @__PURE__ */ new Set([...Object.keys(never), ...sessionDeclines]);
|
|
1272
|
+
const findMatch = () => matchMarketplaceSkills(
|
|
1273
|
+
text,
|
|
1274
|
+
marketplaceEntriesCache ?? [],
|
|
1275
|
+
/* @__PURE__ */ new Set([...installedNamesCache ?? [], ...offeredNames])
|
|
1276
|
+
).find((candidate) => !declinedKeys.has(declineKey(candidate.entry.name, candidate.entry.version))) ?? null;
|
|
1277
|
+
let match = findMatch();
|
|
1278
|
+
if (match && installedWasCached) {
|
|
1279
|
+
try {
|
|
1280
|
+
installedNamesCache = new Set(deps.listInstalledSkillNames());
|
|
1281
|
+
} catch {
|
|
1282
|
+
return null;
|
|
1283
|
+
}
|
|
1284
|
+
match = findMatch();
|
|
1140
1285
|
}
|
|
1141
|
-
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
return
|
|
1286
|
+
return match;
|
|
1287
|
+
};
|
|
1288
|
+
const installGated = (entry, scope) => {
|
|
1289
|
+
assertPromotionInstallSource(entry);
|
|
1290
|
+
const result = deps.installEntry(entry, scope);
|
|
1291
|
+
installedNamesCache?.add(entry.name);
|
|
1292
|
+
return result;
|
|
1293
|
+
};
|
|
1294
|
+
const evaluateAskUserAnswers = (input) => {
|
|
1295
|
+
const offer = pendingOffer;
|
|
1296
|
+
if (!offer) return NO_EFFECTS2;
|
|
1297
|
+
const marker = offerBindingTag(offer.tag);
|
|
1298
|
+
if (input.toolResultDetails?.cancelled === true) {
|
|
1299
|
+
return NO_EFFECTS2;
|
|
1155
1300
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
}
|
|
1166
|
-
return { kind: "effect", effect: result.effect };
|
|
1167
|
-
}
|
|
1168
|
-
function isWithin(child, parent) {
|
|
1169
|
-
const rel = resolve(child);
|
|
1170
|
-
const base = resolve(parent);
|
|
1171
|
-
return rel === base || rel.startsWith(`${base}/`);
|
|
1172
|
-
}
|
|
1173
|
-
function normalizeUserHook(raw, source, options) {
|
|
1174
|
-
const issues = [];
|
|
1175
|
-
if (!isRecord2(raw)) {
|
|
1176
|
-
return { issues: ["hook declaration must be an object"] };
|
|
1177
|
-
}
|
|
1178
|
-
if (raw.on === void 0 || typeof raw.on !== "string" || !isMiddlewareHook(raw.on)) {
|
|
1179
|
-
issues.push("on must be one of before_tool, after_tool, turn_start, turn_end, on_compaction");
|
|
1180
|
-
}
|
|
1181
|
-
let tools;
|
|
1182
|
-
if (raw.tools !== void 0) {
|
|
1183
|
-
const parsed = readStringArray(raw.tools);
|
|
1184
|
-
if (!parsed) issues.push("tools must be an array of non-empty tool names");
|
|
1185
|
-
else tools = parsed;
|
|
1186
|
-
}
|
|
1187
|
-
let enabled = true;
|
|
1188
|
-
if (raw.enabled !== void 0) {
|
|
1189
|
-
if (typeof raw.enabled !== "boolean") issues.push("enabled must be a boolean");
|
|
1190
|
-
else enabled = raw.enabled;
|
|
1191
|
-
}
|
|
1192
|
-
let spec = null;
|
|
1193
|
-
if (raw.kind === "command") spec = normalizeCommandSpec(raw, options, issues);
|
|
1194
|
-
else if (raw.kind === "prompt") spec = normalizePromptSpec(raw, issues);
|
|
1195
|
-
else if (raw.kind === "effect") spec = normalizeEffectSpec(raw, issues);
|
|
1196
|
-
else issues.push('kind must be "command", "prompt", or "effect"');
|
|
1197
|
-
if (issues.length > 0 || spec === null || raw.on === void 0 || typeof raw.on !== "string") {
|
|
1198
|
-
return { issues };
|
|
1199
|
-
}
|
|
1200
|
-
const on = raw.on;
|
|
1201
|
-
const hash = stableHash({ on, tools: tools ?? null, spec });
|
|
1202
|
-
const id = typeof raw.id === "string" && raw.id.length > 0 ? raw.id : `${source.sourceId ?? source.origin}.${spec.kind}.${hash}`;
|
|
1203
|
-
const hook = { id, source, hash, on, enabled, spec };
|
|
1204
|
-
if (tools !== void 0) hook.tools = tools;
|
|
1205
|
-
return { hook, issues };
|
|
1206
|
-
}
|
|
1207
|
-
function declarationsArray(declarations) {
|
|
1208
|
-
if (Array.isArray(declarations)) return declarations;
|
|
1209
|
-
if (isRecord2(declarations) && Array.isArray(declarations.hooks)) return declarations.hooks;
|
|
1210
|
-
return [];
|
|
1211
|
-
}
|
|
1212
|
-
function loadUserHooks(batches, options) {
|
|
1213
|
-
const ordered = [...batches].sort(
|
|
1214
|
-
(a, b) => USER_HOOK_ORIGIN_ORDER.indexOf(a.source.origin) - USER_HOOK_ORIGIN_ORDER.indexOf(b.source.origin)
|
|
1215
|
-
);
|
|
1216
|
-
const byId = /* @__PURE__ */ new Map();
|
|
1217
|
-
const overridden = [];
|
|
1218
|
-
const issues = [];
|
|
1219
|
-
for (const batch of ordered) {
|
|
1220
|
-
const declarations = declarationsArray(batch.declarations);
|
|
1221
|
-
declarations.forEach((raw, index) => {
|
|
1222
|
-
const result = normalizeUserHook(raw, batch.source, options);
|
|
1223
|
-
if (!result.hook) {
|
|
1224
|
-
issues.push({ source: batch.source, index, issues: result.issues });
|
|
1225
|
-
return;
|
|
1301
|
+
for (const answer of answersFromDetails(input.toolResultDetails)) {
|
|
1302
|
+
if (!answer.question.includes(marker)) continue;
|
|
1303
|
+
const option = chosenOfferOption(answer);
|
|
1304
|
+
if (option === null) continue;
|
|
1305
|
+
pendingOffer = null;
|
|
1306
|
+
const offerKey = declineKey(offer.entry.name, offer.entry.version);
|
|
1307
|
+
if (option === SKILL_INSTALL_OFFER_OPTION_NOT_NOW) {
|
|
1308
|
+
sessionDeclines.add(offerKey);
|
|
1309
|
+
return NO_EFFECTS2;
|
|
1226
1310
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
}
|
|
1237
|
-
function commandEffect(hook, output) {
|
|
1238
|
-
const message = output.slice(0, USER_HOOK_COMMAND_OUTPUT_MAX_CHARS);
|
|
1239
|
-
return hook.as === "reminder" ? { kind: "inject_reminder", message } : { kind: "annotate_tool_result", message };
|
|
1240
|
-
}
|
|
1241
|
-
function userHookToRegistration(hook, deps) {
|
|
1242
|
-
const now = deps.now ?? Date.now;
|
|
1243
|
-
const baseReceipt = (input) => ({
|
|
1244
|
-
at: now(),
|
|
1245
|
-
hookId: hook.id,
|
|
1246
|
-
origin: hook.source.origin,
|
|
1247
|
-
sourcePath: hook.source.sourcePath,
|
|
1248
|
-
hash: hook.hash,
|
|
1249
|
-
hook: hook.on,
|
|
1250
|
-
kind: hook.spec.kind,
|
|
1251
|
-
...input.toolName !== void 0 ? { toolName: input.toolName } : {}
|
|
1252
|
-
});
|
|
1253
|
-
const registration = {
|
|
1254
|
-
id: hook.id,
|
|
1255
|
-
description: `${hook.spec.kind} hook from ${hook.source.origin} (${hook.source.sourcePath})`,
|
|
1256
|
-
hooks: [hook.on],
|
|
1257
|
-
evaluate: (input) => {
|
|
1258
|
-
if (!hook.enabled) return [];
|
|
1311
|
+
if (option === SKILL_INSTALL_OFFER_OPTION_NEVER) {
|
|
1312
|
+
sessionDeclines.add(offerKey);
|
|
1313
|
+
try {
|
|
1314
|
+
declines.recordNever(offer.entry.name, offer.entry.version);
|
|
1315
|
+
} catch {
|
|
1316
|
+
}
|
|
1317
|
+
return NO_EFFECTS2;
|
|
1318
|
+
}
|
|
1319
|
+
const scope = option === SKILL_INSTALL_OFFER_OPTION_USER ? "user" : "project";
|
|
1259
1320
|
try {
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1321
|
+
const result = installGated(offer.entry, scope);
|
|
1322
|
+
return [
|
|
1323
|
+
{
|
|
1324
|
+
kind: "annotate_tool_result",
|
|
1325
|
+
severity: "info",
|
|
1326
|
+
message: `[Marketplace] Installed skill "${offer.entry.name}" (${scope} scope) to ${result.path}. It is installed but not active; the operator activates it with /skill ${offer.entry.name}.`
|
|
1327
|
+
}
|
|
1328
|
+
];
|
|
1329
|
+
} catch (error) {
|
|
1330
|
+
sessionDeclines.add(offerKey);
|
|
1331
|
+
return [
|
|
1332
|
+
{
|
|
1333
|
+
kind: "annotate_tool_result",
|
|
1334
|
+
severity: "warn",
|
|
1335
|
+
message: `[Marketplace] Install of "${offer.entry.name}" failed: ${error instanceof Error ? error.message : String(error)}. Continue the task without it.`
|
|
1336
|
+
}
|
|
1337
|
+
];
|
|
1264
1338
|
}
|
|
1265
1339
|
}
|
|
1340
|
+
return NO_EFFECTS2;
|
|
1266
1341
|
};
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
try {
|
|
1301
|
-
text = readFileSync(filePath, "utf8");
|
|
1302
|
-
} catch {
|
|
1303
|
-
return null;
|
|
1304
|
-
}
|
|
1305
|
-
try {
|
|
1306
|
-
const parsed = (0, import_yaml.parse)(text);
|
|
1307
|
-
return { source, declarations: parsed ?? [] };
|
|
1308
|
-
} catch (err) {
|
|
1309
|
-
fileIssues.push({
|
|
1310
|
-
source,
|
|
1311
|
-
message: `failed to parse ${filePath}: ${err instanceof Error ? err.message : String(err)}`
|
|
1312
|
-
});
|
|
1313
|
-
return null;
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
function readHookSources(options) {
|
|
1317
|
-
const fileIssues = [];
|
|
1318
|
-
const batches = [];
|
|
1319
|
-
for (const extension of options.extensions ?? []) {
|
|
1320
|
-
const source = {
|
|
1321
|
-
origin: "extension",
|
|
1322
|
-
sourcePath: `${extension.id}:hooks.yaml`,
|
|
1323
|
-
sourceId: extension.id
|
|
1324
|
-
};
|
|
1325
|
-
const batch = readBatch(source, join(extension.rootPath, "hooks.yaml"), fileIssues);
|
|
1326
|
-
if (batch) batches.push(batch);
|
|
1327
|
-
}
|
|
1328
|
-
const projectBatch = readBatch(
|
|
1329
|
-
{ origin: "project", sourcePath: ".clio-coder/hooks.yaml" },
|
|
1330
|
-
join(options.cwd, ".clio-coder", "hooks.yaml"),
|
|
1331
|
-
fileIssues
|
|
1332
|
-
);
|
|
1333
|
-
if (projectBatch) batches.push(projectBatch);
|
|
1334
|
-
const localBatch = readBatch(
|
|
1335
|
-
{ origin: "project.local", sourcePath: ".clio-coder/hooks.local.yaml" },
|
|
1336
|
-
join(options.cwd, ".clio-coder", "hooks.local.yaml"),
|
|
1337
|
-
fileIssues
|
|
1338
|
-
);
|
|
1339
|
-
if (localBatch) batches.push(localBatch);
|
|
1340
|
-
return { batches, fileIssues };
|
|
1341
|
-
}
|
|
1342
|
-
function installUserHooks(options) {
|
|
1343
|
-
const workspaceRoot = options.workspaceRoot ?? options.cwd;
|
|
1344
|
-
const readOptions = { cwd: options.cwd };
|
|
1345
|
-
if (options.extensions !== void 0) readOptions.extensions = options.extensions;
|
|
1346
|
-
const { batches, fileIssues } = readHookSources(readOptions);
|
|
1347
|
-
const loaded = loadUserHooks(batches, { workspaceRoot });
|
|
1348
|
-
const runCommand = options.runCommand ?? spawnSyncCommandRunner();
|
|
1349
|
-
for (const hook of loaded.hooks) {
|
|
1350
|
-
options.registerHook(
|
|
1351
|
-
userHookToRegistration(hook, {
|
|
1352
|
-
recordReceipt: options.recordReceipt,
|
|
1353
|
-
runCommand,
|
|
1354
|
-
...options.now !== void 0 ? { now: options.now } : {}
|
|
1355
|
-
})
|
|
1356
|
-
);
|
|
1357
|
-
}
|
|
1358
|
-
return { ...loaded, fileIssues };
|
|
1359
|
-
}
|
|
1360
|
-
function spawnSyncCommandRunner() {
|
|
1361
|
-
return (argv, options) => {
|
|
1362
|
-
const [command, ...args] = argv;
|
|
1363
|
-
const attribution = withManagedGitCommitAttributionEnvironment(process.env, {
|
|
1364
|
-
cwd: options.cwd ?? process.cwd(),
|
|
1365
|
-
evidence: {}
|
|
1366
|
-
});
|
|
1367
|
-
reportCommitAttributionDiagnostic(attribution.diagnostic);
|
|
1368
|
-
const result = spawnSync(command ?? "", args, {
|
|
1369
|
-
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
1370
|
-
timeout: options.timeoutMs,
|
|
1371
|
-
maxBuffer: COMMAND_OUTPUT_MAX_BYTES,
|
|
1372
|
-
encoding: "utf8",
|
|
1373
|
-
shell: false,
|
|
1374
|
-
env: attribution.env
|
|
1375
|
-
});
|
|
1376
|
-
const timedOut = result.error !== void 0 && result.error.code === "ETIMEDOUT";
|
|
1377
|
-
return {
|
|
1378
|
-
code: result.status,
|
|
1379
|
-
timedOut,
|
|
1380
|
-
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
1381
|
-
stderr: typeof result.stderr === "string" ? result.stderr : ""
|
|
1382
|
-
};
|
|
1342
|
+
return {
|
|
1343
|
+
id: MARKETPLACE_OFFER_REGISTRATION_ID,
|
|
1344
|
+
description: "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",
|
|
1345
|
+
hooks: ["turn_start", "after_tool"],
|
|
1346
|
+
evaluate(input) {
|
|
1347
|
+
trackSession(input);
|
|
1348
|
+
if (input.hook === "after_tool") {
|
|
1349
|
+
return input.toolName === ToolNames.AskUser ? evaluateAskUserAnswers(input) : NO_EFFECTS2;
|
|
1350
|
+
}
|
|
1351
|
+
if (input.hook !== "turn_start") return NO_EFFECTS2;
|
|
1352
|
+
if (!isSubstantiveUserTurn(input.text)) return NO_EFFECTS2;
|
|
1353
|
+
const pendingSkillRequests = metadataNumber(input, "pendingSkillRequests");
|
|
1354
|
+
if (pendingSkillRequests !== null && pendingSkillRequests > 0) return NO_EFFECTS2;
|
|
1355
|
+
const match = bestMatch(input.text ?? "");
|
|
1356
|
+
if (!match) return NO_EFFECTS2;
|
|
1357
|
+
offeredNames.add(match.entry.name);
|
|
1358
|
+
if (deps.getAutonomy() === "full-auto") {
|
|
1359
|
+
try {
|
|
1360
|
+
const result = installGated(match.entry, "project");
|
|
1361
|
+
return [
|
|
1362
|
+
{
|
|
1363
|
+
kind: "inject_reminder",
|
|
1364
|
+
severity: "info",
|
|
1365
|
+
message: marketplaceAutoInstallReminder(match.entry, result)
|
|
1366
|
+
}
|
|
1367
|
+
];
|
|
1368
|
+
} catch {
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
const tag = newOfferTag();
|
|
1372
|
+
pendingOffer = { entry: match.entry, tag };
|
|
1373
|
+
return [{ kind: "inject_reminder", severity: "info", message: marketplaceOfferReminder(match.entry, tag) }];
|
|
1374
|
+
}
|
|
1383
1375
|
};
|
|
1384
1376
|
}
|
|
1385
1377
|
|
|
1386
1378
|
// src/domains/middleware/memory-intervention.ts
|
|
1387
1379
|
init_esm_shims();
|
|
1388
|
-
import { createHash
|
|
1380
|
+
import { createHash } from "node:crypto";
|
|
1389
1381
|
var MEMORY_INTERVENTION_REGISTRATION_ID = "observer.memory-intervention";
|
|
1390
1382
|
var MEMORY_INTERVENTION_DEFAULT_WINDOW_STEPS = 8;
|
|
1391
1383
|
var MEMORY_INTERVENTION_DEFAULT_MAX_TOKENS = 2e3;
|
|
@@ -1393,7 +1385,7 @@ var MEMORY_INTERVENTION_DEFAULT_EVERY_N_TOOLS = 10;
|
|
|
1393
1385
|
var MEMORY_INTERVENTION_TIMEOUT_BACKOFF_THRESHOLD = 2;
|
|
1394
1386
|
var MEMORY_INTERVENTION_ACTIVITY_LIMIT = 20;
|
|
1395
1387
|
var CALL_DESCRIPTION_MAX_CHARS = 180;
|
|
1396
|
-
var
|
|
1388
|
+
var NO_EFFECTS3 = [];
|
|
1397
1389
|
function createMemoryInterventionRegistration(deps) {
|
|
1398
1390
|
const pending = /* @__PURE__ */ new Map();
|
|
1399
1391
|
const trajectory = [];
|
|
@@ -1423,16 +1415,16 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1423
1415
|
description: "maintain bounded task execution memory and selectively remind after repeated failures or compaction",
|
|
1424
1416
|
hooks: ["before_tool", "after_tool", "turn_start", "turn_end", "on_compaction"],
|
|
1425
1417
|
evaluate(input) {
|
|
1426
|
-
if (!settings().enabled) return
|
|
1418
|
+
if (!settings().enabled) return NO_EFFECTS3;
|
|
1427
1419
|
try {
|
|
1428
1420
|
switch (input.hook) {
|
|
1429
1421
|
case "before_tool":
|
|
1430
1422
|
observeBeforeTool(input);
|
|
1431
|
-
return
|
|
1423
|
+
return NO_EFFECTS3;
|
|
1432
1424
|
case "after_tool":
|
|
1433
1425
|
return observeAfterTool(input);
|
|
1434
1426
|
case "turn_end": {
|
|
1435
|
-
if (toolStep <= lastTurnEndStep) return
|
|
1427
|
+
if (toolStep <= lastTurnEndStep) return NO_EFFECTS3;
|
|
1436
1428
|
const alreadyReported = annotatedSinceTurnEnd;
|
|
1437
1429
|
annotatedSinceTurnEnd = false;
|
|
1438
1430
|
const started = process.hrtime.bigint();
|
|
@@ -1451,9 +1443,9 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1451
1443
|
return effects;
|
|
1452
1444
|
}
|
|
1453
1445
|
case "on_compaction":
|
|
1454
|
-
if (input.metadata?.stage === "working_set_recall") return
|
|
1446
|
+
if (input.metadata?.stage === "working_set_recall") return NO_EFFECTS3;
|
|
1455
1447
|
reactivateAfterCompaction = true;
|
|
1456
|
-
return
|
|
1448
|
+
return NO_EFFECTS3;
|
|
1457
1449
|
case "turn_start": {
|
|
1458
1450
|
if (input.text?.trim()) currentTask = shortText(input.text, 2e3);
|
|
1459
1451
|
annotatedThisTurn.clear();
|
|
@@ -1476,7 +1468,7 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1476
1468
|
}
|
|
1477
1469
|
}
|
|
1478
1470
|
} catch {
|
|
1479
|
-
return
|
|
1471
|
+
return NO_EFFECTS3;
|
|
1480
1472
|
}
|
|
1481
1473
|
},
|
|
1482
1474
|
/**
|
|
@@ -1490,13 +1482,13 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1490
1482
|
* would have been buffered anyway.
|
|
1491
1483
|
*/
|
|
1492
1484
|
async evaluateAsync(input, context) {
|
|
1493
|
-
if (!settings().enabled || input.hook !== "turn_end" || pendingTriggers.size === 0) return
|
|
1485
|
+
if (!settings().enabled || input.hook !== "turn_end" || pendingTriggers.size === 0) return NO_EFFECTS3;
|
|
1494
1486
|
const boundary = input.turnId ?? input.metadata?.userTurnId?.toString() ?? `tool-step:${toolStep}`;
|
|
1495
|
-
if (boundary === lastPromptedBoundary) return
|
|
1487
|
+
if (boundary === lastPromptedBoundary) return NO_EFFECTS3;
|
|
1496
1488
|
if (deps.deliversDeferredReminders === false) {
|
|
1497
1489
|
emitTelemetry([...pendingTriggers], "rules", "silent", "no_consumer", 0, 0, 0, process.hrtime.bigint());
|
|
1498
1490
|
pendingTriggers.clear();
|
|
1499
|
-
return
|
|
1491
|
+
return NO_EFFECTS3;
|
|
1500
1492
|
}
|
|
1501
1493
|
if (promptedStepInFlight) {
|
|
1502
1494
|
emitTelemetry(
|
|
@@ -1509,7 +1501,7 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1509
1501
|
0,
|
|
1510
1502
|
process.hrtime.bigint()
|
|
1511
1503
|
);
|
|
1512
|
-
return
|
|
1504
|
+
return NO_EFFECTS3;
|
|
1513
1505
|
}
|
|
1514
1506
|
lastPromptedBoundary = boundary;
|
|
1515
1507
|
const triggers = [...pendingTriggers];
|
|
@@ -1534,7 +1526,7 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1534
1526
|
}).finally(() => {
|
|
1535
1527
|
promptedStepInFlight = false;
|
|
1536
1528
|
});
|
|
1537
|
-
return
|
|
1529
|
+
return NO_EFFECTS3;
|
|
1538
1530
|
},
|
|
1539
1531
|
runPromptedStep,
|
|
1540
1532
|
signalLoop() {
|
|
@@ -1568,7 +1560,7 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1568
1560
|
inputTokens: 0,
|
|
1569
1561
|
outputTokens: 0,
|
|
1570
1562
|
usage: null,
|
|
1571
|
-
effects:
|
|
1563
|
+
effects: NO_EFFECTS3
|
|
1572
1564
|
});
|
|
1573
1565
|
const live = settings();
|
|
1574
1566
|
if (!live.enabled) {
|
|
@@ -1647,7 +1639,7 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1647
1639
|
);
|
|
1648
1640
|
return {
|
|
1649
1641
|
...promptedResult,
|
|
1650
|
-
effects: promptedResult.reminder === null ?
|
|
1642
|
+
effects: promptedResult.reminder === null ? NO_EFFECTS3 : [{ kind: "inject_reminder", message: promptedResult.reminder, severity: "advisory" }]
|
|
1651
1643
|
};
|
|
1652
1644
|
}
|
|
1653
1645
|
function emitTelemetry(triggerReasons, tier, decision, reason, citedEntries2, inputTokens, outputTokens, started, operations = { bankOperations: 0, droppedOperations: 0 }) {
|
|
@@ -1708,7 +1700,7 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1708
1700
|
}
|
|
1709
1701
|
function observeAfterTool(input) {
|
|
1710
1702
|
const fallback = prepareToolStep(input);
|
|
1711
|
-
if (fallback === null) return
|
|
1703
|
+
if (fallback === null) return NO_EFFECTS3;
|
|
1712
1704
|
const key = pendingKey(input, fallback.operationFingerprint);
|
|
1713
1705
|
const prepared = pending.get(key) ?? fallback;
|
|
1714
1706
|
pending.delete(key);
|
|
@@ -1733,22 +1725,22 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1733
1725
|
};
|
|
1734
1726
|
trajectory.push(step);
|
|
1735
1727
|
if (trajectory.length > live.windowSteps) trajectory.splice(0, trajectory.length - live.windowSteps);
|
|
1736
|
-
if (outcome !== "error") return
|
|
1728
|
+
if (outcome !== "error") return NO_EFFECTS3;
|
|
1737
1729
|
rememberFailure(step);
|
|
1738
1730
|
return annotateRepeatedFailure(step);
|
|
1739
1731
|
}
|
|
1740
1732
|
function annotateRepeatedFailure(step) {
|
|
1741
|
-
if (annotatedThisTurn.has(step.operationFingerprint)) return
|
|
1733
|
+
if (annotatedThisTurn.has(step.operationFingerprint)) return NO_EFFECTS3;
|
|
1742
1734
|
const occurrences = trajectory.filter(
|
|
1743
1735
|
(candidate) => candidate.outcome === "error" && candidate.operationFingerprint === step.operationFingerprint
|
|
1744
1736
|
).length;
|
|
1745
1737
|
const failure = failures.get(step.operationFingerprint);
|
|
1746
|
-
if (occurrences < 2 || failure === void 0) return
|
|
1738
|
+
if (occurrences < 2 || failure === void 0) return NO_EFFECTS3;
|
|
1747
1739
|
const message = boundedReminder(
|
|
1748
1740
|
`Memory: [${failure.entryId}] you already tried ${failure.callDescription} at step ${failure.firstStep} and it failed with ${failure.errorDigest}. Change the approach rather than repeating it.`,
|
|
1749
1741
|
settings().maxTokens
|
|
1750
1742
|
);
|
|
1751
|
-
if (message.length === 0) return
|
|
1743
|
+
if (message.length === 0) return NO_EFFECTS3;
|
|
1752
1744
|
annotatedThisTurn.add(step.operationFingerprint);
|
|
1753
1745
|
lastInjectedOperationFingerprint = step.operationFingerprint;
|
|
1754
1746
|
lastDecision = "injected";
|
|
@@ -1802,7 +1794,7 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1802
1794
|
`Memory: [${failure.entryId}] you already tried ${failure.callDescription} at step ${failure.firstStep} and it failed with ${failure.errorDigest}.`,
|
|
1803
1795
|
settings().maxTokens
|
|
1804
1796
|
);
|
|
1805
|
-
if (message.length === 0) return
|
|
1797
|
+
if (message.length === 0) return NO_EFFECTS3;
|
|
1806
1798
|
lastInjectedOperationFingerprint = step.operationFingerprint;
|
|
1807
1799
|
lastInjectedMessage = message;
|
|
1808
1800
|
lastDecision = "injected";
|
|
@@ -1811,13 +1803,13 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1811
1803
|
return [{ kind: "inject_reminder", message, severity: "advisory" }];
|
|
1812
1804
|
}
|
|
1813
1805
|
lastDecision = "silent";
|
|
1814
|
-
return
|
|
1806
|
+
return NO_EFFECTS3;
|
|
1815
1807
|
} finally {
|
|
1816
1808
|
lastTurnEndStep = toolStep;
|
|
1817
1809
|
}
|
|
1818
1810
|
}
|
|
1819
1811
|
function reactivateKnowledge() {
|
|
1820
|
-
if (!reactivateAfterCompaction) return
|
|
1812
|
+
if (!reactivateAfterCompaction) return NO_EFFECTS3;
|
|
1821
1813
|
reactivateAfterCompaction = false;
|
|
1822
1814
|
const prefix = "Memory: execution state restored after compaction:\n";
|
|
1823
1815
|
const maxTokens = settings().maxTokens;
|
|
@@ -1825,12 +1817,12 @@ function createMemoryInterventionRegistration(deps) {
|
|
|
1825
1817
|
const rendered = deps.bank.renderRestoredState(Math.max(0, maxTokens - prefixTokens));
|
|
1826
1818
|
if (rendered.length === 0) {
|
|
1827
1819
|
lastDecision = "silent";
|
|
1828
|
-
return
|
|
1820
|
+
return NO_EFFECTS3;
|
|
1829
1821
|
}
|
|
1830
1822
|
const message = boundedReminder(`${prefix}${rendered}`, maxTokens);
|
|
1831
1823
|
if (message.length === 0) {
|
|
1832
1824
|
lastDecision = "silent";
|
|
1833
|
-
return
|
|
1825
|
+
return NO_EFFECTS3;
|
|
1834
1826
|
}
|
|
1835
1827
|
const citedIds = [...message.matchAll(/\[([^\]]+)\]/gu)].map((match) => match[1]).filter((id) => id !== void 0);
|
|
1836
1828
|
deps.bank.recordInjection(citedIds);
|
|
@@ -1845,7 +1837,7 @@ function prepareToolStep(input) {
|
|
|
1845
1837
|
const canonical = hashToolCall(toolName, input.toolArgs ?? {});
|
|
1846
1838
|
return {
|
|
1847
1839
|
toolName,
|
|
1848
|
-
operationFingerprint:
|
|
1840
|
+
operationFingerprint: createHash("sha256").update(canonical).digest("hex").slice(0, 16),
|
|
1849
1841
|
callDescription: shortText(canonical, CALL_DESCRIPTION_MAX_CHARS)
|
|
1850
1842
|
};
|
|
1851
1843
|
}
|
|
@@ -1929,114 +1921,6 @@ function announceMemoryStepEndpoint(deps, complete) {
|
|
|
1929
1921
|
};
|
|
1930
1922
|
}
|
|
1931
1923
|
|
|
1932
|
-
// src/domains/middleware/skills-reminder.ts
|
|
1933
|
-
init_esm_shims();
|
|
1934
|
-
var SKILLS_REMINDER_REGISTRATION_ID = "observer.skills-reminder";
|
|
1935
|
-
function skillsReminderMessage(installed, installable = 0) {
|
|
1936
|
-
const counts = installable > 0 ? `${installed} installed, ${installable} installable from the marketplace` : `${installed} installed`;
|
|
1937
|
-
return `[Skills] ${counts}. Start this task by listing them with context(scope="skills") and checking for a match; if one matches, open your reply with the line \`${SKILL_SUGGESTION_ANCHOR}\` (a comma-separated sequence, in order, when several compose) and then continue the task in the same turn without the skill. Only the operator loads a skill, and a marketplace skill is offered for install when the operator runs it. If none match, do not mention skills and continue with the task.`;
|
|
1938
|
-
}
|
|
1939
|
-
var NO_EFFECTS2 = [];
|
|
1940
|
-
var GREETING_WORDS = /* @__PURE__ */ new Set([
|
|
1941
|
-
"hi",
|
|
1942
|
-
"hello",
|
|
1943
|
-
"hey",
|
|
1944
|
-
"heya",
|
|
1945
|
-
"hiya",
|
|
1946
|
-
"howdy",
|
|
1947
|
-
"yo",
|
|
1948
|
-
"sup",
|
|
1949
|
-
"hola",
|
|
1950
|
-
"greetings",
|
|
1951
|
-
"gm",
|
|
1952
|
-
"gn",
|
|
1953
|
-
"morning",
|
|
1954
|
-
"afternoon",
|
|
1955
|
-
"evening",
|
|
1956
|
-
"good",
|
|
1957
|
-
"day",
|
|
1958
|
-
"night",
|
|
1959
|
-
"there",
|
|
1960
|
-
"you",
|
|
1961
|
-
"clio",
|
|
1962
|
-
"thanks",
|
|
1963
|
-
"thank",
|
|
1964
|
-
"thankyou",
|
|
1965
|
-
"thx",
|
|
1966
|
-
"ty",
|
|
1967
|
-
"ok",
|
|
1968
|
-
"okay",
|
|
1969
|
-
"k",
|
|
1970
|
-
"cool",
|
|
1971
|
-
"nice",
|
|
1972
|
-
"test",
|
|
1973
|
-
"testing",
|
|
1974
|
-
"ping",
|
|
1975
|
-
"pong"
|
|
1976
|
-
]);
|
|
1977
|
-
function isSubstantiveUserTurn(text) {
|
|
1978
|
-
const normalized = (text ?? "").toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ").trim();
|
|
1979
|
-
if (normalized.length === 0) return false;
|
|
1980
|
-
const tokens = normalized.split(" ");
|
|
1981
|
-
if (tokens.length > 4) return true;
|
|
1982
|
-
return tokens.some((token) => !GREETING_WORDS.has(token));
|
|
1983
|
-
}
|
|
1984
|
-
function createSkillsReminderRegistration(deps) {
|
|
1985
|
-
let lastSeenSessionId;
|
|
1986
|
-
let spentForActiveSession = false;
|
|
1987
|
-
let observedFreshStart = false;
|
|
1988
|
-
let observedAnyTurn = false;
|
|
1989
|
-
return {
|
|
1990
|
-
id: SKILLS_REMINDER_REGISTRATION_ID,
|
|
1991
|
-
description: "once per session, on the first substantive turn, teaches the skill-suggestion reply protocol; keeps a turn going that stopped on the suggestion",
|
|
1992
|
-
hooks: ["turn_start", "turn_end"],
|
|
1993
|
-
evaluate(input) {
|
|
1994
|
-
if (input.hook === "turn_end") {
|
|
1995
|
-
return isSkillSuggestionWait(input) ? [{ kind: "request_continuation", message: SKILL_SUGGESTION_WAIT_CONTINUATION_MESSAGE }] : NO_EFFECTS2;
|
|
1996
|
-
}
|
|
1997
|
-
const sessionId = input.sessionId ?? null;
|
|
1998
|
-
if (lastSeenSessionId === void 0) {
|
|
1999
|
-
lastSeenSessionId = sessionId;
|
|
2000
|
-
} else if (lastSeenSessionId === null && sessionId !== null) {
|
|
2001
|
-
lastSeenSessionId = sessionId;
|
|
2002
|
-
} else if (sessionId !== lastSeenSessionId) {
|
|
2003
|
-
lastSeenSessionId = sessionId;
|
|
2004
|
-
spentForActiveSession = false;
|
|
2005
|
-
observedFreshStart = false;
|
|
2006
|
-
observedAnyTurn = false;
|
|
2007
|
-
}
|
|
2008
|
-
if (spentForActiveSession) return NO_EFFECTS2;
|
|
2009
|
-
const conversationMessages = metadataNumber(input, "conversationMessages");
|
|
2010
|
-
if (!observedAnyTurn) {
|
|
2011
|
-
observedAnyTurn = true;
|
|
2012
|
-
if (conversationMessages === null || conversationMessages > 0) {
|
|
2013
|
-
spentForActiveSession = true;
|
|
2014
|
-
return NO_EFFECTS2;
|
|
2015
|
-
}
|
|
2016
|
-
observedFreshStart = true;
|
|
2017
|
-
}
|
|
2018
|
-
if (!observedFreshStart) {
|
|
2019
|
-
spentForActiveSession = true;
|
|
2020
|
-
return NO_EFFECTS2;
|
|
2021
|
-
}
|
|
2022
|
-
if (!isSubstantiveUserTurn(input.text)) return NO_EFFECTS2;
|
|
2023
|
-
spentForActiveSession = true;
|
|
2024
|
-
const pendingSkillRequests = metadataNumber(input, "pendingSkillRequests");
|
|
2025
|
-
if (pendingSkillRequests !== null && pendingSkillRequests > 0) return NO_EFFECTS2;
|
|
2026
|
-
let installed = 0;
|
|
2027
|
-
let installable = 0;
|
|
2028
|
-
try {
|
|
2029
|
-
installed = deps.countModelVisibleSkills();
|
|
2030
|
-
installable = deps.countInstallableSkills?.() ?? 0;
|
|
2031
|
-
} catch {
|
|
2032
|
-
return NO_EFFECTS2;
|
|
2033
|
-
}
|
|
2034
|
-
if (installed <= 0 && installable <= 0) return NO_EFFECTS2;
|
|
2035
|
-
return [{ kind: "inject_reminder", severity: "info", message: skillsReminderMessage(installed, installable) }];
|
|
2036
|
-
}
|
|
2037
|
-
};
|
|
2038
|
-
}
|
|
2039
|
-
|
|
2040
1924
|
// src/domains/middleware/task-board-reminder.ts
|
|
2041
1925
|
init_esm_shims();
|
|
2042
1926
|
var TASK_BOARD_REMINDER_REGISTRATION_ID = "observer.task-board-reminder";
|
|
@@ -2063,7 +1947,7 @@ function countEnumeratedSteps(text) {
|
|
|
2063
1947
|
const bulletLines = value.split(/\r?\n/).filter((line) => /^\s*[-*]\s+\S/.test(line)).length;
|
|
2064
1948
|
return bulletLines >= 3 ? bulletLines : 0;
|
|
2065
1949
|
}
|
|
2066
|
-
var
|
|
1950
|
+
var NO_EFFECTS4 = [];
|
|
2067
1951
|
function createTaskBoardReminderRegistration() {
|
|
2068
1952
|
let lastSeenSessionId;
|
|
2069
1953
|
let spentForActiveSession = false;
|
|
@@ -2079,12 +1963,12 @@ function createTaskBoardReminderRegistration() {
|
|
|
2079
1963
|
lastSeenSessionId = sessionId;
|
|
2080
1964
|
spentForActiveSession = false;
|
|
2081
1965
|
}
|
|
2082
|
-
if (spentForActiveSession) return
|
|
1966
|
+
if (spentForActiveSession) return NO_EFFECTS4;
|
|
2083
1967
|
const steps = countEnumeratedSteps(input.text);
|
|
2084
|
-
if (steps < 3) return
|
|
1968
|
+
if (steps < 3) return NO_EFFECTS4;
|
|
2085
1969
|
spentForActiveSession = true;
|
|
2086
1970
|
const pendingSkillRequests = metadataNumber(input, "pendingSkillRequests");
|
|
2087
|
-
if (pendingSkillRequests !== null && pendingSkillRequests > 0) return
|
|
1971
|
+
if (pendingSkillRequests !== null && pendingSkillRequests > 0) return NO_EFFECTS4;
|
|
2088
1972
|
return [{ kind: "inject_reminder", severity: "info", message: taskBoardReminderMessage(steps) }];
|
|
2089
1973
|
}
|
|
2090
1974
|
};
|
|
@@ -2166,7 +2050,7 @@ var WATCHDOG_DIFF_MAX_BYTES = 12 * 1024;
|
|
|
2166
2050
|
var WATCHDOG_PATHS_MAX = 40;
|
|
2167
2051
|
var WATCHDOG_TRUNCATION_MARKER = "\n[diff truncated]";
|
|
2168
2052
|
var MUTATING_TOOL_NAMES = /* @__PURE__ */ new Set([ToolNames.Write, ToolNames.Edit, ToolNames.Artifact]);
|
|
2169
|
-
var
|
|
2053
|
+
var NO_EFFECTS5 = [];
|
|
2170
2054
|
function stringValue2(value) {
|
|
2171
2055
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
2172
2056
|
}
|
|
@@ -2174,20 +2058,20 @@ function firstPath(details) {
|
|
|
2174
2058
|
const paths = details?.paths;
|
|
2175
2059
|
if (!Array.isArray(paths)) return null;
|
|
2176
2060
|
for (const entry of paths) {
|
|
2177
|
-
const
|
|
2178
|
-
if (
|
|
2061
|
+
const path2 = stringValue2(entry);
|
|
2062
|
+
if (path2 !== null) return path2;
|
|
2179
2063
|
}
|
|
2180
2064
|
return null;
|
|
2181
2065
|
}
|
|
2182
2066
|
function coalesceTurnDiff(byPath, maxBytes = WATCHDOG_DIFF_MAX_BYTES) {
|
|
2183
2067
|
const blocks = [];
|
|
2184
2068
|
let index = 0;
|
|
2185
|
-
for (const [
|
|
2069
|
+
for (const [path2, diff] of byPath) {
|
|
2186
2070
|
if (index >= WATCHDOG_PATHS_MAX) {
|
|
2187
2071
|
blocks.push(`[${byPath.size - WATCHDOG_PATHS_MAX} more changed path(s) omitted]`);
|
|
2188
2072
|
break;
|
|
2189
2073
|
}
|
|
2190
|
-
blocks.push(`--- ${
|
|
2074
|
+
blocks.push(`--- ${path2}
|
|
2191
2075
|
${diff}`);
|
|
2192
2076
|
index += 1;
|
|
2193
2077
|
}
|
|
@@ -2279,19 +2163,19 @@ function createWatchdogRegistration(deps) {
|
|
|
2279
2163
|
const settings = active();
|
|
2280
2164
|
if (settings === null) {
|
|
2281
2165
|
if (input.hook === "turn_end") resetTurn();
|
|
2282
|
-
return
|
|
2166
|
+
return NO_EFFECTS5;
|
|
2283
2167
|
}
|
|
2284
2168
|
if (input.hook === "after_tool") {
|
|
2285
2169
|
toolCalls += 1;
|
|
2286
2170
|
recordMutation(input);
|
|
2287
2171
|
const cadence = settings.cadenceToolCalls;
|
|
2288
2172
|
if (cadence !== void 0 && cadence >= 1 && toolCalls % cadence === 0) fire("cadence");
|
|
2289
|
-
return
|
|
2173
|
+
return NO_EFFECTS5;
|
|
2290
2174
|
}
|
|
2291
|
-
if (input.hook !== "turn_end") return
|
|
2175
|
+
if (input.hook !== "turn_end") return NO_EFFECTS5;
|
|
2292
2176
|
fire("turn_end");
|
|
2293
2177
|
resetTurn();
|
|
2294
|
-
return
|
|
2178
|
+
return NO_EFFECTS5;
|
|
2295
2179
|
},
|
|
2296
2180
|
droppedTriggers: () => dropped,
|
|
2297
2181
|
runInFlight: () => inFlight,
|
|
@@ -2312,6 +2196,179 @@ init_esm_shims();
|
|
|
2312
2196
|
// src/domains/middleware/extension.ts
|
|
2313
2197
|
init_esm_shims();
|
|
2314
2198
|
|
|
2199
|
+
// src/domains/middleware/registrations.ts
|
|
2200
|
+
init_esm_shims();
|
|
2201
|
+
var MIDDLEWARE_REGISTRATION_OWNERS = ["user-hooks"];
|
|
2202
|
+
function isRegistrationOwner(value) {
|
|
2203
|
+
return MIDDLEWARE_REGISTRATION_OWNERS.includes(value);
|
|
2204
|
+
}
|
|
2205
|
+
function createMiddlewareRegistrationTable(options) {
|
|
2206
|
+
const fixed = Object.freeze([...options.fixed]);
|
|
2207
|
+
const fixedIds = new Set(fixed.map((registration) => registration.id));
|
|
2208
|
+
const buildList = (host, slots) => {
|
|
2209
|
+
const list = [...fixed];
|
|
2210
|
+
const slotAt = (index) => {
|
|
2211
|
+
for (const owner of MIDDLEWARE_REGISTRATION_OWNERS) {
|
|
2212
|
+
const slot = slots.get(owner);
|
|
2213
|
+
if (slot !== void 0 && slot.anchor === index) list.push(...slot.registrations);
|
|
2214
|
+
}
|
|
2215
|
+
};
|
|
2216
|
+
for (let index = 0; index < host.length; index += 1) {
|
|
2217
|
+
slotAt(index);
|
|
2218
|
+
list.push(host[index]);
|
|
2219
|
+
}
|
|
2220
|
+
slotAt(host.length);
|
|
2221
|
+
return Object.freeze(list);
|
|
2222
|
+
};
|
|
2223
|
+
const makeState = (host, slots) => Object.freeze({
|
|
2224
|
+
host: Object.freeze([...host]),
|
|
2225
|
+
hostIds: new Set(host.map((registration) => registration.id)),
|
|
2226
|
+
slots: new Map(slots),
|
|
2227
|
+
list: buildList(host, slots)
|
|
2228
|
+
});
|
|
2229
|
+
let state = makeState([], /* @__PURE__ */ new Map());
|
|
2230
|
+
const emit = (diagnostic) => {
|
|
2231
|
+
try {
|
|
2232
|
+
options.diagnosticSink()(diagnostic);
|
|
2233
|
+
} catch {
|
|
2234
|
+
}
|
|
2235
|
+
};
|
|
2236
|
+
const slotFor = (base, owner) => base.slots.get(owner) ?? { generation: 0, registrations: [], anchor: base.host.length };
|
|
2237
|
+
const disposeGeneration = (owner, generation) => {
|
|
2238
|
+
const base = state;
|
|
2239
|
+
const held = base.slots.get(owner);
|
|
2240
|
+
if (held === void 0 || held.generation !== generation || held.registrations.length === 0) return;
|
|
2241
|
+
const slots = new Map(base.slots);
|
|
2242
|
+
slots.set(owner, { ...held, registrations: Object.freeze([]) });
|
|
2243
|
+
state = makeState(base.host, slots);
|
|
2244
|
+
};
|
|
2245
|
+
const table = {
|
|
2246
|
+
list: () => state.list,
|
|
2247
|
+
registerHook(registration) {
|
|
2248
|
+
const base = state;
|
|
2249
|
+
if (fixedIds.has(registration.id) || base.hostIds.has(registration.id)) return;
|
|
2250
|
+
const evictions = [];
|
|
2251
|
+
const slots = new Map(base.slots);
|
|
2252
|
+
for (const [owner, slot] of base.slots) {
|
|
2253
|
+
if (!slot.registrations.some((entry) => entry.id === registration.id)) continue;
|
|
2254
|
+
slots.set(owner, {
|
|
2255
|
+
...slot,
|
|
2256
|
+
registrations: Object.freeze(slot.registrations.filter((entry) => entry.id !== registration.id))
|
|
2257
|
+
});
|
|
2258
|
+
evictions.push({
|
|
2259
|
+
kind: "registration_conflict",
|
|
2260
|
+
registrationId: registration.id,
|
|
2261
|
+
owner,
|
|
2262
|
+
generation: slot.generation,
|
|
2263
|
+
conflictsWith: "host",
|
|
2264
|
+
action: "evicted"
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2267
|
+
state = makeState([...base.host, registration], slots);
|
|
2268
|
+
for (const eviction of evictions) emit(eviction);
|
|
2269
|
+
},
|
|
2270
|
+
prepareReplacement(owner, generation, registrations) {
|
|
2271
|
+
if (!isRegistrationOwner(owner)) {
|
|
2272
|
+
return { status: "rejected", owner, reason: "unknown-owner", activeGeneration: 0 };
|
|
2273
|
+
}
|
|
2274
|
+
const base = state;
|
|
2275
|
+
const slot = slotFor(base, owner);
|
|
2276
|
+
if (!Number.isInteger(generation) || generation <= slot.generation) {
|
|
2277
|
+
return { status: "rejected", owner, reason: "stale", activeGeneration: slot.generation };
|
|
2278
|
+
}
|
|
2279
|
+
const dropped = [];
|
|
2280
|
+
const conflicts = [];
|
|
2281
|
+
const accepted = [];
|
|
2282
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2283
|
+
for (const registration of registrations) {
|
|
2284
|
+
const conflictsWith = fixedIds.has(registration.id) ? "builtin" : base.hostIds.has(registration.id) ? "host" : seen.has(registration.id) ? "owned" : null;
|
|
2285
|
+
if (conflictsWith !== null) {
|
|
2286
|
+
dropped.push({ id: registration.id, conflictsWith });
|
|
2287
|
+
conflicts.push({
|
|
2288
|
+
kind: "registration_conflict",
|
|
2289
|
+
registrationId: registration.id,
|
|
2290
|
+
owner,
|
|
2291
|
+
generation,
|
|
2292
|
+
conflictsWith,
|
|
2293
|
+
action: "dropped"
|
|
2294
|
+
});
|
|
2295
|
+
continue;
|
|
2296
|
+
}
|
|
2297
|
+
seen.add(registration.id);
|
|
2298
|
+
accepted.push(registration);
|
|
2299
|
+
}
|
|
2300
|
+
const slots = new Map(base.slots);
|
|
2301
|
+
slots.set(owner, { generation, registrations: Object.freeze(accepted), anchor: slot.anchor });
|
|
2302
|
+
const prepared = makeState(base.host, slots);
|
|
2303
|
+
let settled = false;
|
|
2304
|
+
const frozenDropped = Object.freeze(dropped);
|
|
2305
|
+
const frozenConflicts = Object.freeze(conflicts);
|
|
2306
|
+
const replacement = {
|
|
2307
|
+
owner,
|
|
2308
|
+
generation,
|
|
2309
|
+
dropped: frozenDropped,
|
|
2310
|
+
conflicts: frozenConflicts,
|
|
2311
|
+
size: accepted.length,
|
|
2312
|
+
// Reference identity on the base state covers every kind of
|
|
2313
|
+
// intervening change: host appends, other replacements, disposals.
|
|
2314
|
+
current: () => !settled && state === base,
|
|
2315
|
+
publish() {
|
|
2316
|
+
settled = true;
|
|
2317
|
+
state = prepared;
|
|
2318
|
+
},
|
|
2319
|
+
emitConflicts() {
|
|
2320
|
+
for (const conflict of frozenConflicts) emit(conflict);
|
|
2321
|
+
},
|
|
2322
|
+
dispose() {
|
|
2323
|
+
disposeGeneration(owner, generation);
|
|
2324
|
+
},
|
|
2325
|
+
discard() {
|
|
2326
|
+
settled = true;
|
|
2327
|
+
}
|
|
2328
|
+
};
|
|
2329
|
+
return { status: "prepared", replacement };
|
|
2330
|
+
},
|
|
2331
|
+
replaceRegistrations(owner, generation, registrations) {
|
|
2332
|
+
const prepared = table.prepareReplacement(owner, generation, registrations);
|
|
2333
|
+
if (prepared.status === "rejected") {
|
|
2334
|
+
return {
|
|
2335
|
+
applied: false,
|
|
2336
|
+
owner: prepared.owner,
|
|
2337
|
+
activeGeneration: prepared.activeGeneration,
|
|
2338
|
+
reason: prepared.reason,
|
|
2339
|
+
dropped: [],
|
|
2340
|
+
dispose: () => void 0
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2343
|
+
const replacement = prepared.replacement;
|
|
2344
|
+
if (!replacement.current()) {
|
|
2345
|
+
replacement.discard();
|
|
2346
|
+
return {
|
|
2347
|
+
applied: false,
|
|
2348
|
+
owner,
|
|
2349
|
+
activeGeneration: table.ownedGeneration(owner),
|
|
2350
|
+
reason: "stale",
|
|
2351
|
+
dropped: replacement.dropped,
|
|
2352
|
+
dispose: () => void 0
|
|
2353
|
+
};
|
|
2354
|
+
}
|
|
2355
|
+
replacement.publish();
|
|
2356
|
+
replacement.emitConflicts();
|
|
2357
|
+
return {
|
|
2358
|
+
applied: true,
|
|
2359
|
+
owner,
|
|
2360
|
+
activeGeneration: generation,
|
|
2361
|
+
dropped: replacement.dropped,
|
|
2362
|
+
dispose: () => replacement.dispose()
|
|
2363
|
+
};
|
|
2364
|
+
},
|
|
2365
|
+
ownedGeneration(owner) {
|
|
2366
|
+
return state.slots.get(owner)?.generation ?? 0;
|
|
2367
|
+
}
|
|
2368
|
+
};
|
|
2369
|
+
return table;
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2315
2372
|
// src/domains/middleware/snapshot.ts
|
|
2316
2373
|
init_esm_shims();
|
|
2317
2374
|
function createMiddlewareSnapshot(rules = listMiddlewareRules()) {
|
|
@@ -2332,15 +2389,18 @@ function createMiddlewareContractFromSnapshot(snapshot) {
|
|
|
2332
2389
|
if (builtin?.predicate !== void 0) definition.predicate = builtin.predicate;
|
|
2333
2390
|
return definition;
|
|
2334
2391
|
});
|
|
2335
|
-
|
|
2336
|
-
const
|
|
2392
|
+
let diagnosticSink;
|
|
2393
|
+
const table = createMiddlewareRegistrationTable({
|
|
2394
|
+
fixed: definitions.map(registrationFromRuleDefinition),
|
|
2395
|
+
diagnosticSink: () => diagnosticSink ?? writeMiddlewareDiagnosticToStderr
|
|
2396
|
+
});
|
|
2337
2397
|
const budgetTracker = createHookBudgetTracker({
|
|
2338
2398
|
budgets: resolveHookBudgetsFromEnv(),
|
|
2339
2399
|
...resolveHookBudgetTunablesFromEnv()
|
|
2340
2400
|
});
|
|
2341
|
-
let diagnosticSink;
|
|
2342
2401
|
return {
|
|
2343
2402
|
runHook(input) {
|
|
2403
|
+
const registrations = table.list();
|
|
2344
2404
|
return runMiddlewareRegistrations(input, registrations, {
|
|
2345
2405
|
budgetTracker,
|
|
2346
2406
|
...diagnosticSink !== void 0 ? { onDiagnostic: diagnosticSink } : {}
|
|
@@ -2353,12 +2413,19 @@ function createMiddlewareContractFromSnapshot(snapshot) {
|
|
|
2353
2413
|
return createMiddlewareSnapshot(definitions.map((definition) => definition.rule));
|
|
2354
2414
|
},
|
|
2355
2415
|
registerHook(registration) {
|
|
2356
|
-
|
|
2357
|
-
registeredIds.add(registration.id);
|
|
2358
|
-
registrations.push(registration);
|
|
2416
|
+
table.registerHook(registration);
|
|
2359
2417
|
},
|
|
2360
2418
|
setDiagnosticSink(sink) {
|
|
2361
2419
|
diagnosticSink = sink;
|
|
2420
|
+
},
|
|
2421
|
+
prepareRegistrationReplacement(owner, generation, registrations) {
|
|
2422
|
+
return table.prepareReplacement(owner, generation, registrations);
|
|
2423
|
+
},
|
|
2424
|
+
replaceRegistrations(owner, generation, registrations) {
|
|
2425
|
+
return table.replaceRegistrations(owner, generation, registrations);
|
|
2426
|
+
},
|
|
2427
|
+
ownedGeneration(owner) {
|
|
2428
|
+
return table.ownedGeneration(owner);
|
|
2362
2429
|
}
|
|
2363
2430
|
};
|
|
2364
2431
|
}
|
|
@@ -2369,18 +2436,23 @@ function createEnvHookBudgetTracker(env = process.env) {
|
|
|
2369
2436
|
}
|
|
2370
2437
|
function createMiddlewareBundle(options = {}) {
|
|
2371
2438
|
const ruleDefinitions = combineRuleDefinitions(listMiddlewareRuleDefinitions(), options.ruleDefinitions ?? []);
|
|
2372
|
-
const registrations = combineRegistrations(ruleDefinitions, options.registrations ?? []);
|
|
2373
|
-
const registeredIds = new Set(registrations.map((registration) => registration.id));
|
|
2374
2439
|
let diagnosticSink = options.onDiagnostic;
|
|
2440
|
+
const table = createMiddlewareRegistrationTable({
|
|
2441
|
+
fixed: ruleDefinitions.map(registrationFromRuleDefinition),
|
|
2442
|
+
diagnosticSink: () => diagnosticSink ?? writeMiddlewareDiagnosticToStderr
|
|
2443
|
+
});
|
|
2444
|
+
for (const registration of options.registrations ?? []) table.registerHook(registration);
|
|
2375
2445
|
const budgetTracker = options.budgetTracker ?? createEnvHookBudgetTracker();
|
|
2376
2446
|
const contract = {
|
|
2377
2447
|
runHook(input) {
|
|
2448
|
+
const registrations = table.list();
|
|
2378
2449
|
return runMiddlewareRegistrations(input, registrations, {
|
|
2379
2450
|
budgetTracker,
|
|
2380
2451
|
...diagnosticSink !== void 0 ? { onDiagnostic: diagnosticSink } : {}
|
|
2381
2452
|
});
|
|
2382
2453
|
},
|
|
2383
2454
|
runAsyncHook(input, priorEffects = []) {
|
|
2455
|
+
const registrations = table.list();
|
|
2384
2456
|
return runMiddlewareAsyncRegistrations(input, registrations, priorEffects, {
|
|
2385
2457
|
...diagnosticSink !== void 0 ? { onDiagnostic: diagnosticSink } : {}
|
|
2386
2458
|
});
|
|
@@ -2392,12 +2464,19 @@ function createMiddlewareBundle(options = {}) {
|
|
|
2392
2464
|
return createMiddlewareSnapshot(ruleDefinitions.map((definition) => definition.rule));
|
|
2393
2465
|
},
|
|
2394
2466
|
registerHook(registration) {
|
|
2395
|
-
|
|
2396
|
-
registeredIds.add(registration.id);
|
|
2397
|
-
registrations.push(registration);
|
|
2467
|
+
table.registerHook(registration);
|
|
2398
2468
|
},
|
|
2399
2469
|
setDiagnosticSink(sink) {
|
|
2400
2470
|
diagnosticSink = sink;
|
|
2471
|
+
},
|
|
2472
|
+
prepareRegistrationReplacement(owner, generation, registrations) {
|
|
2473
|
+
return table.prepareReplacement(owner, generation, registrations);
|
|
2474
|
+
},
|
|
2475
|
+
replaceRegistrations(owner, generation, registrations) {
|
|
2476
|
+
return table.replaceRegistrations(owner, generation, registrations);
|
|
2477
|
+
},
|
|
2478
|
+
ownedGeneration(owner) {
|
|
2479
|
+
return table.ownedGeneration(owner);
|
|
2401
2480
|
}
|
|
2402
2481
|
};
|
|
2403
2482
|
return {
|
|
@@ -2419,16 +2498,6 @@ function combineRuleDefinitions(builtin, registered) {
|
|
|
2419
2498
|
}
|
|
2420
2499
|
return combined;
|
|
2421
2500
|
}
|
|
2422
|
-
function combineRegistrations(ruleDefinitions, coded) {
|
|
2423
|
-
const seen = new Set(ruleDefinitions.map((definition) => definition.rule.id));
|
|
2424
|
-
const combined = ruleDefinitions.map(registrationFromRuleDefinition);
|
|
2425
|
-
for (const registration of coded) {
|
|
2426
|
-
if (seen.has(registration.id)) continue;
|
|
2427
|
-
seen.add(registration.id);
|
|
2428
|
-
combined.push(registration);
|
|
2429
|
-
}
|
|
2430
|
-
return combined;
|
|
2431
|
-
}
|
|
2432
2501
|
|
|
2433
2502
|
// src/domains/middleware/manifest.ts
|
|
2434
2503
|
init_esm_shims();
|
|
@@ -2437,28 +2506,496 @@ var MiddlewareManifest = {
|
|
|
2437
2506
|
dependsOn: []
|
|
2438
2507
|
};
|
|
2439
2508
|
|
|
2440
|
-
// src/domains/middleware/
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
};
|
|
2509
|
+
// src/domains/middleware/hooks.ts
|
|
2510
|
+
init_esm_shims();
|
|
2511
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
2512
|
+
import { isAbsolute, resolve } from "node:path";
|
|
2445
2513
|
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2514
|
+
// src/domains/middleware/validate.ts
|
|
2515
|
+
init_esm_shims();
|
|
2516
|
+
function validateMiddlewareEffect(value, source = "$") {
|
|
2517
|
+
const issues = [];
|
|
2518
|
+
const effect = readMiddlewareEffect(value, source, issues);
|
|
2519
|
+
if (issues.length > 0 || effect === null) return { valid: false, issues };
|
|
2520
|
+
return { valid: true, effect, issues: [] };
|
|
2521
|
+
}
|
|
2522
|
+
function readMiddlewareEffect(value, path2, issues) {
|
|
2523
|
+
if (!isRecord(value)) {
|
|
2524
|
+
issues.push({ path: path2, message: "expected middleware effect object" });
|
|
2525
|
+
return null;
|
|
2526
|
+
}
|
|
2527
|
+
const kindValue = value.kind;
|
|
2528
|
+
if (typeof kindValue !== "string" || !isMiddlewareEffectKind(kindValue)) {
|
|
2529
|
+
issues.push({ path: `${path2}.kind`, message: "expected known middleware effect kind" });
|
|
2530
|
+
return null;
|
|
2531
|
+
}
|
|
2532
|
+
switch (kindValue) {
|
|
2533
|
+
case "inject_reminder":
|
|
2534
|
+
return readInjectReminder(value, path2, issues);
|
|
2535
|
+
case "annotate_tool_result":
|
|
2536
|
+
return readAnnotateToolResult(value, path2, issues);
|
|
2537
|
+
case "block_tool":
|
|
2538
|
+
return readBlockTool(value, path2, issues);
|
|
2539
|
+
case "protect_path":
|
|
2540
|
+
return readProtectPath(value, path2, issues);
|
|
2541
|
+
case "request_continuation":
|
|
2542
|
+
return readRequestContinuation(value, path2, issues);
|
|
2543
|
+
case "require_tool":
|
|
2544
|
+
return readRequireTool(value, path2, issues);
|
|
2545
|
+
case "lock_tools":
|
|
2546
|
+
rejectUnexpectedFields(value, path2, ["kind"], issues);
|
|
2547
|
+
return { kind: "lock_tools" };
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
function readRequireTool(record, path2, issues) {
|
|
2551
|
+
rejectUnexpectedFields(record, path2, ["kind", "toolName"], issues);
|
|
2552
|
+
const toolName = readRequiredString(record, `${path2}.toolName`, issues);
|
|
2553
|
+
return toolName === null ? null : { kind: "require_tool", toolName };
|
|
2554
|
+
}
|
|
2555
|
+
function readInjectReminder(record, path2, issues) {
|
|
2556
|
+
rejectUnexpectedFields(record, path2, ["kind", "message", "severity"], issues);
|
|
2557
|
+
const message = readRequiredString(record, `${path2}.message`, issues);
|
|
2558
|
+
const severity = readOptionalString(record, `${path2}.severity`, issues);
|
|
2559
|
+
if (severity !== void 0 && !isMiddlewareReminderSeverity(severity)) {
|
|
2560
|
+
issues.push({ path: `${path2}.severity`, message: "expected info, advisory, warn, or hard-block" });
|
|
2561
|
+
}
|
|
2562
|
+
if (message === null) return null;
|
|
2563
|
+
const effect = { kind: "inject_reminder", message };
|
|
2564
|
+
if (severity !== void 0 && isMiddlewareReminderSeverity(severity)) effect.severity = severity;
|
|
2565
|
+
return effect;
|
|
2566
|
+
}
|
|
2567
|
+
function readAnnotateToolResult(record, path2, issues) {
|
|
2568
|
+
rejectUnexpectedFields(record, path2, ["kind", "message", "severity"], issues);
|
|
2569
|
+
const message = readRequiredString(record, `${path2}.message`, issues);
|
|
2570
|
+
const severity = readOptionalString(record, `${path2}.severity`, issues);
|
|
2571
|
+
if (severity !== void 0 && !isMiddlewareAnnotationSeverity(severity)) {
|
|
2572
|
+
issues.push({ path: `${path2}.severity`, message: "expected info or warn" });
|
|
2573
|
+
}
|
|
2574
|
+
if (message === null) return null;
|
|
2575
|
+
const effect = { kind: "annotate_tool_result", message };
|
|
2576
|
+
if (severity !== void 0 && isMiddlewareAnnotationSeverity(severity)) effect.severity = severity;
|
|
2577
|
+
return effect;
|
|
2578
|
+
}
|
|
2579
|
+
function readBlockTool(record, path2, issues) {
|
|
2580
|
+
rejectUnexpectedFields(record, path2, ["kind", "reason", "severity"], issues);
|
|
2581
|
+
const reason = readRequiredString(record, `${path2}.reason`, issues);
|
|
2582
|
+
const severity = readRequiredString(record, `${path2}.severity`, issues);
|
|
2583
|
+
if (severity !== null && severity !== "hard-block") {
|
|
2584
|
+
issues.push({ path: `${path2}.severity`, message: "expected hard-block" });
|
|
2585
|
+
}
|
|
2586
|
+
if (reason === null || severity !== "hard-block") return null;
|
|
2587
|
+
return { kind: "block_tool", reason, severity };
|
|
2588
|
+
}
|
|
2589
|
+
function readProtectPath(record, path2, issues) {
|
|
2590
|
+
rejectUnexpectedFields(record, path2, ["kind", "path", "reason"], issues);
|
|
2591
|
+
const protectedPath = readRequiredString(record, `${path2}.path`, issues);
|
|
2592
|
+
const reason = readRequiredString(record, `${path2}.reason`, issues);
|
|
2593
|
+
if (protectedPath === null || reason === null) return null;
|
|
2594
|
+
return { kind: "protect_path", path: protectedPath, reason };
|
|
2595
|
+
}
|
|
2596
|
+
function readRequestContinuation(record, path2, issues) {
|
|
2597
|
+
rejectUnexpectedFields(record, path2, ["kind", "message"], issues);
|
|
2598
|
+
const message = readRequiredString(record, `${path2}.message`, issues);
|
|
2599
|
+
if (message === null) return null;
|
|
2600
|
+
return { kind: "request_continuation", message };
|
|
2601
|
+
}
|
|
2602
|
+
function readRequiredString(record, path2, issues) {
|
|
2603
|
+
const value = record[pathField(path2)];
|
|
2604
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
2605
|
+
issues.push({ path: path2, message: "expected non-empty string" });
|
|
2606
|
+
return null;
|
|
2607
|
+
}
|
|
2608
|
+
return value;
|
|
2609
|
+
}
|
|
2610
|
+
function readOptionalString(record, path2, issues) {
|
|
2611
|
+
const field = pathField(path2);
|
|
2612
|
+
if (!Object.hasOwn(record, field)) return void 0;
|
|
2613
|
+
const value = record[field];
|
|
2614
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
2615
|
+
issues.push({ path: path2, message: "expected non-empty string" });
|
|
2616
|
+
return void 0;
|
|
2617
|
+
}
|
|
2618
|
+
return value;
|
|
2619
|
+
}
|
|
2620
|
+
function rejectUnexpectedFields(record, path2, allowedFields, issues) {
|
|
2621
|
+
const allowed = new Set(allowedFields);
|
|
2622
|
+
for (const field of Object.keys(record).sort((a, b) => a.localeCompare(b))) {
|
|
2623
|
+
if (!allowed.has(field)) issues.push({ path: `${path2}.${field}`, message: "unexpected field" });
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
function pathField(path2) {
|
|
2627
|
+
return path2.slice(path2.lastIndexOf(".") + 1);
|
|
2628
|
+
}
|
|
2629
|
+
function isRecord(value) {
|
|
2630
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
// src/domains/middleware/hooks.ts
|
|
2634
|
+
var USER_HOOK_ORIGIN_ORDER = ["extension", "user", "project", "project.local"];
|
|
2635
|
+
var USER_HOOK_COMMAND_TIMEOUT_DEFAULT_MS = 2e3;
|
|
2636
|
+
var USER_HOOK_COMMAND_TIMEOUT_MIN_MS = 100;
|
|
2637
|
+
var USER_HOOK_COMMAND_TIMEOUT_MAX_MS = 5e3;
|
|
2638
|
+
var USER_HOOK_COMMAND_OUTPUT_MAX_CHARS = 4e3;
|
|
2639
|
+
var USER_HOOK_PROMPT_MAX_CHARS = 2e3;
|
|
2640
|
+
function isRecord2(value) {
|
|
2641
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2642
|
+
}
|
|
2643
|
+
function stableHash(value) {
|
|
2644
|
+
return createHash2("sha256").update(canonicalJson(value)).digest("hex").slice(0, 16);
|
|
2645
|
+
}
|
|
2646
|
+
function canonicalJson(value) {
|
|
2647
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
2648
|
+
if (isRecord2(value)) {
|
|
2649
|
+
const keys = Object.keys(value).sort();
|
|
2650
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
|
|
2651
|
+
}
|
|
2652
|
+
return JSON.stringify(value) ?? "null";
|
|
2653
|
+
}
|
|
2654
|
+
function readStringArray(value) {
|
|
2655
|
+
if (!Array.isArray(value)) return null;
|
|
2656
|
+
const out = [];
|
|
2657
|
+
for (const item of value) {
|
|
2658
|
+
if (typeof item !== "string" || item.length === 0) return null;
|
|
2659
|
+
out.push(item);
|
|
2660
|
+
}
|
|
2661
|
+
return out;
|
|
2662
|
+
}
|
|
2663
|
+
function normalizeCommandSpec(raw, options, issues) {
|
|
2664
|
+
const argv = readStringArray(raw.argv);
|
|
2665
|
+
if (!argv || argv.length === 0) {
|
|
2666
|
+
issues.push("command.argv must be a non-empty array of non-empty strings");
|
|
2667
|
+
return null;
|
|
2668
|
+
}
|
|
2669
|
+
const spec = {
|
|
2670
|
+
kind: "command",
|
|
2671
|
+
argv,
|
|
2672
|
+
cwd: resolve(options.workspaceRoot),
|
|
2673
|
+
timeoutMs: USER_HOOK_COMMAND_TIMEOUT_DEFAULT_MS,
|
|
2674
|
+
as: "annotate"
|
|
2675
|
+
};
|
|
2676
|
+
if (raw.cwd !== void 0) {
|
|
2677
|
+
if (typeof raw.cwd !== "string" || raw.cwd.length === 0) {
|
|
2678
|
+
issues.push("command.cwd must be a non-empty string");
|
|
2679
|
+
return null;
|
|
2680
|
+
}
|
|
2681
|
+
const resolved = isAbsolute(raw.cwd) ? resolve(raw.cwd) : resolve(options.workspaceRoot, raw.cwd);
|
|
2682
|
+
if (!isWithin(resolved, options.workspaceRoot)) {
|
|
2683
|
+
issues.push("command.cwd must resolve under the workspace root");
|
|
2684
|
+
return null;
|
|
2685
|
+
}
|
|
2686
|
+
spec.cwd = resolved;
|
|
2687
|
+
}
|
|
2688
|
+
if (raw.timeoutMs !== void 0) {
|
|
2689
|
+
if (typeof raw.timeoutMs !== "number" || !Number.isFinite(raw.timeoutMs)) {
|
|
2690
|
+
issues.push("command.timeoutMs must be a number");
|
|
2691
|
+
return null;
|
|
2692
|
+
}
|
|
2693
|
+
spec.timeoutMs = Math.min(
|
|
2694
|
+
USER_HOOK_COMMAND_TIMEOUT_MAX_MS,
|
|
2695
|
+
Math.max(USER_HOOK_COMMAND_TIMEOUT_MIN_MS, Math.floor(raw.timeoutMs))
|
|
2696
|
+
);
|
|
2697
|
+
}
|
|
2698
|
+
if (raw.as !== void 0) {
|
|
2699
|
+
if (raw.as !== "annotate" && raw.as !== "reminder") {
|
|
2700
|
+
issues.push('command.as must be "annotate" or "reminder"');
|
|
2701
|
+
return null;
|
|
2702
|
+
}
|
|
2703
|
+
spec.as = raw.as;
|
|
2704
|
+
}
|
|
2705
|
+
return spec;
|
|
2706
|
+
}
|
|
2707
|
+
function normalizePromptSpec(raw, issues) {
|
|
2708
|
+
if (typeof raw.message !== "string" || raw.message.trim().length === 0) {
|
|
2709
|
+
issues.push("prompt.message must be a non-empty string");
|
|
2710
|
+
return null;
|
|
2711
|
+
}
|
|
2712
|
+
let severity = "info";
|
|
2713
|
+
if (raw.severity !== void 0) {
|
|
2714
|
+
if (typeof raw.severity !== "string" || !isMiddlewareReminderSeverity(raw.severity)) {
|
|
2715
|
+
issues.push("prompt.severity must be info, advisory, warn, or hard-block");
|
|
2716
|
+
return null;
|
|
2717
|
+
}
|
|
2718
|
+
severity = raw.severity;
|
|
2719
|
+
}
|
|
2720
|
+
return { kind: "prompt", message: raw.message.slice(0, USER_HOOK_PROMPT_MAX_CHARS), severity };
|
|
2721
|
+
}
|
|
2722
|
+
function normalizeEffectSpec(raw, issues) {
|
|
2723
|
+
const result = validateMiddlewareEffect(raw.effect ?? raw, "effect");
|
|
2724
|
+
if (!result.valid) {
|
|
2725
|
+
for (const issue of result.issues) issues.push(`effect: ${issue.message}`);
|
|
2726
|
+
return null;
|
|
2727
|
+
}
|
|
2728
|
+
return { kind: "effect", effect: result.effect };
|
|
2729
|
+
}
|
|
2730
|
+
function isWithin(child, parent) {
|
|
2731
|
+
const rel = resolve(child);
|
|
2732
|
+
const base = resolve(parent);
|
|
2733
|
+
return rel === base || rel.startsWith(`${base}/`);
|
|
2734
|
+
}
|
|
2735
|
+
function normalizeUserHook(raw, source, options) {
|
|
2736
|
+
const issues = [];
|
|
2737
|
+
if (!isRecord2(raw)) {
|
|
2738
|
+
return { issues: ["hook declaration must be an object"] };
|
|
2739
|
+
}
|
|
2740
|
+
if (raw.on === void 0 || typeof raw.on !== "string" || !isMiddlewareHook(raw.on)) {
|
|
2741
|
+
issues.push("on must be one of before_tool, after_tool, turn_start, turn_end, on_compaction");
|
|
2742
|
+
}
|
|
2743
|
+
let tools;
|
|
2744
|
+
if (raw.tools !== void 0) {
|
|
2745
|
+
const parsed = readStringArray(raw.tools);
|
|
2746
|
+
if (!parsed) issues.push("tools must be an array of non-empty tool names");
|
|
2747
|
+
else tools = parsed;
|
|
2748
|
+
}
|
|
2749
|
+
let enabled = true;
|
|
2750
|
+
if (raw.enabled !== void 0) {
|
|
2751
|
+
if (typeof raw.enabled !== "boolean") issues.push("enabled must be a boolean");
|
|
2752
|
+
else enabled = raw.enabled;
|
|
2753
|
+
}
|
|
2754
|
+
let spec = null;
|
|
2755
|
+
if (raw.kind === "command") spec = normalizeCommandSpec(raw, options, issues);
|
|
2756
|
+
else if (raw.kind === "prompt") spec = normalizePromptSpec(raw, issues);
|
|
2757
|
+
else if (raw.kind === "effect") spec = normalizeEffectSpec(raw, issues);
|
|
2758
|
+
else issues.push('kind must be "command", "prompt", or "effect"');
|
|
2759
|
+
if (issues.length > 0 || spec === null || raw.on === void 0 || typeof raw.on !== "string") {
|
|
2760
|
+
return { issues };
|
|
2761
|
+
}
|
|
2762
|
+
const on = raw.on;
|
|
2763
|
+
const hash = stableHash({ on, tools: tools ?? null, spec });
|
|
2764
|
+
const id = typeof raw.id === "string" && raw.id.length > 0 ? raw.id : `${source.sourceId ?? source.origin}.${spec.kind}.${hash}`;
|
|
2765
|
+
const hook = { id, source, hash, on, enabled, spec };
|
|
2766
|
+
if (tools !== void 0) hook.tools = tools;
|
|
2767
|
+
return { hook, issues };
|
|
2768
|
+
}
|
|
2769
|
+
function declarationsArray(declarations) {
|
|
2770
|
+
if (Array.isArray(declarations)) return declarations;
|
|
2771
|
+
if (isRecord2(declarations) && Array.isArray(declarations.hooks)) return declarations.hooks;
|
|
2772
|
+
return [];
|
|
2773
|
+
}
|
|
2774
|
+
function loadUserHooks(batches, options) {
|
|
2775
|
+
const ordered = [...batches].sort(
|
|
2776
|
+
(a, b) => USER_HOOK_ORIGIN_ORDER.indexOf(a.source.origin) - USER_HOOK_ORIGIN_ORDER.indexOf(b.source.origin)
|
|
2777
|
+
);
|
|
2778
|
+
const byId = /* @__PURE__ */ new Map();
|
|
2779
|
+
const overridden = [];
|
|
2780
|
+
const issues = [];
|
|
2781
|
+
for (const batch of ordered) {
|
|
2782
|
+
const declarations = declarationsArray(batch.declarations);
|
|
2783
|
+
declarations.forEach((raw, index) => {
|
|
2784
|
+
const result = normalizeUserHook(raw, batch.source, options);
|
|
2785
|
+
if (!result.hook) {
|
|
2786
|
+
issues.push({ source: batch.source, index, issues: result.issues });
|
|
2787
|
+
return;
|
|
2788
|
+
}
|
|
2789
|
+
const existing = byId.get(result.hook.id);
|
|
2790
|
+
if (existing) overridden.push({ winner: batch.source, loser: existing });
|
|
2791
|
+
byId.set(result.hook.id, result.hook);
|
|
2792
|
+
});
|
|
2793
|
+
}
|
|
2794
|
+
return { hooks: [...byId.values()], overridden, issues };
|
|
2795
|
+
}
|
|
2796
|
+
function reminderEffect(message, severity) {
|
|
2797
|
+
return severity === "info" ? { kind: "inject_reminder", message } : { kind: "inject_reminder", message, severity };
|
|
2798
|
+
}
|
|
2799
|
+
function commandEffect(hook, output) {
|
|
2800
|
+
const message = output.slice(0, USER_HOOK_COMMAND_OUTPUT_MAX_CHARS);
|
|
2801
|
+
return hook.as === "reminder" ? { kind: "inject_reminder", message } : { kind: "annotate_tool_result", message };
|
|
2802
|
+
}
|
|
2803
|
+
function userHookToRegistration(hook, deps) {
|
|
2804
|
+
const now = deps.now ?? Date.now;
|
|
2805
|
+
const extension = hook.source.extension === void 0 ? void 0 : receiptExtension(hook.source.extension);
|
|
2806
|
+
const baseReceipt = (input) => ({
|
|
2807
|
+
at: now(),
|
|
2808
|
+
hookId: hook.id,
|
|
2809
|
+
origin: hook.source.origin,
|
|
2810
|
+
sourcePath: hook.source.sourcePath,
|
|
2811
|
+
hash: hook.hash,
|
|
2812
|
+
hook: hook.on,
|
|
2813
|
+
kind: hook.spec.kind,
|
|
2814
|
+
...extension !== void 0 ? { extension: { ...extension } } : {},
|
|
2815
|
+
...input.toolName !== void 0 ? { toolName: input.toolName } : {}
|
|
2816
|
+
});
|
|
2817
|
+
const registration = {
|
|
2818
|
+
id: hook.id,
|
|
2819
|
+
description: `${hook.spec.kind} hook from ${hook.source.origin} (${hook.source.sourcePath})`,
|
|
2820
|
+
hooks: [hook.on],
|
|
2821
|
+
evaluate: (input) => {
|
|
2822
|
+
if (!hook.enabled) return [];
|
|
2823
|
+
try {
|
|
2824
|
+
return evaluateHook(hook, deps, baseReceipt(input));
|
|
2825
|
+
} catch {
|
|
2826
|
+
deps.recordReceipt({ ...baseReceipt(input), outcome: "skipped" });
|
|
2827
|
+
return [];
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
};
|
|
2831
|
+
if (hook.tools !== void 0) registration.toolNames = [...hook.tools];
|
|
2832
|
+
return registration;
|
|
2833
|
+
}
|
|
2834
|
+
function receiptExtension(source) {
|
|
2835
|
+
return {
|
|
2836
|
+
id: source.provenance.id,
|
|
2837
|
+
scope: source.provenance.scope,
|
|
2838
|
+
canonicalRoot: source.provenance.canonicalRoot,
|
|
2839
|
+
manifestDigest: source.provenance.manifestDigest,
|
|
2840
|
+
contentDigest: source.provenance.contentDigest,
|
|
2841
|
+
declarationsDigest: source.declarationsDigest,
|
|
2842
|
+
generation: source.generation
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
function evaluateHook(hook, deps, base) {
|
|
2846
|
+
if (hook.spec.kind === "prompt") {
|
|
2847
|
+
const effect2 = reminderEffect(hook.spec.message, hook.spec.severity);
|
|
2848
|
+
deps.recordReceipt({ ...base, outcome: "emitted", effectKinds: ["inject_reminder"] });
|
|
2849
|
+
return [effect2];
|
|
2850
|
+
}
|
|
2851
|
+
if (hook.spec.kind === "effect") {
|
|
2852
|
+
deps.recordReceipt({ ...base, outcome: "emitted", effectKinds: [hook.spec.effect.kind] });
|
|
2853
|
+
return [hook.spec.effect];
|
|
2854
|
+
}
|
|
2855
|
+
const result = deps.runCommand(hook.spec.argv, {
|
|
2856
|
+
timeoutMs: hook.spec.timeoutMs,
|
|
2857
|
+
...hook.spec.cwd !== void 0 ? { cwd: hook.spec.cwd } : {}
|
|
2858
|
+
});
|
|
2859
|
+
const output = (result.stdout || result.stderr || "").trim();
|
|
2860
|
+
if (result.timedOut) {
|
|
2861
|
+
deps.recordReceipt({ ...base, outcome: "command-timeout", exitCode: result.code ?? -1, outputChars: output.length });
|
|
2862
|
+
return [];
|
|
2863
|
+
}
|
|
2864
|
+
const outcome = result.code === 0 ? "command-ok" : "command-failed";
|
|
2865
|
+
deps.recordReceipt({ ...base, outcome, exitCode: result.code ?? -1, outputChars: output.length });
|
|
2866
|
+
if (output.length === 0) return [];
|
|
2867
|
+
const effect = commandEffect(hook.spec, output);
|
|
2868
|
+
return [effect];
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
// src/domains/middleware/hooks-io.ts
|
|
2872
|
+
init_esm_shims();
|
|
2873
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
2874
|
+
import { spawnSync } from "node:child_process";
|
|
2875
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
2876
|
+
import { join } from "node:path";
|
|
2877
|
+
var COMMAND_OUTPUT_MAX_BYTES = 1024 * 1024;
|
|
2878
|
+
function readBatch(source, filePath, fileIssues) {
|
|
2879
|
+
let text;
|
|
2880
|
+
try {
|
|
2881
|
+
text = readFileSync3(filePath, "utf8");
|
|
2882
|
+
} catch {
|
|
2883
|
+
return null;
|
|
2884
|
+
}
|
|
2885
|
+
try {
|
|
2886
|
+
const parsed = (0, import_yaml.parse)(text);
|
|
2887
|
+
return { source, declarations: parsed ?? [] };
|
|
2888
|
+
} catch (err) {
|
|
2889
|
+
fileIssues.push({
|
|
2890
|
+
source,
|
|
2891
|
+
message: `failed to parse ${filePath}: ${err instanceof Error ? err.message : String(err)}`
|
|
2892
|
+
});
|
|
2893
|
+
return null;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
function readHookSources(options) {
|
|
2897
|
+
const fileIssues = [];
|
|
2898
|
+
const batches = [];
|
|
2899
|
+
const captured = options.capturedSources;
|
|
2900
|
+
for (const entry of captured?.sources ?? []) {
|
|
2901
|
+
const source = {
|
|
2902
|
+
origin: "extension",
|
|
2903
|
+
sourcePath: `${entry.provenance.id}:hooks.yaml`,
|
|
2904
|
+
sourceId: entry.provenance.id,
|
|
2905
|
+
extension: {
|
|
2906
|
+
provenance: entry.provenance,
|
|
2907
|
+
generation: captured?.generation ?? 0,
|
|
2908
|
+
declarationsDigest: entry.declarationsDigest
|
|
2909
|
+
}
|
|
2910
|
+
};
|
|
2911
|
+
if (entry.parseError !== void 0) {
|
|
2912
|
+
fileIssues.push({ source, message: `failed to parse ${source.sourcePath}: ${entry.parseError}` });
|
|
2913
|
+
continue;
|
|
2914
|
+
}
|
|
2915
|
+
batches.push({ source, declarations: entry.declarations });
|
|
2916
|
+
}
|
|
2917
|
+
const projectBatch = readBatch(
|
|
2918
|
+
{ origin: "project", sourcePath: ".clio-coder/hooks.yaml" },
|
|
2919
|
+
join(options.cwd, ".clio-coder", "hooks.yaml"),
|
|
2920
|
+
fileIssues
|
|
2921
|
+
);
|
|
2922
|
+
if (projectBatch) batches.push(projectBatch);
|
|
2923
|
+
const localBatch = readBatch(
|
|
2924
|
+
{ origin: "project.local", sourcePath: ".clio-coder/hooks.local.yaml" },
|
|
2925
|
+
join(options.cwd, ".clio-coder", "hooks.local.yaml"),
|
|
2926
|
+
fileIssues
|
|
2927
|
+
);
|
|
2928
|
+
if (localBatch) batches.push(localBatch);
|
|
2929
|
+
return { batches, fileIssues };
|
|
2930
|
+
}
|
|
2931
|
+
function buildUserHookRegistrations(options) {
|
|
2932
|
+
const workspaceRoot = options.workspaceRoot ?? options.cwd;
|
|
2933
|
+
const readOptions = { cwd: options.cwd };
|
|
2934
|
+
if (options.capturedSources !== void 0) readOptions.capturedSources = options.capturedSources;
|
|
2935
|
+
const { batches, fileIssues } = readHookSources(readOptions);
|
|
2936
|
+
const loaded = loadUserHooks(batches, { workspaceRoot });
|
|
2937
|
+
const runCommand = options.runCommand ?? spawnSyncCommandRunner();
|
|
2938
|
+
const registrations = loaded.hooks.map(
|
|
2939
|
+
(hook) => userHookToRegistration(hook, {
|
|
2940
|
+
recordReceipt: options.recordReceipt,
|
|
2941
|
+
runCommand,
|
|
2942
|
+
...options.now !== void 0 ? { now: options.now } : {}
|
|
2943
|
+
})
|
|
2944
|
+
);
|
|
2945
|
+
return { ...loaded, fileIssues, registrations };
|
|
2946
|
+
}
|
|
2947
|
+
function spawnSyncCommandRunner() {
|
|
2948
|
+
return (argv, options) => {
|
|
2949
|
+
const [command, ...args] = argv;
|
|
2950
|
+
const attribution = withManagedGitCommitAttributionEnvironment(process.env, {
|
|
2951
|
+
cwd: options.cwd ?? process.cwd(),
|
|
2952
|
+
evidence: {}
|
|
2953
|
+
});
|
|
2954
|
+
reportCommitAttributionDiagnostic(attribution.diagnostic);
|
|
2955
|
+
const result = spawnSync(command ?? "", args, {
|
|
2956
|
+
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
2957
|
+
timeout: options.timeoutMs,
|
|
2958
|
+
maxBuffer: COMMAND_OUTPUT_MAX_BYTES,
|
|
2959
|
+
encoding: "utf8",
|
|
2960
|
+
shell: false,
|
|
2961
|
+
env: attribution.env
|
|
2962
|
+
});
|
|
2963
|
+
const timedOut = result.error !== void 0 && result.error.code === "ETIMEDOUT";
|
|
2964
|
+
return {
|
|
2965
|
+
code: result.status,
|
|
2966
|
+
timedOut,
|
|
2967
|
+
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
2968
|
+
stderr: typeof result.stderr === "string" ? result.stderr : ""
|
|
2969
|
+
};
|
|
2970
|
+
};
|
|
2971
|
+
}
|
|
2972
|
+
|
|
2973
|
+
// src/domains/middleware/index.ts
|
|
2974
|
+
var MiddlewareDomainModule = {
|
|
2975
|
+
manifest: MiddlewareManifest,
|
|
2976
|
+
createExtension: () => createMiddlewareBundle()
|
|
2977
|
+
};
|
|
2978
|
+
|
|
2979
|
+
export {
|
|
2980
|
+
MIDDLEWARE_HOOK_TEXT_MAX_CHARS,
|
|
2981
|
+
shouldRequestStalledTurnContinuation,
|
|
2982
|
+
writeMiddlewareDiagnosticToStderr,
|
|
2983
|
+
formatRegistrationConflict,
|
|
2984
|
+
createMiddlewareContractFromSnapshot,
|
|
2985
|
+
createReadOnlyExplorationNudgeRegistration,
|
|
2986
|
+
createUnbackedWorkerClaimRegistration,
|
|
2987
|
+
openDetachedBatchViews,
|
|
2988
|
+
createDetachedDispatchNudgeRegistration,
|
|
2989
|
+
HOOK_RECEIPT_LOG_CAPACITY,
|
|
2990
|
+
createHookReceiptLog,
|
|
2991
|
+
readPersistedHookReceipts,
|
|
2992
|
+
loadUserHooks,
|
|
2993
|
+
readHookSources,
|
|
2994
|
+
buildUserHookRegistrations,
|
|
2995
|
+
createSkillsReminderRegistration,
|
|
2996
|
+
createMarketplaceOfferRegistration,
|
|
2997
|
+
createMemoryInterventionRegistration,
|
|
2998
|
+
announceMemoryStepEndpoint,
|
|
2462
2999
|
createTaskBoardReminderRegistration,
|
|
2463
3000
|
createTaskNudgeRegistration,
|
|
2464
3001
|
createMiddlewareToolChoiceControl,
|
|
@@ -2467,4 +3004,4 @@ export {
|
|
|
2467
3004
|
createWatchdogRegistration,
|
|
2468
3005
|
MiddlewareDomainModule
|
|
2469
3006
|
};
|
|
2470
|
-
//# sourceMappingURL=chunk-
|
|
3007
|
+
//# sourceMappingURL=chunk-UBRFI4HS.js.map
|