@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
|
@@ -24,9 +24,9 @@ import { getBlueprintDocumentPaths } from "#utils/document-paths.js";
|
|
|
24
24
|
import { resolveBlueprintRoot } from "#utils/blueprint-root.js";
|
|
25
25
|
import { reIngestProjection } from "#projection-ready.js";
|
|
26
26
|
import { assertAllTasksHaveCanonicalPassingEvidence } from "#verification.js";
|
|
27
|
-
import {
|
|
27
|
+
import { assertPromotionTrustProofCurrent, preparePromotionTrustGate, } from "#trust/promotion.js";
|
|
28
28
|
import matter from "gray-matter";
|
|
29
|
-
import { evaluateApprovalGate, formatApprovalGateRequirement } from "#lifecycle/audit";
|
|
29
|
+
import { assertCompletedApprovalGate, evaluateApprovalGate, formatApprovalGateRequirement, } from "#lifecycle/audit";
|
|
30
30
|
/**
|
|
31
31
|
* Module-level factory. `null` = use the production default (loadSyncCredentials
|
|
32
32
|
* from auth.ts + BlueprintSyncClient + ReplicaManager — lazy-imported so that
|
|
@@ -161,6 +161,31 @@ async function reIngestDb(cwd) {
|
|
|
161
161
|
return;
|
|
162
162
|
await reIngestProjection(cwd);
|
|
163
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Force reingest of one blueprint document even when the stored content hash
|
|
166
|
+
* still matches. Used on complete so task-table lag cannot block finalize.
|
|
167
|
+
*/
|
|
168
|
+
async function forceReIngestBlueprint(cwd, slug, documentPath) {
|
|
169
|
+
const target = dbPath(cwd);
|
|
170
|
+
if (!existsSync(target))
|
|
171
|
+
return;
|
|
172
|
+
try {
|
|
173
|
+
const conn = openDb(target);
|
|
174
|
+
try {
|
|
175
|
+
// Invalidate hash so ingestAll's skip-if-unchanged path rewrites tasks.
|
|
176
|
+
conn.db.prepare(`UPDATE blueprints SET content_hash = NULL WHERE slug = ?`).run(slug);
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
conn.close();
|
|
180
|
+
}
|
|
181
|
+
await reIngestProjection(cwd);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Projection is best-effort for complete; markdown gate already passed.
|
|
185
|
+
// Swallow so a broken local projection cannot block lifecycle completion.
|
|
186
|
+
void documentPath;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
164
189
|
/**
|
|
165
190
|
* Update `status:` in YAML frontmatter. Preserves everything else verbatim.
|
|
166
191
|
*/
|
|
@@ -296,19 +321,38 @@ async function advanceTaskLocked(cwd, blueprintSlug, taskId, toStatus) {
|
|
|
296
321
|
* - Re-ingests into DB
|
|
297
322
|
*/
|
|
298
323
|
export async function promoteBlueprint(cwd, slug, toState) {
|
|
324
|
+
const adapter = await resolveSyncAdapterForCli(cwd);
|
|
325
|
+
// Pull platform state under the mutation lock, then release it before any
|
|
326
|
+
// Trust Dossier command spawns a child `wp`. Child startup/ingestion can
|
|
327
|
+
// legitimately need the same repo-scoped lock.
|
|
328
|
+
await withMarkdownWriteLock(cwd, () => runCliPlatformMutationSync(adapter, {
|
|
329
|
+
label: "wp_blueprint_promote",
|
|
330
|
+
ensureFreshSlug: slug,
|
|
331
|
+
}));
|
|
332
|
+
const found = findBlueprintDocument(resolveBlueprintRoot(cwd), slug);
|
|
333
|
+
if (!found) {
|
|
334
|
+
throw new Error(`Blueprint "${slug}" not found in any state directory under ${resolveBlueprintRoot(cwd)}`);
|
|
335
|
+
}
|
|
336
|
+
const crossesDraftApprovalBoundary = found.state === "draft" && (toState === "planned" || toState === "in-progress");
|
|
337
|
+
const trustProof = crossesDraftApprovalBoundary
|
|
338
|
+
? preparePromotionTrustGate({
|
|
339
|
+
repoRoot: cwd,
|
|
340
|
+
file: found.documentPath,
|
|
341
|
+
markdown: readFileSync(found.documentPath, "utf8"),
|
|
342
|
+
})
|
|
343
|
+
: null;
|
|
299
344
|
// F9/R7: cross-worktree markdown writes serialize via the repo-scoped lock.
|
|
300
|
-
|
|
345
|
+
// The proof is revalidated inside this lock before any lifecycle write.
|
|
346
|
+
return withMarkdownWriteLock(cwd, () => promoteBlueprintLocked(cwd, slug, toState, adapter, trustProof));
|
|
301
347
|
}
|
|
302
|
-
async function promoteBlueprintLocked(cwd, slug, toState) {
|
|
348
|
+
async function promoteBlueprintLocked(cwd, slug, toState, adapter, trustProof) {
|
|
303
349
|
const blueprintRoot = resolveBlueprintRoot(cwd);
|
|
304
350
|
const found = findBlueprintDocument(blueprintRoot, slug);
|
|
305
351
|
if (!found) {
|
|
306
352
|
throw new Error(`Blueprint "${slug}" not found in any state directory under ${blueprintRoot}`);
|
|
307
353
|
}
|
|
308
354
|
const { dir: currentDir, documentPath: currentDocumentPath, shape, state: currentState } = found;
|
|
309
|
-
|
|
310
|
-
if (toState === "completed") {
|
|
311
|
-
const markdown = readFileSync(currentDocumentPath, "utf8");
|
|
355
|
+
const assertCompletionReady = (markdown) => {
|
|
312
356
|
const blueprint = parseBlueprint(markdown, slug);
|
|
313
357
|
if (blueprint.tasks.length === 0) {
|
|
314
358
|
throw new Error(`Cannot promote "${slug}" to completed: zero-task blueprints cannot complete through the public lifecycle surface`);
|
|
@@ -319,43 +363,30 @@ async function promoteBlueprintLocked(cwd, slug, toState) {
|
|
|
319
363
|
throw new Error(`Cannot promote "${slug}" to completed: the following tasks are not done/dropped: ${list}`);
|
|
320
364
|
}
|
|
321
365
|
assertAllTasksHaveCanonicalPassingEvidence(markdown, blueprint.tasks.filter((task) => task.status === "done").map((task) => task.id));
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
openTasks = conn.db
|
|
328
|
-
.prepare(`SELECT task_id, status FROM tasks WHERE blueprint_slug = ? AND status NOT IN ('done', 'dropped')`)
|
|
329
|
-
.all(slug);
|
|
330
|
-
}
|
|
331
|
-
finally {
|
|
332
|
-
conn.close();
|
|
333
|
-
}
|
|
334
|
-
if (openTasks.length > 0) {
|
|
335
|
-
const list = openTasks.map((t) => `${t.task_id} (${t.status})`).join(", ");
|
|
336
|
-
throw new Error(`Cannot promote "${slug}" to completed: the following tasks are not done: ${list}`);
|
|
337
|
-
}
|
|
366
|
+
// Completion parity with CI: the CLI completion owner uses the same
|
|
367
|
+
// audit-owned gate as the MCP funnel and execution engine, so all normal
|
|
368
|
+
// paths into `completed` enforce the same plan-purpose approval.
|
|
369
|
+
try {
|
|
370
|
+
assertCompletedApprovalGate(currentDocumentPath, markdown);
|
|
338
371
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const adapter = await resolveSyncAdapterForCli(cwd);
|
|
344
|
-
await runCliPlatformMutationSync(adapter, {
|
|
345
|
-
label: "wp_blueprint_promote",
|
|
346
|
-
ensureFreshSlug: slug,
|
|
347
|
-
});
|
|
372
|
+
catch (error) {
|
|
373
|
+
throw new Error(`Cannot complete "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
348
376
|
// Trust must be proven before any platform status_changed event is published.
|
|
349
377
|
let content = readFileSync(currentDocumentPath, "utf8");
|
|
350
378
|
let trustedSource = content;
|
|
379
|
+
if (toState === "completed") {
|
|
380
|
+
assertCompletionReady(content);
|
|
381
|
+
}
|
|
351
382
|
const crossesDraftApprovalBoundary = currentState === "draft" && (toState === "planned" || toState === "in-progress");
|
|
352
383
|
if (crossesDraftApprovalBoundary) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
trustedSource =
|
|
384
|
+
if (trustProof === null) {
|
|
385
|
+
throw new Error("Blueprint trust gate invalidated: no external gate proof is available");
|
|
386
|
+
}
|
|
387
|
+
assertPromotionTrustProofCurrent({ repoRoot: cwd, file: currentDocumentPath, markdown: content }, trustProof);
|
|
388
|
+
content = trustProof.trustedMarkdown;
|
|
389
|
+
trustedSource = trustProof.sourceMarkdown;
|
|
359
390
|
// Governance Piece 1 — HARD gate at the promotion boundary. One
|
|
360
391
|
// provenance-backed Claude/Codex/Grok or OpenCode-Go model approval can
|
|
361
392
|
// promote. Check AFTER the trust gate so trust failures surface first.
|
|
@@ -385,18 +416,23 @@ async function promoteBlueprintLocked(cwd, slug, toState) {
|
|
|
385
416
|
if (crossesDraftApprovalBoundary) {
|
|
386
417
|
const refreshedSource = readFileSync(currentDocumentPath, "utf8");
|
|
387
418
|
if (refreshedSource !== trustedSource) {
|
|
388
|
-
|
|
389
|
-
repoRoot: cwd,
|
|
390
|
-
file: currentDocumentPath,
|
|
391
|
-
markdown: refreshedSource,
|
|
392
|
-
});
|
|
393
|
-
const approvalEvaluation = evaluateApprovalGate(currentDocumentPath, matter(content).data.approvals);
|
|
394
|
-
if (!approvalEvaluation.satisfied) {
|
|
395
|
-
throw new Error(`Cannot promote "${slug}" to ${toState}: frontmatter \`approvals:\` does not satisfy the promotion reviewer mix (${formatApprovalGateRequirement(approvalEvaluation)}). Record approvals, commit the matching review ledger (e.g. reviews.md), and include tracked review transcript/artifact files referenced by each structured review entry — see catalog/agent/rules/pre-implementation.md.`);
|
|
396
|
-
}
|
|
419
|
+
throw new Error(`Cannot promote "${slug}" to ${toState}: blueprint changed after external trust gates ran; retry promotion`);
|
|
397
420
|
}
|
|
421
|
+
assertPromotionTrustProofCurrent({ repoRoot: cwd, file: currentDocumentPath, markdown: refreshedSource }, trustProof);
|
|
422
|
+
}
|
|
423
|
+
if (toState === "completed") {
|
|
424
|
+
// The platform pull can replace the document after the first completion
|
|
425
|
+
// check. Re-read and re-assert against the exact content written below.
|
|
426
|
+
content = readFileSync(currentDocumentPath, "utf8");
|
|
427
|
+
assertCompletionReady(content);
|
|
398
428
|
}
|
|
399
429
|
}
|
|
430
|
+
if (toState === "completed") {
|
|
431
|
+
// Best-effort projection refresh. Clear content hash first so a lagging
|
|
432
|
+
// tasks table is rewritten even when a prior corrupt UPDATE left the
|
|
433
|
+
// stored hash equal to current markdown.
|
|
434
|
+
await forceReIngestBlueprint(cwd, slug, currentDocumentPath);
|
|
435
|
+
}
|
|
400
436
|
// Always update local markdown + SQLite.
|
|
401
437
|
// Platform-first: these become derived artifacts; disabled: these are canonical.
|
|
402
438
|
// Update frontmatter in the current location first, then move
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BlueprintAuditResult, BlueprintSummary } from "#local";
|
|
2
2
|
import type { BlueprintTemplateEntry } from "#sync/types.js";
|
|
3
|
-
import type { AdvanceTaskResult, BlueprintCommandOptions, BlueprintLifecycleMutationResult, CreateBlueprintResult, ExportBlueprintResult, ExecuteBlueprintResult, MoveBlueprintResult, PromoteBlueprintResult, ShowBlueprintResult } from "./router.js";
|
|
3
|
+
import type { AdvanceTaskResult, BlueprintCommandOptions, BlueprintCanonicalizeResult, BlueprintLifecycleMutationResult, CreateBlueprintResult, ExportBlueprintResult, ExecuteBlueprintResult, MoveBlueprintResult, PromoteBlueprintResult, ShowBlueprintResult } from "./router.js";
|
|
4
4
|
/**
|
|
5
5
|
* Override the platform template fetcher — for tests only.
|
|
6
6
|
* Pass `null` to restore the production default.
|
|
@@ -21,6 +21,7 @@ export declare class BlueprintAuditFailedError extends Error {
|
|
|
21
21
|
interface BlueprintCommandDependencies {
|
|
22
22
|
advanceBlueprintTask: (slug: string, taskId: string, toStatus: string, options: BlueprintCommandOptions) => Promise<AdvanceTaskResult>;
|
|
23
23
|
auditBlueprints: (options: BlueprintCommandOptions) => Promise<BlueprintAuditResult>;
|
|
24
|
+
canonicalizeBlueprintBySlug: (slug: string, options: BlueprintCommandOptions) => Promise<BlueprintCanonicalizeResult>;
|
|
24
25
|
controlBlueprintExec: (action: "status" | "resume" | "stop", slug: string, options: BlueprintCommandOptions) => Promise<ExecuteBlueprintResult>;
|
|
25
26
|
readBlueprintExecutionLogs: (slug: string, options: BlueprintCommandOptions) => Promise<ExecuteBlueprintResult>;
|
|
26
27
|
createBlueprint: (goal: string, options: BlueprintCommandOptions) => Promise<CreateBlueprintResult>;
|
|
@@ -3,7 +3,9 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { executeBlueprintDbSubcommand } from "./db-commands.js";
|
|
6
|
+
import { getBlueprintSubcommandNames } from "./router-output.js";
|
|
6
7
|
import { listTemplates, resolveTemplate } from "./template-resolver.js";
|
|
8
|
+
import { TRUST_DOSSIER_SCAFFOLD } from "#trust/scaffold.js";
|
|
7
9
|
// ---------------------------------------------------------------------------
|
|
8
10
|
// Platform template fetcher (injectable for tests)
|
|
9
11
|
// ---------------------------------------------------------------------------
|
|
@@ -232,6 +234,15 @@ export async function executeBlueprintSubcommand(subcommand, args, options, deps
|
|
|
232
234
|
deps.printBlueprintOutput(options.json ? result : result.message, options.json);
|
|
233
235
|
return;
|
|
234
236
|
}
|
|
237
|
+
case "canonicalize": {
|
|
238
|
+
const slug = args[0];
|
|
239
|
+
if (!slug) {
|
|
240
|
+
throw new Error("Usage: wp blueprint canonicalize <slug>");
|
|
241
|
+
}
|
|
242
|
+
const result = await deps.canonicalizeBlueprintBySlug(slug, options);
|
|
243
|
+
deps.printBlueprintOutput(options.json ? { from: result.from, to: result.to, moved: result.moved } : result.message, options.json);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
235
246
|
case "start": {
|
|
236
247
|
const slug = args[0];
|
|
237
248
|
if (!slug) {
|
|
@@ -350,8 +361,16 @@ export async function executeBlueprintSubcommand(subcommand, args, options, deps
|
|
|
350
361
|
deps.printBlueprintOutput(options.json ? result : result.message, options.json);
|
|
351
362
|
return;
|
|
352
363
|
}
|
|
364
|
+
case "trust-dossier": {
|
|
365
|
+
// Read-only: prints an already-valid "## Trust Dossier" starter block
|
|
366
|
+
// (src/blueprint/trust/scaffold.ts). No file writes, no worktree/lock
|
|
367
|
+
// interaction — an author pastes the output into their overview and
|
|
368
|
+
// edits the example values.
|
|
369
|
+
deps.printBlueprintOutput(options.json ? { markdown: TRUST_DOSSIER_SCAFFOLD } : TRUST_DOSSIER_SCAFFOLD, options.json);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
353
372
|
default: {
|
|
354
|
-
throw new Error(`Unknown blueprint subcommand: ${subcommand}\n\nUse one of:
|
|
373
|
+
throw new Error(`Unknown blueprint subcommand: ${subcommand}\n\nUse one of: ${getBlueprintSubcommandNames().join(", ")}`);
|
|
355
374
|
}
|
|
356
375
|
}
|
|
357
376
|
}
|
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
import type { Blueprint, BlueprintAuditResult, BlueprintSummary } from "#local";
|
|
2
2
|
import type { CreateBlueprintResult, ExecuteBlueprintResult, ShowBlueprintResult } from "./router.js";
|
|
3
|
+
/**
|
|
4
|
+
* Canonical registry of every subcommand `router-dispatch.ts` actually
|
|
5
|
+
* dispatches. This is the single source of truth for both the `--help`
|
|
6
|
+
* `Commands:` block (see `BLUEPRINT_HELP` below) and the unknown-subcommand
|
|
7
|
+
* error list — so a subcommand can't ship dispatched-but-undocumented
|
|
8
|
+
* again. `router-dispatch.test.ts` asserts this list stays equal to the
|
|
9
|
+
* live `case "…":` labels in the dispatch switch.
|
|
10
|
+
*/
|
|
11
|
+
export interface BlueprintSubcommandSpec {
|
|
12
|
+
/** Matches a `case "<name>":` label in router-dispatch.ts exactly. */
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/** One or more `Commands:` lines (without the leading indent). */
|
|
15
|
+
readonly usage: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export declare const BLUEPRINT_SUBCOMMANDS: readonly BlueprintSubcommandSpec[];
|
|
3
18
|
export declare function formatTaskLine(task: Blueprint["tasks"][number]): string;
|
|
4
19
|
export declare function getBlueprintHelpText(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Subcommand names in registry order, for the unknown-subcommand error
|
|
22
|
+
* message. Kept as a function (rather than exporting a derived constant)
|
|
23
|
+
* so the source of truth stays singular: `BLUEPRINT_SUBCOMMANDS`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getBlueprintSubcommandNames(): readonly string[];
|
|
5
26
|
export interface BlueprintInventorySummary {
|
|
6
27
|
total: number;
|
|
7
28
|
byStatus: Record<string, number>;
|
|
@@ -1,25 +1,48 @@
|
|
|
1
1
|
import { buildRoadmapModel, planStatusSchema } from "#local";
|
|
2
|
+
export const BLUEPRINT_SUBCOMMANDS = [
|
|
3
|
+
{ name: "list", usage: ["list [status]"] },
|
|
4
|
+
{
|
|
5
|
+
name: "new",
|
|
6
|
+
usage: ["new <goal> --complexity <XS|S|M|L|XL> [--type <blueprint|parent-roadmap>]"],
|
|
7
|
+
},
|
|
8
|
+
{ name: "show", usage: ["show <slug>"] },
|
|
9
|
+
{
|
|
10
|
+
name: "exec",
|
|
11
|
+
usage: [
|
|
12
|
+
"exec <slug>",
|
|
13
|
+
"exec status <slug>",
|
|
14
|
+
"exec resume <slug>",
|
|
15
|
+
"exec stop <slug>",
|
|
16
|
+
"exec logs <slug>",
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{ name: "start", usage: ["start <slug>"] },
|
|
20
|
+
{ name: "park", usage: ["park <slug>"] },
|
|
21
|
+
{
|
|
22
|
+
name: "task",
|
|
23
|
+
usage: [
|
|
24
|
+
"task start <slug> <taskId>",
|
|
25
|
+
"task block <slug> <taskId> --reason <text>",
|
|
26
|
+
"task unblock <slug> <taskId>",
|
|
27
|
+
"task complete <slug> <taskId>",
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{ name: "finalize", usage: ["finalize <slug>"] },
|
|
31
|
+
{ name: "promote", usage: ["promote <slug> <planned|in-progress|completed|parked>"] },
|
|
32
|
+
{ name: "audit", usage: ["audit [--staged|--all] [--strict]"] },
|
|
33
|
+
{ name: "move", usage: ["move <slug> <status> --force-recovery"] },
|
|
34
|
+
{ name: "canonicalize", usage: ["canonicalize <slug>"] },
|
|
35
|
+
{ name: "control", usage: ["control <status|resume|stop> <slug>"] },
|
|
36
|
+
{ name: "logs", usage: ["logs <slug>"] },
|
|
37
|
+
{ name: "db", usage: ["db <verb> [...args]"] },
|
|
38
|
+
{ name: "export", usage: ["export --format spec-kit <slug>"] },
|
|
39
|
+
{ name: "trust-dossier", usage: ["trust-dossier"] },
|
|
40
|
+
];
|
|
2
41
|
const BLUEPRINT_HELP = [
|
|
3
42
|
"Blueprint management",
|
|
4
43
|
"",
|
|
5
44
|
"Commands:",
|
|
6
|
-
|
|
7
|
-
" new <goal> --complexity <XS|S|M|L|XL> [--type <blueprint|parent-roadmap>]",
|
|
8
|
-
" show <slug>",
|
|
9
|
-
" exec <slug>",
|
|
10
|
-
" exec status <slug>",
|
|
11
|
-
" exec resume <slug>",
|
|
12
|
-
" exec stop <slug>",
|
|
13
|
-
" exec logs <slug>",
|
|
14
|
-
" start <slug>",
|
|
15
|
-
" park <slug>",
|
|
16
|
-
" task start <slug> <taskId>",
|
|
17
|
-
" task block <slug> <taskId> --reason <text>",
|
|
18
|
-
" task unblock <slug> <taskId>",
|
|
19
|
-
" task complete <slug> <taskId>",
|
|
20
|
-
" finalize <slug>",
|
|
21
|
-
" audit [--staged|--all] [--strict]",
|
|
22
|
-
" move <slug> <status> --force-recovery",
|
|
45
|
+
...BLUEPRINT_SUBCOMMANDS.flatMap((spec) => spec.usage.map((line) => ` ${line}`)),
|
|
23
46
|
].join("\n");
|
|
24
47
|
export function formatTaskLine(task) {
|
|
25
48
|
const checkbox = task.status === "done" || task.status === "dropped" ? "x" : " ";
|
|
@@ -28,6 +51,14 @@ export function formatTaskLine(task) {
|
|
|
28
51
|
export function getBlueprintHelpText() {
|
|
29
52
|
return BLUEPRINT_HELP;
|
|
30
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Subcommand names in registry order, for the unknown-subcommand error
|
|
56
|
+
* message. Kept as a function (rather than exporting a derived constant)
|
|
57
|
+
* so the source of truth stays singular: `BLUEPRINT_SUBCOMMANDS`.
|
|
58
|
+
*/
|
|
59
|
+
export function getBlueprintSubcommandNames() {
|
|
60
|
+
return BLUEPRINT_SUBCOMMANDS.map((spec) => spec.name);
|
|
61
|
+
}
|
|
31
62
|
export function summarizeBlueprintInventory(summaries) {
|
|
32
63
|
const byStatus = Object.fromEntries(planStatusSchema.options.toSorted().map((status) => [status, 0]));
|
|
33
64
|
const byType = {
|
|
@@ -73,6 +73,12 @@ export interface BlueprintLifecycleMutationResult {
|
|
|
73
73
|
status: string;
|
|
74
74
|
taskId?: string;
|
|
75
75
|
}
|
|
76
|
+
export interface BlueprintCanonicalizeResult {
|
|
77
|
+
from: string;
|
|
78
|
+
to: string;
|
|
79
|
+
moved: boolean;
|
|
80
|
+
message: string;
|
|
81
|
+
}
|
|
76
82
|
export interface CreateBlueprintResult extends CreatedBlueprint {
|
|
77
83
|
message: string;
|
|
78
84
|
/** True when draft was auto-routed off a primary-like checkout (H-009 DX). */
|
|
@@ -123,6 +129,7 @@ export declare function exportBlueprint(slug: string, format: string, options?:
|
|
|
123
129
|
export declare function advanceBlueprintTask(slug: string, taskId: string, toStatus: string, options?: BlueprintMoveOptions): Promise<AdvanceTaskResult>;
|
|
124
130
|
export declare function promoteBlueprintToState(slug: string, toState: string, options?: BlueprintMoveOptions): Promise<PromoteBlueprintResult>;
|
|
125
131
|
export declare function finalizeBlueprintBySlug(slug: string, options?: BlueprintMoveOptions): Promise<PromoteBlueprintResult>;
|
|
132
|
+
export declare function canonicalizeBlueprintBySlug(slug: string, options?: BlueprintMoveOptions): Promise<BlueprintCanonicalizeResult>;
|
|
126
133
|
export declare function registerBlueprintRouter(cli: CAC): void;
|
|
127
134
|
export declare function _setBlueprintExecCommandExistsForTests(probe: ((command: string) => boolean) | null): void;
|
|
128
135
|
export declare function _setBlueprintExecStarterForTests(starter: ((slug: string, options: BlueprintMoveOptions) => Promise<BlueprintLifecycleMutationResult>) | null): void;
|
|
@@ -5,9 +5,12 @@ import { parseBlueprintForDb } from "#db/parser/blueprint-db-parser";
|
|
|
5
5
|
import { blueprintToSpecKit } from "#export/spec-kit/index";
|
|
6
6
|
import { getProjectRoot } from "#cli/utils";
|
|
7
7
|
import { commandExists as defaultCommandExists } from "#runtime/command-exists.js";
|
|
8
|
-
import { clearBlueprintWorktreeOwnership, ensureBlueprintOwnerWorktree, } from "#worktrees/manager.js";
|
|
8
|
+
import { adoptBlueprintOwnerWorktree, clearBlueprintWorktreeOwnership, ensureBlueprintOwnerWorktree, } from "#worktrees/manager.js";
|
|
9
|
+
import { resolveCurrentManagedWorktreeContext } from "#worktrees/current.js";
|
|
10
|
+
import { canonicalizeWorktreePath, WORKTREE_PROBE_TIMEOUT_MS } from "#worktrees/identity.js";
|
|
9
11
|
import { resolveBlueprintRoot } from "#utils/blueprint-root";
|
|
10
12
|
import { getBlueprintDocumentPaths } from "#utils/document-paths.js";
|
|
13
|
+
import { canonicalizeBlueprint } from "#lifecycle/canonicalize.js";
|
|
11
14
|
import { applyBlueprintLifecycleToFile, BlueprintCreationService, BlueprintService, complexitySchema, relativeBlueprintSlug, parseBlueprint, planStatusSchema, runBlueprintAudit, resolveBlueprintFile, serializeBlueprint, validateAllTasksDone, } from "#local";
|
|
12
15
|
import { resolvePackageAssetPreferred } from "#utils/package-assets";
|
|
13
16
|
import { resolveDraftAuthoringRoot } from "#worktrees/draft-authoring-root.js";
|
|
@@ -392,7 +395,16 @@ export async function startBlueprint(slug, options = {}) {
|
|
|
392
395
|
if (source.blueprint.status !== "planned") {
|
|
393
396
|
throw new Error(`Blueprint ${source.slug} must be planned before start (current: ${source.blueprint.status}).`);
|
|
394
397
|
}
|
|
395
|
-
const
|
|
398
|
+
const relativeSlug = relativeBlueprintSlug(slug);
|
|
399
|
+
const currentManaged = resolveCurrentManagedWorktreeContext(projectRoot);
|
|
400
|
+
const canonicalProjectRoot = canonicalizeWorktreePath(projectRoot);
|
|
401
|
+
const currentBranch = readCurrentGitBranch(projectRoot);
|
|
402
|
+
const binding = currentManaged &&
|
|
403
|
+
currentManaged.kind === "owner" &&
|
|
404
|
+
currentManaged.worktreePath === canonicalProjectRoot &&
|
|
405
|
+
currentBranch === `bp/${relativeSlug}`
|
|
406
|
+
? adoptBlueprintOwnerWorktree(currentManaged.repoRoot, relativeSlug, currentManaged.worktreePath)
|
|
407
|
+
: ensureBlueprintOwnerWorktree(projectRoot, relativeSlug);
|
|
396
408
|
const result = await applyLifecycleMutation(slug, {
|
|
397
409
|
type: "start",
|
|
398
410
|
worktreeOwnerId: binding.id,
|
|
@@ -404,6 +416,20 @@ export async function startBlueprint(slug, options = {}) {
|
|
|
404
416
|
ownerWorktreePath: binding.path,
|
|
405
417
|
};
|
|
406
418
|
}
|
|
419
|
+
function readCurrentGitBranch(cwd) {
|
|
420
|
+
try {
|
|
421
|
+
const branch = execFileSync("git", ["branch", "--show-current"], {
|
|
422
|
+
cwd,
|
|
423
|
+
encoding: "utf8",
|
|
424
|
+
timeout: WORKTREE_PROBE_TIMEOUT_MS,
|
|
425
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
426
|
+
}).trim();
|
|
427
|
+
return branch.length > 0 ? branch : null;
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
407
433
|
export async function parkBlueprint(slug, options = {}) {
|
|
408
434
|
const projectRoot = resolveProjectRoot(options.projectRoot);
|
|
409
435
|
const result = await applyLifecycleMutation(slug, { type: "park" }, projectRoot);
|
|
@@ -487,9 +513,19 @@ export async function finalizeBlueprintBySlug(slug, options = {}) {
|
|
|
487
513
|
const projectRoot = resolveProjectRoot(options.projectRoot);
|
|
488
514
|
return finalizeBlueprintMutation(projectRoot, slug);
|
|
489
515
|
}
|
|
516
|
+
export async function canonicalizeBlueprintBySlug(slug, options = {}) {
|
|
517
|
+
const projectRoot = resolveProjectRoot(options.projectRoot);
|
|
518
|
+
const result = await canonicalizeBlueprint(projectRoot, slug);
|
|
519
|
+
return {
|
|
520
|
+
...result,
|
|
521
|
+
message: result.moved
|
|
522
|
+
? `Canonicalized blueprint ${slug}: ${result.from} -> ${result.to}`
|
|
523
|
+
: `Blueprint ${slug} is already canonical: ${result.to}`,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
490
526
|
export function registerBlueprintRouter(cli) {
|
|
491
527
|
cli
|
|
492
|
-
.command("blueprint [subcommand] [...args]", "Manage blueprints. Use: wp blueprint <action> --help for action-specific options (new, list, show, audit, exec, move, finalize, start, task)")
|
|
528
|
+
.command("blueprint [subcommand] [...args]", "Manage blueprints. Use: wp blueprint <action> --help for action-specific options (new, list, show, audit, exec, move, finalize, start, task, trust-dossier)")
|
|
493
529
|
.option("--json", "Print JSON output")
|
|
494
530
|
.option("--no-tui", "Use plain terminal output")
|
|
495
531
|
.option("--complexity <complexity>", "Blueprint complexity (XS|S|M|L|XL)")
|
|
@@ -510,6 +546,7 @@ export function registerBlueprintRouter(cli) {
|
|
|
510
546
|
await executeBlueprintSubcommand(subcommand, args, options, {
|
|
511
547
|
advanceBlueprintTask,
|
|
512
548
|
auditBlueprints,
|
|
549
|
+
canonicalizeBlueprintBySlug,
|
|
513
550
|
createBlueprint,
|
|
514
551
|
controlBlueprintExec,
|
|
515
552
|
executeBlueprint,
|
|
@@ -31,9 +31,20 @@ export interface CiPreflightDeps {
|
|
|
31
31
|
readonly cwd?: string;
|
|
32
32
|
readonly resolveRepoRoot?: (cwd: string) => string | null;
|
|
33
33
|
readonly hasNodeModules?: (repoRoot: string) => boolean;
|
|
34
|
-
readonly runCheck?: (check: CiPreflightCheck, repoRoot: string) => number
|
|
34
|
+
readonly runCheck?: (check: CiPreflightCheck, repoRoot: string) => number | Promise<number>;
|
|
35
35
|
readonly stdout?: Pick<typeof process.stdout, "write">;
|
|
36
36
|
readonly stderr?: Pick<typeof process.stderr, "write">;
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Re-invoke the same `wp` runtime that is currently executing so each check
|
|
40
|
+
* runs the real verb (faithful CI parity) rather than a reimplemented copy of
|
|
41
|
+
* its affected-resolution logic. Prefers the repo-local `bin/wp` launcher when
|
|
42
|
+
* present so the exact source/compiled selection and NODE_PATH wiring apply;
|
|
43
|
+
* falls back to the running runtime for consumer repos with a global `wp`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveWpLauncher(repoRoot: string): {
|
|
46
|
+
readonly command: string;
|
|
47
|
+
readonly prefixArgs: readonly string[];
|
|
48
|
+
};
|
|
49
|
+
export declare function runCiPreflight(deps?: CiPreflightDeps): Promise<number>;
|
|
39
50
|
export declare function registerCiPreflightCommand(cli: CAC): void;
|
|
@@ -57,7 +57,10 @@ function reproduceLine(check) {
|
|
|
57
57
|
* present so the exact source/compiled selection and NODE_PATH wiring apply;
|
|
58
58
|
* falls back to the running runtime for consumer repos with a global `wp`.
|
|
59
59
|
*/
|
|
60
|
-
|
|
60
|
+
// Exported so `src/mcp/tools/ci-preflight.ts` can re-invoke the exact same
|
|
61
|
+
// `wp` launcher when it substitutes an output-capturing `runCheck` for the
|
|
62
|
+
// default `stdio: "inherit"` spawn — do not duplicate this resolution logic.
|
|
63
|
+
export function resolveWpLauncher(repoRoot) {
|
|
61
64
|
const localLauncher = path.join(repoRoot, "bin", process.platform === "win32" ? "wp.cmd" : "wp");
|
|
62
65
|
if (existsSync(localLauncher))
|
|
63
66
|
return { command: localLauncher, prefixArgs: [] };
|
|
@@ -82,7 +85,7 @@ function defaultRunCheck(check, repoRoot) {
|
|
|
82
85
|
}
|
|
83
86
|
return typeof result.status === "number" ? result.status : 1;
|
|
84
87
|
}
|
|
85
|
-
export function runCiPreflight(deps = {}) {
|
|
88
|
+
export async function runCiPreflight(deps = {}) {
|
|
86
89
|
const cwd = deps.cwd ?? process.cwd();
|
|
87
90
|
const stdout = deps.stdout ?? process.stdout;
|
|
88
91
|
const stderr = deps.stderr ?? process.stderr;
|
|
@@ -100,7 +103,7 @@ export function runCiPreflight(deps = {}) {
|
|
|
100
103
|
}
|
|
101
104
|
for (const check of CI_PREFLIGHT_CHECKS) {
|
|
102
105
|
stdout.write(`\nwp ci-preflight: running ${check.label} (${reproduceLine(check)})\n`);
|
|
103
|
-
const exitCode = runCheck(check, repoRoot);
|
|
106
|
+
const exitCode = await runCheck(check, repoRoot);
|
|
104
107
|
if (exitCode !== 0) {
|
|
105
108
|
const normalizedExit = exitCode === 0 ? 1 : exitCode;
|
|
106
109
|
stderr.write(`\nwp ci-preflight: ${check.label} failed (exit ${normalizedExit}).\n` +
|
|
@@ -2,12 +2,14 @@ import type { CAC } from "cac";
|
|
|
2
2
|
import type { SecretGateCommandOptions, SecretGateRunResult } from "#secret-gate/runner.js";
|
|
3
3
|
import { type CiActEventName, type CiActExecutionMode } from "#ci/act-runner.js";
|
|
4
4
|
export declare const DEFAULT_CI_ACT_TIMEOUT_MS: number;
|
|
5
|
+
export declare const SMOKE_CI_ACT_TIMEOUT_MS = 30000;
|
|
5
6
|
export declare const MAX_CI_ACT_TIMEOUT_MS: number;
|
|
6
7
|
export declare const CI_COMMAND_HELP: string;
|
|
7
8
|
export interface CiActOptions {
|
|
8
9
|
readonly workflow?: string;
|
|
9
10
|
readonly workflowPath?: string;
|
|
10
11
|
readonly job?: string;
|
|
12
|
+
readonly matrix?: readonly string[];
|
|
11
13
|
readonly eventName?: CiActEventName;
|
|
12
14
|
readonly eventPath?: string;
|
|
13
15
|
readonly envProfile?: string;
|
|
@@ -17,6 +19,7 @@ export interface CiActOptions {
|
|
|
17
19
|
readonly platformImage?: string;
|
|
18
20
|
readonly execute?: boolean;
|
|
19
21
|
readonly timeoutMs?: number;
|
|
22
|
+
readonly smoke?: boolean;
|
|
20
23
|
}
|
|
21
24
|
export interface CiCommandConfig {
|
|
22
25
|
readonly command: string;
|
|
@@ -32,5 +35,9 @@ export declare function registerCiCommand(cli: CAC): void;
|
|
|
32
35
|
export declare function buildCiActCommand(options?: CiActOptions, cwd?: string): CiCommandConfig;
|
|
33
36
|
export declare function validateCiActCommand(..._legacyArgs: readonly unknown[]): string | null;
|
|
34
37
|
export declare function runCiActCommand(options?: CiActOptions, deps?: CiCommandDeps): Promise<number>;
|
|
35
|
-
export declare function normalizeCiActTimeoutMs(value: number | undefined
|
|
38
|
+
export declare function normalizeCiActTimeoutMs(value: number | undefined, options?: {
|
|
39
|
+
readonly smoke?: boolean;
|
|
40
|
+
}): number;
|
|
36
41
|
export declare function parseCiActTimeoutMs(value: unknown): number | undefined;
|
|
42
|
+
export declare function parseCiActExecutionMode(value: unknown): CiActExecutionMode | undefined;
|
|
43
|
+
export declare function parseCiActEventName(value: unknown): CiActEventName | undefined;
|