@iowarp/clio-coder 0.3.0 → 0.3.1
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 +33 -0
- package/README.md +50 -53
- package/dist/acp-FPR54DGL.js +138 -0
- package/dist/{agents-Q4MYPMUW.js → agents-OGPIHPJH.js} +33 -25
- package/dist/assets/codewiki.json +1 -0
- package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/LICENSE +21 -0
- package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/cgmanifest.json +16 -0
- package/dist/assets/grammars/notices/tree-sitter-wasms/LICENSE +24 -0
- package/dist/assets/grammars/tree-sitter-c-sharp.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-c.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-cpp.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-go.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-java.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-javascript.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-python.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-ruby.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-rust.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/assets/grammars/tree-sitter.wasm +0 -0
- package/dist/{auth-O6HYIJ6J.js → auth-IC3K6NIZ.js} +22 -15
- package/dist/{chunk-KKKPTZLM.js → chunk-2STGEDFV.js} +8 -1
- package/dist/chunk-3I7MS7N2.js +40 -0
- package/dist/chunk-3R73A4XB.js +69 -0
- package/dist/{chunk-26BZQOAD.js → chunk-474KN5II.js} +86 -115
- package/dist/{chunk-NI4DEJMC.js → chunk-4QKXUHSR.js} +26 -3
- package/dist/{chunk-X3BR7HWV.js → chunk-5WIGXA4T.js} +7 -1
- package/dist/{chunk-TFSSEXL6.js → chunk-673JJUWJ.js} +14 -4
- package/dist/{chunk-GNGDQYDU.js → chunk-7SS2CTV2.js} +27922 -1249
- package/dist/{chunk-7RBKDI66.js → chunk-ASND7OZK.js} +104 -12
- package/dist/{chunk-X3NE4WVW.js → chunk-BNAZZHFG.js} +7 -1
- package/dist/{chunk-RQDWMVRB.js → chunk-BSU2YIWB.js} +9 -3
- package/dist/{chunk-CLJ5HLUD.js → chunk-C4PTHK7P.js} +24 -5
- package/dist/{chunk-QV47YRF4.js → chunk-CGKSTWHD.js} +7 -1
- package/dist/{chunk-BYEU76JP.js → chunk-DKGKUHFA.js} +34 -9
- package/dist/chunk-EYOKLTMF.js +170 -0
- package/dist/{chunk-PS4PFJQP.js → chunk-FCIH3BIZ.js} +15258 -14130
- package/dist/{chunk-2J63S4SF.js → chunk-FST4FYJB.js} +82 -14
- package/dist/{chunk-3DANZDGR.js → chunk-G34LV2PF.js} +34 -9
- package/dist/{chunk-BBUH4VAA.js → chunk-GAEBEQVI.js} +34 -21
- package/dist/chunk-GB6QRBXN.js +8543 -0
- package/dist/chunk-GEP36Y4X.js +12796 -0
- package/dist/{chunk-TKHQ4DGZ.js → chunk-H6F6BYOH.js} +496 -121
- package/dist/{chunk-UGYAX5YI.js → chunk-HQQID6OA.js} +10 -5
- package/dist/chunk-IHXBNWMM.js +137 -0
- package/dist/{chunk-ME6DNWIU.js → chunk-IS3ONKU3.js} +7 -1
- package/dist/{chunk-DXQNI4PC.js → chunk-IWHMRKLL.js} +8 -1
- package/dist/chunk-K2ITRMHZ.js +642 -0
- package/dist/{chunk-KBR4MZZR.js → chunk-K5XEMXTI.js} +7 -1
- package/dist/{chunk-AMFR5YA3.js → chunk-KKNLWXI6.js} +24 -10
- package/dist/{chunk-JWHCJDCI.js → chunk-KY56HMHH.js} +145 -61
- package/dist/{chunk-E3NYWENM.js → chunk-LU4TK2PR.js} +52 -7
- package/dist/{chunk-UWIJNAOB.js → chunk-M5T5VO65.js} +109 -42
- package/dist/{chunk-JPOWPFCU.js → chunk-MAR7Y6HW.js} +38 -16
- package/dist/chunk-N6F52NLF.js +6951 -0
- package/dist/{chunk-UHTSULZS.js → chunk-NMOX6HFD.js} +20 -7
- package/dist/{chunk-WD6AJM35.js → chunk-OLBBMFRD.js} +30 -13
- package/dist/{chunk-VOO7NYPP.js → chunk-PFEFKVGL.js} +22 -6
- package/dist/{chunk-6CWDTGUC.js → chunk-PIUMUEMV.js} +7 -1
- package/dist/chunk-PV4JUBVJ.js +462 -0
- package/dist/{chunk-527KG6XR.js → chunk-Q3RUPKEJ.js} +22 -4
- package/dist/{chunk-D5YD55AR.js → chunk-Q5WJOSJ7.js} +11 -1
- package/dist/{chunk-5N2FG33Q.js → chunk-R346GLFC.js} +7 -1
- package/dist/{chunk-4UQA7NCT.js → chunk-R5KLMSBV.js} +7 -2
- package/dist/{chunk-PIDUD6M2.js → chunk-RDLVBZEO.js} +11 -6
- package/dist/{chunk-O4EJEDHO.js → chunk-RPTR2H26.js} +40 -31
- package/dist/{chunk-HBU5MTAM.js → chunk-SVNXH4L2.js} +7 -1
- package/dist/{chunk-XNISANGE.js → chunk-TEKV33Q5.js} +122 -57
- package/dist/chunk-TXOTCRLG.js +15 -0
- package/dist/{chunk-VPAWTYLY.js → chunk-WEPFGWHJ.js} +7 -1
- package/dist/{chunk-HMYNFFY4.js → chunk-XPLRXC72.js} +7 -2
- package/dist/{chunk-UU3R62TT.js → chunk-XYWBQRDM.js} +13 -4
- package/dist/{chunk-7BHLZB3A.js → chunk-ZPY3JZ5E.js} +32 -10
- package/dist/cli/index.js +39 -33
- package/dist/clio-BZVGEUFJ.js +58 -0
- package/dist/{components-JVHMUBEB.js → components-DMAOEKFB.js} +26 -9
- package/dist/{config-ZFCDBMDC.js → config-IRUQ7SE4.js} +42 -31
- package/dist/configure-S7S6F6CL.js +32 -0
- package/dist/{context-CDXTP2MP.js → context-3KWFLHJG.js} +17 -11
- package/dist/{context-E3KIFVXI.js → context-5RADCKTR.js} +33 -28
- package/dist/{context-clear-3F4PLXOS.js → context-clear-7TSNPAAI.js} +36 -28
- package/dist/{context-index-Q7YSYTR3.js → context-index-W4RLWOQH.js} +10 -4
- package/dist/{docs-YIETIWZI.js → docs-5AWSPS37.js} +16 -10
- package/dist/doctor-UC5NAJYQ.js +77 -0
- package/dist/{eval-B3KZZESM.js → eval-U6TJHRLX.js} +77 -24
- package/dist/{evidence-V67CHM35.js → evidence-YEGUW4L3.js} +34 -26
- package/dist/{evolve-YDZSUQYA.js → evolve-TXARCTPG.js} +39 -26
- package/dist/{extensions-SRG7XCAH.js → extensions-OZFJ3A3G.js} +13 -7
- package/dist/{fleet-CA2CRTVG.js → fleet-6G3DHNYE.js} +45 -37
- package/dist/fleet-preflight-DSNT37JK.js +23 -0
- package/dist/{init-2OZDJE2D.js → init-KZ5QTF6M.js} +42 -34
- package/dist/{memory-3PIQQAKX.js → memory-73ESV5YC.js} +35 -27
- package/dist/{models-DY35XI7Y.js → models-A4PVNWJK.js} +34 -23
- package/dist/{paths-5OMXW7Z4.js → paths-C4H6IV77.js} +12 -6
- package/dist/preload-6WVMHX3A.js +13 -0
- package/dist/{reset-PIFYNOS3.js → reset-BGW6OGMV.js} +17 -11
- package/dist/{run-3VSPP24F.js → run-YTPEYQOH.js} +60 -48
- package/dist/{share-D36RQCXM.js → share-YIFFV4NQ.js} +16 -10
- package/dist/{skills-F2MRLELY.js → skills-2V6RA3OQ.js} +18 -11
- package/dist/{skills-eval-E2ZTW4PL.js → skills-eval-S2TVJO4F.js} +45 -36
- package/dist/{targets-DZMEZAH4.js → targets-TYXLPB23.js} +61 -59
- package/dist/{trace-7NYCUI2J.js → trace-GGOJ6Q6Z.js} +9 -3
- package/dist/{uninstall-AD3JWHBB.js → uninstall-LLLT4F4W.js} +14 -8
- package/dist/{upgrade-WYYBKGDY.js → upgrade-33G2LMM5.js} +45 -23
- package/dist/{usage-ULIDAGFF.js → usage-ZAFSXKKG.js} +35 -27
- package/dist/version-KGEG7EPO.js +21 -0
- package/dist/{wiki-generate-PKFIX6OB.js → wiki-generate-NUQCVOQ3.js} +55 -45
- package/dist/worker/entry.js +101 -43
- package/docs/README.md +12 -9
- package/docs/acp.md +28 -5
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +23 -2
- package/docs/artifact-placement.md +101 -0
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +4 -2
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +125 -41
- package/docs/configuration-and-targets.md +88 -18
- package/docs/context-engine.md +6 -2
- package/docs/development-pipeline.md +77 -0
- package/docs/documentation-coverage.md +4 -4
- package/docs/documentation-guide.md +3 -3
- package/docs/environment-variables.md +2 -1
- package/docs/eval-runner.md +3 -3
- package/docs/evals-internal.md +2 -2
- package/docs/evidence-and-memory.md +6 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +18 -11
- package/docs/fleet-demo-runbook.md +22 -23
- package/docs/fleet-dispatch.md +111 -12
- package/docs/glossary.md +107 -15
- package/docs/html/agents_blueprint.html +3 -3
- package/docs/html/alcf_blueprint.html +3 -3
- package/docs/html/architecture_blueprint.html +3 -3
- package/docs/html/commands_blueprint.html +187 -42
- package/docs/html/configuration_blueprint.html +7 -7
- package/docs/html/context_blueprint.html +3 -3
- package/docs/html/documentation_blueprint.html +1 -1
- package/docs/html/environment_blueprint.html +3 -3
- package/docs/html/eval_blueprint.html +4 -4
- package/docs/html/evals_internal_blueprint.html +3 -3
- package/docs/html/evolution_blueprint.html +3 -3
- package/docs/html/extensions_blueprint.html +3 -3
- package/docs/html/fleet_dispatch_blueprint.html +8 -8
- package/docs/html/index.html +5 -5
- package/docs/html/lifecycle_blueprint.html +4 -4
- package/docs/html/memory_blueprint.html +3 -3
- package/docs/html/middleware_blueprint.html +3 -3
- package/docs/html/models_blueprint.html +2 -2
- package/docs/html/observability_blueprint.html +2 -2
- package/docs/html/provider_adapter_blueprint.html +3 -3
- package/docs/html/safety_blueprint.html +3 -3
- package/docs/html/skills_blueprint.html +2 -2
- package/docs/html/soak_blueprint.html +3 -3
- package/docs/html/tool_usage_blueprint.html +4 -4
- package/docs/html/tools_blueprint.html +2 -2
- package/docs/html/trace_blueprint.html +3 -3
- package/docs/html/tui_design_blueprint.html +100 -40
- package/docs/html/validation_blueprint.html +1 -1
- package/docs/html/worker_dispatch_blueprint.html +3 -3
- package/docs/installation-and-lifecycle.md +62 -11
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +2 -2
- package/docs/observability.md +3 -3
- package/docs/proactive-memory.md +12 -12
- package/docs/prompt-envelope-and-tools.md +2 -2
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +4 -0
- package/docs/safety-model.md +21 -5
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +2 -2
- package/docs/skills-marketplace.md +1 -1
- package/docs/time-conventions.md +101 -0
- package/docs/tool-usage.md +5 -4
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +83 -27
- package/docs/worker-dispatch-mechanics.md +3 -3
- package/package.json +16 -16
- package/skills/README.md +5 -6
- package/skills/git/file-ticket/SKILL.md +107 -0
- package/skills/git/file-ticket/evals.md +54 -0
- package/skills/git/fix-issue/SKILL.md +106 -0
- package/skills/git/fix-issue/evals.md +71 -0
- package/skills/git/ship/SKILL.md +92 -0
- package/skills/git/ship/evals.md +72 -0
- package/skills/skill-marketplace.json +12 -20
- package/src/cli/acp.ts +88 -0
- package/src/cli/agents.ts +60 -0
- package/src/cli/args.ts +280 -0
- package/src/cli/argv.ts +170 -0
- package/src/cli/ask.ts +34 -0
- package/src/cli/auth.ts +468 -0
- package/src/cli/bootstrap-generate.ts +498 -0
- package/src/cli/clio.ts +34 -0
- package/src/cli/components.ts +195 -0
- package/src/cli/config-inspect.ts +330 -0
- package/src/cli/config.ts +72 -0
- package/src/cli/configure-interop.ts +67 -0
- package/src/cli/configure-layout.ts +172 -0
- package/src/cli/configure.ts +1487 -0
- package/src/cli/context-clear.ts +76 -0
- package/src/cli/context-index.ts +102 -0
- package/src/cli/context.ts +316 -0
- package/src/cli/default-target.ts +63 -0
- package/src/cli/docs.ts +340 -0
- package/src/cli/doctor.ts +54 -0
- package/src/cli/eval.ts +315 -0
- package/src/cli/evidence.ts +222 -0
- package/src/cli/evolve.ts +219 -0
- package/src/cli/extensions.ts +205 -0
- package/src/cli/fleet.ts +827 -0
- package/src/cli/index.ts +309 -0
- package/src/cli/init.ts +219 -0
- package/src/cli/initial-message.ts +47 -0
- package/src/cli/internal-dispatch.ts +55 -0
- package/src/cli/memory.ts +180 -0
- package/src/cli/models.ts +257 -0
- package/src/cli/modes/json-stream.ts +85 -0
- package/src/cli/modes/jsonl.ts +9 -0
- package/src/cli/modes/print.ts +589 -0
- package/src/cli/oauth-manual-input.ts +72 -0
- package/src/cli/oauth-select.ts +36 -0
- package/src/cli/output-guard.ts +48 -0
- package/src/cli/paths.ts +44 -0
- package/src/cli/provider-target.ts +113 -0
- package/src/cli/removal.ts +72 -0
- package/src/cli/reset.ts +253 -0
- package/src/cli/run.ts +497 -0
- package/src/cli/share.ts +243 -0
- package/src/cli/shared.ts +60 -0
- package/src/cli/skills-eval.ts +1225 -0
- package/src/cli/skills.ts +470 -0
- package/src/cli/steer-channel.ts +86 -0
- package/src/cli/targets.ts +1150 -0
- package/src/cli/text-layout.ts +102 -0
- package/src/cli/trace.ts +274 -0
- package/src/cli/uninstall.ts +405 -0
- package/src/cli/upgrade.ts +270 -0
- package/src/cli/usage.ts +869 -0
- package/src/cli/validate-model.ts +28 -0
- package/src/cli/version.ts +7 -0
- package/src/cli/wiki-generate.ts +509 -0
- package/src/core/artifact-paths.ts +43 -0
- package/src/core/bash-exec.ts +242 -0
- package/src/core/boot-trace.ts +37 -0
- package/src/core/bus-events.ts +728 -0
- package/src/core/bus-trace.ts +53 -0
- package/src/core/c-header-language.ts +265 -0
- package/src/core/clio-repo.ts +78 -0
- package/src/core/config.ts +1593 -0
- package/src/core/context-floor.ts +33 -0
- package/src/core/defaults.ts +625 -0
- package/src/core/domain-loader.ts +170 -0
- package/src/core/event-bus.ts +94 -0
- package/src/core/file-references.ts +282 -0
- package/src/core/guardrails.ts +185 -0
- package/src/core/headless-permission.ts +21 -0
- package/src/core/init.ts +223 -0
- package/src/core/json-payload.ts +58 -0
- package/src/core/package-root.ts +54 -0
- package/src/core/path-canonical.ts +37 -0
- package/src/core/process-identity.ts +41 -0
- package/src/core/recent-models.ts +91 -0
- package/src/core/release.ts +2 -0
- package/src/core/residency-protection.ts +56 -0
- package/src/core/resolve-config-value.ts +88 -0
- package/src/core/response-schema.ts +279 -0
- package/src/core/run-overrides.ts +77 -0
- package/src/core/safe-exec.ts +193 -0
- package/src/core/safe-id.ts +37 -0
- package/src/core/safe-resource-write.ts +162 -0
- package/src/core/session-routing.ts +339 -0
- package/src/core/settings-layers.ts +220 -0
- package/src/core/shared-bus.ts +8 -0
- package/src/core/shell-quote.ts +26 -0
- package/src/core/skill-activation.ts +190 -0
- package/src/core/startup-timer.ts +37 -0
- package/src/core/state-file-lock.ts +207 -0
- package/src/core/termination.ts +202 -0
- package/src/core/timers.ts +38 -0
- package/src/core/tool-names.ts +65 -0
- package/src/core/verification-scripts.ts +13 -0
- package/src/core/workspace-files.ts +492 -0
- package/src/core/xdg.ts +177 -0
- package/src/domains/agents/builtins/architect.md +4 -4
- package/src/domains/agents/builtins/coder.md +3 -2
- package/src/domains/agents/builtins/debugger.md +1 -1
- package/src/domains/agents/builtins/documenter.md +1 -1
- package/src/domains/agents/builtins/git-master.md +3 -3
- package/src/domains/agents/builtins/provenance.md +1 -1
- package/src/domains/agents/builtins/researcher.md +1 -1
- package/src/domains/agents/builtins/scout.md +1 -1
- package/src/domains/agents/builtins/tester.md +1 -1
- package/src/domains/agents/builtins/verifier.md +1 -1
- package/src/domains/agents/builtins/wiki-writer.md +1 -1
- package/src/domains/agents/catalog.ts +172 -0
- package/src/domains/agents/contract.ts +16 -0
- package/src/domains/agents/extension.ts +110 -0
- package/src/domains/agents/fleet-commands.ts +154 -0
- package/src/domains/agents/fleet-contract.ts +797 -0
- package/src/domains/agents/frontmatter.ts +40 -0
- package/src/domains/agents/index.ts +102 -0
- package/src/domains/agents/manifest.ts +6 -0
- package/src/domains/agents/recipe-schema.ts +202 -0
- package/src/domains/agents/recipe.ts +125 -0
- package/src/domains/agents/registry.ts +111 -0
- package/src/domains/agents/result-contract.ts +1265 -0
- package/src/domains/agents/spec.ts +371 -0
- package/src/domains/agents/write-boundary.ts +109 -0
- package/src/domains/components/diff.ts +99 -0
- package/src/domains/components/hash.ts +21 -0
- package/src/domains/components/index.ts +3 -0
- package/src/domains/components/scan.ts +304 -0
- package/src/domains/components/snapshot.ts +108 -0
- package/src/domains/components/types.ts +82 -0
- package/src/domains/config/agent-namespace.ts +13 -0
- package/src/domains/config/classify.ts +94 -0
- package/src/domains/config/contract.ts +22 -0
- package/src/domains/config/extension.ts +136 -0
- package/src/domains/config/index.ts +13 -0
- package/src/domains/config/keybindings.ts +164 -0
- package/src/domains/config/manifest.ts +6 -0
- package/src/domains/config/watcher.ts +41 -0
- package/src/domains/context/adoption.ts +880 -0
- package/src/domains/context/bootstrap-prompt.ts +273 -0
- package/src/domains/context/bootstrap.ts +1409 -0
- package/src/domains/context/clear.ts +86 -0
- package/src/domains/context/clio-md.ts +327 -0
- package/src/domains/context/codewiki/cmake.ts +356 -0
- package/src/domains/context/codewiki/cooperative.ts +46 -0
- package/src/domains/context/codewiki/digest.ts +135 -0
- package/src/domains/context/codewiki/grammar-assets.ts +33 -0
- package/src/domains/context/codewiki/indexer.ts +1614 -0
- package/src/domains/context/codewiki/tree-sitter.ts +771 -0
- package/src/domains/context/contract.ts +62 -0
- package/src/domains/context/excluded-dirs.ts +1 -0
- package/src/domains/context/extension.ts +407 -0
- package/src/domains/context/fingerprint.ts +196 -0
- package/src/domains/context/index.ts +164 -0
- package/src/domains/context/init-options.ts +69 -0
- package/src/domains/context/manifest.ts +6 -0
- package/src/domains/context/operator-profile.ts +157 -0
- package/src/domains/context/project-metadata.ts +510 -0
- package/src/domains/context/project-rules.ts +227 -0
- package/src/domains/context/prompt-context.ts +62 -0
- package/src/domains/context/refresh.ts +170 -0
- package/src/domains/context/sibling-files.ts +10 -0
- package/src/domains/context/state.ts +237 -0
- package/src/domains/context/wiki/assemble.ts +303 -0
- package/src/domains/context/wiki/frontmatter.ts +210 -0
- package/src/domains/context/wiki/generate.ts +590 -0
- package/src/domains/context/wiki/layout.ts +111 -0
- package/src/domains/context/wiki/meta.ts +221 -0
- package/src/domains/context/wiki/plan-store.ts +217 -0
- package/src/domains/context/wiki/plan.ts +250 -0
- package/src/domains/context/wiki/prompts.ts +270 -0
- package/src/domains/context/wiki/staleness.ts +198 -0
- package/src/domains/dispatch/active-route-planner.ts +168 -0
- package/src/domains/dispatch/admission-queue.ts +150 -0
- package/src/domains/dispatch/admission.ts +334 -0
- package/src/domains/dispatch/agent-candidates.ts +307 -0
- package/src/domains/dispatch/agent-ledger-hub.ts +71 -0
- package/src/domains/dispatch/agent-ledger-store.ts +257 -0
- package/src/domains/dispatch/agent-ledger.ts +212 -0
- package/src/domains/dispatch/agent-plan-adapter.ts +85 -0
- package/src/domains/dispatch/assignment-events.ts +132 -0
- package/src/domains/dispatch/assignment-reconcile.ts +76 -0
- package/src/domains/dispatch/assignment-store.ts +162 -0
- package/src/domains/dispatch/assignment.ts +278 -0
- package/src/domains/dispatch/backoff.ts +59 -0
- package/src/domains/dispatch/batch-store.ts +134 -0
- package/src/domains/dispatch/batch-tracker.ts +66 -0
- package/src/domains/dispatch/capability-match.ts +155 -0
- package/src/domains/dispatch/capacity-lease.ts +413 -0
- package/src/domains/dispatch/code-step-store.ts +52 -0
- package/src/domains/dispatch/code-step.ts +368 -0
- package/src/domains/dispatch/contract.ts +278 -0
- package/src/domains/dispatch/dedup.ts +133 -0
- package/src/domains/dispatch/event-pump.ts +251 -0
- package/src/domains/dispatch/execution-handoff.ts +29 -0
- package/src/domains/dispatch/execution-plan.ts +328 -0
- package/src/domains/dispatch/execution-role.ts +277 -0
- package/src/domains/dispatch/execution-scheduler.ts +583 -0
- package/src/domains/dispatch/extension.ts +5869 -0
- package/src/domains/dispatch/failure-classification.ts +141 -0
- package/src/domains/dispatch/fleet-plan.ts +225 -0
- package/src/domains/dispatch/fleet-preflight.ts +394 -0
- package/src/domains/dispatch/gate-decisions.ts +1040 -0
- package/src/domains/dispatch/gate-role-prompts.ts +58 -0
- package/src/domains/dispatch/heartbeat.ts +27 -0
- package/src/domains/dispatch/index.ts +137 -0
- package/src/domains/dispatch/joint-route-adapter.ts +114 -0
- package/src/domains/dispatch/joint-route-resolver.ts +283 -0
- package/src/domains/dispatch/manifest.ts +6 -0
- package/src/domains/dispatch/orphan-recovery.ts +224 -0
- package/src/domains/dispatch/outcome.ts +109 -0
- package/src/domains/dispatch/phase-timing.ts +47 -0
- package/src/domains/dispatch/placement.ts +202 -0
- package/src/domains/dispatch/receipt-findings.ts +255 -0
- package/src/domains/dispatch/receipt-integrity.ts +378 -0
- package/src/domains/dispatch/recovery-candidates.ts +74 -0
- package/src/domains/dispatch/reproducibility.ts +48 -0
- package/src/domains/dispatch/reservation-store.ts +501 -0
- package/src/domains/dispatch/route-approval.ts +177 -0
- package/src/domains/dispatch/route-candidates.ts +57 -0
- package/src/domains/dispatch/route-decision.ts +1079 -0
- package/src/domains/dispatch/route-facts.ts +187 -0
- package/src/domains/dispatch/route-history.ts +238 -0
- package/src/domains/dispatch/route-observer.ts +488 -0
- package/src/domains/dispatch/route-policy.ts +327 -0
- package/src/domains/dispatch/route-quality.ts +256 -0
- package/src/domains/dispatch/route-readiness.ts +120 -0
- package/src/domains/dispatch/routing-intent.ts +287 -0
- package/src/domains/dispatch/run-identity.ts +56 -0
- package/src/domains/dispatch/scout-transition.ts +130 -0
- package/src/domains/dispatch/state.ts +277 -0
- package/src/domains/dispatch/tool-stats.ts +132 -0
- package/src/domains/dispatch/transport.ts +209 -0
- package/src/domains/dispatch/types.ts +785 -0
- package/src/domains/dispatch/validation-grounding.ts +154 -0
- package/src/domains/dispatch/validation.ts +721 -0
- package/src/domains/dispatch/worker-protocol.ts +275 -0
- package/src/domains/dispatch/worker-spawn.ts +566 -0
- package/src/domains/dispatch/write-boundary-enforcer.ts +97 -0
- package/src/domains/dispatch/write-boundary.ts +426 -0
- package/src/domains/eval/artifacts/redact.ts +42 -0
- package/src/domains/eval/artifacts/store.ts +173 -0
- package/src/domains/eval/compare/compare.ts +33 -0
- package/src/domains/eval/compare/gates.ts +66 -0
- package/src/domains/eval/compare/thresholds.ts +92 -0
- package/src/domains/eval/harness-metrics.ts +62 -0
- package/src/domains/eval/index.ts +66 -0
- package/src/domains/eval/metrics/chaos-stream.ts +93 -0
- package/src/domains/eval/metrics/context.ts +34 -0
- package/src/domains/eval/metrics/coverage.ts +21 -0
- package/src/domains/eval/metrics/evidence.ts +182 -0
- package/src/domains/eval/metrics/fleet-loop-stream.ts +196 -0
- package/src/domains/eval/metrics/invariants.ts +736 -0
- package/src/domains/eval/metrics/latency.ts +4 -0
- package/src/domains/eval/metrics/token-stream.ts +139 -0
- package/src/domains/eval/metrics/tokens.ts +51 -0
- package/src/domains/eval/metrics/tool-calls.ts +7 -0
- package/src/domains/eval/proactive-memory.ts +279 -0
- package/src/domains/eval/provenance.ts +35 -0
- package/src/domains/eval/report.ts +234 -0
- package/src/domains/eval/reports/json.ts +5 -0
- package/src/domains/eval/reports/junit.ts +23 -0
- package/src/domains/eval/reports/markdown.ts +20 -0
- package/src/domains/eval/reports/swe-jsonl.ts +16 -0
- package/src/domains/eval/reports/text.ts +25 -0
- package/src/domains/eval/run-compare.ts +274 -0
- package/src/domains/eval/runner.ts +244 -0
- package/src/domains/eval/runners/clio-run.ts +148 -0
- package/src/domains/eval/runners/context-index.ts +56 -0
- package/src/domains/eval/runners/context-init.ts +203 -0
- package/src/domains/eval/runners/external-command.ts +350 -0
- package/src/domains/eval/runtime-paths.ts +171 -0
- package/src/domains/eval/schema/artifact.ts +75 -0
- package/src/domains/eval/schema/suite.ts +235 -0
- package/src/domains/eval/schema/validate.ts +339 -0
- package/src/domains/eval/store.ts +392 -0
- package/src/domains/eval/suites/load.ts +74 -0
- package/src/domains/eval/suites/matrix.ts +19 -0
- package/src/domains/eval/suites/resolve.ts +44 -0
- package/src/domains/eval/suites/run.ts +325 -0
- package/src/domains/eval/task-file.ts +186 -0
- package/src/domains/eval/types.ts +141 -0
- package/src/domains/eval/verifiers/command.ts +27 -0
- package/src/domains/eval/verifiers/file-exists.ts +6 -0
- package/src/domains/eval/verifiers/patch.ts +22 -0
- package/src/domains/eval/workspaces/git.ts +41 -0
- package/src/domains/eval/workspaces/local.ts +17 -0
- package/src/domains/eval/workspaces/temp-copy.ts +29 -0
- package/src/domains/evidence/build.ts +1714 -0
- package/src/domains/evidence/eval.ts +605 -0
- package/src/domains/evidence/failure-attribution.ts +54 -0
- package/src/domains/evidence/finish-contract-map.ts +42 -0
- package/src/domains/evidence/index.ts +55 -0
- package/src/domains/evidence/provenance.ts +200 -0
- package/src/domains/evidence/redact.ts +81 -0
- package/src/domains/evidence/store.ts +291 -0
- package/src/domains/evidence/types.ts +325 -0
- package/src/domains/evolution/SELF_EDIT_GATE.md +91 -0
- package/src/domains/evolution/index.ts +26 -0
- package/src/domains/evolution/manifest.ts +154 -0
- package/src/domains/evolution/validate.ts +304 -0
- package/src/domains/extensions/contract.ts +22 -0
- package/src/domains/extensions/discovery.ts +193 -0
- package/src/domains/extensions/extension.ts +46 -0
- package/src/domains/extensions/index.ts +34 -0
- package/src/domains/extensions/manager.ts +30 -0
- package/src/domains/extensions/manifest.ts +6 -0
- package/src/domains/extensions/resources.ts +38 -0
- package/src/domains/extensions/state.ts +224 -0
- package/src/domains/extensions/types.ts +83 -0
- package/src/domains/interop/consent.ts +185 -0
- package/src/domains/interop/contract.ts +29 -0
- package/src/domains/interop/detect.ts +173 -0
- package/src/domains/interop/extension.ts +59 -0
- package/src/domains/interop/index.ts +34 -0
- package/src/domains/interop/manifest.ts +6 -0
- package/src/domains/interop/registry.ts +139 -0
- package/src/domains/interop/state.ts +92 -0
- package/src/domains/interop/types.ts +109 -0
- package/src/domains/lifecycle/contract.ts +11 -0
- package/src/domains/lifecycle/doctor.ts +536 -0
- package/src/domains/lifecycle/extension.ts +23 -0
- package/src/domains/lifecycle/index.ts +21 -0
- package/src/domains/lifecycle/install-method.ts +51 -0
- package/src/domains/lifecycle/manifest.ts +6 -0
- package/src/domains/lifecycle/migrations/index.ts +94 -0
- package/src/domains/lifecycle/state.ts +93 -0
- package/src/domains/lifecycle/upgrade-notice.ts +35 -0
- package/src/domains/lifecycle/version.ts +35 -0
- package/src/domains/memory/index.ts +128 -0
- package/src/domains/memory/operations.ts +143 -0
- package/src/domains/memory/prompt-section.ts +86 -0
- package/src/domains/memory/proposal.ts +180 -0
- package/src/domains/memory/store.ts +163 -0
- package/src/domains/memory/task-bank.ts +229 -0
- package/src/domains/memory/task-memory-handoff.ts +222 -0
- package/src/domains/memory/task-memory-policy.ts +602 -0
- package/src/domains/memory/task-memory-status.ts +58 -0
- package/src/domains/memory/task-memory-telemetry.ts +346 -0
- package/src/domains/memory/task-memory-trace.ts +89 -0
- package/src/domains/memory/types.ts +74 -0
- package/src/domains/memory/validate.ts +297 -0
- package/src/domains/middleware/budget.ts +216 -0
- package/src/domains/middleware/contract.ts +35 -0
- package/src/domains/middleware/dispatch-nudge.ts +469 -0
- package/src/domains/middleware/extension.ts +129 -0
- package/src/domains/middleware/hook-receipts.ts +70 -0
- package/src/domains/middleware/hooks-io.ts +174 -0
- package/src/domains/middleware/hooks.ts +432 -0
- package/src/domains/middleware/index.ts +154 -0
- package/src/domains/middleware/manifest.ts +6 -0
- package/src/domains/middleware/memory-intervention.ts +701 -0
- package/src/domains/middleware/rules.ts +42 -0
- package/src/domains/middleware/runtime.ts +333 -0
- package/src/domains/middleware/skills-reminder.ts +187 -0
- package/src/domains/middleware/snapshot.ts +71 -0
- package/src/domains/middleware/stalled-turn.ts +71 -0
- package/src/domains/middleware/task-board-reminder.ts +87 -0
- package/src/domains/middleware/task-nudge.ts +77 -0
- package/src/domains/middleware/tool-choice-control.ts +42 -0
- package/src/domains/middleware/types.ts +131 -0
- package/src/domains/middleware/validate.ts +329 -0
- package/src/domains/observability/accountability.ts +67 -0
- package/src/domains/observability/contract.ts +168 -0
- package/src/domains/observability/cost.ts +206 -0
- package/src/domains/observability/evidence-index.ts +123 -0
- package/src/domains/observability/extension.ts +281 -0
- package/src/domains/observability/index.ts +78 -0
- package/src/domains/observability/manifest.ts +10 -0
- package/src/domains/observability/metrics.ts +37 -0
- package/src/domains/observability/projection.ts +477 -0
- package/src/domains/observability/telemetry.ts +89 -0
- package/src/domains/observability/trace-store.ts +1454 -0
- package/src/domains/prompts/compiler.ts +556 -0
- package/src/domains/prompts/contract.ts +30 -0
- package/src/domains/prompts/extension.ts +304 -0
- package/src/domains/prompts/fragment-loader.ts +139 -0
- package/src/domains/prompts/fragments/identity/clio.md +3 -2
- package/src/domains/prompts/fragments/identity/self-awareness.md +63 -0
- package/src/domains/prompts/fragments/operating/contract.md +10 -1
- package/src/domains/prompts/hash.ts +73 -0
- package/src/domains/prompts/index.ts +32 -0
- package/src/domains/prompts/manifest.ts +8 -0
- package/src/domains/prompts/memory-intervention.ts +57 -0
- package/src/domains/prompts/preload.ts +82 -0
- package/src/domains/providers/auth/api-key.ts +47 -0
- package/src/domains/providers/auth/backend-file.ts +69 -0
- package/src/domains/providers/auth/backend-memory.ts +17 -0
- package/src/domains/providers/auth/index.ts +37 -0
- package/src/domains/providers/auth/oauth.ts +36 -0
- package/src/domains/providers/auth/storage.ts +667 -0
- package/src/domains/providers/capabilities.ts +50 -0
- package/src/domains/providers/catalog.ts +162 -0
- package/src/domains/providers/contract.ts +151 -0
- package/src/domains/providers/credentials.ts +20 -0
- package/src/domains/providers/eligibility.ts +24 -0
- package/src/domains/providers/errors.ts +64 -0
- package/src/domains/providers/extension.ts +536 -0
- package/src/domains/providers/index.ts +142 -0
- package/src/domains/providers/knowledge-base-path.ts +102 -0
- package/src/domains/providers/manifest.ts +6 -0
- package/src/domains/providers/model-capabilities.ts +136 -0
- package/src/domains/providers/model-discovery.ts +144 -0
- package/src/domains/providers/model-family.ts +32 -0
- package/src/domains/providers/model-runtime-capabilities.ts +712 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +2 -2
- package/src/domains/providers/plugins.ts +59 -0
- package/src/domains/providers/probe/fingerprint.ts +44 -0
- package/src/domains/providers/probe/http.ts +114 -0
- package/src/domains/providers/probe/reasoning.ts +111 -0
- package/src/domains/providers/registry.ts +166 -0
- package/src/domains/providers/resolver.ts +156 -0
- package/src/domains/providers/runtime-resolution.ts +720 -0
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +90 -0
- package/src/domains/providers/runtimes/builtins.ts +78 -0
- package/src/domains/providers/runtimes/claude/claude-code.ts +38 -0
- package/src/domains/providers/runtimes/claude/claude-sdk.ts +38 -0
- package/src/domains/providers/runtimes/claude/common.ts +55 -0
- package/src/domains/providers/runtimes/cloud/alcf.ts +171 -0
- package/src/domains/providers/runtimes/cloud/anthropic-max.ts +71 -0
- package/src/domains/providers/runtimes/cloud/anthropic.ts +43 -0
- package/src/domains/providers/runtimes/cloud/bedrock.ts +35 -0
- package/src/domains/providers/runtimes/cloud/deepseek.ts +50 -0
- package/src/domains/providers/runtimes/cloud/google.ts +41 -0
- package/src/domains/providers/runtimes/cloud/groq.ts +46 -0
- package/src/domains/providers/runtimes/cloud/mistral.ts +46 -0
- package/src/domains/providers/runtimes/cloud/openai-codex.ts +49 -0
- package/src/domains/providers/runtimes/cloud/openai.ts +46 -0
- package/src/domains/providers/runtimes/cloud/openrouter.ts +111 -0
- package/src/domains/providers/runtimes/common/lmstudio-logger.ts +32 -0
- package/src/domains/providers/runtimes/common/local-synth.ts +165 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +474 -0
- package/src/domains/providers/runtimes/local-native/lemonade-anthropic.ts +27 -0
- package/src/domains/providers/runtimes/local-native/lemonade-openai.ts +26 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +88 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +207 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +180 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +126 -0
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +98 -0
- package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +491 -0
- package/src/domains/providers/runtimes/local-native/ollama-native.ts +117 -0
- package/src/domains/providers/runtimes/local-native/sglang.ts +26 -0
- package/src/domains/providers/runtimes/local-native/vllm.ts +27 -0
- package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +104 -0
- package/src/domains/providers/runtimes/protocol/anthropic-messages.ts +28 -0
- package/src/domains/providers/runtimes/protocol/bedrock.ts +26 -0
- package/src/domains/providers/runtimes/protocol/google.ts +27 -0
- package/src/domains/providers/runtimes/protocol/openai-compat.ts +145 -0
- package/src/domains/providers/support.ts +238 -0
- package/src/domains/providers/thinking-control-policy.ts +85 -0
- package/src/domains/providers/types/capability-flags.ts +114 -0
- package/src/domains/providers/types/cost-provenance.ts +7 -0
- package/src/domains/providers/types/inference.ts +41 -0
- package/src/domains/providers/types/knowledge-base.ts +156 -0
- package/src/domains/providers/types/local-model-quirks.ts +218 -0
- package/src/domains/providers/types/runtime-descriptor.ts +170 -0
- package/src/domains/providers/types/target-descriptor.ts +38 -0
- package/src/domains/resources/collision.ts +92 -0
- package/src/domains/resources/common-loader.ts +140 -0
- package/src/domains/resources/contract.ts +25 -0
- package/src/domains/resources/extension.ts +61 -0
- package/src/domains/resources/index.ts +74 -0
- package/src/domains/resources/loader.ts +86 -0
- package/src/domains/resources/manifest.ts +6 -0
- package/src/domains/resources/prompts/loader.ts +232 -0
- package/src/domains/resources/prompts/substitute.ts +65 -0
- package/src/domains/resources/skills/content-hash.ts +105 -0
- package/src/domains/resources/skills/evals.ts +175 -0
- package/src/domains/resources/skills/install.ts +410 -0
- package/src/domains/resources/skills/loader.ts +978 -0
- package/src/domains/resources/skills/marketplace.ts +255 -0
- package/src/domains/resources/skills/provenance-pin.ts +115 -0
- package/src/domains/safety/action-classifier.ts +268 -0
- package/src/domains/safety/approval-axis.ts +23 -0
- package/src/domains/safety/audit.ts +487 -0
- package/src/domains/safety/autonomy.ts +174 -0
- package/src/domains/safety/call-target.ts +59 -0
- package/src/domains/safety/contract.ts +65 -0
- package/src/domains/safety/damage-control.ts +44 -0
- package/src/domains/safety/default-path-policy.ts +117 -0
- package/src/domains/safety/extension.ts +383 -0
- package/src/domains/safety/finish-contract-registration.ts +128 -0
- package/src/domains/safety/finish-contract.ts +554 -0
- package/src/domains/safety/index.ts +44 -0
- package/src/domains/safety/loop-detector.ts +143 -0
- package/src/domains/safety/manifest.ts +6 -0
- package/src/domains/safety/path-policy.ts +164 -0
- package/src/domains/safety/policy-engine.ts +994 -0
- package/src/domains/safety/project-policy.ts +391 -0
- package/src/domains/safety/protected-artifacts-registration.ts +189 -0
- package/src/domains/safety/protected-artifacts.ts +993 -0
- package/src/domains/safety/rejection-feedback.ts +102 -0
- package/src/domains/safety/rigor.ts +72 -0
- package/src/domains/safety/rule-compiler.ts +48 -0
- package/src/domains/safety/rule-pack-loader.ts +92 -0
- package/src/domains/safety/run-effects.ts +197 -0
- package/src/domains/safety/scope.ts +61 -0
- package/src/domains/scheduling/budget.ts +35 -0
- package/src/domains/scheduling/cluster.ts +175 -0
- package/src/domains/scheduling/contract.ts +30 -0
- package/src/domains/scheduling/extension.ts +91 -0
- package/src/domains/scheduling/index.ts +12 -0
- package/src/domains/scheduling/manifest.ts +6 -0
- package/src/domains/session/archive-readers.ts +208 -0
- package/src/domains/session/checkpoint.ts +38 -0
- package/src/domains/session/compaction/auto.ts +89 -0
- package/src/domains/session/compaction/branch-summary.ts +186 -0
- package/src/domains/session/compaction/compact.ts +493 -0
- package/src/domains/session/compaction/cut-point.ts +171 -0
- package/src/domains/session/compaction/defaults.ts +34 -0
- package/src/domains/session/compaction/mask-observations.ts +265 -0
- package/src/domains/session/compaction/session-entries.ts +18 -0
- package/src/domains/session/compaction/tokens.ts +147 -0
- package/src/domains/session/context-accounting.ts +583 -0
- package/src/domains/session/context-ledger.ts +348 -0
- package/src/domains/session/contract.ts +144 -0
- package/src/domains/session/cwd-fallback.ts +65 -0
- package/src/domains/session/entries.ts +509 -0
- package/src/domains/session/extension.ts +322 -0
- package/src/domains/session/history.ts +172 -0
- package/src/domains/session/index.ts +84 -0
- package/src/domains/session/manager.ts +128 -0
- package/src/domains/session/manifest.ts +6 -0
- package/src/domains/session/migrations/index.ts +27 -0
- package/src/domains/session/prompt-manifest.ts +173 -0
- package/src/domains/session/protected-artifact-journal.ts +241 -0
- package/src/domains/session/protected-artifacts.ts +90 -0
- package/src/domains/session/retry.ts +238 -0
- package/src/domains/session/task-board.ts +375 -0
- package/src/domains/session/tree/active-path.ts +98 -0
- package/src/domains/session/tree/fork.ts +160 -0
- package/src/domains/session/tree/manager.ts +128 -0
- package/src/domains/session/tree/navigator.ts +177 -0
- package/src/domains/session/tree/preview.ts +259 -0
- package/src/domains/session/usage.ts +148 -0
- package/src/domains/session/workspace/git-probe.ts +161 -0
- package/src/domains/session/workspace/index.ts +4 -0
- package/src/domains/session/workspace/project-type.ts +217 -0
- package/src/domains/session/workspace/snapshot.ts +74 -0
- package/src/domains/share/archive.ts +684 -0
- package/src/domains/share/contract.ts +9 -0
- package/src/domains/share/extension.ts +26 -0
- package/src/domains/share/index.ts +28 -0
- package/src/domains/share/manifest.ts +6 -0
- package/src/engine/acp/adapter.ts +397 -0
- package/src/engine/acp/errors.ts +32 -0
- package/src/engine/acp/event-mapper.ts +154 -0
- package/src/engine/acp/server.ts +656 -0
- package/src/engine/acp/tool-mediator.ts +686 -0
- package/src/engine/acp/transport.ts +654 -0
- package/src/engine/acp/types.ts +170 -0
- package/src/engine/agent.ts +29 -0
- package/src/engine/ai.ts +202 -0
- package/src/engine/alcf-oauth.ts +198 -0
- package/src/engine/antigravity/subprocess-runtime.ts +205 -0
- package/src/engine/apis/degraded-inference.ts +95 -0
- package/src/engine/apis/index.ts +20 -0
- package/src/engine/apis/llamacpp-residency.ts +252 -0
- package/src/engine/apis/lmstudio-native.ts +1438 -0
- package/src/engine/apis/lmstudio-residency.ts +92 -0
- package/src/engine/apis/ollama-native.ts +507 -0
- package/src/engine/apis/openai-completions.ts +716 -0
- package/src/engine/apis/output-budget.ts +99 -0
- package/src/engine/apis/residency-lock.ts +29 -0
- package/src/engine/apis/residency.ts +640 -0
- package/src/engine/apis/resident-models.ts +42 -0
- package/src/engine/apis/sampling-overrides.ts +38 -0
- package/src/engine/apis/thinking-replay.ts +11 -0
- package/src/engine/claude/sdk-runtime.ts +685 -0
- package/src/engine/claude/session-id.ts +5 -0
- package/src/engine/claude/subprocess-runtime.ts +316 -0
- package/src/engine/claude/tool-safety.ts +400 -0
- package/src/engine/external-subprocess.ts +23 -0
- package/src/engine/harmony-response.ts +165 -0
- package/src/engine/loop-guard.ts +1127 -0
- package/src/engine/oauth.ts +192 -0
- package/src/engine/pi-mono-names.ts +13 -0
- package/src/engine/provider-payload.ts +315 -0
- package/src/engine/select-list.ts +53 -0
- package/src/engine/session.ts +834 -0
- package/src/engine/strip-tokenizer-sentinels.ts +125 -0
- package/src/engine/tui.ts +103 -0
- package/src/engine/types.ts +66 -0
- package/src/engine/worker-events.ts +100 -0
- package/src/engine/worker-runtime.ts +1022 -0
- package/src/engine/worker-tools.ts +203 -0
- package/src/entry/orchestrator.ts +1873 -0
- package/src/interactive/application-controller.ts +346 -0
- package/src/interactive/bus-notices.ts +265 -0
- package/src/interactive/chat-loop-messages.ts +626 -0
- package/src/interactive/chat-loop-policy.ts +18 -0
- package/src/interactive/chat-loop.ts +865 -0
- package/src/interactive/chat-panel.ts +1694 -0
- package/src/interactive/chat-renderer.ts +1038 -0
- package/src/interactive/clio-editor.ts +166 -0
- package/src/interactive/command-fallbacks.ts +23 -0
- package/src/interactive/command-output.ts +85 -0
- package/src/interactive/context-activity.ts +203 -0
- package/src/interactive/context-meter.ts +223 -0
- package/src/interactive/context-overlay.ts +220 -0
- package/src/interactive/cost-overlay.ts +279 -0
- package/src/interactive/dispatch-board.ts +1319 -0
- package/src/interactive/dispatch-steering.ts +86 -0
- package/src/interactive/editor-bash.ts +46 -0
- package/src/interactive/editor-steer.ts +51 -0
- package/src/interactive/editor-submit.ts +303 -0
- package/src/interactive/external-editor.ts +67 -0
- package/src/interactive/follow-up-queue-panel.ts +75 -0
- package/src/interactive/footer/dashboard.ts +534 -0
- package/src/interactive/footer/notifications.ts +275 -0
- package/src/interactive/footer/widgets.ts +1246 -0
- package/src/interactive/footer-panel.ts +187 -0
- package/src/interactive/format-time.ts +85 -0
- package/src/interactive/index.ts +11 -0
- package/src/interactive/interactive-application.ts +755 -0
- package/src/interactive/interactive-event-projection.ts +380 -0
- package/src/interactive/interactive-input-runtime.ts +261 -0
- package/src/interactive/interactive-presentation.ts +452 -0
- package/src/interactive/interactive-shell.ts +134 -0
- package/src/interactive/interactive-slash-runtime.ts +492 -0
- package/src/interactive/interactive-subscriptions.ts +111 -0
- package/src/interactive/interactive-tickers.ts +152 -0
- package/src/interactive/keybinding-manager.ts +496 -0
- package/src/interactive/layout.ts +20 -0
- package/src/interactive/leader-key.ts +143 -0
- package/src/interactive/loop-guard-interrupt.ts +101 -0
- package/src/interactive/memory-overlay.ts +280 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +110 -0
- package/src/interactive/overlay-auth-lifecycle.ts +308 -0
- package/src/interactive/overlay-frame.ts +502 -0
- package/src/interactive/overlay-general-openers.ts +217 -0
- package/src/interactive/overlay-key-routing.ts +213 -0
- package/src/interactive/overlay-lifecycle.ts +413 -0
- package/src/interactive/overlay-model-selectors.ts +127 -0
- package/src/interactive/overlay-permission-lifecycle.ts +344 -0
- package/src/interactive/overlay-resource-openers.ts +112 -0
- package/src/interactive/overlay-session-lifecycle.ts +270 -0
- package/src/interactive/overlay-transitions.ts +57 -0
- package/src/interactive/overlays/agents.ts +69 -0
- package/src/interactive/overlays/ask-user.ts +921 -0
- package/src/interactive/overlays/auth-dialog.ts +221 -0
- package/src/interactive/overlays/context-reset.ts +108 -0
- package/src/interactive/overlays/cwd-fallback.ts +141 -0
- package/src/interactive/overlays/extensions.ts +54 -0
- package/src/interactive/overlays/help-reference.ts +140 -0
- package/src/interactive/overlays/interop.ts +139 -0
- package/src/interactive/overlays/keybinding-detail.ts +90 -0
- package/src/interactive/overlays/list-overlay.ts +606 -0
- package/src/interactive/overlays/message-picker.ts +155 -0
- package/src/interactive/overlays/model-selector.ts +1091 -0
- package/src/interactive/overlays/prompts.ts +72 -0
- package/src/interactive/overlays/session-selector-search.ts +31 -0
- package/src/interactive/overlays/session-selector.ts +266 -0
- package/src/interactive/overlays/settings.ts +3363 -0
- package/src/interactive/overlays/skills-hub.ts +237 -0
- package/src/interactive/overlays/tree-selector.ts +387 -0
- package/src/interactive/permission-overlay.ts +170 -0
- package/src/interactive/render-trace.ts +125 -0
- package/src/interactive/renderers/branch-summary.ts +86 -0
- package/src/interactive/renderers/code-ink.ts +420 -0
- package/src/interactive/renderers/compaction-summary.ts +112 -0
- package/src/interactive/renderers/diff.ts +126 -0
- package/src/interactive/renderers/notice.ts +28 -0
- package/src/interactive/renderers/retry-status.ts +31 -0
- package/src/interactive/renderers/structured.ts +89 -0
- package/src/interactive/renderers/tool-execution.ts +1104 -0
- package/src/interactive/renderers/worker-entry.ts +264 -0
- package/src/interactive/session-last-turn.ts +186 -0
- package/src/interactive/session-transcript.ts +105 -0
- package/src/interactive/session-usage-reseed.ts +74 -0
- package/src/interactive/slash-autocomplete.ts +364 -0
- package/src/interactive/slash-commands.ts +1319 -0
- package/src/interactive/slash-spec.ts +453 -0
- package/src/interactive/status/controller.ts +256 -0
- package/src/interactive/status/index.ts +23 -0
- package/src/interactive/status/state-machine.ts +530 -0
- package/src/interactive/status/summary.ts +170 -0
- package/src/interactive/status/types.ts +121 -0
- package/src/interactive/status/verbs.ts +163 -0
- package/src/interactive/status/watchdog.ts +24 -0
- package/src/interactive/tasks-overlay.ts +186 -0
- package/src/interactive/theme/components.ts +55 -0
- package/src/interactive/theme/glyphs.ts +70 -0
- package/src/interactive/theme/index.ts +15 -0
- package/src/interactive/theme/labels.ts +88 -0
- package/src/interactive/theme/rules.ts +138 -0
- package/src/interactive/theme/segments.ts +88 -0
- package/src/interactive/theme/tokens.ts +121 -0
- package/src/interactive/thinking-level-policy.ts +6 -0
- package/src/interactive/tool-prose-loop.ts +122 -0
- package/src/interactive/tool-prose-registration.ts +48 -0
- package/src/interactive/turn-context.ts +854 -0
- package/src/interactive/turn-middleware.ts +283 -0
- package/src/interactive/turn-persistence.ts +441 -0
- package/src/interactive/turn-queues.ts +169 -0
- package/src/interactive/turn-recovery.ts +306 -0
- package/src/interactive/turn-runtime.ts +802 -0
- package/src/interactive/turn-state.ts +123 -0
- package/src/interactive/view/artifacts.ts +1342 -0
- package/src/interactive/view/view-overlay.ts +732 -0
- package/src/interactive/welcome-dashboard.ts +536 -0
- package/src/interactive/worker-receipts.ts +94 -0
- package/src/interactive/worker-replay.ts +111 -0
- package/src/interactive/worker-share.ts +100 -0
- package/src/interactive/worker-stream.ts +442 -0
- package/src/interactive/workspace-facts.ts +141 -0
- package/src/tools/agent-tools.ts +382 -0
- package/src/tools/artifact.ts +103 -0
- package/src/tools/ask-user.ts +656 -0
- package/src/tools/bash.ts +176 -0
- package/src/tools/bootstrap.ts +474 -0
- package/src/tools/codewiki/code-nav.ts +563 -0
- package/src/tools/codewiki/shared.ts +115 -0
- package/src/tools/compete-worktrees.ts +898 -0
- package/src/tools/context/docs-engine.ts +619 -0
- package/src/tools/context/index.ts +435 -0
- package/src/tools/credential-present.ts +151 -0
- package/src/tools/dispatch-arguments.ts +228 -0
- package/src/tools/dispatch-plan.ts +741 -0
- package/src/tools/dispatch-scout.ts +461 -0
- package/src/tools/dispatch.ts +3338 -0
- package/src/tools/edit-diff.ts +534 -0
- package/src/tools/edit.ts +128 -0
- package/src/tools/executables.ts +22 -0
- package/src/tools/file-mutation-queue.ts +35 -0
- package/src/tools/find.ts +292 -0
- package/src/tools/grep.ts +495 -0
- package/src/tools/ignore-policy.ts +169 -0
- package/src/tools/ledger.ts +206 -0
- package/src/tools/ls.ts +110 -0
- package/src/tools/monitor.ts +797 -0
- package/src/tools/network-policy.ts +29 -0
- package/src/tools/observation.ts +421 -0
- package/src/tools/observers.ts +99 -0
- package/src/tools/path-utils.ts +79 -0
- package/src/tools/policy.ts +154 -0
- package/src/tools/profiles.ts +108 -0
- package/src/tools/read.ts +173 -0
- package/src/tools/registry.ts +1157 -0
- package/src/tools/result-shaping.ts +204 -0
- package/src/tools/safe-exec.ts +128 -0
- package/src/tools/spawn-hygiene.ts +182 -0
- package/src/tools/steer.ts +88 -0
- package/src/tools/string-enum.ts +15 -0
- package/src/tools/tasks.ts +168 -0
- package/src/tools/truncate-utf8.ts +17 -0
- package/src/tools/truncate.ts +202 -0
- package/src/tools/verify/frontend.ts +685 -0
- package/src/tools/verify/index.ts +66 -0
- package/src/tools/verify/scripts.ts +108 -0
- package/src/tools/web-fetch.ts +777 -0
- package/src/tools/worker-evidence.ts +215 -0
- package/src/tools/write.ts +52 -0
- package/src/utils/exif-orientation.ts +192 -0
- package/src/utils/git.ts +24 -0
- package/src/utils/image-resize.ts +148 -0
- package/src/utils/photon.ts +103 -0
- package/src/worker/control-lane.ts +22 -0
- package/src/worker/entry.ts +257 -0
- package/src/worker/event-projection.ts +56 -0
- package/src/worker/heartbeat.ts +24 -0
- package/src/worker/ledger-mirror.ts +95 -0
- package/src/worker/ndjson.ts +40 -0
- package/src/worker/protocol.ts +529 -0
- package/src/worker/resource-facts.ts +79 -0
- package/src/worker/runtime-registry.ts +12 -0
- package/src/worker/spec-contract.ts +654 -0
- package/src/worker/stdin-demux.ts +316 -0
- package/dist/acp-UMLFVA3F.js +0 -92
- package/dist/chunk-262G75JS.js +0 -35
- package/dist/chunk-5LDRNKX2.js +0 -1063
- package/dist/chunk-67MTHP2E.js +0 -135
- package/dist/chunk-GOTUR54M.js +0 -9
- package/dist/chunk-TPOCL34A.js +0 -2876
- package/dist/chunk-XV4ZJ6ZM.js +0 -3177
- package/dist/clio-KIQ5SNDS.js +0 -53
- package/dist/configure-G4E3A2PG.js +0 -27
- package/dist/doctor-M5HJJZOL.js +0 -61
- package/dist/domains/agents/builtins/architect.md +0 -33
- package/dist/domains/agents/builtins/coder.md +0 -31
- package/dist/domains/agents/builtins/context-bootstrap.md +0 -38
- package/dist/domains/agents/builtins/debugger.md +0 -30
- package/dist/domains/agents/builtins/documenter.md +0 -31
- package/dist/domains/agents/builtins/git-master.md +0 -30
- package/dist/domains/agents/builtins/provenance.md +0 -30
- package/dist/domains/agents/builtins/researcher.md +0 -71
- package/dist/domains/agents/builtins/scout.md +0 -42
- package/dist/domains/agents/builtins/tester.md +0 -31
- package/dist/domains/agents/builtins/verifier.md +0 -30
- package/dist/domains/agents/builtins/wiki-writer.md +0 -41
- package/dist/fleet-preflight-CLIAX7YR.js +0 -21
- package/dist/preload-KZVHET2B.js +0 -11
- package/dist/version-ROZ6CZKH.js +0 -16
- package/skills/git/commit-crafting/SKILL.md +0 -79
- package/skills/git/commit-crafting/evals.md +0 -92
- package/skills/git/create-pr/SKILL.md +0 -116
- package/skills/git/create-pr/evals.md +0 -114
- package/skills/git/investigate-issue/SKILL.md +0 -139
- package/skills/git/investigate-issue/evals.md +0 -94
- package/skills/git/review-changes/SKILL.md +0 -103
- package/skills/git/review-changes/evals.md +0 -85
|
@@ -0,0 +1,1265 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseJsonObjectPayload } from "../../core/json-payload.js";
|
|
4
|
+
import { AGENT_AUTOMATION_AUTHORITIES, type AgentAutomationAuthority } from "./spec.js";
|
|
5
|
+
|
|
6
|
+
export type ResultContract =
|
|
7
|
+
| { kind: "architect-plan"; path: string }
|
|
8
|
+
| { kind: "scout-report" }
|
|
9
|
+
| { kind: "verifier-report" }
|
|
10
|
+
| { kind: "debugger-report" }
|
|
11
|
+
| { kind: "research-report" }
|
|
12
|
+
| { kind: "mutation-report" }
|
|
13
|
+
| { kind: "provenance-report" }
|
|
14
|
+
| { kind: "external-delegation" }
|
|
15
|
+
/**
|
|
16
|
+
* The run's postcondition is the artifact it left on disk, so its terminal
|
|
17
|
+
* text carries no claim to validate. Only the caller that named the output
|
|
18
|
+
* location can check the artifact, and it does so by reading the location
|
|
19
|
+
* rather than by believing a report. A writer asked for a typed report
|
|
20
|
+
* instead has to invent one: a small model handed `mutation-report` for a
|
|
21
|
+
* documentation pass routinely seals a fabricated passing `npm test` entry,
|
|
22
|
+
* which is a false correctness signal produced purely to satisfy a shape.
|
|
23
|
+
* Recipes may declare this kind; Scout subtasks may not request it, because
|
|
24
|
+
* a subtask's result is consumed as data by its dependents.
|
|
25
|
+
*/
|
|
26
|
+
| { kind: "artifact-report" }
|
|
27
|
+
/**
|
|
28
|
+
* The CLIO-CODER.md handbook payload `clio-coder context init` parses. It exists as its
|
|
29
|
+
* own kind because the alternative was dispatching Scout and telling it in
|
|
30
|
+
* prose to ignore its own recipe: the recipe body and the repair directive
|
|
31
|
+
* both name the findings shape, so a model that obeys the recipe returns
|
|
32
|
+
* reconnaissance and the bootstrap parser rejects every run. A contract is
|
|
33
|
+
* the wrong thing to override with a sentence in a task prompt.
|
|
34
|
+
* Scout subtasks may not request it; it is a command's payload, not a
|
|
35
|
+
* dependency edge.
|
|
36
|
+
*/
|
|
37
|
+
| { kind: "context-handbook" }
|
|
38
|
+
/**
|
|
39
|
+
* A deterministic command's structured result. No agent recipe may declare
|
|
40
|
+
* it (`parseResultContract` rejects the kind) and no Scout subtask may
|
|
41
|
+
* request it: it is authored by the code-step runner, never by a model. It
|
|
42
|
+
* lives in this union so a code step's terminal result is validated, sealed,
|
|
43
|
+
* and handed across plan edges through exactly the same door an agent's
|
|
44
|
+
* report uses.
|
|
45
|
+
*/
|
|
46
|
+
| { kind: "code-report" };
|
|
47
|
+
|
|
48
|
+
export type ResultContractQuality = "pass" | "fail" | "unmeasured";
|
|
49
|
+
|
|
50
|
+
export interface ResultContractValidation {
|
|
51
|
+
/** Whether the declared postcondition itself was met. */
|
|
52
|
+
conformance: "pass" | "fail";
|
|
53
|
+
/** Only correctness-bearing contracts can produce a routing-quality label. */
|
|
54
|
+
quality: ResultContractQuality;
|
|
55
|
+
sourceId: string;
|
|
56
|
+
validatorDigest: string;
|
|
57
|
+
/** Parsed Scout data for the model-facing dispatch projection. */
|
|
58
|
+
scout?: ScoutResult;
|
|
59
|
+
/** Parsed Verifier data for the dispatch review-gate projection. */
|
|
60
|
+
verifier?: VerifierResult;
|
|
61
|
+
reason?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ResultContractFilesystem {
|
|
65
|
+
readFile(path: string): string | null;
|
|
66
|
+
/**
|
|
67
|
+
* Whether anything exists at this location. Optional because most contracts
|
|
68
|
+
* only ever need a file's bytes; a mutation report needs presence, since a
|
|
69
|
+
* run legitimately creates directories and writes through channels no tool
|
|
70
|
+
* event enumerates. Absent means presence is unobservable here, and the
|
|
71
|
+
* mutation grounding below degrades to the quality label rather than
|
|
72
|
+
* calling an unreadable path fabricated.
|
|
73
|
+
*/
|
|
74
|
+
pathExists?(path: string): boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Inclusive `[start, end]` line spans a run actually observed, by absolute
|
|
79
|
+
* path. Grounding is only checkable where this evidence exists, which is the
|
|
80
|
+
* worker that made the reads.
|
|
81
|
+
*/
|
|
82
|
+
export type ObservedReadRanges = ReadonlyMap<string, ReadonlyArray<readonly [number, number]>>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The write-side counterpart of `ObservedReadRanges`: what this run's own tool
|
|
86
|
+
* calls show it changed and ran. Both are recorded by the layer that watched
|
|
87
|
+
* the tool stream (`domains/safety/run-effects.ts`).
|
|
88
|
+
*/
|
|
89
|
+
export interface ObservedRunEffects {
|
|
90
|
+
/** Absolute paths the run's successful tool calls aimed a mutation at. */
|
|
91
|
+
mutatedPaths: ReadonlySet<string>;
|
|
92
|
+
/** Absolute paths whose only mutation attempt came back blocked or errored. */
|
|
93
|
+
failedMutationPaths: ReadonlySet<string>;
|
|
94
|
+
/** Canonical validation commands the run ran to a clean exit. */
|
|
95
|
+
validationCommands: ReadonlySet<string>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface ResultContractValidationInput {
|
|
99
|
+
contract: ResultContract;
|
|
100
|
+
output: string | null;
|
|
101
|
+
cwd: string;
|
|
102
|
+
networkAllowed: boolean;
|
|
103
|
+
filesystem: ResultContractFilesystem;
|
|
104
|
+
/**
|
|
105
|
+
* Line spans this run read. When supplied, a cited line must fall inside
|
|
106
|
+
* one, which turns "this line exists in the file" into "this run looked at
|
|
107
|
+
* this line". Absent means grounding is not observable at this layer and
|
|
108
|
+
* only the weaker existence check applies.
|
|
109
|
+
*/
|
|
110
|
+
observedReadRanges?: ObservedReadRanges;
|
|
111
|
+
/**
|
|
112
|
+
* What this run did to the workspace. When supplied, a mutation report is
|
|
113
|
+
* measured against it instead of being believed. Absent means the effects
|
|
114
|
+
* are not observable at this layer and the report's own word stands, which
|
|
115
|
+
* is what every caller got before grounding existed.
|
|
116
|
+
*/
|
|
117
|
+
observedRunEffects?: ObservedRunEffects;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Receipt-ready projection of the typed result validator.
|
|
122
|
+
*
|
|
123
|
+
* `not-reached` is the third conformance state and is not a soft failure. A
|
|
124
|
+
* declared postcondition is only an applicable check once the run got far
|
|
125
|
+
* enough to produce a terminal result. A worker that crashed before its first
|
|
126
|
+
* token, a target that could not load the model, an operator abort, and an
|
|
127
|
+
* engine loop-guard abort all leave the contract unevaluated. Recording those
|
|
128
|
+
* as `fail` invents correctness evidence out of infrastructure noise, so they
|
|
129
|
+
* seal `not-reached` and stay out of the routing quality denominator.
|
|
130
|
+
*/
|
|
131
|
+
export interface ResultContractFact {
|
|
132
|
+
sourceId: string;
|
|
133
|
+
validatorDigest: string;
|
|
134
|
+
conformance: "pass" | "fail" | "not-reached";
|
|
135
|
+
quality: ResultContractQuality;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface ValidateRecipeResultInput {
|
|
139
|
+
contract: ResultContract | null;
|
|
140
|
+
output: string | null;
|
|
141
|
+
cwd: string;
|
|
142
|
+
networkAllowed: boolean;
|
|
143
|
+
filesystem: ResultContractFilesystem;
|
|
144
|
+
/**
|
|
145
|
+
* Whether the run reached the point where its terminal result was due. The
|
|
146
|
+
* caller owns this judgement because only it knows how the attempt ended.
|
|
147
|
+
*/
|
|
148
|
+
reachedTerminalResult: boolean;
|
|
149
|
+
/** What the run's tool calls show it changed and ran, when observed. */
|
|
150
|
+
observedRunEffects?: ObservedRunEffects;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* A declared contract that never got to run. `applicable: false` carries the
|
|
155
|
+
* contract's identity so offline replay still knows which postcondition was in
|
|
156
|
+
* force, while contributing no correctness label.
|
|
157
|
+
*/
|
|
158
|
+
export type RecipeResultOutcome =
|
|
159
|
+
| { applicable: true; validation: ResultContractValidation; fact: ResultContractFact }
|
|
160
|
+
| { applicable: false; fact: ResultContractFact };
|
|
161
|
+
|
|
162
|
+
export interface ScoutCitation {
|
|
163
|
+
path: string;
|
|
164
|
+
line: number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** One reconnaissance claim and the live-read location that grounds it. */
|
|
168
|
+
export interface ScoutFinding extends ScoutCitation {
|
|
169
|
+
claim: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface ScoutResult {
|
|
173
|
+
findings: ReadonlyArray<ScoutFinding>;
|
|
174
|
+
/** Grounding locations projected from findings, in reported order. */
|
|
175
|
+
citations: ReadonlyArray<ScoutCitation>;
|
|
176
|
+
needsSplit: boolean;
|
|
177
|
+
proposedSubtasks: ReadonlyArray<ScoutSubtask>;
|
|
178
|
+
/**
|
|
179
|
+
* Claims salvaged from a degraded result that carry no citation this run can
|
|
180
|
+
* ground. They are leads, never evidence, and they exist so a small model's
|
|
181
|
+
* observations survive a terminal shape it could not emit. Absent on a
|
|
182
|
+
* strictly conforming result.
|
|
183
|
+
*/
|
|
184
|
+
ungroundedClaims?: ReadonlyArray<string>;
|
|
185
|
+
/**
|
|
186
|
+
* The validator's own reason for accepting a degraded shape. Its presence is
|
|
187
|
+
* the flag: any consumer that needs strict Scout data checks for it. Absent
|
|
188
|
+
* on a strictly conforming result.
|
|
189
|
+
*/
|
|
190
|
+
degradedReason?: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Strict Scout-authored data. Every execution/control field is coordinator-owned. */
|
|
194
|
+
export interface ScoutSubtask {
|
|
195
|
+
id: string;
|
|
196
|
+
task: string;
|
|
197
|
+
dependencies: ReadonlyArray<string>;
|
|
198
|
+
expectedResultContract: ResultContract["kind"];
|
|
199
|
+
requestedAuthority: AgentAutomationAuthority;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface VerifierCheck {
|
|
203
|
+
name: string;
|
|
204
|
+
passed: boolean;
|
|
205
|
+
evidence: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Parsed `verifier-report` payload, for callers that need the verdict itself. */
|
|
209
|
+
export interface VerifierResult {
|
|
210
|
+
verdict: "pass" | "fail";
|
|
211
|
+
checks: ReadonlyArray<VerifierCheck>;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Parsed `code-report` payload. `passed` restates `exitCode === 0` so a
|
|
216
|
+
* downstream reader never has to know a runner's exit conventions, and
|
|
217
|
+
* `outputExcerpt` is the command's own bytes so a builder repairs from what
|
|
218
|
+
* the command printed rather than from someone's summary of it.
|
|
219
|
+
*/
|
|
220
|
+
export interface CodeReportResult {
|
|
221
|
+
passed: boolean;
|
|
222
|
+
exitCode: number;
|
|
223
|
+
checks: ReadonlyArray<VerifierCheck>;
|
|
224
|
+
artifactPaths: ReadonlyArray<string>;
|
|
225
|
+
outputExcerpt: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function canonical(value: unknown): string {
|
|
229
|
+
if (value === null) return "null";
|
|
230
|
+
if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
|
|
231
|
+
if (typeof value === "number") {
|
|
232
|
+
if (!Number.isFinite(value)) throw new Error("result contract cannot digest non-finite numbers");
|
|
233
|
+
return JSON.stringify(value);
|
|
234
|
+
}
|
|
235
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
236
|
+
if (typeof value === "object") {
|
|
237
|
+
const record = value as Record<string, unknown>;
|
|
238
|
+
return `{${Object.keys(record)
|
|
239
|
+
.sort()
|
|
240
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(record[key])}`)
|
|
241
|
+
.join(",")}}`;
|
|
242
|
+
}
|
|
243
|
+
throw new Error(`result contract cannot digest ${typeof value}`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function digest(value: unknown): string {
|
|
247
|
+
return createHash("sha256").update(canonical(value), "utf8").digest("hex");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function resultContractDigest(contract: ResultContract): string {
|
|
251
|
+
return digest(contract);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function resultContractSourceId(contract: ResultContract): string {
|
|
255
|
+
return `agent-result-contract:${contract.kind}:${resultContractDigest(contract)}`;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function failure(contract: ResultContract, quality: ResultContractQuality, reason: string): ResultContractValidation {
|
|
259
|
+
return {
|
|
260
|
+
conformance: "fail",
|
|
261
|
+
quality,
|
|
262
|
+
sourceId: resultContractSourceId(contract),
|
|
263
|
+
validatorDigest: digest({ contract, reason }),
|
|
264
|
+
reason,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function success(
|
|
269
|
+
contract: ResultContract,
|
|
270
|
+
quality: ResultContractQuality,
|
|
271
|
+
value: unknown,
|
|
272
|
+
extra: Pick<ResultContractValidation, "scout" | "verifier" | "reason"> = {},
|
|
273
|
+
): ResultContractValidation {
|
|
274
|
+
return {
|
|
275
|
+
conformance: "pass",
|
|
276
|
+
quality,
|
|
277
|
+
sourceId: resultContractSourceId(contract),
|
|
278
|
+
validatorDigest: digest({ contract, value }),
|
|
279
|
+
...extra,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Read the JSON object a terminal result carries. Every contract prompt asks
|
|
285
|
+
* for bare JSON and a fence is the deviation local models reach for first, so
|
|
286
|
+
* refusing one burns both repair rounds and fails a run whose payload was
|
|
287
|
+
* correct. Widening the span that is searched does not widen what conforms: a
|
|
288
|
+
* candidate still has to parse and still has to be an object, and the per-kind
|
|
289
|
+
* validators still own every field.
|
|
290
|
+
*/
|
|
291
|
+
function parseJson(
|
|
292
|
+
output: string | null,
|
|
293
|
+
): { ok: true; value: Record<string, unknown> } | { ok: false; reason: string } {
|
|
294
|
+
if (output === null || output.trim().length === 0) return { ok: false, reason: "missing final result" };
|
|
295
|
+
const parsed = parseJsonObjectPayload(output);
|
|
296
|
+
if (parsed.ok) return parsed;
|
|
297
|
+
return {
|
|
298
|
+
ok: false,
|
|
299
|
+
reason: parsed.reason === "not-object" ? "result must be a JSON object" : "result must be valid JSON",
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function hasOnlyKeys(value: Record<string, unknown>, keys: ReadonlyArray<string>): boolean {
|
|
304
|
+
const allowed = new Set(keys);
|
|
305
|
+
return Object.keys(value).every((key) => allowed.has(key));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function string(value: unknown): value is string {
|
|
309
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function parseFindings(value: unknown): ScoutFinding[] | null {
|
|
313
|
+
if (!Array.isArray(value)) return null;
|
|
314
|
+
const findings: ScoutFinding[] = [];
|
|
315
|
+
for (const entry of value) {
|
|
316
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
317
|
+
const finding = entry as Record<string, unknown>;
|
|
318
|
+
const line = finding.line;
|
|
319
|
+
if (
|
|
320
|
+
!hasOnlyKeys(finding, ["claim", "path", "line"]) ||
|
|
321
|
+
!string(finding.claim) ||
|
|
322
|
+
!string(finding.path) ||
|
|
323
|
+
typeof line !== "number" ||
|
|
324
|
+
!Number.isSafeInteger(line) ||
|
|
325
|
+
line < 1
|
|
326
|
+
) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
findings.push({ claim: finding.claim, path: finding.path, line });
|
|
330
|
+
}
|
|
331
|
+
return findings;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const RESULT_CONTRACT_KINDS: ReadonlyArray<ResultContract["kind"]> = [
|
|
335
|
+
"architect-plan",
|
|
336
|
+
"scout-report",
|
|
337
|
+
"verifier-report",
|
|
338
|
+
"debugger-report",
|
|
339
|
+
"research-report",
|
|
340
|
+
"mutation-report",
|
|
341
|
+
"provenance-report",
|
|
342
|
+
"external-delegation",
|
|
343
|
+
];
|
|
344
|
+
|
|
345
|
+
function parseSubtasks(value: unknown): ScoutSubtask[] | null {
|
|
346
|
+
if (!Array.isArray(value) || value.length > 4) return null;
|
|
347
|
+
const subtasks: ScoutSubtask[] = [];
|
|
348
|
+
const ids = new Set<string>();
|
|
349
|
+
for (const entry of value) {
|
|
350
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
351
|
+
const subtask = entry as Record<string, unknown>;
|
|
352
|
+
if (
|
|
353
|
+
!hasOnlyKeys(subtask, ["id", "task", "dependencies", "expectedResultContract", "requestedAuthority"]) ||
|
|
354
|
+
!string(subtask.id) ||
|
|
355
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(subtask.id) ||
|
|
356
|
+
ids.has(subtask.id) ||
|
|
357
|
+
!string(subtask.task) ||
|
|
358
|
+
Buffer.byteLength(subtask.task, "utf8") > 4096 ||
|
|
359
|
+
!Array.isArray(subtask.dependencies) ||
|
|
360
|
+
subtask.dependencies.length > 4 ||
|
|
361
|
+
subtask.dependencies.some((dependency) => !string(dependency)) ||
|
|
362
|
+
new Set(subtask.dependencies).size !== subtask.dependencies.length ||
|
|
363
|
+
!RESULT_CONTRACT_KINDS.includes(subtask.expectedResultContract as ResultContract["kind"]) ||
|
|
364
|
+
!AGENT_AUTOMATION_AUTHORITIES.includes(subtask.requestedAuthority as AgentAutomationAuthority)
|
|
365
|
+
) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
ids.add(subtask.id);
|
|
369
|
+
subtasks.push({
|
|
370
|
+
id: subtask.id,
|
|
371
|
+
task: subtask.task,
|
|
372
|
+
dependencies: [...subtask.dependencies] as string[],
|
|
373
|
+
expectedResultContract: subtask.expectedResultContract as ResultContract["kind"],
|
|
374
|
+
requestedAuthority: subtask.requestedAuthority as AgentAutomationAuthority,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
for (const subtask of subtasks) {
|
|
378
|
+
if (subtask.dependencies.some((dependency) => dependency === subtask.id || !ids.has(dependency))) return null;
|
|
379
|
+
}
|
|
380
|
+
const remaining = new Set(ids);
|
|
381
|
+
const completed = new Set<string>();
|
|
382
|
+
while (remaining.size > 0) {
|
|
383
|
+
const ready = subtasks.filter(
|
|
384
|
+
(subtask) => remaining.has(subtask.id) && subtask.dependencies.every((dependency) => completed.has(dependency)),
|
|
385
|
+
);
|
|
386
|
+
if (ready.length === 0) return null;
|
|
387
|
+
for (const subtask of ready) {
|
|
388
|
+
remaining.delete(subtask.id);
|
|
389
|
+
completed.add(subtask.id);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return subtasks;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function isContextHandbookResult(value: Record<string, unknown>): boolean {
|
|
396
|
+
if (!hasOnlyKeys(value, ["projectName", "identity", "conventions", "invariants", "sections"])) return false;
|
|
397
|
+
if (!string(value.projectName) || !string(value.identity)) return false;
|
|
398
|
+
if (!Array.isArray(value.conventions) || value.conventions.some((entry) => !string(entry))) return false;
|
|
399
|
+
if (!Array.isArray(value.invariants) || value.invariants.some((entry) => !string(entry))) return false;
|
|
400
|
+
if (!Array.isArray(value.sections)) return false;
|
|
401
|
+
return value.sections.every((entry) => {
|
|
402
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return false;
|
|
403
|
+
const section = entry as Record<string, unknown>;
|
|
404
|
+
return hasOnlyKeys(section, ["title", "body"]) && string(section.title) && string(section.body);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* The handbook payload conforms or it does not. Quality stays unmeasured: a
|
|
410
|
+
* well-formed handbook is a shape, not evidence that the repository was read
|
|
411
|
+
* correctly, and routing statistics must not treat it as a correctness signal.
|
|
412
|
+
*/
|
|
413
|
+
function validateContextHandbook(contract: ResultContract, output: string | null): ResultContractValidation {
|
|
414
|
+
const parsed = parseJson(output);
|
|
415
|
+
if (!parsed.ok) return failure(contract, "fail", parsed.reason);
|
|
416
|
+
if (!isContextHandbookResult(parsed.value)) {
|
|
417
|
+
return failure(
|
|
418
|
+
contract,
|
|
419
|
+
"fail",
|
|
420
|
+
"context handbook result must carry projectName, identity, conventions[], invariants[], and sections[{title, body}] and nothing else",
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
return success(contract, "unmeasured", parsed.value);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Everything a degraded Scout result still carries: the claims themselves,
|
|
428
|
+
* split by whether a `path`/`line` came with them. Deliberately lenient where
|
|
429
|
+
* `parseFindings` is strict, because this runs only after the strict parse has
|
|
430
|
+
* already failed and the alternative to leniency is discarding the run.
|
|
431
|
+
*/
|
|
432
|
+
function salvageScoutClaims(value: unknown): { grounded: ScoutFinding[]; ungrounded: string[] } {
|
|
433
|
+
const grounded: ScoutFinding[] = [];
|
|
434
|
+
const ungrounded: string[] = [];
|
|
435
|
+
if (!Array.isArray(value)) return { grounded, ungrounded };
|
|
436
|
+
for (const entry of value) {
|
|
437
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
438
|
+
const finding = entry as Record<string, unknown>;
|
|
439
|
+
if (!string(finding.claim)) continue;
|
|
440
|
+
const line = finding.line;
|
|
441
|
+
if (string(finding.path) && typeof line === "number" && Number.isSafeInteger(line) && line >= 1) {
|
|
442
|
+
grounded.push({ claim: finding.claim, path: finding.path, line });
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
ungrounded.push(finding.claim);
|
|
446
|
+
}
|
|
447
|
+
return { grounded, ungrounded };
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* A degraded acceptance. The strict contract is the goal, not the point: on a
|
|
452
|
+
* small local model the `{claim, path, line}` shape is close to a coin flip,
|
|
453
|
+
* and the E19 drive lost an entire 51k-token reconnaissance run because two
|
|
454
|
+
* bounded repair rounds could not land it. Nothing about the evidence was
|
|
455
|
+
* wrong; only the envelope was, and failing the run threw the evidence away
|
|
456
|
+
* with it.
|
|
457
|
+
*
|
|
458
|
+
* So a result that still carries usable claims conforms, and the claims reach
|
|
459
|
+
* the parent. Quality is `unmeasured`, never `pass`: a shape this validator had
|
|
460
|
+
* to repair is not correctness evidence, and routing statistics must not
|
|
461
|
+
* inherit one. `degradedReason` marks it for every consumer that needs the
|
|
462
|
+
* strict data, and `parseScoutResult` refuses it outright, so a degraded run
|
|
463
|
+
* can never become a `from_scout` continuation source.
|
|
464
|
+
*/
|
|
465
|
+
function degradedScout(
|
|
466
|
+
contract: ResultContract,
|
|
467
|
+
value: Record<string, unknown>,
|
|
468
|
+
reason: string,
|
|
469
|
+
): ResultContractValidation | null {
|
|
470
|
+
const salvaged = salvageScoutClaims(value.findings);
|
|
471
|
+
if (salvaged.grounded.length === 0 && salvaged.ungrounded.length === 0) return null;
|
|
472
|
+
const degradedReason = `${reason} (accepted as a degraded reconnaissance result; findings are leads, not validation evidence)`;
|
|
473
|
+
// needsSplit is forced false and subtasks dropped: a subtask is control-plane
|
|
474
|
+
// data a coordinator acts on, so a malformed one is never repaired here.
|
|
475
|
+
const scout: ScoutResult = {
|
|
476
|
+
findings: salvaged.grounded,
|
|
477
|
+
citations: salvaged.grounded.map(({ path: citedPath, line }) => ({ path: citedPath, line })),
|
|
478
|
+
needsSplit: false,
|
|
479
|
+
proposedSubtasks: [],
|
|
480
|
+
ungroundedClaims: salvaged.ungrounded,
|
|
481
|
+
degradedReason,
|
|
482
|
+
};
|
|
483
|
+
return success(contract, "unmeasured", scout, { scout, reason: degradedReason });
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function validateScout(contract: ResultContract, output: string | null): ResultContractValidation {
|
|
487
|
+
const parsed = parseJson(output);
|
|
488
|
+
// Nothing to salvage from bytes that are not a JSON object.
|
|
489
|
+
if (!parsed.ok) return failure(contract, "fail", parsed.reason);
|
|
490
|
+
const value = parsed.value;
|
|
491
|
+
// Every strict rejection below falls through to `degrade`, which returns the
|
|
492
|
+
// strict failure unchanged when the result carries no usable claim either.
|
|
493
|
+
const degrade = (reason: string): ResultContractValidation =>
|
|
494
|
+
degradedScout(contract, value, reason) ?? failure(contract, "fail", reason);
|
|
495
|
+
if (!hasOnlyKeys(value, ["findings", "needsSplit", "proposedSubtasks"])) {
|
|
496
|
+
return degrade("Scout result has unknown fields");
|
|
497
|
+
}
|
|
498
|
+
const findings = parseFindings(value.findings);
|
|
499
|
+
const proposedSubtasks = parseSubtasks(value.proposedSubtasks);
|
|
500
|
+
if (findings === null || typeof value.needsSplit !== "boolean" || proposedSubtasks === null) {
|
|
501
|
+
return degrade(
|
|
502
|
+
"Scout result must carry findings as {claim, path, line} objects, needsSplit, and 0..4 typed proposed subtasks",
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
if (value.needsSplit !== proposedSubtasks.length > 0) {
|
|
506
|
+
return degrade("Scout needsSplit must agree with proposedSubtasks");
|
|
507
|
+
}
|
|
508
|
+
// A grounded report needs at least one cited claim. A split recommendation
|
|
509
|
+
// is the explicit exception: it reports that the task did not fit, so it
|
|
510
|
+
// carries subtasks instead of findings.
|
|
511
|
+
if (findings.length === 0 && !value.needsSplit) {
|
|
512
|
+
return degrade("Scout result must carry at least one cited finding, or set needsSplit");
|
|
513
|
+
}
|
|
514
|
+
if (value.needsSplit && findings.length > 0) {
|
|
515
|
+
return degrade("Scout split recommendations carry typed subtasks instead of findings");
|
|
516
|
+
}
|
|
517
|
+
const scout: ScoutResult = {
|
|
518
|
+
findings,
|
|
519
|
+
citations: findings.map(({ path: citedPath, line }) => ({ path: citedPath, line })),
|
|
520
|
+
needsSplit: value.needsSplit,
|
|
521
|
+
proposedSubtasks,
|
|
522
|
+
};
|
|
523
|
+
return success(contract, "pass", scout, { scout });
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function parseChecks(value: unknown): VerifierCheck[] | null {
|
|
527
|
+
if (!Array.isArray(value) || value.length === 0) return null;
|
|
528
|
+
const checks: VerifierCheck[] = [];
|
|
529
|
+
for (const entry of value) {
|
|
530
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
531
|
+
const check = entry as Record<string, unknown>;
|
|
532
|
+
if (
|
|
533
|
+
!hasOnlyKeys(check, ["name", "passed", "evidence"]) ||
|
|
534
|
+
!string(check.name) ||
|
|
535
|
+
typeof check.passed !== "boolean" ||
|
|
536
|
+
!string(check.evidence)
|
|
537
|
+
) {
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
checks.push({ name: check.name, passed: check.passed, evidence: check.evidence });
|
|
541
|
+
}
|
|
542
|
+
return checks;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
type ScoutCitationEvidence = ScoutCitation & { contentDigest: string };
|
|
546
|
+
|
|
547
|
+
/** One citation against the workspace and, where known, against this run's own reads. */
|
|
548
|
+
function validateScoutCitation(
|
|
549
|
+
input: ResultContractValidationInput,
|
|
550
|
+
citation: ScoutCitation,
|
|
551
|
+
): { ok: true; evidence: ScoutCitationEvidence } | { ok: false; reason: string } {
|
|
552
|
+
const cwd = path.resolve(input.cwd);
|
|
553
|
+
const citedPath = path.resolve(cwd, citation.path);
|
|
554
|
+
const relative = path.relative(cwd, citedPath);
|
|
555
|
+
if (relative === "" || relative.startsWith(`..${path.sep}`) || relative === ".." || path.isAbsolute(relative)) {
|
|
556
|
+
return { ok: false, reason: `Scout citation path escapes the workspace: ${citation.path}` };
|
|
557
|
+
}
|
|
558
|
+
const content = input.filesystem.readFile(citedPath);
|
|
559
|
+
if (content === null) return { ok: false, reason: `Scout citation cannot be read: ${citation.path}` };
|
|
560
|
+
const lineCount = content.split(/\r\n|\r|\n/u).length;
|
|
561
|
+
if (citation.line > lineCount) {
|
|
562
|
+
return { ok: false, reason: `Scout citation is past end of file: ${citation.path}:${citation.line}` };
|
|
563
|
+
}
|
|
564
|
+
// Grounding: a line that exists is not a line anyone looked at. Where the
|
|
565
|
+
// run's own read spans are known, the cited line has to fall inside one,
|
|
566
|
+
// so an approximated or inferred line number cannot pass as observation.
|
|
567
|
+
if (input.observedReadRanges !== undefined) {
|
|
568
|
+
const spans = input.observedReadRanges.get(citedPath) ?? [];
|
|
569
|
+
if (!spans.some(([start, end]) => citation.line >= start && citation.line <= end)) {
|
|
570
|
+
const observed =
|
|
571
|
+
spans.length === 0
|
|
572
|
+
? "this run never read that file"
|
|
573
|
+
: `this run read only ${spans.map(([start, end]) => `${start}-${end}`).join(", ")}`;
|
|
574
|
+
return {
|
|
575
|
+
ok: false,
|
|
576
|
+
reason: `Scout citation is not grounded in a live read: ${citation.path}:${citation.line} (${observed})`,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
ok: true,
|
|
582
|
+
evidence: { ...citation, contentDigest: createHash("sha256").update(content, "utf8").digest("hex") },
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Every citation on a strictly conforming result has to ground. One that does
|
|
588
|
+
* not is a fabricated location on a report claiming `pass`, so it fails the
|
|
589
|
+
* whole result; this check is the only thing standing between an invented
|
|
590
|
+
* `path:line` and a quality label the router believes.
|
|
591
|
+
*/
|
|
592
|
+
function validateScoutCitations(
|
|
593
|
+
input: ResultContractValidationInput,
|
|
594
|
+
citations: ReadonlyArray<ScoutCitation>,
|
|
595
|
+
): { ok: true; evidence: ReadonlyArray<ScoutCitationEvidence> } | { ok: false; reason: string } {
|
|
596
|
+
const evidence: ScoutCitationEvidence[] = [];
|
|
597
|
+
for (const citation of citations) {
|
|
598
|
+
const checked = validateScoutCitation(input, citation);
|
|
599
|
+
if (!checked.ok) return checked;
|
|
600
|
+
evidence.push(checked.evidence);
|
|
601
|
+
}
|
|
602
|
+
return { ok: true, evidence };
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Ground a degraded result without ever failing it. On a strict result an
|
|
607
|
+
* ungrounded citation is fabrication and fails the run; here the result already
|
|
608
|
+
* carries no correctness label, so a citation that does not ground is simply
|
|
609
|
+
* dropped and its claim demoted to an ungrounded lead. The parent gets what the
|
|
610
|
+
* run actually observed, correctly labeled, instead of nothing.
|
|
611
|
+
*/
|
|
612
|
+
function groundDegradedScout(
|
|
613
|
+
contract: ResultContract,
|
|
614
|
+
input: ResultContractValidationInput,
|
|
615
|
+
scout: ScoutResult,
|
|
616
|
+
degradedReason: string,
|
|
617
|
+
): ResultContractValidation {
|
|
618
|
+
const grounded: ScoutFinding[] = [];
|
|
619
|
+
const evidence: ScoutCitationEvidence[] = [];
|
|
620
|
+
const demoted: string[] = [];
|
|
621
|
+
for (const finding of scout.findings) {
|
|
622
|
+
const checked = validateScoutCitation(input, { path: finding.path, line: finding.line });
|
|
623
|
+
if (checked.ok) {
|
|
624
|
+
grounded.push(finding);
|
|
625
|
+
evidence.push(checked.evidence);
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
demoted.push(finding.claim);
|
|
629
|
+
}
|
|
630
|
+
const degraded: ScoutResult = {
|
|
631
|
+
findings: grounded,
|
|
632
|
+
citations: grounded.map(({ path: citedPath, line }) => ({ path: citedPath, line })),
|
|
633
|
+
needsSplit: false,
|
|
634
|
+
proposedSubtasks: [],
|
|
635
|
+
ungroundedClaims: [...(scout.ungroundedClaims ?? []), ...demoted],
|
|
636
|
+
degradedReason,
|
|
637
|
+
};
|
|
638
|
+
return success(contract, "unmeasured", { scout: degraded, evidence }, { scout: degraded, reason: degradedReason });
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function validateVerifier(contract: ResultContract, output: string | null): ResultContractValidation {
|
|
642
|
+
const parsed = parseJson(output);
|
|
643
|
+
if (!parsed.ok) return failure(contract, "fail", parsed.reason);
|
|
644
|
+
const value = parsed.value;
|
|
645
|
+
if (!hasOnlyKeys(value, ["verdict", "checks"]) || (value.verdict !== "pass" && value.verdict !== "fail")) {
|
|
646
|
+
return failure(contract, "fail", "Verifier result must carry pass or fail verdict and checks");
|
|
647
|
+
}
|
|
648
|
+
const checks = parseChecks(value.checks);
|
|
649
|
+
if (checks === null || (value.verdict === "pass") !== checks.every((check) => check.passed)) {
|
|
650
|
+
return failure(contract, "fail", "Verifier verdict must agree with every typed check");
|
|
651
|
+
}
|
|
652
|
+
const verifier: VerifierResult = { verdict: value.verdict, checks };
|
|
653
|
+
return success(contract, value.verdict, verifier, { verifier });
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Parse a Verifier structured result under the same schema its recipe contract
|
|
658
|
+
* enforces. The review gate needs the verdict itself, not just its conformance
|
|
659
|
+
* label, so this exposes the parsed payload the way `parseScoutResult` does for
|
|
660
|
+
* reconnaissance. It defines no new schema.
|
|
661
|
+
*/
|
|
662
|
+
export function parseVerifierResult(output: string | null): VerifierResult | null {
|
|
663
|
+
const validation = validateVerifier({ kind: "verifier-report" }, output);
|
|
664
|
+
return validation.verifier ?? null;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* A code step's result is always `unmeasured` for routing quality. A red suite
|
|
669
|
+
* is evidence about the repository, not about the route that ran the command,
|
|
670
|
+
* and code steps are not routes: they never reach route history or the routing
|
|
671
|
+
* quality reducer. Conformance here judges the shape alone, so a failing
|
|
672
|
+
* command still produces a conformant report that crosses its outgoing edges.
|
|
673
|
+
*/
|
|
674
|
+
function validateCodeReport(contract: ResultContract, output: string | null): ResultContractValidation {
|
|
675
|
+
const parsed = parseJson(output);
|
|
676
|
+
if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
|
|
677
|
+
const value = parsed.value;
|
|
678
|
+
if (
|
|
679
|
+
!hasOnlyKeys(value, ["passed", "exitCode", "checks", "artifactPaths", "outputExcerpt"]) ||
|
|
680
|
+
typeof value.passed !== "boolean" ||
|
|
681
|
+
typeof value.exitCode !== "number" ||
|
|
682
|
+
!Number.isSafeInteger(value.exitCode) ||
|
|
683
|
+
typeof value.outputExcerpt !== "string" ||
|
|
684
|
+
!Array.isArray(value.artifactPaths) ||
|
|
685
|
+
value.artifactPaths.some((entry) => !string(entry))
|
|
686
|
+
) {
|
|
687
|
+
return failure(
|
|
688
|
+
contract,
|
|
689
|
+
"unmeasured",
|
|
690
|
+
"Code result must carry passed, integer exitCode, checks, artifactPaths, and outputExcerpt",
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
const checks = parseChecks(value.checks);
|
|
694
|
+
if (checks === null) return failure(contract, "unmeasured", "Code result must carry typed checks");
|
|
695
|
+
if (value.passed !== (value.exitCode === 0) || value.passed !== checks.every((check) => check.passed)) {
|
|
696
|
+
return failure(contract, "unmeasured", "Code result passed must agree with its exit code and every check");
|
|
697
|
+
}
|
|
698
|
+
return success(contract, "unmeasured", value);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/** Parse a `code-report` payload for callers that need the structured result. */
|
|
702
|
+
export function parseCodeReport(output: string | null): CodeReportResult | null {
|
|
703
|
+
const validation = validateCodeReport({ kind: "code-report" }, output);
|
|
704
|
+
if (validation.conformance !== "pass" || output === null) return null;
|
|
705
|
+
// The same reader the validator used, so a fenced payload that passed
|
|
706
|
+
// validation cannot fail here on a re-parse of the raw text.
|
|
707
|
+
const parsed = parseJsonObjectPayload(output);
|
|
708
|
+
if (!parsed.ok) return null;
|
|
709
|
+
const value = parsed.value as unknown as CodeReportResult;
|
|
710
|
+
return {
|
|
711
|
+
passed: value.passed,
|
|
712
|
+
exitCode: value.exitCode,
|
|
713
|
+
checks: value.checks.map((check) => ({ ...check })),
|
|
714
|
+
artifactPaths: [...value.artifactPaths],
|
|
715
|
+
outputExcerpt: value.outputExcerpt,
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Bytes of authored commit message a terminal result may carry. A commit
|
|
721
|
+
* subject and a short body fit; a pasted diff does not.
|
|
722
|
+
*/
|
|
723
|
+
export const RESULT_COMMIT_MESSAGE_MAX_BYTES = 1_000;
|
|
724
|
+
|
|
725
|
+
/** Authored prose a work-product contract may carry beside its evidence. */
|
|
726
|
+
export interface ResultAuthorship {
|
|
727
|
+
/** The agent's proposed commit message for the work it just produced. */
|
|
728
|
+
commitMessage: string | null;
|
|
729
|
+
/** One-line description, used to build a deterministic fallback message. */
|
|
730
|
+
summary: string | null;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
const AUTHORSHIP_FIELDS: ReadonlyArray<keyof ResultAuthorship> = ["commitMessage", "summary"];
|
|
734
|
+
|
|
735
|
+
function hasControlCharacters(value: string): boolean {
|
|
736
|
+
for (const character of value) {
|
|
737
|
+
const code = character.codePointAt(0) ?? 0;
|
|
738
|
+
if (code === 0x7f) return true;
|
|
739
|
+
if (code < 0x20 && character !== "\n" && character !== "\r" && character !== "\t") return true;
|
|
740
|
+
}
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function normalizeAuthored(value: string): string {
|
|
745
|
+
return value.replace(/\r\n/gu, "\n").replace(/\r/gu, "\n").trim();
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Optional authored fields, checked only for shape. Code owns committing; the
|
|
750
|
+
* agent only supplies the sentence, so the sentence is bounded and free of the
|
|
751
|
+
* control characters that would make a commit log unreadable.
|
|
752
|
+
*/
|
|
753
|
+
function validateAuthorship(value: Record<string, unknown>): string | null {
|
|
754
|
+
for (const field of AUTHORSHIP_FIELDS) {
|
|
755
|
+
const raw = value[field];
|
|
756
|
+
// Absent, null, and blank are three spellings of the same thing: nothing
|
|
757
|
+
// was authored. `ResultAuthorship` types the field `string | null` and
|
|
758
|
+
// `resultContractAuthorship` already normalizes a blank to null, so
|
|
759
|
+
// failing here on a spelling this contract's own reader accepts ends a
|
|
760
|
+
// finished run over an optional field the agent correctly left empty.
|
|
761
|
+
if (raw === undefined || raw === null) continue;
|
|
762
|
+
if (typeof raw !== "string") return `${field} must be a string when present`;
|
|
763
|
+
if (raw.trim().length === 0) continue;
|
|
764
|
+
if (Buffer.byteLength(raw, "utf8") > RESULT_COMMIT_MESSAGE_MAX_BYTES) {
|
|
765
|
+
return `${field} must be at most ${RESULT_COMMIT_MESSAGE_MAX_BYTES} bytes`;
|
|
766
|
+
}
|
|
767
|
+
// Tab, newline, and carriage return are the only control bytes a message
|
|
768
|
+
// may carry; anything else would corrupt the log it lands in.
|
|
769
|
+
if (hasControlCharacters(raw)) return `${field} must not contain control characters`;
|
|
770
|
+
}
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Read the authored commit message and summary from a terminal result.
|
|
776
|
+
*
|
|
777
|
+
* Only work-product contracts carry them: `mutation-report` validates them
|
|
778
|
+
* strictly as optional fields, and `architect-plan` reads them from a JSON
|
|
779
|
+
* answer if one was given, because that contract's postcondition is the plan
|
|
780
|
+
* artifact and its final text has never been constrained. Anything unreadable
|
|
781
|
+
* is simply absent, which the caller turns into its deterministic fallback
|
|
782
|
+
* rather than into a failed commit.
|
|
783
|
+
*/
|
|
784
|
+
export function resultContractAuthorship(contract: ResultContract, output: string | null): ResultAuthorship {
|
|
785
|
+
const empty: ResultAuthorship = { commitMessage: null, summary: null };
|
|
786
|
+
if (contract.kind !== "mutation-report" && contract.kind !== "architect-plan") return empty;
|
|
787
|
+
const parsed = parseJson(output);
|
|
788
|
+
if (!parsed.ok || validateAuthorship(parsed.value) !== null) return empty;
|
|
789
|
+
const read = (field: keyof ResultAuthorship): string | null => {
|
|
790
|
+
const raw = parsed.value[field];
|
|
791
|
+
if (typeof raw !== "string") return null;
|
|
792
|
+
const normalized = normalizeAuthored(raw);
|
|
793
|
+
return normalized.length === 0 ? null : normalized;
|
|
794
|
+
};
|
|
795
|
+
return { commitMessage: read("commitMessage"), summary: read("summary") };
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function validateDebugger(contract: ResultContract, output: string | null): ResultContractValidation {
|
|
799
|
+
const parsed = parseJson(output);
|
|
800
|
+
if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
|
|
801
|
+
const value = parsed.value;
|
|
802
|
+
if (
|
|
803
|
+
!hasOnlyKeys(value, ["diagnosis", "reproduction", "evidence"]) ||
|
|
804
|
+
!string(value.diagnosis) ||
|
|
805
|
+
(value.reproduction !== "reproduced" &&
|
|
806
|
+
value.reproduction !== "not-reproduced" &&
|
|
807
|
+
value.reproduction !== "unknown") ||
|
|
808
|
+
!Array.isArray(value.evidence) ||
|
|
809
|
+
value.evidence.some((entry) => !string(entry))
|
|
810
|
+
) {
|
|
811
|
+
return failure(
|
|
812
|
+
contract,
|
|
813
|
+
"unmeasured",
|
|
814
|
+
"Debugger result must carry diagnosis, reproduction status, and evidence without a verdict",
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
return success(contract, "unmeasured", value);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function validateResearch(
|
|
821
|
+
contract: ResultContract,
|
|
822
|
+
output: string | null,
|
|
823
|
+
networkAllowed: boolean,
|
|
824
|
+
): ResultContractValidation {
|
|
825
|
+
const parsed = parseJson(output);
|
|
826
|
+
if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
|
|
827
|
+
const value = parsed.value;
|
|
828
|
+
if (
|
|
829
|
+
!hasOnlyKeys(value, ["source", "findings"]) ||
|
|
830
|
+
(value.source !== "local" && value.source !== "external") ||
|
|
831
|
+
!Array.isArray(value.findings)
|
|
832
|
+
) {
|
|
833
|
+
return failure(
|
|
834
|
+
contract,
|
|
835
|
+
"unmeasured",
|
|
836
|
+
"Research result must distinguish local or external sources and carry findings",
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
if (value.source === "external" && !networkAllowed) {
|
|
840
|
+
return failure(contract, "unmeasured", "external research requires an allowed network posture");
|
|
841
|
+
}
|
|
842
|
+
for (const finding of value.findings) {
|
|
843
|
+
if (finding === null || typeof finding !== "object" || Array.isArray(finding)) {
|
|
844
|
+
return failure(contract, "unmeasured", "Research findings must be objects");
|
|
845
|
+
}
|
|
846
|
+
const record = finding as Record<string, unknown>;
|
|
847
|
+
if (!hasOnlyKeys(record, ["claim", "evidence"]) || !string(record.claim) || !string(record.evidence)) {
|
|
848
|
+
return failure(contract, "unmeasured", "Research findings must carry claim and evidence");
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
return success(contract, "unmeasured", value);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/** Paths this run wrote, as workspace-relative names, for a validator reason. */
|
|
855
|
+
function describeWriteSet(effects: ObservedRunEffects, cwd: string): string {
|
|
856
|
+
if (effects.mutatedPaths.size === 0) return "this run wrote nothing";
|
|
857
|
+
const written = [...effects.mutatedPaths]
|
|
858
|
+
.map((target) => path.relative(cwd, target) || target)
|
|
859
|
+
.sort()
|
|
860
|
+
.slice(0, MUTATION_WRITE_SET_REASON_LIMIT);
|
|
861
|
+
const more = effects.mutatedPaths.size - written.length;
|
|
862
|
+
return `this run wrote ${written.join(", ")}${more > 0 ? ` (+${more} more)` : ""}`;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/** Written paths quoted back in one validator reason before it is truncated. */
|
|
866
|
+
const MUTATION_WRITE_SET_REASON_LIMIT = 8;
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Whether anything is at this location. Without a presence check the validator
|
|
870
|
+
* cannot tell a fabricated path from a directory or an unreadable file, so it
|
|
871
|
+
* answers yes and lets the quality label carry the doubt.
|
|
872
|
+
*/
|
|
873
|
+
function pathIsPresent(filesystem: ResultContractFilesystem, target: string): boolean {
|
|
874
|
+
if (filesystem.pathExists === undefined) return true;
|
|
875
|
+
return filesystem.pathExists(target);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/** One `validations` entry, quoted by every reason that rejects the array. */
|
|
879
|
+
const MUTATION_VALIDATION_EXAMPLE = '{"name":"npm test","passed":true,"evidence":"exit 0"}';
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* Why a `validations` array was refused, in terms the model can act on. Naming
|
|
883
|
+
* the requirement was not enough for a small local model (#74): a run that
|
|
884
|
+
* emitted `"validations":[]` read the reason as satisfied, spent both repair
|
|
885
|
+
* rounds re-emitting the same empty array, and failed `result_contract_exhausted`.
|
|
886
|
+
* The two ways to get this wrong need different corrections, so each reason
|
|
887
|
+
* says which one happened and shows the entry that would have passed.
|
|
888
|
+
*/
|
|
889
|
+
function mutationValidationsReason(value: unknown): string {
|
|
890
|
+
const empty = Array.isArray(value) && value.length === 0;
|
|
891
|
+
if (empty) {
|
|
892
|
+
return `Mutation result must carry typed validation results: validations was empty. Emit one entry per check this run actually made, each shaped like ${MUTATION_VALIDATION_EXAMPLE}. A run that only read files still names the read and cites what it saw.`;
|
|
893
|
+
}
|
|
894
|
+
return `Mutation result must carry typed validation results: every validations entry is shaped like ${MUTATION_VALIDATION_EXAMPLE}, with a string name, a boolean passed, a string evidence, and no other keys.`;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* A mutation report states what the run changed and what it validated. Shape
|
|
899
|
+
* alone cannot tell either claim from an invention, and the shape example this
|
|
900
|
+
* module prints ends up echoed verbatim by small models, so a run that touched
|
|
901
|
+
* nothing has sealed `mutatedPaths: ["src/file.ts"]` as conforming fact.
|
|
902
|
+
*
|
|
903
|
+
* Where the run's own effects were observed, each reported path is measured
|
|
904
|
+
* against them:
|
|
905
|
+
* - in the write set -> the run did this, and it is verified
|
|
906
|
+
* - its only attempt came back refused -> the run's own tool result says the
|
|
907
|
+
* write did not land, so the claim is false however the file looks on disk
|
|
908
|
+
* - absent from it but present on disk -> the run may have written it through
|
|
909
|
+
* a channel no tool event enumerates, so this is not a failure, but it is
|
|
910
|
+
* not verified either
|
|
911
|
+
* - absent from both -> nothing this run did could have
|
|
912
|
+
* produced it, which is a failed postcondition, not a quality signal
|
|
913
|
+
*
|
|
914
|
+
* Quality follows the same rule as conformance. A reported validation the run
|
|
915
|
+
* never ran is not correctness evidence, so it seals `unmeasured` (the label
|
|
916
|
+
* this module already uses for "nothing here can be measured") instead of
|
|
917
|
+
* pass. A self-reported failure still seals `fail`: an agent reporting against
|
|
918
|
+
* its own interest is the one claim here that needs no corroboration.
|
|
919
|
+
*/
|
|
920
|
+
function validateMutation(contract: ResultContract, input: ResultContractValidationInput): ResultContractValidation {
|
|
921
|
+
const parsed = parseJson(input.output);
|
|
922
|
+
if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
|
|
923
|
+
const value = parsed.value;
|
|
924
|
+
if (
|
|
925
|
+
!hasOnlyKeys(value, ["mutatedPaths", "validations", "commitMessage", "summary"]) ||
|
|
926
|
+
!Array.isArray(value.mutatedPaths) ||
|
|
927
|
+
value.mutatedPaths.some((entry) => !string(entry))
|
|
928
|
+
) {
|
|
929
|
+
return failure(contract, "unmeasured", "Mutation result must carry mutatedPaths and validations");
|
|
930
|
+
}
|
|
931
|
+
const authorship = validateAuthorship(value);
|
|
932
|
+
if (authorship !== null) return failure(contract, "unmeasured", authorship);
|
|
933
|
+
const validations = parseChecks(value.validations);
|
|
934
|
+
if (validations === null) return failure(contract, "unmeasured", mutationValidationsReason(value.validations));
|
|
935
|
+
const reportedFailure = !validations.every((check) => check.passed);
|
|
936
|
+
const effects = input.observedRunEffects;
|
|
937
|
+
if (effects === undefined) return success(contract, reportedFailure ? "fail" : "pass", value);
|
|
938
|
+
const cwd = path.resolve(input.cwd);
|
|
939
|
+
let unverifiedMutation = false;
|
|
940
|
+
for (const reported of value.mutatedPaths as ReadonlyArray<string>) {
|
|
941
|
+
const target = path.resolve(cwd, reported);
|
|
942
|
+
if (effects.mutatedPaths.has(target)) continue;
|
|
943
|
+
if (effects.failedMutationPaths.has(target)) {
|
|
944
|
+
return failure(
|
|
945
|
+
contract,
|
|
946
|
+
"unmeasured",
|
|
947
|
+
`Mutation result names a path whose only write this run attempted was refused: ${reported} (${describeWriteSet(effects, cwd)})`,
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
if (pathIsPresent(input.filesystem, target)) {
|
|
951
|
+
unverifiedMutation = true;
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
return failure(
|
|
955
|
+
contract,
|
|
956
|
+
"unmeasured",
|
|
957
|
+
`Mutation result names a path this run never wrote and that does not exist: ${reported} (${describeWriteSet(effects, cwd)})`,
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
if (reportedFailure) return success(contract, "fail", value);
|
|
961
|
+
const measured = !unverifiedMutation && effects.validationCommands.size > 0;
|
|
962
|
+
return success(contract, measured ? "pass" : "unmeasured", value);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function validateProvenance(contract: ResultContract, output: string | null): ResultContractValidation {
|
|
966
|
+
const parsed = parseJson(output);
|
|
967
|
+
if (!parsed.ok) return failure(contract, "unmeasured", parsed.reason);
|
|
968
|
+
const value = parsed.value;
|
|
969
|
+
if (
|
|
970
|
+
!hasOnlyKeys(value, ["confirmedFacts", "missingEvidence", "nextInspections"]) ||
|
|
971
|
+
![value.confirmedFacts, value.missingEvidence, value.nextInspections].every(
|
|
972
|
+
(entry) => Array.isArray(entry) && entry.every((item) => string(item)),
|
|
973
|
+
)
|
|
974
|
+
) {
|
|
975
|
+
return failure(
|
|
976
|
+
contract,
|
|
977
|
+
"unmeasured",
|
|
978
|
+
"Provenance result must carry confirmedFacts, missingEvidence, and nextInspections",
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
return success(contract, "unmeasured", value);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
function validateArchitect(
|
|
985
|
+
contract: Extract<ResultContract, { kind: "architect-plan" }>,
|
|
986
|
+
input: ResultContractValidationInput,
|
|
987
|
+
): ResultContractValidation {
|
|
988
|
+
const artifactPath = path.resolve(input.cwd, contract.path);
|
|
989
|
+
const content = input.filesystem.readFile(artifactPath);
|
|
990
|
+
if (content === null || content.trim().length === 0) {
|
|
991
|
+
return failure(contract, "unmeasured", `required plan artifact is missing or empty: ${contract.path}`);
|
|
992
|
+
}
|
|
993
|
+
return success(contract, "unmeasured", {
|
|
994
|
+
path: contract.path,
|
|
995
|
+
artifactDigest: createHash("sha256").update(content, "utf8").digest("hex"),
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Validate one terminal result under its recipe's typed contract. The caller
|
|
1001
|
+
* supplies filesystem access so this module stays deterministic and testable.
|
|
1002
|
+
*/
|
|
1003
|
+
/**
|
|
1004
|
+
* Parse the Scout structured result for model-facing task decomposition.
|
|
1005
|
+
* Strict on purpose: this feeds the `from_scout` continuation, where a subtask
|
|
1006
|
+
* becomes a real dispatch, so a degraded result is rejected here even though it
|
|
1007
|
+
* conforms as a terminal result. Degraded reconnaissance is readable evidence,
|
|
1008
|
+
* never a control-plane input.
|
|
1009
|
+
*/
|
|
1010
|
+
export function parseScoutResult(output: string): ScoutResult | null {
|
|
1011
|
+
const validation = validateScout({ kind: "scout-report" }, output);
|
|
1012
|
+
if (validation.conformance !== "pass" || validation.scout === undefined) return null;
|
|
1013
|
+
return validation.scout.degradedReason === undefined ? validation.scout : null;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
export function validateResultContract(input: ResultContractValidationInput): ResultContractValidation {
|
|
1017
|
+
switch (input.contract.kind) {
|
|
1018
|
+
case "architect-plan":
|
|
1019
|
+
return validateArchitect(input.contract, input);
|
|
1020
|
+
case "scout-report": {
|
|
1021
|
+
const validation = validateScout(input.contract, input.output);
|
|
1022
|
+
if (validation.scout === undefined) return validation;
|
|
1023
|
+
const degradedReason = validation.scout.degradedReason;
|
|
1024
|
+
if (degradedReason !== undefined) {
|
|
1025
|
+
return groundDegradedScout(input.contract, input, validation.scout, degradedReason);
|
|
1026
|
+
}
|
|
1027
|
+
const citations = validateScoutCitations(input, validation.scout.citations);
|
|
1028
|
+
return citations.ok
|
|
1029
|
+
? success(
|
|
1030
|
+
input.contract,
|
|
1031
|
+
"pass",
|
|
1032
|
+
{ scout: validation.scout, evidence: citations.evidence },
|
|
1033
|
+
{ scout: validation.scout },
|
|
1034
|
+
)
|
|
1035
|
+
: failure(input.contract, "fail", citations.reason);
|
|
1036
|
+
}
|
|
1037
|
+
case "verifier-report":
|
|
1038
|
+
return validateVerifier(input.contract, input.output);
|
|
1039
|
+
case "debugger-report":
|
|
1040
|
+
return validateDebugger(input.contract, input.output);
|
|
1041
|
+
case "research-report":
|
|
1042
|
+
return validateResearch(input.contract, input.output, input.networkAllowed);
|
|
1043
|
+
case "mutation-report":
|
|
1044
|
+
return validateMutation(input.contract, input);
|
|
1045
|
+
case "provenance-report":
|
|
1046
|
+
return validateProvenance(input.contract, input.output);
|
|
1047
|
+
case "external-delegation":
|
|
1048
|
+
return success(input.contract, "unmeasured", { external: true });
|
|
1049
|
+
case "artifact-report":
|
|
1050
|
+
// Nothing here can be measured: the artifact lives at a location only
|
|
1051
|
+
// the caller knows, so the caller checks it. Any terminal text
|
|
1052
|
+
// conforms, which is what stops a bounded repair round from being
|
|
1053
|
+
// spent teaching a writer a JSON shape that proves nothing.
|
|
1054
|
+
return success(input.contract, "unmeasured", { artifact: true });
|
|
1055
|
+
case "context-handbook":
|
|
1056
|
+
return validateContextHandbook(input.contract, input.output);
|
|
1057
|
+
case "code-report":
|
|
1058
|
+
return validateCodeReport(input.contract, input.output);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
/** Validate a recipe's final result and project it into receipt-safe facts. */
|
|
1063
|
+
export function validateRecipeResult(input: ValidateRecipeResultInput): RecipeResultOutcome | null {
|
|
1064
|
+
if (input.contract === null) return null;
|
|
1065
|
+
if (!input.reachedTerminalResult) {
|
|
1066
|
+
return {
|
|
1067
|
+
applicable: false,
|
|
1068
|
+
fact: {
|
|
1069
|
+
sourceId: resultContractSourceId(input.contract),
|
|
1070
|
+
validatorDigest: digest({ contract: input.contract, reached: false }),
|
|
1071
|
+
conformance: "not-reached",
|
|
1072
|
+
quality: "unmeasured",
|
|
1073
|
+
},
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
const validation = validateResultContract({
|
|
1077
|
+
contract: input.contract,
|
|
1078
|
+
output: input.output,
|
|
1079
|
+
cwd: input.cwd,
|
|
1080
|
+
networkAllowed: input.networkAllowed,
|
|
1081
|
+
filesystem: input.filesystem,
|
|
1082
|
+
...(input.observedRunEffects !== undefined ? { observedRunEffects: input.observedRunEffects } : {}),
|
|
1083
|
+
});
|
|
1084
|
+
return {
|
|
1085
|
+
applicable: true,
|
|
1086
|
+
validation,
|
|
1087
|
+
fact: {
|
|
1088
|
+
sourceId: validation.sourceId,
|
|
1089
|
+
validatorDigest: validation.validatorDigest,
|
|
1090
|
+
conformance: validation.conformance,
|
|
1091
|
+
quality: validation.quality,
|
|
1092
|
+
},
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* Bounded in-worker repair rounds for a terminal result that missed its
|
|
1098
|
+
* contract. A local model with few active parameters routinely gathers correct
|
|
1099
|
+
* evidence and then emits the wrong terminal shape; without feedback that run
|
|
1100
|
+
* is lost. Two rounds is the whole allowance, and the run fails after them.
|
|
1101
|
+
*/
|
|
1102
|
+
export const RESULT_CONTRACT_REPAIR_LIMIT = 2;
|
|
1103
|
+
|
|
1104
|
+
/** Live-read anchors quoted back to the model in a repair round. */
|
|
1105
|
+
export const RESULT_CONTRACT_ANCHOR_LIMIT = 12;
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* The exact terminal shape each contract accepts, quoted to the model verbatim.
|
|
1109
|
+
* This is the one place a contract's wire example is written; agent recipes and
|
|
1110
|
+
* repair rounds both cite it, so a prompt cannot drift from its validator.
|
|
1111
|
+
*/
|
|
1112
|
+
function resultContractShape(contract: ResultContract): string {
|
|
1113
|
+
switch (contract.kind) {
|
|
1114
|
+
case "architect-plan":
|
|
1115
|
+
return `a plan artifact written to ${contract.path}, then optionally {"commitMessage":"...","summary":"..."} describing it`;
|
|
1116
|
+
case "scout-report":
|
|
1117
|
+
// The third alternative is the floor this validator actually accepts.
|
|
1118
|
+
// A repair round that only ever restates the strict shape is what the
|
|
1119
|
+
// run already failed twice, so it is told the cheaper exit as well.
|
|
1120
|
+
return '{"findings":[{"claim":"what you observed","path":"src/file.ts","line":1}],"needsSplit":false,"proposedSubtasks":[]} or {"findings":[],"needsSplit":true,"proposedSubtasks":[{"id":"inspect","task":"Inspect the boundary","dependencies":[],"expectedResultContract":"scout-report","requestedAuthority":"read-only"}]} or, if you cannot produce a citation you are sure of, at least {"findings":[{"claim":"what you observed"}]}, which is accepted as an ungrounded lead rather than losing the run';
|
|
1121
|
+
case "verifier-report":
|
|
1122
|
+
return '{"verdict":"pass","checks":[{"name":"npm run typecheck","passed":true,"evidence":"exit 0"}]}';
|
|
1123
|
+
case "debugger-report":
|
|
1124
|
+
return '{"diagnosis":"...","reproduction":"reproduced","evidence":["..."]}';
|
|
1125
|
+
case "research-report":
|
|
1126
|
+
return '{"source":"local","findings":[{"claim":"...","evidence":"..."}]}';
|
|
1127
|
+
case "mutation-report":
|
|
1128
|
+
return '{"mutatedPaths":["src/file.ts"],"validations":[{"name":"npm test","passed":true,"evidence":"exit 0"}],"commitMessage":"optional: the commit message for this change","summary":"optional: one line"}';
|
|
1129
|
+
case "provenance-report":
|
|
1130
|
+
return '{"confirmedFacts":["..."],"missingEvidence":["..."],"nextInspections":["..."]}';
|
|
1131
|
+
case "external-delegation":
|
|
1132
|
+
return "any final text";
|
|
1133
|
+
case "artifact-report":
|
|
1134
|
+
return "any final text; the artifact you wrote at the location the task named is the result";
|
|
1135
|
+
case "context-handbook":
|
|
1136
|
+
return '{"projectName":"string","identity":"one sentence","conventions":[],"invariants":[],"sections":[{"title":"Architecture","body":"markdown that cites `real/path.ts` tokens"}]}';
|
|
1137
|
+
case "code-report":
|
|
1138
|
+
return '{"passed":false,"exitCode":1,"checks":[{"name":"test","passed":false,"evidence":"exit 1"}],"artifactPaths":["/path/command.log"],"outputExcerpt":"..."}';
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
export interface ResultContractRepairInput {
|
|
1143
|
+
contract: ResultContract;
|
|
1144
|
+
/** The validator's own reason; never a paraphrase. */
|
|
1145
|
+
reason: string;
|
|
1146
|
+
/** 1-based repair round. */
|
|
1147
|
+
attempt: number;
|
|
1148
|
+
/** `path:line` anchors from reads that succeeded in this run. */
|
|
1149
|
+
anchors: ReadonlyArray<string>;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* One repair directive. It states the validator's reason, the exact shape, and
|
|
1154
|
+
* that tool use is over, so the model's only remaining move is to emit the
|
|
1155
|
+
* terminal document from evidence it already has.
|
|
1156
|
+
*/
|
|
1157
|
+
export function resultContractRepairMessage(input: ResultContractRepairInput): string {
|
|
1158
|
+
const last = input.attempt >= RESULT_CONTRACT_REPAIR_LIMIT;
|
|
1159
|
+
const lines = [
|
|
1160
|
+
last
|
|
1161
|
+
? "FINAL RESULT REQUIRED IN THIS RESPONSE. Your previous response still did not satisfy this run's result contract."
|
|
1162
|
+
: "Your previous response did not satisfy this run's result contract.",
|
|
1163
|
+
`Validator reason: ${input.reason}`,
|
|
1164
|
+
"Tool use is over. Answer from the evidence you already gathered.",
|
|
1165
|
+
`Emit exactly this shape and nothing else: ${resultContractShape(input.contract)}`,
|
|
1166
|
+
"Do not add prose, code fences, or commentary around it. Do not describe work you intend to do next.",
|
|
1167
|
+
];
|
|
1168
|
+
if (input.anchors.length > 0) {
|
|
1169
|
+
lines.push(
|
|
1170
|
+
"",
|
|
1171
|
+
"Locations you read successfully in this run (use these exact path:line values):",
|
|
1172
|
+
...input.anchors.slice(-RESULT_CONTRACT_ANCHOR_LIMIT).map((anchor) => `- ${anchor}`),
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
return lines.join("\n");
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/** Name of the synthetic tool call that carries a repair round. */
|
|
1179
|
+
export const RESULT_CONTRACT_REPAIR_TOOL = "result_contract";
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* One repair round as a protocol-legal tool exchange: a synthetic assistant
|
|
1183
|
+
* call to `result_contract` and the tool result that answers it, sharing the
|
|
1184
|
+
* id `clio-result-contract-repair-N`. Strict endpoints (OpenAI, Anthropic)
|
|
1185
|
+
* reject a tool result no assistant call issued; local servers tolerated the
|
|
1186
|
+
* bare result, and this keeps the history-append shape #55 measured while
|
|
1187
|
+
* satisfying both. `stopReason: "toolUse"` and the toolCall block keep the
|
|
1188
|
+
* assistant half out of terminal validation, durable output, and the
|
|
1189
|
+
* synthesis sanitizer.
|
|
1190
|
+
*
|
|
1191
|
+
* The assistant half carries explicit zero usage. pi-ai's context estimator
|
|
1192
|
+
* (`estimateContextTokens`, run while sizing every request) dereferences
|
|
1193
|
+
* `usage` on any assistant message not marked `aborted`/`error`, so a
|
|
1194
|
+
* usage-less `toolUse` message throws `Cannot read properties of undefined
|
|
1195
|
+
* (reading 'totalTokens')` on the very next model round and the worker dies
|
|
1196
|
+
* with the contract `not-reached` (#70). Zero usage keeps the estimator on
|
|
1197
|
+
* the model's last real usage and its byte-for-byte prompt-cache behavior.
|
|
1198
|
+
*/
|
|
1199
|
+
export function resultContractRepairMessages(
|
|
1200
|
+
input: ResultContractRepairInput,
|
|
1201
|
+
origin: { provider: string; api: string; model: string },
|
|
1202
|
+
) {
|
|
1203
|
+
const id = `clio-result-contract-repair-${input.attempt}`;
|
|
1204
|
+
const timestamp = Date.now();
|
|
1205
|
+
return [
|
|
1206
|
+
{
|
|
1207
|
+
role: "assistant",
|
|
1208
|
+
content: [{ type: "toolCall", id, name: RESULT_CONTRACT_REPAIR_TOOL, arguments: {} }],
|
|
1209
|
+
stopReason: "toolUse",
|
|
1210
|
+
usage: {
|
|
1211
|
+
input: 0,
|
|
1212
|
+
output: 0,
|
|
1213
|
+
cacheRead: 0,
|
|
1214
|
+
cacheWrite: 0,
|
|
1215
|
+
totalTokens: 0,
|
|
1216
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
1217
|
+
},
|
|
1218
|
+
...origin,
|
|
1219
|
+
timestamp,
|
|
1220
|
+
},
|
|
1221
|
+
{
|
|
1222
|
+
role: "toolResult",
|
|
1223
|
+
toolCallId: id,
|
|
1224
|
+
toolName: RESULT_CONTRACT_REPAIR_TOOL,
|
|
1225
|
+
content: [{ type: "text", text: resultContractRepairMessage(input) }],
|
|
1226
|
+
isError: true,
|
|
1227
|
+
timestamp,
|
|
1228
|
+
},
|
|
1229
|
+
] as const;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/** Strict frontmatter parser for the one recipe result-contract schema. */
|
|
1233
|
+
export function parseResultContract(value: unknown, sourcePath: string): ResultContract {
|
|
1234
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
1235
|
+
throw new Error(`agent recipe: ${sourcePath}: resultContract must be an object`);
|
|
1236
|
+
}
|
|
1237
|
+
const record = value as Record<string, unknown>;
|
|
1238
|
+
if (typeof record.kind !== "string") throw new Error(`agent recipe: ${sourcePath}: resultContract.kind is required`);
|
|
1239
|
+
const keys = Object.keys(record);
|
|
1240
|
+
const only = (...allowed: string[]): boolean => keys.every((key) => allowed.includes(key));
|
|
1241
|
+
if (record.kind === "architect-plan") {
|
|
1242
|
+
if (!only("kind", "path") || !string(record.path)) {
|
|
1243
|
+
throw new Error(`agent recipe: ${sourcePath}: architect-plan requires only non-empty path`);
|
|
1244
|
+
}
|
|
1245
|
+
if (path.isAbsolute(record.path) || record.path.split(/[\\/]/u).includes("..")) {
|
|
1246
|
+
throw new Error(`agent recipe: ${sourcePath}: architect-plan path must be workspace-relative`);
|
|
1247
|
+
}
|
|
1248
|
+
return { kind: "architect-plan", path: record.path };
|
|
1249
|
+
}
|
|
1250
|
+
const kinds = [
|
|
1251
|
+
"scout-report",
|
|
1252
|
+
"verifier-report",
|
|
1253
|
+
"debugger-report",
|
|
1254
|
+
"research-report",
|
|
1255
|
+
"mutation-report",
|
|
1256
|
+
"provenance-report",
|
|
1257
|
+
"external-delegation",
|
|
1258
|
+
"artifact-report",
|
|
1259
|
+
"context-handbook",
|
|
1260
|
+
] as const;
|
|
1261
|
+
if (!(kinds as ReadonlyArray<string>).includes(record.kind) || !only("kind")) {
|
|
1262
|
+
throw new Error(`agent recipe: ${sourcePath}: resultContract.kind is unsupported or has unknown keys`);
|
|
1263
|
+
}
|
|
1264
|
+
return { kind: record.kind as Exclude<ResultContract["kind"], "architect-plan"> };
|
|
1265
|
+
}
|