@iowarp/clio-coder 0.4.1 → 0.4.3
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 +127 -0
- package/CONTRIBUTING.md +142 -52
- package/README.md +434 -473
- package/SECURITY.md +2 -1
- package/dist/{acp-ZILU3AUO.js → acp-H2NGRPWO.js} +12 -12
- package/dist/{agents-HYWGBGQR.js → agents-TL5LLUQP.js} +56 -55
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-N3QT7CBO.js → auth-E5SW4HMS.js} +23 -21
- package/dist/builtins-IA7V7FUC.js +22 -0
- package/dist/{chunk-7RY5VZPH.js → chunk-2APPQIER.js} +8 -8
- package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
- package/dist/{chunk-JA5QWE4Z.js → chunk-2UG5F4C5.js} +1973 -1664
- package/dist/{chunk-5YHDIDBP.js → chunk-2UH2KFUP.js} +2 -2
- package/dist/{chunk-CTJ4RNAA.js → chunk-2VIKGWFZ.js} +2 -2
- package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
- package/dist/{chunk-GIZNH63R.js → chunk-35MSIRKH.js} +9 -4
- package/dist/chunk-3EBYEESD.js +314 -0
- package/dist/{chunk-J5LZHVIT.js → chunk-3M6DQK6S.js} +113 -35
- package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
- package/dist/{chunk-6FN3E6KX.js → chunk-4O6MANBS.js} +2 -2
- package/dist/chunk-4UVU7BJ5.js +39 -0
- package/dist/{chunk-VKRH2TCS.js → chunk-4WR7VSYB.js} +2 -2
- package/dist/{chunk-BBTJOK6Y.js → chunk-54CBCGIR.js} +5 -5
- package/dist/{chunk-AP73CFDC.js → chunk-5ICU3EUH.js} +2 -2
- package/dist/chunk-5MEZN6CB.js +1334 -0
- package/dist/{chunk-O42A54GG.js → chunk-5OIVVPHF.js} +2 -2
- package/dist/{chunk-ABLSQ6JX.js → chunk-64I3JVYM.js} +8 -2
- package/dist/{chunk-AFKWHWXF.js → chunk-6PTFB5VS.js} +39 -22
- package/dist/{chunk-VN3SHNBN.js → chunk-7DICMOS6.js} +2 -2
- package/dist/chunk-7DRAWPTZ.js +360 -0
- package/dist/chunk-7E7I3WLS.js +3762 -0
- package/dist/{chunk-BJGUKIG4.js → chunk-7ZYNNDKC.js} +7 -7
- package/dist/{chunk-XKA2ICR3.js → chunk-AF4YM7Z4.js} +652 -252
- package/dist/{chunk-GVQJ5CCZ.js → chunk-AX2THNSA.js} +12 -12
- package/dist/{chunk-IG7BCQBA.js → chunk-B4OAX3SI.js} +65 -3
- package/dist/{chunk-TD3PGPQA.js → chunk-B4VEBZKF.js} +3 -3
- package/dist/{chunk-74YWRRU5.js → chunk-BEPZRGGU.js} +10 -10
- package/dist/{chunk-FEFIFZTL.js → chunk-CE5AX47J.js} +2 -2
- package/dist/{chunk-UAPGZHYC.js → chunk-DWUOQKRU.js} +25 -11
- package/dist/{chunk-THYWACCR.js → chunk-E3TPLWFX.js} +3 -3
- package/dist/{chunk-7EPLI7VL.js → chunk-EKCHAPYA.js} +2 -2
- package/dist/{chunk-HLW2MRKE.js → chunk-F4EKGO4N.js} +3 -1
- package/dist/{chunk-PJJ6MY27.js → chunk-F5JHEYZM.js} +7 -7
- package/dist/{chunk-6CCS4G3W.js → chunk-FTMGRKEF.js} +3 -3
- package/dist/{chunk-SINK3QR6.js → chunk-G76U63X4.js} +17 -17
- package/dist/{chunk-EIMVLWB3.js → chunk-GHS5EBTQ.js} +64 -9
- package/dist/{chunk-QMXC4JB7.js → chunk-GI7YYQ3F.js} +187 -1419
- package/dist/{chunk-TZSKNMZG.js → chunk-GTUD2WMY.js} +2 -1
- package/dist/{chunk-6HMJX2VU.js → chunk-GWZNEVM2.js} +44 -12
- package/dist/chunk-GYV6VZOC.js +26 -0
- package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
- package/dist/{chunk-UXN6JT4W.js → chunk-HEQY7ZFI.js} +3 -3
- package/dist/{chunk-7PWAODYW.js → chunk-I7XBWTYH.js} +2 -2
- package/dist/{chunk-GCSMB2KY.js → chunk-I7ZPNEJM.js} +145 -102
- package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
- package/dist/{chunk-QTFGO774.js → chunk-IGLP3ODT.js} +29 -16
- package/dist/chunk-IJNZMHLA.js +101 -0
- package/dist/{chunk-BDPT6GTK.js → chunk-INY6HTFL.js} +7 -7
- package/dist/{chunk-PBP4B7XR.js → chunk-IUE3Y34X.js} +2 -2
- package/dist/{chunk-6NJQITNH.js → chunk-IWT4SF4R.js} +6 -3
- package/dist/{chunk-R23Z6K6I.js → chunk-JDAY6FIL.js} +19 -19
- package/dist/chunk-JEQ3XTHC.js +42 -0
- package/dist/{chunk-FSP7CMNU.js → chunk-JGRC33J2.js} +50 -4
- package/dist/{chunk-TVH4ONAM.js → chunk-JKKCYP3C.js} +10 -10
- package/dist/{chunk-HJWWJ6IL.js → chunk-JSC3U7TI.js} +16 -4
- package/dist/{chunk-C537JADH.js → chunk-KK4JZPBQ.js} +19 -141
- package/dist/{chunk-K6BF4U2H.js → chunk-KKOJXO6R.js} +62 -14
- package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
- package/dist/{chunk-6DWBAZ5U.js → chunk-L47TF46W.js} +5 -7
- package/dist/{chunk-HUAS7ITX.js → chunk-LDJG7DW3.js} +91 -42
- package/dist/{chunk-CDNVLKUX.js → chunk-LLDJM5XK.js} +13 -7
- package/dist/{chunk-YPI3QQCF.js → chunk-MCEPRMZW.js} +2 -4
- package/dist/{chunk-Y4CAGMM6.js → chunk-MNJGS2IN.js} +5 -6
- package/dist/{chunk-VKFQTNDV.js → chunk-MUW2BDDH.js} +4 -4
- package/dist/{chunk-E67WX76H.js → chunk-MWUZBSAQ.js} +104 -152
- package/dist/{chunk-OJTRZGR3.js → chunk-N2Z7HLVY.js} +21 -21
- package/dist/{chunk-TVHHYFHE.js → chunk-NEDJ26B5.js} +2 -2
- package/dist/{chunk-FYUN5KZ3.js → chunk-NIQJ66N4.js} +21 -21
- package/dist/{chunk-U2WB7TZS.js → chunk-NMJXSHBJ.js} +97 -85
- package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
- package/dist/{chunk-VEGN6WIQ.js → chunk-O5CVSAG5.js} +3 -3
- package/dist/{chunk-MOPSG2X7.js → chunk-OML5D5V5.js} +8 -8
- package/dist/{chunk-2VG7KLYV.js → chunk-PAJQJ7BS.js} +5816 -3255
- package/dist/{chunk-ZW55JB7N.js → chunk-PUVDKJ2Y.js} +2 -2
- package/dist/{chunk-BTGG6BG2.js → chunk-QWGDJJYJ.js} +158 -19
- package/dist/chunk-R6Q67RJH.js +134 -0
- package/dist/{chunk-ZJLUDYFY.js → chunk-RRNP2ANY.js} +6 -6
- package/dist/{chunk-PVAMAVBB.js → chunk-RSJ25QSL.js} +102 -2
- package/dist/{chunk-NLFAQR7Z.js → chunk-S66XZJOF.js} +3 -23
- package/dist/chunk-SKHCAU7K.js +385 -0
- package/dist/chunk-SZAA6XDG.js +30 -0
- package/dist/{chunk-J4HBWF6Y.js → chunk-TM6LQDI3.js} +131 -28
- package/dist/chunk-UOIZ7DA4.js +41 -0
- package/dist/{chunk-MA3H6DM5.js → chunk-UPZU6GE4.js} +25 -3
- package/dist/{chunk-BWW4HLO4.js → chunk-UXCU4E3T.js} +8 -6
- package/dist/{chunk-N5UK64DP.js → chunk-V2ANDPVT.js} +4 -4
- package/dist/{chunk-AK5XEFVZ.js → chunk-VA5FNYMT.js} +26 -13
- package/dist/{chunk-6VC4OV3Z.js → chunk-VIA6RFQZ.js} +3 -11
- package/dist/{chunk-ZAZB4JMW.js → chunk-VKPAQYEB.js} +27 -8
- package/dist/{chunk-QKIFBZKT.js → chunk-VW6DOEDG.js} +497 -81
- package/dist/{chunk-SCYB3HA4.js → chunk-W6RRQCPQ.js} +63 -19
- package/dist/{chunk-2NM363SV.js → chunk-WBKFA554.js} +10 -10
- package/dist/{chunk-R32CLGZ6.js → chunk-WCXUNS7U.js} +82 -21
- package/dist/{chunk-GPPB3JBE.js → chunk-WRBAGUNF.js} +3 -3
- package/dist/{chunk-IXJT6DCX.js → chunk-XIVNBFZS.js} +85 -30
- package/dist/{chunk-UEDMSP56.js → chunk-XPWWI35G.js} +417 -201
- package/dist/chunk-XRZT5WY5.js +47 -0
- package/dist/{chunk-3QSOM6PA.js → chunk-Y3CBHOR6.js} +2 -2
- package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
- package/dist/{chunk-AKB4GYDL.js → chunk-YQWYVTMC.js} +5 -5
- package/dist/{chunk-6I5ILFOF.js → chunk-ZA4VCIGV.js} +3 -3
- package/dist/{chunk-7OBGU7UB.js → chunk-ZDN3Y73Y.js} +12 -18
- package/dist/{chunk-3I5NY75V.js → chunk-ZWPRK62N.js} +8 -5
- package/dist/cli/index.js +41 -39
- package/dist/{clio-IT3G3VQH.js → clio-CMMK4KRR.js} +9 -9
- package/dist/{code-nav-RK6S7F6E.js → code-nav-MDZNQS33.js} +89 -21
- package/dist/{components-UBWCQSRW.js → components-UCUQ4QXW.js} +4 -4
- package/dist/{config-3QZRWZJF.js → config-SVM5P5YI.js} +131 -84
- package/dist/{configure-FL7Y3KJF.js → configure-LE3IK2TJ.js} +28 -26
- package/dist/{context-5HE7ODYK.js → context-2OHRKS42.js} +69 -64
- package/dist/{context-KYQFRVDC.js → context-E3VC7RX5.js} +15 -11
- package/dist/{context-XNHL75JV.js → context-VNCR7KAG.js} +93 -65
- package/dist/{context-clear-N545L53A.js → context-clear-BW4O37TG.js} +64 -60
- package/dist/context-map-COB37XXN.js +505 -0
- package/dist/{context-working-set-QHKXSV2F.js → context-working-set-VDS25HXZ.js} +19 -18
- package/dist/{dispatch-runner-RGIE5PCT.js → dispatch-runner-5AHT53RF.js} +93 -82
- package/dist/{docs-5NAF6AU7.js → docs-PD3EXDKU.js} +21 -20
- package/dist/{doctor-ZGPEGHIP.js → doctor-WNNVO6FY.js} +48 -47
- package/dist/{eval-GXLL44RD.js → eval-7G7SGAYO.js} +287 -115
- package/dist/{eval-inventory-HBWSWQOK.js → eval-inventory-Y6QRFOH5.js} +4 -4
- package/dist/{evidence-HWLBRH3Q.js → evidence-VD6736FQ.js} +67 -64
- package/dist/{evolve-FTZBMNVW.js → evolve-AL3NGVRL.js} +65 -62
- package/dist/{extensions-VHRBEID7.js → extensions-MOVJ32NM.js} +9 -7
- package/dist/{fleet-CKZHJWZJ.js → fleet-QZHUMAGI.js} +114 -111
- package/dist/{fleet-commands-EXDXBMV6.js → fleet-commands-BAYT5FJZ.js} +10 -10
- package/dist/{fleet-decisions-OTHB6KRL.js → fleet-decisions-IREVMRU4.js} +7 -6
- package/dist/{fleet-graph-YTEZUCUT.js → fleet-graph-YCTT3HTI.js} +22 -19
- package/dist/{fleet-inspect-SS6YMDCK.js → fleet-inspect-QVJTDAVB.js} +58 -55
- package/dist/{fleet-preflight-PBY4VYOM.js → fleet-preflight-25QAFPK4.js} +4 -4
- package/dist/{fleet-validate-KMEM5L3S.js → fleet-validate-5O57AAJ7.js} +26 -23
- package/dist/{fleet-verify-QD5M7E7Q.js → fleet-verify-CPH2W2T6.js} +59 -56
- package/dist/{fleet-view-WAMJYNDT.js → fleet-view-SWBR3VGQ.js} +58 -55
- package/dist/{init-5XQRBOFV.js → init-J477LKZH.js} +82 -79
- package/dist/{interop-34TVO25M.js → interop-3FCM6XLG.js} +11 -11
- package/dist/{library-3QY6KF57.js → library-QUQEIUG6.js} +30 -27
- package/dist/{memory-L4UTIIIW.js → memory-SGGSEP65.js} +67 -64
- package/dist/{models-ZVX3QOWE.js → models-HEKUAXXK.js} +53 -46
- package/dist/{monitor-CEKVSYTS.js → monitor-HKU57TYQ.js} +63 -60
- package/dist/{orchestrator-77BAP6BC.js → orchestrator-VDFAEFAI.js} +1831 -1057
- package/dist/{panes-7STHOAUJ.js → panes-DN2SSFOH.js} +5 -5
- package/dist/{panes-SHAUIRXY.js → panes-TALGNPZT.js} +29 -14
- package/dist/{paths-L7LGY6RN.js → paths-NBMFAIEZ.js} +5 -5
- package/dist/reset-EAJFFJVB.js +344 -0
- package/dist/{resources-74GKTLSF.js → resources-OVKSEFVE.js} +29 -20
- package/dist/{run-HBAUJNNZ.js → run-7DP7ZF2J.js} +120 -115
- package/dist/{share-G3APVLVP.js → share-WML67FT3.js} +32 -27
- package/dist/{skills-35HHUKCR.js → skills-SG662R2K.js} +41 -31
- package/dist/{skills-eval-QN4HSHDC.js → skills-eval-VVZEUU46.js} +78 -77
- package/dist/{skills-inventory-J357J34F.js → skills-inventory-I2E23GET.js} +23 -20
- package/dist/{slash-commands-JZZCQA32.js → slash-commands-S7MBJDQK.js} +40 -36
- package/dist/{steer-XAVHJM22.js → steer-2LQOMCPB.js} +3 -3
- package/dist/{support-U7QOWY26.js → support-CC2UJBJ6.js} +6 -6
- package/dist/{targets-DSM6CY3M.js → targets-4QC3HIEW.js} +54 -54
- package/dist/{terminal-lease-JOPFUVEM.js → terminal-lease-TUHIJ6Y2.js} +5 -5
- package/dist/{tools-MKNWVPBH.js → tools-TFGJICCU.js} +10 -10
- package/dist/{trace-ECQ7TIYZ.js → trace-FXMXUZUF.js} +55 -7
- package/dist/uninstall-5PEVOE5B.js +408 -0
- package/dist/upgrade-M4WXY6KN.js +303 -0
- package/dist/{usage-X52N3IDJ.js → usage-N7ZNVLEM.js} +151 -104
- package/dist/{verifiers-EJTVVSMA.js → verifiers-DJTP4XX6.js} +15 -15
- package/dist/{verify-YJL6XET2.js → verify-RWE4PPEK.js} +9 -9
- package/dist/{web-fetch-MPIFL3LL.js → web-fetch-MPARV2K7.js} +2 -2
- package/dist/{wiki-generate-4NDZTQ4B.js → wiki-generate-C7IQOXSP.js} +89 -86
- package/dist/{with-panes-OBOBFIIR.js → with-panes-4GCGSL7J.js} +53 -257
- package/dist/worker/entry.js +90 -74
- 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} +27 -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} +29 -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} +61 -27
- package/docs/{observability.md → architecture/observability.md} +38 -14
- package/docs/{pi-boundary.md → architecture/pi-boundary.md} +24 -11
- package/docs/{prompt-envelope-and-tools.md → architecture/prompt-envelope-and-tools.md} +57 -20
- package/docs/{provider-adapter-cookbook.md → architecture/provider-adapter-cookbook.md} +99 -25
- package/docs/{safety-model.md → architecture/safety-model.md} +35 -20
- 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} +13 -5
- 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} +65 -35
- package/docs/{commands-and-modes.md → guide/commands-and-modes.md} +66 -61
- package/docs/{configuration-and-targets.md → guide/configuration-and-targets.md} +323 -297
- package/docs/guide/configuration-reference.md +1163 -0
- package/docs/{environment-variables.md → guide/environment-variables.md} +33 -28
- package/docs/{exit-codes-and-output.md → guide/exit-codes-and-output.md} +6 -3
- package/docs/{extensions-and-sharing.md → guide/extensions-and-sharing.md} +41 -14
- package/docs/{fleet-dispatch.md → guide/fleet-dispatch.md} +39 -43
- package/docs/{glossary.md → guide/glossary.md} +14 -11
- package/docs/{installation-and-lifecycle.md → guide/installation-and-lifecycle.md} +81 -17
- package/docs/guide/panes-and-files.md +290 -0
- package/docs/{proactive-memory.md → guide/proactive-memory.md} +131 -107
- package/docs/{resource-library.md → guide/resource-library.md} +13 -4
- package/docs/{skills-marketplace.md → guide/skills-marketplace.md} +25 -3
- package/docs/{tool-usage.md → guide/tool-usage.md} +87 -23
- package/docs/{troubleshooting.md → guide/troubleshooting.md} +9 -4
- package/docs/{config-knobs-audit.md → history/config-knobs-audit.md} +11 -11
- package/docs/{release-cut-checklist.md → history/release-cut-checklist.md} +29 -2
- package/docs/process/development-pipeline.md +152 -0
- 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} +108 -53
- 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} +11 -7
- 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 +2 -2
- package/evals/behavioral-model.yaml +3 -2
- package/package.json +10 -8
- package/skills/README.md +52 -41
- package/skills/coding/ast-grep/SKILL.md +102 -31
- package/skills/coding/ast-grep/evals.md +26 -0
- package/skills/coding/coding-standards/SKILL.md +41 -6
- package/skills/coding/coding-standards/evals.md +23 -0
- package/skills/coding/prototype/SKILL.md +88 -29
- package/skills/coding/prototype/evals.md +19 -0
- package/skills/coding/tdd/SKILL.md +81 -54
- package/skills/coding/tdd/evals.md +20 -0
- package/skills/context/context-handoff/SKILL.md +44 -3
- package/skills/context/context-handoff/evals.md +44 -0
- package/skills/context/context-prime/SKILL.md +46 -16
- package/skills/context/context-prime/evals.md +45 -0
- package/skills/git/branch-closeout/SKILL.md +132 -0
- package/skills/git/branch-closeout/evals.md +133 -0
- package/skills/git/branch-closeout/references/closeout-checklist.md +81 -0
- package/skills/git/file-ticket/SKILL.md +78 -64
- package/skills/git/file-ticket/assets/issue-template.md +22 -0
- package/skills/git/file-ticket/evals.md +31 -26
- package/skills/git/file-ticket/references/issue-discovery.md +49 -0
- package/skills/git/fix-issue/SKILL.md +88 -65
- package/skills/git/fix-issue/evals.md +35 -31
- package/skills/git/fix-issue/references/diagnosis-and-rca.md +46 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +101 -52
- package/skills/git/resolve-merge-conflicts/evals.md +52 -25
- package/skills/git/resolve-merge-conflicts/references/conflict-matrix.md +126 -0
- package/skills/git/ship/SKILL.md +103 -67
- package/skills/git/ship/assets/pr-template.md +21 -0
- package/skills/git/ship/evals.md +44 -28
- package/skills/git/ship/references/remote-and-branch-policy.md +62 -0
- package/skills/git/worktree-create/SKILL.md +80 -50
- package/skills/git/worktree-create/evals.md +40 -33
- package/skills/git/worktree-create/references/worktree-setup.md +62 -66
- package/skills/git/worktree-merge/SKILL.md +112 -65
- package/skills/git/worktree-merge/evals.md +42 -34
- package/skills/git/worktree-merge/references/merge-strategies.md +52 -0
- package/skills/meta/clio-coder-dev/SKILL.md +9 -5
- package/skills/meta/clio-coder-dev/evals.md +3 -2
- package/skills/meta/clio-coder-test/SKILL.md +102 -95
- package/skills/meta/clio-coder-test/evals.md +9 -4
- package/skills/meta/clio-coder-test/references/harness.md +100 -124
- package/skills/meta/clio-coder-test/references/test-map.md +77 -50
- package/skills/meta/credentials/SKILL.md +2 -2
- package/skills/meta/find-skills/SKILL.md +2 -2
- package/skills/meta/herdr/SKILL.md +2 -2
- package/skills/meta/skill-craft/SKILL.md +22 -16
- package/skills/planning/archify/SKILL.md +196 -0
- package/skills/planning/archify/evals.md +65 -0
- package/skills/planning/architecture/SKILL.md +62 -13
- package/skills/planning/architecture/evals.md +65 -0
- package/skills/planning/backlog/SKILL.md +131 -15
- package/skills/planning/backlog/evals.md +142 -0
- package/skills/planning/prd/SKILL.md +47 -7
- package/skills/planning/prd/evals.md +54 -0
- package/skills/planning/product-intent/SKILL.md +58 -3
- package/skills/planning/product-intent/evals.md +70 -0
- package/skills/planning/tech-spec/SKILL.md +54 -3
- package/skills/planning/tech-spec/evals.md +73 -0
- package/skills/registry.yaml +70 -62
- package/skills/remote.yaml +13 -0
- package/skills/research/arxiv-literature/SKILL.md +77 -19
- package/skills/research/arxiv-literature/evals.md +50 -0
- package/skills/research/experiment-protocol/SKILL.md +21 -2
- package/skills/research/experiment-protocol/evals.md +23 -0
- package/skills/research/scientific-debugging/SKILL.md +24 -2
- package/skills/research/scientific-debugging/evals.md +18 -0
- package/skills/research/scientific-modernization/SKILL.md +27 -2
- package/skills/research/scientific-modernization/evals.md +27 -0
- package/skills/skill-marketplace.json +97 -62
- package/skills/workflow/cut-it/SKILL.md +66 -6
- package/skills/workflow/cut-it/evals.md +101 -0
- package/skills/workflow/design-council/SKILL.md +118 -28
- package/skills/workflow/design-council/evals.md +161 -0
- package/skills/workflow/grill-me/SKILL.md +87 -11
- package/skills/workflow/grill-me/evals.md +153 -0
- package/skills/workflow/workflow-distiller/SKILL.md +77 -18
- package/skills/workflow/workflow-distiller/evals.md +118 -0
- package/src/cli/args.ts +2 -2
- package/src/cli/bootstrap-generate.ts +1 -1
- package/src/cli/config-inspect.ts +65 -12
- package/src/cli/configure-interop.ts +105 -13
- package/src/cli/configure-oauth.ts +57 -0
- package/src/cli/configure-onboarding.ts +980 -0
- package/src/cli/configure-target.ts +594 -0
- package/src/cli/configure.ts +1082 -532
- package/src/cli/context-map.ts +114 -0
- package/src/cli/context.ts +4 -0
- package/src/cli/docs.ts +22 -14
- package/src/cli/doctor-naming.ts +5 -5
- package/src/cli/doctor-toolchain.ts +3 -3
- package/src/cli/eval.ts +1 -2
- package/src/cli/extensions.ts +2 -1
- package/src/cli/fleet.ts +1 -1
- package/src/cli/index.ts +3 -1
- package/src/cli/internal-dispatch.ts +3 -4
- package/src/cli/lifecycle-presenter.ts +436 -0
- package/src/cli/models.ts +10 -2
- package/src/cli/modes/print.ts +5 -1
- package/src/cli/panes.ts +19 -5
- package/src/cli/reset.ts +228 -106
- package/src/cli/run.ts +9 -4
- package/src/cli/select.ts +664 -0
- package/src/cli/share.ts +5 -1
- package/src/cli/skills-eval.ts +3 -3
- package/src/cli/skills.ts +9 -2
- package/src/cli/targets.ts +5 -6
- package/src/cli/trace.ts +55 -4
- package/src/cli/uninstall.ts +233 -165
- package/src/cli/upgrade.ts +204 -149
- package/src/cli/usage.ts +86 -27
- package/src/cli/validate-model.ts +3 -3
- package/src/cli/wiki-generate.ts +1 -1
- package/src/core/artifact-paths.ts +1 -1
- package/src/core/bash-exec.ts +131 -86
- package/src/core/bus-events.ts +51 -6
- package/src/core/config.ts +61 -1
- package/src/core/defaults.ts +7 -4
- package/src/core/dispatch-outcome.ts +16 -0
- package/src/core/external-diagnostic.ts +44 -0
- package/src/core/gateway-routing.ts +157 -0
- package/src/core/guardrails.ts +10 -49
- package/src/core/prompt-hint.ts +9 -0
- package/src/core/safe-exec.ts +17 -2
- package/src/core/skill-activation.ts +89 -2
- 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/builtins/world-knowledge.md +31 -0
- package/src/domains/agents/catalog.ts +13 -15
- package/src/domains/agents/contract.ts +2 -0
- package/src/domains/agents/extension.ts +23 -1
- package/src/domains/agents/result-contract.ts +70 -0
- package/src/domains/config/keybindings.ts +8 -0
- package/src/domains/context/extension.ts +0 -3
- package/src/domains/context/wiki/map-seed.ts +589 -0
- package/src/domains/context/wiki/plan.ts +2 -2
- package/src/domains/context/working-set/path-index.ts +1 -0
- package/src/domains/dispatch/admission.ts +29 -0
- package/src/domains/dispatch/agent-candidates.ts +10 -0
- package/src/domains/dispatch/budget-envelope.ts +86 -1
- package/src/domains/dispatch/capability-match.ts +11 -0
- package/src/domains/dispatch/capacity-lease.ts +17 -0
- package/src/domains/dispatch/contract.ts +11 -1
- package/src/domains/dispatch/extension.ts +237 -49
- 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/path-scope.ts +235 -24
- package/src/domains/dispatch/run-event-journal.ts +4 -15
- package/src/domains/dispatch/state.ts +2 -3
- package/src/domains/dispatch/transport.ts +45 -21
- package/src/domains/dispatch/types.ts +58 -3
- package/src/domains/dispatch/worker-model-metadata.ts +38 -0
- package/src/domains/eval/artifacts/store.ts +5 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +34 -11
- package/src/domains/eval/metrics/token-stream.ts +201 -31
- package/src/domains/eval/metrics/tracked.ts +40 -4
- package/src/domains/eval/runners/clio-run.ts +5 -2
- package/src/domains/eval/schema/suite.ts +28 -0
- package/src/domains/eval/schema/verdict.ts +2 -2
- package/src/domains/eval/store.ts +8 -1
- package/src/domains/eval/suites/resolve.ts +13 -1
- package/src/domains/eval/suites/run.ts +24 -3
- 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/registry.ts +6 -2
- package/src/domains/interop/types.ts +4 -0
- package/src/domains/lifecycle/migrations/2026-09-01-extension-install-digests.ts +27 -0
- package/src/domains/lifecycle/migrations/index.ts +6 -0
- package/src/domains/lifecycle/naming-resources.ts +19 -4
- package/src/domains/lifecycle/naming-yazi.ts +10 -5
- package/src/domains/memory/task-memory-policy.ts +70 -26
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- 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 +28 -5
- package/src/domains/middleware/marketplace-offer.ts +3 -35
- package/src/domains/middleware/memory-intervention.ts +127 -32
- package/src/domains/middleware/memory-step-endpoint.ts +3 -2
- package/src/domains/middleware/registrations.ts +326 -0
- package/src/domains/middleware/runtime.ts +28 -0
- package/src/domains/middleware/skills-reminder.ts +31 -2
- package/src/domains/middleware/snapshot.ts +20 -7
- package/src/domains/mux/contract.ts +38 -0
- package/src/domains/mux/detect.ts +6 -13
- package/src/domains/mux/index.ts +1 -1
- package/src/domains/mux/operations.ts +44 -5
- package/src/domains/mux/yazi/assets/yazi.toml +2 -2
- package/src/domains/mux/yazi/session.ts +53 -4
- package/src/domains/mux/yazi/theme.ts +117 -17
- package/src/domains/observability/compaction-usage.ts +118 -0
- package/src/domains/observability/contract.ts +10 -11
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/extension.ts +17 -4
- package/src/domains/observability/out-of-turn-usage.ts +52 -21
- package/src/domains/observability/projection.ts +14 -90
- package/src/domains/observability/trace-store.ts +43 -7
- package/src/domains/prompts/compiler.ts +73 -53
- package/src/domains/prompts/contract.ts +15 -3
- package/src/domains/prompts/extension.ts +97 -9
- package/src/domains/prompts/fragments/identity/clio-worker.md +1 -3
- 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 +10 -24
- package/src/domains/prompts/fragments/operating/worker.md +1 -8
- package/src/domains/providers/contract.ts +4 -1
- package/src/domains/providers/extension.ts +40 -9
- package/src/domains/providers/index.ts +1 -1
- package/src/domains/providers/model-capabilities.ts +9 -0
- package/src/domains/providers/model-discovery.ts +2 -0
- package/src/domains/providers/model-runtime-capabilities.ts +99 -25
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +699 -114
- package/src/domains/providers/runtime-resolution.ts +31 -0
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +6 -2
- package/src/domains/providers/runtimes/common/local-synth.ts +2 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +7 -2
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +9 -1
- package/src/domains/providers/runtimes/protocol/litellm.ts +119 -29
- package/src/domains/providers/support.ts +11 -5
- package/src/domains/providers/target-model-cache.ts +25 -2
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/cost-provenance.ts +19 -0
- package/src/domains/providers/types/local-model-quirks.ts +85 -37
- package/src/domains/providers/types/runtime-descriptor.ts +20 -1
- package/src/domains/providers/types/target-descriptor.ts +19 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/skills/install.ts +72 -7
- package/src/domains/resources/skills/loader.ts +23 -19
- package/src/domains/resources/skills/marketplace.ts +63 -11
- package/src/domains/safety/autonomy.ts +15 -0
- package/src/domains/safety/call-target.ts +1 -1
- package/src/domains/safety/index.ts +1 -0
- package/src/domains/safety/loop-detector.ts +7 -4
- package/src/domains/safety/path-policy.ts +1 -1
- package/src/domains/safety/policy-engine.ts +34 -11
- package/src/domains/safety/protected-artifacts.ts +191 -88
- package/src/domains/safety/run-effects.ts +2 -22
- package/src/domains/safety/skill-authority.ts +55 -0
- package/src/domains/session/compaction/compact.ts +72 -22
- package/src/domains/session/entries.ts +6 -0
- package/src/domains/session/task-board.ts +10 -9
- package/src/domains/session/usage.ts +3 -3
- package/src/domains/share/archive.ts +164 -7
- package/src/engine/acp/server.ts +62 -9
- package/src/engine/agent.ts +13 -3
- package/src/engine/ai.ts +26 -8
- package/src/engine/antigravity/subprocess-runtime.ts +386 -120
- package/src/engine/api-registry.ts +3 -0
- package/src/engine/apis/llamacpp-residency.ts +3 -4
- package/src/engine/apis/lmstudio.ts +3 -3
- package/src/engine/apis/ollama-native.ts +6 -6
- package/src/engine/apis/openai-completions.ts +145 -39
- package/src/engine/apis/output-budget.ts +8 -18
- package/src/engine/apis/residency.ts +8 -27
- package/src/engine/external-subprocess.ts +114 -6
- package/src/engine/gemma-channel-filter.ts +19 -0
- package/src/engine/loop-guard.ts +92 -12
- package/src/engine/worker-runtime.ts +40 -11
- package/src/engine/worker-tools.ts +3 -1
- package/src/entry/background-model-metadata.ts +18 -0
- package/src/entry/compaction-prompt.ts +57 -0
- package/src/entry/extension-hook-sources.ts +28 -0
- package/src/entry/extension-reload.ts +309 -0
- package/src/entry/orchestrator.ts +464 -251
- package/src/entry/task-memory-lifecycle.ts +35 -0
- package/src/interactive/application-controller.ts +2 -1
- package/src/interactive/bus-notices.ts +8 -1
- package/src/interactive/chat-loop-messages.ts +16 -17
- package/src/interactive/chat-loop.ts +75 -3
- package/src/interactive/chat-panel.ts +36 -13
- package/src/interactive/chat-renderer.ts +72 -7
- package/src/interactive/cost-overlay.ts +26 -2
- package/src/interactive/dispatch-board.ts +6 -11
- package/src/interactive/footer/widgets.ts +13 -0
- package/src/interactive/interactive-application.ts +39 -4
- package/src/interactive/interactive-input-runtime.ts +4 -0
- package/src/interactive/interactive-presentation.ts +2 -2
- package/src/interactive/interactive-slash-runtime.ts +4 -1
- package/src/interactive/overlays/extensions.ts +9 -1
- package/src/interactive/overlays/help-reference.ts +13 -0
- package/src/interactive/overlays/settings.ts +27 -16
- package/src/interactive/panes-runtime.ts +111 -35
- package/src/interactive/prompt-cache-identity.ts +88 -0
- package/src/interactive/renderers/worker-entry.ts +32 -0
- package/src/interactive/slash-commands.ts +153 -20
- package/src/interactive/stream-pacing-policy.ts +0 -23
- package/src/interactive/theme/labels.ts +19 -13
- package/src/interactive/turn-context.ts +39 -20
- package/src/interactive/turn-recovery.ts +8 -0
- package/src/interactive/turn-runtime.ts +27 -11
- package/src/interactive/turn-state.ts +7 -0
- package/src/interactive/worker-receipts.ts +1 -0
- package/src/interactive/worker-stream.ts +6 -1
- package/src/interactive/yazi-bridge.ts +60 -6
- package/src/tools/agent-tools.ts +30 -1
- package/src/tools/artifact.ts +2 -2
- package/src/tools/ask-user.ts +3 -3
- package/src/tools/bash.ts +1 -1
- 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/context/docs-engine.ts +20 -7
- package/src/tools/context/index.ts +59 -21
- package/src/tools/core-bootstrap.ts +28 -6
- package/src/tools/credential-present.ts +1 -2
- package/src/tools/dispatch-arguments.ts +6 -1
- package/src/tools/dispatch-event-text.ts +10 -0
- package/src/tools/dispatch-plan.ts +49 -4
- package/src/tools/dispatch-run-events.ts +1 -1
- package/src/tools/dispatch-runner.ts +12 -0
- 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/ledger.ts +3 -5
- package/src/tools/monitor-surface.ts +5 -13
- package/src/tools/observation.ts +4 -5
- 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 +41 -12
- package/src/tools/result-shaping.ts +18 -14
- package/src/tools/steer-surface.ts +1 -1
- package/src/tools/tasks.ts +1 -1
- package/src/tools/truncate.ts +6 -5
- package/src/tools/verify/surface.ts +6 -12
- package/src/tools/web-fetch-surface.ts +1 -3
- package/src/tools/worker-evidence.ts +3 -1
- package/src/worker/spec-contract.ts +4 -0
- package/dist/builtins-UJLMOVOV.js +0 -17
- package/dist/chunk-5QIAJV2D.js +0 -48
- package/dist/chunk-JZWT5J3Y.js +0 -814
- package/dist/chunk-K7VKOLQQ.js +0 -15
- package/dist/chunk-PMZCIOCJ.js +0 -25
- package/dist/chunk-SUW5DORT.js +0 -819
- package/dist/chunk-UOV2BYIW.js +0 -107
- package/dist/chunk-WR6U3OVP.js +0 -45
- package/dist/chunk-Y45G3AXC.js +0 -1558
- package/dist/reset-EOLM7GVE.js +0 -230
- package/dist/uninstall-N34PCTGJ.js +0 -331
- package/dist/upgrade-H7TOM7YL.js +0 -323
- package/docs/artifact-versions.md +0 -67
- package/docs/development-pipeline.md +0 -121
- package/docs/documentation-coverage.md +0 -46
- package/docs/documentation-guide.md +0 -167
- package/docs/time-conventions.md +0 -101
|
@@ -78,13 +78,13 @@ export interface MemoryInterventionDeps {
|
|
|
78
78
|
everyNTools?: number;
|
|
79
79
|
/** Lazily resolves the explicitly configured background role. Null means rules-only. */
|
|
80
80
|
getModelClient?: () => TaskMemoryModelClient | null;
|
|
81
|
+
/** One alternative route after a client error; never used after timeout, cancellation or model output. */
|
|
82
|
+
getFallbackModelClient?: () => TaskMemoryModelClient | null;
|
|
81
83
|
/** Completion budget derived from the resolved background model capability. */
|
|
82
84
|
getModelMaxTokens?: (configuredMaxTokens: number) => number;
|
|
83
85
|
/**
|
|
84
|
-
* True when
|
|
85
|
-
*
|
|
86
|
-
* own turn on a single-slot server or makes the server evict the resident
|
|
87
|
-
* model to serve it, so the boundary is skipped and the skip is recorded.
|
|
86
|
+
* True when known endpoint occupancy exhausts the resolved capacity bound.
|
|
87
|
+
* A shared gateway URL alone is not evidence that its request slots are full.
|
|
88
88
|
*/
|
|
89
89
|
backgroundEndpointBusy?: () => boolean;
|
|
90
90
|
/**
|
|
@@ -92,6 +92,8 @@ export interface MemoryInterventionDeps {
|
|
|
92
92
|
* routes it to the cost ledger; the middleware never prices anything.
|
|
93
93
|
*/
|
|
94
94
|
onStepUsage?: (usage: TaskMemoryStepUsage) => void;
|
|
95
|
+
/** Capture immutable accounting ownership at launch, before awaiting inference. */
|
|
96
|
+
captureStepUsage?: () => (usage: TaskMemoryStepUsage, isCurrent: boolean) => void;
|
|
95
97
|
/**
|
|
96
98
|
* Bank entries an llm-tier reminder cited when it reached the operator. The
|
|
97
99
|
* composition root proposes them into the durable memory store, which is what
|
|
@@ -139,6 +141,10 @@ export interface MemoryPromptedStepResult extends TaskMemoryPolicyResult {
|
|
|
139
141
|
}
|
|
140
142
|
|
|
141
143
|
export interface MemoryInterventionRegistration extends MiddlewareHookRegistration {
|
|
144
|
+
/** Invalidate pending content and discard all transient session/branch state. */
|
|
145
|
+
reset(): void;
|
|
146
|
+
/** Invalidate immediately without waiting for the model; refuse further work. */
|
|
147
|
+
dispose(): void;
|
|
142
148
|
evaluateAsync(
|
|
143
149
|
input: MiddlewareHookInput,
|
|
144
150
|
context?: MiddlewareHookEvaluationContext,
|
|
@@ -154,10 +160,9 @@ export interface MemoryInterventionRegistration extends MiddlewareHookRegistrati
|
|
|
154
160
|
/** True while a detached background memory step is still running. */
|
|
155
161
|
stepInFlight(): boolean;
|
|
156
162
|
/**
|
|
157
|
-
* Resolves
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* one at all rather than starting one it will abandon.
|
|
163
|
+
* Resolves when this generation's detached policy settles. Reset/shutdown
|
|
164
|
+
* release the policy immediately; an abort-ignoring transport can still
|
|
165
|
+
* finish later, with authority only to report its originating usage.
|
|
161
166
|
*/
|
|
162
167
|
whenIdle(): Promise<void>;
|
|
163
168
|
}
|
|
@@ -167,6 +172,10 @@ export interface MemoryInterventionRegistration extends MiddlewareHookRegistrati
|
|
|
167
172
|
* emits only cited, advisory reminders through the existing visible channel.
|
|
168
173
|
*/
|
|
169
174
|
export function createMemoryInterventionRegistration(deps: MemoryInterventionDeps): MemoryInterventionRegistration {
|
|
175
|
+
let generation = 0;
|
|
176
|
+
let generationController = new AbortController();
|
|
177
|
+
let observedSessionId: string | undefined;
|
|
178
|
+
let disposed = false;
|
|
170
179
|
const pending = new Map<string, PendingToolStep>();
|
|
171
180
|
const trajectory: TrajectoryStep[] = [];
|
|
172
181
|
const failures = new Map<string, FailedAttempt>();
|
|
@@ -194,11 +203,17 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
194
203
|
let consecutiveLlmTimeouts = 0;
|
|
195
204
|
|
|
196
205
|
return {
|
|
206
|
+
reset,
|
|
207
|
+
dispose(): void {
|
|
208
|
+
disposed = true;
|
|
209
|
+
reset();
|
|
210
|
+
},
|
|
197
211
|
id: MEMORY_INTERVENTION_REGISTRATION_ID,
|
|
198
212
|
description: "maintain bounded task execution memory and selectively remind after repeated failures or compaction",
|
|
199
213
|
hooks: ["before_tool", "after_tool", "turn_start", "turn_end", "on_compaction"],
|
|
200
214
|
evaluate(input): ReadonlyArray<MiddlewareEffect> {
|
|
201
|
-
|
|
215
|
+
observeSession(input);
|
|
216
|
+
if (disposed || !settings().enabled) return NO_EFFECTS;
|
|
202
217
|
try {
|
|
203
218
|
switch (input.hook) {
|
|
204
219
|
case "before_tool":
|
|
@@ -274,7 +289,8 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
274
289
|
* would have been buffered anyway.
|
|
275
290
|
*/
|
|
276
291
|
async evaluateAsync(input, context): Promise<ReadonlyArray<MiddlewareEffect>> {
|
|
277
|
-
|
|
292
|
+
observeSession(input);
|
|
293
|
+
if (disposed || !settings().enabled || input.hook !== "turn_end" || pendingTriggers.size === 0) return NO_EFFECTS;
|
|
278
294
|
const boundary = input.turnId ?? input.metadata?.userTurnId?.toString() ?? `tool-step:${toolStep}`;
|
|
279
295
|
if (boundary === lastPromptedBoundary) return NO_EFFECTS;
|
|
280
296
|
// One row rather than none, so a headless operator reading the log sees
|
|
@@ -316,6 +332,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
316
332
|
) ??
|
|
317
333
|
false);
|
|
318
334
|
rulesInjectedSincePromptedStep = false;
|
|
335
|
+
const stepGeneration = generation;
|
|
319
336
|
promptedStepInFlight = true;
|
|
320
337
|
outstandingStep = runPromptedStep({
|
|
321
338
|
deterministicTrigger: triggers.some((trigger) => trigger !== "interval"),
|
|
@@ -323,6 +340,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
323
340
|
triggerReasons: triggers,
|
|
324
341
|
})
|
|
325
342
|
.then((result) => {
|
|
343
|
+
if (stepGeneration !== generation || disposed) return;
|
|
326
344
|
// A rules-only reminder can win the visible boundary while the optional
|
|
327
345
|
// background route resolves to null. Preserve the operator-visible
|
|
328
346
|
// injected outcome instead of overwriting it with that no-client silence.
|
|
@@ -336,13 +354,13 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
336
354
|
// covers a throwing delivery sink, which must not surface anywhere.
|
|
337
355
|
})
|
|
338
356
|
.finally(() => {
|
|
339
|
-
promptedStepInFlight = false;
|
|
357
|
+
if (stepGeneration === generation) promptedStepInFlight = false;
|
|
340
358
|
});
|
|
341
359
|
return NO_EFFECTS;
|
|
342
360
|
},
|
|
343
361
|
runPromptedStep,
|
|
344
362
|
signalLoop(): void {
|
|
345
|
-
if (settings().enabled) pendingTriggers.add("loop_signal");
|
|
363
|
+
if (!disposed && settings().enabled) pendingTriggers.add("loop_signal");
|
|
346
364
|
},
|
|
347
365
|
lastDecision: () => lastDecision,
|
|
348
366
|
recentActivity: () => [...activity],
|
|
@@ -350,6 +368,43 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
350
368
|
whenIdle: () => outstandingStep,
|
|
351
369
|
};
|
|
352
370
|
|
|
371
|
+
function observeSession(input: MiddlewareHookInput): void {
|
|
372
|
+
if (input.sessionId === undefined) return;
|
|
373
|
+
if (observedSessionId !== undefined && observedSessionId !== input.sessionId) reset();
|
|
374
|
+
observedSessionId = input.sessionId;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function reset(): void {
|
|
378
|
+
generation += 1;
|
|
379
|
+
generationController.abort();
|
|
380
|
+
generationController = new AbortController();
|
|
381
|
+
deps.bank.clear();
|
|
382
|
+
pending.clear();
|
|
383
|
+
trajectory.length = 0;
|
|
384
|
+
failures.clear();
|
|
385
|
+
toolStep = 0;
|
|
386
|
+
lastTurnEndStep = 0;
|
|
387
|
+
reactivateAfterCompaction = false;
|
|
388
|
+
lastInjectedOperationFingerprint = null;
|
|
389
|
+
currentTask = "(current task unavailable)";
|
|
390
|
+
toolsSinceMemoryStep = 0;
|
|
391
|
+
consecutiveErrors = 0;
|
|
392
|
+
lastPromptedBoundary = null;
|
|
393
|
+
lastInjectedMessage = null;
|
|
394
|
+
lastDecision = null;
|
|
395
|
+
pendingTriggers.clear();
|
|
396
|
+
activity.length = 0;
|
|
397
|
+
annotatedThisTurn.clear();
|
|
398
|
+
telemetryBankSnapshot = deps.bank.snapshot();
|
|
399
|
+
promptedStepInFlight = false;
|
|
400
|
+
promptedStepTier = "rules";
|
|
401
|
+
outstandingStep = Promise.resolve();
|
|
402
|
+
rulesInjectedSincePromptedStep = false;
|
|
403
|
+
annotatedSinceTurnEnd = false;
|
|
404
|
+
consecutiveLlmTimeouts = 0;
|
|
405
|
+
observedSessionId = undefined;
|
|
406
|
+
}
|
|
407
|
+
|
|
353
408
|
function settings(): MemoryInterventionSettings {
|
|
354
409
|
const live = deps.getSettings?.();
|
|
355
410
|
return {
|
|
@@ -377,12 +432,16 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
377
432
|
effects: NO_EFFECTS,
|
|
378
433
|
});
|
|
379
434
|
const live = settings();
|
|
380
|
-
|
|
435
|
+
const stepGeneration = generation;
|
|
436
|
+
const isCurrent = () => !disposed && stepGeneration === generation;
|
|
437
|
+
const usageSink = deps.captureStepUsage?.();
|
|
438
|
+
if (disposed || !live.enabled) {
|
|
381
439
|
const result = silent("no_client");
|
|
382
440
|
lastDecision = result.decision;
|
|
383
441
|
return result;
|
|
384
442
|
}
|
|
385
443
|
const started = process.hrtime.bigint();
|
|
444
|
+
let attemptStarted = started;
|
|
386
445
|
const triggers = input.triggerReasons?.length ? input.triggerReasons : ["manual" as const];
|
|
387
446
|
let tier: TaskMemoryTelemetryTier = "rules";
|
|
388
447
|
promptedStepTier = tier;
|
|
@@ -407,17 +466,58 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
407
466
|
} else {
|
|
408
467
|
tier = "llm";
|
|
409
468
|
promptedStepTier = tier;
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
469
|
+
const runClient = (selected: TaskMemoryModelClient, timeoutMs: number) =>
|
|
470
|
+
runTaskMemoryPolicy(deps.bank, selected, {
|
|
471
|
+
isCurrent,
|
|
472
|
+
signal: generationController.signal,
|
|
473
|
+
onStepUsage: (usage) => {
|
|
474
|
+
if (usageSink) usageSink(usage, isCurrent());
|
|
475
|
+
else deps.onStepUsage?.(usage);
|
|
476
|
+
},
|
|
477
|
+
task: input.task?.trim() || currentTask,
|
|
478
|
+
trajectory: [...trajectory],
|
|
479
|
+
deterministicTrigger: input.deterministicTrigger,
|
|
480
|
+
maxTokens: live.maxTokens,
|
|
481
|
+
modelMaxTokens: positiveInteger(deps.getModelMaxTokens?.(live.maxTokens), live.maxTokens),
|
|
482
|
+
...(input.suppressIntervention === undefined ? {} : { suppressIntervention: input.suppressIntervention }),
|
|
483
|
+
previousReminder: lastInjectedMessage,
|
|
484
|
+
timeoutMs,
|
|
485
|
+
...(deps.onEnvelope === undefined ? {} : { onEnvelope: deps.onEnvelope }),
|
|
486
|
+
});
|
|
487
|
+
const remainingMs = () => Math.floor(live.timeoutMs - Number(process.hrtime.bigint() - started) / 1_000_000);
|
|
488
|
+
const initialTimeoutMs = remainingMs();
|
|
489
|
+
promptedResult =
|
|
490
|
+
initialTimeoutMs <= 0
|
|
491
|
+
? { ...silent("deadline"), decision: "timeout" }
|
|
492
|
+
: await runClient(client, initialTimeoutMs);
|
|
493
|
+
if (promptedResult.reason === "client_error" && isCurrent() && remainingMs() > 0) {
|
|
494
|
+
let fallback: TaskMemoryModelClient | null = null;
|
|
495
|
+
let fallbackReady = false;
|
|
496
|
+
try {
|
|
497
|
+
fallback = deps.getFallbackModelClient?.() ?? null;
|
|
498
|
+
fallbackReady = fallback !== null && deps.backgroundEndpointBusy?.() !== true;
|
|
499
|
+
} catch {
|
|
500
|
+
/* Fail closed and preserve the original call if routing or capacity is unreadable. */
|
|
501
|
+
}
|
|
502
|
+
const fallbackTimeoutMs = remainingMs();
|
|
503
|
+
if (fallback !== null && fallbackReady && isCurrent() && fallbackTimeoutMs > 0) {
|
|
504
|
+
// Each attempted call keeps its own telemetry and origin usage.
|
|
505
|
+
// The returned policy result describes the final attempt only.
|
|
506
|
+
emitTelemetry(
|
|
507
|
+
triggers,
|
|
508
|
+
tier,
|
|
509
|
+
promptedResult.decision,
|
|
510
|
+
promptedResult.reason,
|
|
511
|
+
0,
|
|
512
|
+
promptedResult.inputTokens,
|
|
513
|
+
promptedResult.outputTokens,
|
|
514
|
+
started,
|
|
515
|
+
{ bankOperations: promptedResult.bankOperations, droppedOperations: promptedResult.droppedOperations },
|
|
516
|
+
);
|
|
517
|
+
attemptStarted = process.hrtime.bigint();
|
|
518
|
+
promptedResult = await runClient(fallback, fallbackTimeoutMs);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
421
521
|
}
|
|
422
522
|
}
|
|
423
523
|
} catch (error) {
|
|
@@ -436,16 +536,11 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
436
536
|
error: error instanceof Error ? error.message : "resolving the background model client failed",
|
|
437
537
|
});
|
|
438
538
|
}
|
|
539
|
+
if (!isCurrent()) return { ...promptedResult, reminder: null, effects: NO_EFFECTS };
|
|
540
|
+
if (promptedResult.reason === "endpoint_busy") telemetryDecision = "dropped";
|
|
439
541
|
if (tier === "llm" && promptedResult.decision === "timeout") consecutiveLlmTimeouts += 1;
|
|
440
542
|
else if (tier === "llm" && telemetryDecision !== "dropped") consecutiveLlmTimeouts = 0;
|
|
441
543
|
lastDecision = promptedResult.decision;
|
|
442
|
-
if (promptedResult.usage !== null) {
|
|
443
|
-
try {
|
|
444
|
-
deps.onStepUsage?.(promptedResult.usage);
|
|
445
|
-
} catch {
|
|
446
|
-
// Accounting is bookkeeping. A failing sink never changes memory behavior.
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
544
|
if (promptedResult.decision === "injected") reportInjectedEntries(promptedResult.reminder);
|
|
450
545
|
emitTelemetry(
|
|
451
546
|
triggers,
|
|
@@ -455,7 +550,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
455
550
|
citedEntryCount(promptedResult.reminder),
|
|
456
551
|
promptedResult.inputTokens,
|
|
457
552
|
promptedResult.outputTokens,
|
|
458
|
-
|
|
553
|
+
attemptStarted,
|
|
459
554
|
{ bankOperations: promptedResult.bankOperations, droppedOperations: promptedResult.droppedOperations },
|
|
460
555
|
);
|
|
461
556
|
return {
|
|
@@ -50,8 +50,9 @@ export function announceMemoryStepEndpoint<Request, Response>(
|
|
|
50
50
|
const { bus, endpointKey, targetId } = deps;
|
|
51
51
|
if (endpointKey === null) return complete;
|
|
52
52
|
return async (request: Request): Promise<Response> => {
|
|
53
|
-
//
|
|
54
|
-
//
|
|
53
|
+
// The production client rechecks capacity after asynchronous preparation,
|
|
54
|
+
// immediately before calling this wrapper. Register synchronously so no
|
|
55
|
+
// local foreground launch can interleave between that check and this hold.
|
|
55
56
|
const releaseEndpointSlot = registerForegroundStream(endpointKey);
|
|
56
57
|
try {
|
|
57
58
|
return await complete(request);
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ordered, copy-on-write registration table behind a middleware contract.
|
|
3
|
+
*
|
|
4
|
+
* Three tiers share one id namespace and one evaluation list:
|
|
5
|
+
*
|
|
6
|
+
* - fixed: declarative rules (builtin plus composition-root definitions),
|
|
7
|
+
* immutable for the life of the contract and always evaluated first;
|
|
8
|
+
* - host: coded registrations appended by the composition root through
|
|
9
|
+
* registerHook, append-only, first id wins;
|
|
10
|
+
* - owned: registration sets replaced as one unit by an owner under a
|
|
11
|
+
* strictly increasing generation. Today the only owner is "user-hooks".
|
|
12
|
+
*
|
|
13
|
+
* The whole table is one immutable state object held behind a single
|
|
14
|
+
* reference. Every writer computes a complete next state and publishes it
|
|
15
|
+
* with one assignment; readers capture the reference once per evaluation, so
|
|
16
|
+
* an evaluation that started before a publish finishes against the state it
|
|
17
|
+
* started with, including across an await. Preparation never runs user code:
|
|
18
|
+
* conflicts are returned as frozen data and a caller emits them through the
|
|
19
|
+
* diagnostic sink only after publication.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { MiddlewareDiagnostic, MiddlewareDiagnosticSink, MiddlewareHookRegistration } from "./runtime.js";
|
|
23
|
+
|
|
24
|
+
export const MIDDLEWARE_REGISTRATION_OWNERS = ["user-hooks"] as const;
|
|
25
|
+
|
|
26
|
+
export type MiddlewareRegistrationOwner = (typeof MIDDLEWARE_REGISTRATION_OWNERS)[number];
|
|
27
|
+
|
|
28
|
+
export type MiddlewareRegistrationConflictTier = "builtin" | "host" | "owned";
|
|
29
|
+
|
|
30
|
+
export interface MiddlewareRegistrationConflict {
|
|
31
|
+
id: string;
|
|
32
|
+
conflictsWith: MiddlewareRegistrationConflictTier;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type ReplaceRegistrationsRejection = "stale" | "unknown-owner";
|
|
36
|
+
|
|
37
|
+
export type RegistrationConflictDiagnostic = Extract<MiddlewareDiagnostic, { kind: "registration_conflict" }>;
|
|
38
|
+
|
|
39
|
+
export interface ReplaceRegistrationsReport {
|
|
40
|
+
applied: boolean;
|
|
41
|
+
owner: MiddlewareRegistrationOwner;
|
|
42
|
+
/** Generation active for the owner after the call. */
|
|
43
|
+
activeGeneration: number;
|
|
44
|
+
reason?: ReplaceRegistrationsRejection;
|
|
45
|
+
/** Offered registrations dropped for colliding with a builtin, host, or earlier owned id. */
|
|
46
|
+
dropped: ReadonlyArray<MiddlewareRegistrationConflict>;
|
|
47
|
+
/**
|
|
48
|
+
* Remove this generation's registrations if the owner still holds it. A
|
|
49
|
+
* disposer for a superseded generation is a no-op, so a late disposal can
|
|
50
|
+
* never remove a newer generation's registrations.
|
|
51
|
+
*/
|
|
52
|
+
dispose(): void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A validated replacement whose complete next table state is already built.
|
|
57
|
+
* `publish` is one reference assignment: it does not validate, refuse,
|
|
58
|
+
* throw, or call out. The caller checks `current()` on the same stack
|
|
59
|
+
* immediately before publishing, then emits `conflicts` afterwards.
|
|
60
|
+
*/
|
|
61
|
+
export interface MiddlewareRegistrationReplacement {
|
|
62
|
+
owner: MiddlewareRegistrationOwner;
|
|
63
|
+
generation: number;
|
|
64
|
+
dropped: ReadonlyArray<MiddlewareRegistrationConflict>;
|
|
65
|
+
/** Diagnostics for `dropped`, as data. Nothing was emitted during preparation. */
|
|
66
|
+
conflicts: ReadonlyArray<RegistrationConflictDiagnostic>;
|
|
67
|
+
/** Registrations that will be active for the owner after publish. */
|
|
68
|
+
size: number;
|
|
69
|
+
/** True while the table state this replacement was prepared against is still the live one. */
|
|
70
|
+
current(): boolean;
|
|
71
|
+
/** Assignment-only publication of the prepared state. */
|
|
72
|
+
publish(): void;
|
|
73
|
+
/** Send `conflicts` to the diagnostic sink. Call only after publication. */
|
|
74
|
+
emitConflicts(): void;
|
|
75
|
+
/** Remove this generation's registrations if the owner still holds it. */
|
|
76
|
+
dispose(): void;
|
|
77
|
+
discard(): void;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type PrepareRegistrationReplacementResult =
|
|
81
|
+
| { status: "prepared"; replacement: MiddlewareRegistrationReplacement }
|
|
82
|
+
| {
|
|
83
|
+
status: "rejected";
|
|
84
|
+
owner: MiddlewareRegistrationOwner;
|
|
85
|
+
reason: ReplaceRegistrationsRejection;
|
|
86
|
+
activeGeneration: number;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export interface MiddlewareRegistrationTable {
|
|
90
|
+
/** The current frozen evaluation list. Capture once per evaluation. */
|
|
91
|
+
list(): ReadonlyArray<MiddlewareHookRegistration>;
|
|
92
|
+
registerHook(registration: MiddlewareHookRegistration): void;
|
|
93
|
+
prepareReplacement(
|
|
94
|
+
owner: MiddlewareRegistrationOwner,
|
|
95
|
+
generation: number,
|
|
96
|
+
registrations: ReadonlyArray<MiddlewareHookRegistration>,
|
|
97
|
+
): PrepareRegistrationReplacementResult;
|
|
98
|
+
replaceRegistrations(
|
|
99
|
+
owner: MiddlewareRegistrationOwner,
|
|
100
|
+
generation: number,
|
|
101
|
+
registrations: ReadonlyArray<MiddlewareHookRegistration>,
|
|
102
|
+
): ReplaceRegistrationsReport;
|
|
103
|
+
ownedGeneration(owner: MiddlewareRegistrationOwner): number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface OwnerSlot {
|
|
107
|
+
generation: number;
|
|
108
|
+
registrations: ReadonlyArray<MiddlewareHookRegistration>;
|
|
109
|
+
/** Host index the slot sits before; fixed at the owner's first replacement. */
|
|
110
|
+
anchor: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** One immutable table state. Replaced wholesale, never mutated. */
|
|
114
|
+
interface TableState {
|
|
115
|
+
host: ReadonlyArray<MiddlewareHookRegistration>;
|
|
116
|
+
hostIds: ReadonlySet<string>;
|
|
117
|
+
slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>;
|
|
118
|
+
list: ReadonlyArray<MiddlewareHookRegistration>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface MiddlewareRegistrationTableOptions {
|
|
122
|
+
fixed: ReadonlyArray<MiddlewareHookRegistration>;
|
|
123
|
+
/** Resolved per emission so the composition root can swap the sink later. */
|
|
124
|
+
diagnosticSink: () => MiddlewareDiagnosticSink;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function isRegistrationOwner(value: string): value is MiddlewareRegistrationOwner {
|
|
128
|
+
return (MIDDLEWARE_REGISTRATION_OWNERS as ReadonlyArray<string>).includes(value);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function createMiddlewareRegistrationTable(
|
|
132
|
+
options: MiddlewareRegistrationTableOptions,
|
|
133
|
+
): MiddlewareRegistrationTable {
|
|
134
|
+
const fixed = Object.freeze([...options.fixed]);
|
|
135
|
+
const fixedIds = new Set(fixed.map((registration) => registration.id));
|
|
136
|
+
|
|
137
|
+
const buildList = (
|
|
138
|
+
host: ReadonlyArray<MiddlewareHookRegistration>,
|
|
139
|
+
slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>,
|
|
140
|
+
): ReadonlyArray<MiddlewareHookRegistration> => {
|
|
141
|
+
const list: MiddlewareHookRegistration[] = [...fixed];
|
|
142
|
+
const slotAt = (index: number): void => {
|
|
143
|
+
for (const owner of MIDDLEWARE_REGISTRATION_OWNERS) {
|
|
144
|
+
const slot = slots.get(owner);
|
|
145
|
+
if (slot !== undefined && slot.anchor === index) list.push(...slot.registrations);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
for (let index = 0; index < host.length; index += 1) {
|
|
149
|
+
slotAt(index);
|
|
150
|
+
list.push(host[index] as MiddlewareHookRegistration);
|
|
151
|
+
}
|
|
152
|
+
slotAt(host.length);
|
|
153
|
+
return Object.freeze(list);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const makeState = (
|
|
157
|
+
host: ReadonlyArray<MiddlewareHookRegistration>,
|
|
158
|
+
slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>,
|
|
159
|
+
): TableState =>
|
|
160
|
+
Object.freeze({
|
|
161
|
+
host: Object.freeze([...host]),
|
|
162
|
+
hostIds: new Set(host.map((registration) => registration.id)),
|
|
163
|
+
slots: new Map(slots),
|
|
164
|
+
list: buildList(host, slots),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// The single live reference. Every publish below is `state = next`.
|
|
168
|
+
let state: TableState = makeState([], new Map());
|
|
169
|
+
|
|
170
|
+
const emit = (diagnostic: MiddlewareDiagnostic): void => {
|
|
171
|
+
try {
|
|
172
|
+
options.diagnosticSink()(diagnostic);
|
|
173
|
+
} catch {
|
|
174
|
+
// A diagnostics sink must never affect registration bookkeeping.
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const slotFor = (base: TableState, owner: MiddlewareRegistrationOwner): OwnerSlot =>
|
|
179
|
+
base.slots.get(owner) ?? { generation: 0, registrations: [], anchor: base.host.length };
|
|
180
|
+
|
|
181
|
+
const disposeGeneration = (owner: MiddlewareRegistrationOwner, generation: number): void => {
|
|
182
|
+
const base = state;
|
|
183
|
+
const held = base.slots.get(owner);
|
|
184
|
+
if (held === undefined || held.generation !== generation || held.registrations.length === 0) return;
|
|
185
|
+
const slots = new Map(base.slots);
|
|
186
|
+
slots.set(owner, { ...held, registrations: Object.freeze([]) });
|
|
187
|
+
state = makeState(base.host, slots);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const table: MiddlewareRegistrationTable = {
|
|
191
|
+
list: () => state.list,
|
|
192
|
+
registerHook(registration) {
|
|
193
|
+
const base = state;
|
|
194
|
+
if (fixedIds.has(registration.id) || base.hostIds.has(registration.id)) return;
|
|
195
|
+
const evictions: RegistrationConflictDiagnostic[] = [];
|
|
196
|
+
const slots = new Map(base.slots);
|
|
197
|
+
for (const [owner, slot] of base.slots) {
|
|
198
|
+
if (!slot.registrations.some((entry) => entry.id === registration.id)) continue;
|
|
199
|
+
slots.set(owner, {
|
|
200
|
+
...slot,
|
|
201
|
+
registrations: Object.freeze(slot.registrations.filter((entry) => entry.id !== registration.id)),
|
|
202
|
+
});
|
|
203
|
+
evictions.push({
|
|
204
|
+
kind: "registration_conflict",
|
|
205
|
+
registrationId: registration.id,
|
|
206
|
+
owner,
|
|
207
|
+
generation: slot.generation,
|
|
208
|
+
conflictsWith: "host",
|
|
209
|
+
action: "evicted",
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
state = makeState([...base.host, registration], slots);
|
|
213
|
+
// Diagnostics only after the publish; a sink that registers another
|
|
214
|
+
// host hook re-enters against the already-published state.
|
|
215
|
+
for (const eviction of evictions) emit(eviction);
|
|
216
|
+
},
|
|
217
|
+
prepareReplacement(owner, generation, registrations) {
|
|
218
|
+
if (!isRegistrationOwner(owner)) {
|
|
219
|
+
return { status: "rejected", owner, reason: "unknown-owner", activeGeneration: 0 };
|
|
220
|
+
}
|
|
221
|
+
const base = state;
|
|
222
|
+
const slot = slotFor(base, owner);
|
|
223
|
+
if (!Number.isInteger(generation) || generation <= slot.generation) {
|
|
224
|
+
return { status: "rejected", owner, reason: "stale", activeGeneration: slot.generation };
|
|
225
|
+
}
|
|
226
|
+
const dropped: MiddlewareRegistrationConflict[] = [];
|
|
227
|
+
const conflicts: RegistrationConflictDiagnostic[] = [];
|
|
228
|
+
const accepted: MiddlewareHookRegistration[] = [];
|
|
229
|
+
const seen = new Set<string>();
|
|
230
|
+
for (const registration of registrations) {
|
|
231
|
+
const conflictsWith: MiddlewareRegistrationConflictTier | null = fixedIds.has(registration.id)
|
|
232
|
+
? "builtin"
|
|
233
|
+
: base.hostIds.has(registration.id)
|
|
234
|
+
? "host"
|
|
235
|
+
: seen.has(registration.id)
|
|
236
|
+
? "owned"
|
|
237
|
+
: null;
|
|
238
|
+
if (conflictsWith !== null) {
|
|
239
|
+
dropped.push({ id: registration.id, conflictsWith });
|
|
240
|
+
conflicts.push({
|
|
241
|
+
kind: "registration_conflict",
|
|
242
|
+
registrationId: registration.id,
|
|
243
|
+
owner,
|
|
244
|
+
generation,
|
|
245
|
+
conflictsWith,
|
|
246
|
+
action: "dropped",
|
|
247
|
+
});
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
seen.add(registration.id);
|
|
251
|
+
accepted.push(registration);
|
|
252
|
+
}
|
|
253
|
+
const slots = new Map(base.slots);
|
|
254
|
+
slots.set(owner, { generation, registrations: Object.freeze(accepted), anchor: slot.anchor });
|
|
255
|
+
const prepared = makeState(base.host, slots);
|
|
256
|
+
let settled = false;
|
|
257
|
+
const frozenDropped = Object.freeze(dropped);
|
|
258
|
+
const frozenConflicts = Object.freeze(conflicts);
|
|
259
|
+
const replacement: MiddlewareRegistrationReplacement = {
|
|
260
|
+
owner,
|
|
261
|
+
generation,
|
|
262
|
+
dropped: frozenDropped,
|
|
263
|
+
conflicts: frozenConflicts,
|
|
264
|
+
size: accepted.length,
|
|
265
|
+
// Reference identity on the base state covers every kind of
|
|
266
|
+
// intervening change: host appends, other replacements, disposals.
|
|
267
|
+
current: () => !settled && state === base,
|
|
268
|
+
publish() {
|
|
269
|
+
settled = true;
|
|
270
|
+
state = prepared;
|
|
271
|
+
},
|
|
272
|
+
emitConflicts() {
|
|
273
|
+
for (const conflict of frozenConflicts) emit(conflict);
|
|
274
|
+
},
|
|
275
|
+
dispose() {
|
|
276
|
+
disposeGeneration(owner, generation);
|
|
277
|
+
},
|
|
278
|
+
discard() {
|
|
279
|
+
settled = true;
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
return { status: "prepared", replacement };
|
|
283
|
+
},
|
|
284
|
+
replaceRegistrations(owner, generation, registrations) {
|
|
285
|
+
const prepared = table.prepareReplacement(owner, generation, registrations);
|
|
286
|
+
if (prepared.status === "rejected") {
|
|
287
|
+
return {
|
|
288
|
+
applied: false,
|
|
289
|
+
owner: prepared.owner,
|
|
290
|
+
activeGeneration: prepared.activeGeneration,
|
|
291
|
+
reason: prepared.reason,
|
|
292
|
+
dropped: [],
|
|
293
|
+
dispose: () => undefined,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
const replacement = prepared.replacement;
|
|
297
|
+
// Nothing ran between prepare and here, so current() holds; the
|
|
298
|
+
// check is kept so the one-call form has the same shape as a caller
|
|
299
|
+
// that validates on its own stack.
|
|
300
|
+
if (!replacement.current()) {
|
|
301
|
+
replacement.discard();
|
|
302
|
+
return {
|
|
303
|
+
applied: false,
|
|
304
|
+
owner,
|
|
305
|
+
activeGeneration: table.ownedGeneration(owner),
|
|
306
|
+
reason: "stale",
|
|
307
|
+
dropped: replacement.dropped,
|
|
308
|
+
dispose: () => undefined,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
replacement.publish();
|
|
312
|
+
replacement.emitConflicts();
|
|
313
|
+
return {
|
|
314
|
+
applied: true,
|
|
315
|
+
owner,
|
|
316
|
+
activeGeneration: generation,
|
|
317
|
+
dropped: replacement.dropped,
|
|
318
|
+
dispose: () => replacement.dispose(),
|
|
319
|
+
};
|
|
320
|
+
},
|
|
321
|
+
ownedGeneration(owner) {
|
|
322
|
+
return state.slots.get(owner)?.generation ?? 0;
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
return table;
|
|
326
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHookBudgetTracker, type HookBudgetStats, type HookBudgetTracker } from "./budget.js";
|
|
2
|
+
import type { MiddlewareRegistrationConflictTier, MiddlewareRegistrationOwner } from "./registrations.js";
|
|
2
3
|
import { listMiddlewareRuleDefinitions } from "./rules.js";
|
|
3
4
|
import {
|
|
4
5
|
MIDDLEWARE_HOOK_TEXT_MAX_CHARS,
|
|
@@ -90,6 +91,20 @@ export type MiddlewareDiagnostic =
|
|
|
90
91
|
steadyStateWarn: boolean;
|
|
91
92
|
/** Rolling-window stats (p50/p95/over-count) for diagnosis. */
|
|
92
93
|
stats: HookBudgetStats;
|
|
94
|
+
}
|
|
95
|
+
| {
|
|
96
|
+
/**
|
|
97
|
+
* An owned registration set offered an id already held by a builtin
|
|
98
|
+
* rule or a host registration (dropped), or a later host registration
|
|
99
|
+
* took an id an owner held (evicted). Bookkeeping only; nothing was
|
|
100
|
+
* evaluated.
|
|
101
|
+
*/
|
|
102
|
+
kind: "registration_conflict";
|
|
103
|
+
registrationId: string;
|
|
104
|
+
owner: MiddlewareRegistrationOwner;
|
|
105
|
+
generation: number;
|
|
106
|
+
conflictsWith: MiddlewareRegistrationConflictTier;
|
|
107
|
+
action: "dropped" | "evicted";
|
|
93
108
|
};
|
|
94
109
|
|
|
95
110
|
export type MiddlewareDiagnosticSink = (diagnostic: MiddlewareDiagnostic) => void;
|
|
@@ -106,6 +121,10 @@ export function writeMiddlewareDiagnosticToStderr(diagnostic: MiddlewareDiagnost
|
|
|
106
121
|
);
|
|
107
122
|
return;
|
|
108
123
|
}
|
|
124
|
+
if (diagnostic.kind === "registration_conflict") {
|
|
125
|
+
process.stderr.write(`[clio-coder:middleware] ${formatRegistrationConflict(diagnostic)}\n`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
109
128
|
// A single post-warmup spike is telemetry, not operator-facing noise: only
|
|
110
129
|
// consistent slowness prints, unless CLIO_CODER_HOOK_BUDGET_DEBUG=1 asks for all.
|
|
111
130
|
if (!diagnostic.steadyStateWarn && process.env.CLIO_CODER_HOOK_BUDGET_DEBUG !== "1") return;
|
|
@@ -120,6 +139,15 @@ export function writeMiddlewareDiagnosticToStderr(diagnostic: MiddlewareDiagnost
|
|
|
120
139
|
);
|
|
121
140
|
}
|
|
122
141
|
|
|
142
|
+
/** One operator line for a registration_conflict diagnostic. */
|
|
143
|
+
export function formatRegistrationConflict(
|
|
144
|
+
diagnostic: Extract<MiddlewareDiagnostic, { kind: "registration_conflict" }>,
|
|
145
|
+
): string {
|
|
146
|
+
return diagnostic.action === "dropped"
|
|
147
|
+
? `${diagnostic.owner} registration '${diagnostic.registrationId}' (generation ${diagnostic.generation}) dropped: id is held by a ${diagnostic.conflictsWith} registration`
|
|
148
|
+
: `${diagnostic.owner} registration '${diagnostic.registrationId}' (generation ${diagnostic.generation}) evicted by a ${diagnostic.conflictsWith} registration with the same id`;
|
|
149
|
+
}
|
|
150
|
+
|
|
123
151
|
/**
|
|
124
152
|
* Wrap a declarative rule definition as a degenerate coded registration so a
|
|
125
153
|
* single ordered evaluation path serves both. The wrapped `evaluate` keeps the
|