@iowarp/clio-coder 0.3.6 → 0.3.8
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 +59 -0
- package/README.md +22 -6
- package/dist/{acp-2BEHC4DL.js → acp-U67UHUK2.js} +14 -14
- package/dist/{agents-LNNFTM53.js → agents-YU6SGALZ.js} +42 -35
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-KXXFI2VS.js → auth-5ZPJOIVG.js} +32 -24
- package/dist/builtins-C6JMZVV6.js +17 -0
- package/dist/{chunk-E25LMLRW.js → chunk-26LEYJZH.js} +2 -2
- package/dist/{chunk-TSHXZTOQ.js → chunk-2HEJ2F35.js} +5 -5
- package/dist/{chunk-PBTHKCPN.js → chunk-2HFZQUHL.js} +7 -7
- package/dist/{chunk-FO5ZOVUY.js → chunk-3BINW3FP.js} +5 -5
- package/dist/{chunk-4OC57DA6.js → chunk-4DGYLA73.js} +53 -2
- package/dist/{chunk-CKXWIANG.js → chunk-4SPRNWDE.js} +18 -16
- package/dist/{chunk-E2ER4LJF.js → chunk-5C3AQNDW.js} +25 -1
- package/dist/{chunk-XF5N4U5A.js → chunk-5DHKRSMQ.js} +9 -8
- package/dist/{chunk-43AOLP7E.js → chunk-5FR74PWO.js} +2 -1
- package/dist/{chunk-EKY57CSP.js → chunk-5H3GB5BO.js} +68 -772
- package/dist/{chunk-6XXKFVSN.js → chunk-5Q2VVUKB.js} +4 -4
- package/dist/{chunk-DJVECN66.js → chunk-7RFXX52T.js} +295 -3705
- package/dist/{chunk-ZXF4XRKW.js → chunk-7RGZWPB6.js} +158 -8
- package/dist/{chunk-FYYLNIL5.js → chunk-A2NJGIB3.js} +2 -2
- package/dist/{chunk-XXQNGV4M.js → chunk-A3WNZD3P.js} +548 -72
- package/dist/{chunk-VEZEGCGW.js → chunk-B5CSFE7B.js} +23 -21
- package/dist/{chunk-2SFS6XQE.js → chunk-DGSYXYMX.js} +3 -2
- package/dist/chunk-DR52UMZW.js +21 -0
- package/dist/{chunk-ZWLZP4ZT.js → chunk-DYIM5TJT.js} +98 -12
- package/dist/{chunk-QKMUKYO7.js → chunk-E77JEWSD.js} +270 -125
- package/dist/{chunk-LYF7OHWH.js → chunk-EMYUUSFG.js} +12 -467
- package/dist/{chunk-4VP4KH3K.js → chunk-EQ63NRB7.js} +8 -8
- package/dist/chunk-FBVTI2TJ.js +518 -0
- package/dist/{chunk-R46L2BIR.js → chunk-FHJEP5SW.js} +19 -25
- package/dist/{chunk-WR67VIZY.js → chunk-GN57SG4G.js} +66 -8
- package/dist/{chunk-RD5U66HV.js → chunk-GPIEI3LY.js} +9 -9
- package/dist/{chunk-PCZJO5TI.js → chunk-GU2UIAFZ.js} +13 -178
- package/dist/chunk-GWS3VEIW.js +195 -0
- package/dist/chunk-H7IXIC72.js +103 -0
- package/dist/{chunk-3BPUFZDL.js → chunk-HLE42MG7.js} +3 -3
- package/dist/{chunk-24I7BN55.js → chunk-IFBNV6H6.js} +3 -3
- package/dist/{chunk-QNQHSOLF.js → chunk-IGWKHNIQ.js} +114 -55
- package/dist/chunk-IIZWH4XA.js +172 -0
- package/dist/{chunk-AD2SYQYC.js → chunk-IJ7RPIYJ.js} +124 -6
- package/dist/chunk-J3YUBZWY.js +382 -0
- package/dist/{chunk-5JGRAMKL.js → chunk-JOZYP4GM.js} +8 -6
- package/dist/{chunk-OH3TOQTB.js → chunk-K4XHGFR5.js} +751 -15
- package/dist/{chunk-EYPA3EGJ.js → chunk-KTYTFRMB.js} +178 -14
- package/dist/chunk-LU7P4LHA.js +33 -0
- package/dist/chunk-ME6CCNFO.js +108 -0
- package/dist/chunk-MXKJU4JB.js +1100 -0
- package/dist/{chunk-RY3LY4J5.js → chunk-N22QMJKY.js} +21 -18
- package/dist/chunk-NMPKI6XL.js +3006 -0
- package/dist/chunk-NUGM5KR6.js +165 -0
- package/dist/{chunk-22NAGB7X.js → chunk-P43ETTHK.js} +5 -94
- package/dist/{chunk-NILBFAPG.js → chunk-PMDBGQSJ.js} +2 -2
- package/dist/chunk-PT7HYKEM.js +165 -0
- package/dist/chunk-RVG5JXAL.js +41 -0
- package/dist/{chunk-GEYXPTRF.js → chunk-RWSI4YD7.js} +2 -2
- package/dist/{chunk-4BPJXDWC.js → chunk-TANS5ZJS.js} +35 -19
- package/dist/{verifiers-NCBTHHN2.js → chunk-TB5666IT.js} +67 -324
- package/dist/{chunk-QM3F2GKX.js → chunk-TLQJPP24.js} +7927 -8088
- package/dist/{chunk-G7MUEIGA.js → chunk-TT36MB5S.js} +2 -1
- package/dist/chunk-TTHACPOM.js +961 -0
- package/dist/{chunk-6US73PDB.js → chunk-TYPGUK6W.js} +7 -7
- package/dist/{chunk-MFFY33HR.js → chunk-U6MBIEMB.js} +554 -209
- package/dist/chunk-VAWNZU7Z.js +242 -0
- package/dist/{chunk-IR4CFBFN.js → chunk-VCBR6CU7.js} +12 -12
- package/dist/{chunk-WHJYKASB.js → chunk-VHN4MY6O.js} +2 -2
- package/dist/{chunk-XYDYPRZI.js → chunk-VWZOAB7K.js} +10 -10
- package/dist/{chunk-ZRGEBJ4T.js → chunk-WLFILSD5.js} +48 -48
- package/dist/{chunk-K7T3E2SR.js → chunk-WNIJTQQK.js} +12 -11
- package/dist/{chunk-CYQKWTG3.js → chunk-WSB3FPX7.js} +68 -20
- package/dist/{chunk-KHSFENX2.js → chunk-WWCZ5F23.js} +116 -14
- package/dist/{chunk-XE2VEJHX.js → chunk-WXY7KU3G.js} +2 -2
- package/dist/{chunk-PPAMZ32Z.js → chunk-XK56QHLX.js} +6 -1
- package/dist/{chunk-KOHPCX4K.js → chunk-XWSF374K.js} +5 -5
- package/dist/{chunk-CJUB2JJ2.js → chunk-YS5VLNH5.js} +10 -10
- package/dist/{chunk-ZZMN5OM4.js → chunk-ZNLWCMVZ.js} +2 -2
- package/dist/{chunk-WHGPSPT5.js → chunk-ZVJ5BLO2.js} +2 -2
- package/dist/cli/index.js +33 -31
- package/dist/{clio-M2KGYUFZ.js → clio-QVTYJ57A.js} +10 -10
- package/dist/{code-nav-GQNL7XA6.js → code-nav-FGGFIE7L.js} +5 -5
- package/dist/codewiki/build-worker.js +4 -4
- package/dist/{components-5TTYYX6G.js → components-ZFA3SAER.js} +9 -9
- package/dist/{config-XUUYQIWO.js → config-LW5IJFQN.js} +65 -55
- package/dist/{configure-IHJ7YOMV.js → configure-7XIZCOU4.js} +29 -24
- package/dist/{context-75MIWW3U.js → context-L3WL3X7K.js} +54 -43
- package/dist/{context-ZQ7SIFJV.js → context-N52ZA626.js} +30 -14
- package/dist/{context-74JLXAWD.js → context-Y6Y7QPR6.js} +12 -12
- package/dist/{context-clear-GYKWNUML.js → context-clear-MBQRLSDQ.js} +54 -43
- package/dist/{context-index-SSR5ECNE.js → context-index-HVMFQHK3.js} +5 -5
- package/dist/{context-working-set-UX5KEP4J.js → context-working-set-GS6DSO7F.js} +18 -18
- package/dist/{dispatch-runner-GIJBHNFL.js → dispatch-runner-22ZCNOM3.js} +367 -79
- package/dist/{docs-6FZSCG5B.js → docs-7LQ23DLM.js} +9 -9
- package/dist/{doctor-SVJ5BZCW.js → doctor-M7YEDGAE.js} +27 -23
- package/dist/{eval-CG6LLBLD.js → eval-BEC2WHDA.js} +73 -20
- package/dist/{evidence-ZYFIEN42.js → evidence-REJUMSKM.js} +70 -59
- package/dist/{evolve-QGEXEMDW.js → evolve-PY5ZBA5K.js} +50 -39
- package/dist/{extensions-ADGNCJJD.js → extensions-HVKU65YU.js} +7 -7
- package/dist/{fleet-S5R4ZOQY.js → fleet-7WZEWRFA.js} +236 -377
- package/dist/fleet-commands-UVHWM76J.js +70 -0
- package/dist/fleet-graph-6ULH7PES.js +125 -0
- package/dist/fleet-new-RDVJLHHH.js +48 -0
- package/dist/{fleet-preflight-BHSNPBMH.js → fleet-preflight-J53T6CCE.js} +5 -5
- package/dist/fleet-validate-72PC4SLA.js +79 -0
- package/dist/{init-5DRU55YR.js → init-OG3TPGQG.js} +69 -57
- package/dist/library-CNTMPLRF.js +217 -0
- package/dist/{memory-7YKKR6UC.js → memory-6IS7F275.js} +52 -41
- package/dist/{models-ZPOLRU2C.js → models-ENRJDA5W.js} +37 -31
- package/dist/{monitor-US5F5YGZ.js → monitor-XLDVO7TN.js} +79 -42
- package/dist/{orchestrator-E2AL4T5N.js → orchestrator-6KSPYRHA.js} +4126 -762
- package/dist/{paths-E7KYAQWE.js → paths-DBXMZMDU.js} +6 -6
- package/dist/registry-LG64LTF4.js +11 -0
- package/dist/{reset-KZ652EK6.js → reset-RZ4ER727.js} +12 -12
- package/dist/{run-SRNBKDWD.js → run-Y2CNK5RU.js} +89 -76
- package/dist/{share-CGZE33UP.js → share-A55GYP6Z.js} +37 -13
- package/dist/{skills-S2X4DLY5.js → skills-ALC5J6AT.js} +29 -13
- package/dist/{skills-eval-W2GGIC4R.js → skills-eval-JPBEBYQU.js} +60 -48
- package/dist/support-MIETYA5E.js +38 -0
- package/dist/{targets-54SWINWB.js → targets-VGNXIR3S.js} +46 -36
- package/dist/{terminal-lease-SAIF2OGY.js → terminal-lease-WOBR64YA.js} +4 -4
- package/dist/{uninstall-BVLWXKBT.js → uninstall-ZJF5H5ZN.js} +9 -9
- package/dist/{upgrade-JKAR27XC.js → upgrade-FUSUAGHR.js} +31 -28
- package/dist/{usage-MSAWCLX4.js → usage-N4MKVHKD.js} +140 -68
- package/dist/verifiers-YAWOJ3H2.js +336 -0
- package/dist/{verify-X5HDROLA.js → verify-LTDHYBGY.js} +10 -9
- package/dist/{wiki-generate-GUSOQ6ZP.js → wiki-generate-6M7GHTBJ.js} +75 -62
- package/dist/worker/entry.js +67 -57
- package/docs/README.md +3 -2
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +11 -6
- package/docs/built-in-agents.md +26 -2
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +83 -3
- package/docs/configuration-and-targets.md +86 -4
- package/docs/context-engine.md +1 -1
- package/docs/development-pipeline.md +1 -1
- package/docs/dispatch-architecture-rationale.md +1 -1
- package/docs/documentation-coverage.md +3 -3
- package/docs/documentation-guide.md +3 -3
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +74 -10
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +4 -1
- package/docs/extensions-and-sharing.md +6 -2
- package/docs/fleet-demo-runbook.md +2 -2
- package/docs/fleet-dispatch.md +228 -16
- package/docs/git-commit-provenance.md +2 -2
- package/docs/glossary.md +22 -2
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +2 -1
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +56 -9
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +4 -2
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +83 -65
- package/docs/resource-library.md +59 -0
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +37 -1
- package/docs/skills-marketplace.md +16 -3
- package/docs/tool-usage.md +14 -7
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +3 -3
- package/package.json +1 -2
- package/src/cli/argv.ts +5 -0
- package/src/cli/configure.ts +107 -23
- package/src/cli/doctor.ts +5 -1
- package/src/cli/evidence.ts +30 -25
- package/src/cli/fleet-commands.ts +37 -0
- package/src/cli/fleet-graph.ts +102 -0
- package/src/cli/fleet-new.ts +36 -0
- package/src/cli/fleet-preflight.ts +111 -0
- package/src/cli/fleet-validate.ts +30 -0
- package/src/cli/fleet.ts +173 -335
- package/src/cli/index.ts +3 -1
- package/src/cli/library.ts +190 -0
- package/src/cli/share.ts +13 -1
- package/src/cli/shared.ts +1 -0
- package/src/cli/targets.ts +4 -1
- package/src/cli/usage.ts +111 -19
- package/src/cli/validate-model.ts +60 -5
- package/src/core/bus-events.ts +29 -0
- package/src/core/commit-attribution.ts +4 -4
- package/src/core/config.ts +130 -0
- package/src/core/defaults.ts +81 -0
- package/src/core/path-boundary.ts +100 -0
- package/src/domains/agents/builtins/architect.md +1 -0
- package/src/domains/agents/builtins/oracle.md +33 -0
- package/src/domains/agents/catalog.ts +13 -1
- package/src/domains/agents/extension.ts +2 -11
- package/src/domains/agents/fleet-contract.ts +304 -24
- package/src/domains/agents/index.ts +14 -0
- package/src/domains/agents/recipe.ts +7 -1
- package/src/domains/agents/registry.ts +73 -5
- package/src/domains/agents/result-contract.ts +360 -15
- package/src/domains/agents/write-boundary.ts +15 -50
- package/src/domains/config/classify.ts +4 -0
- package/src/domains/context/project-rules.ts +51 -1
- package/src/domains/dispatch/active-route-planner.ts +14 -0
- package/src/domains/dispatch/assignment-reconcile.ts +22 -5
- package/src/domains/dispatch/assignment-store.ts +151 -14
- package/src/domains/dispatch/backoff.ts +2 -1
- package/src/domains/dispatch/capability-match.ts +1 -0
- package/src/domains/dispatch/checkout-writer-lease.ts +175 -0
- package/src/domains/dispatch/contract.ts +48 -0
- package/src/domains/dispatch/delegation-plan.ts +164 -0
- package/src/domains/dispatch/execution-plan.ts +76 -5
- package/src/domains/dispatch/execution-role.ts +12 -2
- package/src/domains/dispatch/execution-scheduler.ts +183 -67
- package/src/domains/dispatch/extension.ts +412 -74
- package/src/domains/dispatch/fleet-gate.ts +14 -0
- package/src/domains/dispatch/fleet-plan.ts +63 -3
- package/src/domains/dispatch/fleet-run.ts +791 -0
- package/src/domains/dispatch/gate-role-prompts.ts +47 -0
- package/src/domains/dispatch/host-verification.ts +178 -0
- package/src/domains/dispatch/index.ts +41 -1
- package/src/domains/dispatch/intent-requirements.ts +40 -0
- package/src/domains/dispatch/intent.ts +235 -0
- package/src/domains/dispatch/path-scope.ts +370 -0
- package/src/domains/dispatch/receipt-integrity.ts +9 -4
- package/src/domains/dispatch/state.ts +36 -3
- package/src/domains/dispatch/types.ts +64 -12
- package/src/domains/dispatch/validation.ts +69 -6
- package/src/domains/dispatch/write-boundary-enforcer.ts +45 -0
- package/src/domains/dispatch/write-boundary.ts +201 -22
- package/src/domains/eval/metrics/evidence.ts +79 -2
- package/src/domains/eval/runners/clio-run.ts +12 -2
- package/src/domains/evidence/build.ts +69 -11
- package/src/domains/evidence/index.ts +21 -0
- package/src/domains/evidence/provenance.ts +46 -11
- package/src/domains/evidence/trust-projection.ts +274 -0
- package/src/domains/evidence/trust-status.ts +155 -18
- package/src/domains/evidence/types.ts +4 -0
- package/src/domains/extensions/discovery.ts +88 -1
- package/src/domains/extensions/resources.ts +20 -8
- package/src/domains/extensions/state.ts +6 -2
- package/src/domains/extensions/types.ts +4 -1
- package/src/domains/lifecycle/doctor.ts +140 -1
- package/src/domains/middleware/index.ts +15 -0
- package/src/domains/middleware/watchdog.ts +281 -0
- package/src/domains/observability/contract.ts +3 -1
- package/src/domains/observability/cost.ts +12 -1
- package/src/domains/observability/extension.ts +2 -2
- package/src/domains/observability/index.ts +10 -0
- package/src/domains/observability/out-of-turn-usage.ts +223 -0
- package/src/domains/prompts/contract.ts +3 -5
- package/src/domains/providers/extension.ts +30 -2
- package/src/domains/resources/common-loader.ts +3 -0
- package/src/domains/resources/index.ts +20 -0
- package/src/domains/resources/library.ts +326 -0
- package/src/domains/resources/prompts/loader.ts +119 -14
- package/src/domains/resources/skills/marketplace.ts +37 -12
- package/src/domains/safety/policy-engine.ts +5 -5
- package/src/domains/safety/run-effects.ts +64 -1
- package/src/domains/safety/scope.ts +7 -12
- package/src/domains/session/handoff.ts +629 -0
- package/src/domains/share/archive.ts +67 -2
- package/src/engine/acp/server.ts +4 -1
- package/src/engine/prompt-templates.ts +18 -1
- package/src/engine/worker-runtime.ts +6 -3
- package/src/entry/orchestrator.ts +37 -0
- package/src/interactive/bus-notices.ts +26 -0
- package/src/interactive/chat-loop.ts +235 -1
- package/src/interactive/chat-renderer.ts +22 -0
- package/src/interactive/cost-overlay.ts +31 -3
- package/src/interactive/council-dispatch.ts +30 -0
- package/src/interactive/council-grid.ts +213 -0
- package/src/interactive/council.ts +99 -0
- package/src/interactive/dispatch-board.ts +311 -17
- package/src/interactive/fleet-run-preview.ts +307 -0
- package/src/interactive/footer/notifications.ts +219 -0
- package/src/interactive/handoff-round.ts +56 -0
- package/src/interactive/interactive-application.ts +43 -1
- package/src/interactive/interactive-event-projection.ts +23 -1
- package/src/interactive/interactive-slash-runtime.ts +52 -2
- package/src/interactive/interactive-subscriptions.ts +14 -2
- package/src/interactive/oracle.ts +179 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +6 -0
- package/src/interactive/overlay-general-openers.ts +190 -1
- package/src/interactive/overlay-key-routing.ts +17 -1
- package/src/interactive/overlay-lifecycle.ts +41 -1
- package/src/interactive/overlay-permission-lifecycle.ts +10 -0
- package/src/interactive/overlay-resource-openers.ts +11 -3
- package/src/interactive/overlay-session-lifecycle.ts +234 -2
- package/src/interactive/overlays/fleet-run-approval.ts +208 -0
- package/src/interactive/overlays/handoff-review.ts +185 -0
- package/src/interactive/overlays/library-install-confirm.ts +151 -0
- package/src/interactive/overlays/list-overlay.ts +168 -2
- package/src/interactive/overlays/settings.ts +221 -30
- package/src/interactive/overlays/side-question.ts +139 -0
- package/src/interactive/overlays/skills-hub.ts +401 -15
- package/src/interactive/side-question.ts +171 -0
- package/src/interactive/slash-commands.ts +439 -7
- package/src/interactive/slash-spec.ts +19 -6
- package/src/interactive/theme/tokens.ts +30 -0
- package/src/interactive/turn-middleware.ts +15 -1
- package/src/interactive/view/artifacts.ts +42 -9
- package/src/interactive/view/view-overlay.ts +15 -3
- package/src/interactive/watchdog-run.ts +75 -0
- package/src/interactive/worker-receipts.ts +14 -2
- package/src/interactive/worker-share.ts +56 -1
- package/src/interactive/worker-stream.ts +15 -0
- package/src/tools/bootstrap.ts +3 -0
- package/src/tools/compete-worktrees.ts +13 -79
- package/src/tools/dispatch-admission.ts +251 -18
- package/src/tools/dispatch-arguments.ts +84 -1
- package/src/tools/dispatch-plan.ts +165 -6
- package/src/tools/dispatch-runner.ts +364 -23
- package/src/tools/dispatch-types.ts +20 -1
- package/src/tools/dispatch.ts +72 -2
- package/src/tools/monitor.ts +29 -0
- package/src/tools/profiles.ts +18 -4
- package/src/tools/task-worktree.ts +238 -0
- package/src/tools/verify/authoring.ts +61 -1
- package/src/tools/verify/scripts.ts +62 -0
- package/src/tools/worker-evidence.ts +21 -14
- package/src/worker/spec-contract.ts +3 -1
- package/dist/chunk-HC4CLZ2Y.js +0 -68
package/src/cli/index.ts
CHANGED
|
@@ -57,7 +57,7 @@ Usage:
|
|
|
57
57
|
clio-coder uninstall remove all Clio Coder state; --remove-binary also unlinks the launcher
|
|
58
58
|
clio-coder upgrade upgrade Clio Coder and run pending migrations
|
|
59
59
|
clio-coder agents list discovered agent recipes
|
|
60
|
-
clio-coder fleet
|
|
60
|
+
clio-coder fleet new|validate|graph|commands|run|status|drain|resume fleet authoring, execution, status, and admission control
|
|
61
61
|
clio-coder evidence build, list, or inspect evidence artifacts
|
|
62
62
|
clio-coder eval run, report, or compare local eval task files
|
|
63
63
|
clio-coder memory list, propose, promote, approve, reject, or prune memory
|
|
@@ -65,6 +65,7 @@ Usage:
|
|
|
65
65
|
clio-coder trace query or view the durable dispatch trace mirror
|
|
66
66
|
clio-coder extensions install, list, enable, disable, or remove extension packages
|
|
67
67
|
clio-coder skills list, inspect, validate, or install skills
|
|
68
|
+
clio-coder library list, search, add, or sync agents, prompts, fleets, and skills from catalogs
|
|
68
69
|
clio-coder verifiers discover, author, validate, edit, or dry-run project checks
|
|
69
70
|
clio-coder docs [topic] serve the HTML docs of a source checkout on 127.0.0.1 (--no-open to skip browser)
|
|
70
71
|
clio-coder dev <command> harness instruments; run 'clio-coder dev' for the list
|
|
@@ -246,6 +247,7 @@ const COMMAND_HANDLERS = new Map<string, CommandHandler>([
|
|
|
246
247
|
["ext", extensionsCommand],
|
|
247
248
|
["fleet", async (subArgs) => (await import("./fleet.js")).runFleetCommand(subArgs)],
|
|
248
249
|
["skills", async (subArgs) => (await import("./skills.js")).runSkillsCommand(subArgs)],
|
|
250
|
+
["library", async (subArgs) => (await import("./library.js")).runLibraryCommand(subArgs)],
|
|
249
251
|
["verifiers", async (subArgs) => (await import("./verifiers.js")).runVerifiersCommand(subArgs)],
|
|
250
252
|
["docs", async (subArgs) => (await import("./docs.js")).runDocsCommand(subArgs)],
|
|
251
253
|
["share", async (subArgs) => (await import("./share.js")).runShareCommand(subArgs)],
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import {
|
|
2
|
+
classifyLibraryRequirements,
|
|
3
|
+
confirmLibraryRemote,
|
|
4
|
+
discoverLibrary,
|
|
5
|
+
installLibraryPlan,
|
|
6
|
+
type LibraryEntry,
|
|
7
|
+
type LibraryEntryKind,
|
|
8
|
+
libraryEntryRef,
|
|
9
|
+
libraryInstallPath,
|
|
10
|
+
planLibraryInstall,
|
|
11
|
+
syncLibrary,
|
|
12
|
+
} from "../domains/resources/index.js";
|
|
13
|
+
import { printError, printOk } from "./shared.js";
|
|
14
|
+
|
|
15
|
+
const KINDS = new Set<LibraryEntryKind>(["skill", "agent", "prompt", "fleet"]);
|
|
16
|
+
const HELP = `clio-coder library <command>
|
|
17
|
+
|
|
18
|
+
Commands:
|
|
19
|
+
clio-coder library list [--kind <kind>] [--json]
|
|
20
|
+
clio-coder library search <query> [--kind <kind>] [--json]
|
|
21
|
+
clio-coder library add <ref> [--from <catalog|path>] [--with-requirements] [--yes] [--json]
|
|
22
|
+
clio-coder library use <kind> <name>
|
|
23
|
+
clio-coder library sync
|
|
24
|
+
clio-coder library push
|
|
25
|
+
clio-coder library remote confirm <url>
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
interface Parsed {
|
|
29
|
+
command?: string;
|
|
30
|
+
positional: string[];
|
|
31
|
+
kind?: LibraryEntryKind;
|
|
32
|
+
from?: string;
|
|
33
|
+
json: boolean;
|
|
34
|
+
yes: boolean;
|
|
35
|
+
withRequirements: boolean;
|
|
36
|
+
help: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parse(argv: ReadonlyArray<string>): Parsed {
|
|
40
|
+
const out: Parsed = { positional: [], json: false, yes: false, withRequirements: false, help: false };
|
|
41
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
42
|
+
const arg = argv[i];
|
|
43
|
+
if (!arg) continue;
|
|
44
|
+
if (!out.command && !arg.startsWith("-")) {
|
|
45
|
+
out.command = arg;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (arg === "--json") out.json = true;
|
|
49
|
+
else if (arg === "--yes") out.yes = true;
|
|
50
|
+
else if (arg === "--with-requirements") out.withRequirements = true;
|
|
51
|
+
else if (arg === "--help" || arg === "-h") out.help = true;
|
|
52
|
+
else if (arg === "--kind") {
|
|
53
|
+
const value = argv[++i];
|
|
54
|
+
if (!value || !KINDS.has(value as LibraryEntryKind))
|
|
55
|
+
throw new Error("--kind requires skill, agent, prompt, or fleet");
|
|
56
|
+
out.kind = value as LibraryEntryKind;
|
|
57
|
+
} else if (arg === "--from") {
|
|
58
|
+
const value = argv[++i];
|
|
59
|
+
if (!value) throw new Error("--from requires a value");
|
|
60
|
+
out.from = value;
|
|
61
|
+
} else if (arg.startsWith("-")) throw new Error(`unknown flag: ${arg}`);
|
|
62
|
+
else out.positional.push(arg);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function selectEntry(entries: ReadonlyArray<LibraryEntry>, ref: string): LibraryEntry {
|
|
68
|
+
const matches = ref.includes(":")
|
|
69
|
+
? entries.filter((entry) => libraryEntryRef(entry) === ref)
|
|
70
|
+
: entries.filter((entry) => entry.name === ref);
|
|
71
|
+
if (matches.length === 0) throw new Error(`library entry not found: ${ref}`);
|
|
72
|
+
if (matches.length > 1)
|
|
73
|
+
throw new Error(`library entry is ambiguous; use a typed reference: ${matches.map(libraryEntryRef).join(", ")}`);
|
|
74
|
+
return matches[0] as LibraryEntry;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function filtered(entries: ReadonlyArray<LibraryEntry>, kind?: LibraryEntryKind): LibraryEntry[] {
|
|
78
|
+
return entries.filter((entry) => kind === undefined || entry.kind === kind);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function runLibraryCommand(argv: ReadonlyArray<string>): Promise<number> {
|
|
82
|
+
let parsed: Parsed;
|
|
83
|
+
try {
|
|
84
|
+
parsed = parse(argv);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
printError(error instanceof Error ? error.message : String(error));
|
|
87
|
+
return 2;
|
|
88
|
+
}
|
|
89
|
+
if (!parsed.command || parsed.help) {
|
|
90
|
+
process.stdout.write(HELP);
|
|
91
|
+
return parsed.help ? 0 : 2;
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
if (parsed.command === "list" || parsed.command === "search") {
|
|
95
|
+
const discovery = discoverLibrary();
|
|
96
|
+
const query = parsed.command === "search" ? parsed.positional.join(" ").trim().toLowerCase() : "";
|
|
97
|
+
if (parsed.command === "search" && !query) throw new Error("library search requires a query");
|
|
98
|
+
const entries = filtered(discovery.entries, parsed.kind).filter(
|
|
99
|
+
(entry) => !query || entry.name.toLowerCase().includes(query) || entry.description.toLowerCase().includes(query),
|
|
100
|
+
);
|
|
101
|
+
if (parsed.json)
|
|
102
|
+
process.stdout.write(`${JSON.stringify({ entries, diagnostics: discovery.diagnostics }, null, 2)}\n`);
|
|
103
|
+
else
|
|
104
|
+
for (const entry of entries) process.stdout.write(`${libraryEntryRef(entry).padEnd(28)} ${entry.description}\n`);
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
if (parsed.command === "add") {
|
|
108
|
+
const ref = parsed.positional[0];
|
|
109
|
+
if (!ref || parsed.positional.length !== 1) throw new Error("library add requires one reference");
|
|
110
|
+
const catalog = parsed.from && parsed.from !== "catalog" ? parsed.from : undefined;
|
|
111
|
+
const discovery = discoverLibrary(catalog ? { catalog } : {});
|
|
112
|
+
let entry: LibraryEntry;
|
|
113
|
+
try {
|
|
114
|
+
entry = selectEntry(discovery.entries, ref);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const refusal = ref.includes(":")
|
|
117
|
+
? discovery.refusals[ref]
|
|
118
|
+
: Object.entries(discovery.refusals).find(([key]) => key.endsWith(`:${ref}`))?.[1];
|
|
119
|
+
if (refusal) throw new Error(refusal);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
const requirements = classifyLibraryRequirements(entry, discovery.entries);
|
|
123
|
+
if (requirements.unsatisfied.length > 0 && !parsed.withRequirements) {
|
|
124
|
+
const refs = requirements.unsatisfied.map(libraryEntryRef);
|
|
125
|
+
if (parsed.json)
|
|
126
|
+
process.stdout.write(
|
|
127
|
+
`${JSON.stringify({ ok: false, entry: libraryEntryRef(entry), satisfiedRequirements: requirements.satisfied.map(libraryEntryRef), unresolvedRequirements: refs }, null, 2)}\n`,
|
|
128
|
+
);
|
|
129
|
+
else
|
|
130
|
+
process.stderr.write(
|
|
131
|
+
`satisfied requirements: ${requirements.satisfied.length > 0 ? requirements.satisfied.map(libraryEntryRef).join(", ") : "none"}\nunresolved requirements: ${refs.join(", ")}\npass --with-requirements to install them in dependency order\n`,
|
|
132
|
+
);
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
const plans = [...(parsed.withRequirements ? requirements.unsatisfied : []), entry].map(planLibraryInstall);
|
|
136
|
+
if (parsed.json)
|
|
137
|
+
process.stdout.write(
|
|
138
|
+
`${JSON.stringify({ ok: true, confirmed: parsed.yes, satisfiedRequirements: requirements.satisfied.map(libraryEntryRef), writes: plans.map((plan) => ({ ref: libraryEntryRef(plan.entry), path: plan.path, sha256: plan.sha256 })) }, null, 2)}\n`,
|
|
139
|
+
);
|
|
140
|
+
else {
|
|
141
|
+
process.stdout.write("library add plan:\n");
|
|
142
|
+
process.stdout.write(
|
|
143
|
+
` satisfied requirements: ${requirements.satisfied.length > 0 ? requirements.satisfied.map(libraryEntryRef).join(", ") : "none"}\n`,
|
|
144
|
+
);
|
|
145
|
+
for (const plan of plans)
|
|
146
|
+
process.stdout.write(` ${libraryEntryRef(plan.entry)} -> ${plan.path} sha256 ${plan.sha256}\n`);
|
|
147
|
+
}
|
|
148
|
+
if (!parsed.yes) return 0;
|
|
149
|
+
for (const plan of plans) installLibraryPlan(plan);
|
|
150
|
+
if (!parsed.json) printOk(`installed ${plans.length} library entry or entries`);
|
|
151
|
+
return 0;
|
|
152
|
+
}
|
|
153
|
+
if (parsed.command === "use") {
|
|
154
|
+
const kind = parsed.positional[0] as LibraryEntryKind | undefined;
|
|
155
|
+
const name = parsed.positional[1];
|
|
156
|
+
if (!kind || !KINDS.has(kind) || !name || parsed.positional.length !== 2)
|
|
157
|
+
throw new Error("library use requires a kind and name");
|
|
158
|
+
// A skill is loaded by the operator from the Skills Hub, never by a CLI
|
|
159
|
+
// verb, so the honest answer names where it lives and how to load it.
|
|
160
|
+
const output =
|
|
161
|
+
kind === "fleet"
|
|
162
|
+
? `clio-coder fleet run ${name}`
|
|
163
|
+
: kind === "agent"
|
|
164
|
+
? `/run ${name}`
|
|
165
|
+
: kind === "skill"
|
|
166
|
+
? `${libraryInstallPath({ kind, name })}\nload it from /skill in the TUI, or ask the model to call context(scope="skills")`
|
|
167
|
+
: name;
|
|
168
|
+
process.stdout.write(`${output}\n`);
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
if (parsed.command === "remote") {
|
|
172
|
+
if (parsed.positional[0] !== "confirm" || !parsed.positional[1] || parsed.positional.length !== 2)
|
|
173
|
+
throw new Error("library remote confirm requires a URL");
|
|
174
|
+
confirmLibraryRemote(parsed.positional[1]);
|
|
175
|
+
printOk("confirmed library remote");
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
if (parsed.command === "sync" || parsed.command === "push") {
|
|
179
|
+
await syncLibrary(parsed.command);
|
|
180
|
+
printOk(`library ${parsed.command} complete`);
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
throw new Error(`unknown library command: ${parsed.command}`);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
186
|
+
printError(message);
|
|
187
|
+
if (parsed.json) process.stdout.write(`${JSON.stringify({ ok: false, error: message }, null, 2)}\n`);
|
|
188
|
+
return 1;
|
|
189
|
+
}
|
|
190
|
+
}
|
package/src/cli/share.ts
CHANGED
|
@@ -15,7 +15,7 @@ const HELP = `clio-coder share <command>
|
|
|
15
15
|
Export and import portable Clio project/resource archives.
|
|
16
16
|
|
|
17
17
|
Commands:
|
|
18
|
-
clio-coder share export --out <path> [--project|--user|--both] [--context] [--prompts] [--skills] [--settings] [--extensions]
|
|
18
|
+
clio-coder share export --out <path> [--project|--user|--both] [--context] [--prompts] [--skills] [--agents] [--fleets] [--settings] [--extensions]
|
|
19
19
|
clio-coder share import <path> [--dry-run] [--force] [--project|--user] [--json]
|
|
20
20
|
clio-coder share inspect <path> [--json]
|
|
21
21
|
|
|
@@ -36,6 +36,8 @@ interface Parsed {
|
|
|
36
36
|
includeContext?: boolean;
|
|
37
37
|
includePrompts?: boolean;
|
|
38
38
|
includeSkills?: boolean;
|
|
39
|
+
includeAgents?: boolean;
|
|
40
|
+
includeFleets?: boolean;
|
|
39
41
|
includeSettings?: boolean;
|
|
40
42
|
includeExtensions?: boolean;
|
|
41
43
|
}
|
|
@@ -93,6 +95,12 @@ function parse(argv: ReadonlyArray<string>): Parsed | null {
|
|
|
93
95
|
case "--skills":
|
|
94
96
|
out.includeSkills = true;
|
|
95
97
|
break;
|
|
98
|
+
case "--agents":
|
|
99
|
+
out.includeAgents = true;
|
|
100
|
+
break;
|
|
101
|
+
case "--fleets":
|
|
102
|
+
out.includeFleets = true;
|
|
103
|
+
break;
|
|
96
104
|
case "--settings":
|
|
97
105
|
out.includeSettings = true;
|
|
98
106
|
break;
|
|
@@ -103,6 +111,8 @@ function parse(argv: ReadonlyArray<string>): Parsed | null {
|
|
|
103
111
|
out.includeContext = true;
|
|
104
112
|
out.includePrompts = true;
|
|
105
113
|
out.includeSkills = true;
|
|
114
|
+
out.includeAgents = true;
|
|
115
|
+
out.includeFleets = true;
|
|
106
116
|
out.includeSettings = true;
|
|
107
117
|
out.includeExtensions = true;
|
|
108
118
|
break;
|
|
@@ -152,6 +162,8 @@ function exportOptions(parsed: Parsed): ShareExportOptions {
|
|
|
152
162
|
...(parsed.includeContext !== undefined ? { includeContext: parsed.includeContext } : {}),
|
|
153
163
|
...(parsed.includePrompts !== undefined ? { includePrompts: parsed.includePrompts } : {}),
|
|
154
164
|
...(parsed.includeSkills !== undefined ? { includeSkills: parsed.includeSkills } : {}),
|
|
165
|
+
...(parsed.includeAgents !== undefined ? { includeAgents: parsed.includeAgents } : {}),
|
|
166
|
+
...(parsed.includeFleets !== undefined ? { includeFleets: parsed.includeFleets } : {}),
|
|
155
167
|
...(parsed.includeSettings !== undefined ? { includeSettings: parsed.includeSettings } : {}),
|
|
156
168
|
...(parsed.includeExtensions !== undefined ? { includeExtensions: parsed.includeExtensions } : {}),
|
|
157
169
|
};
|
package/src/cli/shared.ts
CHANGED
package/src/cli/targets.ts
CHANGED
|
@@ -953,7 +953,7 @@ function renderTable(providers: ProvidersContract, entries: ReadonlyArray<Target
|
|
|
953
953
|
}
|
|
954
954
|
}
|
|
955
955
|
|
|
956
|
-
function targetTableRow(providers: ProvidersContract, status: TargetStatus): TargetTableRow {
|
|
956
|
+
export function targetTableRow(providers: ProvidersContract, status: TargetStatus): TargetTableRow {
|
|
957
957
|
return {
|
|
958
958
|
id: status.target.id,
|
|
959
959
|
tier: statusTier(status),
|
|
@@ -1051,6 +1051,9 @@ function formatNotes(status: TargetStatus): string {
|
|
|
1051
1051
|
if (status.runtime?.auth === "claude-cli") parts.push("claude-cli");
|
|
1052
1052
|
if (status.capabilities.contextWindow > 0) parts.push(formatContextWindow(status));
|
|
1053
1053
|
if (!status.available && status.reason) parts.push(status.reason);
|
|
1054
|
+
// A reachable target that cannot serve its own default is degraded, and the
|
|
1055
|
+
// row has to say why or the model column reads as a model that works.
|
|
1056
|
+
if (status.health.status === "degraded" && status.health.lastError) parts.push(status.health.lastError);
|
|
1054
1057
|
const residency = residentModelsSummary(status.discoveredModelStates);
|
|
1055
1058
|
if (residency) parts.push(residency);
|
|
1056
1059
|
if (status.probeNotes && status.probeNotes.length > 0) parts.push(`note: ${status.probeNotes.join("; ")}`);
|
package/src/cli/usage.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { clioDataDir, clioStateDir } from "../core/xdg.js";
|
|
10
10
|
import { loadMemoryRecordsSync, type MemoryRecord } from "../domains/memory/index.js";
|
|
11
11
|
import { readEvidenceIndex } from "../domains/observability/evidence-index.js";
|
|
12
|
+
import { type OutOfTurnUsageRow, readOutOfTurnUsageRows } from "../domains/observability/out-of-turn-usage.js";
|
|
12
13
|
import { loadSkills } from "../domains/resources/index.js";
|
|
13
14
|
import {
|
|
14
15
|
type LedgerUsageCall,
|
|
@@ -23,9 +24,10 @@ import { formatColumns, printError } from "./shared.js";
|
|
|
23
24
|
const HELP = `clio-coder usage report [--repo <path>] [--days <n>] [--json]
|
|
24
25
|
|
|
25
26
|
Cross-session usage analyzer (experimental, read-only). Reads the local usage
|
|
26
|
-
archive (receipts, session ledgers,
|
|
27
|
-
and reports facts plus improvement opportunities,
|
|
28
|
-
counts. Nothing is written or stored; suggestions are
|
|
27
|
+
archive (receipts, session ledgers, the out-of-turn usage store, audit rows,
|
|
28
|
+
evidence index, memory store) and reports facts plus improvement opportunities,
|
|
29
|
+
every line citing ids and counts. Nothing is written or stored; suggestions are
|
|
30
|
+
printed only.
|
|
29
31
|
|
|
30
32
|
Flags:
|
|
31
33
|
--repo <path> restrict sessions (and runs via the run ledger) to one repo
|
|
@@ -98,6 +100,54 @@ function addResponseModelIdObservation(counts: ResponseModelIdObservationCounts,
|
|
|
98
100
|
addResponseModelIdObservationCount(counts, call.responseModelIdObservation, call.apiCalls ?? 1);
|
|
99
101
|
}
|
|
100
102
|
|
|
103
|
+
/**
|
|
104
|
+
* How the folded calls split between the session's own turns and the rounds
|
|
105
|
+
* that were billed beside it. A `/btw` side question and a `/handoff` round are
|
|
106
|
+
* real spend and belong in the token and cost totals, but neither is a turn:
|
|
107
|
+
* they never entered the session. `turns` therefore subtracts them from the
|
|
108
|
+
* folded row count, which is exactly what the `/cost` overlay does.
|
|
109
|
+
*/
|
|
110
|
+
interface CallOrigins {
|
|
111
|
+
rows: number;
|
|
112
|
+
sideQuestions: number;
|
|
113
|
+
handoffs: number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function emptyCallOrigins(): CallOrigins {
|
|
117
|
+
return { rows: 0, sideQuestions: 0, handoffs: 0 };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function turnsOf(origins: CallOrigins): number {
|
|
121
|
+
return origins.rows - origins.sideQuestions - origins.handoffs;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function hasLabelledCall(origins: CallOrigins): boolean {
|
|
125
|
+
return origins.sideQuestions > 0 || origins.handoffs > 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function addOutOfTurnRow(origins: CallOrigins, row: OutOfTurnUsageRow): void {
|
|
129
|
+
origins.rows += 1;
|
|
130
|
+
if (row.label === "side-question") origins.sideQuestions += 1;
|
|
131
|
+
else origins.handoffs += 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** The out-of-turn store keeps its own usage shape; fold it as one completed call. */
|
|
135
|
+
function outOfTurnUsageCall(row: OutOfTurnUsageRow): LedgerUsageCall {
|
|
136
|
+
return {
|
|
137
|
+
providerId: row.target,
|
|
138
|
+
attributedModelId: row.attributedModelId,
|
|
139
|
+
requestedModelId: row.attributedModelId,
|
|
140
|
+
responseModelIdObservation: { state: "not-observed" },
|
|
141
|
+
input: row.usage.input,
|
|
142
|
+
output: row.usage.output,
|
|
143
|
+
cacheRead: row.usage.cacheRead,
|
|
144
|
+
cacheWrite: row.usage.cacheWrite,
|
|
145
|
+
reasoningTokens: row.usage.reasoning,
|
|
146
|
+
totalTokens: row.usage.totalTokens,
|
|
147
|
+
costUsd: row.usage.costUsd,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
101
151
|
function addUsageCall(totals: UsageTotals, call: LedgerUsageCall): void {
|
|
102
152
|
totals.apiCalls += call.apiCalls ?? 1;
|
|
103
153
|
totals.input += call.input;
|
|
@@ -250,6 +300,13 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
250
300
|
(receipt) => repoRunIds === null || repoRunIds.has(receipt.runId),
|
|
251
301
|
);
|
|
252
302
|
const sessions = await readSessions(stateDir, windowStart, now, repoHash, diagnostics);
|
|
303
|
+
// Side questions and handoff rounds append nothing to the session ledger by
|
|
304
|
+
// design, so their spend lives in its own store and is folded in here.
|
|
305
|
+
const outOfTurn = readOutOfTurnUsageRows(stateDir);
|
|
306
|
+
for (const error of outOfTurn.errors) diagnostics.notes.push(error);
|
|
307
|
+
const outOfTurnRows = outOfTurn.rows.filter(
|
|
308
|
+
(row) => inWindow(row.timestamp, windowStart, now) && (repoHash === undefined || row.repoIdentity === repoHash),
|
|
309
|
+
);
|
|
253
310
|
const auditRows = await readAuditRows(stateDir);
|
|
254
311
|
diagnostics.malformedAuditRows = auditRows.errors.length;
|
|
255
312
|
const auditInWindow = auditRows.rows.filter((row) => row.ts !== null && inWindow(row.ts, windowStart, now));
|
|
@@ -345,23 +402,36 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
345
402
|
}
|
|
346
403
|
>();
|
|
347
404
|
const usageTotals = emptyUsageTotals();
|
|
405
|
+
const callOrigins = emptyCallOrigins();
|
|
406
|
+
const foldCall = (call: LedgerUsageCall): void => {
|
|
407
|
+
addUsageCall(usageTotals, call);
|
|
408
|
+
const key = `${call.providerId}::${call.attributedModelId}`;
|
|
409
|
+
const entry = usageByModel.get(key) ?? {
|
|
410
|
+
providerId: call.providerId,
|
|
411
|
+
attributedModelId: call.attributedModelId,
|
|
412
|
+
requestedModelIds: new Set<string>(),
|
|
413
|
+
responseModelIdObservationCounts: emptyResponseModelIdObservationCounts(),
|
|
414
|
+
totals: emptyUsageTotals(),
|
|
415
|
+
};
|
|
416
|
+
entry.requestedModelIds.add(call.requestedModelId);
|
|
417
|
+
addResponseModelIdObservation(entry.responseModelIdObservationCounts, call);
|
|
418
|
+
addUsageCall(entry.totals, call);
|
|
419
|
+
usageByModel.set(key, entry);
|
|
420
|
+
};
|
|
348
421
|
for (const session of sessions) {
|
|
349
422
|
for (const call of session.usageCalls) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const entry = usageByModel.get(key) ?? {
|
|
353
|
-
providerId: call.providerId,
|
|
354
|
-
attributedModelId: call.attributedModelId,
|
|
355
|
-
requestedModelIds: new Set<string>(),
|
|
356
|
-
responseModelIdObservationCounts: emptyResponseModelIdObservationCounts(),
|
|
357
|
-
totals: emptyUsageTotals(),
|
|
358
|
-
};
|
|
359
|
-
entry.requestedModelIds.add(call.requestedModelId);
|
|
360
|
-
addResponseModelIdObservation(entry.responseModelIdObservationCounts, call);
|
|
361
|
-
addUsageCall(entry.totals, call);
|
|
362
|
-
usageByModel.set(key, entry);
|
|
423
|
+
foldCall(call);
|
|
424
|
+
callOrigins.rows += 1;
|
|
363
425
|
}
|
|
364
426
|
}
|
|
427
|
+
for (const row of outOfTurnRows) {
|
|
428
|
+
foldCall(outOfTurnUsageCall(row));
|
|
429
|
+
addOutOfTurnRow(callOrigins, row);
|
|
430
|
+
}
|
|
431
|
+
// Token and cost facts need one of their two inputs on disk. A machine whose
|
|
432
|
+
// session store is gone can still have recorded out-of-turn spend, and
|
|
433
|
+
// dropping those rows would report money that was spent as nothing at all.
|
|
434
|
+
const usageMeasurable = presence.sessionsPresent || outOfTurnRows.length > 0;
|
|
365
435
|
const usageRows = [...usageByModel.values()].sort(
|
|
366
436
|
(a, b) => b.totals.totalTokens - a.totals.totalTokens || a.providerId.localeCompare(b.providerId),
|
|
367
437
|
);
|
|
@@ -443,8 +513,22 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
443
513
|
if (presence.receiptsPresent) emit({ kind: "fact", fact: "dispatch-runs", value: receipts.length });
|
|
444
514
|
else emit({ kind: "fact", fact: "receipt-store-missing", path: presence.receiptsPath });
|
|
445
515
|
emit({ kind: "fact", fact: "audit-tool-calls", value: auditToolCalls.length, blocked: auditBlocked.length });
|
|
446
|
-
if (
|
|
447
|
-
|
|
516
|
+
if (usageMeasurable) {
|
|
517
|
+
// The origin split is emitted only when something out of turn was
|
|
518
|
+
// recorded, so a report over an archive with no `/btw` or `/handoff`
|
|
519
|
+
// round in it stays byte-identical to what it printed before.
|
|
520
|
+
emit({
|
|
521
|
+
kind: "fact",
|
|
522
|
+
fact: "tokens",
|
|
523
|
+
...usageTotals,
|
|
524
|
+
...(hasLabelledCall(callOrigins)
|
|
525
|
+
? {
|
|
526
|
+
turns: turnsOf(callOrigins),
|
|
527
|
+
sideQuestions: callOrigins.sideQuestions,
|
|
528
|
+
handoffs: callOrigins.handoffs,
|
|
529
|
+
}
|
|
530
|
+
: {}),
|
|
531
|
+
});
|
|
448
532
|
for (const row of usageRows) {
|
|
449
533
|
emit({
|
|
450
534
|
kind: "fact",
|
|
@@ -505,10 +589,18 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
505
589
|
out(` receipt store missing at ${presence.receiptsPath}`);
|
|
506
590
|
}
|
|
507
591
|
out(` audited tool calls in window: ${auditToolCalls.length} (${auditBlocked.length} blocked/denied)`);
|
|
508
|
-
if (
|
|
592
|
+
if (usageMeasurable) {
|
|
509
593
|
out(
|
|
510
594
|
` tokens in window: ${usageTotals.totalTokens} over ${usageTotals.apiCalls} model calls (input ${usageTotals.input}, output ${usageTotals.output}, cache read ${usageTotals.cacheRead}, cache write ${usageTotals.cacheWrite}, reasoning ${usageTotals.reasoningTokens})`,
|
|
511
595
|
);
|
|
596
|
+
if (hasLabelledCall(callOrigins)) {
|
|
597
|
+
// Only printed when a labelled call is in the window. Over an archive
|
|
598
|
+
// with none, these three lines would say nothing the line above does
|
|
599
|
+
// not already say, and their absence keeps the older output intact.
|
|
600
|
+
out(` turns in window: ${turnsOf(callOrigins)}`);
|
|
601
|
+
if (callOrigins.sideQuestions > 0) out(` side questions in window: ${callOrigins.sideQuestions}`);
|
|
602
|
+
if (callOrigins.handoffs > 0) out(` handoffs in window: ${callOrigins.handoffs}`);
|
|
603
|
+
}
|
|
512
604
|
out(` provider-reported cost in window: $${usageTotals.costUsd.toFixed(4)}`);
|
|
513
605
|
}
|
|
514
606
|
if (usageRows.length > 0) {
|
|
@@ -1,7 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a target advertised when it was asked, for runtimes with no static
|
|
3
|
+
* catalog. `models` is the id list the probe returned and `resident` the
|
|
4
|
+
* subset the server reports as loaded, when it reports load state at all.
|
|
5
|
+
*/
|
|
6
|
+
export interface LiveModelInventory {
|
|
7
|
+
targetId: string;
|
|
8
|
+
url?: string | undefined;
|
|
9
|
+
models: ReadonlyArray<string>;
|
|
10
|
+
resident: ReadonlyArray<string>;
|
|
11
|
+
}
|
|
12
|
+
|
|
1
13
|
export interface ValidateModelInput {
|
|
2
14
|
runtimeId: string;
|
|
3
15
|
modelId: string;
|
|
4
16
|
knownModels: ReadonlyArray<string>;
|
|
17
|
+
/**
|
|
18
|
+
* The live list, when one was fetched. It is consulted only when the static
|
|
19
|
+
* catalog is empty, so the catalog stays the authority for cloud runtimes
|
|
20
|
+
* and the probe becomes the authority where there is nothing else.
|
|
21
|
+
*/
|
|
22
|
+
live?: LiveModelInventory | undefined;
|
|
5
23
|
force: boolean;
|
|
6
24
|
}
|
|
7
25
|
|
|
@@ -9,9 +27,30 @@ export type ValidateModelResult =
|
|
|
9
27
|
| { ok: true; warning?: string }
|
|
10
28
|
| { ok: false; reason: string; knownModels: ReadonlyArray<string> };
|
|
11
29
|
|
|
30
|
+
const SAMPLE_SIZE = 10;
|
|
31
|
+
|
|
32
|
+
function sample(models: ReadonlyArray<string>): string {
|
|
33
|
+
const shown = models.slice(0, SAMPLE_SIZE).join(", ");
|
|
34
|
+
return models.length > SAMPLE_SIZE ? `${shown}, …` : shown;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function describeLiveTarget(live: LiveModelInventory): string {
|
|
38
|
+
return live.url ? `target '${live.targetId}' at ${live.url}` : `target '${live.targetId}'`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The refusal `configure` prints for a model the live target does not advertise. */
|
|
42
|
+
export function formatUnadvertisedModelReason(modelId: string, live: LiveModelInventory): string {
|
|
43
|
+
const resident = live.resident.length > 0 ? live.resident.join(", ") : "none";
|
|
44
|
+
return (
|
|
45
|
+
`${describeLiveTarget(live)} does not advertise model '${modelId}'. ` +
|
|
46
|
+
`Advertised (${live.models.length}): ${sample(live.models)}. Resident instances: ${resident}. ` +
|
|
47
|
+
"Pass one of the advertised ids with --model, or --force to save a model the target cannot serve."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
12
51
|
export function validateModelChoice(input: ValidateModelInput): ValidateModelResult {
|
|
13
|
-
const { runtimeId, modelId, knownModels, force } = input;
|
|
14
|
-
if (knownModels.length === 0) return
|
|
52
|
+
const { runtimeId, modelId, knownModels, live, force } = input;
|
|
53
|
+
if (knownModels.length === 0) return validateAgainstLive(modelId, live, force);
|
|
15
54
|
if (knownModels.includes(modelId)) return { ok: true };
|
|
16
55
|
if (force) {
|
|
17
56
|
return {
|
|
@@ -19,10 +58,26 @@ export function validateModelChoice(input: ValidateModelInput): ValidateModelRes
|
|
|
19
58
|
warning: `model '${modelId}' not in ${runtimeId} catalog (use without --force to reject)`,
|
|
20
59
|
};
|
|
21
60
|
}
|
|
22
|
-
const sample = knownModels.slice(0, 10).join(", ");
|
|
23
61
|
return {
|
|
24
62
|
ok: false,
|
|
25
|
-
reason: `model '${modelId}' not in ${runtimeId} catalog. Known: ${sample}. Use --force to skip validation.`,
|
|
26
|
-
knownModels: knownModels.slice(0,
|
|
63
|
+
reason: `model '${modelId}' not in ${runtimeId} catalog. Known: ${sample(knownModels)}. Use --force to skip validation.`,
|
|
64
|
+
knownModels: knownModels.slice(0, SAMPLE_SIZE),
|
|
27
65
|
};
|
|
28
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* With no catalog, the live list is the only evidence there is. An empty
|
|
70
|
+
* catalog used to be an early `ok` on its own, which is how a placeholder id
|
|
71
|
+
* was written next to the very list that ruled it out.
|
|
72
|
+
*/
|
|
73
|
+
function validateAgainstLive(
|
|
74
|
+
modelId: string,
|
|
75
|
+
live: LiveModelInventory | undefined,
|
|
76
|
+
force: boolean,
|
|
77
|
+
): ValidateModelResult {
|
|
78
|
+
if (!live || live.models.length === 0) return { ok: true };
|
|
79
|
+
if (live.models.includes(modelId)) return { ok: true };
|
|
80
|
+
const reason = formatUnadvertisedModelReason(modelId, live);
|
|
81
|
+
if (force) return { ok: true, warning: `${reason.replace(/ Pass one of.*$/u, "")} Saved anyway because of --force.` };
|
|
82
|
+
return { ok: false, reason, knownModels: live.models.slice(0, SAMPLE_SIZE) };
|
|
83
|
+
}
|
package/src/core/bus-events.ts
CHANGED
|
@@ -51,6 +51,7 @@ export const BusChannels = {
|
|
|
51
51
|
ToolBudgetExceeded: "safety.toolBudgetExceeded",
|
|
52
52
|
ProviderHealth: "provider.health",
|
|
53
53
|
RuntimeNotice: "runtime.notice",
|
|
54
|
+
DispatchScopeNotice: "dispatch.scopeNotice",
|
|
54
55
|
DispatchEnqueued: "dispatch.enqueued",
|
|
55
56
|
DispatchStarted: "dispatch.started",
|
|
56
57
|
DispatchProgress: "dispatch.progress",
|
|
@@ -108,6 +109,29 @@ export interface ContextWarningPayload {
|
|
|
108
109
|
warning: string | null;
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
/** A dispatch path-scope decision that must remain visible in the operator transcript. */
|
|
113
|
+
export type DispatchScopeNoticePayload =
|
|
114
|
+
| {
|
|
115
|
+
code: "typed_scope_replaced_inferred_paths";
|
|
116
|
+
level: "warning";
|
|
117
|
+
agentId: string;
|
|
118
|
+
omittedPaths: ReadonlyArray<string>;
|
|
119
|
+
message: string;
|
|
120
|
+
}
|
|
121
|
+
| {
|
|
122
|
+
code: "legacy_scope_inferred" | "legacy_scope_empty";
|
|
123
|
+
level: "warning";
|
|
124
|
+
agentId: string;
|
|
125
|
+
paths: ReadonlyArray<{
|
|
126
|
+
path: string;
|
|
127
|
+
policy: "working-context" | "write-boundary";
|
|
128
|
+
provenance: "declared" | "derived" | "inferred";
|
|
129
|
+
source: "intent.read_roots" | "intent.write_roots" | "intent.relevant_paths" | "writeRoots" | "task" | "briefing";
|
|
130
|
+
confidence: "certain" | "high" | "medium" | "low";
|
|
131
|
+
}>;
|
|
132
|
+
message: string;
|
|
133
|
+
};
|
|
134
|
+
|
|
111
135
|
export type ContextActivityKind = "context-init" | "context-clear" | "context-refresh" | "context-wiki" | "compaction";
|
|
112
136
|
export type ContextActivityPhase = "scan" | "codewiki" | "generate" | "clio-md" | "state" | "done";
|
|
113
137
|
export type ContextActivityStatus = "started" | "running" | "completed" | "failed";
|
|
@@ -487,6 +511,8 @@ export interface DispatchRunIdentity {
|
|
|
487
511
|
node?: string | undefined;
|
|
488
512
|
/** Review/compete gate role and cycle, for fleet board badges. */
|
|
489
513
|
gate?: { role: string; cycle: number } | undefined;
|
|
514
|
+
/** Council group presentation data for the Fleet Runs board. */
|
|
515
|
+
council?: { group: string; label: string; color?: string; round: number } | undefined;
|
|
490
516
|
/** Dead-node failover hops recorded on this run's chain so far. */
|
|
491
517
|
rerouteCount?: number | undefined;
|
|
492
518
|
/** Model context window in tokens, for the per-worker context meter. */
|
|
@@ -572,6 +598,8 @@ export interface DispatchTerminalStats {
|
|
|
572
598
|
exitCode: number;
|
|
573
599
|
/** Honest activity record aggregated from the run's tool telemetry; null when the receipt predates it. */
|
|
574
600
|
toolActivity: ToolActivitySummary | null;
|
|
601
|
+
/** Host-run declared verification status when the request included checks. */
|
|
602
|
+
hostVerification?: "verified" | "rejected" | "skipped";
|
|
575
603
|
}
|
|
576
604
|
|
|
577
605
|
/** Published on {@link BusChannels.DispatchCompleted} when a run finalizes as succeeded. */
|
|
@@ -733,6 +761,7 @@ export type BusPayloadMap = {
|
|
|
733
761
|
[BusChannels.ToolBudgetExceeded]: ToolBudgetExceededPayload;
|
|
734
762
|
[BusChannels.ProviderHealth]: ProviderHealthPayload;
|
|
735
763
|
[BusChannels.RuntimeNotice]: RuntimeNoticePayload;
|
|
764
|
+
[BusChannels.DispatchScopeNotice]: DispatchScopeNoticePayload;
|
|
736
765
|
[BusChannels.DispatchEnqueued]: DispatchEnqueuedPayload;
|
|
737
766
|
[BusChannels.DispatchStarted]: DispatchStartedPayload;
|
|
738
767
|
[BusChannels.DispatchProgress]: DispatchProgressPayload;
|
|
@@ -16,7 +16,7 @@ export const CLIO_COMMIT_TRAILERS = {
|
|
|
16
16
|
} as const;
|
|
17
17
|
|
|
18
18
|
export interface CommitReceiptEvidence {
|
|
19
|
-
version:
|
|
19
|
+
version: 20;
|
|
20
20
|
algorithm: "sha256";
|
|
21
21
|
digest: string;
|
|
22
22
|
/** The receipt was checked against its run-ledger envelope. */
|
|
@@ -58,7 +58,7 @@ const KNOWN_CLIO_TRAILERS = new Set(
|
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
function isClioTrailer(key: string): boolean {
|
|
61
|
-
return KNOWN_CLIO_TRAILERS.has(key) || key.startsWith("clio-evidence:receipt-
|
|
61
|
+
return KNOWN_CLIO_TRAILERS.has(key) || key.startsWith("clio-evidence:receipt-v20/sha256:");
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
@@ -87,7 +87,7 @@ function trailerBlockStart(lines: ReadonlyArray<string>): number | null {
|
|
|
87
87
|
|
|
88
88
|
function receiptTrailer(receipt: CommitReceiptEvidence | undefined): string | null {
|
|
89
89
|
if (
|
|
90
|
-
receipt?.version !==
|
|
90
|
+
receipt?.version !== 20 ||
|
|
91
91
|
receipt.algorithm !== "sha256" ||
|
|
92
92
|
receipt.integrityValid !== true ||
|
|
93
93
|
receipt.directlyRelevant !== true ||
|
|
@@ -95,7 +95,7 @@ function receiptTrailer(receipt: CommitReceiptEvidence | undefined): string | nu
|
|
|
95
95
|
) {
|
|
96
96
|
return null;
|
|
97
97
|
}
|
|
98
|
-
return `Clio-Evidence: receipt-
|
|
98
|
+
return `Clio-Evidence: receipt-v20/sha256:${receipt.digest}`;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/**
|