@webpresso/agent-kit 3.1.28 → 3.2.0
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.
Potentially problematic release.
This version of @webpresso/agent-kit might be problematic. Click here for more details.
- package/README.md +53 -15
- package/bin/_run.js +179 -19
- package/catalog/AGENTS.md.tpl +6 -6
- package/catalog/agent/agents/implementer.md +45 -0
- package/catalog/agent/rules/ci-cost-local-first.md +139 -0
- package/catalog/agent/rules/ci-test-perf.md +5 -1
- package/catalog/agent/rules/cmd-execution.md +9 -0
- package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
- package/catalog/agent/rules/pre-implementation.md +30 -2
- package/catalog/agent/rules/supported-agent-clis.md +9 -0
- package/catalog/agent/rules/test-scan-perf.md +80 -0
- package/catalog/agent/rules/typescript-version.md +50 -0
- package/catalog/agent/rules/workflow-skills-routing.md +4 -2
- package/catalog/agent/skills/codex/SKILL.md +25 -1
- package/catalog/agent/skills/fix/SKILL.md +3 -0
- package/catalog/agent/skills/verify/SKILL.md +22 -2
- package/catalog/docs/templates/blueprint.md +1 -1
- package/dist/esm/audit/agents.js +1 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
- package/dist/esm/audit/blueprint-pr-coverage.js +72 -7
- package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
- package/dist/esm/audit/ci-guardrails-wiring.js +90 -0
- package/dist/esm/audit/ci-test-perf.js +30 -0
- package/dist/esm/audit/command-surface.js +4 -2
- package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
- package/dist/esm/audit/host-substitution-risk.js +256 -0
- package/dist/esm/audit/registry.d.ts +4 -4
- package/dist/esm/audit/registry.js +11 -1
- package/dist/esm/audit/roadmap-links.js +6 -0
- package/dist/esm/audit/test-scan-perf.d.ts +18 -0
- package/dist/esm/audit/test-scan-perf.js +275 -0
- package/dist/esm/audit/toolchain-isolation.js +1 -2
- package/dist/esm/audit/typescript-version.d.ts +2 -0
- package/dist/esm/audit/typescript-version.js +123 -0
- package/dist/esm/blueprint/core/parser.js +43 -1
- package/dist/esm/blueprint/core/validation/criteria.d.ts +14 -0
- package/dist/esm/blueprint/core/validation/criteria.js +41 -2
- package/dist/esm/blueprint/core/validation/state.js +25 -14
- package/dist/esm/blueprint/db/migrations/run.js +4 -2
- package/dist/esm/blueprint/lifecycle/audit.d.ts +20 -0
- package/dist/esm/blueprint/lifecycle/audit.js +65 -10
- package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
- package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
- package/dist/esm/blueprint/lifecycle/engine.d.ts +9 -0
- package/dist/esm/blueprint/lifecycle/engine.js +53 -6
- package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
- package/dist/esm/blueprint/lifecycle/local.js +19 -3
- package/dist/esm/blueprint/lifecycle/review-provenance.d.ts +6 -0
- package/dist/esm/blueprint/lifecycle/review-provenance.js +118 -12
- package/dist/esm/blueprint/markdown/helpers.js +6 -2
- package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
- package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
- package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
- package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
- package/dist/esm/blueprint/trust/command-runner.js +148 -0
- package/dist/esm/blueprint/trust/gates.d.ts +7 -0
- package/dist/esm/blueprint/trust/gates.js +20 -0
- package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
- package/dist/esm/blueprint/trust/promotion.js +62 -112
- package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
- package/dist/esm/blueprint/trust/scaffold.js +64 -0
- package/dist/esm/blueprint/trust/validator.d.ts +1 -0
- package/dist/esm/blueprint/trust/validator.js +7 -1
- package/dist/esm/blueprint/utils/archive.js +27 -5
- package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
- package/dist/esm/blueprint/utils/document-paths.js +45 -12
- package/dist/esm/build/cli-mcp-parity.js +10 -0
- package/dist/esm/ci/act-replay.js +110 -7
- package/dist/esm/ci/act-runner.d.ts +4 -0
- package/dist/esm/ci/act-runner.js +85 -26
- package/dist/esm/ci/act-worktree-git.d.ts +11 -0
- package/dist/esm/ci/act-worktree-git.js +219 -0
- package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
- package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
- package/dist/esm/cli/cli.d.ts +1 -1
- package/dist/esm/cli/cli.js +34 -0
- package/dist/esm/cli/commands/agent-launch.d.ts +6 -1
- package/dist/esm/cli/commands/agent-launch.js +82 -4
- package/dist/esm/cli/commands/audit-core.d.ts +1 -1
- package/dist/esm/cli/commands/audit-core.js +8 -1
- package/dist/esm/cli/commands/audit.js +20 -5
- package/dist/esm/cli/commands/blueprint/execution.js +18 -6
- package/dist/esm/cli/commands/blueprint/mutations.js +83 -47
- package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
- package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
- package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
- package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
- package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
- package/dist/esm/cli/commands/blueprint/router.js +40 -3
- package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
- package/dist/esm/cli/commands/ci-preflight.js +6 -3
- package/dist/esm/cli/commands/ci.d.ts +8 -1
- package/dist/esm/cli/commands/ci.js +80 -21
- package/dist/esm/cli/commands/compile.js +5 -31
- package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
- package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
- package/dist/esm/cli/commands/dash/keymap.js +1 -0
- package/dist/esm/cli/commands/dash/launch-preferences.d.ts +15 -0
- package/dist/esm/cli/commands/dash/launch-preferences.js +46 -17
- package/dist/esm/cli/commands/dash/plan-once-label.d.ts +7 -0
- package/dist/esm/cli/commands/dash/plan-once-label.js +5 -0
- package/dist/esm/cli/commands/dash/plan-once-membership.d.ts +67 -0
- package/dist/esm/cli/commands/dash/plan-once-membership.js +151 -0
- package/dist/esm/cli/commands/dash/plan-once-merge.d.ts +143 -0
- package/dist/esm/cli/commands/dash/plan-once-merge.js +238 -0
- package/dist/esm/cli/commands/dash/plan-once.d.ts +22 -2
- package/dist/esm/cli/commands/dash/plan-once.js +41 -4
- package/dist/esm/cli/commands/dash/tui/attention-hud.d.ts +9 -0
- package/dist/esm/cli/commands/dash/tui/attention-hud.js +9 -0
- package/dist/esm/cli/commands/dash/tui/chat-bridge.d.ts +41 -0
- package/dist/esm/cli/commands/dash/tui/chat-bridge.js +73 -0
- package/dist/esm/cli/commands/dash/tui/chat-mode.d.ts +47 -0
- package/dist/esm/cli/commands/dash/tui/chat-mode.js +98 -0
- package/dist/esm/cli/commands/dash/tui/frame.d.ts +3 -0
- package/dist/esm/cli/commands/dash/tui/frame.js +3 -1
- package/dist/esm/cli/commands/dash/tui/palette.d.ts +1 -1
- package/dist/esm/cli/commands/dash/tui/palette.js +14 -0
- package/dist/esm/cli/commands/dash/tui/runtime.js +239 -4
- package/dist/esm/cli/commands/dash/tui/state.d.ts +41 -0
- package/dist/esm/cli/commands/dash/tui/state.js +257 -4
- package/dist/esm/cli/commands/doctor.js +5 -0
- package/dist/esm/cli/commands/format.js +0 -2
- package/dist/esm/cli/commands/hook.d.ts +5 -0
- package/dist/esm/cli/commands/hook.js +15 -9
- package/dist/esm/cli/commands/init/config.d.ts +0 -1
- package/dist/esm/cli/commands/init/config.js +3 -6
- package/dist/esm/cli/commands/init/convergence-apply.d.ts +24 -0
- package/dist/esm/cli/commands/init/convergence-apply.js +221 -0
- package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
- package/dist/esm/cli/commands/init/convergence-state.js +54 -0
- package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
- package/dist/esm/cli/commands/init/convergence.js +57 -0
- package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
- package/dist/esm/cli/commands/init/git-convergence.js +168 -0
- package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
- package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
- package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
- package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
- package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
- package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
- package/dist/esm/cli/commands/init/host-visibility.js +94 -5
- package/dist/esm/cli/commands/init/index.d.ts +1 -0
- package/dist/esm/cli/commands/init/index.js +326 -173
- package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
- package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
- package/dist/esm/cli/commands/init/merge.d.ts +1 -0
- package/dist/esm/cli/commands/init/merge.js +30 -1
- package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
- package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
- package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
- package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
- package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +11 -0
- package/dist/esm/cli/commands/init/scaffold-base-kit.js +56 -1
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/claude.d.ts +5 -6
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/claude.js +6 -13
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +51 -23
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/ir.d.ts +0 -2
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/ir.js +0 -2
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/merge.d.ts +6 -3
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/merge.js +39 -26
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +297 -173
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +7 -0
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +58 -0
- package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
- package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
- package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
- package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
- package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
- package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
- package/dist/esm/cli/commands/logs.d.ts +15 -0
- package/dist/esm/cli/commands/logs.js +192 -3
- package/dist/esm/cli/commands/opencode-rotate.d.ts +49 -0
- package/dist/esm/cli/commands/opencode-rotate.js +135 -0
- package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
- package/dist/esm/cli/commands/public-readiness.js +42 -0
- package/dist/esm/cli/commands/quality-log-store.d.ts +1 -0
- package/dist/esm/cli/commands/quality-log-store.js +187 -51
- package/dist/esm/cli/commands/review.d.ts +35 -3
- package/dist/esm/cli/commands/review.js +734 -217
- package/dist/esm/cli/commands/run-wait.d.ts +2 -0
- package/dist/esm/cli/commands/run-wait.js +122 -0
- package/dist/esm/cli/commands/secrets.d.ts +1 -0
- package/dist/esm/cli/commands/secrets.js +4 -1
- package/dist/esm/cli/commands/setup-help.js +1 -1
- package/dist/esm/cli/commands/setup-repair-help.js +1 -1
- package/dist/esm/cli/commands/worktree/router-dispatch.js +13 -8
- package/dist/esm/cli/direct-provider-launch.js +31 -3
- package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
- package/dist/esm/cli/optional-tool-freshness.js +219 -9
- package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
- package/dist/esm/daemon/domains/git-actions.js +136 -0
- package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
- package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
- package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
- package/dist/esm/daemon/domains/sessions-search.js +29 -0
- package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
- package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
- package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
- package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
- package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
- package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
- package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
- package/dist/esm/daemon/handlers/git-handlers.js +27 -0
- package/dist/esm/daemon/handlers/product.d.ts +7 -0
- package/dist/esm/daemon/handlers/product.js +10 -119
- package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
- package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
- package/dist/esm/daemon/handlers/shared.d.ts +5 -0
- package/dist/esm/daemon/handlers/shared.js +16 -0
- package/dist/esm/daemon/methods.d.ts +8 -1
- package/dist/esm/daemon/methods.js +7 -0
- package/dist/esm/daemon/protocol/contract.d.ts +43 -0
- package/dist/esm/daemon/protocol/contract.js +26 -0
- package/dist/esm/daemon/protocol/index.d.ts +1 -1
- package/dist/esm/daemon/protocol/index.js +1 -1
- package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
- package/dist/esm/hooks/__conformance__/matrix.js +137 -0
- package/dist/esm/hooks/conformance/batch.js +5 -0
- package/dist/esm/hooks/doctor.d.ts +15 -0
- package/dist/esm/hooks/doctor.js +79 -8
- package/dist/esm/hooks/permission-request/index.js +9 -3
- package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
- package/dist/esm/hooks/permission-request/policy.js +13 -0
- package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
- package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
- package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
- package/dist/esm/hooks/pretool-guard/logger.js +16 -0
- package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
- package/dist/esm/hooks/pretool-guard/runner.js +68 -16
- package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
- package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +58 -4
- package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
- package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
- package/dist/esm/hooks/pretool-guard/validators/mcp-redirect.d.ts +0 -1
- package/dist/esm/hooks/pretool-guard/validators/mcp-redirect.js +8 -5
- package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
- package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
- package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.d.ts +9 -7
- package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.js +126 -14
- package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
- package/dist/esm/hooks/shared/guard-outcome.js +215 -0
- package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
- package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
- package/dist/esm/hooks/shared/types.d.ts +8 -5
- package/dist/esm/hooks/shared/types.js +23 -8
- package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
- package/dist/esm/hooks/stop/qa-changed-files.js +74 -0
- package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
- package/dist/esm/mcp/blueprint/handlers/document-mutations.js +78 -4
- package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
- package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
- package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
- package/dist/esm/mcp/blueprint/registration.js +3 -2
- package/dist/esm/mcp/server.d.ts +1 -0
- package/dist/esm/mcp/server.js +27 -0
- package/dist/esm/mcp/tools/_names.d.ts +1 -1
- package/dist/esm/mcp/tools/_names.js +5 -0
- package/dist/esm/mcp/tools/_registry.js +10 -0
- package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
- package/dist/esm/mcp/tools/_shared/result.js +44 -1
- package/dist/esm/mcp/tools/audit.d.ts +5 -1
- package/dist/esm/mcp/tools/audit.js +40 -0
- package/dist/esm/mcp/tools/audits.d.ts +4 -0
- package/dist/esm/mcp/tools/ci-act.js +9 -11
- package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
- package/dist/esm/mcp/tools/ci-preflight.js +183 -0
- package/dist/esm/mcp/tools/pr-upsert.js +39 -1
- package/dist/esm/mcp/tools/review-run.d.ts +28 -0
- package/dist/esm/mcp/tools/review-run.js +216 -0
- package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
- package/dist/esm/mcp/tools/run-wait.js +593 -0
- package/dist/esm/mcp/tools/session-id.d.ts +3 -0
- package/dist/esm/mcp/tools/session-id.js +45 -0
- package/dist/esm/mcp/tools/session-info.d.ts +3 -0
- package/dist/esm/mcp/tools/session-info.js +49 -0
- package/dist/esm/output-transforms/audit.d.ts +23 -0
- package/dist/esm/output-transforms/audit.js +47 -0
- package/dist/esm/output-transforms/index.js +2 -0
- package/dist/esm/paths/state-root.js +3 -0
- package/dist/esm/review/authority.js +30 -7
- package/dist/esm/review/availability.d.ts +22 -0
- package/dist/esm/review/availability.js +123 -23
- package/dist/esm/review/delivery-verifier.d.ts +27 -0
- package/dist/esm/review/delivery-verifier.js +115 -0
- package/dist/esm/review/events.d.ts +3 -2
- package/dist/esm/review/events.js +23 -3
- package/dist/esm/review/execution/adapters.js +26 -9
- package/dist/esm/review/execution/output-policy.d.ts +2 -0
- package/dist/esm/review/execution/output-policy.js +12 -0
- package/dist/esm/review/execution/review-checkout.js +87 -6
- package/dist/esm/review/execution/supervisor.js +5 -0
- package/dist/esm/review/execution/types.d.ts +8 -0
- package/dist/esm/review/opencode-account.d.ts +24 -0
- package/dist/esm/review/opencode-account.js +68 -0
- package/dist/esm/review/opencode-auth.d.ts +33 -0
- package/dist/esm/review/opencode-auth.js +79 -0
- package/dist/esm/review/subject.d.ts +27 -0
- package/dist/esm/review/subject.js +179 -32
- package/dist/esm/runtime/executor.d.ts +1 -0
- package/dist/esm/runtime/executor.js +2 -1
- package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
- package/dist/esm/runtime/opencode-account-materializer.js +33 -0
- package/dist/esm/secret-gate/runner.d.ts +1 -0
- package/dist/esm/secret-gate/runner.js +4 -1
- package/dist/esm/status/snapshot.js +30 -19
- package/dist/esm/test/duration-sequencer.d.ts +20 -0
- package/dist/esm/test/duration-sequencer.js +54 -0
- package/dist/esm/test/shard-durations.json +922 -0
- package/dist/esm/test/worker-budget.d.ts +6 -0
- package/dist/esm/test/worker-budget.js +59 -1
- package/dist/esm/test-helpers/global-setup.d.ts +1 -1
- package/dist/esm/test-helpers/global-setup.js +68 -24
- package/dist/esm/ultragoal/service.d.ts +7 -0
- package/dist/esm/ultragoal/service.js +42 -2
- package/dist/esm/utils/write-json-file.js +3 -1
- package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
- package/dist/esm/worktrees/codex-project-trust.js +56 -0
- package/dist/esm/worktrees/current.d.ts +1 -0
- package/dist/esm/worktrees/current.js +1 -0
- package/dist/esm/worktrees/project-agent-surfaces.d.ts +1 -0
- package/dist/esm/worktrees/project-agent-surfaces.js +2 -1
- package/dist/esm/worktrees/registry.d.ts +8 -0
- package/dist/esm/worktrees/registry.js +18 -3
- package/package.json +18 -15
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge-set projection: membership (expected hosts) + registry runs → rollup.
|
|
3
|
+
* Pure given membership + run observations — no second run store.
|
|
4
|
+
*
|
|
5
|
+
* Operator surface: summary + per-host matrix only. Git/PR auto-merge is out of
|
|
6
|
+
* scope (no silent git merge of host work).
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { type FanOutAttentionProjection } from "#cli/commands/dash/plan-once-attention.js";
|
|
10
|
+
import { type PlanMembership } from "#cli/commands/dash/plan-once-membership.js";
|
|
11
|
+
export declare const MERGE_ROLLUPS: readonly ["all-ok", "partial", "all-failed", "incomplete"];
|
|
12
|
+
export type MergeRollup = (typeof MERGE_ROLLUPS)[number];
|
|
13
|
+
/** Rollups that should occupy the attention strip (all-ok does not). */
|
|
14
|
+
export declare const MERGE_ATTENTION_ROLLUPS: readonly ["incomplete", "partial", "all-failed"];
|
|
15
|
+
export declare const mergeRollupSchema: z.ZodEnum<{
|
|
16
|
+
"all-failed": "all-failed";
|
|
17
|
+
"all-ok": "all-ok";
|
|
18
|
+
incomplete: "incomplete";
|
|
19
|
+
partial: "partial";
|
|
20
|
+
}>;
|
|
21
|
+
export declare const mergeHostStatusSchema: z.ZodEnum<{
|
|
22
|
+
failed: "failed";
|
|
23
|
+
missing: "missing";
|
|
24
|
+
ok: "ok";
|
|
25
|
+
unknown: "unknown";
|
|
26
|
+
}>;
|
|
27
|
+
export declare const mergeHostObservationSchema: z.ZodObject<{
|
|
28
|
+
host: z.ZodString;
|
|
29
|
+
workdir: z.ZodString;
|
|
30
|
+
expectedLabel: z.ZodString;
|
|
31
|
+
runId: z.ZodNullable<z.ZodString>;
|
|
32
|
+
state: z.ZodNullable<z.ZodString>;
|
|
33
|
+
error: z.ZodNullable<z.ZodString>;
|
|
34
|
+
status: z.ZodEnum<{
|
|
35
|
+
failed: "failed";
|
|
36
|
+
missing: "missing";
|
|
37
|
+
ok: "ok";
|
|
38
|
+
unknown: "unknown";
|
|
39
|
+
}>;
|
|
40
|
+
}, z.core.$strict>;
|
|
41
|
+
export type MergeHostObservation = z.infer<typeof mergeHostObservationSchema>;
|
|
42
|
+
export type MergeSetProjection = {
|
|
43
|
+
readonly planId: string;
|
|
44
|
+
readonly expectedCount: number;
|
|
45
|
+
readonly observedCount: number;
|
|
46
|
+
readonly missingCount: number;
|
|
47
|
+
readonly failedCount: number;
|
|
48
|
+
readonly okCount: number;
|
|
49
|
+
readonly rollup: MergeRollup;
|
|
50
|
+
readonly hosts: readonly MergeHostObservation[];
|
|
51
|
+
readonly attention: FanOutAttentionProjection;
|
|
52
|
+
};
|
|
53
|
+
/** Serializable subset of merge projection (attention omitted). */
|
|
54
|
+
export declare const mergeSetCoreSchema: z.ZodObject<{
|
|
55
|
+
planId: z.ZodString;
|
|
56
|
+
expectedCount: z.ZodNumber;
|
|
57
|
+
observedCount: z.ZodNumber;
|
|
58
|
+
missingCount: z.ZodNumber;
|
|
59
|
+
failedCount: z.ZodNumber;
|
|
60
|
+
okCount: z.ZodNumber;
|
|
61
|
+
rollup: z.ZodEnum<{
|
|
62
|
+
"all-failed": "all-failed";
|
|
63
|
+
"all-ok": "all-ok";
|
|
64
|
+
incomplete: "incomplete";
|
|
65
|
+
partial: "partial";
|
|
66
|
+
}>;
|
|
67
|
+
hosts: z.ZodArray<z.ZodObject<{
|
|
68
|
+
host: z.ZodString;
|
|
69
|
+
workdir: z.ZodString;
|
|
70
|
+
expectedLabel: z.ZodString;
|
|
71
|
+
runId: z.ZodNullable<z.ZodString>;
|
|
72
|
+
state: z.ZodNullable<z.ZodString>;
|
|
73
|
+
error: z.ZodNullable<z.ZodString>;
|
|
74
|
+
status: z.ZodEnum<{
|
|
75
|
+
failed: "failed";
|
|
76
|
+
missing: "missing";
|
|
77
|
+
ok: "ok";
|
|
78
|
+
unknown: "unknown";
|
|
79
|
+
}>;
|
|
80
|
+
}, z.core.$strict>>;
|
|
81
|
+
}, z.core.$strict>;
|
|
82
|
+
export type MergeRunRow = {
|
|
83
|
+
readonly id: string;
|
|
84
|
+
readonly provider: string;
|
|
85
|
+
readonly state: string;
|
|
86
|
+
readonly error?: string | null;
|
|
87
|
+
readonly label?: string | null;
|
|
88
|
+
/** ISO timestamp when present — used to prefer newest re-apply label match. */
|
|
89
|
+
readonly updatedAt?: string | null;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Project merge set from durable membership + registry-visible runs.
|
|
93
|
+
* Missing expected host → incomplete (never all-ok).
|
|
94
|
+
*/
|
|
95
|
+
export declare function projectMergeSet(input: {
|
|
96
|
+
readonly membership: PlanMembership;
|
|
97
|
+
readonly runs: readonly MergeRunRow[];
|
|
98
|
+
readonly now?: string;
|
|
99
|
+
}): MergeSetProjection;
|
|
100
|
+
export type ProjectMergeSetForPlanResult = {
|
|
101
|
+
readonly ok: true;
|
|
102
|
+
readonly projection: MergeSetProjection;
|
|
103
|
+
} | {
|
|
104
|
+
readonly ok: false;
|
|
105
|
+
readonly error: "membership-missing";
|
|
106
|
+
readonly planId: string;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* planId → load durable membership + readDashRuns → merge projection.
|
|
110
|
+
* Uses run-registry only (no second run store). Missing membership fails closed.
|
|
111
|
+
* Includes archived runs so archived hosts do not look missing after cleanup.
|
|
112
|
+
*/
|
|
113
|
+
export declare function projectMergeSetForPlan(planId: string, options?: {
|
|
114
|
+
readonly cwd?: string;
|
|
115
|
+
readonly now?: string;
|
|
116
|
+
}): Promise<ProjectMergeSetForPlanResult>;
|
|
117
|
+
/** Project merge sets for every durable membership under the state root. */
|
|
118
|
+
export declare function projectAllMergeSets(options?: {
|
|
119
|
+
readonly cwd?: string;
|
|
120
|
+
readonly now?: string;
|
|
121
|
+
}): Promise<readonly MergeSetProjection[]>;
|
|
122
|
+
/** One-line operator rollup for HUD/attention strip. */
|
|
123
|
+
export declare function formatMergeSetSummary(projection: MergeSetProjection): string;
|
|
124
|
+
/** Per-host matrix lines for operator surface. */
|
|
125
|
+
export declare function formatMergeSetMatrix(projection: MergeSetProjection): readonly string[];
|
|
126
|
+
export type MergeOperatorSurface = {
|
|
127
|
+
readonly summary: string;
|
|
128
|
+
readonly matrix: readonly string[];
|
|
129
|
+
/**
|
|
130
|
+
* Explicit scope boundary: this surface is status/summary only.
|
|
131
|
+
* Silent git/PR auto-merge of host worktrees remains out of scope.
|
|
132
|
+
*/
|
|
133
|
+
readonly scopeNote: string;
|
|
134
|
+
};
|
|
135
|
+
/** Operator-visible merge surface (HUD/browser). No silent git merge. */
|
|
136
|
+
export declare function formatMergeOperatorSurface(projection: MergeSetProjection): MergeOperatorSurface;
|
|
137
|
+
/** Pick the highest-severity merge projection for a single attention line. */
|
|
138
|
+
export declare function pickPrimaryMergeProjection(projections: readonly MergeSetProjection[]): MergeSetProjection | null;
|
|
139
|
+
/**
|
|
140
|
+
* Attention-strip line for the worst non-ok merge set.
|
|
141
|
+
* all-ok is omitted so generic per-run attention remains visible.
|
|
142
|
+
*/
|
|
143
|
+
export declare function formatPrimaryMergeAttentionLine(projections: readonly MergeSetProjection[]): string | null;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge-set projection: membership (expected hosts) + registry runs → rollup.
|
|
3
|
+
* Pure given membership + run observations — no second run store.
|
|
4
|
+
*
|
|
5
|
+
* Operator surface: summary + per-host matrix only. Git/PR auto-merge is out of
|
|
6
|
+
* scope (no silent git merge of host work).
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { projectFanOutAttention, } from "#cli/commands/dash/plan-once-attention.js";
|
|
10
|
+
import { readPlanMembership, listPlanMemberships, } from "#cli/commands/dash/plan-once-membership.js";
|
|
11
|
+
import { readDashRuns } from "#cli/commands/dash/run-registry.js";
|
|
12
|
+
export const MERGE_ROLLUPS = ["all-ok", "partial", "all-failed", "incomplete"];
|
|
13
|
+
/** Rollups that should occupy the attention strip (all-ok does not). */
|
|
14
|
+
export const MERGE_ATTENTION_ROLLUPS = ["incomplete", "partial", "all-failed"];
|
|
15
|
+
export const mergeRollupSchema = z.enum(MERGE_ROLLUPS);
|
|
16
|
+
export const mergeHostStatusSchema = z.enum(["ok", "failed", "missing", "unknown"]);
|
|
17
|
+
export const mergeHostObservationSchema = z
|
|
18
|
+
.object({
|
|
19
|
+
host: z.string().min(1),
|
|
20
|
+
workdir: z.string().min(1),
|
|
21
|
+
expectedLabel: z.string().min(1),
|
|
22
|
+
runId: z.string().nullable(),
|
|
23
|
+
state: z.string().nullable(),
|
|
24
|
+
error: z.string().nullable(),
|
|
25
|
+
status: mergeHostStatusSchema,
|
|
26
|
+
})
|
|
27
|
+
.strict();
|
|
28
|
+
/** Serializable subset of merge projection (attention omitted). */
|
|
29
|
+
export const mergeSetCoreSchema = z
|
|
30
|
+
.object({
|
|
31
|
+
planId: z.string().uuid(),
|
|
32
|
+
expectedCount: z.number().int().nonnegative(),
|
|
33
|
+
observedCount: z.number().int().nonnegative(),
|
|
34
|
+
missingCount: z.number().int().nonnegative(),
|
|
35
|
+
failedCount: z.number().int().nonnegative(),
|
|
36
|
+
okCount: z.number().int().nonnegative(),
|
|
37
|
+
rollup: mergeRollupSchema,
|
|
38
|
+
hosts: z.array(mergeHostObservationSchema),
|
|
39
|
+
})
|
|
40
|
+
.strict();
|
|
41
|
+
function matchRun(expected, runs) {
|
|
42
|
+
// Exact label only — substring/prefix matching can join the wrong host when
|
|
43
|
+
// labels share prefixes and would undercount missing hosts as observed.
|
|
44
|
+
const matches = runs.filter((r) => r.label === expected.label);
|
|
45
|
+
if (matches.length === 0)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (matches.length === 1)
|
|
48
|
+
return matches[0];
|
|
49
|
+
// Prefer newest when re-apply leaves multiple rows with the same label.
|
|
50
|
+
return matches.reduce((best, row) => {
|
|
51
|
+
const bestTs = best.updatedAt ?? "";
|
|
52
|
+
const rowTs = row.updatedAt ?? "";
|
|
53
|
+
return rowTs >= bestTs ? row : best;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function hostStatus(run) {
|
|
57
|
+
if (!run)
|
|
58
|
+
return "missing";
|
|
59
|
+
const state = run.state.toLowerCase();
|
|
60
|
+
if (state === "failed" || state === "error")
|
|
61
|
+
return "failed";
|
|
62
|
+
if (state === "unknown" || state === "stale")
|
|
63
|
+
return "unknown";
|
|
64
|
+
if (state === "running" ||
|
|
65
|
+
state === "starting" ||
|
|
66
|
+
state === "completed" ||
|
|
67
|
+
state === "idle" ||
|
|
68
|
+
state === "waiting" ||
|
|
69
|
+
state === "detached" ||
|
|
70
|
+
state === "stopped" ||
|
|
71
|
+
state === "archived") {
|
|
72
|
+
return "ok";
|
|
73
|
+
}
|
|
74
|
+
// Unrecognized durable state: fail-closed as unknown (not green)
|
|
75
|
+
return "unknown";
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Project merge set from durable membership + registry-visible runs.
|
|
79
|
+
* Missing expected host → incomplete (never all-ok).
|
|
80
|
+
*/
|
|
81
|
+
export function projectMergeSet(input) {
|
|
82
|
+
const hosts = input.membership.hosts.map((expected) => {
|
|
83
|
+
const run = matchRun(expected, input.runs);
|
|
84
|
+
const status = hostStatus(run);
|
|
85
|
+
return {
|
|
86
|
+
host: expected.host,
|
|
87
|
+
workdir: expected.workdir,
|
|
88
|
+
expectedLabel: expected.label,
|
|
89
|
+
runId: run?.id ?? null,
|
|
90
|
+
state: run?.state ?? null,
|
|
91
|
+
error: run?.error ?? null,
|
|
92
|
+
status,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
const missingCount = hosts.filter((h) => h.status === "missing").length;
|
|
96
|
+
const failedCount = hosts.filter((h) => h.status === "failed" || h.status === "unknown").length;
|
|
97
|
+
const okCount = hosts.filter((h) => h.status === "ok").length;
|
|
98
|
+
const observedCount = hosts.filter((h) => h.runId !== null).length;
|
|
99
|
+
let rollup;
|
|
100
|
+
if (missingCount > 0) {
|
|
101
|
+
rollup = "incomplete";
|
|
102
|
+
}
|
|
103
|
+
else if (failedCount === hosts.length && hosts.length > 0) {
|
|
104
|
+
rollup = "all-failed";
|
|
105
|
+
}
|
|
106
|
+
else if (failedCount > 0) {
|
|
107
|
+
rollup = "partial";
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
rollup = "all-ok";
|
|
111
|
+
}
|
|
112
|
+
const attentionRuns = hosts
|
|
113
|
+
.filter((h) => h.runId)
|
|
114
|
+
.map((h) => ({
|
|
115
|
+
runId: h.runId,
|
|
116
|
+
provider: h.host,
|
|
117
|
+
state: h.state ?? "unknown",
|
|
118
|
+
error: h.error,
|
|
119
|
+
}));
|
|
120
|
+
const attention = projectFanOutAttention({
|
|
121
|
+
planId: input.membership.planId,
|
|
122
|
+
runs: attentionRuns,
|
|
123
|
+
now: input.now,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
planId: input.membership.planId,
|
|
127
|
+
expectedCount: hosts.length,
|
|
128
|
+
observedCount,
|
|
129
|
+
missingCount,
|
|
130
|
+
failedCount,
|
|
131
|
+
okCount,
|
|
132
|
+
rollup,
|
|
133
|
+
hosts,
|
|
134
|
+
attention,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function toMergeRunRows(runs) {
|
|
138
|
+
return runs.map((r) => ({
|
|
139
|
+
id: r.id,
|
|
140
|
+
provider: r.provider,
|
|
141
|
+
state: r.state,
|
|
142
|
+
error: r.error,
|
|
143
|
+
label: r.label,
|
|
144
|
+
updatedAt: r.updatedAt,
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* planId → load durable membership + readDashRuns → merge projection.
|
|
149
|
+
* Uses run-registry only (no second run store). Missing membership fails closed.
|
|
150
|
+
* Includes archived runs so archived hosts do not look missing after cleanup.
|
|
151
|
+
*/
|
|
152
|
+
export async function projectMergeSetForPlan(planId, options = {}) {
|
|
153
|
+
const membership = await readPlanMembership(planId, { cwd: options.cwd });
|
|
154
|
+
if (!membership) {
|
|
155
|
+
return { ok: false, error: "membership-missing", planId };
|
|
156
|
+
}
|
|
157
|
+
const { runs } = await readDashRuns({ cwd: options.cwd, includeArchived: true });
|
|
158
|
+
const projection = projectMergeSet({
|
|
159
|
+
membership,
|
|
160
|
+
runs: toMergeRunRows(runs),
|
|
161
|
+
now: options.now,
|
|
162
|
+
});
|
|
163
|
+
return { ok: true, projection };
|
|
164
|
+
}
|
|
165
|
+
/** Project merge sets for every durable membership under the state root. */
|
|
166
|
+
export async function projectAllMergeSets(options = {}) {
|
|
167
|
+
const memberships = await listPlanMemberships({ cwd: options.cwd });
|
|
168
|
+
if (memberships.length === 0)
|
|
169
|
+
return [];
|
|
170
|
+
// includeArchived: archived plan-once hosts are still N-of-N observations.
|
|
171
|
+
const { runs } = await readDashRuns({ cwd: options.cwd, includeArchived: true });
|
|
172
|
+
const rows = toMergeRunRows(runs);
|
|
173
|
+
return memberships.map((membership) => projectMergeSet({ membership, runs: rows, now: options.now }));
|
|
174
|
+
}
|
|
175
|
+
/** One-line operator rollup for HUD/attention strip. */
|
|
176
|
+
export function formatMergeSetSummary(projection) {
|
|
177
|
+
const short = projection.planId.slice(0, 8);
|
|
178
|
+
const base = `merge ${short} · ${projection.rollup} · ${projection.okCount}/${projection.expectedCount} ok`;
|
|
179
|
+
// "all-ok" means every expected host is observed and non-failed — not that
|
|
180
|
+
// every host is terminal (running/starting still map to ok for N-of-N).
|
|
181
|
+
if (projection.rollup === "all-ok")
|
|
182
|
+
return `${base} · all observed · none failed`;
|
|
183
|
+
if (projection.missingCount > 0) {
|
|
184
|
+
const missing = projection.hosts
|
|
185
|
+
.filter((h) => h.status === "missing")
|
|
186
|
+
.map((h) => h.host)
|
|
187
|
+
.join(",");
|
|
188
|
+
return `${base} · missing ${missing}`;
|
|
189
|
+
}
|
|
190
|
+
if (projection.failedCount > 0) {
|
|
191
|
+
const failed = projection.hosts
|
|
192
|
+
.filter((h) => h.status === "failed" || h.status === "unknown")
|
|
193
|
+
.map((h) => `${h.host}:${h.error ?? h.state ?? h.status}`)
|
|
194
|
+
.join("; ");
|
|
195
|
+
return `${base} · ${failed}`;
|
|
196
|
+
}
|
|
197
|
+
return base;
|
|
198
|
+
}
|
|
199
|
+
/** Per-host matrix lines for operator surface. */
|
|
200
|
+
export function formatMergeSetMatrix(projection) {
|
|
201
|
+
return projection.hosts.map((h) => {
|
|
202
|
+
const state = h.state ?? "—";
|
|
203
|
+
const err = h.error ? ` · ${h.error}` : "";
|
|
204
|
+
return `${h.host} · ${h.status} · ${state}${err}`;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/** Operator-visible merge surface (HUD/browser). No silent git merge. */
|
|
208
|
+
export function formatMergeOperatorSurface(projection) {
|
|
209
|
+
return {
|
|
210
|
+
summary: formatMergeSetSummary(projection),
|
|
211
|
+
matrix: formatMergeSetMatrix(projection),
|
|
212
|
+
scopeNote: "git/PR auto-merge out of scope — status/summary only",
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const ROLLUP_SEVERITY = {
|
|
216
|
+
incomplete: 4,
|
|
217
|
+
"all-failed": 3,
|
|
218
|
+
partial: 2,
|
|
219
|
+
"all-ok": 1,
|
|
220
|
+
};
|
|
221
|
+
/** Pick the highest-severity merge projection for a single attention line. */
|
|
222
|
+
export function pickPrimaryMergeProjection(projections) {
|
|
223
|
+
if (projections.length === 0)
|
|
224
|
+
return null;
|
|
225
|
+
return [...projections].sort((a, b) => ROLLUP_SEVERITY[b.rollup] - ROLLUP_SEVERITY[a.rollup])[0];
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Attention-strip line for the worst non-ok merge set.
|
|
229
|
+
* all-ok is omitted so generic per-run attention remains visible.
|
|
230
|
+
*/
|
|
231
|
+
export function formatPrimaryMergeAttentionLine(projections) {
|
|
232
|
+
const primary = pickPrimaryMergeProjection(projections);
|
|
233
|
+
if (!primary)
|
|
234
|
+
return null;
|
|
235
|
+
if (primary.rollup === "all-ok")
|
|
236
|
+
return null;
|
|
237
|
+
return formatMergeSetSummary(primary);
|
|
238
|
+
}
|
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
* - Partial failure: continue remaining hosts; failed hosts reported honestly.
|
|
15
15
|
*/
|
|
16
16
|
import type { DashLaunchCoordinator, DashLaunchResult } from "#cli/commands/dash/launch-coordinator.js";
|
|
17
|
-
import { type MultiHostPlanProposal, type PlanOnceDecision, type
|
|
17
|
+
import { type MultiHostPlanProposal, type PlanOnceDecision, type PlanOnceValidationIssue } from "#cli/commands/dash/plan-once-schema.js";
|
|
18
18
|
import { type DashPermissionMode, type DashProvider } from "#cli/commands/dash/provider-capabilities.js";
|
|
19
19
|
import { type CreateDashRunInput } from "#cli/commands/dash/run-registry.js";
|
|
20
20
|
import type { DashRun, DashRunState } from "#cli/commands/dash/run-types.js";
|
|
21
21
|
export { PLAN_ONCE_SCHEMA_VERSION, parseMultiHostPlanProposal, parsePlanOnceDecision, multiHostPlanProposalSchema, planOnceDecisionSchema, type MultiHostPlanProposal, type PlanOnceDecision, type PlanOnceHostEntry, type PlanOnceValidationIssue, } from "#cli/commands/dash/plan-once-schema.js";
|
|
22
|
+
export { planOnceRunLabel } from "#cli/commands/dash/plan-once-label.js";
|
|
22
23
|
/** Documented fan-out concurrency — sequential because coordinator admits one pending launch. */
|
|
23
24
|
export declare const PLAN_ONCE_FANOUT_CONCURRENCY: "sequential";
|
|
24
25
|
export type PlanOnceFanOutConcurrency = typeof PLAN_ONCE_FANOUT_CONCURRENCY;
|
|
@@ -39,6 +40,26 @@ export declare function createPlanOnceSession(plan: MultiHostPlanProposal): Plan
|
|
|
39
40
|
export declare function reducePlanOnceDecision(session: PlanOnceSession, decision: PlanOnceDecision): PlanOnceReduceResult;
|
|
40
41
|
/** Parse decision then reduce — convenience for IPC/menu handlers. */
|
|
41
42
|
export declare function applyPlanOnceDecision(session: PlanOnceSession, rawDecision: unknown): PlanOnceReduceResult;
|
|
43
|
+
export type ConfirmPlanOnceWithMembershipResult = {
|
|
44
|
+
readonly ok: true;
|
|
45
|
+
readonly session: PlanOnceSession;
|
|
46
|
+
/** Set when confirm succeeds and membership was written. */
|
|
47
|
+
readonly membershipWritten: boolean;
|
|
48
|
+
} | {
|
|
49
|
+
readonly ok: false;
|
|
50
|
+
readonly error: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Confirm-once with durable membership write. Cancel never writes membership.
|
|
54
|
+
* Lazy-imports membership IO so pure reducers stay free of FS side effects.
|
|
55
|
+
*/
|
|
56
|
+
export declare function confirmPlanOnceWithMembership(input: {
|
|
57
|
+
readonly session: PlanOnceSession;
|
|
58
|
+
readonly decision: PlanOnceDecision | unknown;
|
|
59
|
+
readonly cwd?: string;
|
|
60
|
+
/** Injected for tests; default writes real membership store. */
|
|
61
|
+
readonly writeMembership?: (plan: MultiHostPlanProposal, cwd?: string) => Promise<unknown>;
|
|
62
|
+
}): Promise<ConfirmPlanOnceWithMembershipResult>;
|
|
42
63
|
export type FanOutHostResult = {
|
|
43
64
|
readonly host: DashProvider;
|
|
44
65
|
readonly workdir: string;
|
|
@@ -91,7 +112,6 @@ export type PlanOnceApplyDeps = {
|
|
|
91
112
|
/** Registry file scope (dash instance cwd). Host workdirs may differ. */
|
|
92
113
|
readonly registryCwd: string;
|
|
93
114
|
};
|
|
94
|
-
export declare function planOnceRunLabel(planId: string, host: PlanOnceHostEntry): string;
|
|
95
115
|
/**
|
|
96
116
|
* Apply a confirmed plan: sequential fan-out through launch coordinator.
|
|
97
117
|
*
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { resolveLaunchPermissionMode } from "#cli/commands/dash/launch-preferences.js";
|
|
2
|
+
import { planOnceRunLabel } from "#cli/commands/dash/plan-once-label.js";
|
|
2
3
|
import { parseMultiHostPlanProposal, parsePlanOnceDecision, } from "#cli/commands/dash/plan-once-schema.js";
|
|
3
4
|
import { buildDashLaunchCommand, } from "#cli/commands/dash/provider-capabilities.js";
|
|
4
5
|
import { updateDashRun } from "#cli/commands/dash/run-registry.js";
|
|
5
6
|
export { PLAN_ONCE_SCHEMA_VERSION, parseMultiHostPlanProposal, parsePlanOnceDecision, multiHostPlanProposalSchema, planOnceDecisionSchema, } from "#cli/commands/dash/plan-once-schema.js";
|
|
7
|
+
export { planOnceRunLabel } from "#cli/commands/dash/plan-once-label.js";
|
|
6
8
|
/** Documented fan-out concurrency — sequential because coordinator admits one pending launch. */
|
|
7
9
|
export const PLAN_ONCE_FANOUT_CONCURRENCY = "sequential";
|
|
8
10
|
/** Pure confirm-once / cancel reducer — no registry side effects. */
|
|
@@ -35,6 +37,37 @@ export function applyPlanOnceDecision(session, rawDecision) {
|
|
|
35
37
|
}
|
|
36
38
|
return reducePlanOnceDecision(session, parsed.decision);
|
|
37
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Confirm-once with durable membership write. Cancel never writes membership.
|
|
42
|
+
* Lazy-imports membership IO so pure reducers stay free of FS side effects.
|
|
43
|
+
*/
|
|
44
|
+
export async function confirmPlanOnceWithMembership(input) {
|
|
45
|
+
// Always schema-parse the public entrypoint (no cast-on-kind shortcut).
|
|
46
|
+
const parsed = parsePlanOnceDecision(input.decision);
|
|
47
|
+
if (!parsed.ok) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
error: parsed.issues.map((i) => i.message).join("; ") || "Invalid plan decision",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const reduced = reducePlanOnceDecision(input.session, parsed.decision);
|
|
54
|
+
if (!reduced.ok)
|
|
55
|
+
return { ok: false, error: reduced.error };
|
|
56
|
+
if (reduced.session.status === "cancelled") {
|
|
57
|
+
return { ok: true, session: reduced.session, membershipWritten: false };
|
|
58
|
+
}
|
|
59
|
+
if (reduced.session.status !== "confirmed") {
|
|
60
|
+
return { ok: false, error: `Unexpected status after decision: ${reduced.session.status}` };
|
|
61
|
+
}
|
|
62
|
+
if (input.writeMembership) {
|
|
63
|
+
await input.writeMembership(reduced.session.plan, input.cwd);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const { buildPlanMembership, writePlanMembership } = await import("#cli/commands/dash/plan-once-membership.js");
|
|
67
|
+
await writePlanMembership(buildPlanMembership(reduced.session.plan), { cwd: input.cwd });
|
|
68
|
+
}
|
|
69
|
+
return { ok: true, session: reduced.session, membershipWritten: true };
|
|
70
|
+
}
|
|
38
71
|
function defaultRegistryPort() {
|
|
39
72
|
// createRun is intentionally not used by apply — only updateRun for plan labels.
|
|
40
73
|
// Import createDashRun only when tests inject a full port; production update path:
|
|
@@ -53,10 +86,6 @@ function defaultDeps(input) {
|
|
|
53
86
|
registryCwd: input.registryCwd,
|
|
54
87
|
};
|
|
55
88
|
}
|
|
56
|
-
export function planOnceRunLabel(planId, host) {
|
|
57
|
-
const base = host.label?.trim() || host.host;
|
|
58
|
-
return `plan-once:${planId}:${base}`;
|
|
59
|
-
}
|
|
60
89
|
function outcomeRunId(result) {
|
|
61
90
|
const outcome = result.outcome;
|
|
62
91
|
if ("runId" in outcome && typeof outcome.runId === "string" && outcome.runId.length > 0) {
|
|
@@ -80,6 +109,14 @@ export async function applyConfirmedMultiHostPlan(input) {
|
|
|
80
109
|
const deps = defaultDeps(input);
|
|
81
110
|
const plan = input.session.plan;
|
|
82
111
|
const hostResults = [];
|
|
112
|
+
// Ensure durable membership exists before fan-out (idempotent). Cancel never reaches here.
|
|
113
|
+
try {
|
|
114
|
+
const { buildPlanMembership, writePlanMembership } = await import("#cli/commands/dash/plan-once-membership.js");
|
|
115
|
+
await writePlanMembership(buildPlanMembership(plan), { cwd: deps.registryCwd });
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Membership write failure does not block launch; merge may report incomplete.
|
|
119
|
+
}
|
|
83
120
|
for (const entry of plan.hosts) {
|
|
84
121
|
const permissionMode = deps.resolvePermissionMode(entry.extraArgs ?? [], entry.host);
|
|
85
122
|
const command = buildDashLaunchCommand(entry.host, permissionMode, entry.extraArgs ?? []);
|
|
@@ -2,6 +2,15 @@ import { type AttentionItem } from "#cli/commands/dash/attention.js";
|
|
|
2
2
|
import type { AgentRunStatus } from "#cli/commands/dash/pane-controller.js";
|
|
3
3
|
export declare function attentionItemsFromRunStatuses(statuses: readonly AgentRunStatus[], now?: string): readonly AttentionItem[];
|
|
4
4
|
export declare function formatAttentionLine(items: readonly AttentionItem[]): string | null;
|
|
5
|
+
/**
|
|
6
|
+
* Prefer multi-host merge rollup when the merge line is non-null.
|
|
7
|
+
* Callers should pass a merge line only for non-all-ok rollups
|
|
8
|
+
* (`formatPrimaryMergeAttentionLine`) so all-ok does not hide live failures.
|
|
9
|
+
*/
|
|
10
|
+
export declare function selectAttentionLine(input: {
|
|
11
|
+
readonly mergeLine: string | null;
|
|
12
|
+
readonly genericLine: string | null;
|
|
13
|
+
}): string | null;
|
|
5
14
|
/** Dash-process RSS + active run count (owned tree probe is best-effort elsewhere). */
|
|
6
15
|
export declare function formatResourceLine(input: {
|
|
7
16
|
readonly statuses: readonly AgentRunStatus[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Project session attention + process resource HUD lines for the pure TUI.
|
|
2
2
|
// Uses the same normalizeSessionState / projectAttention domain as desktop.
|
|
3
|
+
// Multi-host merge rollup (plan-once membership) can override the generic line.
|
|
3
4
|
import { normalizeSessionState, projectAttention, } from "#cli/commands/dash/attention.js";
|
|
4
5
|
import { resourceView } from "#cli/commands/dash/resources.js";
|
|
5
6
|
export function attentionItemsFromRunStatuses(statuses, now = new Date().toISOString()) {
|
|
@@ -35,6 +36,14 @@ export function formatAttentionLine(items) {
|
|
|
35
36
|
return null;
|
|
36
37
|
return `attention · ${top.provider}:${top.state} · ${top.reason} · ${top.action}`;
|
|
37
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Prefer multi-host merge rollup when the merge line is non-null.
|
|
41
|
+
* Callers should pass a merge line only for non-all-ok rollups
|
|
42
|
+
* (`formatPrimaryMergeAttentionLine`) so all-ok does not hide live failures.
|
|
43
|
+
*/
|
|
44
|
+
export function selectAttentionLine(input) {
|
|
45
|
+
return input.mergeLine ?? input.genericLine;
|
|
46
|
+
}
|
|
38
47
|
/** Dash-process RSS + active run count (owned tree probe is best-effort elsewhere). */
|
|
39
48
|
export function formatResourceLine(input) {
|
|
40
49
|
const active = input.statuses.filter((status) => status.running || status.active);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integrated-chat bridge port: hermetic fake for CI + real adapter seam.
|
|
3
|
+
* Does not create dash runs — uses existing run identity only (no second registry).
|
|
4
|
+
*/
|
|
5
|
+
import type { DashProvider } from "#cli/commands/dash/provider-capabilities.js";
|
|
6
|
+
export type ChatRole = "user" | "assistant" | "system";
|
|
7
|
+
export type ChatMessage = {
|
|
8
|
+
readonly role: ChatRole;
|
|
9
|
+
readonly text: string;
|
|
10
|
+
readonly at: string;
|
|
11
|
+
};
|
|
12
|
+
export type ChatSession = {
|
|
13
|
+
readonly runId: string;
|
|
14
|
+
readonly host: DashProvider;
|
|
15
|
+
readonly label: string | null;
|
|
16
|
+
readonly messages: readonly ChatMessage[];
|
|
17
|
+
};
|
|
18
|
+
export type ChatBridgeResult = {
|
|
19
|
+
readonly ok: true;
|
|
20
|
+
readonly session: ChatSession;
|
|
21
|
+
} | {
|
|
22
|
+
readonly ok: false;
|
|
23
|
+
readonly error: string;
|
|
24
|
+
};
|
|
25
|
+
export type ChatBridge = {
|
|
26
|
+
open(input: {
|
|
27
|
+
readonly host: DashProvider;
|
|
28
|
+
readonly runId: string;
|
|
29
|
+
readonly label?: string | null;
|
|
30
|
+
}): Promise<ChatBridgeResult>;
|
|
31
|
+
send(session: ChatSession, text: string): Promise<ChatBridgeResult>;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Hermetic bridge: drives real send/receive entry points without live ACP.
|
|
35
|
+
* Codex is the MVP host (capability matrix); others fail with matrix reasons.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createHermeticChatBridge(options?: {
|
|
38
|
+
readonly now?: () => string;
|
|
39
|
+
}): ChatBridge;
|
|
40
|
+
/** Format transcript lines for browser overlay. */
|
|
41
|
+
export declare function formatChatTranscript(session: ChatSession): readonly string[];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { hostAcpCapability } from "#cli/commands/dash/tui/chat-mode.js";
|
|
2
|
+
function nowIso() {
|
|
3
|
+
return new Date().toISOString();
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Hermetic bridge: drives real send/receive entry points without live ACP.
|
|
7
|
+
* Codex is the MVP host (capability matrix); others fail with matrix reasons.
|
|
8
|
+
*/
|
|
9
|
+
export function createHermeticChatBridge(options = {}) {
|
|
10
|
+
const stamp = options.now ?? nowIso;
|
|
11
|
+
return {
|
|
12
|
+
async open(input) {
|
|
13
|
+
if (!input.runId.trim()) {
|
|
14
|
+
return { ok: false, error: "runId is required (use existing dash run identity)" };
|
|
15
|
+
}
|
|
16
|
+
const cap = hostAcpCapability(input.host);
|
|
17
|
+
if (!cap.acpAvailable) {
|
|
18
|
+
return { ok: false, error: cap.reason };
|
|
19
|
+
}
|
|
20
|
+
const session = {
|
|
21
|
+
runId: input.runId,
|
|
22
|
+
host: input.host,
|
|
23
|
+
label: input.label ?? null,
|
|
24
|
+
messages: [
|
|
25
|
+
{
|
|
26
|
+
role: "system",
|
|
27
|
+
text: `Integrated chat open for ${input.host} (hermetic). Host-pane remains available via mode switch.`,
|
|
28
|
+
at: stamp(),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
return { ok: true, session };
|
|
33
|
+
},
|
|
34
|
+
async send(session, text) {
|
|
35
|
+
const trimmed = text.trim();
|
|
36
|
+
if (!trimmed) {
|
|
37
|
+
return { ok: false, error: "message text is required" };
|
|
38
|
+
}
|
|
39
|
+
const cap = hostAcpCapability(session.host);
|
|
40
|
+
if (!cap.acpAvailable) {
|
|
41
|
+
return { ok: false, error: cap.reason };
|
|
42
|
+
}
|
|
43
|
+
const userMsg = { role: "user", text: trimmed, at: stamp() };
|
|
44
|
+
// Hermetic assistant echo proves receive path without live LLM.
|
|
45
|
+
const assistantMsg = {
|
|
46
|
+
role: "assistant",
|
|
47
|
+
text: `[hermetic:${session.host}] ${trimmed}`,
|
|
48
|
+
at: stamp(),
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
ok: true,
|
|
52
|
+
session: {
|
|
53
|
+
...session,
|
|
54
|
+
messages: [...session.messages, userMsg, assistantMsg],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Format transcript lines for browser overlay. */
|
|
61
|
+
export function formatChatTranscript(session) {
|
|
62
|
+
const header = [
|
|
63
|
+
`chat · ${session.host} · run ${session.runId.slice(0, 8)}`,
|
|
64
|
+
session.label ? `label · ${session.label}` : null,
|
|
65
|
+
"scope · integrated-chat (host-pane available via mode switch)",
|
|
66
|
+
"─".repeat(40),
|
|
67
|
+
].filter((line) => line !== null);
|
|
68
|
+
const body = session.messages.map((msg) => {
|
|
69
|
+
const tag = msg.role === "user" ? "you" : msg.role === "assistant" ? "host" : "sys";
|
|
70
|
+
return `${tag} · ${msg.text}`;
|
|
71
|
+
});
|
|
72
|
+
return [...header, ...body];
|
|
73
|
+
}
|