@webpresso/agent-kit 3.1.28 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @webpresso/agent-kit might be problematic. Click here for more details.
- package/README.md +53 -15
- package/bin/_run.js +179 -19
- package/catalog/AGENTS.md.tpl +6 -6
- package/catalog/agent/agents/implementer.md +45 -0
- package/catalog/agent/rules/ci-cost-local-first.md +139 -0
- package/catalog/agent/rules/ci-test-perf.md +5 -1
- package/catalog/agent/rules/cmd-execution.md +9 -0
- package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
- package/catalog/agent/rules/pre-implementation.md +30 -2
- package/catalog/agent/rules/supported-agent-clis.md +9 -0
- package/catalog/agent/rules/test-scan-perf.md +80 -0
- package/catalog/agent/rules/typescript-version.md +50 -0
- package/catalog/agent/rules/workflow-skills-routing.md +4 -2
- package/catalog/agent/skills/codex/SKILL.md +25 -1
- package/catalog/agent/skills/fix/SKILL.md +3 -0
- package/catalog/agent/skills/verify/SKILL.md +22 -2
- package/catalog/docs/templates/blueprint.md +1 -1
- package/dist/esm/audit/agents.js +1 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
- package/dist/esm/audit/blueprint-pr-coverage.js +72 -7
- package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
- package/dist/esm/audit/ci-guardrails-wiring.js +90 -0
- package/dist/esm/audit/ci-test-perf.js +30 -0
- package/dist/esm/audit/command-surface.js +4 -2
- package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
- package/dist/esm/audit/host-substitution-risk.js +256 -0
- package/dist/esm/audit/registry.d.ts +4 -4
- package/dist/esm/audit/registry.js +11 -1
- package/dist/esm/audit/roadmap-links.js +6 -0
- package/dist/esm/audit/test-scan-perf.d.ts +18 -0
- package/dist/esm/audit/test-scan-perf.js +275 -0
- package/dist/esm/audit/toolchain-isolation.js +1 -2
- package/dist/esm/audit/typescript-version.d.ts +2 -0
- package/dist/esm/audit/typescript-version.js +123 -0
- package/dist/esm/blueprint/core/parser.js +43 -1
- package/dist/esm/blueprint/core/validation/criteria.d.ts +14 -0
- package/dist/esm/blueprint/core/validation/criteria.js +41 -2
- package/dist/esm/blueprint/core/validation/state.js +25 -14
- package/dist/esm/blueprint/db/migrations/run.js +4 -2
- package/dist/esm/blueprint/lifecycle/audit.d.ts +20 -0
- package/dist/esm/blueprint/lifecycle/audit.js +65 -10
- package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
- package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
- package/dist/esm/blueprint/lifecycle/engine.d.ts +9 -0
- package/dist/esm/blueprint/lifecycle/engine.js +53 -6
- package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
- package/dist/esm/blueprint/lifecycle/local.js +19 -3
- package/dist/esm/blueprint/lifecycle/review-provenance.d.ts +6 -0
- package/dist/esm/blueprint/lifecycle/review-provenance.js +118 -12
- package/dist/esm/blueprint/markdown/helpers.js +6 -2
- package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
- package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
- package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
- package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
- package/dist/esm/blueprint/trust/command-runner.js +148 -0
- package/dist/esm/blueprint/trust/gates.d.ts +7 -0
- package/dist/esm/blueprint/trust/gates.js +20 -0
- package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
- package/dist/esm/blueprint/trust/promotion.js +62 -112
- package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
- package/dist/esm/blueprint/trust/scaffold.js +64 -0
- package/dist/esm/blueprint/trust/validator.d.ts +1 -0
- package/dist/esm/blueprint/trust/validator.js +7 -1
- package/dist/esm/blueprint/utils/archive.js +27 -5
- package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
- package/dist/esm/blueprint/utils/document-paths.js +45 -12
- package/dist/esm/build/cli-mcp-parity.js +10 -0
- package/dist/esm/ci/act-replay.js +110 -7
- package/dist/esm/ci/act-runner.d.ts +4 -0
- package/dist/esm/ci/act-runner.js +85 -26
- package/dist/esm/ci/act-worktree-git.d.ts +11 -0
- package/dist/esm/ci/act-worktree-git.js +219 -0
- package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
- package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
- package/dist/esm/cli/cli.d.ts +1 -1
- package/dist/esm/cli/cli.js +34 -0
- package/dist/esm/cli/commands/agent-launch.d.ts +6 -1
- package/dist/esm/cli/commands/agent-launch.js +82 -4
- package/dist/esm/cli/commands/audit-core.d.ts +1 -1
- package/dist/esm/cli/commands/audit-core.js +8 -1
- package/dist/esm/cli/commands/audit.js +20 -5
- package/dist/esm/cli/commands/blueprint/execution.js +18 -6
- package/dist/esm/cli/commands/blueprint/mutations.js +83 -47
- package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
- package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
- package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
- package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
- package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
- package/dist/esm/cli/commands/blueprint/router.js +40 -3
- package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
- package/dist/esm/cli/commands/ci-preflight.js +6 -3
- package/dist/esm/cli/commands/ci.d.ts +8 -1
- package/dist/esm/cli/commands/ci.js +80 -21
- package/dist/esm/cli/commands/compile.js +5 -31
- package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
- package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
- package/dist/esm/cli/commands/dash/keymap.js +1 -0
- package/dist/esm/cli/commands/dash/launch-preferences.d.ts +15 -0
- package/dist/esm/cli/commands/dash/launch-preferences.js +46 -17
- package/dist/esm/cli/commands/dash/plan-once-label.d.ts +7 -0
- package/dist/esm/cli/commands/dash/plan-once-label.js +5 -0
- package/dist/esm/cli/commands/dash/plan-once-membership.d.ts +67 -0
- package/dist/esm/cli/commands/dash/plan-once-membership.js +151 -0
- package/dist/esm/cli/commands/dash/plan-once-merge.d.ts +143 -0
- package/dist/esm/cli/commands/dash/plan-once-merge.js +238 -0
- package/dist/esm/cli/commands/dash/plan-once.d.ts +22 -2
- package/dist/esm/cli/commands/dash/plan-once.js +41 -4
- package/dist/esm/cli/commands/dash/tui/attention-hud.d.ts +9 -0
- package/dist/esm/cli/commands/dash/tui/attention-hud.js +9 -0
- package/dist/esm/cli/commands/dash/tui/chat-bridge.d.ts +41 -0
- package/dist/esm/cli/commands/dash/tui/chat-bridge.js +73 -0
- package/dist/esm/cli/commands/dash/tui/chat-mode.d.ts +47 -0
- package/dist/esm/cli/commands/dash/tui/chat-mode.js +98 -0
- package/dist/esm/cli/commands/dash/tui/frame.d.ts +3 -0
- package/dist/esm/cli/commands/dash/tui/frame.js +3 -1
- package/dist/esm/cli/commands/dash/tui/palette.d.ts +1 -1
- package/dist/esm/cli/commands/dash/tui/palette.js +14 -0
- package/dist/esm/cli/commands/dash/tui/runtime.js +239 -4
- package/dist/esm/cli/commands/dash/tui/state.d.ts +41 -0
- package/dist/esm/cli/commands/dash/tui/state.js +257 -4
- package/dist/esm/cli/commands/doctor.js +5 -0
- package/dist/esm/cli/commands/format.js +0 -2
- package/dist/esm/cli/commands/hook.d.ts +5 -0
- package/dist/esm/cli/commands/hook.js +15 -9
- package/dist/esm/cli/commands/init/config.d.ts +0 -1
- package/dist/esm/cli/commands/init/config.js +3 -6
- package/dist/esm/cli/commands/init/convergence-apply.d.ts +24 -0
- package/dist/esm/cli/commands/init/convergence-apply.js +221 -0
- package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
- package/dist/esm/cli/commands/init/convergence-state.js +54 -0
- package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
- package/dist/esm/cli/commands/init/convergence.js +57 -0
- package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
- package/dist/esm/cli/commands/init/git-convergence.js +168 -0
- package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
- package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
- package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
- package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
- package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
- package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
- package/dist/esm/cli/commands/init/host-visibility.js +94 -5
- package/dist/esm/cli/commands/init/index.d.ts +1 -0
- package/dist/esm/cli/commands/init/index.js +326 -173
- package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
- package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
- package/dist/esm/cli/commands/init/merge.d.ts +1 -0
- package/dist/esm/cli/commands/init/merge.js +30 -1
- package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
- package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
- package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
- package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
- package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +11 -0
- package/dist/esm/cli/commands/init/scaffold-base-kit.js +56 -1
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/claude.d.ts +5 -6
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/claude.js +6 -13
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +51 -23
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/ir.d.ts +0 -2
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/ir.js +0 -2
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/merge.d.ts +6 -3
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/merge.js +39 -26
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +297 -173
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +7 -0
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +58 -0
- package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
- package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
- package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
- package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
- package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
- package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
- package/dist/esm/cli/commands/logs.d.ts +15 -0
- package/dist/esm/cli/commands/logs.js +192 -3
- package/dist/esm/cli/commands/opencode-rotate.d.ts +49 -0
- package/dist/esm/cli/commands/opencode-rotate.js +135 -0
- package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
- package/dist/esm/cli/commands/public-readiness.js +42 -0
- package/dist/esm/cli/commands/quality-log-store.d.ts +1 -0
- package/dist/esm/cli/commands/quality-log-store.js +187 -51
- package/dist/esm/cli/commands/review.d.ts +35 -3
- package/dist/esm/cli/commands/review.js +734 -217
- package/dist/esm/cli/commands/run-wait.d.ts +2 -0
- package/dist/esm/cli/commands/run-wait.js +122 -0
- package/dist/esm/cli/commands/secrets.d.ts +1 -0
- package/dist/esm/cli/commands/secrets.js +4 -1
- package/dist/esm/cli/commands/setup-help.js +1 -1
- package/dist/esm/cli/commands/setup-repair-help.js +1 -1
- package/dist/esm/cli/commands/worktree/router-dispatch.js +13 -8
- package/dist/esm/cli/direct-provider-launch.js +31 -3
- package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
- package/dist/esm/cli/optional-tool-freshness.js +219 -9
- package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
- package/dist/esm/daemon/domains/git-actions.js +136 -0
- package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
- package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
- package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
- package/dist/esm/daemon/domains/sessions-search.js +29 -0
- package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
- package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
- package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
- package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
- package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
- package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
- package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
- package/dist/esm/daemon/handlers/git-handlers.js +27 -0
- package/dist/esm/daemon/handlers/product.d.ts +7 -0
- package/dist/esm/daemon/handlers/product.js +10 -119
- package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
- package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
- package/dist/esm/daemon/handlers/shared.d.ts +5 -0
- package/dist/esm/daemon/handlers/shared.js +16 -0
- package/dist/esm/daemon/methods.d.ts +8 -1
- package/dist/esm/daemon/methods.js +7 -0
- package/dist/esm/daemon/protocol/contract.d.ts +43 -0
- package/dist/esm/daemon/protocol/contract.js +26 -0
- package/dist/esm/daemon/protocol/index.d.ts +1 -1
- package/dist/esm/daemon/protocol/index.js +1 -1
- package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
- package/dist/esm/hooks/__conformance__/matrix.js +137 -0
- package/dist/esm/hooks/conformance/batch.js +5 -0
- package/dist/esm/hooks/doctor.d.ts +15 -0
- package/dist/esm/hooks/doctor.js +79 -8
- package/dist/esm/hooks/permission-request/index.js +9 -3
- package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
- package/dist/esm/hooks/permission-request/policy.js +13 -0
- package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
- package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
- package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
- package/dist/esm/hooks/pretool-guard/logger.js +16 -0
- package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
- package/dist/esm/hooks/pretool-guard/runner.js +68 -16
- package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
- package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +58 -4
- package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
- package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
- package/dist/esm/hooks/pretool-guard/validators/mcp-redirect.d.ts +0 -1
- package/dist/esm/hooks/pretool-guard/validators/mcp-redirect.js +8 -5
- package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
- package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
- package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.d.ts +9 -7
- package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.js +126 -14
- package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
- package/dist/esm/hooks/shared/guard-outcome.js +215 -0
- package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
- package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
- package/dist/esm/hooks/shared/types.d.ts +8 -5
- package/dist/esm/hooks/shared/types.js +23 -8
- package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
- package/dist/esm/hooks/stop/qa-changed-files.js +74 -0
- package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
- package/dist/esm/mcp/blueprint/handlers/document-mutations.js +78 -4
- package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
- package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
- package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
- package/dist/esm/mcp/blueprint/registration.js +3 -2
- package/dist/esm/mcp/server.d.ts +1 -0
- package/dist/esm/mcp/server.js +27 -0
- package/dist/esm/mcp/tools/_names.d.ts +1 -1
- package/dist/esm/mcp/tools/_names.js +5 -0
- package/dist/esm/mcp/tools/_registry.js +10 -0
- package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
- package/dist/esm/mcp/tools/_shared/result.js +44 -1
- package/dist/esm/mcp/tools/audit.d.ts +5 -1
- package/dist/esm/mcp/tools/audit.js +40 -0
- package/dist/esm/mcp/tools/audits.d.ts +4 -0
- package/dist/esm/mcp/tools/ci-act.js +9 -11
- package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
- package/dist/esm/mcp/tools/ci-preflight.js +183 -0
- package/dist/esm/mcp/tools/pr-upsert.js +39 -1
- package/dist/esm/mcp/tools/review-run.d.ts +28 -0
- package/dist/esm/mcp/tools/review-run.js +216 -0
- package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
- package/dist/esm/mcp/tools/run-wait.js +593 -0
- package/dist/esm/mcp/tools/session-id.d.ts +3 -0
- package/dist/esm/mcp/tools/session-id.js +45 -0
- package/dist/esm/mcp/tools/session-info.d.ts +3 -0
- package/dist/esm/mcp/tools/session-info.js +49 -0
- package/dist/esm/output-transforms/audit.d.ts +23 -0
- package/dist/esm/output-transforms/audit.js +47 -0
- package/dist/esm/output-transforms/index.js +2 -0
- package/dist/esm/paths/state-root.js +3 -0
- package/dist/esm/review/authority.js +30 -7
- package/dist/esm/review/availability.d.ts +22 -0
- package/dist/esm/review/availability.js +123 -23
- package/dist/esm/review/delivery-verifier.d.ts +27 -0
- package/dist/esm/review/delivery-verifier.js +115 -0
- package/dist/esm/review/events.d.ts +3 -2
- package/dist/esm/review/events.js +23 -3
- package/dist/esm/review/execution/adapters.js +26 -9
- package/dist/esm/review/execution/output-policy.d.ts +2 -0
- package/dist/esm/review/execution/output-policy.js +12 -0
- package/dist/esm/review/execution/review-checkout.js +87 -6
- package/dist/esm/review/execution/supervisor.js +5 -0
- package/dist/esm/review/execution/types.d.ts +8 -0
- package/dist/esm/review/opencode-account.d.ts +24 -0
- package/dist/esm/review/opencode-account.js +68 -0
- package/dist/esm/review/opencode-auth.d.ts +33 -0
- package/dist/esm/review/opencode-auth.js +79 -0
- package/dist/esm/review/subject.d.ts +27 -0
- package/dist/esm/review/subject.js +179 -32
- package/dist/esm/runtime/executor.d.ts +1 -0
- package/dist/esm/runtime/executor.js +2 -1
- package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
- package/dist/esm/runtime/opencode-account-materializer.js +33 -0
- package/dist/esm/secret-gate/runner.d.ts +1 -0
- package/dist/esm/secret-gate/runner.js +4 -1
- package/dist/esm/status/snapshot.js +30 -19
- package/dist/esm/test/duration-sequencer.d.ts +20 -0
- package/dist/esm/test/duration-sequencer.js +54 -0
- package/dist/esm/test/shard-durations.json +922 -0
- package/dist/esm/test/worker-budget.d.ts +6 -0
- package/dist/esm/test/worker-budget.js +59 -1
- package/dist/esm/test-helpers/global-setup.d.ts +1 -1
- package/dist/esm/test-helpers/global-setup.js +68 -24
- package/dist/esm/ultragoal/service.d.ts +7 -0
- package/dist/esm/ultragoal/service.js +42 -2
- package/dist/esm/utils/write-json-file.js +3 -1
- package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
- package/dist/esm/worktrees/codex-project-trust.js +56 -0
- package/dist/esm/worktrees/current.d.ts +1 -0
- package/dist/esm/worktrees/current.js +1 -0
- package/dist/esm/worktrees/project-agent-surfaces.d.ts +1 -0
- package/dist/esm/worktrees/project-agent-surfaces.js +2 -1
- package/dist/esm/worktrees/registry.d.ts +8 -0
- package/dist/esm/worktrees/registry.js +18 -3
- package/package.json +18 -15
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, rmSync, symlinkSync, } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, join, resolve, sep } from "node:path";
|
|
5
|
+
export function prepareActGitWorkspace(cwd) {
|
|
6
|
+
const sourceCwd = resolve(cwd);
|
|
7
|
+
const linked = readLinkedWorktreeGitMetadata(sourceCwd);
|
|
8
|
+
if (!linked) {
|
|
9
|
+
return {
|
|
10
|
+
cwd: sourceCwd,
|
|
11
|
+
prepared: false,
|
|
12
|
+
cleanup() { },
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
assertExistingDirectory(linked.gitDir, "linked-worktree gitdir");
|
|
16
|
+
const commonDir = resolveGitCommonDir(linked.gitDir);
|
|
17
|
+
assertExistingDirectory(commonDir, "linked-worktree commondir");
|
|
18
|
+
const tempRoot = mkdtempSync(join(tmpdir(), "wp-ci-act-worktree-"));
|
|
19
|
+
const preparedCwd = join(tempRoot, "workspace");
|
|
20
|
+
try {
|
|
21
|
+
const head = git(sourceCwd, ["rev-parse", "HEAD"]);
|
|
22
|
+
git(sourceCwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
23
|
+
execFileSync("git", [
|
|
24
|
+
"clone",
|
|
25
|
+
"--local",
|
|
26
|
+
"--no-hardlinks",
|
|
27
|
+
"--dissociate",
|
|
28
|
+
"--no-checkout",
|
|
29
|
+
sourceCwd,
|
|
30
|
+
preparedCwd,
|
|
31
|
+
], {
|
|
32
|
+
encoding: "utf8",
|
|
33
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
34
|
+
});
|
|
35
|
+
syncOriginRemote(sourceCwd, preparedCwd);
|
|
36
|
+
git(preparedCwd, ["checkout", "--detach", "--quiet", head]);
|
|
37
|
+
overlayWorkingTreeChanges(sourceCwd, preparedCwd);
|
|
38
|
+
assertPreparedGitMetadataIsSelfContained(preparedCwd);
|
|
39
|
+
return {
|
|
40
|
+
cwd: preparedCwd,
|
|
41
|
+
prepared: true,
|
|
42
|
+
cleanup() {
|
|
43
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function readLinkedWorktreeGitMetadata(cwd) {
|
|
53
|
+
const gitPath = join(cwd, ".git");
|
|
54
|
+
if (!existsSync(gitPath)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const stat = lstatSync(gitPath);
|
|
58
|
+
if (stat.isDirectory())
|
|
59
|
+
return null;
|
|
60
|
+
if (!stat.isFile()) {
|
|
61
|
+
throw new Error(`Cannot prepare ci act workspace: ${gitPath} is not a file or directory.`);
|
|
62
|
+
}
|
|
63
|
+
const content = readFileSync(gitPath, "utf8").trim();
|
|
64
|
+
const match = /^gitdir:\s*(.+)$/u.exec(content);
|
|
65
|
+
if (!match?.[1]) {
|
|
66
|
+
throw new Error(`Cannot prepare ci act workspace: ${gitPath} is not a valid gitdir file.`);
|
|
67
|
+
}
|
|
68
|
+
return { gitDir: resolve(cwd, match[1]) };
|
|
69
|
+
}
|
|
70
|
+
function resolveGitCommonDir(gitDir) {
|
|
71
|
+
const commonDirPath = join(gitDir, "commondir");
|
|
72
|
+
if (!existsSync(commonDirPath))
|
|
73
|
+
return gitDir;
|
|
74
|
+
const raw = readFileSync(commonDirPath, "utf8").trim();
|
|
75
|
+
if (!raw)
|
|
76
|
+
throw new Error(`Cannot prepare ci act workspace: ${commonDirPath} is empty.`);
|
|
77
|
+
return resolve(gitDir, raw);
|
|
78
|
+
}
|
|
79
|
+
function overlayWorkingTreeChanges(sourceCwd, preparedCwd) {
|
|
80
|
+
const changed = parseGitDiffNameStatus(splitGitNullOutput(gitRaw(sourceCwd, ["diff", "--name-status", "--find-renames", "-z", "HEAD", "--"])));
|
|
81
|
+
const untracked = splitGitNullOutput(gitRaw(sourceCwd, ["ls-files", "--others", "--exclude-standard", "-z"]));
|
|
82
|
+
const copyPaths = new Set([...changed.copyPaths, ...untracked]);
|
|
83
|
+
for (const relativePath of changed.removePaths) {
|
|
84
|
+
assertSafeGitRelativePath(relativePath);
|
|
85
|
+
rmSync(join(preparedCwd, relativePath), { recursive: true, force: true });
|
|
86
|
+
}
|
|
87
|
+
for (const relativePath of copyPaths) {
|
|
88
|
+
assertSafeGitRelativePath(relativePath);
|
|
89
|
+
const sourcePath = join(sourceCwd, relativePath);
|
|
90
|
+
const preparedPath = join(preparedCwd, relativePath);
|
|
91
|
+
const sourceStat = tryLstat(sourcePath);
|
|
92
|
+
if (!sourceStat) {
|
|
93
|
+
rmSync(preparedPath, { recursive: true, force: true });
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
mkdirSync(dirname(preparedPath), { recursive: true });
|
|
97
|
+
if (sourceStat.isSymbolicLink()) {
|
|
98
|
+
rmSync(preparedPath, { recursive: true, force: true });
|
|
99
|
+
symlinkSync(readlinkSync(sourcePath), preparedPath);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
rmSync(preparedPath, { recursive: true, force: true });
|
|
103
|
+
cpSync(sourcePath, preparedPath, { recursive: true, force: true, errorOnExist: false });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function tryLstat(path) {
|
|
107
|
+
try {
|
|
108
|
+
return lstatSync(path);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function parseGitDiffNameStatus(entries) {
|
|
118
|
+
const copyPaths = new Set();
|
|
119
|
+
const removePaths = new Set();
|
|
120
|
+
for (let index = 0; index < entries.length;) {
|
|
121
|
+
const status = entries[index++];
|
|
122
|
+
if (!status)
|
|
123
|
+
continue;
|
|
124
|
+
if (status.startsWith("R")) {
|
|
125
|
+
const oldPath = entries[index++];
|
|
126
|
+
const newPath = entries[index++];
|
|
127
|
+
if (oldPath)
|
|
128
|
+
removePaths.add(oldPath);
|
|
129
|
+
if (newPath)
|
|
130
|
+
copyPaths.add(newPath);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (status.startsWith("C")) {
|
|
134
|
+
index++;
|
|
135
|
+
const newPath = entries[index++];
|
|
136
|
+
if (newPath)
|
|
137
|
+
copyPaths.add(newPath);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const path = entries[index++];
|
|
141
|
+
if (!path)
|
|
142
|
+
continue;
|
|
143
|
+
if (status.startsWith("D")) {
|
|
144
|
+
removePaths.add(path);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
copyPaths.add(path);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { copyPaths, removePaths };
|
|
151
|
+
}
|
|
152
|
+
function syncOriginRemote(sourceCwd, preparedCwd) {
|
|
153
|
+
const originUrl = tryGit(sourceCwd, ["remote", "get-url", "origin"]);
|
|
154
|
+
if (originUrl) {
|
|
155
|
+
git(preparedCwd, ["remote", "set-url", "origin", originUrl]);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
tryGit(preparedCwd, ["remote", "remove", "origin"]);
|
|
159
|
+
}
|
|
160
|
+
function assertPreparedGitMetadataIsSelfContained(preparedCwd) {
|
|
161
|
+
const gitPath = join(preparedCwd, ".git");
|
|
162
|
+
if (!existsSync(gitPath) || !lstatSync(gitPath).isDirectory()) {
|
|
163
|
+
throw new Error("Cannot prepare ci act workspace: prepared .git metadata is not a directory.");
|
|
164
|
+
}
|
|
165
|
+
const commonDir = resolve(preparedCwd, git(preparedCwd, ["rev-parse", "--git-common-dir"]));
|
|
166
|
+
const relative = commonDirRelativeToPrepared(preparedCwd, commonDir);
|
|
167
|
+
if (relative === null) {
|
|
168
|
+
throw new Error(`Cannot prepare ci act workspace: prepared git common dir escaped the execution workspace (${commonDir}).`);
|
|
169
|
+
}
|
|
170
|
+
const alternatesPath = join(commonDir, "objects", "info", "alternates");
|
|
171
|
+
if (existsSync(alternatesPath) && readFileSync(alternatesPath, "utf8").trim().length > 0) {
|
|
172
|
+
throw new Error(`Cannot prepare ci act workspace: prepared git objects still depend on alternates (${alternatesPath}).`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function commonDirRelativeToPrepared(preparedCwd, commonDir) {
|
|
176
|
+
const normalizedRoot = resolve(preparedCwd);
|
|
177
|
+
const normalizedCommon = resolve(commonDir);
|
|
178
|
+
if (normalizedCommon === normalizedRoot)
|
|
179
|
+
return "";
|
|
180
|
+
if (normalizedCommon.startsWith(`${normalizedRoot}${sep}`)) {
|
|
181
|
+
return normalizedCommon.slice(normalizedRoot.length + 1);
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
function splitGitNullOutput(output) {
|
|
186
|
+
return output.split("\0").filter((entry) => entry.length > 0);
|
|
187
|
+
}
|
|
188
|
+
function assertSafeGitRelativePath(relativePath) {
|
|
189
|
+
if (relativePath.length === 0 ||
|
|
190
|
+
relativePath.startsWith("/") ||
|
|
191
|
+
relativePath === ".." ||
|
|
192
|
+
relativePath.startsWith("../") ||
|
|
193
|
+
relativePath.includes("/../")) {
|
|
194
|
+
throw new Error(`Unsafe git path returned while preparing ci act workspace: ${relativePath}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function assertExistingDirectory(path, label) {
|
|
198
|
+
if (!existsSync(path) || !lstatSync(path).isDirectory()) {
|
|
199
|
+
throw new Error(`Cannot prepare ci act workspace: ${label} is missing or unreadable: ${path}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function git(cwd, args) {
|
|
203
|
+
return gitRaw(cwd, args).trim();
|
|
204
|
+
}
|
|
205
|
+
function tryGit(cwd, args) {
|
|
206
|
+
try {
|
|
207
|
+
return git(cwd, args);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function gitRaw(cwd, args) {
|
|
214
|
+
return execFileSync("git", [...args], {
|
|
215
|
+
cwd,
|
|
216
|
+
encoding: "utf8",
|
|
217
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
218
|
+
});
|
|
219
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CliCommand } from "@webpresso/cli-contract";
|
|
2
2
|
export declare const blueprintCommands: {
|
|
3
3
|
audit: CliCommand<Record<string, unknown>>;
|
|
4
|
+
canonicalize: CliCommand<Record<string, unknown>>;
|
|
4
5
|
exec: CliCommand<Record<string, unknown>>;
|
|
5
6
|
finalize: CliCommand<Record<string, unknown>>;
|
|
6
7
|
list: CliCommand<Record<string, unknown>>;
|
|
@@ -35,6 +35,7 @@ function createBlueprintAuditCommand() {
|
|
|
35
35
|
}
|
|
36
36
|
export const blueprintCommands = {
|
|
37
37
|
audit: createBlueprintAuditCommand(),
|
|
38
|
+
canonicalize: placeholderCommand(SCOPE, "canonicalize", "Canonicalize a flat blueprint to folder shape"),
|
|
38
39
|
exec: placeholderGroup(SCOPE, "exec", "Execute a blueprint", {
|
|
39
40
|
logs: placeholderCommand(SCOPE, "logs", "Show blueprint execution logs"),
|
|
40
41
|
resume: placeholderCommand(SCOPE, "resume", "Resume blueprint execution"),
|
package/dist/esm/cli/cli.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Lazy-loads subcommand modules based on the first argv to keep startup
|
|
6
6
|
* cheap. Modeled on apps/cli-wp/src/cli.ts.
|
|
7
7
|
*/
|
|
8
|
-
declare const SUPPORTED_COMMANDS: readonly ["blueprint", "browser", "dash", "dash-helper-start", "dash-helper-complete", "claude", "codex", "grok", "opencode", "yolo", "config", "secrets", "roadmap", "status", "review", "sync", "audit", "qa", "ultragoal", "compile", "rule", "skill", "skills", "docs", "setup", "init", "dev", "deploy", "preview", "cleanup", "migrate", "doctor", "err", "test", "e2e", "ci", "ci-preflight", "typecheck", "lint", "format", "logs", "session-id", "session-info", "session", "tech-debt", "pr", "fleet", "worktree", "mcp", "hook", "hooks", "self-install-guard", "gain", "bench", "install", "add", "remove", "update", "exec", "run"];
|
|
8
|
+
declare const SUPPORTED_COMMANDS: readonly ["blueprint", "browser", "dash", "dash-helper-start", "dash-helper-complete", "claude", "codex", "grok", "opencode", "yolo", "config", "secrets", "roadmap", "status", "review", "sync", "audit", "qa", "ultragoal", "compile", "rule", "skill", "skills", "docs", "setup", "init", "dev", "deploy", "preview", "cleanup", "migrate", "doctor", "err", "test", "e2e", "ci", "ci-preflight", "public:readiness", "typecheck", "lint", "format", "logs", "session-id", "session-info", "session", "tech-debt", "pr", "fleet", "worktree", "mcp", "hook", "hooks", "self-install-guard", "optional-tool-refresh", "gain", "bench", "install", "add", "remove", "update", "exec", "run"];
|
|
9
9
|
export type SupportedCommand = (typeof SUPPORTED_COMMANDS)[number];
|
|
10
10
|
type RootHelpEntry = {
|
|
11
11
|
readonly command: string;
|
package/dist/esm/cli/cli.js
CHANGED
|
@@ -55,6 +55,7 @@ const SUPPORTED_COMMANDS = [
|
|
|
55
55
|
"e2e",
|
|
56
56
|
"ci",
|
|
57
57
|
"ci-preflight",
|
|
58
|
+
"public:readiness",
|
|
58
59
|
"typecheck",
|
|
59
60
|
"lint",
|
|
60
61
|
"format",
|
|
@@ -70,6 +71,7 @@ const SUPPORTED_COMMANDS = [
|
|
|
70
71
|
"hook",
|
|
71
72
|
"hooks",
|
|
72
73
|
"self-install-guard",
|
|
74
|
+
"optional-tool-refresh",
|
|
73
75
|
"gain",
|
|
74
76
|
"bench",
|
|
75
77
|
"install",
|
|
@@ -111,6 +113,10 @@ const ROOT_HELP_CORE_ENTRIES = [
|
|
|
111
113
|
command: "ci-preflight",
|
|
112
114
|
description: "Run the locally-runnable required CI checks fail-fast (the pre-push gate)",
|
|
113
115
|
},
|
|
116
|
+
{
|
|
117
|
+
command: "public:readiness",
|
|
118
|
+
description: "Run the public package readiness gate through the portable wp surface",
|
|
119
|
+
},
|
|
114
120
|
{ command: "logs", description: "Print persisted raw output from recent quality runs" },
|
|
115
121
|
{ command: "dev", description: "Run a manifest-backed development target" },
|
|
116
122
|
{ command: "status", description: "Show unified local readiness and next action" },
|
|
@@ -364,6 +370,10 @@ const COMMAND_REGISTRARS = {
|
|
|
364
370
|
const { registerCiPreflightCommand } = await import("./commands/ci-preflight.js");
|
|
365
371
|
registerCiPreflightCommand(cli);
|
|
366
372
|
},
|
|
373
|
+
"public:readiness": async (cli) => {
|
|
374
|
+
const { registerPublicReadinessCommand } = await import("./commands/public-readiness.js");
|
|
375
|
+
registerPublicReadinessCommand(cli);
|
|
376
|
+
},
|
|
367
377
|
typecheck: async (cli) => {
|
|
368
378
|
const { registerTypecheckCommand } = await import("./commands/typecheck.js");
|
|
369
379
|
registerTypecheckCommand(cli);
|
|
@@ -422,6 +432,15 @@ const COMMAND_REGISTRARS = {
|
|
|
422
432
|
const { registerSelfInstallGuardCommand } = await import("./commands/self-install-guard.js");
|
|
423
433
|
registerSelfInstallGuardCommand(cli);
|
|
424
434
|
},
|
|
435
|
+
"optional-tool-refresh": async (cli) => {
|
|
436
|
+
cli
|
|
437
|
+
.command("optional-tool-refresh <tool> [...args]", "Internal detached optional-tool freshness worker")
|
|
438
|
+
.allowUnknownOptions()
|
|
439
|
+
.action(async (tool, args = []) => {
|
|
440
|
+
const { runOptionalToolRefreshWorker } = await import("./optional-tool-freshness.js");
|
|
441
|
+
process.exitCode = runOptionalToolRefreshWorker([tool, ...args]);
|
|
442
|
+
});
|
|
443
|
+
},
|
|
425
444
|
gain: async (cli) => {
|
|
426
445
|
const { registerGainCommand } = await import("./commands/gain/index.js");
|
|
427
446
|
registerGainCommand(cli);
|
|
@@ -636,6 +655,21 @@ export async function main() {
|
|
|
636
655
|
console.error(formatUnknownCommandError(command, SUPPORTED_COMMANDS));
|
|
637
656
|
return 1;
|
|
638
657
|
}
|
|
658
|
+
// `wp run wait` is the read-only workflow-run waiter, intercepted before the
|
|
659
|
+
// package-manager `run` facade (which maps `wp run <script>` to `vp run
|
|
660
|
+
// <script>`). Without this, `wait` would be treated as a package script name.
|
|
661
|
+
// Errors resolve to an exit code here, mirroring main()'s catch below, so a
|
|
662
|
+
// bad flag never rejects the main() promise.
|
|
663
|
+
if (resolvedCommand === "run" && argv[3] === "wait") {
|
|
664
|
+
const { runRunWaitCommand } = await import("./commands/run-wait.js");
|
|
665
|
+
try {
|
|
666
|
+
return await runRunWaitCommand(argv.slice(4));
|
|
667
|
+
}
|
|
668
|
+
catch (error) {
|
|
669
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
670
|
+
return 1;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
639
673
|
await COMMAND_REGISTRARS[resolvedCommand](cli, resolvedCommand);
|
|
640
674
|
if (resolvedCommand === "session") {
|
|
641
675
|
const { runSessionCommand } = await import("./commands/session.js");
|
|
@@ -2,6 +2,7 @@ import type { CAC } from "cac";
|
|
|
2
2
|
import { type DashPermissionMode, type DashProvider } from "#cli/commands/dash/provider-capabilities.js";
|
|
3
3
|
import { type RuntimeCommandOptions } from "#runtime/executor.js";
|
|
4
4
|
import { type SecretsConfig } from "#runtime/secrets-config.js";
|
|
5
|
+
import { resolveOpencodeAccountsGracefully } from "#runtime/opencode-account-materializer.js";
|
|
5
6
|
export declare const AGENT_LAUNCH_COMMANDS: readonly ["claude", "codex", "grok", "opencode"];
|
|
6
7
|
export type AgentLaunchCommand = DashProvider;
|
|
7
8
|
export declare const DEFAULT_AGENT_SECRET_PROFILE = "preview";
|
|
@@ -18,6 +19,10 @@ export interface AgentLaunchDeps {
|
|
|
18
19
|
error?: Error;
|
|
19
20
|
};
|
|
20
21
|
readonly ensureCodexSkillSurface?: (cwd: string, env?: NodeJS.ProcessEnv) => string | null;
|
|
22
|
+
readonly resolveOpencodeAccounts?: typeof resolveOpencodeAccountsGracefully;
|
|
23
|
+
readonly materializeGlobalOpencodeAuth?: (key: string) => void;
|
|
24
|
+
readonly readActiveKey?: () => string | undefined;
|
|
25
|
+
readonly recordCooldown?: (canonicalId: string) => Promise<unknown>;
|
|
21
26
|
}
|
|
22
27
|
export declare function buildDefaultAgentArgs(command: AgentLaunchCommand, args?: readonly string[], permissionMode?: DashPermissionMode): readonly string[];
|
|
23
28
|
export declare function isAgentLaunchCommand(command: string | undefined): command is AgentLaunchCommand;
|
|
@@ -29,5 +34,5 @@ export declare function buildAgentRuntimeCommandOptions(input: {
|
|
|
29
34
|
readonly env?: NodeJS.ProcessEnv;
|
|
30
35
|
readonly secretsConfig: SecretsConfig | null;
|
|
31
36
|
}): RuntimeCommandOptions;
|
|
32
|
-
export declare function runAgentLaunchCommand(command: AgentLaunchCommand, args?: readonly string[], options?: AgentLaunchOptions, deps?: AgentLaunchDeps): number
|
|
37
|
+
export declare function runAgentLaunchCommand(command: AgentLaunchCommand, args?: readonly string[], options?: AgentLaunchOptions, deps?: AgentLaunchDeps): Promise<number>;
|
|
33
38
|
export declare function registerAgentLaunchCommand(cli: CAC, command: AgentLaunchCommand): void;
|
|
@@ -7,6 +7,11 @@ import { WP_AGENT_LAUNCHED_VIA_WP_ENV, WP_AGENT_LAUNCHED_VIA_WP_VALUE, } from "#
|
|
|
7
7
|
import { readSecretsConfig } from "#runtime/secrets-config.js";
|
|
8
8
|
import { resolveFreshAgentKitPackageRoot } from "#cli/commands/init/package-root";
|
|
9
9
|
import { ensureCodexUserPlugin } from "#cli/commands/init/scaffolders/codex-plugin/index.js";
|
|
10
|
+
import { resolveOpencodeAccountsGracefully } from "#runtime/opencode-account-materializer.js";
|
|
11
|
+
import { loadOpencodeAccountAvailability, pruneExpiredOpencodeAccountSuppressions, } from "#review/availability.js";
|
|
12
|
+
import { selectActiveOpencodeAccount } from "#review/opencode-account.js";
|
|
13
|
+
import { materializeOpencodeGoAuth } from "#review/opencode-auth.js";
|
|
14
|
+
import { describeOpencodeRotate, OPENCODE_ROTATE_FLAG, rotateActiveOpencodeAccount, } from "#cli/commands/opencode-rotate.js";
|
|
10
15
|
export const AGENT_LAUNCH_COMMANDS = DASH_PROVIDERS;
|
|
11
16
|
export const DEFAULT_AGENT_SECRET_PROFILE = "preview";
|
|
12
17
|
export const AGENT_SECRET_PROFILE_ENV = "WP_AGENT_SECRET_PROFILE";
|
|
@@ -83,7 +88,67 @@ function ensureCodexSkillSurface(cwd, env = process.env) {
|
|
|
83
88
|
return `Codex plugin refresh failed (${result.kind}). Run \`wp install codex\` and retry.`;
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Choose the active opencode-go account and materialize its key into the
|
|
93
|
+
* global opencode `auth.json` before the TUI launches.
|
|
94
|
+
*
|
|
95
|
+
* Honest limitation: interactive opencode is a long-lived TUI — the account is
|
|
96
|
+
* chosen once at launch and a mid-session dollar-cap is NOT auto-swapped. A
|
|
97
|
+
* plain relaunch does NOT rotate either: nothing on this path records a
|
|
98
|
+
* cooldown, so an exhausted account stays "first non-suppressed" and gets
|
|
99
|
+
* re-picked every time. Run `wp opencode --wp-rotate` to cool the current
|
|
100
|
+
* account and launch on the next one. Only the review gate does automatic
|
|
101
|
+
* in-flight failover, because only it can observe the usage-limit response.
|
|
102
|
+
*
|
|
103
|
+
* Never throws: a Doppler outage or materialize failure must not block the
|
|
104
|
+
* TUI from launching, so every failure is logged and swallowed.
|
|
105
|
+
*/
|
|
106
|
+
function selectAndMaterializeOpencodeAccount(cwd, deps, secretProfile) {
|
|
107
|
+
try {
|
|
108
|
+
const resolution = (deps.resolveOpencodeAccounts ?? resolveOpencodeAccountsGracefully)({
|
|
109
|
+
cwd,
|
|
110
|
+
secretProfile,
|
|
111
|
+
});
|
|
112
|
+
if (!resolution.ok)
|
|
113
|
+
return;
|
|
114
|
+
const pruned = pruneExpiredOpencodeAccountSuppressions(loadOpencodeAccountAvailability());
|
|
115
|
+
const selection = selectActiveOpencodeAccount(resolution.accounts, pruned.state);
|
|
116
|
+
if (!selection)
|
|
117
|
+
return;
|
|
118
|
+
(deps.materializeGlobalOpencodeAuth ?? ((key) => materializeOpencodeGoAuth(key)))(selection.account.key);
|
|
119
|
+
if (selection.cooled) {
|
|
120
|
+
console.error(`wp opencode: all OpenCode Go accounts are within their usage cooldown; launching on the soonest-expiring account (${selection.account.id}).`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
125
|
+
console.error(`wp opencode: account selection failed, launching without it (${message}).`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Run the opencode-only pre-launch credential step and return the args to
|
|
130
|
+
* forward to the binary. `--wp-rotate` is consumed here and must never reach
|
|
131
|
+
* opencode, which would treat it as a prompt.
|
|
132
|
+
*/
|
|
133
|
+
async function prepareOpencodeLaunch(cwd, args, secretsConfig, deps, secretProfile) {
|
|
134
|
+
if (!args.includes(OPENCODE_ROTATE_FLAG)) {
|
|
135
|
+
if (secretsConfig !== null)
|
|
136
|
+
selectAndMaterializeOpencodeAccount(cwd, deps, secretProfile);
|
|
137
|
+
return args;
|
|
138
|
+
}
|
|
139
|
+
const outcome = await rotateActiveOpencodeAccount(cwd, secretProfile, deps);
|
|
140
|
+
for (const line of describeOpencodeRotate(outcome))
|
|
141
|
+
console.error(line);
|
|
142
|
+
// A successful rotation already materialized the next account, so the normal
|
|
143
|
+
// launch-time selection is skipped to avoid a second, redundant write. When
|
|
144
|
+
// rotation could not run, fall through to that selection so the launch still
|
|
145
|
+
// gets the best account it can rather than whatever the store happens to hold.
|
|
146
|
+
if (outcome.kind === "unavailable" && secretsConfig !== null) {
|
|
147
|
+
selectAndMaterializeOpencodeAccount(cwd, deps, secretProfile);
|
|
148
|
+
}
|
|
149
|
+
return args.filter((arg) => arg !== OPENCODE_ROTATE_FLAG);
|
|
150
|
+
}
|
|
151
|
+
export async function runAgentLaunchCommand(command, args = [], options = {}, deps = {}) {
|
|
87
152
|
const cwd = options.cwd ?? process.cwd();
|
|
88
153
|
if (command === "codex") {
|
|
89
154
|
const skillSurfaceError = (deps.ensureCodexSkillSurface ?? ensureCodexSkillSurface)(cwd, options.env ?? process.env);
|
|
@@ -93,9 +158,19 @@ export function runAgentLaunchCommand(command, args = [], options = {}, deps = {
|
|
|
93
158
|
}
|
|
94
159
|
}
|
|
95
160
|
const secretsConfig = (deps.readSecretsConfig ?? readSecretsConfig)(cwd);
|
|
161
|
+
// Account discovery must resolve secrets through the same profile the launch
|
|
162
|
+
// itself uses (below, via buildAgentRuntimeCommandOptions). Without it no
|
|
163
|
+
// environment selector reaches the secret manager, which then falls back to
|
|
164
|
+
// its own ambient, path-scoped config — that resolves only in a checkout that
|
|
165
|
+
// happens to sit under the scoped directory and fails in every managed
|
|
166
|
+
// worktree, CI clone, and fresh checkout.
|
|
167
|
+
const secretProfile = resolveAgentSecretProfile(options.env ?? process.env);
|
|
168
|
+
const launchArgs = command === "opencode"
|
|
169
|
+
? await prepareOpencodeLaunch(cwd, args, secretsConfig, deps, secretProfile)
|
|
170
|
+
: args;
|
|
96
171
|
const runtimeOptions = buildAgentRuntimeCommandOptions({
|
|
97
172
|
command,
|
|
98
|
-
args,
|
|
173
|
+
args: launchArgs,
|
|
99
174
|
cwd,
|
|
100
175
|
env: options.env ?? process.env,
|
|
101
176
|
secretsConfig,
|
|
@@ -108,8 +183,11 @@ export function runAgentLaunchCommand(command, args = [], options = {}, deps = {
|
|
|
108
183
|
return result.status ?? 1;
|
|
109
184
|
}
|
|
110
185
|
export function registerAgentLaunchCommand(cli, command) {
|
|
186
|
+
const rotateHint = command === "opencode"
|
|
187
|
+
? ` (pass \`${OPENCODE_ROTATE_FLAG}\` to cool the current OpenCode Go account and launch on the next one)`
|
|
188
|
+
: "";
|
|
111
189
|
cli
|
|
112
|
-
.command(`${command} [...args]`, `Launch ${command} with provider-backed agent secrets and safe-by-default permissions (run \`wp yolo on\` for persistent full-auto)`)
|
|
190
|
+
.command(`${command} [...args]`, `Launch ${command} with provider-backed agent secrets and safe-by-default permissions (run \`wp yolo on\` for persistent full-auto)${rotateHint}`)
|
|
113
191
|
.allowUnknownOptions()
|
|
114
|
-
.action((args = []) => runAgentLaunchCommand(command, args, { cwd: process.cwd() }));
|
|
192
|
+
.action(async (args = []) => await runAgentLaunchCommand(command, args, { cwd: process.cwd() }));
|
|
115
193
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAuditKindDescriptor } from "#audit/registry";
|
|
1
2
|
function optionsForCompositeRepoAudit(name, options) {
|
|
2
3
|
if (name !== "reference-parity-matrix" || options.strict !== true)
|
|
3
4
|
return options;
|
|
@@ -94,7 +95,13 @@ export async function runAuditDispatch(auditKind, targets, options, deps) {
|
|
|
94
95
|
let allOk = true;
|
|
95
96
|
for (const name of deps.knownRepoKinds) {
|
|
96
97
|
const result = await deps.runRepoAudit(name, root, optionsForCompositeRepoAudit(name, options));
|
|
97
|
-
|
|
98
|
+
// Signal-class kinds (registry.ts gateClass) still run and still
|
|
99
|
+
// report their findings via `results` below, but a failing signal
|
|
100
|
+
// kind must not flip the umbrella — only blocking-class failures do.
|
|
101
|
+
// Unclassified kinds default to blocking, matching the registry's
|
|
102
|
+
// own descriptor() default.
|
|
103
|
+
const gateClass = getAuditKindDescriptor(name)?.gateClass ?? "blocking";
|
|
104
|
+
if (!result.ok && gateClass !== "signal")
|
|
98
105
|
allOk = false;
|
|
99
106
|
results.push({ name, result });
|
|
100
107
|
}
|
|
@@ -15,6 +15,7 @@ import { createCliLogSink } from "#cli/commands/quality-log-store.js";
|
|
|
15
15
|
import { emitCliCommandOutput, runLoggedChildCommand } from "#cli/commands/quality-runner.js";
|
|
16
16
|
export const REPO_AUDIT_REGISTRY = {
|
|
17
17
|
"catalog-drift": async (root) => (await import("#audit/repo-guardrails")).auditCatalogDrift(root),
|
|
18
|
+
"typescript-version": async (root) => (await import("#audit/typescript-version")).auditTypescriptVersion(root),
|
|
18
19
|
"package-surface": async (root) => (await import("#audit/package-surface")).auditPackageSurface(root),
|
|
19
20
|
"command-surface": async (root) => (await import("#audit/command-surface")).auditCommandSurface(root),
|
|
20
21
|
"reference-parity-matrix": async (root, options) => (await import("#audit/reference-parity-matrix")).auditReferenceParityMatrix(root, undefined, {
|
|
@@ -123,6 +124,10 @@ export const REPO_AUDIT_REGISTRY = {
|
|
|
123
124
|
"secrets-config": async (root) => (await import("#audit/secrets-config")).auditSecretsConfig(root),
|
|
124
125
|
"consumer-agent-kit-dependency": async (root) => (await import("#audit/consumer-agent-kit-dependency")).auditConsumerAgentKitDependency(root),
|
|
125
126
|
"ci-test-perf": async (root) => (await import("#audit/ci-test-perf")).auditCiTestPerf(root),
|
|
127
|
+
"ci-guardrails-wiring": async (root) => (await import("#audit/ci-guardrails-wiring")).auditCiGuardrailsWiring(root),
|
|
128
|
+
"test-scan-perf": async (root, options) => (await import("#audit/test-scan-perf")).auditTestScanPerf(root, {
|
|
129
|
+
affectedFiles: options.affectedFiles,
|
|
130
|
+
}),
|
|
126
131
|
"worktree-main-ownership": async (root) => (await import("#audit/worktree-main-ownership")).auditWorktreeMainOwnership(root),
|
|
127
132
|
sast: async (root, options) => (await import("#audit/sast")).auditSast(root, {
|
|
128
133
|
bin: options.bin,
|
|
@@ -137,6 +142,7 @@ export const REPO_AUDIT_REGISTRY = {
|
|
|
137
142
|
draftTechDebt: options.draftTechDebt,
|
|
138
143
|
}),
|
|
139
144
|
"harness-overlay-evidence": async (root) => (await import("#audit/harness-overlay-evidence")).auditHarnessOverlayEvidence(root),
|
|
145
|
+
"host-substitution-risk": async (root) => (await import("#audit/host-substitution-risk")).auditHostSubstitutionRisk(root),
|
|
140
146
|
"legacy-workflow-identity": async (root) => (await import("#audit/legacy-workflow-identity")).auditLegacyWorkflowIdentity(root),
|
|
141
147
|
rules: async (root) => runContentAudit(root, "rule"),
|
|
142
148
|
skills: async (root) => runContentAudit(root, "skill"),
|
|
@@ -464,22 +470,31 @@ export function registerAuditCommand(cli) {
|
|
|
464
470
|
}
|
|
465
471
|
case "aggregate-result": {
|
|
466
472
|
const { formatRepoAuditReport } = await import("#audit/repo-guardrails");
|
|
473
|
+
const isSignal = (name) => getAuditKindDescriptor(name)?.gateClass === "signal";
|
|
467
474
|
for (const { name, result } of outcome.results) {
|
|
468
475
|
if (result.ok)
|
|
469
476
|
continue;
|
|
470
|
-
|
|
477
|
+
const label = isSignal(name) ? `${name} (signal, non-blocking)` : name;
|
|
478
|
+
sink.write(`\n[${label}]\n${formatRepoAuditReport(result)}\n`);
|
|
471
479
|
}
|
|
472
480
|
const failed = outcome.results.filter(({ result }) => !result.ok);
|
|
481
|
+
const blockingFailed = failed.filter(({ name }) => !isSignal(name));
|
|
482
|
+
const signalFailed = failed.filter(({ name }) => isSignal(name));
|
|
473
483
|
if (failed.length > 0) {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
.join(", ")}
|
|
484
|
+
const parts = [];
|
|
485
|
+
if (blockingFailed.length > 0) {
|
|
486
|
+
parts.push(`${blockingFailed.length} blocking: ${blockingFailed.map(({ name }) => name).join(", ")}`);
|
|
487
|
+
}
|
|
488
|
+
if (signalFailed.length > 0) {
|
|
489
|
+
parts.push(`${signalFailed.length} signal/non-blocking: ${signalFailed.map(({ name }) => name).join(", ")}`);
|
|
490
|
+
}
|
|
491
|
+
sink.write(`\nguardrails: ${failed.length}/${outcome.results.length} audits reported findings (${parts.join("; ")})\n`);
|
|
477
492
|
}
|
|
478
493
|
exitCode = outcome.code;
|
|
479
494
|
summary =
|
|
480
495
|
outcome.code === 0
|
|
481
496
|
? "audit guardrails passed"
|
|
482
|
-
: `audit guardrails failed (${
|
|
497
|
+
: `audit guardrails failed (${blockingFailed.length}/${outcome.results.length})`;
|
|
483
498
|
break;
|
|
484
499
|
}
|
|
485
500
|
case "quality-exit": {
|
|
@@ -9,6 +9,7 @@ import { setTimeout as delay } from "node:timers/promises";
|
|
|
9
9
|
import { applyRuntimeProgressSnapshot, buildBlueprintProgressBridgeState, normalizeRuntimeTaskSnapshot, projectBlueprintLifecycleFromRuntime, readBlueprintExecutionArtifacts, runtimeStateSnapshotSchema, writeBlueprintExecutionArtifacts, writeBlueprintExecutionMetadata, } from "#index";
|
|
10
10
|
import { applyBlueprintLifecycleToFile, parseBlueprint } from "#local";
|
|
11
11
|
import { resolveBlueprintRoot } from "#utils/blueprint-root";
|
|
12
|
+
import { resolveBlueprintDocumentIdentity } from "#utils/document-paths.js";
|
|
12
13
|
import { clearBlueprintExecutionState, persistBlueprintExecutionArtifacts, persistBlueprintExecutionMetadata, persistBlueprintProgressBridgeState, readBlueprintExecutionArtifactsState, readBlueprintExecutionState, readBlueprintProgressBridgeState, readBlueprintRuntimeSnapshot, writeBlueprintRuntimeSnapshot, } from "./execution-io.js";
|
|
13
14
|
import { assertCompletionEvidence, mergeExecutionArtifacts, } from "./execution-state.js";
|
|
14
15
|
import { buildBlueprintExecutionControlCommand, buildBlueprintExecutionLaunchCommand, buildBlueprintExecutionRuntimePaths, buildBlueprintLaunchSpec, buildListTasksVerificationCommand, isMissingFileError, nowIsoTimestamp, parseRuntimeApiResponse, parseTeamExecutionId, resolveControlStatus, toProjectRelativePath, uniqueStrings, } from "./execution-spec.js";
|
|
@@ -114,22 +115,33 @@ export async function reconcileBlueprintRuntimeSnapshot(projectRoot, blueprintPa
|
|
|
114
115
|
const currentStatus = currentDir.split(blueprintsRoot + path.sep)[1]?.split(path.sep)[0];
|
|
115
116
|
const relativeSlug = slug.replace(/^[^/]+\//u, "");
|
|
116
117
|
const targetDir = path.join(blueprintsRoot, nextStatus, relativeSlug);
|
|
117
|
-
|
|
118
|
+
// A flat document owns only its own file; renaming its parent directory
|
|
119
|
+
// would move the entire lifecycle state directory. Lifecycle moves are
|
|
120
|
+
// shape-preserving: flat stays flat, folder moves as a folder.
|
|
121
|
+
const isFlatDocument = resolveBlueprintDocumentIdentity(blueprintsRoot, blueprintPath)?.shape === "flat";
|
|
122
|
+
const targetPath = isFlatDocument ? `${targetDir}.md` : path.join(targetDir, "_overview.md");
|
|
123
|
+
const documentMoved = blueprintPath !== targetPath;
|
|
118
124
|
const nextMarkdown = completionEvidence
|
|
119
125
|
? writeBlueprintExecutionArtifacts(result.markdown, completionEvidence)
|
|
120
126
|
: result.markdown;
|
|
121
|
-
if (
|
|
127
|
+
if (documentMoved && currentStatus && currentStatus !== nextStatus) {
|
|
122
128
|
const { mkdir, rename } = await import("node:fs/promises");
|
|
123
|
-
|
|
124
|
-
|
|
129
|
+
if (isFlatDocument) {
|
|
130
|
+
await mkdir(path.dirname(targetPath), { recursive: true });
|
|
131
|
+
await rename(blueprintPath, targetPath);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
await mkdir(path.dirname(targetDir), { recursive: true });
|
|
135
|
+
await rename(currentDir, targetDir);
|
|
136
|
+
}
|
|
125
137
|
await writeFile(targetPath, nextMarkdown, "utf-8");
|
|
126
138
|
}
|
|
127
139
|
else {
|
|
128
140
|
await writeFile(blueprintPath, nextMarkdown, "utf-8");
|
|
129
141
|
}
|
|
130
142
|
return {
|
|
131
|
-
moved:
|
|
132
|
-
path:
|
|
143
|
+
moved: documentMoved,
|
|
144
|
+
path: documentMoved ? targetPath : blueprintPath,
|
|
133
145
|
status: result.execution.status,
|
|
134
146
|
};
|
|
135
147
|
}
|