@iowarp/clio-coder 0.4.1 → 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 +92 -0
- package/CONTRIBUTING.md +59 -36
- package/README.md +404 -472
- package/SECURITY.md +2 -1
- package/dist/{acp-ZILU3AUO.js → acp-TMDQZDIG.js} +7 -7
- package/dist/{agents-HYWGBGQR.js → agents-5N5NG3XG.js} +28 -28
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-N3QT7CBO.js → auth-Z5CCBXKQ.js} +8 -9
- package/dist/{builtins-UJLMOVOV.js → builtins-K6TNDT24.js} +4 -4
- package/dist/{chunk-GVQJ5CCZ.js → chunk-2HFQNRV3.js} +7 -7
- package/dist/{chunk-QMXC4JB7.js → chunk-2NHR3NAY.js} +163 -1401
- package/dist/chunk-2X4RYJTJ.js +39 -0
- package/dist/{chunk-Y45G3AXC.js → chunk-2Z2IKEXI.js} +6 -10
- package/dist/{chunk-EIMVLWB3.js → chunk-34BHNEE3.js} +7 -3
- package/dist/{chunk-GIZNH63R.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-AP73CFDC.js → chunk-3KIPBMUA.js} +2 -2
- package/dist/{chunk-J5LZHVIT.js → chunk-3M6DQK6S.js} +113 -35
- package/dist/{chunk-VEGN6WIQ.js → chunk-462T4EGZ.js} +2 -2
- package/dist/{chunk-AFKWHWXF.js → chunk-4JDLP6ZS.js} +33 -16
- package/dist/{chunk-6FN3E6KX.js → chunk-4O6MANBS.js} +2 -2
- package/dist/{chunk-AKB4GYDL.js → chunk-54ODD65L.js} +5 -5
- package/dist/{chunk-BBTJOK6Y.js → chunk-5KW52TEP.js} +3 -3
- package/dist/{chunk-6CCS4G3W.js → chunk-5PFYMY2V.js} +2 -2
- package/dist/chunk-77QIVUZB.js +1334 -0
- package/dist/{chunk-7OBGU7UB.js → chunk-7BHIY2MW.js} +7 -13
- package/dist/{chunk-3QSOM6PA.js → chunk-AZ4WMN4W.js} +2 -2
- package/dist/{chunk-6NJQITNH.js → chunk-B74PXLU7.js} +6 -3
- package/dist/{chunk-R23Z6K6I.js → chunk-B7HM5Z7T.js} +15 -15
- package/dist/{chunk-R32CLGZ6.js → chunk-BO7Y52RY.js} +81 -20
- package/dist/{chunk-UEDMSP56.js → chunk-BYMNWQ7O.js} +123 -148
- package/dist/{chunk-ZJLUDYFY.js → chunk-CRFOIAX3.js} +4 -4
- package/dist/{chunk-2NM363SV.js → chunk-CYZW7JHJ.js} +7 -7
- package/dist/{chunk-6HMJX2VU.js → chunk-DYHAXKHD.js} +38 -10
- package/dist/{chunk-THYWACCR.js → chunk-DZAW46HP.js} +3 -3
- package/dist/{chunk-FYUN5KZ3.js → chunk-DZEK6CJN.js} +17 -17
- package/dist/{chunk-3I5NY75V.js → chunk-E7GT7O5N.js} +5 -5
- package/dist/{chunk-VKFQTNDV.js → chunk-F2I26BDK.js} +4 -4
- package/dist/{chunk-HLW2MRKE.js → chunk-F4EKGO4N.js} +3 -1
- package/dist/{chunk-IXJT6DCX.js → chunk-FVDGR2ZL.js} +3 -3
- package/dist/{chunk-TZSKNMZG.js → chunk-GTUD2WMY.js} +2 -1
- package/dist/{chunk-7EPLI7VL.js → chunk-HIICAHCJ.js} +2 -2
- package/dist/{chunk-E67WX76H.js → chunk-HKMD33FO.js} +29 -80
- package/dist/chunk-HLAFFSEK.js +360 -0
- package/dist/{chunk-UAPGZHYC.js → chunk-I64IFBLB.js} +9 -2
- package/dist/{chunk-XKA2ICR3.js → chunk-I66ZTYNP.js} +440 -175
- package/dist/{chunk-7PWAODYW.js → chunk-I7XBWTYH.js} +2 -2
- package/dist/{chunk-PVAMAVBB.js → chunk-IDNA72AH.js} +102 -2
- package/dist/{chunk-GCSMB2KY.js → chunk-IKOZFYBN.js} +1 -1
- package/dist/{chunk-2VG7KLYV.js → chunk-IKSLQ4XV.js} +5460 -3241
- package/dist/{chunk-QKIFBZKT.js → chunk-IMXMHHMQ.js} +166 -25
- package/dist/{chunk-74YWRRU5.js → chunk-JBCS7CRR.js} +2 -2
- package/dist/{chunk-BDPT6GTK.js → chunk-JWJGP5DQ.js} +2 -2
- package/dist/{chunk-K6BF4U2H.js → chunk-KKOJXO6R.js} +62 -14
- package/dist/chunk-KPXDY6QF.js +47 -0
- package/dist/{chunk-ABLSQ6JX.js → chunk-LJID3DYZ.js} +7 -1
- package/dist/{chunk-VKRH2TCS.js → chunk-M2DAX4F6.js} +2 -2
- package/dist/{chunk-6I5ILFOF.js → chunk-M2WXEHER.js} +2 -2
- package/dist/{chunk-YPI3QQCF.js → chunk-MCEPRMZW.js} +2 -4
- package/dist/{chunk-N5UK64DP.js → chunk-MCMZMDAC.js} +2 -2
- package/dist/{chunk-Y4CAGMM6.js → chunk-MNJGS2IN.js} +5 -6
- package/dist/{chunk-TVHHYFHE.js → chunk-NEDJ26B5.js} +2 -2
- package/dist/{chunk-U2WB7TZS.js → chunk-NMJXSHBJ.js} +97 -85
- package/dist/{chunk-HUAS7ITX.js → chunk-O3YUNJZ2.js} +13 -21
- package/dist/{chunk-MA3H6DM5.js → chunk-P75RZCJW.js} +25 -3
- package/dist/{chunk-IG7BCQBA.js → chunk-PGF63K6I.js} +2 -2
- package/dist/chunk-PJX3WQUQ.js +42 -0
- package/dist/{chunk-6DWBAZ5U.js → chunk-Q4XWMHX6.js} +4 -6
- package/dist/{chunk-OJTRZGR3.js → chunk-QQLGQY2A.js} +8 -8
- package/dist/{chunk-J4HBWF6Y.js → chunk-RLYRBIYQ.js} +115 -20
- package/dist/{chunk-NLFAQR7Z.js → chunk-S66XZJOF.js} +3 -23
- package/dist/{chunk-C537JADH.js → chunk-SSEYRH53.js} +6 -7
- package/dist/chunk-SZAA6XDG.js +30 -0
- package/dist/{chunk-MOPSG2X7.js → chunk-TPEQIQIE.js} +6 -6
- package/dist/{chunk-JA5QWE4Z.js → chunk-UBRFI4HS.js} +1879 -1650
- package/dist/{chunk-BTGG6BG2.js → chunk-UH347SHR.js} +154 -15
- package/dist/{chunk-5YHDIDBP.js → chunk-UH632ZYL.js} +2 -2
- package/dist/{chunk-BWW4HLO4.js → chunk-UXCU4E3T.js} +8 -6
- package/dist/{chunk-6VC4OV3Z.js → chunk-VIA6RFQZ.js} +3 -11
- package/dist/{chunk-ZAZB4JMW.js → chunk-VKPAQYEB.js} +27 -8
- package/dist/{chunk-UXN6JT4W.js → chunk-W4YEMFBX.js} +2 -2
- package/dist/{chunk-TD3PGPQA.js → chunk-W6NIE6OW.js} +2 -2
- package/dist/{chunk-TVH4ONAM.js → chunk-X7IARSHT.js} +3 -3
- package/dist/{chunk-PJJ6MY27.js → chunk-XE3PCIXH.js} +3 -3
- package/dist/{chunk-FEFIFZTL.js → chunk-XGDPUNND.js} +2 -2
- package/dist/{chunk-SCYB3HA4.js → chunk-XOXV5GKE.js} +51 -16
- package/dist/{chunk-QTFGO774.js → chunk-XQRY4DTA.js} +24 -11
- package/dist/{chunk-BJGUKIG4.js → chunk-YJISEZKC.js} +2 -2
- package/dist/{chunk-GPPB3JBE.js → chunk-ZGNYYXQ6.js} +2 -2
- package/dist/{chunk-SINK3QR6.js → chunk-ZNT2M6TG.js} +7 -7
- package/dist/{chunk-7RY5VZPH.js → chunk-ZW4HH5JJ.js} +6 -6
- package/dist/cli/index.js +33 -32
- package/dist/{clio-IT3G3VQH.js → clio-7VB377CC.js} +7 -7
- package/dist/{code-nav-RK6S7F6E.js → code-nav-YVLCYA7V.js} +85 -17
- package/dist/{config-3QZRWZJF.js → config-4HVOS65E.js} +88 -43
- package/dist/{configure-FL7Y3KJF.js → configure-PIWO7B24.js} +10 -10
- package/dist/{context-5HE7ODYK.js → context-IYEHL3WQ.js} +33 -31
- package/dist/{context-XNHL75JV.js → context-KQYIWPWT.js} +47 -34
- package/dist/{context-KYQFRVDC.js → context-N6ZE3LGJ.js} +11 -11
- package/dist/{context-clear-N545L53A.js → context-clear-G4OGZJDS.js} +33 -31
- package/dist/{context-working-set-QHKXSV2F.js → context-working-set-BWLF6LJP.js} +7 -7
- package/dist/{dispatch-runner-RGIE5PCT.js → dispatch-runner-2QQAITS3.js} +38 -38
- package/dist/{docs-5NAF6AU7.js → docs-PD3EXDKU.js} +21 -20
- package/dist/{doctor-ZGPEGHIP.js → doctor-LHBD36VU.js} +23 -22
- package/dist/{eval-GXLL44RD.js → eval-C45FYRJ6.js} +21 -20
- package/dist/{eval-inventory-HBWSWQOK.js → eval-inventory-6DEJPLBF.js} +2 -2
- package/dist/{evidence-HWLBRH3Q.js → evidence-6SHONYAF.js} +30 -28
- package/dist/{evolve-FTZBMNVW.js → evolve-KRKMV72X.js} +30 -28
- package/dist/{extensions-VHRBEID7.js → extensions-KPZ2UHBB.js} +5 -3
- package/dist/{fleet-CKZHJWZJ.js → fleet-IVTCKDHT.js} +62 -61
- package/dist/{fleet-commands-EXDXBMV6.js → fleet-commands-EDWL3IT7.js} +5 -5
- package/dist/{fleet-decisions-OTHB6KRL.js → fleet-decisions-YP3YEFGK.js} +4 -4
- package/dist/{fleet-graph-YTEZUCUT.js → fleet-graph-ZFWKHY2M.js} +16 -14
- package/dist/{fleet-inspect-SS6YMDCK.js → fleet-inspect-FVUNCBML.js} +31 -29
- package/dist/{fleet-preflight-PBY4VYOM.js → fleet-preflight-UN5XED4R.js} +2 -2
- package/dist/{fleet-validate-KMEM5L3S.js → fleet-validate-XOWC4HSX.js} +17 -15
- package/dist/{fleet-verify-QD5M7E7Q.js → fleet-verify-UN3SODEL.js} +30 -28
- package/dist/{fleet-view-WAMJYNDT.js → fleet-view-TWHJKCN6.js} +31 -29
- package/dist/{init-5XQRBOFV.js → init-T2QORQ3Y.js} +50 -49
- package/dist/{interop-34TVO25M.js → interop-IN5I2A66.js} +5 -5
- package/dist/{library-3QY6KF57.js → library-LSCATDLZ.js} +15 -13
- package/dist/{memory-L4UTIIIW.js → memory-HYOKAGGJ.js} +31 -29
- package/dist/{models-ZVX3QOWE.js → models-2GPMFYCM.js} +22 -21
- package/dist/{monitor-CEKVSYTS.js → monitor-E4ASVUJH.js} +34 -32
- package/dist/{orchestrator-77BAP6BC.js → orchestrator-DDMPR3PY.js} +984 -583
- package/dist/{panes-7STHOAUJ.js → panes-E3RUXOW5.js} +4 -4
- package/dist/{panes-SHAUIRXY.js → panes-IXKLOKA2.js} +23 -8
- package/dist/{reset-EOLM7GVE.js → reset-OAQP3W4O.js} +4 -4
- package/dist/{resources-74GKTLSF.js → resources-OTRSN34L.js} +15 -13
- package/dist/{run-HBAUJNNZ.js → run-5DEYH5QK.js} +60 -59
- package/dist/{share-G3APVLVP.js → share-IHWTLO3M.js} +19 -15
- package/dist/{skills-35HHUKCR.js → skills-IYMXMKW4.js} +17 -15
- package/dist/{skills-eval-QN4HSHDC.js → skills-eval-DROHSJAR.js} +36 -36
- package/dist/{skills-inventory-J357J34F.js → skills-inventory-D7X4L4ZX.js} +15 -13
- package/dist/{slash-commands-JZZCQA32.js → slash-commands-QBM7UZ3B.js} +21 -18
- package/dist/{steer-XAVHJM22.js → steer-Z5DO23FJ.js} +2 -2
- package/dist/{targets-DSM6CY3M.js → targets-P2FUC4IL.js} +25 -28
- package/dist/{terminal-lease-JOPFUVEM.js → terminal-lease-YREJ3JX2.js} +5 -5
- package/dist/{tools-MKNWVPBH.js → tools-5B7RO6MV.js} +4 -4
- package/dist/{trace-ECQ7TIYZ.js → trace-YMGMUM6A.js} +55 -7
- package/dist/{upgrade-H7TOM7YL.js → upgrade-PXK3S2YM.js} +11 -9
- package/dist/{usage-X52N3IDJ.js → usage-ME5MPXGX.js} +36 -34
- package/dist/{verifiers-EJTVVSMA.js → verifiers-BVZ7IWOO.js} +5 -5
- package/dist/{verify-YJL6XET2.js → verify-5K7ZKQFC.js} +4 -4
- package/dist/{web-fetch-MPIFL3LL.js → web-fetch-MPARV2K7.js} +2 -2
- package/dist/{wiki-generate-4NDZTQ4B.js → wiki-generate-F5W5QTYY.js} +48 -47
- package/dist/{with-panes-OBOBFIIR.js → with-panes-BYOJCLAM.js} +51 -255
- package/dist/worker/entry.js +45 -30
- 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} +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} +50 -34
- package/docs/{commands-and-modes.md → guide/commands-and-modes.md} +65 -60
- package/docs/{configuration-and-targets.md → guide/configuration-and-targets.md} +227 -289
- package/docs/guide/configuration-reference.md +1158 -0
- package/docs/{environment-variables.md → guide/environment-variables.md} +31 -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} +44 -13
- 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} +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/{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} +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/package.json +9 -7
- package/skills/README.md +46 -37
- package/skills/coding/ast-grep/SKILL.md +2 -2
- package/skills/coding/coding-standards/SKILL.md +2 -2
- package/skills/coding/prototype/SKILL.md +2 -2
- package/skills/coding/tdd/SKILL.md +2 -2
- package/skills/context/context-handoff/SKILL.md +2 -2
- package/skills/context/context-prime/SKILL.md +2 -2
- package/skills/git/file-ticket/SKILL.md +2 -2
- package/skills/git/fix-issue/SKILL.md +3 -3
- package/skills/git/resolve-merge-conflicts/SKILL.md +2 -2
- package/skills/git/ship/SKILL.md +2 -2
- package/skills/git/worktree-create/SKILL.md +2 -2
- package/skills/git/worktree-merge/SKILL.md +2 -2
- 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/architecture/SKILL.md +2 -2
- package/skills/planning/backlog/SKILL.md +2 -2
- package/skills/planning/prd/SKILL.md +2 -2
- package/skills/planning/product-intent/SKILL.md +2 -2
- package/skills/planning/tech-spec/SKILL.md +2 -2
- package/skills/registry.yaml +62 -62
- package/skills/research/arxiv-literature/SKILL.md +2 -2
- package/skills/research/experiment-protocol/SKILL.md +2 -2
- package/skills/research/scientific-debugging/SKILL.md +2 -2
- package/skills/research/scientific-modernization/SKILL.md +2 -2
- package/skills/skill-marketplace.json +62 -62
- package/skills/workflow/cut-it/SKILL.md +2 -2
- package/skills/workflow/design-council/SKILL.md +2 -2
- package/skills/workflow/grill-me/SKILL.md +2 -2
- package/skills/workflow/workflow-distiller/SKILL.md +2 -2
- 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.ts +0 -4
- 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 +2 -1
- package/src/cli/internal-dispatch.ts +3 -4
- package/src/cli/panes.ts +19 -5
- package/src/cli/run.ts +2 -2
- package/src/cli/share.ts +5 -1
- package/src/cli/skills-eval.ts +3 -3
- package/src/cli/targets.ts +2 -6
- package/src/cli/trace.ts +55 -4
- 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 +5 -1
- package/src/core/defaults.ts +7 -4
- package/src/core/dispatch-outcome.ts +16 -0
- package/src/core/guardrails.ts +10 -49
- package/src/core/prompt-hint.ts +9 -0
- 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 +12 -14
- package/src/domains/agents/contract.ts +2 -0
- package/src/domains/agents/extension.ts +23 -1
- package/src/domains/config/keybindings.ts +8 -0
- package/src/domains/context/extension.ts +0 -3
- package/src/domains/context/working-set/path-index.ts +1 -0
- package/src/domains/dispatch/capability-match.ts +10 -0
- package/src/domains/dispatch/extension.ts +105 -22
- 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 +55 -3
- package/src/domains/eval/artifacts/store.ts +5 -0
- package/src/domains/eval/store.ts +8 -1
- 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/lifecycle/migrations/2026-09-01-extension-install-digests.ts +27 -0
- package/src/domains/lifecycle/migrations/index.ts +2 -0
- package/src/domains/lifecycle/naming-resources.ts +19 -4
- package/src/domains/lifecycle/naming-yazi.ts +10 -5
- 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 -4
- package/src/domains/middleware/registrations.ts +326 -0
- package/src/domains/middleware/runtime.ts +28 -0
- 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/contract.ts +10 -11
- package/src/domains/observability/extension.ts +11 -3
- 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/index.ts +1 -1
- package/src/domains/providers/model-runtime-capabilities.ts +85 -21
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +669 -104
- package/src/domains/providers/runtime-resolution.ts +31 -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/types/cost-provenance.ts +19 -0
- package/src/domains/providers/types/local-model-quirks.ts +85 -37
- package/src/domains/resources/skills/loader.ts +16 -19
- package/src/domains/safety/call-target.ts +1 -1
- package/src/domains/safety/loop-detector.ts +7 -4
- package/src/domains/session/task-board.ts +10 -9
- package/src/domains/share/archive.ts +164 -7
- package/src/engine/acp/server.ts +62 -9
- 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 +28 -25
- package/src/engine/apis/output-budget.ts +8 -18
- package/src/engine/apis/residency.ts +8 -27
- 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/extension-hook-sources.ts +28 -0
- package/src/entry/extension-reload.ts +309 -0
- package/src/entry/orchestrator.ts +59 -35
- package/src/interactive/application-controller.ts +2 -1
- package/src/interactive/bus-notices.ts +8 -1
- package/src/interactive/chat-loop-messages.ts +3 -13
- package/src/interactive/chat-loop.ts +10 -1
- package/src/interactive/chat-panel.ts +36 -13
- package/src/interactive/chat-renderer.ts +71 -7
- 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 +2 -0
- 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/slash-commands.ts +129 -14
- package/src/interactive/stream-pacing-policy.ts +0 -23
- package/src/interactive/turn-context.ts +30 -15
- 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 +29 -12
- package/src/tools/core-bootstrap.ts +28 -6
- package/src/tools/credential-present.ts +1 -2
- package/src/tools/dispatch-arguments.ts +5 -1
- package/src/tools/dispatch-plan.ts +48 -4
- package/src/tools/dispatch-run-events.ts +1 -1
- 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 +30 -7
- 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/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/docs/artifact-versions.md +0 -67
- package/docs/documentation-coverage.md +0 -46
- package/docs/documentation-guide.md +0 -167
- package/docs/time-conventions.md +0 -101
|
@@ -51,12 +51,47 @@ export const USER_HOOK_COMMAND_OUTPUT_MAX_CHARS = 4_000;
|
|
|
51
51
|
/** Cap on a prompt hook's injected message, in characters. */
|
|
52
52
|
export const USER_HOOK_PROMPT_MAX_CHARS = 2_000;
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Provenance of an installed package that supplied hook declarations, as the
|
|
56
|
+
* composition root attributes it. Middleware treats it as opaque identity
|
|
57
|
+
* data; it neither reads packages nor knows how the digests were produced.
|
|
58
|
+
*/
|
|
59
|
+
export interface UserHookPackageProvenance {
|
|
60
|
+
id: string;
|
|
61
|
+
/** Install scope label of the package (for example "user" or "project"). */
|
|
62
|
+
scope: string;
|
|
63
|
+
/** Path recorded at install, when known. */
|
|
64
|
+
sourcePath?: string;
|
|
65
|
+
/** Canonical filesystem identity of the installed package root. */
|
|
66
|
+
canonicalRoot: string;
|
|
67
|
+
/** SHA-256 of the manifest bytes covered by the installed-tree digest. */
|
|
68
|
+
manifestDigest: string;
|
|
69
|
+
/** Installed-tree digest recorded at install and reverified by the supplier. */
|
|
70
|
+
contentDigest: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Attribution for a hook declared by an installed package. The declaration
|
|
75
|
+
* bytes behind `declarationsDigest` are the ones the supplier hashed during
|
|
76
|
+
* content verification and captured; nothing here was re-read from a mutable
|
|
77
|
+
* path after verification.
|
|
78
|
+
*/
|
|
79
|
+
export interface UserHookExtensionSource {
|
|
80
|
+
provenance: UserHookPackageProvenance;
|
|
81
|
+
/** Generation the declarations were admitted under; 0 for an ephemeral build. */
|
|
82
|
+
generation: number;
|
|
83
|
+
/** SHA-256 of the captured hooks.yaml bytes. */
|
|
84
|
+
declarationsDigest: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
54
87
|
export interface UserHookSource {
|
|
55
88
|
origin: UserHookOrigin;
|
|
56
89
|
/** File path or `extensionId:path` the declaration was read from. */
|
|
57
90
|
sourcePath: string;
|
|
58
91
|
/** Extension id when origin is "extension". */
|
|
59
92
|
sourceId?: string;
|
|
93
|
+
/** Present exactly when origin is "extension". */
|
|
94
|
+
extension?: UserHookExtensionSource;
|
|
60
95
|
}
|
|
61
96
|
|
|
62
97
|
export interface NormalizedCommandHook {
|
|
@@ -314,6 +349,17 @@ export function loadUserHooks(
|
|
|
314
349
|
|
|
315
350
|
export type UserHookOutcome = "emitted" | "command-ok" | "command-failed" | "command-timeout" | "skipped";
|
|
316
351
|
|
|
352
|
+
/** Bounded extension attribution carried on every receipt of an extension hook. */
|
|
353
|
+
export interface HookReceiptExtension {
|
|
354
|
+
id: string;
|
|
355
|
+
scope: string;
|
|
356
|
+
canonicalRoot: string;
|
|
357
|
+
manifestDigest: string;
|
|
358
|
+
contentDigest: string;
|
|
359
|
+
declarationsDigest: string;
|
|
360
|
+
generation: number;
|
|
361
|
+
}
|
|
362
|
+
|
|
317
363
|
export interface HookReceipt {
|
|
318
364
|
at: number;
|
|
319
365
|
hookId: string;
|
|
@@ -327,6 +373,7 @@ export interface HookReceipt {
|
|
|
327
373
|
exitCode?: number;
|
|
328
374
|
outputChars?: number;
|
|
329
375
|
toolName?: string;
|
|
376
|
+
extension?: HookReceiptExtension;
|
|
330
377
|
}
|
|
331
378
|
|
|
332
379
|
export type HookReceiptSink = (receipt: HookReceipt) => void;
|
|
@@ -372,6 +419,10 @@ export function userHookToRegistration(
|
|
|
372
419
|
deps: UserHookRegistrationDeps,
|
|
373
420
|
): MiddlewareHookRegistration {
|
|
374
421
|
const now = deps.now ?? Date.now;
|
|
422
|
+
// Attribution is fixed when the registration is built, so a receipt written
|
|
423
|
+
// by a registration from an older generation names that generation even
|
|
424
|
+
// after a newer one is active.
|
|
425
|
+
const extension = hook.source.extension === undefined ? undefined : receiptExtension(hook.source.extension);
|
|
375
426
|
const baseReceipt = (input: { toolName?: string }): Omit<HookReceipt, "outcome"> => ({
|
|
376
427
|
at: now(),
|
|
377
428
|
hookId: hook.id,
|
|
@@ -380,6 +431,7 @@ export function userHookToRegistration(
|
|
|
380
431
|
hash: hook.hash,
|
|
381
432
|
hook: hook.on,
|
|
382
433
|
kind: hook.spec.kind,
|
|
434
|
+
...(extension !== undefined ? { extension: { ...extension } } : {}),
|
|
383
435
|
...(input.toolName !== undefined ? { toolName: input.toolName } : {}),
|
|
384
436
|
});
|
|
385
437
|
const registration: MiddlewareHookRegistration = {
|
|
@@ -401,6 +453,18 @@ export function userHookToRegistration(
|
|
|
401
453
|
return registration;
|
|
402
454
|
}
|
|
403
455
|
|
|
456
|
+
function receiptExtension(source: UserHookExtensionSource): HookReceiptExtension {
|
|
457
|
+
return {
|
|
458
|
+
id: source.provenance.id,
|
|
459
|
+
scope: source.provenance.scope,
|
|
460
|
+
canonicalRoot: source.provenance.canonicalRoot,
|
|
461
|
+
manifestDigest: source.provenance.manifestDigest,
|
|
462
|
+
contentDigest: source.provenance.contentDigest,
|
|
463
|
+
declarationsDigest: source.declarationsDigest,
|
|
464
|
+
generation: source.generation,
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
404
468
|
function evaluateHook(
|
|
405
469
|
hook: NormalizedUserHook,
|
|
406
470
|
deps: UserHookRegistrationDeps,
|
|
@@ -41,19 +41,27 @@ export {
|
|
|
41
41
|
} from "./dispatch-nudge.js";
|
|
42
42
|
export type { MiddlewareBundleOptions } from "./extension.js";
|
|
43
43
|
export { createEnvHookBudgetTracker, createMiddlewareBundle } from "./extension.js";
|
|
44
|
-
export {
|
|
44
|
+
export {
|
|
45
|
+
createHookReceiptLog,
|
|
46
|
+
HOOK_RECEIPT_LOG_CAPACITY,
|
|
47
|
+
type HookReceiptLog,
|
|
48
|
+
readPersistedHookReceipts,
|
|
49
|
+
} from "./hook-receipts.js";
|
|
45
50
|
export type {
|
|
46
51
|
HookReceipt,
|
|
52
|
+
HookReceiptExtension,
|
|
47
53
|
HookReceiptSink,
|
|
48
54
|
NormalizedUserHook,
|
|
49
55
|
UserHookCommandResult,
|
|
50
56
|
UserHookCommandRunner,
|
|
51
57
|
UserHookDeclarationBatch,
|
|
58
|
+
UserHookExtensionSource,
|
|
52
59
|
UserHookKind,
|
|
53
60
|
UserHookLoadIssue,
|
|
54
61
|
UserHookLoadResult,
|
|
55
62
|
UserHookOrigin,
|
|
56
63
|
UserHookOutcome,
|
|
64
|
+
UserHookPackageProvenance,
|
|
57
65
|
UserHookSource,
|
|
58
66
|
} from "./hooks.js";
|
|
59
67
|
export {
|
|
@@ -66,10 +74,12 @@ export {
|
|
|
66
74
|
userHookToRegistration,
|
|
67
75
|
} from "./hooks.js";
|
|
68
76
|
export {
|
|
69
|
-
type
|
|
77
|
+
type BuildUserHookRegistrationsOptions,
|
|
78
|
+
type BuildUserHookRegistrationsResult,
|
|
79
|
+
buildUserHookRegistrations,
|
|
80
|
+
type CapturedHookDeclarations,
|
|
81
|
+
type CapturedHookSourceSet,
|
|
70
82
|
type HookFileIssue,
|
|
71
|
-
type InstallUserHooksResult,
|
|
72
|
-
installUserHooks,
|
|
73
83
|
readHookSources,
|
|
74
84
|
spawnSyncCommandRunner,
|
|
75
85
|
} from "./hooks-io.js";
|
|
@@ -89,6 +99,19 @@ export {
|
|
|
89
99
|
type MemoryInterventionDeps,
|
|
90
100
|
} from "./memory-intervention.js";
|
|
91
101
|
export { announceMemoryStepEndpoint, type MemoryStepEndpointAnnouncerDeps } from "./memory-step-endpoint.js";
|
|
102
|
+
export {
|
|
103
|
+
createMiddlewareRegistrationTable,
|
|
104
|
+
MIDDLEWARE_REGISTRATION_OWNERS,
|
|
105
|
+
type MiddlewareRegistrationConflict,
|
|
106
|
+
type MiddlewareRegistrationConflictTier,
|
|
107
|
+
type MiddlewareRegistrationOwner,
|
|
108
|
+
type MiddlewareRegistrationReplacement,
|
|
109
|
+
type MiddlewareRegistrationTable,
|
|
110
|
+
type MiddlewareRegistrationTableOptions,
|
|
111
|
+
type PrepareRegistrationReplacementResult,
|
|
112
|
+
type ReplaceRegistrationsRejection,
|
|
113
|
+
type ReplaceRegistrationsReport,
|
|
114
|
+
} from "./registrations.js";
|
|
92
115
|
export { BUILTIN_MIDDLEWARE_RULE_IDS, listMiddlewareRuleDefinitions, listMiddlewareRules } from "./rules.js";
|
|
93
116
|
export type {
|
|
94
117
|
MiddlewareDiagnostic,
|
|
@@ -99,6 +122,7 @@ export type {
|
|
|
99
122
|
RunMiddlewareRegistrationsOptions,
|
|
100
123
|
} from "./runtime.js";
|
|
101
124
|
export {
|
|
125
|
+
formatRegistrationConflict,
|
|
102
126
|
registrationFromRuleDefinition,
|
|
103
127
|
runMiddlewareHook,
|
|
104
128
|
runMiddlewareRegistrations,
|
|
@@ -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
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { createHookBudgetTracker, resolveHookBudgetsFromEnv, resolveHookBudgetTunablesFromEnv } from "./budget.js";
|
|
2
2
|
import type { MiddlewareContract } from "./contract.js";
|
|
3
|
+
import { createMiddlewareRegistrationTable } from "./registrations.js";
|
|
3
4
|
import { cloneMiddlewareRule, listMiddlewareRuleDefinitions, listMiddlewareRules } from "./rules.js";
|
|
4
5
|
import {
|
|
5
6
|
cloneMiddlewareEffect,
|
|
6
7
|
type MiddlewareDiagnosticSink,
|
|
7
|
-
type MiddlewareHookRegistration,
|
|
8
8
|
type MiddlewareRuleDefinition,
|
|
9
9
|
registrationFromRuleDefinition,
|
|
10
10
|
runMiddlewareRegistrations,
|
|
11
|
+
writeMiddlewareDiagnosticToStderr,
|
|
11
12
|
} from "./runtime.js";
|
|
12
13
|
import type { MiddlewareRule, MiddlewareSnapshot } from "./types.js";
|
|
13
14
|
|
|
@@ -39,15 +40,20 @@ export function createMiddlewareContractFromSnapshot(snapshot: MiddlewareSnapsho
|
|
|
39
40
|
if (builtin?.predicate !== undefined) definition.predicate = builtin.predicate;
|
|
40
41
|
return definition;
|
|
41
42
|
});
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
let diagnosticSink: MiddlewareDiagnosticSink | undefined;
|
|
44
|
+
// Workers never receive owned registrations; the table exists so the
|
|
45
|
+
// worker contract satisfies the same interface with the same semantics.
|
|
46
|
+
const table = createMiddlewareRegistrationTable({
|
|
47
|
+
fixed: definitions.map(registrationFromRuleDefinition),
|
|
48
|
+
diagnosticSink: () => diagnosticSink ?? writeMiddlewareDiagnosticToStderr,
|
|
49
|
+
});
|
|
44
50
|
const budgetTracker = createHookBudgetTracker({
|
|
45
51
|
budgets: resolveHookBudgetsFromEnv(),
|
|
46
52
|
...resolveHookBudgetTunablesFromEnv(),
|
|
47
53
|
});
|
|
48
|
-
let diagnosticSink: MiddlewareDiagnosticSink | undefined;
|
|
49
54
|
return {
|
|
50
55
|
runHook(input) {
|
|
56
|
+
const registrations = table.list();
|
|
51
57
|
return runMiddlewareRegistrations(input, registrations, {
|
|
52
58
|
budgetTracker,
|
|
53
59
|
...(diagnosticSink !== undefined ? { onDiagnostic: diagnosticSink } : {}),
|
|
@@ -60,12 +66,19 @@ export function createMiddlewareContractFromSnapshot(snapshot: MiddlewareSnapsho
|
|
|
60
66
|
return createMiddlewareSnapshot(definitions.map((definition) => definition.rule));
|
|
61
67
|
},
|
|
62
68
|
registerHook(registration) {
|
|
63
|
-
|
|
64
|
-
registeredIds.add(registration.id);
|
|
65
|
-
registrations.push(registration);
|
|
69
|
+
table.registerHook(registration);
|
|
66
70
|
},
|
|
67
71
|
setDiagnosticSink(sink) {
|
|
68
72
|
diagnosticSink = sink;
|
|
69
73
|
},
|
|
74
|
+
prepareRegistrationReplacement(owner, generation, registrations) {
|
|
75
|
+
return table.prepareReplacement(owner, generation, registrations);
|
|
76
|
+
},
|
|
77
|
+
replaceRegistrations(owner, generation, registrations) {
|
|
78
|
+
return table.replaceRegistrations(owner, generation, registrations);
|
|
79
|
+
},
|
|
80
|
+
ownedGeneration(owner) {
|
|
81
|
+
return table.ownedGeneration(owner);
|
|
82
|
+
},
|
|
70
83
|
};
|
|
71
84
|
}
|
|
@@ -119,6 +119,20 @@ export interface MuxContract extends DomainContract {
|
|
|
119
119
|
focusPane(paneId: string): Promise<boolean>;
|
|
120
120
|
/** Zoom one Clio-created pane on, off, or toggled. Zooming steals focus; same rule as focusPane. */
|
|
121
121
|
zoomPane(paneId: string, mode: "on" | "off" | "toggle"): Promise<boolean>;
|
|
122
|
+
/**
|
|
123
|
+
* Bring keyboard focus back to Clio's own hosting pane. This is the return
|
|
124
|
+
* half of every explicit pane interaction: a pick in the files pane, a
|
|
125
|
+
* toggle that closed a pane the operator was looking at. False outside
|
|
126
|
+
* guest mode, without an anchor pane, or below the pane.focus floor.
|
|
127
|
+
*/
|
|
128
|
+
focusSelf(): Promise<boolean>;
|
|
129
|
+
/**
|
|
130
|
+
* Leave zoom on the tab that hosts Clio, so a dock split from the anchor is
|
|
131
|
+
* visible again. A zoomed tab hides every pane but one; opening or focusing
|
|
132
|
+
* the files pane behind a zoom would report success for a pane the operator
|
|
133
|
+
* cannot see. False when nothing was zoomed or the tier is absent.
|
|
134
|
+
*/
|
|
135
|
+
unzoomSelf(): Promise<boolean>;
|
|
122
136
|
/** Set a dock's share of its axis. False when the slot has no dock or the tier is absent. */
|
|
123
137
|
resizeDock(slot: DockSlot, share: number): Promise<boolean>;
|
|
124
138
|
/** Live dock geometry states, for `/panes` status. */
|
|
@@ -425,6 +439,30 @@ export function createMuxRuntime(options: MuxRuntimeOptions): MuxRuntime {
|
|
|
425
439
|
);
|
|
426
440
|
},
|
|
427
441
|
|
|
442
|
+
async focusSelf(): Promise<boolean> {
|
|
443
|
+
if (anchorPaneId === null || !muxSupportsMethod(detection.server, "pane.focus")) return false;
|
|
444
|
+
return await attempt(
|
|
445
|
+
"focusSelf",
|
|
446
|
+
async (live) => {
|
|
447
|
+
await live.paneFocus(anchorPaneId);
|
|
448
|
+
return true;
|
|
449
|
+
},
|
|
450
|
+
false,
|
|
451
|
+
);
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
async unzoomSelf(): Promise<boolean> {
|
|
455
|
+
if (anchorPaneId === null || !muxSupportsMethod(detection.server, "pane.zoom")) return false;
|
|
456
|
+
return await attempt(
|
|
457
|
+
"unzoomSelf",
|
|
458
|
+
async (live) => {
|
|
459
|
+
const result = await live.paneZoom(anchorPaneId, "off");
|
|
460
|
+
return result.changed;
|
|
461
|
+
},
|
|
462
|
+
false,
|
|
463
|
+
);
|
|
464
|
+
},
|
|
465
|
+
|
|
428
466
|
async resizeDock(slot: DockSlot, share: number): Promise<boolean> {
|
|
429
467
|
if (!docks) return false;
|
|
430
468
|
return await attempt("resizeDock", () => docks.resize(slot, share), false);
|