@iowarp/clio-coder 0.3.7 → 0.3.9
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 +80 -0
- package/README.md +13 -4
- package/dist/{acp-SK4MD6MM.js → acp-7LOELQFP.js} +13 -13
- package/dist/{agents-2FN2K6ME.js → agents-FIBG2SHA.js} +41 -37
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-QIYZWM5I.js → auth-OI4LIH2I.js} +31 -24
- package/dist/builtins-AD25UL3C.js +17 -0
- package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
- package/dist/chunk-3DPEIQKN.js +113 -0
- package/dist/{chunk-EOOQZZDE.js → chunk-3DUR4WUA.js} +19 -19
- package/dist/{chunk-WHJYKASB.js → chunk-3MRC2YSQ.js} +2 -2
- package/dist/{chunk-EBEFWSGL.js → chunk-3UUY7R3Z.js} +14 -10
- package/dist/{chunk-LADCF22A.js → chunk-3V5AYSEQ.js} +113 -54
- package/dist/{chunk-BMWK7ZIZ.js → chunk-465CC7FK.js} +16 -13
- package/dist/{chunk-5WIGXA4T.js → chunk-47CMYGET.js} +111 -4
- package/dist/{chunk-CEYBNUGC.js → chunk-4H6ULJ3H.js} +378 -36
- package/dist/{chunk-YTYFXUI3.js → chunk-4LJX2PUC.js} +9 -9
- package/dist/{chunk-DOOEX22V.js → chunk-56KB5IJP.js} +5 -5
- package/dist/{chunk-SPULKLCF.js → chunk-5DQRIYDZ.js} +2 -2
- package/dist/{chunk-TSHXZTOQ.js → chunk-5HFBWUMU.js} +23 -11
- package/dist/{chunk-5UJ6ECTS.js → chunk-5PVQ4SRS.js} +80 -8
- package/dist/{chunk-ZWLZP4ZT.js → chunk-5QKCQQ3E.js} +359 -17
- package/dist/{chunk-6M7VS3J3.js → chunk-5T7RBWN2.js} +111 -5
- package/dist/chunk-774ILSRL.js +172 -0
- package/dist/chunk-7C6RYZGQ.js +391 -0
- package/dist/{chunk-GH5622CP.js → chunk-A2NJGIB3.js} +2 -2
- package/dist/{chunk-C4JBQ5SR.js → chunk-AD7Y7STJ.js} +6 -6
- package/dist/{chunk-GEYXPTRF.js → chunk-AEYBF3TB.js} +33 -12
- package/dist/{chunk-2SFS6XQE.js → chunk-AMKHQW3C.js} +3 -2
- package/dist/{chunk-D4MDIG46.js → chunk-B5CSFE7B.js} +7 -7
- package/dist/{chunk-MXI6J5JF.js → chunk-B5XRQOLB.js} +10 -10
- package/dist/{chunk-X2KV5FXT.js → chunk-BVDVID7E.js} +2 -2
- package/dist/{chunk-JNXPYBB4.js → chunk-CA42X6KT.js} +3 -3
- package/dist/{chunk-VREKEFLL.js → chunk-D73KXYPF.js} +3 -3
- package/dist/{chunk-JTSEDYVQ.js → chunk-DG4M6ZUE.js} +7 -7
- package/dist/{chunk-DQA7QLMD.js → chunk-EBOC7MT3.js} +10 -25
- package/dist/{chunk-KZ2H5X4G.js → chunk-ECUO3KDP.js} +129 -14
- package/dist/{chunk-JRIO5UD2.js → chunk-EQ63NRB7.js} +5 -5
- package/dist/{chunk-YD734TPH.js → chunk-FALJGAWU.js} +2 -2
- package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
- package/dist/{chunk-XEGB6BCN.js → chunk-GAYUJ7LE.js} +68 -14
- package/dist/{chunk-UND3GU2L.js → chunk-H7IXIC72.js} +2 -2
- package/dist/{chunk-IR4CFBFN.js → chunk-HAY4ZE2P.js} +12 -12
- package/dist/{chunk-UVDSQ6LW.js → chunk-HCBCAYZU.js} +74 -147
- package/dist/{chunk-4DWFMQDR.js → chunk-HJB5IUKP.js} +89 -145
- package/dist/{chunk-M4AKACEO.js → chunk-HKO36JWF.js} +33 -5
- package/dist/{chunk-KCMKRQX4.js → chunk-HPCTNZM2.js} +45 -82
- package/dist/{chunk-465YSENW.js → chunk-IFBNV6H6.js} +3 -3
- package/dist/{chunk-FJ3H4MN5.js → chunk-IHKBWSXF.js} +2 -2
- package/dist/chunk-JEQQR47K.js +3025 -0
- package/dist/{chunk-FO5ZOVUY.js → chunk-KV2AOLDF.js} +27 -7
- package/dist/chunk-LU7P4LHA.js +33 -0
- package/dist/{chunk-6TUKSZVF.js → chunk-LXPJXFM5.js} +11 -11
- package/dist/{chunk-VQNODYQ4.js → chunk-MIX5N5AC.js} +488 -3668
- package/dist/chunk-MLOK6ZOS.js +2888 -0
- package/dist/{chunk-ZZMN5OM4.js → chunk-MV2VUEJC.js} +2 -2
- package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
- package/dist/{chunk-OBMAI2DP.js → chunk-N3PBVRTZ.js} +12 -388
- package/dist/{chunk-WJHBC77E.js → chunk-N5XKWMDW.js} +17 -7
- package/dist/{chunk-5C3AQNDW.js → chunk-NNNWO6F2.js} +124 -36
- package/dist/{chunk-UFQ3F4FW.js → chunk-NQ6UCCOD.js} +4 -4
- package/dist/chunk-NUGM5KR6.js +165 -0
- package/dist/{chunk-DMD2AGVS.js → chunk-NZU6YDNV.js} +20 -18
- package/dist/{chunk-WHGPSPT5.js → chunk-O6I4CIEU.js} +151 -13
- package/dist/{chunk-XN3L4EYL.js → chunk-OEDBCISO.js} +2 -2
- package/dist/{chunk-PD3MESLB.js → chunk-P3JGPQFL.js} +4 -4
- package/dist/{chunk-UHXRNZ2J.js → chunk-PNY46YEY.js} +23 -6
- package/dist/{chunk-THKY7CD7.js → chunk-PZ4I4JE2.js} +134 -29
- package/dist/{chunk-SROCI7ZU.js → chunk-QQ7EKM72.js} +5 -5
- package/dist/{chunk-QCTRSGHQ.js → chunk-R7LNVMCS.js} +91 -53
- package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
- package/dist/chunk-RKKLTLYB.js +45 -0
- package/dist/{chunk-OB5HIGJY.js → chunk-RKRLDWD3.js} +4 -1
- package/dist/{chunk-DJNLUABN.js → chunk-S4COXYBG.js} +588 -32
- package/dist/{chunk-3HAPLH5M.js → chunk-T3Z6VAAF.js} +172 -11
- package/dist/{chunk-FOT2FX5J.js → chunk-TD7UE2L5.js} +12 -10
- package/dist/{chunk-UUANF5CR.js → chunk-TEO2TLVN.js} +856 -967
- package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
- package/dist/{chunk-EELBMBT6.js → chunk-VKBMFOYV.js} +74 -15
- package/dist/chunk-VO2LKSTM.js +165 -0
- package/dist/{chunk-5C77SEEY.js → chunk-VPTUJU4P.js} +3 -3
- package/dist/{chunk-WEH5XRJQ.js → chunk-WIE7ZOSW.js} +2 -2
- package/dist/{chunk-J7PIKKWC.js → chunk-WXCJ7VME.js} +8 -8
- package/dist/{chunk-4DGYLA73.js → chunk-XDOQXGFO.js} +22 -7
- package/dist/{chunk-PPAMZ32Z.js → chunk-XK56QHLX.js} +6 -1
- package/dist/{chunk-AB4XIIVB.js → chunk-YKOFT37S.js} +6 -6
- package/dist/chunk-YSEHGPCT.js +127 -0
- package/dist/{chunk-HFSBBKSQ.js → chunk-YW7UVM5V.js} +138 -3
- package/dist/cli/index.js +32 -32
- package/dist/{clio-WBVQEBKO.js → clio-LT5V7SSZ.js} +9 -9
- package/dist/{code-nav-FGGFIE7L.js → code-nav-LMW275PA.js} +5 -5
- package/dist/codewiki/build-worker.js +4 -4
- package/dist/{components-F7OEATSO.js → components-ZFA3SAER.js} +8 -8
- package/dist/{config-TRBL3RCF.js → config-RXS5T3JT.js} +98 -65
- package/dist/{configure-OLCVPHNM.js → configure-2WYWSCSD.js} +26 -22
- package/dist/{context-MJIJ6GOX.js → context-I3BTOTCS.js} +12 -12
- package/dist/{context-XEWE3MOJ.js → context-MVOORGMF.js} +54 -47
- package/dist/{context-WFPKQSM6.js → context-PALKKQYL.js} +28 -28
- package/dist/{context-clear-KNOS2JPB.js → context-clear-N2WOYZ2K.js} +53 -46
- package/dist/{context-index-SSR5ECNE.js → context-index-HNG3MOME.js} +6 -6
- package/dist/{context-working-set-EUXAZI6N.js → context-working-set-MIEVECVZ.js} +17 -18
- package/dist/{dispatch-runner-B7MTOVKL.js → dispatch-runner-VVA4SRRH.js} +90 -61
- package/dist/{docs-FLJTIDSE.js → docs-7LQ23DLM.js} +8 -8
- package/dist/doctor-TWBWFK5V.js +165 -0
- package/dist/eval-IJ5VEZDJ.js +4483 -0
- package/dist/{evidence-JZNBUOQZ.js → evidence-L5APPXNV.js} +68 -61
- package/dist/{evolve-FJVC4KKI.js → evolve-RGNKFJ52.js} +47 -40
- package/dist/{extensions-IQL36S7K.js → extensions-7WYWUX5A.js} +13 -7
- package/dist/{fleet-BDKYJFCP.js → fleet-6CNVBZZP.js} +113 -76
- package/dist/{fleet-commands-ZFIWZSB3.js → fleet-commands-L2SXSYEI.js} +10 -10
- package/dist/{fleet-graph-Y6HPXIVF.js → fleet-graph-2J3OOIPO.js} +17 -15
- package/dist/{fleet-preflight-BHSNPBMH.js → fleet-preflight-CZRJ4JP5.js} +5 -6
- package/dist/{fleet-validate-BIYREGIK.js → fleet-validate-C5RI6DP7.js} +20 -19
- package/dist/{init-LQUB5COQ.js → init-VBN2ACVA.js} +70 -63
- package/dist/{library-NJAHIGG4.js → library-JHGUMLY2.js} +22 -20
- package/dist/{memory-OG6HOYKM.js → memory-K4OQIYWG.js} +49 -42
- package/dist/{models-5ZG5XY7J.js → models-2NCZUWDD.js} +35 -29
- package/dist/{monitor-TJ7AMTGB.js → monitor-MMVTJABD.js} +64 -45
- package/dist/{orchestrator-WZYB54DM.js → orchestrator-ZKBPCHW6.js} +1971 -520
- package/dist/{paths-XUC7GS6E.js → paths-DBXMZMDU.js} +5 -5
- package/dist/registry-LG64LTF4.js +11 -0
- package/dist/{reset-PXQT45IY.js → reset-DD5JGOY3.js} +11 -11
- package/dist/{run-FQ74YF62.js → run-QEGNX7FL.js} +89 -83
- package/dist/{share-FW7SVCL3.js → share-JKD3BQMW.js} +20 -18
- package/dist/{skills-7E7IRB3R.js → skills-LMQIKDOZ.js} +23 -21
- package/dist/{skills-eval-LI75W6OK.js → skills-eval-I7X2774U.js} +59 -52
- package/dist/{steer-GGWFUJUD.js → steer-CF5TDANS.js} +3 -3
- package/dist/support-I7LOJLIF.js +38 -0
- package/dist/{targets-4CIFKCTW.js → targets-RUSR6B5Z.js} +77 -42
- package/dist/{terminal-lease-WUZY7ZV5.js → terminal-lease-QYVORFR4.js} +6 -4
- package/dist/{trace-PNCASAXC.js → trace-ODOQIVIW.js} +61 -6
- package/dist/{uninstall-7FV7IP4E.js → uninstall-ZJF5H5ZN.js} +8 -8
- package/dist/{upgrade-K2HVIVMQ.js → upgrade-XANW3FXB.js} +29 -26
- package/dist/{usage-GTZELZQX.js → usage-4H7ZRXQT.js} +110 -61
- package/dist/{verifiers-RLAHT27O.js → verifiers-UZXNBZEB.js} +13 -13
- package/dist/{verify-BX3BRKH5.js → verify-BVKWTNDL.js} +9 -9
- package/dist/{wiki-generate-ASIFASCN.js → wiki-generate-MY7WV2QI.js} +76 -69
- package/dist/worker/entry.js +69 -66
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +1 -1
- package/docs/artifact-versions.md +11 -5
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +23 -2
- package/docs/commands-and-modes.md +2 -2
- package/docs/configuration-and-targets.md +37 -5
- package/docs/context-engine.md +63 -4
- package/docs/documentation-coverage.md +3 -3
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +2 -0
- package/docs/eval-runner.md +262 -11
- package/docs/evals-internal.md +72 -2
- package/docs/evidence-and-memory.md +77 -12
- package/docs/evolution.md +1 -1
- package/docs/extensions-and-sharing.md +3 -1
- package/docs/fleet-dispatch.md +34 -9
- package/docs/glossary.md +21 -1
- package/docs/installation-and-lifecycle.md +1 -1
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +54 -3
- package/docs/proactive-memory.md +127 -14
- package/docs/prompt-envelope-and-tools.md +22 -2
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +60 -41
- package/docs/safety-model.md +1 -1
- package/docs/scientific-validation.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +1 -1
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +87 -0
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +2 -2
- package/src/cli/agents.ts +1 -1
- package/src/cli/argv.ts +5 -0
- package/src/cli/config-inspect.ts +33 -6
- package/src/cli/config.ts +1 -1
- package/src/cli/configure.ts +107 -23
- package/src/cli/doctor-state-size.ts +82 -0
- package/src/cli/doctor.ts +7 -1
- package/src/cli/eval.ts +80 -16
- package/src/cli/evidence.ts +30 -25
- package/src/cli/extensions.ts +5 -1
- package/src/cli/fleet-preflight.ts +2 -12
- package/src/cli/fleet.ts +32 -3
- package/src/cli/shared.ts +1 -0
- package/src/cli/targets.ts +45 -11
- package/src/cli/trace.ts +63 -4
- package/src/cli/usage.ts +63 -14
- package/src/cli/validate-model.ts +60 -5
- package/src/core/bus-events.ts +54 -1
- package/src/core/cache-telemetry.ts +42 -0
- package/src/core/commit-attribution.ts +4 -4
- package/src/core/config.ts +18 -0
- package/src/core/defaults.ts +36 -6
- package/src/core/endpoint-key.ts +27 -0
- package/src/core/path-boundary.ts +100 -0
- package/src/core/residency-target-key.ts +25 -0
- package/src/core/response-schema.ts +36 -2
- package/src/domains/agents/extension.ts +2 -11
- package/src/domains/agents/fleet-contract.ts +30 -12
- package/src/domains/agents/recipe.ts +7 -1
- package/src/domains/agents/registry.ts +73 -5
- package/src/domains/agents/result-contract.ts +128 -17
- package/src/domains/agents/write-boundary.ts +15 -50
- package/src/domains/config/classify.ts +3 -0
- package/src/domains/context/codewiki/coordinator.ts +12 -4
- package/src/domains/context/project-rules.ts +51 -1
- package/src/domains/dispatch/admission.ts +40 -3
- package/src/domains/dispatch/assignment-reconcile.ts +22 -5
- package/src/domains/dispatch/assignment-store.ts +151 -14
- package/src/domains/dispatch/capacity-lease.ts +98 -9
- package/src/domains/dispatch/contract.ts +26 -1
- package/src/domains/dispatch/delegation-plan.ts +2 -5
- package/src/domains/dispatch/execution-plan.ts +44 -4
- package/src/domains/dispatch/execution-role.ts +9 -1
- package/src/domains/dispatch/extension.ts +309 -96
- package/src/domains/dispatch/fleet-run.ts +78 -4
- package/src/domains/dispatch/gate-role-prompts.ts +38 -0
- package/src/domains/dispatch/heartbeat.ts +32 -8
- package/src/domains/dispatch/index.ts +6 -1
- package/src/domains/dispatch/intent-requirements.ts +40 -0
- package/src/domains/dispatch/intent.ts +84 -8
- package/src/domains/dispatch/orphan-recovery.ts +5 -0
- package/src/domains/dispatch/path-scope.ts +370 -0
- package/src/domains/dispatch/receipt-integrity.ts +2 -1
- package/src/domains/dispatch/reservation-store.ts +116 -8
- package/src/domains/dispatch/state.ts +4 -0
- package/src/domains/dispatch/types.ts +14 -7
- package/src/domains/dispatch/validation.ts +6 -3
- package/src/domains/dispatch/worker-spawn.ts +25 -11
- package/src/domains/dispatch/write-boundary-enforcer.ts +62 -0
- package/src/domains/dispatch/write-boundary.ts +262 -22
- package/src/domains/eval/artifacts/store.ts +62 -0
- package/src/domains/eval/compare/behavioral.ts +224 -0
- package/src/domains/eval/compare/compare.ts +355 -2
- package/src/domains/eval/compare/envelope.ts +128 -0
- package/src/domains/eval/compare/gates.ts +24 -6
- package/src/domains/eval/compare/thresholds.ts +30 -3
- package/src/domains/eval/execution-provenance.ts +240 -0
- package/src/domains/eval/metrics/aggregate.ts +136 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
- package/src/domains/eval/metrics/evidence.ts +79 -2
- package/src/domains/eval/metrics/tracked.ts +413 -0
- package/src/domains/eval/provenance.ts +117 -0
- package/src/domains/eval/reports/comparison.ts +128 -0
- package/src/domains/eval/reports/junit.ts +17 -3
- package/src/domains/eval/reports/markdown.ts +3 -3
- package/src/domains/eval/reports/text.ts +14 -0
- package/src/domains/eval/run-compare.ts +20 -0
- package/src/domains/eval/runners/clio-run.ts +139 -2
- package/src/domains/eval/runners/external-command.ts +28 -3
- package/src/domains/eval/schema/adapter.ts +111 -0
- package/src/domains/eval/schema/artifact.ts +20 -0
- package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
- package/src/domains/eval/schema/behavioral.ts +520 -0
- package/src/domains/eval/schema/execution-envelope.ts +194 -0
- package/src/domains/eval/schema/serving.ts +74 -0
- package/src/domains/eval/schema/suite.ts +38 -8
- package/src/domains/eval/schema/validate.ts +58 -3
- package/src/domains/eval/schema/verdict.ts +237 -0
- package/src/domains/eval/suites/resolve.ts +2 -0
- package/src/domains/eval/suites/run.ts +264 -33
- package/src/domains/eval/verifiers/command.ts +2 -1
- package/src/domains/eval/workspaces/temp-copy.ts +145 -13
- package/src/domains/evidence/build.ts +68 -21
- package/src/domains/evidence/eval.ts +2 -12
- package/src/domains/evidence/findings-markdown.ts +33 -0
- package/src/domains/evidence/index.ts +21 -0
- package/src/domains/evidence/provenance.ts +46 -11
- package/src/domains/evidence/run-trust.ts +7 -113
- package/src/domains/evidence/trust-projection.ts +274 -0
- package/src/domains/evidence/trust-status.ts +145 -17
- package/src/domains/evidence/types.ts +4 -0
- package/src/domains/extensions/compatibility.ts +285 -0
- package/src/domains/extensions/discovery.ts +126 -4
- package/src/domains/extensions/resources.ts +21 -9
- package/src/domains/extensions/state.ts +18 -5
- package/src/domains/extensions/types.ts +6 -1
- package/src/domains/lifecycle/doctor.ts +209 -2
- package/src/domains/memory/index.ts +14 -0
- package/src/domains/memory/task-bank-promotion.ts +64 -0
- package/src/domains/memory/task-memory-policy.ts +77 -8
- package/src/domains/memory/task-memory-spend.ts +131 -0
- package/src/domains/memory/task-memory-status.ts +7 -0
- package/src/domains/memory/task-memory-telemetry.ts +2 -0
- package/src/domains/middleware/index.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +69 -5
- package/src/domains/middleware/memory-step-endpoint.ts +71 -0
- package/src/domains/observability/background-memory-usage.ts +140 -0
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/index.ts +7 -0
- package/src/domains/observability/out-of-turn-usage.ts +51 -2
- package/src/domains/observability/trace-store.ts +192 -2
- package/src/domains/prompts/compiler.ts +100 -13
- package/src/domains/prompts/contract.ts +3 -5
- package/src/domains/providers/endpoint-capacity.ts +96 -0
- package/src/domains/providers/extension.ts +30 -2
- package/src/domains/providers/index.ts +10 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
- package/src/domains/providers/runtime-resolution.ts +8 -1
- package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
- package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
- package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/target-descriptor.ts +2 -0
- package/src/domains/resources/common-loader.ts +3 -0
- package/src/domains/resources/prompts/loader.ts +184 -17
- package/src/domains/safety/call-target.ts +52 -0
- package/src/domains/safety/policy-engine.ts +5 -5
- package/src/domains/safety/run-effects.ts +96 -2
- package/src/domains/safety/scope.ts +7 -12
- package/src/domains/session/context-accounting.ts +52 -1
- package/src/domains/session/context-ledger.ts +37 -13
- package/src/domains/session/index.ts +6 -0
- package/src/domains/session/prompt-cache.ts +140 -0
- package/src/domains/session/prompt-manifest.ts +42 -0
- package/src/engine/acp/adapter.ts +18 -3
- package/src/engine/acp/server.ts +4 -1
- package/src/engine/ai.ts +35 -0
- package/src/engine/apis/llamacpp-residency.ts +55 -3
- package/src/engine/apis/lmstudio.ts +25 -5
- package/src/engine/apis/ollama-native.ts +2 -1
- package/src/engine/apis/openai-completions.ts +80 -17
- package/src/engine/apis/residency-lock.ts +3 -1
- package/src/engine/apis/residency.ts +34 -1
- package/src/engine/prompt-templates.ts +18 -1
- package/src/engine/provider-payload.ts +29 -1
- package/src/engine/worker-runtime.ts +6 -3
- package/src/entry/orchestrator.ts +176 -30
- package/src/interactive/chat-loop-messages.ts +26 -7
- package/src/interactive/chat-loop.ts +318 -41
- package/src/interactive/chat-panel.ts +62 -8
- package/src/interactive/clio-editor.ts +45 -8
- package/src/interactive/context-activity.ts +5 -1
- package/src/interactive/context-meter.ts +1 -1
- package/src/interactive/context-overlay.ts +40 -10
- package/src/interactive/cost-overlay.ts +64 -6
- package/src/interactive/dispatch-board.ts +127 -5
- package/src/interactive/fleet-run-preview.ts +41 -15
- package/src/interactive/handoff-round.ts +41 -2
- package/src/interactive/interactive-application.ts +24 -1
- package/src/interactive/interactive-event-projection.ts +14 -0
- package/src/interactive/interactive-input-runtime.ts +8 -0
- package/src/interactive/interactive-presentation.ts +4 -0
- package/src/interactive/interactive-shell.ts +20 -17
- package/src/interactive/interactive-slash-runtime.ts +27 -4
- package/src/interactive/memory-overlay.ts +8 -0
- package/src/interactive/mutation-preview.ts +295 -0
- package/src/interactive/overlay-general-openers.ts +16 -0
- package/src/interactive/overlay-key-routing.ts +38 -0
- package/src/interactive/overlay-lifecycle.ts +38 -5
- package/src/interactive/overlay-permission-lifecycle.ts +22 -2
- package/src/interactive/overlay-session-lifecycle.ts +73 -9
- package/src/interactive/overlays/ask-user.ts +91 -19
- package/src/interactive/overlays/help-reference.ts +4 -0
- package/src/interactive/overlays/prompts.ts +11 -1
- package/src/interactive/overlays/settings.ts +176 -48
- package/src/interactive/permission-hint.ts +34 -2
- package/src/interactive/permission-overlay.ts +159 -9
- package/src/interactive/prewarm.ts +197 -0
- package/src/interactive/render-trace.ts +162 -15
- package/src/interactive/renderers/tool-execution.ts +4 -0
- package/src/interactive/side-question.ts +58 -1
- package/src/interactive/slash-commands.ts +7 -2
- package/src/interactive/status/controller.ts +11 -0
- package/src/interactive/status/state-machine.ts +54 -2
- package/src/interactive/status/types.ts +7 -0
- package/src/interactive/terminal-lease.ts +2 -0
- package/src/interactive/turn-context.ts +299 -31
- package/src/interactive/turn-persistence.ts +14 -4
- package/src/interactive/turn-prewarm.ts +364 -0
- package/src/interactive/turn-queues.ts +7 -4
- package/src/interactive/turn-runtime.ts +8 -1
- package/src/interactive/turn-state.ts +23 -0
- package/src/interactive/view/artifacts.ts +42 -9
- package/src/interactive/view/view-overlay.ts +43 -6
- package/src/interactive/worker-receipts.ts +14 -2
- package/src/interactive/worker-stream.ts +8 -0
- package/src/tools/ask-user.ts +43 -2
- package/src/tools/dispatch-admission.ts +12 -13
- package/src/tools/dispatch-arguments.ts +27 -0
- package/src/tools/dispatch-plan.ts +46 -9
- package/src/tools/dispatch-runner.ts +48 -13
- package/src/tools/dispatch-scout.ts +1 -1
- package/src/tools/monitor.ts +13 -0
- package/src/tools/registry.ts +16 -0
- package/src/tools/worker-evidence.ts +19 -13
- package/src/worker/spec-contract.ts +2 -1
- package/dist/chunk-AOCYTWAV.js +0 -449
- package/dist/chunk-HWUFFB6L.js +0 -83
- package/dist/chunk-R346GLFC.js +0 -31
- package/dist/chunk-ZGH7FGS5.js +0 -1079
- package/dist/doctor-RN4YKO2X.js +0 -87
- package/dist/eval-RUBJVSNQ.js +0 -2557
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
import { existsSync, readFileSync } from "node:fs";
|
|
17
17
|
import { join } from "node:path";
|
|
18
18
|
import { clioStateDir } from "../core/xdg.js";
|
|
19
|
+
import type { RunEnvelope, RunReceipt } from "../domains/dispatch/types.js";
|
|
20
|
+
import { inspectRunReceiptTrustStatus } from "../domains/evidence/trust-status.js";
|
|
19
21
|
import { receiptFilePath } from "./view/artifacts.js";
|
|
20
22
|
import type { WorkerReceiptFacts, WorkerResultContract } from "./worker-stream.js";
|
|
21
23
|
|
|
@@ -86,12 +88,22 @@ export function workerReceiptFacts(receipt: Record<string, unknown>): WorkerRece
|
|
|
86
88
|
|
|
87
89
|
/** Read and project `<state>/receipts/<runId>.json` alone; null when it is absent or unreadable. */
|
|
88
90
|
function readReceiptFileFacts(runId: string, stateDir: string): WorkerReceiptFacts | null {
|
|
91
|
+
let parsed: unknown;
|
|
89
92
|
try {
|
|
90
|
-
|
|
91
|
-
return isRecord(parsed) ? workerReceiptFacts(parsed) : null;
|
|
93
|
+
parsed = JSON.parse(readFileSync(receiptFilePath(stateDir, runId), "utf8"));
|
|
92
94
|
} catch {
|
|
93
95
|
return null;
|
|
94
96
|
}
|
|
97
|
+
if (!isRecord(parsed)) return null;
|
|
98
|
+
const facts = workerReceiptFacts(parsed);
|
|
99
|
+
if (facts === null) return null;
|
|
100
|
+
// The trust verdict is an authenticated read-back: the receipt file
|
|
101
|
+
// against the ledger row it was sealed from. Without the row there is no
|
|
102
|
+
// authentication, and no verdict is better than a guessed one.
|
|
103
|
+
const row = findRunRow(runId, stateDir);
|
|
104
|
+
if (row === null) return facts;
|
|
105
|
+
const trust = inspectRunReceiptTrustStatus(parsed as unknown as RunReceipt, row as unknown as RunEnvelope).status;
|
|
106
|
+
return { ...facts, trust };
|
|
95
107
|
}
|
|
96
108
|
|
|
97
109
|
/** Read and project `<state>/receipts/<runId>.json`; null when it is absent or unreadable. */
|
|
@@ -42,6 +42,7 @@ import type {
|
|
|
42
42
|
RunAbortedPayload,
|
|
43
43
|
} from "../core/bus-events.js";
|
|
44
44
|
import type { RunKind } from "../domains/dispatch/types.js";
|
|
45
|
+
import type { CanonicalTrustStatus } from "../domains/evidence/trust-status.js";
|
|
45
46
|
import type { WorkerRunOrigin, WorkerRunRuntime, WorkerRunRuntimeKind } from "../domains/session/index.js";
|
|
46
47
|
import { createWorkerProgressFold, type WorkerProgressFold, type WorkerProgressSnapshot } from "./worker-progress.js";
|
|
47
48
|
|
|
@@ -88,6 +89,13 @@ export interface WorkerReceiptSummary {
|
|
|
88
89
|
/** A receipt's projection: the summary plus the answer it sealed. */
|
|
89
90
|
export interface WorkerReceiptFacts extends WorkerReceiptSummary {
|
|
90
91
|
text?: string;
|
|
92
|
+
/**
|
|
93
|
+
* The canonical trust status of the persisted receipt, authenticated
|
|
94
|
+
* against the persisted ledger row it was sealed from. Present only when
|
|
95
|
+
* both could be read back, so a surface that shows it shows an
|
|
96
|
+
* authenticated verdict and never the sealing process's own claim.
|
|
97
|
+
*/
|
|
98
|
+
trust?: CanonicalTrustStatus;
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
/** Reads `receipts/<runId>.json` and projects it; null when it is absent or unreadable. */
|
package/src/tools/ask-user.ts
CHANGED
|
@@ -40,13 +40,27 @@ export interface AskUserQuestion {
|
|
|
40
40
|
|
|
41
41
|
export interface AskUserAnswer {
|
|
42
42
|
question: string;
|
|
43
|
+
/** The whole answer on one line: the chosen labels, then the typed text. */
|
|
43
44
|
answer: string;
|
|
45
|
+
/**
|
|
46
|
+
* The option labels the operator chose, in list order. Absent when they only
|
|
47
|
+
* typed. Present with no {@link value} is a label-only answer, which is how a
|
|
48
|
+
* reader tells "they picked the option" from "they picked it and typed a
|
|
49
|
+
* figure" (issue #228).
|
|
50
|
+
*/
|
|
51
|
+
options?: string[];
|
|
52
|
+
/** The operator's typed text, exactly as submitted. Absent when they only chose. */
|
|
53
|
+
value?: string;
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
export interface AskUserDecision {
|
|
47
57
|
key: string;
|
|
48
58
|
value: string;
|
|
49
59
|
label?: string;
|
|
60
|
+
/** The chosen labels behind `value`; derived by the harness, not model-supplied. */
|
|
61
|
+
options?: string[];
|
|
62
|
+
/** The typed text behind `value`; derived by the harness, not model-supplied. */
|
|
63
|
+
text?: string;
|
|
50
64
|
/** Question that produced this decision; derived by the harness, not model-supplied. */
|
|
51
65
|
source_question?: string;
|
|
52
66
|
}
|
|
@@ -299,6 +313,13 @@ export function cancelledAskUserResult(): AskUserResult {
|
|
|
299
313
|
return { answers: [], cancelled: true };
|
|
300
314
|
}
|
|
301
315
|
|
|
316
|
+
/** The chosen labels, dropped when the surface supplied nothing usable. */
|
|
317
|
+
function normalizeAnswerOptions(value: unknown): string[] | undefined {
|
|
318
|
+
if (!Array.isArray(value)) return undefined;
|
|
319
|
+
const labels = value.filter((entry): entry is string => typeof entry === "string" && entry.trim().length > 0);
|
|
320
|
+
return labels.length > 0 ? labels : undefined;
|
|
321
|
+
}
|
|
322
|
+
|
|
302
323
|
function normalizeAskUserResult(questions: ReadonlyArray<AskUserQuestion>, result: AskUserResult): AskUserResult {
|
|
303
324
|
if (result.cancelled === true) return cancelledAskUserResult();
|
|
304
325
|
const answers: AskUserAnswer[] = [];
|
|
@@ -308,7 +329,18 @@ function normalizeAskUserResult(questions: ReadonlyArray<AskUserQuestion>, resul
|
|
|
308
329
|
if (!raw) continue;
|
|
309
330
|
const question = typeof raw.question === "string" && raw.question.trim().length > 0 ? raw.question : fallbackQuestion;
|
|
310
331
|
const answer = typeof raw.answer === "string" ? raw.answer.trim() : "";
|
|
311
|
-
if (question.length
|
|
332
|
+
if (question.length === 0 || answer.length === 0) continue;
|
|
333
|
+
// The typed text keeps every byte the operator submitted. The one-line
|
|
334
|
+
// `answer` is a rendering of the same decision and is trimmed like any
|
|
335
|
+
// other display string; `value` is the record.
|
|
336
|
+
const options = normalizeAnswerOptions(raw.options);
|
|
337
|
+
const value = typeof raw.value === "string" && raw.value.length > 0 ? raw.value : undefined;
|
|
338
|
+
answers.push({
|
|
339
|
+
question,
|
|
340
|
+
answer,
|
|
341
|
+
...(options ? { options } : {}),
|
|
342
|
+
...(value !== undefined ? { value } : {}),
|
|
343
|
+
});
|
|
312
344
|
}
|
|
313
345
|
return { answers };
|
|
314
346
|
}
|
|
@@ -363,7 +395,12 @@ function transcriptQuestions(questions: ReadonlyArray<AskUserQuestion>): AskUser
|
|
|
363
395
|
}
|
|
364
396
|
|
|
365
397
|
function transcriptAnswers(answers: ReadonlyArray<AskUserAnswer>): AskUserTranscriptAnswer[] {
|
|
366
|
-
return answers.map((answer) => ({
|
|
398
|
+
return answers.map((answer) => ({
|
|
399
|
+
question: answer.question,
|
|
400
|
+
answer: answer.answer,
|
|
401
|
+
...(answer.options && answer.options.length > 0 ? { options: [...answer.options] } : {}),
|
|
402
|
+
...(answer.value !== undefined ? { value: answer.value } : {}),
|
|
403
|
+
}));
|
|
367
404
|
}
|
|
368
405
|
|
|
369
406
|
function toDecisionKey(value: string): string {
|
|
@@ -397,6 +434,8 @@ function decisionFromAnswer(
|
|
|
397
434
|
key,
|
|
398
435
|
value: answer.answer,
|
|
399
436
|
...(label ? { label } : {}),
|
|
437
|
+
...(answer.options && answer.options.length > 0 ? { options: [...answer.options] } : {}),
|
|
438
|
+
...(answer.value !== undefined ? { text: answer.value } : {}),
|
|
400
439
|
source_question: answer.question,
|
|
401
440
|
};
|
|
402
441
|
}
|
|
@@ -406,6 +445,8 @@ function toTranscriptDecision(decision: AskUserDecision): AskUserTranscriptDecis
|
|
|
406
445
|
key: toDecisionKey(decision.key),
|
|
407
446
|
value: decision.value,
|
|
408
447
|
...(decision.label ? { label: decision.label } : {}),
|
|
448
|
+
...(decision.options && decision.options.length > 0 ? { options: [...decision.options] } : {}),
|
|
449
|
+
...(decision.text !== undefined ? { text: decision.text } : {}),
|
|
409
450
|
...(decision.source_question ? { source_question: decision.source_question } : {}),
|
|
410
451
|
};
|
|
411
452
|
}
|
|
@@ -6,8 +6,10 @@ import {
|
|
|
6
6
|
COUNCIL_JUDGE_PROMPT,
|
|
7
7
|
JUDGE_GATE_PROMPT,
|
|
8
8
|
REVIEWER_GATE_PROMPT,
|
|
9
|
+
renderCouncilVoteMemberTask,
|
|
9
10
|
} from "../domains/dispatch/gate-role-prompts.js";
|
|
10
11
|
import { normalizeDispatchIntent } from "../domains/dispatch/intent.js";
|
|
12
|
+
import { renderDispatchReviewerTask } from "../domains/dispatch/intent-requirements.js";
|
|
11
13
|
import { approvedRouteCandidates } from "../domains/dispatch/route-approval.js";
|
|
12
14
|
import { defaultRoutingIntent } from "../domains/dispatch/routing-intent.js";
|
|
13
15
|
import type { DispatchFailoverMode } from "../domains/dispatch/validation.js";
|
|
@@ -139,15 +141,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
139
141
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
140
142
|
}
|
|
141
143
|
|
|
142
|
-
function reviewerTask(originalTask: string, builderRunId: string, cycle: number): string {
|
|
143
|
-
return [
|
|
144
|
-
`Review the work of builder run ${builderRunId} (review cycle ${cycle}).`,
|
|
145
|
-
"The builder's final answer is provided as input data; verify it against the workspace, do not trust it blindly.",
|
|
146
|
-
"Original task the builder was given:",
|
|
147
|
-
originalTask,
|
|
148
|
-
].join("\n\n");
|
|
149
|
-
}
|
|
150
|
-
|
|
151
144
|
function reviewSettingsFromArgs(
|
|
152
145
|
args: Record<string, unknown>,
|
|
153
146
|
): { ok: true; review: DispatchReviewSettings | undefined } | { ok: false; message: string } {
|
|
@@ -534,9 +527,6 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
534
527
|
if (parsed.requests.length !== 1 || parsed.requests[0] === undefined) {
|
|
535
528
|
return shapeRejection(args, REVIEW_SINGLE_TASK_MESSAGE);
|
|
536
529
|
}
|
|
537
|
-
if (parsed.requests.some((request) => (request.resolvedVerification?.length ?? 0) > 0)) {
|
|
538
|
-
return shapeRejection(args, "verification_unsupported_for_mode: review requests cannot run host verification");
|
|
539
|
-
}
|
|
540
530
|
}
|
|
541
531
|
if (mode === "compete" && (parsed.requests.length !== 1 || parsed.requests[0] === undefined)) {
|
|
542
532
|
return shapeRejection(args, COMPETE_SINGLE_TASK_MESSAGE);
|
|
@@ -587,7 +577,7 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
587
577
|
{
|
|
588
578
|
agentId: gateDeciderAgentId(reviewResult.review.reviewer),
|
|
589
579
|
executionRole: "reviewer",
|
|
590
|
-
task:
|
|
580
|
+
task: renderDispatchReviewerTask(base.task, subject.runId, cycle, base.intent),
|
|
591
581
|
systemPrompt: REVIEWER_GATE_PROMPT,
|
|
592
582
|
autonomy: "read-only",
|
|
593
583
|
gate: { role: "reviewer", group: "plan-preview", cycle, subjects: [subject] },
|
|
@@ -648,6 +638,15 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
648
638
|
executionRole: "researcher",
|
|
649
639
|
autonomy: "read-only",
|
|
650
640
|
toolProfile: "council-read-only",
|
|
641
|
+
// The runner reuses this composed task from the resolved plan, so
|
|
642
|
+
// the approval artifact the plan hash binds shows the operator the
|
|
643
|
+
// exact ballot the member is asked to cast.
|
|
644
|
+
...(council.synthesis === "vote"
|
|
645
|
+
? {
|
|
646
|
+
task: renderCouncilVoteMemberTask(base.task),
|
|
647
|
+
resultContractOverride: { kind: "council-ballot" as const },
|
|
648
|
+
}
|
|
649
|
+
: {}),
|
|
651
650
|
target: member.target,
|
|
652
651
|
...(member.model ? { model: member.model } : {}),
|
|
653
652
|
...(member.thinking ? { thinkingLevel: member.thinking as NonNullable<DispatchRequest["thinkingLevel"]> } : {}),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Pure model-argument parsing; every returned DispatchRequest has a concrete agent id. */
|
|
2
2
|
|
|
3
|
+
import { pathBoundaryCovers } from "../core/path-boundary.js";
|
|
3
4
|
import type { AgentAutomationAuthority } from "../domains/agents/spec.js";
|
|
4
5
|
import { type AgentTaskType, classifyAgentTask } from "../domains/dispatch/agent-candidates.js";
|
|
5
6
|
import { cloneDispatchBudgetRequest } from "../domains/dispatch/budget-envelope.js";
|
|
@@ -261,8 +262,34 @@ export function dispatchRequestsFromArgs(
|
|
|
261
262
|
for (let index = 0; index < tasks.length; index += 1) {
|
|
262
263
|
const item = tasks[index];
|
|
263
264
|
const itemArgs: Record<string, unknown> = isRecord(item) ? { ...shared, ...item } : { ...shared, task: item };
|
|
265
|
+
const sharedIntent = isRecord(shared.intent) ? shared.intent : null;
|
|
266
|
+
const itemIntent = isRecord(item) && Object.hasOwn(item, "intent") && isRecord(item.intent) ? item.intent : null;
|
|
267
|
+
if (sharedIntent !== null && itemIntent !== null) itemArgs.intent = { ...sharedIntent, ...itemIntent };
|
|
264
268
|
const parsed = dispatchRequestFromArgs(itemArgs, options);
|
|
265
269
|
if (!parsed.ok) return { ok: false, message: `dispatch: task ${index + 1}: ${parsed.message}` };
|
|
270
|
+
if (sharedIntent !== null && itemIntent !== null) {
|
|
271
|
+
if (options.resolveIntent === undefined) {
|
|
272
|
+
return { ok: false, message: `dispatch: task ${index + 1}: intent resolver is unavailable` };
|
|
273
|
+
}
|
|
274
|
+
const ceiling = options.resolveIntent(sharedIntent, parsed.request.cwd);
|
|
275
|
+
if (!ceiling.ok) return { ok: false, message: `dispatch: task ${index + 1}: ${ceiling.message}` };
|
|
276
|
+
const pathCeilings = {
|
|
277
|
+
readRoots: [...ceiling.intent.readRoots, ...ceiling.intent.writeRoots],
|
|
278
|
+
writeRoots: ceiling.intent.writeRoots,
|
|
279
|
+
relevantPaths: [...ceiling.intent.readRoots, ...ceiling.intent.writeRoots, ...ceiling.intent.relevantPaths],
|
|
280
|
+
};
|
|
281
|
+
for (const field of ["readRoots", "writeRoots", "relevantPaths"] as const) {
|
|
282
|
+
const outside = parsed.request.intent?.[field].find(
|
|
283
|
+
(candidate) => !pathBoundaryCovers(pathCeilings[field], candidate),
|
|
284
|
+
);
|
|
285
|
+
if (outside !== undefined) {
|
|
286
|
+
return {
|
|
287
|
+
ok: false,
|
|
288
|
+
message: `dispatch: task ${index + 1}: intent_scope_widening: ${field} entry '${outside}' is outside the top-level intent ceiling`,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
266
293
|
requests.push(parsed.request);
|
|
267
294
|
}
|
|
268
295
|
return { ok: true, requests };
|
|
@@ -21,6 +21,7 @@ import { AGENT_AUTOMATION_AUTHORITIES, type AgentAutomationAuthority } from "../
|
|
|
21
21
|
import type { DispatchRequest } from "../domains/dispatch/contract.js";
|
|
22
22
|
import { type ExecutionRole, isExecutionRole } from "../domains/dispatch/execution-role.js";
|
|
23
23
|
import { type DispatchIntent, isDispatchIntent } from "../domains/dispatch/intent.js";
|
|
24
|
+
import { resolveDispatchPathScope } from "../domains/dispatch/path-scope.js";
|
|
24
25
|
import {
|
|
25
26
|
type ApprovedAssignmentRoute,
|
|
26
27
|
cloneApprovedAssignmentRoute,
|
|
@@ -235,15 +236,46 @@ function str(value: unknown): string | undefined {
|
|
|
235
236
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
236
237
|
}
|
|
237
238
|
|
|
238
|
-
/** Keep terminal control bytes and line breaks out of approval artifacts. */
|
|
239
|
-
function safeField(value: string): string {
|
|
239
|
+
/** Keep terminal control bytes and line breaks out of approval artifacts without losing their identity. */
|
|
240
|
+
function safeField(value: string, bindChangedValue = true): string {
|
|
240
241
|
let result = "";
|
|
241
242
|
for (const character of value) {
|
|
242
243
|
const code = character.codePointAt(0) ?? 0;
|
|
243
244
|
result += code < 32 || (code >= 127 && code <= 159) ? "?" : character;
|
|
244
|
-
if (result.length >= 256)
|
|
245
|
+
if (result.length >= 256) {
|
|
246
|
+
result = `${result.slice(0, 255)}…`;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (!bindChangedValue || result === value) return result;
|
|
251
|
+
return `${result}{sha256=${createHash("sha256").update(value, "utf8").digest("hex")}}`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function renderLegacyPathScope(task: DispatchPlanTaskView): string[] {
|
|
255
|
+
if (task.intent !== undefined) return [];
|
|
256
|
+
const scope = resolveDispatchPathScope({
|
|
257
|
+
agentId: task.agent,
|
|
258
|
+
executionRole: task.executionRole,
|
|
259
|
+
task: task.task,
|
|
260
|
+
...(task.briefing !== undefined ? { briefing: task.briefing } : {}),
|
|
261
|
+
});
|
|
262
|
+
const lines = [" scope mode=legacy-inferred"];
|
|
263
|
+
for (const [policy, entries] of [
|
|
264
|
+
["working_context", scope.provenance.workingContextPaths],
|
|
265
|
+
["write_boundary", scope.provenance.writeBoundaries],
|
|
266
|
+
] as const) {
|
|
267
|
+
for (const entry of entries) {
|
|
268
|
+
for (const evidence of entry.evidence) {
|
|
269
|
+
lines.push(
|
|
270
|
+
` scope ${policy} path=${JSON.stringify(safeField(entry.path))} provenance=${evidence.provenance} source=${evidence.source} confidence=${evidence.confidence} reason=${evidence.reason}`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (scope.provenance.workingContextPaths.length === 0 && scope.provenance.writeBoundaries.length === 0) {
|
|
276
|
+
lines.push(" scope policy_paths=none");
|
|
245
277
|
}
|
|
246
|
-
return
|
|
278
|
+
return lines;
|
|
247
279
|
}
|
|
248
280
|
|
|
249
281
|
function taskViews(args: Record<string, unknown>): DispatchPlanTaskView[] {
|
|
@@ -365,7 +397,7 @@ function renderPlanText(
|
|
|
365
397
|
? ""
|
|
366
398
|
: ` posture=${routing.posture} maxCostUsd=${routing.maxCostUsd ?? "none"} deadlineMs=${routing.deadlineMs ?? "none"} minimumQuality=${routing.minimumQuality ?? "none"} locality=${routing.locality}`;
|
|
367
399
|
lines.push(
|
|
368
|
-
` ${index + 1}.${role} agent=${safeField(task.agent)}${target}${model}${node}${failover}${routingText} task=${JSON.stringify(safeField(task.task))}`,
|
|
400
|
+
` ${index + 1}.${role} agent=${safeField(task.agent)}${target}${model}${node}${failover}${routingText} task_bytes=${Buffer.byteLength(task.task, "utf8")} task_sha256=${createHash("sha256").update(task.task, "utf8").digest("hex")} task_preview=${JSON.stringify(safeField(task.task, false))}`,
|
|
369
401
|
);
|
|
370
402
|
if (task.council !== undefined) {
|
|
371
403
|
lines.push(
|
|
@@ -392,31 +424,36 @@ function renderPlanText(
|
|
|
392
424
|
}
|
|
393
425
|
if (task.agentSelection !== null) {
|
|
394
426
|
lines.push(
|
|
395
|
-
` agent-selection=auto baseline=${safeField(task.agentSelection.baselineAgentId)} authority=${task.agentSelection.approvedAuthorities.map(safeField).join(",")} basis=${task.agentSelection.authorityBasis}`,
|
|
427
|
+
` agent-selection=auto baseline=${safeField(task.agentSelection.baselineAgentId)} authority=${task.agentSelection.approvedAuthorities.map((authority) => safeField(authority)).join(",")} basis=${task.agentSelection.authorityBasis}`,
|
|
396
428
|
);
|
|
397
429
|
}
|
|
398
430
|
if (task.stepId !== null) {
|
|
399
431
|
lines.push(
|
|
400
|
-
` step=${safeField(task.stepId)} wave=${task.wave ?? "?"} role=${task.executionRole} dependencies=${task.dependencies.map(safeField).join(",") || "none"} result=${task.expectedResultContract ?? "none"} authority=${task.authorityGrant?.requested ?? "none"} basis=${task.authorityGrant?.basis ?? "none"}`,
|
|
432
|
+
` step=${safeField(task.stepId)} wave=${task.wave ?? "?"} role=${task.executionRole} dependencies=${task.dependencies.map((dependency) => safeField(dependency)).join(",") || "none"} result=${task.expectedResultContract ?? "none"} authority=${task.authorityGrant?.requested ?? "none"} basis=${task.authorityGrant?.basis ?? "none"}`,
|
|
401
433
|
);
|
|
402
434
|
const agentReasons = task.agentDecision?.agentSelection.evaluations
|
|
403
435
|
.filter((evaluation) => evaluation.rejections.length > 0)
|
|
404
436
|
.slice(0, 8)
|
|
405
437
|
.map(
|
|
406
|
-
(evaluation) =>
|
|
438
|
+
(evaluation) =>
|
|
439
|
+
`${safeField(evaluation.agentId)}:${evaluation.rejections
|
|
440
|
+
.slice(0, 4)
|
|
441
|
+
.map((rejection) => safeField(rejection))
|
|
442
|
+
.join(",")}`,
|
|
407
443
|
);
|
|
408
444
|
if (agentReasons !== undefined && agentReasons.length > 0)
|
|
409
445
|
lines.push(` agent-exclusions=${agentReasons.join(";")}`);
|
|
410
446
|
}
|
|
411
447
|
if (task.briefing !== undefined) {
|
|
412
448
|
lines.push(
|
|
413
|
-
` briefing_bytes=${Buffer.byteLength(task.briefing, "utf8")} briefing_sha256=${createHash("sha256").update(task.briefing, "utf8").digest("hex")} briefing_preview=${JSON.stringify(safeField(task.briefing))}`,
|
|
449
|
+
` briefing_bytes=${Buffer.byteLength(task.briefing, "utf8")} briefing_sha256=${createHash("sha256").update(task.briefing, "utf8").digest("hex")} briefing_preview=${JSON.stringify(safeField(task.briefing, false))}`,
|
|
414
450
|
);
|
|
415
451
|
}
|
|
416
452
|
if (task.intent !== undefined) {
|
|
417
453
|
const serialized = JSON.stringify(task.intent);
|
|
418
454
|
lines.push(` intent_sha256=${createHash("sha256").update(serialized, "utf8").digest("hex")}`);
|
|
419
455
|
}
|
|
456
|
+
lines.push(...renderLegacyPathScope(task));
|
|
420
457
|
for (const check of task.resolvedVerification ?? []) {
|
|
421
458
|
lines.push(
|
|
422
459
|
` verification check=${safeField(check.check)} argv=${JSON.stringify(check.argv)} cwd=${JSON.stringify(check.cwd)} timeout_ms=${check.timeoutMs}`,
|
|
@@ -38,12 +38,15 @@ import {
|
|
|
38
38
|
type CompeteStance,
|
|
39
39
|
JUDGE_GATE_PROMPT,
|
|
40
40
|
REVIEWER_GATE_PROMPT,
|
|
41
|
+
renderCouncilVoteMemberTask,
|
|
41
42
|
} from "../domains/dispatch/gate-role-prompts.js";
|
|
43
|
+
import { renderDispatchReviewerTask } from "../domains/dispatch/intent-requirements.js";
|
|
42
44
|
import { UNVERIFIABLE_RECEIPT_VERIFICATION } from "../domains/dispatch/receipt-findings.js";
|
|
43
45
|
import { type ReceiptIntegrityResult, verifyReceiptIntegrity } from "../domains/dispatch/receipt-integrity.js";
|
|
44
46
|
import { explainRouteDecision } from "../domains/dispatch/routing-intent.js";
|
|
45
47
|
import type { RunGateProvenance, RunGateSubjectRef, RunPlanProvenance, RunReceipt } from "../domains/dispatch/types.js";
|
|
46
48
|
import { extractRunProvenance, provenanceCompactSuffix } from "../domains/evidence/provenance.js";
|
|
49
|
+
import { summarizeTrustStatus } from "../domains/evidence/trust-projection.js";
|
|
47
50
|
import { adaptRunReceiptTrustStatus } from "../domains/evidence/trust-status.js";
|
|
48
51
|
import type { AutonomyLevel } from "../domains/safety/autonomy.js";
|
|
49
52
|
import {
|
|
@@ -580,6 +583,10 @@ function dispatchDetails(
|
|
|
580
583
|
hostVerification: integrity.ok ? (receipt.hostVerification ?? null) : null,
|
|
581
584
|
receiptIntegrity: integrity,
|
|
582
585
|
trustStatus,
|
|
586
|
+
// The bounded projection sits shallow and flat on purpose: a
|
|
587
|
+
// depth-capped wire (ACP rawOutput) keeps it whole while the
|
|
588
|
+
// canonical status's nested references fall off the end.
|
|
589
|
+
trust: summarizeTrustStatus(trustStatus),
|
|
583
590
|
...(receipt.outcome !== undefined && receipt.outcome !== "succeeded"
|
|
584
591
|
? { outcome: receipt.outcome, outcomeDetail: receipt.outcomeDetail ?? null }
|
|
585
592
|
: {}),
|
|
@@ -632,15 +639,6 @@ function competeCorrelation(
|
|
|
632
639
|
return gateCorrelationOf(subject, decider);
|
|
633
640
|
}
|
|
634
641
|
|
|
635
|
-
function reviewerTask(originalTask: string, builderRunId: string, cycle: number): string {
|
|
636
|
-
return [
|
|
637
|
-
`Review the work of builder run ${builderRunId} (review cycle ${cycle}).`,
|
|
638
|
-
"The builder's final answer is provided as input data; verify it against the workspace, do not trust it blindly.",
|
|
639
|
-
"Original task the builder was given:",
|
|
640
|
-
originalTask,
|
|
641
|
-
].join("\n\n");
|
|
642
|
-
}
|
|
643
|
-
|
|
644
642
|
type ReviewGateSettings = DispatchReviewSettings;
|
|
645
643
|
|
|
646
644
|
const REVIEW_SINGLE_TASK_MESSAGE =
|
|
@@ -787,7 +785,7 @@ async function runReviewGated(
|
|
|
787
785
|
const reviewerRequest: DispatchRequest = {
|
|
788
786
|
agentId: gateDeciderAgentId(review.reviewer),
|
|
789
787
|
executionRole: "reviewer",
|
|
790
|
-
task:
|
|
788
|
+
task: renderDispatchReviewerTask(base.task, builder.receipt.runId, cycle, base.intent),
|
|
791
789
|
systemPrompt: REVIEWER_GATE_PROMPT,
|
|
792
790
|
autonomy: "read-only",
|
|
793
791
|
gate: { role: "reviewer", group, cycle, subjects: [subjectRef(builder.receipt)] },
|
|
@@ -1797,10 +1795,19 @@ function competeResult(
|
|
|
1797
1795
|
const COUNCIL_BRIEFING_MAX_BYTES = 8 * 1024;
|
|
1798
1796
|
const COUNCIL_BRIEFING_TRUNCATION = "\n[council peer briefing truncated]";
|
|
1799
1797
|
|
|
1798
|
+
/**
|
|
1799
|
+
* The verdict a council answer casts, lower-cased.
|
|
1800
|
+
*
|
|
1801
|
+
* A tally groups by the exact string, so folding case is the difference
|
|
1802
|
+
* between two members who both said yes agreeing and splitting into a
|
|
1803
|
+
* `no_majority` the operator has to read past. Folding happens here, at the one
|
|
1804
|
+
* place a verdict is ever read, so the reported member verdict and the tally
|
|
1805
|
+
* key can never disagree.
|
|
1806
|
+
*/
|
|
1800
1807
|
function councilVerdict(text: string): string | undefined {
|
|
1801
1808
|
const parsed = parseJsonObjectPayload(text);
|
|
1802
1809
|
return parsed.ok && typeof parsed.value.verdict === "string" && parsed.value.verdict.trim().length > 0
|
|
1803
|
-
? parsed.value.verdict.trim()
|
|
1810
|
+
? parsed.value.verdict.trim().toLowerCase()
|
|
1804
1811
|
: undefined;
|
|
1805
1812
|
}
|
|
1806
1813
|
|
|
@@ -1866,11 +1873,32 @@ async function runCouncil(
|
|
|
1866
1873
|
}
|
|
1867
1874
|
const position = (round - 1) * council.members.length + index + 1;
|
|
1868
1875
|
const pinned = council.resolvedTasks?.find((task) => task.role === "member" && task.position === position);
|
|
1876
|
+
let voteTask = base.task;
|
|
1877
|
+
if (council.synthesis === "vote") {
|
|
1878
|
+
if (pinned !== undefined) voteTask = pinned.task;
|
|
1879
|
+
else if (council.resolvedTasks !== undefined)
|
|
1880
|
+
throw new Error(`dispatch: resolved council plan has no member task at position ${position}`);
|
|
1881
|
+
else voteTask = renderCouncilVoteMemberTask(base.task);
|
|
1882
|
+
}
|
|
1869
1883
|
const request: DispatchRequest = {
|
|
1870
1884
|
...base,
|
|
1871
1885
|
executionRole: "researcher",
|
|
1872
1886
|
autonomy: "read-only",
|
|
1873
1887
|
toolProfile: "council-read-only",
|
|
1888
|
+
// A vote is a majority over the members' verdict fields, so a vote
|
|
1889
|
+
// council asks each member for one and seals the ballot it asked
|
|
1890
|
+
// for. The seated recipe is untouched: the ask is a task suffix and
|
|
1891
|
+
// the postcondition is an override, so the member is still the
|
|
1892
|
+
// agent the operator seated, and any recipe can be voted with.
|
|
1893
|
+
// Admission already composed the suffix into each resolved member
|
|
1894
|
+
// task, so reuse its exact bytes. The fallback supports dispatch
|
|
1895
|
+
// contracts that have no resolved admission artifact.
|
|
1896
|
+
...(council.synthesis === "vote"
|
|
1897
|
+
? {
|
|
1898
|
+
task: voteTask,
|
|
1899
|
+
resultContractOverride: { kind: "council-ballot" as const },
|
|
1900
|
+
}
|
|
1901
|
+
: {}),
|
|
1874
1902
|
target: member.target,
|
|
1875
1903
|
...(member.model ? { model: member.model } : {}),
|
|
1876
1904
|
...(member.thinking ? { thinkingLevel: member.thinking as NonNullable<DispatchRequest["thinkingLevel"]> } : {}),
|
|
@@ -1911,7 +1939,11 @@ async function runCouncil(
|
|
|
1911
1939
|
label: run.receipt.council?.label ?? "member",
|
|
1912
1940
|
runId: run.receipt.runId,
|
|
1913
1941
|
round: run.receipt.council?.round ?? 1,
|
|
1914
|
-
|
|
1942
|
+
// A ballot's prose lives in its `text` field, so the report carries the
|
|
1943
|
+
// member's answer rather than its wire envelope, the same way the judge
|
|
1944
|
+
// line already does. A member answering any other shape has no `text`
|
|
1945
|
+
// key and keeps its whole answer.
|
|
1946
|
+
answer: councilJudgeText(text),
|
|
1915
1947
|
...(verdict !== undefined ? { verdict } : {}),
|
|
1916
1948
|
...(failed ? { failed: { reason: pipelineFailureReason(run.receipt) } } : {}),
|
|
1917
1949
|
};
|
|
@@ -1967,13 +1999,16 @@ async function runCouncil(
|
|
|
1967
1999
|
judgeRunId: judgeRun.receipt.runId,
|
|
1968
2000
|
};
|
|
1969
2001
|
}
|
|
1970
|
-
if (
|
|
2002
|
+
if (prior.size > 0 && deps.dispatch.sealCouncilSynthesis !== undefined) {
|
|
1971
2003
|
const finalRuns = [...prior.values()];
|
|
1972
2004
|
const template = finalRuns[0];
|
|
1973
2005
|
if (template === undefined) throw new Error("council synthesis has no final member receipt");
|
|
1974
2006
|
// The sealed text is the whole council-report, not the synthesis alone:
|
|
1975
2007
|
// /share <synthesis runId> reads this receipt to bring every final
|
|
1976
2008
|
// member's labelled answer and the synthesis line into the main context.
|
|
2009
|
+
// A judge council seals it on the same terms: the judge run's own
|
|
2010
|
+
// receipt holds only its {"verdict","text"} payload, which carries no
|
|
2011
|
+
// member answers and no roster labels for the main agent to act on.
|
|
1977
2012
|
const text = JSON.stringify({ members, synthesis } satisfies CouncilReport);
|
|
1978
2013
|
const receipt = await deps.dispatch.sealCouncilSynthesis({
|
|
1979
2014
|
group,
|
|
@@ -256,7 +256,7 @@ export async function runScoutContinuationPlan<T, S>(input: {
|
|
|
256
256
|
};
|
|
257
257
|
},
|
|
258
258
|
cancel: (assignmentId) => input.dispatch.abort(assignmentId),
|
|
259
|
-
release: (ownerId) => input.dispatch.reservations?.
|
|
259
|
+
release: (ownerId) => input.dispatch.reservations?.release(ownerId),
|
|
260
260
|
releaseUnconsumed: (ownerId) => input.dispatch.reservations?.rollbackUnconsumed(ownerId),
|
|
261
261
|
},
|
|
262
262
|
input.signal,
|
package/src/tools/monitor.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type RunReceipt,
|
|
18
18
|
type RunReceiptVerification,
|
|
19
19
|
} from "../domains/dispatch/types.js";
|
|
20
|
+
import { summarizeTrustStatus } from "../domains/evidence/trust-projection.js";
|
|
20
21
|
import {
|
|
21
22
|
adaptRunReceiptTrustStatus,
|
|
22
23
|
type CanonicalTrustStatus,
|
|
@@ -389,6 +390,7 @@ function runReceipt(deps: MonitorToolDeps, runId: string): ToolResult {
|
|
|
389
390
|
receiptPath: run.receiptPath,
|
|
390
391
|
receiptIntegrity,
|
|
391
392
|
trustStatus,
|
|
393
|
+
trust: summarizeTrustStatus(trustStatus),
|
|
392
394
|
...(receipt !== null && receiptIntegrity.ok
|
|
393
395
|
? {
|
|
394
396
|
evidenceVerification: receipt.verification,
|
|
@@ -455,6 +457,17 @@ function durableRunEvidence(run: RunEnvelope | null): DurableRunEvidence {
|
|
|
455
457
|
const inspection = inspectRunReceiptTrustStatus(receipt, run);
|
|
456
458
|
const integrity = inspection.integrity;
|
|
457
459
|
if (!integrity.ok) {
|
|
460
|
+
// A retired seal is set aside unread, as a missing receipt is. It is
|
|
461
|
+
// not a failed one, so it never reads as tampering here either.
|
|
462
|
+
if (integrity.retired !== undefined) {
|
|
463
|
+
return {
|
|
464
|
+
...unavailableRunEvidence(
|
|
465
|
+
integrity.reason,
|
|
466
|
+
`${integrity.reason}; worker text is unavailable and validation is unknown.`,
|
|
467
|
+
),
|
|
468
|
+
trustStatus: inspection.status,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
458
471
|
return {
|
|
459
472
|
...unavailableRunEvidence(
|
|
460
473
|
integrity.reason,
|
package/src/tools/registry.ts
CHANGED
|
@@ -234,13 +234,29 @@ export interface AskUserTranscriptQuestion {
|
|
|
234
234
|
|
|
235
235
|
export interface AskUserTranscriptAnswer {
|
|
236
236
|
question: string;
|
|
237
|
+
/** The whole answer on one line: the chosen labels, then the typed text. */
|
|
237
238
|
answer: string;
|
|
239
|
+
/**
|
|
240
|
+
* The option labels the operator chose, in list order. Absent when they only
|
|
241
|
+
* typed. Present with no {@link value} is a label-only answer.
|
|
242
|
+
*/
|
|
243
|
+
options?: string[];
|
|
244
|
+
/**
|
|
245
|
+
* The operator's typed text, exactly as submitted. Absent when they only
|
|
246
|
+
* chose. Recording an option label without this is what lost the figures in
|
|
247
|
+
* issue #228.
|
|
248
|
+
*/
|
|
249
|
+
value?: string;
|
|
238
250
|
}
|
|
239
251
|
|
|
240
252
|
export interface AskUserTranscriptDecision {
|
|
241
253
|
key: string;
|
|
242
254
|
value: string;
|
|
243
255
|
label?: string;
|
|
256
|
+
/** The chosen labels behind {@link value}, when the answer had any. Harness-derived. */
|
|
257
|
+
options?: string[];
|
|
258
|
+
/** The typed text behind {@link value}, when the answer had any. Harness-derived. */
|
|
259
|
+
text?: string;
|
|
244
260
|
source_question?: string;
|
|
245
261
|
}
|
|
246
262
|
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "../domains/dispatch/budget-envelope.js";
|
|
8
8
|
import type { ReceiptIntegrityResult } from "../domains/dispatch/receipt-integrity.js";
|
|
9
9
|
import type { RunReceipt, RunReceiptVerification } from "../domains/dispatch/types.js";
|
|
10
|
+
import { formatTrustAxes, formatTrustSummary } from "../domains/evidence/trust-projection.js";
|
|
10
11
|
import { adaptRunReceiptTrustStatus, type CanonicalTrustStatus } from "../domains/evidence/trust-status.js";
|
|
11
12
|
import { receiptResponseModelIdObservationLabel } from "./dispatch-event-text.js";
|
|
12
13
|
|
|
@@ -128,9 +129,9 @@ export function receiptEvidenceLabels(
|
|
|
128
129
|
integrity: ReceiptIntegrityResult,
|
|
129
130
|
): string[] {
|
|
130
131
|
const status = adaptRunReceiptTrustStatus({ ...receipt, verification: verification }, { integrity });
|
|
131
|
-
const canonical =
|
|
132
|
+
const canonical = canonicalTrustLabels(status);
|
|
132
133
|
if (!integrity.ok) {
|
|
133
|
-
return [canonical, `receipt_integrity=FAILED reason=${JSON.stringify(integrity.reason)}`];
|
|
134
|
+
return [...canonical, `receipt_integrity=FAILED reason=${JSON.stringify(integrity.reason)}`];
|
|
134
135
|
}
|
|
135
136
|
const briefing =
|
|
136
137
|
receipt.briefing === undefined
|
|
@@ -154,7 +155,7 @@ export function receiptEvidenceLabels(
|
|
|
154
155
|
`budget_reason=${JSON.stringify(formatBudgetReasons(receipt.budget))}`,
|
|
155
156
|
];
|
|
156
157
|
return [
|
|
157
|
-
canonical,
|
|
158
|
+
...canonical,
|
|
158
159
|
`receipt_integrity=verified/v${receipt.integrity.version}/${receipt.integrity.algorithm}`,
|
|
159
160
|
`evidence_verification=${verification.state}/${verification.basis}`,
|
|
160
161
|
`host_verification=${receipt.hostVerification?.status ?? "not_requested"}`,
|
|
@@ -167,16 +168,13 @@ export function receiptEvidenceLabels(
|
|
|
167
168
|
];
|
|
168
169
|
}
|
|
169
170
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
`autonomyEnforcement:${status.autonomyEnforcement.state}`,
|
|
178
|
-
`completionEvidence:${status.completionEvidence.state}`,
|
|
179
|
-
].join(" ");
|
|
171
|
+
/**
|
|
172
|
+
* The compact projection first, then the canonical axis line, both from the
|
|
173
|
+
* shared projection so the dispatch and monitor text can never spell a state
|
|
174
|
+
* differently from `evidence inspect` or the board.
|
|
175
|
+
*/
|
|
176
|
+
function canonicalTrustLabels(status: CanonicalTrustStatus): string[] {
|
|
177
|
+
return [`trust=${JSON.stringify(formatTrustSummary(status))}`, formatTrustAxes(status)];
|
|
180
178
|
}
|
|
181
179
|
|
|
182
180
|
/**
|
|
@@ -192,6 +190,14 @@ export function workerTextLabel(status: CanonicalTrustStatus): string {
|
|
|
192
190
|
return "reconnaissance output (advisory leads, not validation evidence):";
|
|
193
191
|
case "unknown":
|
|
194
192
|
return "worker claims (validation not observable at this layer):";
|
|
193
|
+
// The three remaining states were one label. The evidence bundle tells
|
|
194
|
+
// a failed check, an inferred claim, and no validation at all apart, so
|
|
195
|
+
// the terminal must too or it hands the operator a coarser verdict than
|
|
196
|
+
// the report for the same run.
|
|
197
|
+
case "failed":
|
|
198
|
+
return "worker claims (validation failed; a check ran and did not pass):";
|
|
199
|
+
case "ungrounded":
|
|
200
|
+
return "worker claims (inferred; validation claimed, none observed):";
|
|
195
201
|
default:
|
|
196
202
|
return "worker claims (unverified prose):";
|
|
197
203
|
}
|
|
@@ -162,7 +162,8 @@ interface WorkerSpecFields {
|
|
|
162
162
|
*/
|
|
163
163
|
autonomy?: AutonomyLevel;
|
|
164
164
|
/**
|
|
165
|
-
* Absolute
|
|
165
|
+
* Absolute path boundaries write-class tool calls are confined to for this run.
|
|
166
|
+
* Exact files omit a trailing slash and subtrees retain one.
|
|
166
167
|
* Enforced at the shared worker safety seam so a write/edit target outside
|
|
167
168
|
* every root is a final block. Only set on runtimes that mediate per-tool
|
|
168
169
|
* calls (native, claude-sdk); dispatch refuses it on subprocess runtimes.
|