@iowarp/clio-coder 0.3.4 → 0.3.7
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 +65 -2
- package/CONTRIBUTING.md +6 -6
- package/README.md +16 -5
- package/dist/{acp-S5R4RR5B.js → acp-SK4MD6MM.js} +11 -11
- package/dist/{agents-P6DMMVZY.js → agents-2FN2K6ME.js} +33 -26
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-2XCZLPKS.js → auth-QIYZWM5I.js} +15 -15
- package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
- package/dist/{chunk-VAWWTKDP.js → chunk-3HAPLH5M.js} +11 -11
- package/dist/{chunk-YCWGATWI.js → chunk-465YSENW.js} +3 -3
- package/dist/{chunk-4OC57DA6.js → chunk-4DGYLA73.js} +53 -2
- package/dist/{chunk-UZHIZC5S.js → chunk-4DWFMQDR.js} +61 -76
- package/dist/{chunk-ZWMF7253.js → chunk-5C3AQNDW.js} +328 -9
- package/dist/{chunk-22NAGB7X.js → chunk-5C77SEEY.js} +5 -94
- package/dist/{chunk-WPQLXFOZ.js → chunk-5FR74PWO.js} +3 -2
- package/dist/{chunk-35MKKU5R.js → chunk-5UJ6ECTS.js} +18 -10
- package/dist/{chunk-BRXQQJFP.js → chunk-6M7VS3J3.js} +571 -50
- package/dist/{chunk-QQK64KLB.js → chunk-6TUKSZVF.js} +141 -23
- package/dist/{chunk-N4CZJQRK.js → chunk-AB4XIIVB.js} +8 -6
- package/dist/{chunk-KRPY7NTG.js → chunk-BMWK7ZIZ.js} +14 -20
- package/dist/{chunk-4BPJXDWC.js → chunk-C4JBQ5SR.js} +30 -14
- package/dist/{chunk-ZYKPLLNQ.js → chunk-CEYBNUGC.js} +821 -83
- package/dist/{chunk-VEZEGCGW.js → chunk-D4MDIG46.js} +20 -18
- package/dist/chunk-DJNLUABN.js +843 -0
- package/dist/{chunk-BP4OYD6A.js → chunk-DMD2AGVS.js} +21 -2
- package/dist/{chunk-KOHPCX4K.js → chunk-DOOEX22V.js} +2 -2
- package/dist/chunk-DQA7QLMD.js +123 -0
- package/dist/chunk-DR52UMZW.js +21 -0
- package/dist/{chunk-3HZ5RWN2.js → chunk-EBEFWSGL.js} +9 -7
- package/dist/{chunk-EDRHSCIE.js → chunk-EELBMBT6.js} +128 -13
- package/dist/{chunk-HV5X7OR2.js → chunk-EOOQZZDE.js} +16 -14
- package/dist/{chunk-WR67VIZY.js → chunk-FOT2FX5J.js} +63 -5
- package/dist/{chunk-BPGS2WCQ.js → chunk-GEYXPTRF.js} +2 -1
- package/dist/{chunk-FYYLNIL5.js → chunk-GH5622CP.js} +2 -2
- package/dist/{chunk-BEY543CS.js → chunk-GOXNB3AO.js} +5 -2
- package/dist/chunk-GWS3VEIW.js +195 -0
- package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
- package/dist/chunk-HWUFFB6L.js +83 -0
- package/dist/{chunk-X6COSD2O.js → chunk-J7PIKKWC.js} +8 -436
- package/dist/{chunk-NILBFAPG.js → chunk-JNXPYBB4.js} +2 -2
- package/dist/{chunk-4VP4KH3K.js → chunk-JRIO5UD2.js} +4 -4
- package/dist/{chunk-K6WL7QZT.js → chunk-JTSEDYVQ.js} +7 -7
- package/dist/{chunk-QKMUKYO7.js → chunk-KCMKRQX4.js} +236 -84
- package/dist/chunk-KZ2H5X4G.js +1026 -0
- package/dist/{chunk-A2GZF7DC.js → chunk-LADCF22A.js} +13 -13
- package/dist/chunk-LCGCVYZ4.js +57 -0
- package/dist/chunk-M4AKACEO.js +382 -0
- package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
- package/dist/{chunk-4JUF2NNX.js → chunk-MXI6J5JF.js} +7 -7
- package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
- package/dist/{chunk-TTNYS3EA.js → chunk-OB5HIGJY.js} +1 -1
- package/dist/{chunk-7RXG6QRZ.js → chunk-OBMAI2DP.js} +61 -840
- package/dist/{chunk-5M54SPOL.js → chunk-ODFEOB4F.js} +161 -5
- package/dist/chunk-PD3MESLB.js +242 -0
- package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
- package/dist/{chunk-VMNQ6OZA.js → chunk-QCTRSGHQ.js} +963 -786
- package/dist/chunk-RVG5JXAL.js +41 -0
- package/dist/{chunk-RD5U66HV.js → chunk-SROCI7ZU.js} +7 -7
- package/dist/{chunk-MFFY33HR.js → chunk-THKY7CD7.js} +466 -205
- package/dist/{chunk-34475P3I.js → chunk-TSHXZTOQ.js} +5 -4
- package/dist/{chunk-PCZJO5TI.js → chunk-UFQ3F4FW.js} +13 -178
- package/dist/{chunk-AD2SYQYC.js → chunk-UHXRNZ2J.js} +121 -3
- package/dist/chunk-UND3GU2L.js +103 -0
- package/dist/{chunk-QQL5RT5M.js → chunk-UUANF5CR.js} +2323 -2114
- package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
- package/dist/chunk-UVDSQ6LW.js +472 -0
- package/dist/{chunk-QWU7ZBO7.js → chunk-VQNODYQ4.js} +215 -56
- package/dist/chunk-VREKEFLL.js +37 -0
- package/dist/{chunk-2TZWSW76.js → chunk-WHGPSPT5.js} +2 -2
- package/dist/{chunk-TW3WDMVS.js → chunk-WHJYKASB.js} +2 -2
- package/dist/{chunk-MEQ45TQ4.js → chunk-WJHBC77E.js} +21 -7
- package/dist/{chunk-HXG4IURW.js → chunk-X2KV5FXT.js} +2 -2
- package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
- package/dist/{chunk-2LZI5CAG.js → chunk-XEGB6BCN.js} +228 -36
- package/dist/{chunk-E25LMLRW.js → chunk-YD734TPH.js} +2 -2
- package/dist/{verifiers-4UUM6TEE.js → chunk-YTYFXUI3.js} +121 -372
- package/dist/{chunk-3JLKSKD7.js → chunk-ZGH7FGS5.js} +17 -7
- package/dist/{chunk-VSNATDE6.js → chunk-ZZMN5OM4.js} +2 -2
- package/dist/cli/index.js +34 -32
- package/dist/{clio-J5JIOIDS.js → clio-WBVQEBKO.js} +7 -7
- package/dist/{code-nav-AXCXSBHX.js → code-nav-FGGFIE7L.js} +7 -7
- package/dist/codewiki/build-worker.js +4 -4
- package/dist/{components-KELWS457.js → components-F7OEATSO.js} +5 -5
- package/dist/{config-OEBMIN2U.js → config-TRBL3RCF.js} +48 -41
- package/dist/{configure-PUQOSIXQ.js → configure-OLCVPHNM.js} +17 -17
- package/dist/{context-URSXPBCK.js → context-MJIJ6GOX.js} +12 -12
- package/dist/{context-EKDCKUUZ.js → context-WFPKQSM6.js} +26 -9
- package/dist/{context-MGSE4Z2T.js → context-XEWE3MOJ.js} +44 -37
- package/dist/{context-clear-KDAJRNUK.js → context-clear-KNOS2JPB.js} +44 -37
- package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
- package/dist/{context-working-set-SBKMPPI2.js → context-working-set-EUXAZI6N.js} +14 -13
- package/dist/{dispatch-runner-MSWN72NK.js → dispatch-runner-B7MTOVKL.js} +321 -60
- package/dist/{docs-2C2LTVT2.js → docs-FLJTIDSE.js} +5 -5
- package/dist/{doctor-7BSE27PJ.js → doctor-RN4YKO2X.js} +15 -15
- package/dist/{eval-IZGDOO4H.js → eval-RUBJVSNQ.js} +52 -236
- package/dist/{evidence-SR7WXB5B.js → evidence-JZNBUOQZ.js} +39 -33
- package/dist/{evolve-K7VE2CBX.js → evolve-FJVC4KKI.js} +39 -33
- package/dist/{extensions-QVDOHDGJ.js → extensions-IQL36S7K.js} +5 -5
- package/dist/{fleet-7XMJNQNF.js → fleet-BDKYJFCP.js} +243 -370
- package/dist/fleet-commands-ZFIWZSB3.js +70 -0
- package/dist/fleet-graph-Y6HPXIVF.js +125 -0
- package/dist/fleet-new-RDVJLHHH.js +48 -0
- package/dist/{fleet-preflight-AQNAH644.js → fleet-preflight-BHSNPBMH.js} +2 -2
- package/dist/fleet-validate-BIYREGIK.js +79 -0
- package/dist/{init-JGNPAYXT.js → init-LQUB5COQ.js} +57 -48
- package/dist/library-NJAHIGG4.js +217 -0
- package/dist/memory-OG6HOYKM.js +472 -0
- package/dist/{models-ZMMLFJNN.js → models-5ZG5XY7J.js} +23 -22
- package/dist/{monitor-2F3T5KHP.js → monitor-TJ7AMTGB.js} +69 -35
- package/dist/{orchestrator-ORHT43JB.js → orchestrator-WZYB54DM.js} +4868 -1189
- package/dist/{paths-UXLN5YYZ.js → paths-XUC7GS6E.js} +5 -5
- package/dist/{reset-NXGTYNUO.js → reset-PXQT45IY.js} +8 -8
- package/dist/{run-RF4WJGMT.js → run-FQ74YF62.js} +82 -62
- package/dist/{share-UT3W6E4M.js → share-FW7SVCL3.js} +34 -10
- package/dist/{skills-PSACKC5Q.js → skills-7E7IRB3R.js} +25 -9
- package/dist/{skills-eval-WJSI55RZ.js → skills-eval-LI75W6OK.js} +43 -35
- package/dist/{targets-PIIRAOYS.js → targets-4CIFKCTW.js} +27 -24
- package/dist/{terminal-lease-ULWXWNVY.js → terminal-lease-WUZY7ZV5.js} +5 -4
- package/dist/{uninstall-FZCQCDKC.js → uninstall-7FV7IP4E.js} +5 -5
- package/dist/{upgrade-346TZ6AV.js → upgrade-K2HVIVMQ.js} +21 -20
- package/dist/{usage-6KKXR32N.js → usage-GTZELZQX.js} +159 -59
- package/dist/verifiers-RLAHT27O.js +336 -0
- package/dist/{verify-X5HDROLA.js → verify-BX3BRKH5.js} +7 -6
- package/dist/{wiki-generate-7STOCIFZ.js → wiki-generate-ASIFASCN.js} +58 -48
- package/dist/worker/entry.js +98 -84
- package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
- package/docs/README.md +4 -3
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-placement.md +1 -2
- package/docs/artifact-versions.md +10 -6
- package/docs/built-in-agents.md +26 -2
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +90 -8
- package/docs/configuration-and-targets.md +90 -2
- package/docs/context-engine.md +4 -2
- package/docs/context-working-set.md +4 -4
- package/docs/development-pipeline.md +1 -1
- package/docs/dispatch-architecture-rationale.md +1 -1
- package/docs/documentation-coverage.md +4 -4
- package/docs/documentation-guide.md +4 -4
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +4 -45
- package/docs/evidence-and-memory.md +70 -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 +224 -11
- package/docs/git-commit-provenance.md +2 -2
- package/docs/glossary.md +1 -1
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +20 -2
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +55 -8
- package/docs/proactive-memory.md +26 -16
- 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 +29 -7
- 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 +38 -4
- package/docs/worker-dispatch-mechanics.md +3 -3
- package/package.json +7 -4
- package/src/cli/agents.ts +2 -3
- package/src/cli/argv.ts +14 -1
- 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 +121 -0
- package/src/cli/fleet-validate.ts +30 -0
- package/src/cli/fleet.ts +188 -335
- package/src/cli/index.ts +4 -2
- package/src/cli/library.ts +190 -0
- package/src/cli/memory.ts +272 -10
- package/src/cli/modes/json-stream.ts +2 -2
- package/src/cli/modes/print.ts +12 -1
- package/src/cli/run.ts +22 -2
- package/src/cli/share.ts +13 -1
- package/src/cli/targets.ts +12 -3
- package/src/cli/usage.ts +160 -20
- package/src/core/bus-events.ts +7 -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/response-model-id.ts +134 -0
- package/src/core/toml.ts +62 -0
- package/src/core/workspace-files.ts +0 -1
- package/src/domains/agents/builtins/architect.md +2 -1
- package/src/domains/agents/builtins/oracle.md +33 -0
- package/src/domains/agents/catalog.ts +18 -5
- package/src/domains/agents/fleet-contract.ts +278 -16
- package/src/domains/agents/index.ts +14 -0
- package/src/domains/agents/recipe.ts +54 -14
- package/src/domains/agents/result-contract.ts +242 -5
- package/src/domains/config/classify.ts +4 -0
- package/src/domains/context/bootstrap.ts +36 -27
- package/src/domains/context/project-metadata.ts +19 -63
- package/src/domains/context/prompt-context.ts +8 -0
- package/src/domains/context/working-set/policies/index.ts +3 -4
- package/src/domains/dispatch/active-route-planner.ts +14 -0
- package/src/domains/dispatch/backoff.ts +2 -1
- package/src/domains/dispatch/budget-envelope.ts +396 -0
- 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 +36 -0
- package/src/domains/dispatch/delegation-plan.ts +167 -0
- package/src/domains/dispatch/execution-plan.ts +76 -5
- package/src/domains/dispatch/execution-role.ts +3 -1
- package/src/domains/dispatch/execution-scheduler.ts +183 -67
- package/src/domains/dispatch/extension.ts +339 -36
- 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 +737 -0
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/host-verification.ts +178 -0
- package/src/domains/dispatch/index.ts +38 -0
- package/src/domains/dispatch/intent.ts +159 -0
- package/src/domains/dispatch/orphan-recovery.ts +1 -0
- package/src/domains/dispatch/receipt-integrity.ts +12 -4
- package/src/domains/dispatch/state.ts +37 -3
- package/src/domains/dispatch/types.ts +61 -9
- package/src/domains/dispatch/validation.ts +80 -6
- package/src/domains/dispatch/worker-spawn.ts +14 -3
- package/src/domains/eval/metrics/evidence.ts +0 -116
- package/src/domains/eval/metrics/invariants.ts +1 -1
- package/src/domains/eval/runners/clio-run.ts +1 -10
- package/src/domains/eval/runners/external-command.ts +2 -29
- package/src/domains/eval/schema/suite.ts +0 -7
- package/src/domains/eval/suites/run.ts +1 -7
- package/src/domains/evidence/trust-status.ts +10 -1
- package/src/domains/memory/index.ts +22 -0
- package/src/domains/memory/operations.ts +58 -1
- package/src/domains/memory/promotion.ts +281 -0
- package/src/domains/memory/prompt-section.ts +25 -5
- package/src/domains/memory/proposal.ts +51 -7
- package/src/domains/memory/task-bank.ts +3 -2
- package/src/domains/memory/task-memory-handoff.ts +181 -24
- package/src/domains/memory/task-memory-policy.ts +3 -1
- package/src/domains/memory/types.ts +37 -0
- package/src/domains/memory/validate.ts +178 -0
- package/src/domains/middleware/index.ts +15 -0
- package/src/domains/middleware/memory-intervention.ts +35 -25
- package/src/domains/middleware/runtime.ts +6 -0
- package/src/domains/middleware/skills-reminder.ts +19 -4
- package/src/domains/middleware/stalled-turn.ts +43 -1
- package/src/domains/middleware/types.ts +10 -0
- package/src/domains/middleware/watchdog.ts +281 -0
- package/src/domains/observability/contract.ts +9 -2
- package/src/domains/observability/cost.ts +31 -4
- 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/providers/index.ts +3 -0
- package/src/domains/providers/model-discovery.ts +9 -0
- package/src/domains/providers/runtime-resolution.ts +38 -1
- package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
- package/src/domains/providers/types/context-window-slots.ts +18 -0
- package/src/domains/providers/types/runtime-descriptor.ts +3 -1
- package/src/domains/resources/index.ts +20 -0
- package/src/domains/resources/library.ts +326 -0
- package/src/domains/resources/skills/marketplace.ts +37 -12
- package/src/domains/safety/call-target.ts +211 -14
- package/src/domains/safety/decision-presentation.ts +268 -0
- package/src/domains/safety/redaction.ts +73 -0
- package/src/domains/session/context-ledger.ts +10 -1
- package/src/domains/session/decision-board.ts +4 -0
- package/src/domains/session/entries.ts +3 -0
- package/src/domains/session/handoff.ts +629 -0
- package/src/domains/session/history.ts +68 -19
- package/src/domains/session/usage.ts +24 -7
- package/src/domains/share/archive.ts +67 -2
- package/src/engine/acp/event-mapper.ts +7 -0
- package/src/engine/acp/server.ts +29 -2
- package/src/engine/apis/lmstudio.ts +25 -4
- package/src/engine/apis/openai-completions.ts +147 -22
- package/src/engine/claude/sdk-runtime.ts +8 -2
- package/src/engine/claude/tool-safety.ts +13 -0
- package/src/engine/loop-guard.ts +27 -3
- package/src/engine/worker-events.ts +4 -3
- package/src/engine/worker-runtime.ts +59 -54
- package/src/entry/orchestrator.ts +55 -1
- package/src/interactive/bus-notices.ts +26 -0
- package/src/interactive/chat-loop-messages.ts +22 -0
- package/src/interactive/chat-loop.ts +248 -1
- package/src/interactive/chat-renderer.ts +41 -3
- package/src/interactive/clio-editor.ts +44 -7
- package/src/interactive/context-overlay.ts +43 -5
- package/src/interactive/cost-overlay.ts +70 -11
- 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 +471 -50
- package/src/interactive/fleet-run-preview.ts +307 -0
- package/src/interactive/footer/notifications.ts +219 -0
- package/src/interactive/footer/widgets.ts +13 -0
- package/src/interactive/handoff-round.ts +56 -0
- package/src/interactive/interactive-application.ts +49 -2
- package/src/interactive/interactive-event-projection.ts +9 -1
- package/src/interactive/interactive-input-runtime.ts +11 -1
- package/src/interactive/interactive-presentation.ts +11 -1
- package/src/interactive/interactive-slash-runtime.ts +52 -2
- package/src/interactive/interactive-subscriptions.ts +14 -2
- package/src/interactive/memory-overlay.ts +89 -4
- package/src/interactive/oracle.ts +179 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +7 -1
- package/src/interactive/overlay-frame.ts +5 -2
- package/src/interactive/overlay-general-openers.ts +230 -2
- package/src/interactive/overlay-key-routing.ts +58 -2
- package/src/interactive/overlay-lifecycle.ts +52 -5
- package/src/interactive/overlay-permission-lifecycle.ts +33 -8
- package/src/interactive/overlay-resource-openers.ts +11 -3
- package/src/interactive/overlay-session-lifecycle.ts +234 -2
- package/src/interactive/overlay-transitions.ts +11 -0
- package/src/interactive/overlays/ask-user.ts +74 -30
- package/src/interactive/overlays/decisions.ts +3 -1
- 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 +101 -4
- package/src/interactive/overlays/side-question.ts +139 -0
- package/src/interactive/overlays/skills-hub.ts +401 -15
- package/src/interactive/permission-hint.ts +35 -0
- package/src/interactive/permission-overlay.ts +95 -45
- package/src/interactive/renderers/tool-execution.ts +19 -49
- package/src/interactive/session-last-turn.ts +8 -1
- package/src/interactive/session-usage-reseed.ts +36 -10
- package/src/interactive/side-question.ts +171 -0
- package/src/interactive/slash-commands.ts +434 -7
- package/src/interactive/slash-spec.ts +19 -6
- package/src/interactive/status/summary.ts +5 -0
- package/src/interactive/status/types.ts +5 -0
- package/src/interactive/terminal-lease.ts +1 -0
- package/src/interactive/theme/tokens.ts +30 -0
- package/src/interactive/turn-context.ts +96 -23
- package/src/interactive/turn-middleware.ts +16 -1
- package/src/interactive/turn-runtime.ts +37 -8
- package/src/interactive/turn-state.ts +3 -0
- package/src/interactive/watchdog-run.ts +75 -0
- package/src/interactive/worker-progress.ts +440 -0
- package/src/interactive/worker-share.ts +56 -1
- package/src/interactive/worker-stream.ts +58 -110
- package/src/tools/agent-tools.ts +28 -3
- package/src/tools/ask-user.ts +21 -1
- package/src/tools/bootstrap.ts +3 -0
- package/src/tools/compete-worktrees.ts +13 -79
- package/src/tools/context/index.ts +2 -2
- package/src/tools/dispatch-admission.ts +242 -8
- package/src/tools/dispatch-arguments.ts +65 -1
- package/src/tools/dispatch-event-text.ts +19 -0
- package/src/tools/dispatch-plan.ts +136 -6
- package/src/tools/dispatch-runner.ts +319 -13
- package/src/tools/dispatch-types.ts +20 -1
- package/src/tools/dispatch.ts +96 -3
- package/src/tools/monitor.ts +31 -0
- package/src/tools/profiles.ts +18 -4
- package/src/tools/registry.ts +15 -5
- package/src/tools/result-disposition.ts +156 -0
- package/src/tools/result-shaping.ts +59 -1
- package/src/tools/task-worktree.ts +238 -0
- package/src/tools/verify/authoring.ts +116 -55
- package/src/tools/verify/scripts.ts +62 -0
- package/src/tools/worker-evidence.ts +21 -1
- package/src/worker/spec-contract.ts +44 -3
- package/dist/chunk-EFADSJET.js +0 -18
- package/dist/chunk-HC4CLZ2Y.js +0 -68
- package/dist/memory-4ALKDJ4Q.js +0 -246
- package/src/domains/eval/metrics/chaos-stream.ts +0 -93
package/src/cli/fleet.ts
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* `clio-coder fleet` operator surface.
|
|
3
3
|
*
|
|
4
4
|
* clio-coder fleet list enumerate .clio-coder/fleets/*.md with validity
|
|
5
|
+
* clio-coder fleet new <name> --from <name> copy a shipped contract into the project
|
|
6
|
+
* clio-coder fleet validate|graph <name> inspect a contract without executing it
|
|
7
|
+
* clio-coder fleet commands init draft a repository command registry
|
|
5
8
|
* clio-coder fleet run <name> --var k=v ... preflight + execute a fleet contract
|
|
6
9
|
* clio-coder fleet status [--json] runtime snapshot from the durable ledger
|
|
7
10
|
* clio-coder fleet drain|resume [--json] close or reopen durable dispatch admission
|
|
@@ -15,7 +18,7 @@
|
|
|
15
18
|
import { randomBytes } from "node:crypto";
|
|
16
19
|
import { readFileSync } from "node:fs";
|
|
17
20
|
import { join } from "node:path";
|
|
18
|
-
import {
|
|
21
|
+
import { type ClioSettings, readSettings } from "../core/config.js";
|
|
19
22
|
import { loadDomains } from "../core/domain-loader.js";
|
|
20
23
|
import { clioStateDir } from "../core/xdg.js";
|
|
21
24
|
import type { AgentsContract } from "../domains/agents/contract.js";
|
|
@@ -32,41 +35,34 @@ import {
|
|
|
32
35
|
loadFleetCommands,
|
|
33
36
|
loadFleetContract,
|
|
34
37
|
renderFleetPrompt,
|
|
35
|
-
resultContractAuthorship,
|
|
36
38
|
} from "../domains/agents/index.js";
|
|
37
39
|
import type { ConfigContract } from "../domains/config/contract.js";
|
|
38
40
|
import { ConfigDomainModule } from "../domains/config/index.js";
|
|
39
41
|
import { ContextDomainModule } from "../domains/context/runtime.js";
|
|
40
|
-
import { type CapacityDrain, capacityDrain, setCapacityDraining } from "../domains/dispatch/capacity-lease.js";
|
|
41
|
-
import { runCodeStep } from "../domains/dispatch/code-step.js";
|
|
42
|
-
import { codeStepDir, writeCodeStepRecord } from "../domains/dispatch/code-step-store.js";
|
|
43
|
-
import type { DispatchContract, DispatchRequest } from "../domains/dispatch/contract.js";
|
|
44
|
-
import {
|
|
45
|
-
type ExecutionPlan,
|
|
46
|
-
type ExecutionPlanCodeStep,
|
|
47
|
-
executionPlanAncestors,
|
|
48
|
-
} from "../domains/dispatch/execution-plan.js";
|
|
49
42
|
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
import {
|
|
43
|
+
formatBudgetPolicy,
|
|
44
|
+
formatBudgetReasons,
|
|
45
|
+
formatBudgetRequest,
|
|
46
|
+
formatEffectiveBudget,
|
|
47
|
+
type RunToolBudgetEnvelope,
|
|
48
|
+
} from "../domains/dispatch/budget-envelope.js";
|
|
49
|
+
import { type CapacityDrain, capacityDrain, setCapacityDraining } from "../domains/dispatch/capacity-lease.js";
|
|
50
|
+
import type { DispatchContract } from "../domains/dispatch/contract.js";
|
|
51
|
+
import type { ExecutionPlan } from "../domains/dispatch/execution-plan.js";
|
|
52
|
+
import { agentRoleFactsResolver, requestExecutionRole, withAttemptRole } from "../domains/dispatch/execution-role.js";
|
|
57
53
|
import { compileFleetExecutionPlan } from "../domains/dispatch/fleet-plan.js";
|
|
58
54
|
import {
|
|
59
|
-
|
|
60
|
-
type
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
55
|
+
DispatchDomainModule,
|
|
56
|
+
type ExecuteFleetRunInput,
|
|
57
|
+
executeFleetRun,
|
|
58
|
+
type FleetRunOutcome,
|
|
59
|
+
planFleetResume,
|
|
60
|
+
readFleetRun,
|
|
61
|
+
} from "../domains/dispatch/index.js";
|
|
66
62
|
import { openLedger } from "../domains/dispatch/state.js";
|
|
67
63
|
import type { RunEnvelope, RunReceipt } from "../domains/dispatch/types.js";
|
|
68
64
|
import { WRITE_BOUNDARY_VIOLATION_REASON } from "../domains/dispatch/write-boundary.js";
|
|
69
|
-
import {
|
|
65
|
+
import { preflightWriteBoundaries } from "../domains/dispatch/write-boundary-enforcer.js";
|
|
70
66
|
import { ensureClioState, LifecycleDomainModule } from "../domains/lifecycle/index.js";
|
|
71
67
|
import { MiddlewareDomainModule } from "../domains/middleware/index.js";
|
|
72
68
|
import { ObservabilityDomainModule } from "../domains/observability/index.js";
|
|
@@ -85,7 +81,12 @@ Repo-owned fleet contracts and the dispatch status surface.
|
|
|
85
81
|
|
|
86
82
|
Subcommands:
|
|
87
83
|
list list .clio-coder/fleets/*.md contracts with validation status
|
|
84
|
+
new <name> --from <builtin> copy build-review, build-test, or sdlc into this repository
|
|
85
|
+
validate <name> [--json] run the fleet execution preflight without side effects
|
|
86
|
+
graph <name> [--json] print compiled waves, loops, scopes, and write boundaries
|
|
87
|
+
commands init draft a commented command registry from declared project entries
|
|
88
88
|
run <name> [--var k=v ...] preflight and execute a fleet contract
|
|
89
|
+
[--resume <runId>] replay a completed prefix from a prior run of the same plan
|
|
89
90
|
[--json] emit step receipts as JSON
|
|
90
91
|
status [--json] show running, retrying, and total dispatch state
|
|
91
92
|
drain [--json] deny new execution starts for up to one hour
|
|
@@ -104,6 +105,11 @@ function fail(message: string): number {
|
|
|
104
105
|
return 2;
|
|
105
106
|
}
|
|
106
107
|
|
|
108
|
+
function refuse(message: string): number {
|
|
109
|
+
process.stderr.write(`clio-coder fleet: ${message}\n`);
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
|
|
107
113
|
function parseVars(args: ReadonlyArray<string>): { vars: Record<string, string>; rest: string[]; error?: string } {
|
|
108
114
|
const vars: Record<string, string> = {};
|
|
109
115
|
const rest: string[] = [];
|
|
@@ -127,25 +133,6 @@ function parseVars(args: ReadonlyArray<string>): { vars: Record<string, string>;
|
|
|
127
133
|
return { vars, rest };
|
|
128
134
|
}
|
|
129
135
|
|
|
130
|
-
/** Sealed independence facts between the work under review and its reviewer. */
|
|
131
|
-
function fleetGateCorrelation(subject: RunReceipt, decider: RunReceipt): GateDecisionCorrelation {
|
|
132
|
-
const facts = (receipt: RunReceipt) => ({
|
|
133
|
-
agentId: receipt.agentId,
|
|
134
|
-
targetId: receipt.targetId,
|
|
135
|
-
wireModelId: receipt.wireModelId,
|
|
136
|
-
runtimeId: receipt.runtimeId,
|
|
137
|
-
nodeId: receipt.node?.id ?? "local",
|
|
138
|
-
});
|
|
139
|
-
const { agent, target, modelFamily, runtime, node, independent } = gateRouteCorrelation(
|
|
140
|
-
facts(subject),
|
|
141
|
-
facts(decider),
|
|
142
|
-
);
|
|
143
|
-
return { agent, target, modelFamily, runtime, node, independent };
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** Owner id for a plan with no model runs; it holds nothing to release. */
|
|
147
|
-
const NO_WORKER_RESERVATION = "fleet-no-worker-reservation";
|
|
148
|
-
|
|
149
136
|
function newFleetRootId(): string {
|
|
150
137
|
return `fleet-${randomBytes(6).toString("hex")}`;
|
|
151
138
|
}
|
|
@@ -157,7 +144,14 @@ function newFleetRootId(): string {
|
|
|
157
144
|
function renderStep(step: FleetContractStep): string {
|
|
158
145
|
if (step.kind === "code") return `code:${step.command}[${step.scope}]`;
|
|
159
146
|
if (step.kind === "agent") return `${step.agent}[${step.scope}]`;
|
|
160
|
-
|
|
147
|
+
if (step.kind === "gate") return `gate:${step.path}[${step.run}]`;
|
|
148
|
+
if (step.kind === "plan") return `plan:${step.agent}[${step.roster.join(",")}; max ${step.maxTasks}]`;
|
|
149
|
+
const check =
|
|
150
|
+
step.check.kind === "code"
|
|
151
|
+
? `code:${step.check.command}`
|
|
152
|
+
: step.check.kind === "gate"
|
|
153
|
+
? `gate:${step.check.gate}`
|
|
154
|
+
: step.check.agent;
|
|
161
155
|
return `loop:${step.id}(${check} -> ${step.repair.agent} x${step.maxAttempts})`;
|
|
162
156
|
}
|
|
163
157
|
|
|
@@ -209,6 +203,7 @@ interface FleetPreflightDeps {
|
|
|
209
203
|
agents: AgentsContract;
|
|
210
204
|
safety: SafetyContract;
|
|
211
205
|
scheduling: SchedulingContract | undefined;
|
|
206
|
+
settings: Readonly<ClioSettings>;
|
|
212
207
|
}
|
|
213
208
|
|
|
214
209
|
/** Every agent a contract dispatches, including both halves of every loop. */
|
|
@@ -218,7 +213,11 @@ function contractAgents(
|
|
|
218
213
|
const agents: Array<{ id: string; agent: string; scope: "readonly" | "workspace" }> = [];
|
|
219
214
|
for (const step of contract.steps) {
|
|
220
215
|
if (step.kind === "agent") agents.push({ id: step.id, agent: step.agent, scope: step.scope });
|
|
221
|
-
else if (step.kind === "
|
|
216
|
+
else if (step.kind === "gate") agents.push({ id: step.id, agent: step.agent, scope: "workspace" });
|
|
217
|
+
else if (step.kind === "plan") {
|
|
218
|
+
agents.push({ id: step.id, agent: step.agent, scope: step.scope });
|
|
219
|
+
for (const agent of step.roster) agents.push({ id: `${step.id}.roster`, agent, scope: "readonly" });
|
|
220
|
+
} else if (step.kind === "loop") {
|
|
222
221
|
if (step.check.kind === "agent") {
|
|
223
222
|
agents.push({ id: `${step.id}.check`, agent: step.check.agent, scope: step.check.scope });
|
|
224
223
|
}
|
|
@@ -229,6 +228,28 @@ function contractAgents(
|
|
|
229
228
|
}
|
|
230
229
|
|
|
231
230
|
function preflightFleet(contract: FleetContract, deps: FleetPreflightDeps): string | null {
|
|
231
|
+
const targets = new Set(deps.settings.targets.map((target) => target.id));
|
|
232
|
+
const profiles = new Set(Object.keys(deps.settings.workers?.profiles ?? {}));
|
|
233
|
+
const checkRoute = (id: string, route: { target?: string; profile?: string }): string | null => {
|
|
234
|
+
if (route.target !== undefined && !targets.has(route.target))
|
|
235
|
+
return `unknown target '${route.target}' at step '${id}'`;
|
|
236
|
+
if (route.profile !== undefined && !profiles.has(route.profile))
|
|
237
|
+
return `unknown profile '${route.profile}' at step '${id}'`;
|
|
238
|
+
return null;
|
|
239
|
+
};
|
|
240
|
+
for (const step of contract.steps) {
|
|
241
|
+
if (step.kind === "agent" || step.kind === "gate" || step.kind === "plan") {
|
|
242
|
+
const error = checkRoute(step.id, step);
|
|
243
|
+
if (error !== null) return error;
|
|
244
|
+
}
|
|
245
|
+
if (step.kind !== "loop") continue;
|
|
246
|
+
if (step.check.kind === "agent") {
|
|
247
|
+
const error = checkRoute(`${step.id}.check`, step.check);
|
|
248
|
+
if (error !== null) return error;
|
|
249
|
+
}
|
|
250
|
+
const error = checkRoute(`${step.id}.repair`, step.repair);
|
|
251
|
+
if (error !== null) return error;
|
|
252
|
+
}
|
|
232
253
|
for (const step of contractAgents(contract)) {
|
|
233
254
|
if (!deps.agents.get(step.agent)) {
|
|
234
255
|
return `unknown agent '${step.agent}' (step '${step.id}' must name a recipe from 'clio-coder agents')`;
|
|
@@ -257,23 +278,21 @@ async function runFleet(args: ReadonlyArray<string>): Promise<number> {
|
|
|
257
278
|
const { vars, rest, error } = parseVars(args);
|
|
258
279
|
if (error !== undefined) return fail(error);
|
|
259
280
|
const json = rest.includes("--json");
|
|
281
|
+
const resumeIndex = rest.indexOf("--resume");
|
|
282
|
+
const resumeId = resumeIndex === -1 ? undefined : rest[resumeIndex + 1];
|
|
283
|
+
if (resumeIndex !== -1 && (resumeId === undefined || resumeId.startsWith("-")))
|
|
284
|
+
return fail("--resume requires a run id");
|
|
260
285
|
const name = rest.find((arg) => !arg.startsWith("-"));
|
|
261
|
-
if (!name) return fail("usage: clio-coder fleet run <name> [--var key=value ...] [--json]");
|
|
286
|
+
if (!name) return fail("usage: clio-coder fleet run <name> [--var key=value ...] [--resume <runId>] [--json]");
|
|
262
287
|
|
|
263
|
-
// Phase 1: zero-side-effect validation. Parse and render strictly before
|
|
264
|
-
// any domain boots or any process spawns.
|
|
265
288
|
let contract: FleetContract;
|
|
266
289
|
let prompt: string;
|
|
267
290
|
let commands: FleetCommandRegistry | null;
|
|
268
291
|
try {
|
|
269
292
|
contract = loadFleetContract(process.cwd(), name);
|
|
270
293
|
prompt = renderFleetPrompt(contract.body, vars);
|
|
271
|
-
// loadFleetContract already refused any unregistered command id; this
|
|
272
|
-
// read is the binding the runner executes.
|
|
273
294
|
commands = loadFleetCommands(process.cwd());
|
|
274
295
|
} catch (err) {
|
|
275
|
-
// The listing calls this state `setup` and says how to leave it; the run
|
|
276
|
-
// path is where a user meets it with intent, so it says the same thing.
|
|
277
296
|
if (err instanceof FleetCommandRegistryMissingError) {
|
|
278
297
|
process.stderr.write(`clio-coder fleet: ${err.message}\n ${FLEET_COMMANDS_REMEDY}\n`);
|
|
279
298
|
return 2;
|
|
@@ -306,16 +325,19 @@ async function runFleet(args: ReadonlyArray<string>): Promise<number> {
|
|
|
306
325
|
await loaded.stop();
|
|
307
326
|
return fail("required domains unavailable (dispatch/agents/safety)");
|
|
308
327
|
}
|
|
309
|
-
|
|
310
328
|
const roleFacts = agentRoleFactsResolver((id) => agents.getSpec(id));
|
|
311
|
-
const preflightError = preflightFleet(contract, {
|
|
329
|
+
const preflightError = preflightFleet(contract, {
|
|
330
|
+
agents,
|
|
331
|
+
safety,
|
|
332
|
+
scheduling,
|
|
333
|
+
settings: config?.get() ?? readSettings(),
|
|
334
|
+
});
|
|
312
335
|
if (preflightError !== null) {
|
|
313
336
|
await loaded.stop();
|
|
314
337
|
return fail(`preflight failed: ${preflightError}`);
|
|
315
338
|
}
|
|
316
339
|
|
|
317
340
|
const fleetRootId = newFleetRootId();
|
|
318
|
-
let planOutcome: ExecutionPlanResult;
|
|
319
341
|
let plan: ExecutionPlan;
|
|
320
342
|
try {
|
|
321
343
|
plan = compileFleetExecutionPlan({
|
|
@@ -334,9 +356,14 @@ async function runFleet(args: ReadonlyArray<string>): Promise<number> {
|
|
|
334
356
|
return {
|
|
335
357
|
requestedAuthority: spec.capabilityClass,
|
|
336
358
|
approvedAuthority: spec.capabilityClass,
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
359
|
+
expectedResultContract:
|
|
360
|
+
context.planRole === true
|
|
361
|
+
? "delegation-plan"
|
|
362
|
+
: context.gateAuthorRole === true
|
|
363
|
+
? "artifact-report"
|
|
364
|
+
: context.gateRole === "reviewer"
|
|
365
|
+
? "verifier-report"
|
|
366
|
+
: spec.resultContract.kind,
|
|
340
367
|
executionRole: withAttemptRole(requestRole, context.attempt),
|
|
341
368
|
};
|
|
342
369
|
},
|
|
@@ -345,268 +372,91 @@ async function runFleet(args: ReadonlyArray<string>): Promise<number> {
|
|
|
345
372
|
await loaded.stop();
|
|
346
373
|
return fail(err instanceof Error ? err.message : String(err));
|
|
347
374
|
}
|
|
348
|
-
// A declared boundary is verified against the checkout, so the checkout has
|
|
349
|
-
// to be one this can read. Refused here, before any spawn, rather than
|
|
350
|
-
// discovered as an unenforceable claim halfway through the run.
|
|
351
375
|
try {
|
|
352
376
|
preflightWriteBoundaries(plan, process.cwd());
|
|
353
377
|
} catch (err) {
|
|
354
378
|
await loaded.stop();
|
|
355
379
|
return fail(`preflight failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
356
380
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
381
|
+
|
|
382
|
+
let resume: ExecuteFleetRunInput["resume"];
|
|
383
|
+
if (resumeId !== undefined) {
|
|
384
|
+
const record = readFleetRun(resumeId);
|
|
385
|
+
if (record === null) {
|
|
386
|
+
await loaded.stop();
|
|
387
|
+
return refuse(`resume run '${resumeId}' was not found in the durable fleet ledger`);
|
|
388
|
+
}
|
|
389
|
+
const planned = planFleetResume(record, plan, contract, vars);
|
|
390
|
+
if (!planned.ok) {
|
|
391
|
+
if (planned.reason === "fleet-name") {
|
|
392
|
+
await loaded.stop();
|
|
393
|
+
return refuse(`resume run '${resumeId}' belongs to fleet '${planned.priorFleet}', not '${planned.currentFleet}'`);
|
|
394
|
+
}
|
|
395
|
+
if (planned.reason === "vars") {
|
|
396
|
+
await loaded.stop();
|
|
397
|
+
return refuse(`resume run '${resumeId}' used different --var values`);
|
|
398
|
+
}
|
|
399
|
+
process.stderr.write(
|
|
400
|
+
`clio-coder fleet: resume plan hash differs: prior=${planned.priorHash} current=${planned.currentHash}\n`,
|
|
401
|
+
);
|
|
402
|
+
for (const entry of planned.diff) {
|
|
403
|
+
process.stderr.write(` step ${entry.index + 1}: ${entry.priorId} -> ${entry.currentId}\n`);
|
|
404
|
+
process.stderr.write(` prior: ${JSON.stringify(entry.prior)}\n`);
|
|
405
|
+
process.stderr.write(` current: ${JSON.stringify(entry.current)}\n`);
|
|
406
|
+
}
|
|
407
|
+
await loaded.stop();
|
|
408
|
+
return 1;
|
|
409
|
+
}
|
|
410
|
+
resume = { record, replayed: planned.replayed };
|
|
411
|
+
}
|
|
412
|
+
|
|
367
413
|
process.stderr.write(
|
|
368
414
|
`fleet ${contract.name}: root=${fleetRootId} plan=${plan.hash} steps=${plan.steps.length} loops=${plan.loops.length}\n`,
|
|
369
415
|
);
|
|
370
|
-
|
|
371
|
-
const receiptsByStep = new Map<string, RunReceipt>();
|
|
372
|
-
const planStep = (stepId: string) => plan.steps.find((entry) => entry.id === stepId);
|
|
373
|
-
const attributionEnabled = config?.get().attribution.gitCommits ?? true;
|
|
374
|
-
// Freshness is coordinator-owned execution state. Worker prose cannot set
|
|
375
|
-
// either flag: a successful deterministic verification sets the first, and
|
|
376
|
-
// an integrity-valid independent gate decision sets the second. Any later
|
|
377
|
-
// workspace agent invalidates both before a commit may read them.
|
|
378
|
-
let validationFresh = false;
|
|
379
|
-
let independentReviewFresh = false;
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* The commit message is the words of the agent that produced the work, and
|
|
383
|
-
* only that agent's. Candidates are consulted newest first; when none of
|
|
384
|
-
* them authored one, code writes a deterministic line rather than inventing
|
|
385
|
-
* a sentence or reusing somebody else's.
|
|
386
|
-
*/
|
|
387
|
-
const commitMessageFor = (
|
|
388
|
-
step: ExecutionPlanCodeStep,
|
|
389
|
-
priorResults: ReadonlyMap<string, { output: string }>,
|
|
390
|
-
): string => {
|
|
391
|
-
for (const candidate of step.commitFrom ?? []) {
|
|
392
|
-
const source = planStep(candidate);
|
|
393
|
-
const result = priorResults.get(candidate);
|
|
394
|
-
if (source === undefined || source.kind !== "agent" || result === undefined) continue;
|
|
395
|
-
const resultContract = agents.getSpec(source.agentId)?.resultContract ?? null;
|
|
396
|
-
if (resultContract === null) continue;
|
|
397
|
-
const authored = resultContractAuthorship(resultContract, result.output);
|
|
398
|
-
if (authored.commitMessage !== null) return authored.commitMessage;
|
|
399
|
-
if (authored.summary !== null) return `clio(${fleetRootId}): ${authored.summary}`;
|
|
400
|
-
}
|
|
401
|
-
return `clio(${fleetRootId}): ${contract.name} ${step.id}`;
|
|
402
|
-
};
|
|
416
|
+
let outcome: FleetRunOutcome;
|
|
403
417
|
try {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
memberId: admission.step.id,
|
|
427
|
-
wave: plan.waves.findIndex((wave) => wave.includes(admission.step.id)),
|
|
428
|
-
resolution: dispatch.preview?.({
|
|
429
|
-
agentId: admission.step.agentId,
|
|
430
|
-
executionRole: admission.step.executionRole,
|
|
431
|
-
task: admission.step.task,
|
|
432
|
-
}) as NonNullable<ReturnType<NonNullable<DispatchContract["preview"]>>>,
|
|
433
|
-
})),
|
|
434
|
-
});
|
|
435
|
-
if (!reservation) throw new Error("fleet whole-plan reservation is unavailable");
|
|
436
|
-
return { ownerId: reservation.ownerId };
|
|
437
|
-
},
|
|
438
|
-
async run(step, handoffs, reservation, ledger) {
|
|
439
|
-
// A loop repair is attempt n of the same logical work, so it enters
|
|
440
|
-
// the run ledger as one: recovery evidence, not a fresh observation.
|
|
441
|
-
const attempt = step.loop?.role === "repair" ? step.loop.attempt : 0;
|
|
442
|
-
const request: DispatchRequest = {
|
|
443
|
-
agentId: step.agentId,
|
|
444
|
-
executionRole: step.executionRole,
|
|
445
|
-
task: step.task,
|
|
446
|
-
predecessorHandoffs: handoffs,
|
|
447
|
-
requestOrigin: "user",
|
|
448
|
-
lineage: { parentRunId: fleetRootId, rootRunId: fleetRootId, attempt, depth: 1 },
|
|
449
|
-
reservation,
|
|
450
|
-
...(ledger !== undefined ? { ledger } : {}),
|
|
451
|
-
...(step.loop?.role === "check"
|
|
452
|
-
? {
|
|
453
|
-
gate: {
|
|
454
|
-
role: "reviewer" as const,
|
|
455
|
-
group: `${fleetRootId}:${step.loop.loopId}`,
|
|
456
|
-
cycle: step.loop.attempt,
|
|
457
|
-
subjects: handoffs.map((handoff) => ({
|
|
458
|
-
runId: handoff.terminalRunId,
|
|
459
|
-
digest: handoff.receiptDigest,
|
|
460
|
-
})),
|
|
461
|
-
},
|
|
462
|
-
}
|
|
463
|
-
: {}),
|
|
464
|
-
...(step.scope === "readonly" ? { autonomy: "read-only" as const } : {}),
|
|
465
|
-
};
|
|
466
|
-
const handle = await dispatch.dispatch(request);
|
|
467
|
-
void (async () => {
|
|
468
|
-
for await (const _event of handle.events) {
|
|
469
|
-
/* background display drain */
|
|
470
|
-
}
|
|
471
|
-
})().catch(() => {});
|
|
472
|
-
return {
|
|
473
|
-
assignmentId: handle.runId,
|
|
474
|
-
result: handle.finalPromise.then((receipt) => {
|
|
475
|
-
if (step.scope === "workspace") {
|
|
476
|
-
validationFresh = false;
|
|
477
|
-
independentReviewFresh = false;
|
|
478
|
-
}
|
|
479
|
-
receipts.push(receipt);
|
|
480
|
-
receiptsByStep.set(step.id, receipt);
|
|
481
|
-
const envelope = dispatch.getRun(receipt.runId);
|
|
482
|
-
const integrityValid = envelope !== null && verifyReceiptIntegrity(receipt, envelope).ok;
|
|
483
|
-
const succeeded = receipt.exitCode === 0 && (receipt.outcome === undefined || receipt.outcome === "succeeded");
|
|
484
|
-
if (json) process.stdout.write(`${JSON.stringify(receipt)}\n`);
|
|
485
|
-
else
|
|
486
|
-
process.stdout.write(
|
|
487
|
-
`step ${step.id} ${step.agentId}: ${succeeded ? "succeeded" : "failed"} assignment=${handle.runId} terminal-run=${receipt.runId} cost=$${receipt.costUsd.toFixed(4)}\n`,
|
|
488
|
-
);
|
|
489
|
-
return {
|
|
490
|
-
stepId: step.id,
|
|
491
|
-
assignmentId: handle.runId,
|
|
492
|
-
terminalRunId: receipt.runId,
|
|
493
|
-
receiptDigest: receipt.integrity.digest,
|
|
494
|
-
output: receipt.output?.state === "final" ? receipt.output.text : "",
|
|
495
|
-
succeeded,
|
|
496
|
-
integrityValid,
|
|
497
|
-
};
|
|
498
|
-
}),
|
|
499
|
-
};
|
|
500
|
-
},
|
|
501
|
-
async runCode(step, _handoffs, signal, priorResults) {
|
|
502
|
-
const command = commands?.commands.get(step.commandId);
|
|
503
|
-
if (command === undefined) throw new Error(`fleet code step '${step.id}' has no registered command`);
|
|
504
|
-
const isCommit = step.commitFrom !== undefined;
|
|
505
|
-
const evidence = isCommit
|
|
506
|
-
? deriveFleetCommitAttribution({
|
|
507
|
-
plan,
|
|
508
|
-
step,
|
|
509
|
-
priorResults,
|
|
510
|
-
validationFresh,
|
|
511
|
-
independentReviewFresh,
|
|
512
|
-
})
|
|
513
|
-
: null;
|
|
514
|
-
if (!isCommit && step.scope === "workspace" && step.verification !== true) {
|
|
515
|
-
validationFresh = false;
|
|
516
|
-
independentReviewFresh = false;
|
|
418
|
+
outcome = await executeFleetRun({
|
|
419
|
+
plan,
|
|
420
|
+
contractName: contract.name,
|
|
421
|
+
commands,
|
|
422
|
+
workspaceRoot: process.cwd(),
|
|
423
|
+
fleetRootId,
|
|
424
|
+
dispatch,
|
|
425
|
+
agents: { getSpec: (agentId) => agents.getSpec(agentId) },
|
|
426
|
+
attributionEnabled: config?.get().attribution.gitCommits ?? true,
|
|
427
|
+
vars,
|
|
428
|
+
...(resume !== undefined ? { resume } : {}),
|
|
429
|
+
onStepSettled(step) {
|
|
430
|
+
if (step.replayed === true && step.result !== undefined) {
|
|
431
|
+
if (json)
|
|
432
|
+
process.stdout.write(
|
|
433
|
+
`${JSON.stringify({ stepId: step.stepId, status: "replayed", receipt: { runId: step.result.terminalRunId, digest: step.result.receiptDigest } })}\n`,
|
|
434
|
+
);
|
|
435
|
+
else
|
|
436
|
+
process.stdout.write(
|
|
437
|
+
`step ${step.stepId}: replayed terminal-run=${step.result.terminalRunId} receipt=${step.result.receiptDigest}\n`,
|
|
438
|
+
);
|
|
439
|
+
return;
|
|
517
440
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
...(isCommit && evidence !== null && originalMessage !== null
|
|
526
|
-
? {
|
|
527
|
-
substitutions: {
|
|
528
|
-
commitMessage: attributeCommitMessage(originalMessage, evidence, attributionEnabled),
|
|
529
|
-
},
|
|
530
|
-
requireWorkspaceChanges: true,
|
|
531
|
-
commitAttribution: { enabled: attributionEnabled, evidence },
|
|
532
|
-
}
|
|
533
|
-
: {}),
|
|
534
|
-
});
|
|
535
|
-
if (step.verification === true) validationFresh = outcome.report.passed;
|
|
536
|
-
const recordPath = await writeCodeStepRecord(fleetRootId, outcome.record);
|
|
537
|
-
if (json) process.stdout.write(`${JSON.stringify({ codeStep: outcome.record })}\n`);
|
|
538
|
-
else
|
|
539
|
-
process.stdout.write(
|
|
540
|
-
`step ${step.id} code:${command.id}: ${outcome.report.passed ? "passed" : "failed"} exit=${outcome.report.exitCode} ${outcome.record.durationMs}ms record=${recordPath}\n`,
|
|
541
|
-
);
|
|
542
|
-
return {
|
|
543
|
-
stepId: step.id,
|
|
544
|
-
assignmentId: outcome.record.runId,
|
|
545
|
-
terminalRunId: outcome.record.runId,
|
|
546
|
-
receiptDigest: outcome.record.reportDigest,
|
|
547
|
-
output: outcome.output,
|
|
548
|
-
succeeded: outcome.report.passed,
|
|
549
|
-
// The runner authored this report itself, so its provenance is
|
|
550
|
-
// valid by construction; only the command's verdict can be red.
|
|
551
|
-
integrityValid: true,
|
|
552
|
-
};
|
|
553
|
-
},
|
|
554
|
-
async decideLoop({ loop, step, attempt, terminalAttempt, result }) {
|
|
555
|
-
// Reuse the coordinator's existing review policy verbatim: pass ends
|
|
556
|
-
// the loop, a failure with attempts left earns one repair, and the
|
|
557
|
-
// same failure at the bound is simply the terminal answer. `revise`
|
|
558
|
-
// is never a verdict the reviewed model authors.
|
|
559
|
-
const decider = receiptsByStep.get(step.id);
|
|
560
|
-
// The subject is the work under review: the most recent agent run
|
|
561
|
-
// upstream of this verification. A direct dependency is not enough,
|
|
562
|
-
// because a loop's declared dependency is another loop's
|
|
563
|
-
// deterministic check, which produced no receipt at all.
|
|
564
|
-
const ancestors = executionPlanAncestors(plan, step.id);
|
|
565
|
-
let subject: RunReceipt | undefined;
|
|
566
|
-
for (const [stepId, receipt] of receiptsByStep) {
|
|
567
|
-
if (ancestors.has(stepId)) subject = receipt;
|
|
441
|
+
if (step.receipt !== undefined) {
|
|
442
|
+
if (json) process.stdout.write(`${JSON.stringify(step.receipt)}\n`);
|
|
443
|
+
else
|
|
444
|
+
process.stdout.write(
|
|
445
|
+
`step ${step.stepId} ${step.agentId}: ${step.succeeded ? "succeeded" : "failed"}${step.failureReason !== undefined ? ` reason=${step.failureReason}` : ""} assignment=${step.assignmentId} terminal-run=${step.terminalRunId} cost=$${step.costUsd.toFixed(4)}\n`,
|
|
446
|
+
);
|
|
447
|
+
return;
|
|
568
448
|
}
|
|
569
|
-
if (
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
449
|
+
if (step.codeStep !== undefined) {
|
|
450
|
+
if (json) process.stdout.write(`${JSON.stringify({ codeStep: step.codeStep })}\n`);
|
|
451
|
+
else
|
|
452
|
+
process.stdout.write(
|
|
453
|
+
`step ${step.stepId} code:${step.commandId}: ${step.succeeded ? "passed" : "failed"} exit=${step.codeStep.exitCode} ${step.codeStep.durationMs}ms record=${step.recordPath}\n`,
|
|
454
|
+
);
|
|
575
455
|
}
|
|
576
|
-
const correlation = fleetGateCorrelation(subject, decider);
|
|
577
|
-
const decided = decideReviewGate({
|
|
578
|
-
group: `${fleetRootId}:${loop.id}`,
|
|
579
|
-
cycle: attempt,
|
|
580
|
-
terminalCycle: terminalAttempt,
|
|
581
|
-
subjects: [{ runId: subject.runId, digest: subject.integrity.digest }],
|
|
582
|
-
decider: { runId: decider.runId, digest: decider.integrity.digest },
|
|
583
|
-
correlation,
|
|
584
|
-
output: result.output,
|
|
585
|
-
});
|
|
586
|
-
independentReviewFresh = decided.verdict === "pass" && correlation.independent;
|
|
587
|
-
const staged = stagePendingGateDecision(decided.draft);
|
|
588
|
-
const { path: decisionPath } = materializePendingGateDecision(staged);
|
|
589
|
-
if (!json) {
|
|
590
|
-
process.stdout.write(
|
|
591
|
-
`loop ${loop.id} cycle ${attempt}: ${decided.draft.outcome}${decided.draft.detail === undefined ? "" : ` (${decided.draft.detail})`} decision=${decisionPath}\n`,
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
return {
|
|
595
|
-
resolved: decided.verdict === "pass",
|
|
596
|
-
findings: decided.findings,
|
|
597
|
-
needsDecision: decided.needsDecision,
|
|
598
|
-
};
|
|
599
|
-
},
|
|
600
|
-
beginWriteBoundary: (window, stepIds) => boundaryEnforcer.begin(window, stepIds),
|
|
601
|
-
verifyWriteBoundary: (window, stepIds) => boundaryEnforcer.verify(window, stepIds),
|
|
602
|
-
cancel: (assignmentId) => dispatch.abort(assignmentId),
|
|
603
|
-
release: (ownerId) => {
|
|
604
|
-
if (ownerId === NO_WORKER_RESERVATION) return;
|
|
605
|
-
dispatch.reservations?.rollbackUnconsumed(ownerId);
|
|
606
456
|
},
|
|
607
|
-
|
|
608
|
-
if (
|
|
609
|
-
|
|
457
|
+
onNotice(text, kind) {
|
|
458
|
+
if (kind === "write-boundary") process.stderr.write(`${text}\n`);
|
|
459
|
+
else if (kind === "gate" && !json) process.stdout.write(`${text}\n`);
|
|
610
460
|
},
|
|
611
461
|
});
|
|
612
462
|
} catch (err) {
|
|
@@ -616,53 +466,40 @@ async function runFleet(args: ReadonlyArray<string>): Promise<number> {
|
|
|
616
466
|
}
|
|
617
467
|
await dispatch.drain();
|
|
618
468
|
await loaded.stop();
|
|
619
|
-
|
|
620
|
-
// verification that a later attempt fixed is the loop working as declared,
|
|
621
|
-
// and a node a resolved loop made unnecessary never had to run at all.
|
|
622
|
-
const required = plan.steps.filter((step) => step.loop === undefined && !planOutcome.unneeded.includes(step.id));
|
|
623
|
-
const failedLoops = planOutcome.loops.filter((loop) => !loop.resolved);
|
|
624
|
-
const succeededSteps = required.filter((step) => planOutcome.results.get(step.id)?.succeeded === true).length;
|
|
625
|
-
const resolvedLoops = planOutcome.loops.length - failedLoops.length;
|
|
469
|
+
|
|
626
470
|
if (json) {
|
|
627
471
|
process.stdout.write(
|
|
628
472
|
`${JSON.stringify({
|
|
629
473
|
fleet: contract.name,
|
|
630
474
|
rootId: fleetRootId,
|
|
631
475
|
planHash: plan.hash,
|
|
632
|
-
loops:
|
|
633
|
-
revalidated:
|
|
634
|
-
unneeded:
|
|
635
|
-
skipped:
|
|
636
|
-
needsDecision:
|
|
637
|
-
writeBoundaries:
|
|
476
|
+
loops: outcome.result.loops,
|
|
477
|
+
revalidated: outcome.result.revalidated,
|
|
478
|
+
unneeded: outcome.result.unneeded,
|
|
479
|
+
skipped: outcome.result.skipped,
|
|
480
|
+
needsDecision: outcome.result.needsDecision,
|
|
481
|
+
writeBoundaries: outcome.result.writeBoundaries,
|
|
638
482
|
})}\n`,
|
|
639
483
|
);
|
|
640
484
|
} else {
|
|
641
|
-
const spentUsd = receipts.reduce((sum, receipt) => sum + receipt.costUsd, 0);
|
|
642
485
|
process.stdout.write(
|
|
643
|
-
`fleet ${contract.name}: ${
|
|
486
|
+
`fleet ${contract.name}: ${outcome.succeededStepCount}/${outcome.requiredStepCount} steps succeeded, ${outcome.resolvedLoopCount}/${outcome.result.loops.length} loops resolved, total cost $${outcome.totalCostUsd.toFixed(4)}\n`,
|
|
644
487
|
);
|
|
645
|
-
for (const loop of
|
|
488
|
+
for (const loop of outcome.result.loops)
|
|
646
489
|
process.stdout.write(
|
|
647
490
|
` loop ${loop.loopId}: ${loop.reason} after ${loop.attempts} verification(s) and ${loop.repairs} repair(s)\n`,
|
|
648
491
|
);
|
|
649
|
-
|
|
650
|
-
if (planOutcome.revalidated.length > 0) {
|
|
492
|
+
if (outcome.result.revalidated.length > 0)
|
|
651
493
|
process.stdout.write(
|
|
652
|
-
` staleness: re-ran ${
|
|
494
|
+
` staleness: re-ran ${outcome.result.revalidated.join(", ")} because a workspace step landed after the last green\n`,
|
|
653
495
|
);
|
|
654
|
-
}
|
|
655
|
-
for (const
|
|
656
|
-
for (const boundary of planOutcome.writeBoundaries) {
|
|
496
|
+
for (const message of outcome.result.needsDecision) process.stdout.write(` needs operator decision: ${message}\n`);
|
|
497
|
+
for (const boundary of outcome.result.writeBoundaries) {
|
|
657
498
|
if (!boundary.violated) continue;
|
|
658
499
|
process.stdout.write(` write boundary ${boundary.window}: ${boundary.detail ?? WRITE_BOUNDARY_VIOLATION_REASON}\n`);
|
|
659
500
|
}
|
|
660
501
|
}
|
|
661
|
-
|
|
662
|
-
failedLoops.length === 0 &&
|
|
663
|
-
planOutcome.skipped.length === 0 &&
|
|
664
|
-
required.every((step) => planOutcome.results.get(step.id)?.succeeded === true);
|
|
665
|
-
return cleanRun ? 0 : 1;
|
|
502
|
+
return outcome.cleanRun ? 0 : 1;
|
|
666
503
|
}
|
|
667
504
|
|
|
668
505
|
// ---------------------------------------------------------------------------
|
|
@@ -740,6 +577,7 @@ export function statusSnapshot(): {
|
|
|
740
577
|
return {
|
|
741
578
|
runId: row.id,
|
|
742
579
|
agentId: row.agentId,
|
|
580
|
+
budget: row.budget ?? null,
|
|
743
581
|
runtimeKind: row.runtimeKind,
|
|
744
582
|
outcomePhase: row.status,
|
|
745
583
|
heartbeat: rowHeartbeat(row),
|
|
@@ -798,6 +636,13 @@ function runStatus(args: ReadonlyArray<string>): number {
|
|
|
798
636
|
process.stdout.write(
|
|
799
637
|
` ${row.runId} ${row.agentId} node=${row.node} ${row.heartbeat} attempt=${lineage.attempt} depth=${lineage.depth} ${Math.round((row.elapsedMs as number) / 1000)}s $${(row.costUsd as number).toFixed(4)}\n`,
|
|
800
638
|
);
|
|
639
|
+
const budget = row.budget as RunToolBudgetEnvelope | null;
|
|
640
|
+
if (budget !== null) {
|
|
641
|
+
process.stdout.write(` recipe policy: ${formatBudgetPolicy(budget)}\n`);
|
|
642
|
+
process.stdout.write(` requested envelope: ${formatBudgetRequest(budget)}\n`);
|
|
643
|
+
process.stdout.write(` effective envelope: ${formatEffectiveBudget(budget)}\n`);
|
|
644
|
+
process.stdout.write(` clamp or escalation reason: ${formatBudgetReasons(budget)}\n`);
|
|
645
|
+
}
|
|
801
646
|
}
|
|
802
647
|
}
|
|
803
648
|
if (snapshot.retrying.length === 0) {
|
|
@@ -852,6 +697,14 @@ export async function runFleetCommand(args: ReadonlyArray<string>): Promise<numb
|
|
|
852
697
|
switch (sub) {
|
|
853
698
|
case "list":
|
|
854
699
|
return runList(args.slice(1));
|
|
700
|
+
case "new":
|
|
701
|
+
return (await import("./fleet-new.js")).runFleetNew(args.slice(1));
|
|
702
|
+
case "validate":
|
|
703
|
+
return (await import("./fleet-validate.js")).runFleetValidate(args.slice(1));
|
|
704
|
+
case "graph":
|
|
705
|
+
return (await import("./fleet-graph.js")).runFleetGraph(args.slice(1));
|
|
706
|
+
case "commands":
|
|
707
|
+
return (await import("./fleet-commands.js")).runFleetCommands(args.slice(1));
|
|
855
708
|
case "run":
|
|
856
709
|
return runFleet(args.slice(1));
|
|
857
710
|
case "status":
|