@iowarp/clio-coder 0.3.1 → 0.3.3
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 +233 -373
- package/CONTRIBUTING.md +23 -23
- package/README.md +284 -613
- package/dist/{acp-FPR54DGL.js → acp-P2AQILE2.js} +43 -53
- package/dist/{agents-OGPIHPJH.js → agents-72W3BI7I.js} +43 -26
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-IC3K6NIZ.js → auth-5TWEIYDN.js} +20 -12
- package/dist/chunk-2DJ2KNFG.js +2095 -0
- package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
- package/dist/chunk-2SFS6XQE.js +122 -0
- package/dist/{chunk-PV4JUBVJ.js → chunk-2TLUCQVG.js} +40 -21
- package/dist/chunk-2VTFPG5O.js +48 -0
- package/dist/chunk-4BJ5BYCE.js +61 -0
- package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
- package/dist/chunk-4VP4KH3K.js +962 -0
- package/dist/chunk-4XUGQOHA.js +797 -0
- package/dist/chunk-4ZG3XFUR.js +77 -0
- package/dist/chunk-5B2AEOW5.js +5407 -0
- package/dist/{chunk-K2ITRMHZ.js → chunk-5TSRNF4G.js} +6 -138
- package/dist/{chunk-4QKXUHSR.js → chunk-5UFT4SUX.js} +70 -20
- package/dist/{chunk-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
- package/dist/chunk-65DEGPJ6.js +52 -0
- package/dist/chunk-6EJMN2Y3.js +17 -0
- package/dist/chunk-6N5PTWMY.js +136 -0
- package/dist/chunk-6SGHMWE3.js +277 -0
- package/dist/chunk-6XLNIQDB.js +27 -0
- package/dist/chunk-7CR24IG7.js +242 -0
- package/dist/chunk-7MNJORFF.js +22 -0
- package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
- package/dist/chunk-AGYYIBLL.js +1069 -0
- package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
- package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
- package/dist/chunk-CBCAPZAA.js +229 -0
- package/dist/chunk-CMZWFGD2.js +352 -0
- package/dist/chunk-COU2UHX6.js +400 -0
- package/dist/chunk-DSELYM6W.js +1077 -0
- package/dist/chunk-DUYJ5IO6.js +644 -0
- package/dist/chunk-ECH6PKUQ.js +39 -0
- package/dist/chunk-ED4KHGC3.js +143 -0
- package/dist/chunk-EKMEHE4H.js +340 -0
- package/dist/chunk-FCSXB6T2.js +338 -0
- package/dist/chunk-FJ3H4MN5.js +48 -0
- package/dist/{chunk-RPTR2H26.js → chunk-FNTMWMX5.js} +21 -15
- package/dist/chunk-FQ4SKYE4.js +29 -0
- package/dist/chunk-G4BMMOKF.js +182 -0
- package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
- package/dist/chunk-HC4CLZ2Y.js +68 -0
- package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
- package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
- package/dist/chunk-I4HZDVNP.js +73 -0
- package/dist/chunk-IKCO5N3L.js +162 -0
- package/dist/chunk-IR4CFBFN.js +56 -0
- package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
- package/dist/chunk-J7CWMCQD.js +255 -0
- package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
- package/dist/chunk-KZWTDYJF.js +217 -0
- package/dist/chunk-LBMZMYH2.js +285 -0
- package/dist/{chunk-G34LV2PF.js → chunk-LM5TQCJZ.js} +84 -170
- package/dist/chunk-LW6DSM3M.js +5135 -0
- package/dist/chunk-LWLEKMDQ.js +3482 -0
- package/dist/{chunk-H6F6BYOH.js → chunk-LZSJBIVT.js} +7003 -7434
- package/dist/{chunk-HQQID6OA.js → chunk-M6SHUN7Q.js} +5 -5
- package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
- package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
- package/dist/chunk-OAO4GE4M.js +619 -0
- package/dist/{chunk-Q3RUPKEJ.js → chunk-OC7FIQPC.js} +58 -189
- package/dist/chunk-OKGUZO2U.js +34 -0
- package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
- package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
- package/dist/chunk-OQE5J4C6.js +73 -0
- package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
- package/dist/{chunk-MAR7Y6HW.js → chunk-PAJK6MAQ.js} +23 -16
- package/dist/{chunk-M5T5VO65.js → chunk-PIWWS5BL.js} +837 -635
- package/dist/chunk-POHLU5DW.js +1186 -0
- package/dist/chunk-QKMUKYO7.js +4961 -0
- package/dist/chunk-SRDMMSEP.js +16405 -0
- package/dist/chunk-SST6Z5JA.js +80 -0
- package/dist/chunk-STBPMHSX.js +2456 -0
- package/dist/chunk-T6YILFSB.js +80 -0
- package/dist/chunk-TZK7PACC.js +174 -0
- package/dist/chunk-TZTZS7QK.js +227 -0
- package/dist/{chunk-ASND7OZK.js → chunk-UFIIWP2H.js} +13 -13
- package/dist/chunk-UOV2BYIW.js +107 -0
- package/dist/{chunk-PFEFKVGL.js → chunk-V6RTAOC2.js} +13 -11
- package/dist/chunk-VAKQQHWR.js +434 -0
- package/dist/chunk-VG7TBQIY.js +128 -0
- package/dist/chunk-VJWL6YS5.js +244 -0
- package/dist/{chunk-EYOKLTMF.js → chunk-VPAYEGVX.js} +17 -3
- package/dist/chunk-WEH5XRJQ.js +32 -0
- package/dist/chunk-X4RCMKVQ.js +641 -0
- package/dist/{chunk-TEKV33Q5.js → chunk-X6IAEBZR.js} +65 -33
- package/dist/chunk-XBXAASKX.js +18 -0
- package/dist/chunk-XN3L4EYL.js +46 -0
- package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
- package/dist/chunk-YHZX5GEU.js +193 -0
- package/dist/chunk-YXLYO42X.js +91 -0
- package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
- package/dist/chunk-ZI647VB5.js +37 -0
- package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
- package/dist/chunk-ZWMF7253.js +1882 -0
- package/dist/cli/index.js +62 -54
- package/dist/clio-JOU4FXVA.js +25 -0
- package/dist/code-nav-7AX6FYE6.js +600 -0
- package/dist/codewiki/build-worker.js +66 -0
- package/dist/compile-cache-CVJMMODC.js +18 -0
- package/dist/{components-DMAOEKFB.js → components-KELWS457.js} +11 -6
- package/dist/{config-IRUQ7SE4.js → config-XCDVKR23.js} +92 -55
- package/dist/configure-4GAP54ZW.js +42 -0
- package/dist/{context-5RADCKTR.js → context-4UOGGLQ5.js} +71 -35
- package/dist/context-5VKGUVJJ.js +866 -0
- package/dist/{context-3KWFLHJG.js → context-77FM5DV5.js} +15 -13
- package/dist/{context-clear-7TSNPAAI.js → context-clear-XXJRLCJJ.js} +54 -28
- package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
- package/dist/dispatch-runner-QPRDDBDX.js +1997 -0
- package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
- package/dist/{doctor-UC5NAJYQ.js → doctor-HR46URBJ.js} +27 -17
- package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
- package/dist/{evidence-YEGUW4L3.js → evidence-6HG2PY2B.js} +46 -26
- package/dist/{evolve-TXARCTPG.js → evolve-K7YU3NCY.js} +45 -25
- package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
- package/dist/{fleet-6G3DHNYE.js → fleet-VY3HHKN6.js} +163 -54
- package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
- package/dist/{init-KZ5QTF6M.js → init-JYGXI3FK.js} +69 -32
- package/dist/{memory-73ESV5YC.js → memory-WFZMGYHX.js} +48 -27
- package/dist/{models-A4PVNWJK.js → models-I5QWSEOM.js} +39 -25
- package/dist/monitor-GE4ID3IA.js +661 -0
- package/dist/{chunk-FCIH3BIZ.js → orchestrator-EM5MC3HM.js} +15979 -12407
- package/dist/{paths-C4H6IV77.js → paths-UXLN5YYZ.js} +10 -5
- package/dist/{preload-6WVMHX3A.js → preload-P6DGH2PZ.js} +2 -2
- package/dist/{reset-BGW6OGMV.js → reset-L2FQEE3E.js} +16 -10
- package/dist/{run-YTPEYQOH.js → run-ZU3QMZPZ.js} +101 -61
- package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
- package/dist/{skills-2V6RA3OQ.js → skills-X5VXCRNQ.js} +34 -14
- package/dist/{skills-eval-S2TVJO4F.js → skills-eval-WKIHWTHR.js} +70 -34
- package/dist/steer-GGWFUJUD.js +77 -0
- package/dist/{targets-TYXLPB23.js → targets-SNCPI2NR.js} +43 -27
- package/dist/terminal-lease-BNAHVHBS.js +395 -0
- package/dist/{trace-GGOJ6Q6Z.js → trace-PNCASAXC.js} +41 -16
- package/dist/{chunk-N6F52NLF.js → tree-sitter-HGKH6LG4.js} +28 -2306
- package/dist/{uninstall-LLLT4F4W.js → uninstall-FZCQCDKC.js} +10 -5
- package/dist/{upgrade-33G2LMM5.js → upgrade-JQHHPQ4K.js} +45 -25
- package/dist/{usage-ZAFSXKKG.js → usage-OR4O5SMZ.js} +62 -31
- package/dist/verify-375KUB3Y.js +716 -0
- package/dist/web-fetch-2YHJ3KTG.js +638 -0
- package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-UEXP2ARI.js} +74 -34
- package/dist/worker/entry.js +221 -36
- package/dist/workspace-G4ZWUIPR.js +22 -0
- package/docs/README.md +22 -17
- package/docs/acp.md +168 -16
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +136 -7
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +114 -71
- package/docs/config-knobs-audit.md +1 -3
- package/docs/configuration-and-targets.md +174 -46
- package/docs/context-engine.md +29 -6
- package/docs/development-pipeline.md +26 -1
- package/docs/dispatch-architecture-rationale.md +1 -1
- package/docs/documentation-coverage.md +2 -2
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +13 -5
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +6 -2
- package/docs/evolution.md +2 -2
- package/docs/exit-codes-and-output.md +15 -9
- package/docs/extensions-and-sharing.md +9 -9
- package/docs/fleet-dispatch.md +7 -5
- package/docs/git-commit-provenance.md +120 -0
- package/docs/glossary.md +1 -1
- package/docs/installation-and-lifecycle.md +34 -27
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +45 -14
- package/docs/observability.md +8 -5
- package/docs/performance-methodology.md +491 -0
- package/docs/pi-boundary.md +72 -0
- package/docs/proactive-memory.md +3 -3
- package/docs/prompt-envelope-and-tools.md +24 -3
- package/docs/provider-adapter-cookbook.md +57 -4
- package/docs/release-cut-checklist.md +129 -115
- package/docs/safety-model.md +9 -5
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +55 -12
- package/docs/skills-marketplace.md +12 -8
- package/docs/time-conventions.md +1 -1
- package/docs/tool-usage.md +3 -3
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +10 -7
- package/docs/tui-design.md +47 -10
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +19 -22
- package/skills/coding/ast-grep/SKILL.md +136 -0
- package/skills/coding/ast-grep/evals.md +56 -0
- package/skills/coding/ast-grep/references/rule_reference.md +297 -0
- package/skills/coding/coding-standards/SKILL.md +113 -0
- package/skills/coding/coding-standards/evals.md +34 -0
- package/skills/coding/prototype/SKILL.md +86 -0
- package/skills/coding/prototype/evals.md +42 -0
- package/skills/coding/prototype/references/LOGIC.md +67 -0
- package/skills/coding/prototype/references/UI.md +112 -0
- package/skills/coding/tdd/SKILL.md +101 -0
- package/skills/coding/tdd/evals.md +41 -0
- package/skills/coding/tdd/references/mocking.md +59 -0
- package/skills/coding/tdd/references/tests.md +77 -0
- package/skills/context/context-handoff/SKILL.md +126 -0
- package/skills/context/context-handoff/evals.md +57 -0
- package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
- package/skills/context/context-prime/SKILL.md +95 -0
- package/skills/context/context-prime/evals.md +54 -0
- package/skills/meta/clio-dev/SKILL.md +91 -0
- package/skills/meta/clio-dev/evals.md +45 -0
- package/skills/meta/clio-test/SKILL.md +130 -0
- package/skills/meta/clio-test/evals.md +43 -0
- package/skills/meta/clio-test/references/harness.md +97 -0
- package/skills/meta/clio-test/references/test-map.md +59 -0
- package/skills/meta/credentials/SKILL.md +125 -0
- package/skills/meta/credentials/evals.md +104 -0
- package/skills/meta/find-skills/SKILL.md +72 -0
- package/skills/meta/find-skills/evals.md +47 -0
- package/skills/meta/herdr/SKILL.md +127 -0
- package/skills/meta/herdr/evals.md +38 -0
- package/skills/meta/skill-craft/SKILL.md +102 -0
- package/skills/meta/skill-craft/evals.md +41 -0
- package/skills/planning/architecture/SKILL.md +129 -0
- package/skills/planning/architecture/evals.md +36 -0
- package/skills/planning/backlog/SKILL.md +90 -0
- package/skills/planning/backlog/evals.md +43 -0
- package/skills/planning/prd/SKILL.md +82 -0
- package/skills/planning/prd/evals.md +49 -0
- package/skills/planning/product-intent/SKILL.md +112 -0
- package/skills/planning/product-intent/evals.md +36 -0
- package/skills/planning/tech-spec/SKILL.md +115 -0
- package/skills/planning/tech-spec/evals.md +47 -0
- package/skills/registry.yaml +136 -0
- package/skills/research/arxiv-literature/SKILL.md +104 -0
- package/skills/research/arxiv-literature/evals.md +58 -0
- package/skills/research/experiment-protocol/SKILL.md +122 -0
- package/skills/research/experiment-protocol/evals.md +91 -0
- package/skills/research/scientific-debugging/SKILL.md +119 -0
- package/skills/research/scientific-debugging/evals.md +138 -0
- package/skills/research/scientific-modernization/SKILL.md +138 -0
- package/skills/research/scientific-modernization/evals.md +84 -0
- package/skills/workflow/design-council/SKILL.md +139 -0
- package/skills/workflow/design-council/evals.md +97 -0
- package/skills/workflow/grill-me/SKILL.md +186 -0
- package/skills/workflow/grill-me/evals.md +78 -0
- package/skills/workflow/workflow-distiller/SKILL.md +136 -0
- package/skills/workflow/workflow-distiller/evals.md +107 -0
- package/src/cli/acp.ts +31 -4
- package/src/cli/clio.ts +68 -6
- package/src/cli/config-inspect.ts +28 -22
- package/src/cli/configure.ts +47 -9
- package/src/cli/context-clear.ts +2 -2
- package/src/cli/context-index.ts +21 -23
- package/src/cli/context.ts +13 -8
- package/src/cli/default-target.ts +9 -17
- package/src/cli/docs.ts +11 -5
- package/src/cli/evidence.ts +4 -1
- package/src/cli/extensions.ts +10 -1
- package/src/cli/fleet.ts +47 -6
- package/src/cli/index.ts +55 -26
- package/src/cli/memory.ts +3 -1
- package/src/cli/models.ts +1 -1
- package/src/cli/modes/json-stream.ts +37 -1
- package/src/cli/modes/print.ts +24 -9
- package/src/cli/run.ts +2 -2
- package/src/cli/skills-eval.ts +23 -8
- package/src/cli/skills.ts +19 -4
- package/src/cli/targets.ts +4 -0
- package/src/cli/text-layout.ts +15 -5
- package/src/cli/trace.ts +62 -14
- package/src/cli/upgrade.ts +18 -2
- package/src/cli/usage.ts +10 -3
- package/src/cli/wiki-generate.ts +2 -1
- package/src/core/agent-environment.ts +7 -0
- package/src/core/bash-exec.ts +72 -1
- package/src/core/boot-trace.ts +9 -4
- package/src/core/bus-events.ts +20 -4
- package/src/core/commit-attribution.ts +157 -0
- package/src/core/compile-cache.ts +159 -0
- package/src/core/config.ts +131 -2
- package/src/core/defaults.ts +39 -5
- package/src/core/domain-loader.ts +12 -5
- package/src/core/git-commit-attribution.ts +387 -0
- package/src/core/incomplete-installation.ts +45 -0
- package/src/core/response-schema.ts +1 -1
- package/src/core/safe-exec.ts +13 -1
- package/src/core/settings-layers.ts +155 -21
- package/src/core/skill-activation.ts +1 -1
- package/src/core/startup-timer.ts +3 -3
- package/src/core/state-file-lock.ts +13 -1
- package/src/core/termination.ts +78 -5
- package/src/domains/config/classify.ts +15 -3
- package/src/domains/config/extension.ts +19 -13
- package/src/domains/config/index.ts +10 -0
- package/src/domains/config/keybindings.ts +45 -9
- package/src/domains/context/bootstrap-prompt.ts +1 -1
- package/src/domains/context/bootstrap.ts +111 -18
- package/src/domains/context/clear.ts +16 -11
- package/src/domains/context/clio-md.ts +111 -9
- package/src/domains/context/codewiki/artifact.ts +400 -0
- package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
- package/src/domains/context/codewiki/build-worker.ts +54 -0
- package/src/domains/context/codewiki/coordinator.ts +182 -0
- package/src/domains/context/codewiki/indexer.ts +59 -144
- package/src/domains/context/codewiki/paths.ts +67 -0
- package/src/domains/context/codewiki/schema.ts +80 -0
- package/src/domains/context/codewiki/tree-sitter.ts +1 -1
- package/src/domains/context/contract.ts +11 -5
- package/src/domains/context/extension.ts +94 -143
- package/src/domains/context/fingerprint.ts +3 -1
- package/src/domains/context/index.ts +12 -22
- package/src/domains/context/project-metadata.ts +19 -0
- package/src/domains/context/prompt-context.ts +9 -10
- package/src/domains/context/refresh.ts +29 -21
- package/src/domains/context/runtime.ts +17 -0
- package/src/domains/context/wiki/generate.ts +39 -34
- package/src/domains/context/wiki/plan.ts +1 -1
- package/src/domains/context/wiki/prompts.ts +21 -8
- package/src/domains/dispatch/code-step.ts +20 -1
- package/src/domains/dispatch/extension.ts +158 -21
- package/src/domains/dispatch/failure-classification.ts +6 -0
- package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
- package/src/domains/dispatch/orphan-recovery.ts +50 -8
- package/src/domains/dispatch/receipt-integrity.ts +5 -0
- package/src/domains/dispatch/state.ts +31 -6
- package/src/domains/dispatch/transport.ts +2 -1
- package/src/domains/dispatch/types.ts +14 -0
- package/src/domains/dispatch/worker-spawn.ts +21 -2
- package/src/domains/eval/metrics/context.ts +1 -1
- package/src/domains/eval/types.ts +0 -1
- package/src/domains/evidence/build.ts +41 -1
- package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
- package/src/domains/lifecycle/migrations/index.ts +24 -4
- package/src/domains/middleware/hooks-io.ts +12 -0
- package/src/domains/middleware/skills-reminder.ts +30 -15
- package/src/domains/prompts/compiler.ts +142 -84
- package/src/domains/prompts/contract.ts +18 -2
- package/src/domains/prompts/extension.ts +39 -7
- package/src/domains/prompts/fragment-loader.ts +0 -1
- package/src/domains/prompts/fragments/identity/clio.md +2 -4
- package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
- package/src/domains/prompts/fragments/identity/self-awareness.md +1 -45
- package/src/domains/prompts/fragments/operating/contract.md +4 -50
- package/src/domains/prompts/fragments/operating/delegation.md +42 -0
- package/src/domains/prompts/fragments/operating/skills.md +26 -0
- package/src/domains/prompts/fragments/operating/worker.md +16 -0
- package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
- package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
- package/src/domains/prompts/fragments/safety/read-only.md +4 -4
- package/src/domains/prompts/fragments/safety/suggest.md +2 -2
- package/src/domains/prompts/fragments/wiki/page.md +10 -0
- package/src/domains/prompts/fragments/wiki/plan.md +10 -0
- package/src/domains/prompts/preload.ts +3 -3
- package/src/domains/providers/auth/api-key.ts +1 -1
- package/src/domains/providers/auth/backend-file.ts +20 -10
- package/src/domains/providers/auth/backend-memory.ts +59 -4
- package/src/domains/providers/auth/boot-status.ts +65 -0
- package/src/domains/providers/auth/oauth.ts +2 -1
- package/src/domains/providers/auth/storage.ts +97 -38
- package/src/domains/providers/capabilities.ts +12 -4
- package/src/domains/providers/contract.ts +15 -4
- package/src/domains/providers/extension.ts +18 -6
- package/src/domains/providers/model-runtime-capabilities.ts +15 -4
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +118 -35
- package/src/domains/providers/plugins.ts +5 -3
- package/src/domains/providers/probe/fingerprint.ts +25 -5
- package/src/domains/providers/registry.ts +31 -10
- package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -2
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
- package/src/domains/providers/runtimes/common/local-synth.ts +6 -7
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
- package/src/domains/providers/support.ts +6 -3
- package/src/domains/providers/types/local-model-quirks.ts +7 -9
- package/src/domains/providers/types/runtime-descriptor.ts +12 -1
- package/src/domains/providers/types/target-descriptor.ts +22 -0
- package/src/domains/resources/contract.ts +0 -1
- package/src/domains/resources/extension.ts +1 -3
- package/src/domains/resources/loader.ts +3 -4
- package/src/domains/resources/prompts/loader.ts +16 -2
- package/src/domains/resources/prompts/substitute.ts +1 -65
- package/src/domains/resources/skills/content-hash.ts +2 -0
- package/src/domains/resources/skills/install.ts +17 -0
- package/src/domains/resources/skills/loader.ts +17 -10
- package/src/domains/resources/skills/marketplace.ts +55 -9
- package/src/domains/safety/action-classifier.ts +4 -2
- package/src/domains/safety/audit.ts +8 -2
- package/src/domains/safety/extension.ts +1 -1
- package/src/domains/session/compaction/branch-summary.ts +3 -2
- package/src/domains/session/compaction/cut-point.ts +2 -1
- package/src/domains/session/compaction/tokens.ts +2 -1
- package/src/domains/session/context-ledger.ts +14 -0
- package/src/domains/session/contract.ts +15 -0
- package/src/domains/session/decision-board.ts +190 -0
- package/src/domains/session/entries.ts +66 -3
- package/src/domains/session/extension.ts +93 -12
- package/src/domains/session/retry.ts +10 -18
- package/src/domains/session/session-artifacts.ts +107 -0
- package/src/domains/session/task-board.ts +207 -13
- package/src/domains/session/tree/active-path.ts +44 -5
- package/src/domains/session/tree/fork.ts +26 -27
- package/src/domains/session/tree/preview.ts +2 -2
- package/src/domains/session/workspace/git-probe.ts +17 -11
- package/src/domains/user-tasks/store.ts +297 -0
- package/src/engine/acp/errors.ts +96 -0
- package/src/engine/acp/server.ts +1728 -146
- package/src/engine/acp/transport.ts +135 -14
- package/src/engine/acp/types.ts +26 -0
- package/src/engine/agent.ts +3 -3
- package/src/engine/ai.ts +32 -27
- package/src/engine/alcf-oauth.ts +26 -19
- package/src/engine/api-registry.ts +223 -0
- package/src/engine/apis/index.ts +3 -7
- package/src/engine/apis/llamacpp-residency.ts +49 -9
- package/src/engine/apis/lmstudio-residency.ts +5 -21
- package/src/engine/apis/lmstudio.ts +243 -0
- package/src/engine/apis/ollama-native.ts +24 -3
- package/src/engine/apis/openai-completions.ts +170 -91
- package/src/engine/apis/residency.ts +139 -3
- package/src/engine/apis/types.ts +16 -0
- package/src/engine/env-api-keys.ts +98 -0
- package/src/engine/gemma-channel-filter.ts +223 -0
- package/src/engine/instrumented-tui.ts +192 -0
- package/src/engine/messages.ts +14 -0
- package/src/engine/models.ts +42 -0
- package/src/engine/oauth.ts +16 -12
- package/src/engine/prompt-templates.ts +1 -0
- package/src/engine/provider-payload.ts +16 -59
- package/src/engine/strip-tokenizer-sentinels.ts +1 -1
- package/src/engine/truncate.ts +9 -0
- package/src/engine/tui.ts +17 -9
- package/src/engine/types.ts +3 -6
- package/src/engine/worker-runtime-capabilities.ts +5 -0
- package/src/engine/worker-runtime.ts +1 -1
- package/src/engine/worker-tools.ts +9 -4
- package/src/entry/boot-options.ts +50 -0
- package/src/entry/orchestrator.ts +288 -150
- package/src/interactive/application-controller.ts +89 -2
- package/src/interactive/chat-loop.ts +266 -41
- package/src/interactive/chat-panel.ts +715 -278
- package/src/interactive/chat-renderer.ts +306 -85
- package/src/interactive/clio-editor.ts +3 -8
- package/src/interactive/command-fallbacks.ts +2 -2
- package/src/interactive/context-overlay.ts +27 -1
- package/src/interactive/editor-submit.ts +253 -24
- package/src/interactive/export-html/ansi-to-html.ts +161 -0
- package/src/interactive/export-html/index.ts +51 -0
- package/src/interactive/export-html/template.ts +45 -0
- package/src/interactive/export-html/tool-renderer.ts +54 -0
- package/src/interactive/footer/dashboard.ts +4 -0
- package/src/interactive/footer/notifications.ts +1 -1
- package/src/interactive/footer/widgets.ts +42 -22
- package/src/interactive/footer-panel.ts +8 -3
- package/src/interactive/format-time.ts +14 -2
- package/src/interactive/interactive-application.ts +203 -17
- package/src/interactive/interactive-event-projection.ts +18 -1
- package/src/interactive/interactive-input-runtime.ts +50 -4
- package/src/interactive/interactive-presentation.ts +151 -19
- package/src/interactive/interactive-shell.ts +268 -14
- package/src/interactive/interactive-slash-runtime.ts +184 -117
- package/src/interactive/interactive-tickers.ts +38 -7
- package/src/interactive/keybinding-manager.ts +1 -1
- package/src/interactive/layout.ts +40 -3
- package/src/interactive/overlay-frame.ts +1 -1
- package/src/interactive/overlay-general-openers.ts +58 -1
- package/src/interactive/overlay-key-routing.ts +3 -0
- package/src/interactive/overlay-lifecycle.ts +13 -0
- package/src/interactive/overlay-permission-lifecycle.ts +2 -1
- package/src/interactive/overlay-session-lifecycle.ts +69 -12
- package/src/interactive/overlays/ask-user.ts +146 -24
- package/src/interactive/overlays/decisions.ts +300 -0
- package/src/interactive/overlays/help-reference.ts +15 -10
- package/src/interactive/overlays/model-selector.ts +34 -16
- package/src/interactive/overlays/session-selector.ts +18 -0
- package/src/interactive/overlays/settings.ts +105 -17
- package/src/interactive/overlays/skills-hub.ts +4 -4
- package/src/interactive/overlays/tree-selector.ts +41 -6
- package/src/interactive/render-trace.ts +499 -90
- package/src/interactive/renderers/compaction-summary.ts +2 -2
- package/src/interactive/renderers/diff.ts +115 -104
- package/src/interactive/renderers/mermaid.ts +53 -0
- package/src/interactive/renderers/tool-execution.ts +516 -168
- package/src/interactive/renderers/worker-entry.ts +20 -4
- package/src/interactive/session-switch-settlement.ts +10 -0
- package/src/interactive/slash-autocomplete.ts +6 -114
- package/src/interactive/slash-commands.ts +135 -47
- package/src/interactive/slash-spec.ts +9 -38
- package/src/interactive/status/controller.ts +5 -1
- package/src/interactive/status/index.ts +12 -1
- package/src/interactive/status/reasoning.ts +87 -0
- package/src/interactive/status/summary.ts +13 -2
- package/src/interactive/stdout-backpressure.ts +99 -0
- package/src/interactive/stream-pacer.ts +530 -0
- package/src/interactive/stream-pacing-policy.ts +66 -0
- package/src/interactive/tasks-overlay.ts +368 -14
- package/src/interactive/terminal-lease.ts +485 -0
- package/src/interactive/theme/tokens.ts +1 -1
- package/src/interactive/transcript-detail.ts +120 -0
- package/src/interactive/turn-context.ts +4 -3
- package/src/interactive/turn-persistence.ts +30 -13
- package/src/interactive/turn-queues.ts +12 -0
- package/src/interactive/turn-recovery.ts +25 -8
- package/src/interactive/turn-runtime.ts +79 -12
- package/src/interactive/turn-state.ts +10 -0
- package/src/interactive/view/artifacts.ts +114 -4
- package/src/interactive/view/view-overlay.ts +3 -0
- package/src/interactive/welcome-dashboard.ts +17 -16
- package/src/interactive/worker-receipts.ts +52 -3
- package/src/interactive/worker-stream.ts +5 -1
- package/src/tools/agent-tools.ts +23 -3
- package/src/tools/artifact.ts +2 -2
- package/src/tools/ask-user.ts +23 -13
- package/src/tools/bash.ts +30 -2
- package/src/tools/bootstrap.ts +34 -431
- package/src/tools/builtin-tool-catalog.ts +271 -0
- package/src/tools/codewiki/code-nav-surface.ts +29 -0
- package/src/tools/codewiki/code-nav.ts +8 -22
- package/src/tools/codewiki/shared.ts +41 -38
- package/src/tools/context/docs-engine.ts +14 -3
- package/src/tools/context/index.ts +107 -28
- package/src/tools/context/surface.ts +19 -0
- package/src/tools/core-bootstrap.ts +168 -0
- package/src/tools/credential-present.ts +5 -5
- package/src/tools/dispatch-admission.ts +533 -0
- package/src/tools/dispatch-background.ts +54 -0
- package/src/tools/dispatch-event-text.ts +6 -0
- package/src/tools/dispatch-plan.ts +9 -4
- package/src/tools/dispatch-run-events.ts +238 -0
- package/src/tools/dispatch-runner.ts +2370 -0
- package/src/tools/dispatch-scout-admission.ts +295 -0
- package/src/tools/dispatch-types.ts +77 -0
- package/src/tools/dispatch.ts +67 -3161
- package/src/tools/find.ts +4 -2
- package/src/tools/grep.ts +2 -2
- package/src/tools/lazy-tool.ts +60 -0
- package/src/tools/ledger.ts +3 -3
- package/src/tools/monitor-surface.ts +36 -0
- package/src/tools/monitor.ts +2 -32
- package/src/tools/observers.ts +2 -2
- package/src/tools/presentation.ts +107 -0
- package/src/tools/registry.ts +45 -27
- package/src/tools/safe-exec.ts +2 -2
- package/src/tools/steer-surface.ts +17 -0
- package/src/tools/steer.ts +2 -13
- package/src/tools/tasks.ts +108 -11
- package/src/tools/truncate.ts +25 -184
- package/src/tools/verify/frontend.ts +3 -1
- package/src/tools/verify/index.ts +3 -38
- package/src/tools/verify/surface.ts +46 -0
- package/src/tools/web-fetch-surface.ts +23 -0
- package/src/tools/web-fetch.ts +2 -20
- package/src/tools/write.ts +7 -2
- package/src/worker/entry.ts +39 -2
- package/src/worker/spec-contract.ts +26 -5
- package/dist/chunk-7SS2CTV2.js +0 -61361
- package/dist/chunk-DKGKUHFA.js +0 -924
- package/dist/chunk-GEP36Y4X.js +0 -12796
- package/dist/chunk-XYWBQRDM.js +0 -137
- package/dist/clio-BZVGEUFJ.js +0 -58
- package/dist/configure-S7S6F6CL.js +0 -32
- package/docs/html/agents_blueprint.html +0 -936
- package/docs/html/alcf_blueprint.html +0 -324
- package/docs/html/architecture_blueprint.html +0 -850
- package/docs/html/commands_blueprint.html +0 -939
- package/docs/html/config_knobs_audit_blueprint.html +0 -178
- package/docs/html/configuration_blueprint.html +0 -1080
- package/docs/html/context_blueprint.html +0 -603
- package/docs/html/documentation_blueprint.html +0 -832
- package/docs/html/environment_blueprint.html +0 -404
- package/docs/html/eval_blueprint.html +0 -743
- package/docs/html/evals_internal_blueprint.html +0 -190
- package/docs/html/evolution_blueprint.html +0 -674
- package/docs/html/extensions_blueprint.html +0 -2065
- package/docs/html/fleet_dispatch_blueprint.html +0 -286
- package/docs/html/index.html +0 -919
- package/docs/html/lifecycle_blueprint.html +0 -723
- package/docs/html/memory_blueprint.html +0 -699
- package/docs/html/middleware_blueprint.html +0 -664
- package/docs/html/models_blueprint.html +0 -2366
- package/docs/html/observability_blueprint.html +0 -683
- package/docs/html/provider_adapter_blueprint.html +0 -245
- package/docs/html/safety_blueprint.html +0 -1386
- package/docs/html/shared.css +0 -571
- package/docs/html/shared.js +0 -143
- package/docs/html/skills_blueprint.html +0 -671
- package/docs/html/soak_blueprint.html +0 -182
- package/docs/html/tool_usage_blueprint.html +0 -350
- package/docs/html/tools_blueprint.html +0 -2249
- package/docs/html/trace_blueprint.html +0 -235
- package/docs/html/tui_design_blueprint.html +0 -374
- package/docs/html/validation_blueprint.html +0 -961
- package/docs/html/worker_dispatch_blueprint.html +0 -231
- package/src/core/release.ts +0 -2
- package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
- package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
- package/src/engine/apis/lmstudio-native.ts +0 -1438
- package/src/engine/apis/thinking-replay.ts +0 -11
- package/src/tools/string-enum.ts +0 -15
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import type { DispatchPlanTaskResolution, DispatchRequest } from "../domains/dispatch/contract.js";
|
|
3
|
+
import type { ExecutionPlan } from "../domains/dispatch/execution-plan.js";
|
|
4
|
+
import { gateDeciderAgentId } from "../domains/dispatch/execution-role.js";
|
|
5
|
+
import { JUDGE_GATE_PROMPT, REVIEWER_GATE_PROMPT } from "../domains/dispatch/gate-role-prompts.js";
|
|
6
|
+
import { approvedRouteCandidates } from "../domains/dispatch/route-approval.js";
|
|
7
|
+
import { defaultRoutingIntent } from "../domains/dispatch/routing-intent.js";
|
|
8
|
+
import type { DispatchFailoverMode } from "../domains/dispatch/validation.js";
|
|
9
|
+
import {
|
|
10
|
+
dispatchRequestsFromArgs,
|
|
11
|
+
maxOutputBytesArg,
|
|
12
|
+
prepareDispatchArguments,
|
|
13
|
+
stringArg,
|
|
14
|
+
timeoutMsArg,
|
|
15
|
+
} from "./dispatch-arguments.js";
|
|
16
|
+
import {
|
|
17
|
+
DISPATCH_PLAN_PREPARATION_ERROR_ARGUMENT,
|
|
18
|
+
type DispatchPlanView,
|
|
19
|
+
describeDispatchPlan,
|
|
20
|
+
RESOLVED_DISPATCH_PLAN_ARGUMENT,
|
|
21
|
+
type ResolvedDispatchPlanArtifact,
|
|
22
|
+
resolvedDispatchPlanFromArgs,
|
|
23
|
+
withResolvedDispatchPlan,
|
|
24
|
+
} from "./dispatch-plan.js";
|
|
25
|
+
import {
|
|
26
|
+
loadVerifiedScoutSource,
|
|
27
|
+
prepareScoutContinuation,
|
|
28
|
+
scoutContinuationRefFromArgs,
|
|
29
|
+
} from "./dispatch-scout-admission.js";
|
|
30
|
+
import type {
|
|
31
|
+
DispatchCompeteSettings,
|
|
32
|
+
DispatchExecutionSnapshot,
|
|
33
|
+
DispatchMode,
|
|
34
|
+
DispatchReviewSettings,
|
|
35
|
+
DispatchToolDeps,
|
|
36
|
+
} from "./dispatch-types.js";
|
|
37
|
+
import type { ToolSpec } from "./registry.js";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The six identity-sensitive stores which bind synchronous admission to the
|
|
41
|
+
* later, dynamically loaded dispatch runner. They intentionally live for one
|
|
42
|
+
* tool surface and are never serialized or reconstructed.
|
|
43
|
+
*/
|
|
44
|
+
export interface DispatchAdmissionState {
|
|
45
|
+
readonly preparedAdmissionArgs: WeakSet<Record<string, unknown>>;
|
|
46
|
+
readonly trustedResolvedPlans: WeakMap<Record<string, unknown>, ResolvedDispatchPlanArtifact>;
|
|
47
|
+
readonly trustedReservationOwners: WeakMap<Record<string, unknown>, string>;
|
|
48
|
+
readonly trustedExecutionSnapshots: WeakMap<Record<string, unknown>, DispatchExecutionSnapshot>;
|
|
49
|
+
readonly trustedExecutionPlans: WeakMap<Record<string, unknown>, ExecutionPlan>;
|
|
50
|
+
readonly taskResolutions: WeakMap<object, DispatchPlanTaskResolution>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface DispatchAdmissionController {
|
|
54
|
+
readonly state: DispatchAdmissionState;
|
|
55
|
+
prepareAdmissionArguments(args: Record<string, unknown>): Record<string, unknown>;
|
|
56
|
+
disposeAdmissionArguments(args: Record<string, unknown>): void;
|
|
57
|
+
prepareArguments(args: Record<string, unknown>): Record<string, unknown>;
|
|
58
|
+
describeDispatchPlan(args: Record<string, unknown>): DispatchPlanView;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type ResolvedPlanTask = ResolvedDispatchPlanArtifact["tasks"][number];
|
|
62
|
+
|
|
63
|
+
const REVIEW_MAX_CYCLES_DEFAULT = 2;
|
|
64
|
+
const REVIEW_MAX_CYCLES_LIMIT = 4;
|
|
65
|
+
const REVIEW_SINGLE_TASK_MESSAGE =
|
|
66
|
+
"dispatch: review supports exactly one task; run the fan-out without review, then dispatch one integration task with review to gate the combined result";
|
|
67
|
+
const COMPETE_SINGLE_TASK_MESSAGE = "dispatch: compete requires exactly one task";
|
|
68
|
+
const COMPETE_NO_REVIEW_MESSAGE = "dispatch: compete has its own judge and cannot combine with review";
|
|
69
|
+
const COMPETE_MIN_CANDIDATES = 2;
|
|
70
|
+
const COMPETE_MAX_CANDIDATES = 4;
|
|
71
|
+
|
|
72
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
73
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function reviewerTask(originalTask: string, builderRunId: string, cycle: number): string {
|
|
77
|
+
return [
|
|
78
|
+
`Review the work of builder run ${builderRunId} (review cycle ${cycle}).`,
|
|
79
|
+
"The builder's final answer is provided as input data; verify it against the workspace, do not trust it blindly.",
|
|
80
|
+
"Original task the builder was given:",
|
|
81
|
+
originalTask,
|
|
82
|
+
].join("\n\n");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function reviewSettingsFromArgs(
|
|
86
|
+
args: Record<string, unknown>,
|
|
87
|
+
): { ok: true; review: DispatchReviewSettings | undefined } | { ok: false; message: string } {
|
|
88
|
+
const raw = args.review;
|
|
89
|
+
if (raw === undefined || raw === false) return { ok: true, review: undefined };
|
|
90
|
+
const record = raw === true ? {} : isRecord(raw) ? raw : null;
|
|
91
|
+
if (record === null) return { ok: false, message: "dispatch: review must be true or an options object" };
|
|
92
|
+
const review: DispatchReviewSettings = { maxCycles: REVIEW_MAX_CYCLES_DEFAULT };
|
|
93
|
+
const reviewer = stringArg(record, "reviewer", "agent");
|
|
94
|
+
if (reviewer) review.reviewer = reviewer;
|
|
95
|
+
if (record.max_cycles !== undefined) {
|
|
96
|
+
const cycles = record.max_cycles;
|
|
97
|
+
if (typeof cycles !== "number" || !Number.isInteger(cycles) || cycles < 1 || cycles > REVIEW_MAX_CYCLES_LIMIT) {
|
|
98
|
+
return { ok: false, message: `dispatch: review.max_cycles must be an integer 1..${REVIEW_MAX_CYCLES_LIMIT}` };
|
|
99
|
+
}
|
|
100
|
+
review.maxCycles = cycles;
|
|
101
|
+
}
|
|
102
|
+
const node = stringArg(record, "node");
|
|
103
|
+
if (node) review.node = node;
|
|
104
|
+
const model = stringArg(record, "model");
|
|
105
|
+
if (model) review.model = model;
|
|
106
|
+
const target = stringArg(record, "target");
|
|
107
|
+
if (target) review.target = target;
|
|
108
|
+
return { ok: true, review };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function competeSettingsFromArgs(args: Record<string, unknown>):
|
|
112
|
+
| { ok: true; compete: DispatchCompeteSettings }
|
|
113
|
+
| {
|
|
114
|
+
ok: false;
|
|
115
|
+
message: string;
|
|
116
|
+
} {
|
|
117
|
+
let candidates = COMPETE_MIN_CANDIDATES;
|
|
118
|
+
if (args.candidates !== undefined) {
|
|
119
|
+
if (
|
|
120
|
+
typeof args.candidates !== "number" ||
|
|
121
|
+
!Number.isInteger(args.candidates) ||
|
|
122
|
+
args.candidates < COMPETE_MIN_CANDIDATES ||
|
|
123
|
+
args.candidates > COMPETE_MAX_CANDIDATES
|
|
124
|
+
) {
|
|
125
|
+
return {
|
|
126
|
+
ok: false,
|
|
127
|
+
message: `dispatch: candidates must be an integer ${COMPETE_MIN_CANDIDATES}..${COMPETE_MAX_CANDIDATES}`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
candidates = args.candidates;
|
|
131
|
+
}
|
|
132
|
+
if (args.judge !== undefined && !isRecord(args.judge)) {
|
|
133
|
+
return { ok: false, message: "dispatch: judge must be an options object" };
|
|
134
|
+
}
|
|
135
|
+
if (!isRecord(args.judge)) return { ok: true, compete: { candidates } };
|
|
136
|
+
const judge: { agent?: string; model?: string; target?: string; node?: string } = {};
|
|
137
|
+
for (const key of ["agent", "model", "target", "node"] as const) {
|
|
138
|
+
const value = stringArg(args.judge, key);
|
|
139
|
+
if (value !== undefined) judge[key] = value;
|
|
140
|
+
}
|
|
141
|
+
return { ok: true, compete: { candidates, judge } };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function deepFreeze<T>(value: T): T {
|
|
145
|
+
if (typeof value !== "object" || value === null || Object.isFrozen(value)) return value;
|
|
146
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
147
|
+
return Object.freeze(value);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function createDispatchAdmissionController(deps: DispatchToolDeps): DispatchAdmissionController {
|
|
151
|
+
const state: DispatchAdmissionState = {
|
|
152
|
+
preparedAdmissionArgs: new WeakSet<Record<string, unknown>>(),
|
|
153
|
+
trustedResolvedPlans: new WeakMap<Record<string, unknown>, ResolvedDispatchPlanArtifact>(),
|
|
154
|
+
trustedReservationOwners: new WeakMap<Record<string, unknown>, string>(),
|
|
155
|
+
trustedExecutionSnapshots: new WeakMap<Record<string, unknown>, DispatchExecutionSnapshot>(),
|
|
156
|
+
trustedExecutionPlans: new WeakMap<Record<string, unknown>, ExecutionPlan>(),
|
|
157
|
+
taskResolutions: new WeakMap<object, DispatchPlanTaskResolution>(),
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const parseRequests = (args: Record<string, unknown>) =>
|
|
161
|
+
dispatchRequestsFromArgs(args, {
|
|
162
|
+
...(deps.getAgentRoleFacts ? { resolveFacts: deps.getAgentRoleFacts } : {}),
|
|
163
|
+
hasAgent: (id) => deps.getAgentSpecs().some((spec) => spec.id === id),
|
|
164
|
+
auto: {
|
|
165
|
+
approvedAuthorities: ["read-only", "verification", "artifact-write", "workspace-edit"],
|
|
166
|
+
authorityBasis: deps.getAutonomy?.() === "full-auto" ? "full-auto-policy" : "operator-plan-approval",
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
const trustExecution = (args: Record<string, unknown>, snapshot: DispatchExecutionSnapshot) => {
|
|
170
|
+
state.trustedExecutionSnapshots.set(args, deepFreeze(structuredClone(snapshot)));
|
|
171
|
+
return args;
|
|
172
|
+
};
|
|
173
|
+
const dispatchExecutionSnapshot = (
|
|
174
|
+
args: Record<string, unknown>,
|
|
175
|
+
fields: Pick<DispatchExecutionSnapshot & { kind: "dispatch" }, "requests" | "mode" | "review" | "compete">,
|
|
176
|
+
): DispatchExecutionSnapshot => ({
|
|
177
|
+
kind: "dispatch",
|
|
178
|
+
planView: describeDispatchPlan(args),
|
|
179
|
+
...fields,
|
|
180
|
+
detach: args.detach === true,
|
|
181
|
+
timeoutMs: timeoutMsArg(args),
|
|
182
|
+
maxOutputBytes: maxOutputBytesArg(args),
|
|
183
|
+
});
|
|
184
|
+
const markPrepared = (args: Record<string, unknown>): Record<string, unknown> => {
|
|
185
|
+
const exposed = resolvedDispatchPlanFromArgs(args);
|
|
186
|
+
if (exposed !== null) {
|
|
187
|
+
const trusted = deepFreeze(structuredClone(exposed));
|
|
188
|
+
const policyView = deepFreeze(structuredClone(exposed));
|
|
189
|
+
state.trustedResolvedPlans.set(args, trusted);
|
|
190
|
+
Object.defineProperty(args, RESOLVED_DISPATCH_PLAN_ARGUMENT, {
|
|
191
|
+
value: policyView,
|
|
192
|
+
enumerable: true,
|
|
193
|
+
configurable: false,
|
|
194
|
+
writable: false,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
state.preparedAdmissionArgs.add(args);
|
|
198
|
+
return args;
|
|
199
|
+
};
|
|
200
|
+
const stripUntrustedPlanFields = (rawArgs: Record<string, unknown>): Record<string, unknown> => {
|
|
201
|
+
const clean = { ...prepareDispatchArguments(rawArgs) };
|
|
202
|
+
Reflect.deleteProperty(clean, RESOLVED_DISPATCH_PLAN_ARGUMENT);
|
|
203
|
+
Reflect.deleteProperty(clean, DISPATCH_PLAN_PREPARATION_ERROR_ARGUMENT);
|
|
204
|
+
return clean;
|
|
205
|
+
};
|
|
206
|
+
const preparationFailure = (args: Record<string, unknown>, err: unknown): Record<string, unknown> =>
|
|
207
|
+
markPrepared({
|
|
208
|
+
...args,
|
|
209
|
+
[DISPATCH_PLAN_PREPARATION_ERROR_ARGUMENT]: err instanceof Error ? err.message : String(err),
|
|
210
|
+
});
|
|
211
|
+
const shapeRejection = (args: Record<string, unknown>, message: string): Record<string, unknown> =>
|
|
212
|
+
preparationFailure(args, message);
|
|
213
|
+
const resolveTask = (
|
|
214
|
+
request: DispatchRequest,
|
|
215
|
+
role: NonNullable<ResolvedPlanTask["role"]>,
|
|
216
|
+
position: number,
|
|
217
|
+
): ResolvedPlanTask => {
|
|
218
|
+
const resolution = deps.dispatch.preview?.(request);
|
|
219
|
+
if (resolution === undefined) throw new Error("dispatch preview is unavailable");
|
|
220
|
+
const pinned = request.node !== undefined || request.target !== undefined || request.model !== undefined;
|
|
221
|
+
const approvedCandidates =
|
|
222
|
+
pinned || request.failover !== "approved"
|
|
223
|
+
? []
|
|
224
|
+
: resolution.routeApproval === null
|
|
225
|
+
? (deps.dispatch.routeCandidates?.(request) ?? [])
|
|
226
|
+
: approvedRouteCandidates(resolution.routeApproval);
|
|
227
|
+
const failover: DispatchFailoverMode = pinned || approvedCandidates.length === 0 ? "none" : "approved";
|
|
228
|
+
const task: ResolvedPlanTask = {
|
|
229
|
+
agent: resolution.agentId,
|
|
230
|
+
task: request.task,
|
|
231
|
+
...(request.briefing !== undefined ? { briefing: request.briefing } : {}),
|
|
232
|
+
target: resolution.targetId,
|
|
233
|
+
model: resolution.wireModelId,
|
|
234
|
+
node: resolution.node.id,
|
|
235
|
+
nodeKind: resolution.node.kind,
|
|
236
|
+
...(resolution.node.host !== undefined ? { nodeHost: resolution.node.host } : {}),
|
|
237
|
+
routingIntent: request.routingIntent ?? defaultRoutingIntent(request),
|
|
238
|
+
failover,
|
|
239
|
+
routeApproval: resolution.routeApproval,
|
|
240
|
+
agentSelection: request.agentSelection === undefined ? null : structuredClone(request.agentSelection),
|
|
241
|
+
stepId: null,
|
|
242
|
+
dependencies: [],
|
|
243
|
+
executionRole: request.executionRole,
|
|
244
|
+
expectedResultContract: null,
|
|
245
|
+
authorityGrant: null,
|
|
246
|
+
agentDecision: null,
|
|
247
|
+
wave: null,
|
|
248
|
+
...(failover === "approved" ? { allowedCandidates: approvedCandidates.map((candidate) => ({ ...candidate })) } : {}),
|
|
249
|
+
role,
|
|
250
|
+
position,
|
|
251
|
+
};
|
|
252
|
+
state.taskResolutions.set(task, resolution);
|
|
253
|
+
return task;
|
|
254
|
+
};
|
|
255
|
+
const resolvedCostCeiling = (): number => {
|
|
256
|
+
const injected = deps.getCostCeilingUsd?.();
|
|
257
|
+
if (injected !== undefined && Number.isFinite(injected) && injected > 0) return injected;
|
|
258
|
+
const ceiling = deps.dispatch.costCeilingUsd?.();
|
|
259
|
+
if (ceiling === undefined || !Number.isFinite(ceiling) || ceiling <= 0) {
|
|
260
|
+
throw new Error("dispatch scheduling cost ceiling is unavailable");
|
|
261
|
+
}
|
|
262
|
+
return ceiling;
|
|
263
|
+
};
|
|
264
|
+
const reservationWave = (
|
|
265
|
+
topology: ResolvedDispatchPlanArtifact["topology"],
|
|
266
|
+
task: ResolvedPlanTask,
|
|
267
|
+
index: number,
|
|
268
|
+
) => {
|
|
269
|
+
if (topology === "fleet") return task.wave ?? index;
|
|
270
|
+
if (topology === "parallel" || topology === "detached") return 0;
|
|
271
|
+
if (topology === "compete") return task.role === "judge" ? 1 : 0;
|
|
272
|
+
return index;
|
|
273
|
+
};
|
|
274
|
+
const markReservedPlan = (args: Record<string, unknown>, artifact: ResolvedDispatchPlanArtifact) => {
|
|
275
|
+
const prepared = withResolvedDispatchPlan(args, artifact);
|
|
276
|
+
if (deps.dispatch.reservations === undefined) return markPrepared(prepared);
|
|
277
|
+
const tasks = artifact.tasks.map((task, index) => {
|
|
278
|
+
const resolution = state.taskResolutions.get(task);
|
|
279
|
+
if (resolution === undefined || (task.stepId === null && (task.role === undefined || task.position === undefined))) {
|
|
280
|
+
throw new Error("dispatch reservation resolution is incomplete");
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
memberId: task.stepId ?? `${task.role}-${task.position}`,
|
|
284
|
+
wave: reservationWave(artifact.topology, task, index),
|
|
285
|
+
resolution,
|
|
286
|
+
};
|
|
287
|
+
});
|
|
288
|
+
const reservation = deps.dispatch.reservations.prepare({
|
|
289
|
+
topology: artifact.topology === "fleet" ? "parallel" : artifact.topology,
|
|
290
|
+
tasks,
|
|
291
|
+
});
|
|
292
|
+
try {
|
|
293
|
+
const marked = markPrepared(prepared);
|
|
294
|
+
state.trustedReservationOwners.set(marked, reservation.ownerId);
|
|
295
|
+
return marked;
|
|
296
|
+
} catch (error) {
|
|
297
|
+
deps.dispatch.reservations.rollback(reservation.ownerId);
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const prepareAdmissionArguments = (rawArgs: Record<string, unknown>): Record<string, unknown> => {
|
|
303
|
+
const args = stripUntrustedPlanFields(rawArgs);
|
|
304
|
+
if (args.list === true) {
|
|
305
|
+
const marked = markPrepared(args);
|
|
306
|
+
return trustExecution(marked, { kind: "list" });
|
|
307
|
+
}
|
|
308
|
+
const continuation = scoutContinuationRefFromArgs(args);
|
|
309
|
+
if (!continuation.ok) return preparationFailure(args, continuation.message);
|
|
310
|
+
if (continuation.ref !== null) {
|
|
311
|
+
try {
|
|
312
|
+
const source = loadVerifiedScoutSource({
|
|
313
|
+
ref: continuation.ref,
|
|
314
|
+
dispatch: deps.dispatch,
|
|
315
|
+
agentSpecs: deps.getAgentSpecs(),
|
|
316
|
+
});
|
|
317
|
+
const prepared = prepareScoutContinuation({
|
|
318
|
+
source,
|
|
319
|
+
authorization: deps.getAutonomy?.() === "full-auto" ? "full-auto-policy" : "operator-plan-approval",
|
|
320
|
+
planAgentSelection: deps.dispatch.planAgentSelection,
|
|
321
|
+
costCeilingUsd: resolvedCostCeiling(),
|
|
322
|
+
});
|
|
323
|
+
for (const [index, task] of prepared.artifact.tasks.entries()) {
|
|
324
|
+
const resolution = prepared.resolutions[index];
|
|
325
|
+
if (resolution === undefined) throw new Error("dispatch: Scout route resolution is incomplete");
|
|
326
|
+
state.taskResolutions.set(task, resolution);
|
|
327
|
+
}
|
|
328
|
+
const marked = markReservedPlan(args, prepared.artifact);
|
|
329
|
+
trustExecution(
|
|
330
|
+
marked,
|
|
331
|
+
dispatchExecutionSnapshot(marked, {
|
|
332
|
+
requests: prepared.requests,
|
|
333
|
+
mode: "parallel",
|
|
334
|
+
review: undefined,
|
|
335
|
+
compete: undefined,
|
|
336
|
+
}),
|
|
337
|
+
);
|
|
338
|
+
state.trustedExecutionPlans.set(marked, deepFreeze(structuredClone(prepared.executionPlan)));
|
|
339
|
+
return marked;
|
|
340
|
+
} catch (error) {
|
|
341
|
+
return preparationFailure(args, error);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (args.apply_winner !== undefined) {
|
|
345
|
+
if (!isRecord(args.apply_winner)) {
|
|
346
|
+
return shapeRejection(args, "dispatch: apply_winner must be an options object");
|
|
347
|
+
}
|
|
348
|
+
const branch = stringArg(args.apply_winner, "branch");
|
|
349
|
+
const match = branch ? /^clio\/compete\/([A-Za-z0-9][A-Za-z0-9._-]{0,127})\/([1-9]\d*)$/.exec(branch) : null;
|
|
350
|
+
if (branch === undefined) return shapeRejection(args, "dispatch: apply_winner.branch is required");
|
|
351
|
+
if (match === null) {
|
|
352
|
+
return shapeRejection(args, "dispatch: apply_winner.branch must be a clio/compete/<group>/<n> branch");
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
const cwd = resolve(stringArg(args.apply_winner, "cwd") ?? process.cwd());
|
|
356
|
+
return trustExecution(
|
|
357
|
+
markPrepared(
|
|
358
|
+
withResolvedDispatchPlan(args, {
|
|
359
|
+
version: 3,
|
|
360
|
+
topology: "compete",
|
|
361
|
+
source: null,
|
|
362
|
+
maxWorkers: null,
|
|
363
|
+
onFailure: null,
|
|
364
|
+
tasks: [],
|
|
365
|
+
costCeilingUsd: resolvedCostCeiling(),
|
|
366
|
+
deadlineMs: null,
|
|
367
|
+
confirmation: { branch, group: match[1] ?? "", index: Number.parseInt(match[2] ?? "", 10), cwd },
|
|
368
|
+
}),
|
|
369
|
+
),
|
|
370
|
+
{ kind: "apply-winner", branch, cwd },
|
|
371
|
+
);
|
|
372
|
+
} catch (error) {
|
|
373
|
+
return preparationFailure(args, error);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const parsed = parseRequests(args);
|
|
377
|
+
if (!parsed.ok) return shapeRejection(args, parsed.message);
|
|
378
|
+
if (args.mode !== undefined && !["parallel", "sequential", "pipeline", "compete"].includes(String(args.mode))) {
|
|
379
|
+
return shapeRejection(
|
|
380
|
+
args,
|
|
381
|
+
`dispatch: mode must be parallel, sequential, pipeline, or compete; got '${String(args.mode)}'`,
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
const mode: DispatchMode =
|
|
385
|
+
args.mode === "sequential"
|
|
386
|
+
? "sequential"
|
|
387
|
+
: args.mode === "pipeline"
|
|
388
|
+
? "pipeline"
|
|
389
|
+
: args.mode === "compete"
|
|
390
|
+
? "compete"
|
|
391
|
+
: "parallel";
|
|
392
|
+
const reviewResult = reviewSettingsFromArgs(args);
|
|
393
|
+
if (!reviewResult.ok) return shapeRejection(args, reviewResult.message);
|
|
394
|
+
if (reviewResult.review !== undefined) {
|
|
395
|
+
if (mode === "compete") return shapeRejection(args, COMPETE_NO_REVIEW_MESSAGE);
|
|
396
|
+
if (mode !== "parallel") return shapeRejection(args, `dispatch: review does not combine with mode=${mode}`);
|
|
397
|
+
if (parsed.requests.length !== 1 || parsed.requests[0] === undefined) {
|
|
398
|
+
return shapeRejection(args, REVIEW_SINGLE_TASK_MESSAGE);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (mode === "compete" && (parsed.requests.length !== 1 || parsed.requests[0] === undefined)) {
|
|
402
|
+
return shapeRejection(args, COMPETE_SINGLE_TASK_MESSAGE);
|
|
403
|
+
}
|
|
404
|
+
const competeResult = mode === "compete" ? competeSettingsFromArgs(args) : undefined;
|
|
405
|
+
if (competeResult !== undefined && !competeResult.ok) return shapeRejection(args, competeResult.message);
|
|
406
|
+
const snapshotFields = {
|
|
407
|
+
requests: parsed.requests,
|
|
408
|
+
mode,
|
|
409
|
+
review: reviewResult.review,
|
|
410
|
+
compete: competeResult?.ok === true ? competeResult.compete : undefined,
|
|
411
|
+
};
|
|
412
|
+
if (deps.dispatch.preview === undefined) {
|
|
413
|
+
const marked = markPrepared(args);
|
|
414
|
+
return trustExecution(marked, dispatchExecutionSnapshot(marked, snapshotFields));
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
const tasks: ResolvedDispatchPlanArtifact["tasks"] = [];
|
|
418
|
+
if (reviewResult.review !== undefined) {
|
|
419
|
+
const base = parsed.requests[0];
|
|
420
|
+
if (base === undefined) return shapeRejection(args, REVIEW_SINGLE_TASK_MESSAGE);
|
|
421
|
+
for (let cycle = 1; cycle <= reviewResult.review.maxCycles; cycle += 1) {
|
|
422
|
+
const subject = { runId: `plan-builder-${cycle}`, digest: null };
|
|
423
|
+
tasks.push(
|
|
424
|
+
resolveTask(
|
|
425
|
+
{ ...base, executionRole: "builder", gate: { role: "builder", group: "plan-preview", cycle } },
|
|
426
|
+
"builder",
|
|
427
|
+
cycle,
|
|
428
|
+
),
|
|
429
|
+
);
|
|
430
|
+
tasks.push(
|
|
431
|
+
resolveTask(
|
|
432
|
+
{
|
|
433
|
+
agentId: gateDeciderAgentId(reviewResult.review.reviewer),
|
|
434
|
+
executionRole: "reviewer",
|
|
435
|
+
task: reviewerTask(base.task, subject.runId, cycle),
|
|
436
|
+
systemPrompt: REVIEWER_GATE_PROMPT,
|
|
437
|
+
autonomy: "read-only",
|
|
438
|
+
gate: { role: "reviewer", group: "plan-preview", cycle, subjects: [subject] },
|
|
439
|
+
...(base.cwd !== undefined ? { cwd: base.cwd } : {}),
|
|
440
|
+
...(reviewResult.review.node !== undefined ? { node: reviewResult.review.node } : {}),
|
|
441
|
+
...(reviewResult.review.model !== undefined ? { model: reviewResult.review.model } : {}),
|
|
442
|
+
...(reviewResult.review.target !== undefined ? { target: reviewResult.review.target } : {}),
|
|
443
|
+
},
|
|
444
|
+
"reviewer",
|
|
445
|
+
cycle,
|
|
446
|
+
),
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
} else if (mode === "compete") {
|
|
450
|
+
const compete = competeResult?.ok === true ? competeResult.compete : undefined;
|
|
451
|
+
if (compete === undefined) throw new Error("dispatch: compete admission settings are unavailable");
|
|
452
|
+
const base = parsed.requests[0];
|
|
453
|
+
if (base === undefined) return shapeRejection(args, COMPETE_SINGLE_TASK_MESSAGE);
|
|
454
|
+
const subjects: Array<{ runId: string; digest: null }> = [];
|
|
455
|
+
for (let candidate = 1; candidate <= compete.candidates; candidate += 1) {
|
|
456
|
+
subjects.push({ runId: `plan-candidate-${candidate}`, digest: null });
|
|
457
|
+
tasks.push(
|
|
458
|
+
resolveTask(
|
|
459
|
+
{ ...base, executionRole: "builder", gate: { role: "candidate", group: "plan-preview", cycle: candidate } },
|
|
460
|
+
"candidate",
|
|
461
|
+
candidate,
|
|
462
|
+
),
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
tasks.push(
|
|
466
|
+
resolveTask(
|
|
467
|
+
{
|
|
468
|
+
agentId: gateDeciderAgentId(compete.judge?.agent),
|
|
469
|
+
executionRole: "judge",
|
|
470
|
+
task: `Plan-time capability check for the ${compete.candidates}-candidate judge.`,
|
|
471
|
+
systemPrompt: JUDGE_GATE_PROMPT,
|
|
472
|
+
autonomy: "read-only",
|
|
473
|
+
gate: { role: "judge", group: "plan-preview", cycle: 1, subjects },
|
|
474
|
+
...(base.cwd !== undefined ? { cwd: base.cwd } : {}),
|
|
475
|
+
...(compete.judge?.node !== undefined ? { node: compete.judge.node } : {}),
|
|
476
|
+
...(compete.judge?.model !== undefined ? { model: compete.judge.model } : {}),
|
|
477
|
+
...(compete.judge?.target !== undefined ? { target: compete.judge.target } : {}),
|
|
478
|
+
},
|
|
479
|
+
"judge",
|
|
480
|
+
1,
|
|
481
|
+
),
|
|
482
|
+
);
|
|
483
|
+
} else {
|
|
484
|
+
for (const [index, request] of parsed.requests.entries()) tasks.push(resolveTask(request, "task", index + 1));
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const topology = describeDispatchPlan(args).topology;
|
|
488
|
+
const planScale =
|
|
489
|
+
tasks.length > 1 ||
|
|
490
|
+
topology === "compete" ||
|
|
491
|
+
tasks.some((task) => task.node !== "local" || task.failover === "approved");
|
|
492
|
+
if (!planScale) {
|
|
493
|
+
const marked = markPrepared(args);
|
|
494
|
+
return trustExecution(marked, dispatchExecutionSnapshot(marked, snapshotFields));
|
|
495
|
+
}
|
|
496
|
+
const marked = markReservedPlan(args, {
|
|
497
|
+
version: 3,
|
|
498
|
+
topology,
|
|
499
|
+
source: null,
|
|
500
|
+
maxWorkers: null,
|
|
501
|
+
onFailure: null,
|
|
502
|
+
tasks,
|
|
503
|
+
costCeilingUsd: resolvedCostCeiling(),
|
|
504
|
+
deadlineMs: null,
|
|
505
|
+
});
|
|
506
|
+
return trustExecution(marked, dispatchExecutionSnapshot(marked, snapshotFields));
|
|
507
|
+
} catch (error) {
|
|
508
|
+
return preparationFailure(args, error);
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const prepareArguments = (args: Record<string, unknown>): Record<string, unknown> =>
|
|
513
|
+
state.preparedAdmissionArgs.has(args) ? args : prepareAdmissionArguments(args);
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
state,
|
|
517
|
+
prepareAdmissionArguments,
|
|
518
|
+
disposeAdmissionArguments(args) {
|
|
519
|
+
const ownerId = state.trustedReservationOwners.get(args);
|
|
520
|
+
if (ownerId !== undefined) deps.dispatch.reservations?.rollbackUnconsumed(ownerId);
|
|
521
|
+
},
|
|
522
|
+
prepareArguments,
|
|
523
|
+
describeDispatchPlan(args) {
|
|
524
|
+
const trusted = state.trustedResolvedPlans.get(args);
|
|
525
|
+
return describeDispatchPlan(trusted === undefined ? args : { ...args, [RESOLVED_DISPATCH_PLAN_ARGUMENT]: trusted });
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export type DispatchAdmissionToolHooks = Pick<
|
|
531
|
+
ToolSpec,
|
|
532
|
+
"prepareAdmissionArguments" | "disposeAdmissionArguments" | "prepareArguments" | "describeDispatchPlan"
|
|
533
|
+
>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result of an operator-initiated attach to detach conversion. The message is
|
|
3
|
+
* the line the keypress feedback renders, so a refusal names the topology that
|
|
4
|
+
* refused rather than reading as a dropped key.
|
|
5
|
+
*/
|
|
6
|
+
export type DispatchBackgroundOutcome = { ok: true; message: string } | { ok: false; message: string };
|
|
7
|
+
|
|
8
|
+
export interface DispatchBackgroundControl {
|
|
9
|
+
/** Tool call the control belongs to; one attached dispatch owns one control. */
|
|
10
|
+
toolCallId: string;
|
|
11
|
+
/** Operator-facing name of the call, used in both outcome messages. */
|
|
12
|
+
label: string;
|
|
13
|
+
convert(): DispatchBackgroundOutcome;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Live attached dispatches that the operator may send to the background. An
|
|
18
|
+
* attached `dispatch` call registers one control for as long as it awaits its
|
|
19
|
+
* runs; the TUI keybinding fires the newest one. Absent from a deps bundle
|
|
20
|
+
* (workers, headless) nothing registers and attached dispatch behaves exactly
|
|
21
|
+
* as it did before.
|
|
22
|
+
*/
|
|
23
|
+
export interface DispatchBackgroundRegistry {
|
|
24
|
+
/** Returns the deregistration handle; calling it more than once is harmless. */
|
|
25
|
+
register(control: DispatchBackgroundControl): () => void;
|
|
26
|
+
/** Fire the newest still-registered control. */
|
|
27
|
+
backgroundNewest(): DispatchBackgroundOutcome;
|
|
28
|
+
/** How many attached dispatches are currently registered. */
|
|
29
|
+
size(): number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createDispatchBackgroundRegistry(): DispatchBackgroundRegistry {
|
|
33
|
+
// Map insertion order is registration order, and the newest attached dispatch
|
|
34
|
+
// is the one the operator just watched start, so the keypress takes the last
|
|
35
|
+
// entry rather than asking a UI projection which segment is newest.
|
|
36
|
+
const controls = new Map<string, DispatchBackgroundControl>();
|
|
37
|
+
return {
|
|
38
|
+
register(control) {
|
|
39
|
+
controls.set(control.toolCallId, control);
|
|
40
|
+
return () => {
|
|
41
|
+
if (controls.get(control.toolCallId) === control) controls.delete(control.toolCallId);
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
backgroundNewest() {
|
|
45
|
+
let newest: DispatchBackgroundControl | undefined;
|
|
46
|
+
for (const control of controls.values()) newest = control;
|
|
47
|
+
if (newest === undefined) {
|
|
48
|
+
return { ok: false, message: "background: no attached dispatch is running" };
|
|
49
|
+
}
|
|
50
|
+
return newest.convert();
|
|
51
|
+
},
|
|
52
|
+
size: () => controls.size,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { durableAssistantTextFromEvent } from "../domains/dispatch/event-pump.js";
|
|
2
|
+
|
|
3
|
+
/** Return the durable final assistant text carried by a worker event. */
|
|
4
|
+
export function assistantTextFromEvent(event: unknown): string {
|
|
5
|
+
return durableAssistantTextFromEvent(event).trim();
|
|
6
|
+
}
|
|
@@ -96,7 +96,7 @@ export interface DispatchPlanView {
|
|
|
96
96
|
/** Whole-plan deadline for a Scout dependency plan. */
|
|
97
97
|
deadlineMs?: number;
|
|
98
98
|
/** Supervised compete-winner confirmation, when this is an apply action. */
|
|
99
|
-
confirmation?: { branch: string; group: string; index: number };
|
|
99
|
+
confirmation?: { branch: string; group: string; index: number; cwd?: string };
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
export const RESOLVED_DISPATCH_PLAN_ARGUMENT = "__clio_resolved_dispatch_plan";
|
|
@@ -130,7 +130,7 @@ export interface ResolvedDispatchPlanArtifact {
|
|
|
130
130
|
>;
|
|
131
131
|
costCeilingUsd: number;
|
|
132
132
|
deadlineMs: number | null;
|
|
133
|
-
confirmation?: { branch: string; group: string; index: number };
|
|
133
|
+
confirmation?: { branch: string; group: string; index: number; cwd?: string };
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
export function withResolvedPlanTaskPin(
|
|
@@ -290,7 +290,7 @@ function renderPlanText(
|
|
|
290
290
|
];
|
|
291
291
|
if (confirmation !== undefined) {
|
|
292
292
|
lines.push(
|
|
293
|
-
`winner confirmation: group=${safeField(confirmation.group)} candidate=${confirmation.index} branch=${safeField(confirmation.branch)}`,
|
|
293
|
+
`winner confirmation: group=${safeField(confirmation.group)} candidate=${confirmation.index} branch=${safeField(confirmation.branch)}${confirmation.cwd === undefined ? "" : ` cwd=${safeField(confirmation.cwd)}`}`,
|
|
294
294
|
);
|
|
295
295
|
}
|
|
296
296
|
if (source !== null) {
|
|
@@ -544,11 +544,15 @@ export function resolvedDispatchPlanFromArgs(args: Record<string, unknown>): Res
|
|
|
544
544
|
if (value.confirmation !== undefined) {
|
|
545
545
|
if (
|
|
546
546
|
!isRecord(value.confirmation) ||
|
|
547
|
-
|
|
547
|
+
!["branch\u0000group\u0000index", "branch\u0000cwd\u0000group\u0000index"].includes(
|
|
548
|
+
Object.keys(value.confirmation).sort().join("\u0000"),
|
|
549
|
+
) ||
|
|
548
550
|
typeof value.confirmation.branch !== "string" ||
|
|
549
551
|
value.confirmation.branch.trim().length === 0 ||
|
|
550
552
|
typeof value.confirmation.group !== "string" ||
|
|
551
553
|
value.confirmation.group.trim().length === 0 ||
|
|
554
|
+
(value.confirmation.cwd !== undefined &&
|
|
555
|
+
(typeof value.confirmation.cwd !== "string" || value.confirmation.cwd.trim().length === 0)) ||
|
|
552
556
|
!Number.isInteger(value.confirmation.index) ||
|
|
553
557
|
Number(value.confirmation.index) < 1
|
|
554
558
|
) {
|
|
@@ -558,6 +562,7 @@ export function resolvedDispatchPlanFromArgs(args: Record<string, unknown>): Res
|
|
|
558
562
|
branch: value.confirmation.branch.trim(),
|
|
559
563
|
group: value.confirmation.group.trim(),
|
|
560
564
|
index: Number(value.confirmation.index),
|
|
565
|
+
...(value.confirmation.cwd === undefined ? {} : { cwd: value.confirmation.cwd.trim() }),
|
|
561
566
|
};
|
|
562
567
|
}
|
|
563
568
|
if (value.tasks.length === 0 && confirmation === undefined) return null;
|