@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
|
@@ -619,6 +619,15 @@ export function adaptRunReceiptValidationStatus(
|
|
|
619
619
|
if (receipt.hostVerification?.status === "verified") {
|
|
620
620
|
return attributed("validated", receiptSource(receipt), { kind: "validator", id: "host-verification" }, artifacts);
|
|
621
621
|
}
|
|
622
|
+
// A batch member the failure was charged away from carries a check that
|
|
623
|
+
// exited non-zero, so the validator has no verdict for this run: neither the
|
|
624
|
+
// "failed" the exit code alone would suggest nor the "validated" a passing
|
|
625
|
+
// check earns. It stops here rather than falling through to receipt-quality,
|
|
626
|
+
// which cannot see that a declared host check failed on the tree this run
|
|
627
|
+
// shipped in.
|
|
628
|
+
if (receipt.hostVerification?.status === "not_implicated") {
|
|
629
|
+
return attributed("unknown", receiptSource(receipt), { kind: "validator", id: "host-verification" }, artifacts);
|
|
630
|
+
}
|
|
622
631
|
if (qualityHasFailure(receipt.quality)) {
|
|
623
632
|
return attributed("failed", receiptSource(receipt), { kind: "validator", id: "receipt-quality" }, artifacts);
|
|
624
633
|
}
|
|
@@ -939,7 +948,7 @@ export interface GroundedEvidenceValidationInput {
|
|
|
939
948
|
* Project validation that the evidence linker grounded in an executed
|
|
940
949
|
* artifact. Grounding requires at least one independently observed artifact:
|
|
941
950
|
* a self-report of the run under inspection cannot ground its own validation
|
|
942
|
-
* (docs/evidence-and-memory.md, "composition rules"), and an empty reference
|
|
951
|
+
* (docs/architecture/evidence-and-memory.md, "composition rules"), and an empty reference
|
|
943
952
|
* list grounds
|
|
944
953
|
* nothing at all.
|
|
945
954
|
*/
|
|
@@ -5,8 +5,10 @@ import type {
|
|
|
5
5
|
ExtensionInstallResult,
|
|
6
6
|
ExtensionListOptions,
|
|
7
7
|
ExtensionMutationResult,
|
|
8
|
+
ExtensionReloadPrepareResult,
|
|
8
9
|
ExtensionResourceKind,
|
|
9
10
|
ExtensionResourceRoot,
|
|
11
|
+
ExtensionSnapshot,
|
|
10
12
|
InstalledExtension,
|
|
11
13
|
} from "./manager.js";
|
|
12
14
|
|
|
@@ -17,6 +19,18 @@ export interface ExtensionsContract extends DomainContract {
|
|
|
17
19
|
enable(id: string, options?: ExtensionListOptions): ExtensionMutationResult;
|
|
18
20
|
disable(id: string, options?: ExtensionListOptions): ExtensionMutationResult;
|
|
19
21
|
remove(id: string, options?: ExtensionListOptions): ExtensionMutationResult;
|
|
22
|
+
/** Committed projection for the bundle's cwd; ephemeral generation-0 build for any other cwd. */
|
|
20
23
|
resourceRoots(kind: ExtensionResourceKind, cwd?: string): ExtensionResourceRoot[];
|
|
21
|
-
|
|
24
|
+
snapshot(): ExtensionSnapshot | null;
|
|
25
|
+
generation(): number;
|
|
26
|
+
/**
|
|
27
|
+
* Build and validate the next generation from disk without publishing it.
|
|
28
|
+
* Never throws: a build failure or an in-flight candidate is reported as a
|
|
29
|
+
* rejection and the committed generation is untouched. A rejected build
|
|
30
|
+
* still burns its reserved generation number. The candidate publishes
|
|
31
|
+
* itself with one assignment-only call after the caller has confirmed
|
|
32
|
+
* `current()` on the same stack. Nothing is published at start(); the
|
|
33
|
+
* composition root publishes the boot generation together with its hooks.
|
|
34
|
+
*/
|
|
35
|
+
prepareReload(): ExtensionReloadPrepareResult;
|
|
22
36
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
1
|
+
import { type Dirent, existsSync, lstatSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
4
4
|
import { evaluateClioCompatibility } from "./compatibility.js";
|
|
@@ -10,6 +10,23 @@ import type {
|
|
|
10
10
|
} from "./types.js";
|
|
11
11
|
|
|
12
12
|
const MANIFEST_NAMES = ["clio-coder-extension.yaml", "clio-coder-extension.yml", "clio-coder-extension.json"] as const;
|
|
13
|
+
const MANIFEST_KEYS = new Set([
|
|
14
|
+
"manifestVersion",
|
|
15
|
+
"id",
|
|
16
|
+
"name",
|
|
17
|
+
"version",
|
|
18
|
+
"description",
|
|
19
|
+
"resources",
|
|
20
|
+
"tools",
|
|
21
|
+
"settings",
|
|
22
|
+
"compatibility",
|
|
23
|
+
]);
|
|
24
|
+
const RESOURCE_KEYS = new Set(["skills", "prompts", "agents", "fleets", "themes"]);
|
|
25
|
+
const COMPATIBILITY_KEYS = new Set(["clio"]);
|
|
26
|
+
|
|
27
|
+
function compareNames(a: { name: string }, b: { name: string }): number {
|
|
28
|
+
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
29
|
+
}
|
|
13
30
|
|
|
14
31
|
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
15
32
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -35,19 +52,45 @@ function readJsonOrYaml(filePath: string): unknown {
|
|
|
35
52
|
return parseYaml(raw);
|
|
36
53
|
}
|
|
37
54
|
|
|
38
|
-
function
|
|
39
|
-
|
|
55
|
+
function rejectUnknownKeys(
|
|
56
|
+
value: Record<string, unknown>,
|
|
57
|
+
allowed: ReadonlySet<string>,
|
|
58
|
+
label: string,
|
|
59
|
+
manifestPath: string,
|
|
60
|
+
diagnostics: ExtensionDiagnostic[],
|
|
61
|
+
): void {
|
|
62
|
+
for (const key of Object.keys(value).sort()) {
|
|
63
|
+
if (!allowed.has(key)) {
|
|
64
|
+
diagnostics.push({ type: "error", message: `unknown ${label} key '${key}'`, path: manifestPath });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeResources(
|
|
70
|
+
value: unknown,
|
|
71
|
+
manifestPath: string,
|
|
72
|
+
diagnostics: ExtensionDiagnostic[],
|
|
73
|
+
): ExtensionManifestResources {
|
|
74
|
+
if (value === undefined) return {};
|
|
75
|
+
if (!isRecord(value)) {
|
|
76
|
+
diagnostics.push({ type: "error", message: "resources must be an object", path: manifestPath });
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
rejectUnknownKeys(value, RESOURCE_KEYS, "resources", manifestPath, diagnostics);
|
|
40
80
|
const out: ExtensionManifestResources = {};
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
81
|
+
for (const kind of RESOURCE_KEYS) {
|
|
82
|
+
if (value[kind] === undefined) continue;
|
|
83
|
+
const resourcePath = trimString(value[kind]);
|
|
84
|
+
if (!resourcePath) {
|
|
85
|
+
diagnostics.push({
|
|
86
|
+
type: "error",
|
|
87
|
+
message: `resources.${kind} must be a non-empty string`,
|
|
88
|
+
path: manifestPath,
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
out[kind as keyof ExtensionManifestResources] = resourcePath;
|
|
93
|
+
}
|
|
51
94
|
return out;
|
|
52
95
|
}
|
|
53
96
|
|
|
@@ -77,7 +120,7 @@ function validateResourceTree(
|
|
|
77
120
|
try {
|
|
78
121
|
canonicalRoot = realpathSync(resolvedRoot);
|
|
79
122
|
canonicalResource = realpathSync(resolved);
|
|
80
|
-
if (!
|
|
123
|
+
if (!statSync(resolved).isDirectory()) {
|
|
81
124
|
diagnostics.push({ type: "error", message: `resources.${kind} is not a directory`, path: resolved });
|
|
82
125
|
return;
|
|
83
126
|
}
|
|
@@ -98,16 +141,32 @@ function validateResourceTree(
|
|
|
98
141
|
while (pending.length > 0) {
|
|
99
142
|
const directory = pending.pop();
|
|
100
143
|
if (!directory) continue;
|
|
101
|
-
for (const entry of readdirSync(directory, { withFileTypes: true }).sort(
|
|
144
|
+
for (const entry of readdirSync(directory, { withFileTypes: true }).sort(compareNames)) {
|
|
102
145
|
const candidate = path.join(directory, entry.name);
|
|
103
146
|
if (entry.isSymbolicLink()) {
|
|
104
147
|
try {
|
|
105
|
-
|
|
148
|
+
const canonicalTarget = realpathSync(candidate);
|
|
149
|
+
if (!contained(canonicalRoot, canonicalTarget)) {
|
|
106
150
|
diagnostics.push({
|
|
107
151
|
type: "error",
|
|
108
152
|
message: `resources.${kind} contains an escaping symbolic link`,
|
|
109
153
|
path: candidate,
|
|
110
154
|
});
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const targetStat = statSync(candidate);
|
|
158
|
+
if (!targetStat.isDirectory() && !targetStat.isFile()) {
|
|
159
|
+
diagnostics.push({
|
|
160
|
+
type: "error",
|
|
161
|
+
message: `resources.${kind} contains a symbolic link to an unsupported filesystem entry`,
|
|
162
|
+
path: candidate,
|
|
163
|
+
});
|
|
164
|
+
} else if (targetStat.isFile() && targetStat.nlink !== 1) {
|
|
165
|
+
diagnostics.push({
|
|
166
|
+
type: "error",
|
|
167
|
+
message: `resources.${kind} contains a symbolic link to a hard-linked file`,
|
|
168
|
+
path: candidate,
|
|
169
|
+
});
|
|
111
170
|
}
|
|
112
171
|
} catch (error) {
|
|
113
172
|
diagnostics.push({
|
|
@@ -118,6 +177,28 @@ function validateResourceTree(
|
|
|
118
177
|
}
|
|
119
178
|
} else if (entry.isDirectory()) {
|
|
120
179
|
pending.push(candidate);
|
|
180
|
+
} else if (entry.isFile()) {
|
|
181
|
+
try {
|
|
182
|
+
if (lstatSync(candidate).nlink !== 1) {
|
|
183
|
+
diagnostics.push({
|
|
184
|
+
type: "error",
|
|
185
|
+
message: `resources.${kind} contains a hard-linked file`,
|
|
186
|
+
path: candidate,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
diagnostics.push({
|
|
191
|
+
type: "error",
|
|
192
|
+
message: `resources.${kind} entry could not be inspected: ${error instanceof Error ? error.message : String(error)}`,
|
|
193
|
+
path: candidate,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
diagnostics.push({
|
|
198
|
+
type: "error",
|
|
199
|
+
message: `resources.${kind} contains an unsupported filesystem entry`,
|
|
200
|
+
path: candidate,
|
|
201
|
+
});
|
|
121
202
|
}
|
|
122
203
|
}
|
|
123
204
|
}
|
|
@@ -133,9 +214,32 @@ function validateResourceRoots(
|
|
|
133
214
|
}
|
|
134
215
|
}
|
|
135
216
|
|
|
136
|
-
function stringArray(
|
|
137
|
-
|
|
138
|
-
|
|
217
|
+
function stringArray(
|
|
218
|
+
value: unknown,
|
|
219
|
+
field: "tools" | "settings",
|
|
220
|
+
manifestPath: string,
|
|
221
|
+
diagnostics: ExtensionDiagnostic[],
|
|
222
|
+
): string[] | undefined {
|
|
223
|
+
if (value === undefined) return undefined;
|
|
224
|
+
if (!Array.isArray(value)) {
|
|
225
|
+
diagnostics.push({ type: "error", message: `${field} must be an array of non-empty strings`, path: manifestPath });
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
const out: string[] = [];
|
|
229
|
+
const seen = new Set<string>();
|
|
230
|
+
for (const entry of value) {
|
|
231
|
+
const parsed = trimString(entry);
|
|
232
|
+
if (!parsed) {
|
|
233
|
+
diagnostics.push({ type: "error", message: `${field} must contain only non-empty strings`, path: manifestPath });
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (seen.has(parsed)) {
|
|
237
|
+
diagnostics.push({ type: "error", message: `${field} contains duplicate entry '${parsed}'`, path: manifestPath });
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
seen.add(parsed);
|
|
241
|
+
out.push(parsed);
|
|
242
|
+
}
|
|
139
243
|
return out.length > 0 ? out : undefined;
|
|
140
244
|
}
|
|
141
245
|
|
|
@@ -150,6 +254,7 @@ export function parseExtensionManifest(
|
|
|
150
254
|
if (!isRecord(value)) {
|
|
151
255
|
return { diagnostics: [{ type: "error", message: "extension manifest must be an object", path: manifestPath }] };
|
|
152
256
|
}
|
|
257
|
+
rejectUnknownKeys(value, MANIFEST_KEYS, "manifest", manifestPath, diagnostics);
|
|
153
258
|
if (value.manifestVersion !== 1) {
|
|
154
259
|
diagnostics.push({ type: "error", message: "manifestVersion must be 1", path: manifestPath });
|
|
155
260
|
}
|
|
@@ -164,31 +269,36 @@ export function parseExtensionManifest(
|
|
|
164
269
|
}
|
|
165
270
|
if (!version) diagnostics.push({ type: "error", message: "version is required", path: manifestPath });
|
|
166
271
|
if (!description) diagnostics.push({ type: "error", message: "description is required", path: manifestPath });
|
|
167
|
-
const resources = normalizeResources(value.resources);
|
|
168
|
-
const tools = stringArray(value.tools);
|
|
169
|
-
const settings = stringArray(value.settings);
|
|
272
|
+
const resources = normalizeResources(value.resources, manifestPath, diagnostics);
|
|
273
|
+
const tools = stringArray(value.tools, "tools", manifestPath, diagnostics);
|
|
274
|
+
const settings = stringArray(value.settings, "settings", manifestPath, diagnostics);
|
|
170
275
|
let compatibility: ClioExtensionManifest["compatibility"];
|
|
171
276
|
if (value.compatibility !== undefined) {
|
|
172
277
|
if (!isRecord(value.compatibility)) {
|
|
173
278
|
diagnostics.push({ type: "error", message: "compatibility must be an object", path: manifestPath });
|
|
174
|
-
} else
|
|
175
|
-
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
type: "error",
|
|
179
|
-
message: "compatibility.clio must be a non-empty semver range",
|
|
180
|
-
path: manifestPath,
|
|
181
|
-
});
|
|
279
|
+
} else {
|
|
280
|
+
rejectUnknownKeys(value.compatibility, COMPATIBILITY_KEYS, "compatibility", manifestPath, diagnostics);
|
|
281
|
+
if (!("clio" in value.compatibility)) {
|
|
282
|
+
compatibility = {};
|
|
182
283
|
} else {
|
|
183
|
-
const
|
|
184
|
-
if (
|
|
284
|
+
const range = trimString(value.compatibility.clio);
|
|
285
|
+
if (range === undefined) {
|
|
185
286
|
diagnostics.push({
|
|
186
287
|
type: "error",
|
|
187
|
-
message:
|
|
288
|
+
message: "compatibility.clio must be a non-empty semver range",
|
|
188
289
|
path: manifestPath,
|
|
189
290
|
});
|
|
190
291
|
} else {
|
|
191
|
-
|
|
292
|
+
const evaluation = evaluateClioCompatibility(range);
|
|
293
|
+
if (!evaluation.rangeValid) {
|
|
294
|
+
diagnostics.push({
|
|
295
|
+
type: "error",
|
|
296
|
+
message: `extension ${id ?? "<unknown>"} declares malformed compatibility.clio range '${range}'`,
|
|
297
|
+
path: manifestPath,
|
|
298
|
+
});
|
|
299
|
+
} else {
|
|
300
|
+
compatibility = { clio: range };
|
|
301
|
+
}
|
|
192
302
|
}
|
|
193
303
|
}
|
|
194
304
|
}
|
|
@@ -268,7 +378,24 @@ export function discoverExtensionPackages(root: string): ExtensionCandidate[] {
|
|
|
268
378
|
if (!existsSync(full)) {
|
|
269
379
|
return [{ path: full, valid: false, diagnostics: [{ type: "error", message: "path does not exist", path: full }] }];
|
|
270
380
|
}
|
|
271
|
-
|
|
381
|
+
let stat: ReturnType<typeof statSync>;
|
|
382
|
+
try {
|
|
383
|
+
stat = statSync(full);
|
|
384
|
+
} catch (error) {
|
|
385
|
+
return [
|
|
386
|
+
{
|
|
387
|
+
path: full,
|
|
388
|
+
valid: false,
|
|
389
|
+
diagnostics: [
|
|
390
|
+
{
|
|
391
|
+
type: "error",
|
|
392
|
+
message: `extension path could not be inspected: ${error instanceof Error ? error.message : String(error)}`,
|
|
393
|
+
path: full,
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
},
|
|
397
|
+
];
|
|
398
|
+
}
|
|
272
399
|
if (!stat.isDirectory()) {
|
|
273
400
|
return [
|
|
274
401
|
{
|
|
@@ -278,16 +405,86 @@ export function discoverExtensionPackages(root: string): ExtensionCandidate[] {
|
|
|
278
405
|
},
|
|
279
406
|
];
|
|
280
407
|
}
|
|
281
|
-
|
|
408
|
+
let canonicalFull: string;
|
|
409
|
+
try {
|
|
410
|
+
canonicalFull = realpathSync(full);
|
|
411
|
+
} catch (error) {
|
|
412
|
+
return [
|
|
413
|
+
{
|
|
414
|
+
path: full,
|
|
415
|
+
valid: false,
|
|
416
|
+
diagnostics: [
|
|
417
|
+
{
|
|
418
|
+
type: "error",
|
|
419
|
+
message: `extension path could not be canonicalized: ${error instanceof Error ? error.message : String(error)}`,
|
|
420
|
+
path: full,
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
},
|
|
424
|
+
];
|
|
425
|
+
}
|
|
426
|
+
const direct = loadManifestFromRoot(canonicalFull);
|
|
282
427
|
if (direct.valid || direct.manifestPath) return [direct];
|
|
283
428
|
const candidates: ExtensionCandidate[] = [];
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
429
|
+
const discoveryFailures: ExtensionCandidate[] = [];
|
|
430
|
+
const spellingsByCanonicalRoot = new Map<string, string[]>();
|
|
431
|
+
let entries: Dirent<string>[];
|
|
432
|
+
try {
|
|
433
|
+
entries = readdirSync(canonicalFull, { withFileTypes: true, encoding: "utf8" });
|
|
434
|
+
} catch (error) {
|
|
435
|
+
return [
|
|
436
|
+
{
|
|
437
|
+
path: canonicalFull,
|
|
438
|
+
valid: false,
|
|
439
|
+
diagnostics: [
|
|
440
|
+
{
|
|
441
|
+
type: "error",
|
|
442
|
+
message: `extension directory could not be read: ${error instanceof Error ? error.message : String(error)}`,
|
|
443
|
+
path: canonicalFull,
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
},
|
|
447
|
+
];
|
|
448
|
+
}
|
|
449
|
+
for (const entry of entries.sort(compareNames)) {
|
|
450
|
+
if (entry.name.startsWith(".")) continue;
|
|
451
|
+
const child = path.join(canonicalFull, entry.name);
|
|
452
|
+
try {
|
|
453
|
+
if (!entry.isDirectory() && !(entry.isSymbolicLink() && statSync(child).isDirectory())) continue;
|
|
454
|
+
const canonicalChild = realpathSync(child);
|
|
455
|
+
const spellings = spellingsByCanonicalRoot.get(canonicalChild) ?? [];
|
|
456
|
+
spellings.push(child);
|
|
457
|
+
spellingsByCanonicalRoot.set(canonicalChild, spellings);
|
|
458
|
+
} catch (error) {
|
|
459
|
+
discoveryFailures.push({
|
|
460
|
+
path: child,
|
|
461
|
+
valid: false,
|
|
462
|
+
diagnostics: [
|
|
463
|
+
{
|
|
464
|
+
type: "error",
|
|
465
|
+
message: `extension child could not be canonicalized: ${error instanceof Error ? error.message : String(error)}`,
|
|
466
|
+
path: child,
|
|
467
|
+
},
|
|
468
|
+
],
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
for (const canonicalChild of [...spellingsByCanonicalRoot.keys()].sort()) {
|
|
473
|
+
const loaded = loadManifestFromRoot(canonicalChild);
|
|
474
|
+
const spellings = spellingsByCanonicalRoot.get(canonicalChild) ?? [];
|
|
475
|
+
if (spellings.length > 1) {
|
|
476
|
+
loaded.diagnostics.push({
|
|
477
|
+
type: "warning",
|
|
478
|
+
message: `duplicate canonical extension root loaded once; discovered as ${spellings.sort().join(", ")}`,
|
|
479
|
+
path: canonicalChild,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
288
482
|
if (loaded.valid || loaded.manifestPath) candidates.push(loaded);
|
|
289
483
|
}
|
|
290
|
-
const discovered = candidates.
|
|
484
|
+
const discovered = [...candidates, ...discoveryFailures].sort((a, b) =>
|
|
485
|
+
a.path < b.path ? -1 : a.path > b.path ? 1 : 0,
|
|
486
|
+
);
|
|
487
|
+
if (discovered.length === 0) discovered.push(direct);
|
|
291
488
|
const ids = new Map<string, ExtensionCandidate[]>();
|
|
292
489
|
for (const candidate of discovered) {
|
|
293
490
|
const id = candidate.manifest?.id;
|
|
@@ -9,11 +9,76 @@ import {
|
|
|
9
9
|
listInstalledExtensions,
|
|
10
10
|
removeExtension,
|
|
11
11
|
} from "./manager.js";
|
|
12
|
+
import {
|
|
13
|
+
type BuildExtensionSnapshotInput,
|
|
14
|
+
buildExtensionSnapshot,
|
|
15
|
+
diffExtensionSnapshots,
|
|
16
|
+
EXTENSION_SNAPSHOT_DIAGNOSTIC_MESSAGE_CAP,
|
|
17
|
+
} from "./snapshot.js";
|
|
18
|
+
import { bindExtensionSnapshotStore, createExtensionSnapshotStore } from "./snapshot-store.js";
|
|
19
|
+
import type {
|
|
20
|
+
ExtensionReloadCandidate,
|
|
21
|
+
ExtensionReloadRejection,
|
|
22
|
+
ExtensionReloadRejectionReason,
|
|
23
|
+
ExtensionSnapshotDiagnostics,
|
|
24
|
+
} from "./types.js";
|
|
25
|
+
|
|
26
|
+
/** Test seams only; the domain loader constructs the bundle with defaults. */
|
|
27
|
+
export interface ExtensionsBundleOptions {
|
|
28
|
+
cwd?: () => string;
|
|
29
|
+
now?: BuildExtensionSnapshotInput["now"];
|
|
30
|
+
listRecords?: BuildExtensionSnapshotInput["listRecords"];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function failureDiagnostics(error: unknown): ExtensionSnapshotDiagnostics {
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35
|
+
return {
|
|
36
|
+
entries: [{ type: "error", message: message.slice(0, EXTENSION_SNAPSHOT_DIAGNOSTIC_MESSAGE_CAP) }],
|
|
37
|
+
truncated: 0,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function createExtensionsBundle(
|
|
42
|
+
_context: DomainContext,
|
|
43
|
+
options: ExtensionsBundleOptions = {},
|
|
44
|
+
): DomainBundle<ExtensionsContract> {
|
|
45
|
+
const store = createExtensionSnapshotStore();
|
|
46
|
+
const cwd = options.cwd ?? (() => process.cwd());
|
|
47
|
+
const build = (generation: number) =>
|
|
48
|
+
buildExtensionSnapshot({
|
|
49
|
+
cwd: cwd(),
|
|
50
|
+
generation,
|
|
51
|
+
...(options.now !== undefined ? { now: options.now } : {}),
|
|
52
|
+
...(options.listRecords !== undefined ? { listRecords: options.listRecords } : {}),
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* The single prepared-but-unpublished candidate. Holding it here is what
|
|
56
|
+
* makes prepare reentrancy-safe and lets a candidate tell whether it is
|
|
57
|
+
* still the one in flight.
|
|
58
|
+
*/
|
|
59
|
+
let inFlight: ExtensionReloadCandidate | null = null;
|
|
60
|
+
|
|
61
|
+
const rejected = (
|
|
62
|
+
reason: ExtensionReloadRejectionReason,
|
|
63
|
+
diagnostics: ExtensionSnapshotDiagnostics,
|
|
64
|
+
): ExtensionReloadRejection => ({
|
|
65
|
+
status: "rejected",
|
|
66
|
+
reason,
|
|
67
|
+
generation: store.current()?.generation ?? 0,
|
|
68
|
+
diagnostics,
|
|
69
|
+
});
|
|
12
70
|
|
|
13
|
-
export function createExtensionsBundle(_context: DomainContext): DomainBundle<ExtensionsContract> {
|
|
14
71
|
const extension: DomainExtension = {
|
|
15
72
|
start() {
|
|
16
|
-
|
|
73
|
+
// Bind an empty store only. Until the composition root publishes the
|
|
74
|
+
// boot generation together with its user hooks, every reader takes
|
|
75
|
+
// the ephemeral generation-0 path, so no consumer can observe
|
|
76
|
+
// extension resources paired with hooks from another generation.
|
|
77
|
+
bindExtensionSnapshotStore(store);
|
|
78
|
+
},
|
|
79
|
+
stop() {
|
|
80
|
+
inFlight = null;
|
|
81
|
+
bindExtensionSnapshotStore(null);
|
|
17
82
|
},
|
|
18
83
|
};
|
|
19
84
|
const contract: ExtensionsContract = {
|
|
@@ -35,11 +100,45 @@ export function createExtensionsBundle(_context: DomainContext): DomainBundle<Ex
|
|
|
35
100
|
remove(id, options = {}) {
|
|
36
101
|
return removeExtension(id, options);
|
|
37
102
|
},
|
|
38
|
-
resourceRoots(kind,
|
|
39
|
-
return enabledExtensionResourceRoots(kind, cwd);
|
|
103
|
+
resourceRoots(kind, requestedCwd) {
|
|
104
|
+
return enabledExtensionResourceRoots(kind, requestedCwd ?? cwd());
|
|
105
|
+
},
|
|
106
|
+
snapshot() {
|
|
107
|
+
return store.current();
|
|
108
|
+
},
|
|
109
|
+
generation() {
|
|
110
|
+
return store.current()?.generation ?? 0;
|
|
40
111
|
},
|
|
41
|
-
|
|
42
|
-
return
|
|
112
|
+
prepareReload() {
|
|
113
|
+
if (inFlight !== null) return rejected("reentrant", { entries: [], truncated: 0 });
|
|
114
|
+
const previous = store.current();
|
|
115
|
+
// Reserve before building so a discarded candidate burns its number
|
|
116
|
+
// and generations stay strictly monotonic without a second counter.
|
|
117
|
+
const generation = store.nextGeneration();
|
|
118
|
+
let snapshot: ReturnType<typeof build>;
|
|
119
|
+
try {
|
|
120
|
+
snapshot = build(generation);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return rejected("build-failed", failureDiagnostics(error));
|
|
123
|
+
}
|
|
124
|
+
const candidate: ExtensionReloadCandidate = {
|
|
125
|
+
generation,
|
|
126
|
+
previousGeneration: previous?.generation ?? 0,
|
|
127
|
+
snapshot,
|
|
128
|
+
...diffExtensionSnapshots(previous, snapshot),
|
|
129
|
+
// Identity on the committed reference covers every intervening
|
|
130
|
+
// publish; the in-flight check covers discard and double publish.
|
|
131
|
+
current: () => inFlight === candidate && store.current() === previous,
|
|
132
|
+
publish() {
|
|
133
|
+
store.publish(snapshot);
|
|
134
|
+
inFlight = null;
|
|
135
|
+
},
|
|
136
|
+
discard() {
|
|
137
|
+
if (inFlight === candidate) inFlight = null;
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
inFlight = candidate;
|
|
141
|
+
return { status: "prepared", candidate };
|
|
43
142
|
},
|
|
44
143
|
};
|
|
45
144
|
return { extension, contract };
|
|
@@ -15,20 +15,44 @@ export {
|
|
|
15
15
|
discoverExtensionPackages,
|
|
16
16
|
type ExtensionCandidate,
|
|
17
17
|
type ExtensionDiagnostic,
|
|
18
|
+
type ExtensionHookSource,
|
|
18
19
|
type ExtensionInstallOptions,
|
|
19
20
|
type ExtensionInstallResult,
|
|
20
21
|
type ExtensionListOptions,
|
|
21
22
|
type ExtensionMutationResult,
|
|
23
|
+
type ExtensionProvenance,
|
|
24
|
+
type ExtensionReloadCandidate,
|
|
25
|
+
type ExtensionReloadCommitted,
|
|
26
|
+
type ExtensionReloadPrepareResult,
|
|
27
|
+
type ExtensionReloadRejection,
|
|
28
|
+
type ExtensionReloadRejectionReason,
|
|
29
|
+
type ExtensionReloadResult,
|
|
22
30
|
type ExtensionResourceKind,
|
|
23
31
|
type ExtensionResourceRoot,
|
|
24
32
|
type ExtensionScope,
|
|
33
|
+
type ExtensionSnapshot,
|
|
34
|
+
type ExtensionSnapshotDiagnostics,
|
|
35
|
+
type ExtensionStateUpgradeReport,
|
|
25
36
|
enabledExtensionResourceRoots,
|
|
26
37
|
enableExtension,
|
|
27
38
|
extensionManifestYaml,
|
|
39
|
+
extensionSnapshotFor,
|
|
28
40
|
type InstalledExtension,
|
|
41
|
+
type InstalledExtensionRecord,
|
|
29
42
|
installExtension,
|
|
43
|
+
isLoadableExtension,
|
|
44
|
+
type LoadableExtension,
|
|
45
|
+
listInstalledExtensionRecords,
|
|
30
46
|
listInstalledExtensions,
|
|
31
47
|
parseExtensionManifest,
|
|
32
48
|
removeExtension,
|
|
49
|
+
upgradeLegacyExtensionInstallState,
|
|
33
50
|
} from "./manager.js";
|
|
34
51
|
export { ExtensionsManifest } from "./manifest.js";
|
|
52
|
+
export {
|
|
53
|
+
buildExtensionSnapshot,
|
|
54
|
+
diffExtensionSnapshots,
|
|
55
|
+
EXTENSION_SNAPSHOT_DIAGNOSTIC_CAP,
|
|
56
|
+
EXTENSION_SNAPSHOT_DIAGNOSTIC_MESSAGE_CAP,
|
|
57
|
+
EXTENSION_SNAPSHOT_DIAGNOSTIC_PER_PACKAGE_CAP,
|
|
58
|
+
} from "./snapshot.js";
|