@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
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { buildPublicCiActCommand, resolveCiActExecutionMode, sanitizePublicCiActArgv, } from "#ci/act-runner.js";
|
|
1
|
+
import { buildPublicCiActCommand, preparePublicCiActExecution, resolveCiActExecutionMode, resolveCiActSecretEnvProfile, sanitizePublicCiActArgv, shouldForceCiActSecretGate, } from "#ci/act-runner.js";
|
|
2
2
|
import { redactText } from "#mcp/tools/_shared/redact.js";
|
|
3
3
|
import { runSecretGateCommand } from "#secret-gate/runner.js";
|
|
4
4
|
export const DEFAULT_CI_ACT_TIMEOUT_MS = 20 * 60_000;
|
|
5
|
+
export const SMOKE_CI_ACT_TIMEOUT_MS = 30_000;
|
|
5
6
|
export const MAX_CI_ACT_TIMEOUT_MS = 60 * 60_000;
|
|
6
7
|
export const CI_COMMAND_HELP = [
|
|
7
8
|
"Run repository CI helpers through the portable, secret-safe wp surface.",
|
|
@@ -10,6 +11,8 @@ export const CI_COMMAND_HELP = [
|
|
|
10
11
|
"Examples:",
|
|
11
12
|
" wp ci act --workflow ci-e2e",
|
|
12
13
|
" wp ci act --workflow ci-e2e --execute",
|
|
14
|
+
" wp ci act --workflow ci-e2e --execute --smoke",
|
|
15
|
+
" wp ci act --workflow ci-e2e --job test --matrix target:beta",
|
|
13
16
|
" wp ci act --workflow-path .github/workflows/ci.yml --job test",
|
|
14
17
|
].join("\n");
|
|
15
18
|
export function registerCiCommand(cli) {
|
|
@@ -20,6 +23,7 @@ export function registerCiCommand(cli) {
|
|
|
20
23
|
})
|
|
21
24
|
.option("--workflow-path <path>", "Explicit workflow file path")
|
|
22
25
|
.option("--job <id>", "Workflow job id")
|
|
26
|
+
.option("--matrix <key:value>", "Run only matching act matrix selector(s) (repeatable)")
|
|
23
27
|
.option("--event-name <name>", "act event name: pull_request | push | workflow_dispatch")
|
|
24
28
|
.option("--event-path <path>", "Use an existing event JSON file")
|
|
25
29
|
.option("--env-profile <profile>", "Secret-gate runtime profile", { default: "secrets-only" })
|
|
@@ -28,6 +32,7 @@ export function registerCiCommand(cli) {
|
|
|
28
32
|
.option("--container-architecture <arch>", "act container architecture override")
|
|
29
33
|
.option("--platform-image <image>", "act runner image for ubicloud-standard-2")
|
|
30
34
|
.option("--timeout-ms <ms>", `act execution timeout in milliseconds (default: ${DEFAULT_CI_ACT_TIMEOUT_MS})`)
|
|
35
|
+
.option("--smoke", `Use a short ${SMOKE_CI_ACT_TIMEOUT_MS}ms timeout for targeted local proof`)
|
|
31
36
|
.option("--execute", "Run act; default is a redacted dry-run preview")
|
|
32
37
|
.option("--dry-run", "Print the resolved command without executing it")
|
|
33
38
|
.action((action, flags) => {
|
|
@@ -39,14 +44,16 @@ export function registerCiCommand(cli) {
|
|
|
39
44
|
workflow: flags.workflow,
|
|
40
45
|
workflowPath: flags.workflowPath,
|
|
41
46
|
job: flags.job,
|
|
42
|
-
|
|
47
|
+
matrix: parseCiActMatrixFlags(flags.matrix),
|
|
48
|
+
eventName: parseCiActEventName(flags.eventName),
|
|
43
49
|
envProfile: flags.envProfile,
|
|
44
50
|
secretProfile: flags.secretProfile,
|
|
45
|
-
mode: flags.mode,
|
|
51
|
+
mode: parseCiActExecutionMode(flags.mode),
|
|
46
52
|
containerArchitecture: flags.containerArchitecture,
|
|
47
53
|
platformImage: flags.platformImage,
|
|
48
54
|
eventPath: flags.eventPath,
|
|
49
55
|
execute: Boolean(flags.execute) && !flags.dryRun,
|
|
56
|
+
smoke: Boolean(flags.smoke),
|
|
50
57
|
timeoutMs: parseCiActTimeoutMs(flags.timeoutMs),
|
|
51
58
|
});
|
|
52
59
|
});
|
|
@@ -60,8 +67,8 @@ export function validateCiActCommand(..._legacyArgs) {
|
|
|
60
67
|
}
|
|
61
68
|
export async function runCiActCommand(options = {}, deps = {}) {
|
|
62
69
|
const cwd = deps.cwd ?? process.cwd();
|
|
63
|
-
const command = buildPublicCiActCommand({ ...options, cwd });
|
|
64
70
|
if (!options.execute) {
|
|
71
|
+
const command = buildPublicCiActCommand({ ...options, cwd });
|
|
65
72
|
const preview = sanitizePublicCiActArgv(command);
|
|
66
73
|
(deps.stdout ?? process.stdout).write(`${JSON.stringify({ command: preview.command, args: preview.args })}\n`);
|
|
67
74
|
return 0;
|
|
@@ -69,23 +76,34 @@ export async function runCiActCommand(options = {}, deps = {}) {
|
|
|
69
76
|
if (resolveCiActExecutionMode(options) === "replay") {
|
|
70
77
|
(deps.stderr ?? process.stderr).write("Warning: replay mode is a generated local approximation and is not security-equivalent to GitHub CI or OIDC.\n");
|
|
71
78
|
}
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
const prepared = preparePublicCiActExecution({ ...options, cwd });
|
|
80
|
+
try {
|
|
81
|
+
const secretProfile = resolveCiActSecretEnvProfile({ ...options, cwd }) ?? "preview";
|
|
82
|
+
const result = await (deps.run ?? runSecretGateCommand)({
|
|
83
|
+
cwd,
|
|
84
|
+
commandCwd: prepared.cwd,
|
|
85
|
+
sink: "act",
|
|
86
|
+
profile: secretProfile,
|
|
87
|
+
envProfile: options.envProfile ?? "secrets-only",
|
|
88
|
+
forceSecretGate: shouldForceCiActSecretGate(options.envProfile),
|
|
89
|
+
command: "act",
|
|
90
|
+
args: prepared.command.actArgs,
|
|
91
|
+
timeoutMs: normalizeCiActTimeoutMs(options.timeoutMs, { smoke: options.smoke }),
|
|
92
|
+
});
|
|
93
|
+
const stdout = redactText(result.stdout) ?? "";
|
|
94
|
+
const stderr = redactText(result.stderr) ?? "";
|
|
95
|
+
if (stdout)
|
|
96
|
+
(deps.stdout ?? process.stdout).write(stdout);
|
|
97
|
+
if (stderr)
|
|
98
|
+
(deps.stderr ?? process.stderr).write(stderr);
|
|
99
|
+
return result.exitCode;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
prepared.cleanup();
|
|
103
|
+
}
|
|
86
104
|
}
|
|
87
|
-
export function normalizeCiActTimeoutMs(value) {
|
|
88
|
-
const timeoutMs = value ?? DEFAULT_CI_ACT_TIMEOUT_MS;
|
|
105
|
+
export function normalizeCiActTimeoutMs(value, options = {}) {
|
|
106
|
+
const timeoutMs = value ?? (options.smoke ? SMOKE_CI_ACT_TIMEOUT_MS : DEFAULT_CI_ACT_TIMEOUT_MS);
|
|
89
107
|
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
|
|
90
108
|
throw new Error("--timeout-ms must be a positive integer");
|
|
91
109
|
}
|
|
@@ -100,7 +118,48 @@ export function parseCiActTimeoutMs(value) {
|
|
|
100
118
|
const parsed = typeof value === "number"
|
|
101
119
|
? value
|
|
102
120
|
: typeof value === "string"
|
|
103
|
-
?
|
|
121
|
+
? parseCiActTimeoutString(value)
|
|
104
122
|
: Number.NaN;
|
|
105
123
|
return normalizeCiActTimeoutMs(parsed);
|
|
106
124
|
}
|
|
125
|
+
export function parseCiActExecutionMode(value) {
|
|
126
|
+
if (value === undefined || value === null || value === "")
|
|
127
|
+
return undefined;
|
|
128
|
+
if (value === "direct" || value === "replay")
|
|
129
|
+
return value;
|
|
130
|
+
throw new Error('--mode must be "direct" or "replay"');
|
|
131
|
+
}
|
|
132
|
+
export function parseCiActEventName(value) {
|
|
133
|
+
if (value === undefined || value === null || value === "")
|
|
134
|
+
return undefined;
|
|
135
|
+
if (value === "pull_request" || value === "push" || value === "workflow_dispatch")
|
|
136
|
+
return value;
|
|
137
|
+
throw new Error('--event-name must be "pull_request", "push", or "workflow_dispatch"');
|
|
138
|
+
}
|
|
139
|
+
function parseCiActTimeoutString(value) {
|
|
140
|
+
const trimmed = value.trim();
|
|
141
|
+
if (!/^[1-9]\d*$/u.test(trimmed)) {
|
|
142
|
+
throw new Error("--timeout-ms must be a positive integer");
|
|
143
|
+
}
|
|
144
|
+
return Number(trimmed);
|
|
145
|
+
}
|
|
146
|
+
function parseCiActMatrixFlags(value) {
|
|
147
|
+
if (value === undefined)
|
|
148
|
+
return [];
|
|
149
|
+
if (typeof value === "string") {
|
|
150
|
+
if (value.trim().length === 0) {
|
|
151
|
+
throw new Error("--matrix must be provided as one or more key:value selectors");
|
|
152
|
+
}
|
|
153
|
+
return [value];
|
|
154
|
+
}
|
|
155
|
+
if (Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
|
|
156
|
+
if (value.some((entry) => entry.trim().length === 0)) {
|
|
157
|
+
throw new Error("--matrix must be provided as one or more key:value selectors");
|
|
158
|
+
}
|
|
159
|
+
return [...value];
|
|
160
|
+
}
|
|
161
|
+
if (value === true) {
|
|
162
|
+
throw new Error("--matrix must be provided as one or more key:value selectors");
|
|
163
|
+
}
|
|
164
|
+
throw new Error("--matrix must be provided as one or more key:value selectors");
|
|
165
|
+
}
|
|
@@ -247,22 +247,10 @@ export async function runCompile(options) {
|
|
|
247
247
|
message: `wp compile: rulesync exited with code ${exitCode}`,
|
|
248
248
|
};
|
|
249
249
|
}
|
|
250
|
-
// Step 4:
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const manifestOpts = {
|
|
255
|
-
agentDir,
|
|
256
|
-
outDir: cwd,
|
|
257
|
-
version: pkgVersion,
|
|
258
|
-
skills: skillNames,
|
|
259
|
-
commands: commandNames,
|
|
260
|
-
};
|
|
261
|
-
await Promise.all([
|
|
262
|
-
import("#compiler/manifests/claude").then((m) => m.emitManifest(manifestOpts)),
|
|
263
|
-
import("#compiler/manifests/codex").then((m) => m.emitManifest(manifestOpts)),
|
|
264
|
-
]);
|
|
265
|
-
// Step 5: Run mergeAgentsMd to produce AGENTS.md at repo root
|
|
250
|
+
// Step 4: Run mergeAgentsMd to produce AGENTS.md at repo root
|
|
251
|
+
// (Plugin manifests are hand-maintained SSOT under packages/*-plugin/;
|
|
252
|
+
// wp compile no longer emits them — golden tests + version stamping own
|
|
253
|
+
// that surface.)
|
|
266
254
|
const agentsLayers = collectAgentsLayers(agentDir);
|
|
267
255
|
if (agentsLayers.length > 0) {
|
|
268
256
|
const { mergeAgentsMd } = await import("#compiler/memory/merger");
|
|
@@ -278,11 +266,9 @@ export async function runCompile(options) {
|
|
|
278
266
|
writeFileSync(join(cwd, "AGENTS.md"), mergeResult.content);
|
|
279
267
|
}
|
|
280
268
|
}
|
|
281
|
-
// Step
|
|
269
|
+
// Step 5: Write .compile-manifest.json with content-hash sentinels
|
|
282
270
|
const outputHashes = {
|
|
283
271
|
"AGENTS.md": hashFile(join(cwd, "AGENTS.md")),
|
|
284
|
-
"packages/claude-plugin/.claude-plugin/plugin.json": hashFile(join(cwd, "packages", "claude-plugin", ".claude-plugin", "plugin.json")),
|
|
285
|
-
"packages/codex-plugin/.codex-plugin/plugin.json": hashFile(join(cwd, "packages", "codex-plugin", ".codex-plugin", "plugin.json")),
|
|
286
272
|
};
|
|
287
273
|
const compileManifest = {
|
|
288
274
|
version: COMPILE_MANIFEST_VERSION,
|
|
@@ -303,18 +289,6 @@ export async function runCompile(options) {
|
|
|
303
289
|
cleanup();
|
|
304
290
|
}
|
|
305
291
|
}
|
|
306
|
-
function readPackageVersion(cwd) {
|
|
307
|
-
const pkgPath = join(cwd, "package.json");
|
|
308
|
-
if (!existsSync(pkgPath))
|
|
309
|
-
return "0.0.0";
|
|
310
|
-
try {
|
|
311
|
-
const parsed = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
312
|
-
return typeof parsed.version === "string" ? parsed.version : "0.0.0";
|
|
313
|
-
}
|
|
314
|
-
catch {
|
|
315
|
-
return "0.0.0";
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
292
|
function collectAgentsLayers(agentDir) {
|
|
319
293
|
const agentsDir = join(agentDir, "agents");
|
|
320
294
|
if (!existsSync(agentsDir))
|
|
@@ -56,3 +56,4 @@ export type DeliveryStatusOptions = {
|
|
|
56
56
|
* prior values and expose a retryable adapter warning.
|
|
57
57
|
*/
|
|
58
58
|
export declare function collectDeliveryStatus(options?: DeliveryStatusOptions): Promise<DeliveryStatus>;
|
|
59
|
+
export declare function blueprintDocumentPath(cwd: string, state: string, slug: string): string | null;
|
|
@@ -107,14 +107,21 @@ function checkState(value) {
|
|
|
107
107
|
return "pending";
|
|
108
108
|
return states.length > 0 ? "passing" : "unknown";
|
|
109
109
|
}
|
|
110
|
+
export function blueprintDocumentPath(cwd, state, slug) {
|
|
111
|
+
const folder = join(cwd, "blueprints", state, slug, "_overview.md");
|
|
112
|
+
if (existsSync(folder))
|
|
113
|
+
return folder;
|
|
114
|
+
const flat = join(cwd, "blueprints", state, `${slug}.md`);
|
|
115
|
+
return existsSync(flat) ? flat : null;
|
|
116
|
+
}
|
|
110
117
|
function readBlueprintDelivery(cwd) {
|
|
111
118
|
const branch = run("git", ["branch", "--show-current"], cwd);
|
|
112
119
|
if (!branch?.startsWith("bp/"))
|
|
113
120
|
return null;
|
|
114
121
|
const slug = branch.slice(3);
|
|
115
122
|
for (const state of ["in-progress", "planned", "draft", "completed", "parked", "archived"]) {
|
|
116
|
-
const path =
|
|
117
|
-
if (!
|
|
123
|
+
const path = blueprintDocumentPath(cwd, state, slug);
|
|
124
|
+
if (!path)
|
|
118
125
|
continue;
|
|
119
126
|
const raw = readFileSync(path, "utf8");
|
|
120
127
|
return {
|
|
@@ -129,8 +136,8 @@ function readVerificationDelivery(cwd) {
|
|
|
129
136
|
const blueprint = readBlueprintDelivery(cwd);
|
|
130
137
|
if (!blueprint)
|
|
131
138
|
return null;
|
|
132
|
-
const path =
|
|
133
|
-
if (!
|
|
139
|
+
const path = blueprintDocumentPath(cwd, blueprint.state, blueprint.slug);
|
|
140
|
+
if (!path)
|
|
134
141
|
return null;
|
|
135
142
|
const raw = readFileSync(path, "utf8");
|
|
136
143
|
const evidenceCount = (raw.match(/^\*\*Verification:\*\*/gmu) ?? []).length;
|
|
@@ -27,6 +27,7 @@ const MENU_BINDINGS = [
|
|
|
27
27
|
{ keys: "x", label: "actions", footerPriority: 0 },
|
|
28
28
|
{ keys: "⇥/^s", label: "sessions" },
|
|
29
29
|
{ keys: "b", label: "blueprints" },
|
|
30
|
+
{ keys: "c", label: "chat" },
|
|
30
31
|
{ keys: "d/^o", label: "mode" },
|
|
31
32
|
{ keys: "^p", label: "palette", footerPriority: 1 },
|
|
32
33
|
{ keys: "?/^x", label: "help" },
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type DashPermissionMode, type DashProvider } from "#cli/commands/dash/provider-capabilities.js";
|
|
2
|
+
import { type ControlPlaneChatMode } from "#cli/commands/dash/tui/chat-mode.js";
|
|
2
3
|
export type LaunchPreferences = {
|
|
3
4
|
readonly version: number;
|
|
4
5
|
readonly yolo: boolean;
|
|
6
|
+
readonly chatMode?: ControlPlaneChatMode;
|
|
5
7
|
};
|
|
6
8
|
export type YoloPreferenceState = {
|
|
7
9
|
readonly enabled: boolean;
|
|
@@ -9,9 +11,22 @@ export type YoloPreferenceState = {
|
|
|
9
11
|
/** The preference file exists but could not be parsed (fails safe to off). */
|
|
10
12
|
readonly corrupt: boolean;
|
|
11
13
|
};
|
|
14
|
+
export type ChatModePreferenceState = {
|
|
15
|
+
readonly mode: ControlPlaneChatMode;
|
|
16
|
+
readonly persisted: boolean;
|
|
17
|
+
/** The preference file exists but could not be parsed (fails safe to host-pane). */
|
|
18
|
+
readonly corrupt: boolean;
|
|
19
|
+
};
|
|
12
20
|
export declare function readYoloPreferenceState(): YoloPreferenceState;
|
|
13
21
|
export declare function readYoloPreference(): boolean;
|
|
14
22
|
export declare function writeYoloPreference(enabled: boolean): void;
|
|
23
|
+
/**
|
|
24
|
+
* Read persisted control-plane chat mode. Missing, corrupt, or invalid values
|
|
25
|
+
* fail safe to host-pane (never open integrated-chat chrome from bad prefs).
|
|
26
|
+
*/
|
|
27
|
+
export declare function readChatModePreferenceState(): ChatModePreferenceState;
|
|
28
|
+
export declare function readChatModePreference(): ControlPlaneChatMode;
|
|
29
|
+
export declare function writeChatModePreference(mode: ControlPlaneChatMode): void;
|
|
15
30
|
/**
|
|
16
31
|
* Precedence: explicit `--wp-permission-mode` > provider-native permission flags
|
|
17
32
|
* already in args > persisted yolo (true → 'dangerous') > 'safe'. When `provider`
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// User-scope persistence for
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// corrupt/missing read fails safe (yolo off).
|
|
1
|
+
// User-scope persistence for personal dash launch preferences (yolo + chat mode).
|
|
2
|
+
// Deliberately NOT the tracked .webpressorc.json — a repo file would let one
|
|
3
|
+
// contributor flip teammates into bypass via git pull. The file lives under the
|
|
4
|
+
// env-paths state root; corrupt/missing reads fail safe (yolo off, host-pane).
|
|
6
5
|
import { randomUUID } from "node:crypto";
|
|
7
6
|
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
8
7
|
import { dirname, join } from "node:path";
|
|
9
8
|
import { hasProviderNativePermissionFlag, parseDashPermissionMode, } from "#cli/commands/dash/provider-capabilities.js";
|
|
9
|
+
import { DEFAULT_CONTROL_PLANE_CHAT_MODE, isControlPlaneChatMode, } from "#cli/commands/dash/tui/chat-mode.js";
|
|
10
10
|
import { getStateRoot } from "#paths/state-root.js";
|
|
11
11
|
const LAUNCH_PREFERENCES_FILENAME = "launch-preferences.json";
|
|
12
12
|
const LAUNCH_PREFERENCES_VERSION = 1;
|
|
@@ -31,6 +31,23 @@ function readRawPreferences() {
|
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
/** Atomic read-merge-write so unknown fields survive partial updates. */
|
|
35
|
+
function writePreferencesPatch(patch) {
|
|
36
|
+
const path = launchPreferencesPath();
|
|
37
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
38
|
+
// A corrupt existing file is discarded (readRawPreferences → null).
|
|
39
|
+
const existing = readRawPreferences() ?? {};
|
|
40
|
+
const payload = { ...existing, version: LAUNCH_PREFERENCES_VERSION, ...patch };
|
|
41
|
+
const tmpPath = `${path}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;
|
|
42
|
+
try {
|
|
43
|
+
writeFileSync(tmpPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
44
|
+
renameSync(tmpPath, path);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
rmSync(tmpPath, { force: true });
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
34
51
|
export function readYoloPreferenceState() {
|
|
35
52
|
const path = launchPreferencesPath();
|
|
36
53
|
if (!existsSync(path))
|
|
@@ -44,21 +61,33 @@ export function readYoloPreference() {
|
|
|
44
61
|
return readYoloPreferenceState().enabled;
|
|
45
62
|
}
|
|
46
63
|
export function writeYoloPreference(enabled) {
|
|
64
|
+
writePreferencesPatch({ yolo: enabled });
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Read persisted control-plane chat mode. Missing, corrupt, or invalid values
|
|
68
|
+
* fail safe to host-pane (never open integrated-chat chrome from bad prefs).
|
|
69
|
+
*/
|
|
70
|
+
export function readChatModePreferenceState() {
|
|
47
71
|
const path = launchPreferencesPath();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// wp's toggle. A corrupt existing file is discarded (readRawPreferences → null).
|
|
51
|
-
const existing = readRawPreferences() ?? {};
|
|
52
|
-
const payload = { ...existing, version: LAUNCH_PREFERENCES_VERSION, yolo: enabled };
|
|
53
|
-
const tmpPath = `${path}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;
|
|
54
|
-
try {
|
|
55
|
-
writeFileSync(tmpPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
56
|
-
renameSync(tmpPath, path);
|
|
72
|
+
if (!existsSync(path)) {
|
|
73
|
+
return { mode: DEFAULT_CONTROL_PLANE_CHAT_MODE, persisted: false, corrupt: false };
|
|
57
74
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
75
|
+
const raw = readRawPreferences();
|
|
76
|
+
if (raw === null) {
|
|
77
|
+
return { mode: DEFAULT_CONTROL_PLANE_CHAT_MODE, persisted: false, corrupt: true };
|
|
61
78
|
}
|
|
79
|
+
const value = raw.chatMode;
|
|
80
|
+
if (typeof value === "string" && isControlPlaneChatMode(value)) {
|
|
81
|
+
return { mode: value, persisted: true, corrupt: false };
|
|
82
|
+
}
|
|
83
|
+
// File present but chatMode absent or invalid — not corrupt JSON.
|
|
84
|
+
return { mode: DEFAULT_CONTROL_PLANE_CHAT_MODE, persisted: true, corrupt: false };
|
|
85
|
+
}
|
|
86
|
+
export function readChatModePreference() {
|
|
87
|
+
return readChatModePreferenceState().mode;
|
|
88
|
+
}
|
|
89
|
+
export function writeChatModePreference(mode) {
|
|
90
|
+
writePreferencesPatch({ chatMode: mode });
|
|
62
91
|
}
|
|
63
92
|
/**
|
|
64
93
|
* Precedence: explicit `--wp-permission-mode` > provider-native permission flags
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared plan-once run label contract.
|
|
3
|
+
* Exact equality is SSOT for membership ↔ registry join; keep one helper.
|
|
4
|
+
*/
|
|
5
|
+
import type { PlanOnceHostEntry } from "#cli/commands/dash/plan-once-schema.js";
|
|
6
|
+
/** Durable run label: `plan-once:<planId>:<label|host>`. */
|
|
7
|
+
export declare function planOnceRunLabel(planId: string, host: PlanOnceHostEntry): string;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type MultiHostPlanProposal } from "#cli/commands/dash/plan-once-schema.js";
|
|
3
|
+
export declare const PLAN_MEMBERSHIP_SCHEMA_VERSION: 1;
|
|
4
|
+
export declare const planMembershipHostSchema: z.ZodObject<{
|
|
5
|
+
host: z.ZodEnum<{
|
|
6
|
+
claude: "claude";
|
|
7
|
+
codex: "codex";
|
|
8
|
+
grok: "grok";
|
|
9
|
+
opencode: "opencode";
|
|
10
|
+
}>;
|
|
11
|
+
workdir: z.ZodString;
|
|
12
|
+
label: z.ZodString;
|
|
13
|
+
}, z.core.$strict>;
|
|
14
|
+
export type PlanMembershipHost = z.infer<typeof planMembershipHostSchema>;
|
|
15
|
+
export declare const planMembershipSchema: z.ZodObject<{
|
|
16
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
17
|
+
planId: z.ZodString;
|
|
18
|
+
hosts: z.ZodArray<z.ZodObject<{
|
|
19
|
+
host: z.ZodEnum<{
|
|
20
|
+
claude: "claude";
|
|
21
|
+
codex: "codex";
|
|
22
|
+
grok: "grok";
|
|
23
|
+
opencode: "opencode";
|
|
24
|
+
}>;
|
|
25
|
+
workdir: z.ZodString;
|
|
26
|
+
label: z.ZodString;
|
|
27
|
+
}, z.core.$strict>>;
|
|
28
|
+
confirmedAt: z.ZodString;
|
|
29
|
+
}, z.core.$strict>;
|
|
30
|
+
export type PlanMembership = z.infer<typeof planMembershipSchema>;
|
|
31
|
+
export declare const planMembershipStoreSchema: z.ZodObject<{
|
|
32
|
+
version: z.ZodLiteral<1>;
|
|
33
|
+
plans: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
34
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
35
|
+
planId: z.ZodString;
|
|
36
|
+
hosts: z.ZodArray<z.ZodObject<{
|
|
37
|
+
host: z.ZodEnum<{
|
|
38
|
+
claude: "claude";
|
|
39
|
+
codex: "codex";
|
|
40
|
+
grok: "grok";
|
|
41
|
+
opencode: "opencode";
|
|
42
|
+
}>;
|
|
43
|
+
workdir: z.ZodString;
|
|
44
|
+
label: z.ZodString;
|
|
45
|
+
}, z.core.$strict>>;
|
|
46
|
+
confirmedAt: z.ZodString;
|
|
47
|
+
}, z.core.$strict>>;
|
|
48
|
+
}, z.core.$strict>;
|
|
49
|
+
export type PlanMembershipStore = z.infer<typeof planMembershipStoreSchema>;
|
|
50
|
+
/** Pure: build immutable membership from a confirmed multi-host plan. */
|
|
51
|
+
export declare function buildPlanMembership(plan: MultiHostPlanProposal, confirmedAt?: string): PlanMembership;
|
|
52
|
+
/** Persist membership for a planId (idempotent overwrite for same planId). */
|
|
53
|
+
export declare function writePlanMembership(membership: PlanMembership, options?: {
|
|
54
|
+
readonly cwd?: string;
|
|
55
|
+
}): Promise<PlanMembership>;
|
|
56
|
+
/** Read membership for planId, or null if absent. */
|
|
57
|
+
export declare function readPlanMembership(planId: string, options?: {
|
|
58
|
+
readonly cwd?: string;
|
|
59
|
+
}): Promise<PlanMembership | null>;
|
|
60
|
+
/** List all durable plan memberships (operator / merge projection scan). */
|
|
61
|
+
export declare function listPlanMemberships(options?: {
|
|
62
|
+
readonly cwd?: string;
|
|
63
|
+
}): Promise<readonly PlanMembership[]>;
|
|
64
|
+
/** Test helper: clear membership store file content via rewrite empty. */
|
|
65
|
+
export declare function clearPlanMembershipStoreForTests(options: {
|
|
66
|
+
readonly cwd?: string;
|
|
67
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable plan-once membership (expected host set for a planId).
|
|
3
|
+
*
|
|
4
|
+
* Labels alone are not N-of-N SSOT: a host that never creates a run disappears
|
|
5
|
+
* from registry-only views. Membership is written on confirm (not cancel) and
|
|
6
|
+
* is a plan-record sidecar — not a second run-registry.
|
|
7
|
+
*/
|
|
8
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
10
|
+
import { dirname } from "node:path";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { planOnceRunLabel } from "#cli/commands/dash/plan-once-label.js";
|
|
13
|
+
import { planOnceHostSchema, } from "#cli/commands/dash/plan-once-schema.js";
|
|
14
|
+
import { getSurfacePathAsync, withLock } from "#paths/state-root.js";
|
|
15
|
+
import { writeJsonFileAtomic } from "#shared-utils/write-json-file.js";
|
|
16
|
+
export const PLAN_MEMBERSHIP_SCHEMA_VERSION = 1;
|
|
17
|
+
const MEMBERSHIP_SURFACE = "dash/plan-once-memberships.json";
|
|
18
|
+
export const planMembershipHostSchema = z
|
|
19
|
+
.object({
|
|
20
|
+
host: planOnceHostSchema,
|
|
21
|
+
workdir: z.string().min(1),
|
|
22
|
+
/** Expected run label: plan-once:<planId>:<label|host> */
|
|
23
|
+
label: z.string().min(1),
|
|
24
|
+
})
|
|
25
|
+
.strict();
|
|
26
|
+
export const planMembershipSchema = z
|
|
27
|
+
.object({
|
|
28
|
+
schemaVersion: z.literal(PLAN_MEMBERSHIP_SCHEMA_VERSION),
|
|
29
|
+
planId: z.string().uuid(),
|
|
30
|
+
hosts: z.array(planMembershipHostSchema).min(1),
|
|
31
|
+
confirmedAt: z.string().datetime(),
|
|
32
|
+
})
|
|
33
|
+
.strict();
|
|
34
|
+
export const planMembershipStoreSchema = z
|
|
35
|
+
.object({
|
|
36
|
+
version: z.literal(1),
|
|
37
|
+
plans: z.record(z.string(), planMembershipSchema),
|
|
38
|
+
})
|
|
39
|
+
.strict();
|
|
40
|
+
function emptyStore() {
|
|
41
|
+
return { version: 1, plans: {} };
|
|
42
|
+
}
|
|
43
|
+
/** Pure: build immutable membership from a confirmed multi-host plan. */
|
|
44
|
+
export function buildPlanMembership(plan, confirmedAt = new Date().toISOString()) {
|
|
45
|
+
const hosts = plan.hosts.map((entry) => ({
|
|
46
|
+
host: entry.host,
|
|
47
|
+
workdir: entry.workdir,
|
|
48
|
+
label: planOnceRunLabel(plan.planId, entry),
|
|
49
|
+
}));
|
|
50
|
+
return planMembershipSchema.parse({
|
|
51
|
+
schemaVersion: PLAN_MEMBERSHIP_SCHEMA_VERSION,
|
|
52
|
+
planId: plan.planId,
|
|
53
|
+
hosts,
|
|
54
|
+
confirmedAt,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async function membershipPath(cwd) {
|
|
58
|
+
return getSurfacePathAsync(MEMBERSHIP_SURFACE, "repo", cwd);
|
|
59
|
+
}
|
|
60
|
+
function corruptCopyPath(path) {
|
|
61
|
+
return `${path}.corrupt-${new Date().toISOString().replaceAll(":", "-")}-${randomUUID()}`;
|
|
62
|
+
}
|
|
63
|
+
function preserveStore(path) {
|
|
64
|
+
if (!existsSync(path))
|
|
65
|
+
return undefined;
|
|
66
|
+
const preservedPath = corruptCopyPath(path);
|
|
67
|
+
try {
|
|
68
|
+
copyFileSync(path, preservedPath);
|
|
69
|
+
return preservedPath;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Read membership store. Missing file → empty (ok).
|
|
77
|
+
* Corrupt/unreadable file → ok:false with quarantine path; never treat as empty
|
|
78
|
+
* for write merge (would wipe sibling plan memberships).
|
|
79
|
+
*/
|
|
80
|
+
function readStoreFromPath(path) {
|
|
81
|
+
if (!existsSync(path))
|
|
82
|
+
return { ok: true, store: emptyStore() };
|
|
83
|
+
try {
|
|
84
|
+
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
85
|
+
const parsed = planMembershipStoreSchema.safeParse(raw);
|
|
86
|
+
if (parsed.success)
|
|
87
|
+
return { ok: true, store: parsed.data };
|
|
88
|
+
const preservedPath = preserveStore(path);
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
reason: "plan membership store failed schema validation",
|
|
92
|
+
...(preservedPath ? { preservedPath } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
const preservedPath = preserveStore(path);
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
reason: error instanceof Error ? error.message : "plan membership store unreadable",
|
|
100
|
+
...(preservedPath ? { preservedPath } : {}),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function storeForRead(path) {
|
|
105
|
+
const read = readStoreFromPath(path);
|
|
106
|
+
// Projection reads fail closed to empty (no memberships) without wiping disk.
|
|
107
|
+
return read.ok ? read.store : emptyStore();
|
|
108
|
+
}
|
|
109
|
+
/** Persist membership for a planId (idempotent overwrite for same planId). */
|
|
110
|
+
export async function writePlanMembership(membership, options = {}) {
|
|
111
|
+
const validated = planMembershipSchema.parse(membership);
|
|
112
|
+
const path = await membershipPath(options.cwd);
|
|
113
|
+
return withLock("repo", () => {
|
|
114
|
+
const read = readStoreFromPath(path);
|
|
115
|
+
if (!read.ok) {
|
|
116
|
+
const preserved = read.preservedPath ? ` (preserved ${read.preservedPath})` : "";
|
|
117
|
+
throw new Error(`Refusing to write plan membership: store corrupt — ${read.reason}${preserved}`);
|
|
118
|
+
}
|
|
119
|
+
const next = {
|
|
120
|
+
version: 1,
|
|
121
|
+
plans: { ...read.store.plans, [validated.planId]: validated },
|
|
122
|
+
};
|
|
123
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
124
|
+
writeJsonFileAtomic(path, planMembershipStoreSchema.parse(next));
|
|
125
|
+
return validated;
|
|
126
|
+
}, options.cwd);
|
|
127
|
+
}
|
|
128
|
+
/** Read membership for planId, or null if absent. */
|
|
129
|
+
export async function readPlanMembership(planId, options = {}) {
|
|
130
|
+
const path = await membershipPath(options.cwd);
|
|
131
|
+
return withLock("repo", () => {
|
|
132
|
+
const store = storeForRead(path);
|
|
133
|
+
return store.plans[planId] ?? null;
|
|
134
|
+
}, options.cwd);
|
|
135
|
+
}
|
|
136
|
+
/** List all durable plan memberships (operator / merge projection scan). */
|
|
137
|
+
export async function listPlanMemberships(options = {}) {
|
|
138
|
+
const path = await membershipPath(options.cwd);
|
|
139
|
+
return withLock("repo", () => {
|
|
140
|
+
const store = storeForRead(path);
|
|
141
|
+
return Object.values(store.plans);
|
|
142
|
+
}, options.cwd);
|
|
143
|
+
}
|
|
144
|
+
/** Test helper: clear membership store file content via rewrite empty. */
|
|
145
|
+
export async function clearPlanMembershipStoreForTests(options) {
|
|
146
|
+
const path = await membershipPath(options.cwd);
|
|
147
|
+
await withLock("repo", () => {
|
|
148
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
149
|
+
writeJsonFileAtomic(path, emptyStore());
|
|
150
|
+
}, options.cwd);
|
|
151
|
+
}
|