@webpresso/agent-kit 3.1.30 → 3.3.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 +183 -20
- package/catalog/AGENTS.md.tpl +3 -3
- package/catalog/agent/agents/implementer.md +45 -0
- package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
- package/catalog/agent/rules/pre-implementation.md +28 -1
- package/catalog/agent/rules/supported-agent-clis.md +9 -0
- package/catalog/agent/rules/typescript-version.md +50 -0
- package/catalog/agent/skills/codex/SKILL.md +25 -1
- package/catalog/agent/skills/verify/SKILL.md +4 -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 +4 -0
- package/dist/esm/audit/blueprint-trust.js +14 -10
- package/dist/esm/audit/changeset-evidence.d.ts +23 -0
- package/dist/esm/audit/changeset-evidence.js +30 -0
- package/dist/esm/audit/changeset-required.d.ts +10 -0
- package/dist/esm/audit/changeset-required.js +73 -0
- package/dist/esm/audit/ci-guardrails-detection.d.ts +27 -0
- package/dist/esm/audit/ci-guardrails-detection.js +68 -0
- package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
- package/dist/esm/audit/ci-guardrails-wiring.js +80 -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 +13 -1
- 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 +101 -2
- package/dist/esm/blueprint/core/schema.d.ts +1 -0
- package/dist/esm/blueprint/core/schema.js +26 -0
- 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 +87 -20
- package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
- package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
- 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 +68 -12
- package/dist/esm/blueprint/lifecycle/rollout-anchor.d.ts +97 -0
- package/dist/esm/blueprint/lifecycle/rollout-anchor.js +161 -0
- 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/sync/client.d.ts +2 -1
- package/dist/esm/blueprint/sync/client.js +1 -1
- 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/dossier.d.ts +1 -0
- package/dist/esm/blueprint/trust/dossier.js +40 -6
- 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 +74 -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 +15 -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 +43 -0
- package/dist/esm/cli/commands/agent-launch.d.ts +8 -1
- package/dist/esm/cli/commands/agent-launch.js +93 -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 +21 -5
- package/dist/esm/cli/commands/blueprint/execution.js +18 -6
- package/dist/esm/cli/commands/blueprint/mutations.js +59 -40
- 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 +13 -1
- package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
- package/dist/esm/cli/commands/ci-preflight.js +30 -6
- 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/doctor.js +5 -0
- 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.js +2 -2
- package/dist/esm/cli/commands/init/convergence-apply.d.ts +88 -0
- package/dist/esm/cli/commands/init/convergence-apply.js +325 -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 +3 -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/package-root.d.ts +7 -0
- package/dist/esm/cli/commands/init/package-root.js +10 -2
- 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 +20 -0
- package/dist/esm/cli/commands/init/scaffold-base-kit.js +61 -5
- 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 +54 -24
- 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 +288 -202
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +22 -0
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +230 -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/opencode-probe.d.ts +107 -0
- package/dist/esm/cli/commands/opencode-probe.js +323 -0
- package/dist/esm/cli/commands/opencode-rotate.d.ts +72 -0
- package/dist/esm/cli/commands/opencode-rotate.js +147 -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-runner.js +3 -3
- package/dist/esm/cli/commands/review.d.ts +35 -3
- package/dist/esm/cli/commands/review.js +751 -209
- 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/rust-check.d.ts +24 -0
- package/dist/esm/cli/commands/rust-check.js +110 -0
- 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/typecheck.d.ts +1 -0
- package/dist/esm/cli/commands/typecheck.js +30 -1
- package/dist/esm/cli/commands/worktree/router-dispatch.d.ts +6 -0
- package/dist/esm/cli/commands/worktree/router-dispatch.js +126 -9
- package/dist/esm/cli/commands/worktree/router.js +10 -0
- package/dist/esm/cli/direct-provider-launch.js +9 -5
- 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 +5 -3
- package/dist/esm/hooks/doctor.js +67 -16
- 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 +54 -0
- 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/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.js +6 -1
- 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 +50 -9
- package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
- package/dist/esm/hooks/stop/qa-changed-files.js +92 -0
- package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
- package/dist/esm/mcp/blueprint/handlers/document-mutations.d.ts +5 -0
- package/dist/esm/mcp/blueprint/handlers/document-mutations.js +109 -11
- 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 +42 -0
- package/dist/esm/mcp/tools/audits.d.ts +4 -0
- 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-fetch-and-index.d.ts +1 -1
- 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/package.json +2 -0
- package/dist/esm/platform/client.d.ts +7 -1
- package/dist/esm/platform/github-contract-source.d.ts +2 -1
- package/dist/esm/pr-description/contract.js +24 -4
- package/dist/esm/review/authority.js +27 -14
- package/dist/esm/review/availability.d.ts +33 -0
- package/dist/esm/review/availability.js +122 -20
- 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.d.ts +11 -1
- package/dist/esm/review/execution/adapters.js +36 -10
- package/dist/esm/review/execution/artifacts.d.ts +1 -1
- 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 +121 -21
- package/dist/esm/review/execution/supervisor.js +36 -4
- package/dist/esm/review/execution/types.d.ts +9 -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 +25 -0
- package/dist/esm/review/subject.js +116 -26
- package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
- package/dist/esm/runtime/opencode-account-materializer.js +33 -0
- package/dist/esm/rust/affected-manifests.d.ts +38 -0
- package/dist/esm/rust/affected-manifests.js +69 -0
- package/dist/esm/session-memory/fetch-index.d.ts +1 -1
- package/dist/esm/status/snapshot.js +32 -25
- 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 -2
- package/dist/esm/test-helpers/global-setup.js +79 -32
- package/dist/esm/typecheck/planner.d.ts +9 -1
- package/dist/esm/typecheck/planner.js +31 -0
- 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/orphan-scan.d.ts +50 -0
- package/dist/esm/worktrees/orphan-scan.js +211 -0
- package/dist/esm/worktrees/registry.d.ts +8 -0
- package/dist/esm/worktrees/registry.js +18 -3
- package/package.json +18 -13
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const RUN_WAIT_HELP = "wp run wait \u2014 read-only GitHub workflow-run waiter (push/dispatch runs, e.g. production deploys on main)\n\nUsage:\n wp run wait --run-id <id> [options]\n wp run wait --sha <head-sha> [--workflow <file-or-name>] [options]\n\nSelector (exactly one required):\n --run-id <id> Watch a specific workflow run by database id\n --sha <sha> Watch the newest run for a head commit SHA\n --workflow <file|name> Filter --sha selection to one workflow\n\nOptions:\n --until <target> run-terminal (default) | all-jobs-terminal\n --poll-interval-ms <n> Poll interval (default 15000)\n --timeout-ms <n> Overall watch deadline (max 300000, default 120000)\n --max-output-bytes <n> Per-command output budget\n --cwd <path> Project root or descendant\n --json Emit exactly one JSON document (default output)\n -h, --help Show this help\n\nRead-only: issues only `gh` GET calls; never mutates run state.";
|
|
2
|
+
export declare function runRunWaitCommand(args: readonly string[]): Promise<number>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { RUN_WAIT_UNTIL_VALUES, runRunWait, } from "#mcp/tools/run-wait.js";
|
|
2
|
+
// `wp run wait` is intercepted in cli.ts before the package-manager `run`
|
|
3
|
+
// facade (which maps `wp run <script>` to `vp run <script>`). This module owns
|
|
4
|
+
// only the `wait` subcommand and keeps arg parsing dependency-free so the
|
|
5
|
+
// interception path stays cheap.
|
|
6
|
+
export const RUN_WAIT_HELP = `wp run wait — read-only GitHub workflow-run waiter (push/dispatch runs, e.g. production deploys on main)
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
wp run wait --run-id <id> [options]
|
|
10
|
+
wp run wait --sha <head-sha> [--workflow <file-or-name>] [options]
|
|
11
|
+
|
|
12
|
+
Selector (exactly one required):
|
|
13
|
+
--run-id <id> Watch a specific workflow run by database id
|
|
14
|
+
--sha <sha> Watch the newest run for a head commit SHA
|
|
15
|
+
--workflow <file|name> Filter --sha selection to one workflow
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--until <target> run-terminal (default) | all-jobs-terminal
|
|
19
|
+
--poll-interval-ms <n> Poll interval (default 15000)
|
|
20
|
+
--timeout-ms <n> Overall watch deadline (max 300000, default 120000)
|
|
21
|
+
--max-output-bytes <n> Per-command output budget
|
|
22
|
+
--cwd <path> Project root or descendant
|
|
23
|
+
--json Emit exactly one JSON document (default output)
|
|
24
|
+
-h, --help Show this help
|
|
25
|
+
|
|
26
|
+
Read-only: issues only \`gh\` GET calls; never mutates run state.`;
|
|
27
|
+
function parsePositiveInteger(value, name) {
|
|
28
|
+
if (value === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
const parsed = Number.parseInt(value, 10);
|
|
31
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
32
|
+
throw new Error(`${name} must be a positive integer`);
|
|
33
|
+
}
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
function normalizeUntil(value) {
|
|
37
|
+
if (value === undefined)
|
|
38
|
+
return undefined;
|
|
39
|
+
const normalized = value.replaceAll("-", "_");
|
|
40
|
+
if (!RUN_WAIT_UNTIL_VALUES.includes(normalized)) {
|
|
41
|
+
throw new Error(`Unknown run wait target: ${value}`);
|
|
42
|
+
}
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
const VALUE_FLAGS = new Set([
|
|
46
|
+
"--run-id",
|
|
47
|
+
"--sha",
|
|
48
|
+
"--workflow",
|
|
49
|
+
"--until",
|
|
50
|
+
"--poll-interval-ms",
|
|
51
|
+
"--timeout-ms",
|
|
52
|
+
"--max-output-bytes",
|
|
53
|
+
"--cwd",
|
|
54
|
+
]);
|
|
55
|
+
function parseFlags(args) {
|
|
56
|
+
const values = {};
|
|
57
|
+
let help = false;
|
|
58
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
59
|
+
const arg = args[index];
|
|
60
|
+
if (arg === undefined)
|
|
61
|
+
continue;
|
|
62
|
+
if (arg === "--help" || arg === "-h") {
|
|
63
|
+
help = true;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (arg === "--json")
|
|
67
|
+
continue; // JSON is the only output shape
|
|
68
|
+
const eq = arg.indexOf("=");
|
|
69
|
+
if (eq !== -1 && arg.startsWith("--")) {
|
|
70
|
+
const key = arg.slice(0, eq);
|
|
71
|
+
if (VALUE_FLAGS.has(key)) {
|
|
72
|
+
values[key] = arg.slice(eq + 1);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (VALUE_FLAGS.has(arg)) {
|
|
77
|
+
const next = args[index + 1];
|
|
78
|
+
if (next === undefined)
|
|
79
|
+
throw new Error(`${arg} requires a value`);
|
|
80
|
+
values[arg] = next;
|
|
81
|
+
index += 1;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`Unknown run wait option: ${arg}`);
|
|
85
|
+
}
|
|
86
|
+
return { values, help };
|
|
87
|
+
}
|
|
88
|
+
export async function runRunWaitCommand(args) {
|
|
89
|
+
const { values, help } = parseFlags(args);
|
|
90
|
+
if (help) {
|
|
91
|
+
console.log(RUN_WAIT_HELP);
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
const runId = values["--run-id"];
|
|
95
|
+
const input = {
|
|
96
|
+
sha: values["--sha"],
|
|
97
|
+
runId: runId === undefined ? undefined : runId,
|
|
98
|
+
workflow: values["--workflow"],
|
|
99
|
+
until: normalizeUntil(values["--until"]),
|
|
100
|
+
pollIntervalMs: parsePositiveInteger(values["--poll-interval-ms"], "--poll-interval-ms"),
|
|
101
|
+
timeoutMs: parsePositiveInteger(values["--timeout-ms"], "--timeout-ms"),
|
|
102
|
+
maxOutputBytes: parsePositiveInteger(values["--max-output-bytes"], "--max-output-bytes"),
|
|
103
|
+
cwd: values["--cwd"],
|
|
104
|
+
};
|
|
105
|
+
let payload;
|
|
106
|
+
try {
|
|
107
|
+
payload = await runRunWait(input);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const issues = error.issues;
|
|
111
|
+
if (Array.isArray(issues)) {
|
|
112
|
+
const message = issues
|
|
113
|
+
.map((issue) => (typeof issue.message === "string" ? issue.message : String(issue.message)))
|
|
114
|
+
.join("; ");
|
|
115
|
+
console.error(`wp run wait: ${message}`);
|
|
116
|
+
return 1;
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
121
|
+
return payload.status === "success" ? 0 : 1;
|
|
122
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CAC } from "cac";
|
|
2
|
+
import type { AffectedResolutionDeps } from "#git/affected";
|
|
3
|
+
/**
|
|
4
|
+
* `wp rust-check` — the Rust counterpart of `wp typecheck`/`wp test`: proves
|
|
5
|
+
* an affected tracked Rust crate still compiles and passes its tests.
|
|
6
|
+
*
|
|
7
|
+
* Exists because `wp ci-preflight`'s other stages only resolve TS/JS
|
|
8
|
+
* affectedness, so a Rust-only branch previously reported every stage as
|
|
9
|
+
* "no affected files" and exited green without ever invoking `cargo` — a
|
|
10
|
+
* silent false pass (see `catalog/agent/rules/ci-cost-local-first.md`).
|
|
11
|
+
* This command always prints an explicit status line, whether or not it
|
|
12
|
+
* found Rust crates to check, so "green" is never ambiguous.
|
|
13
|
+
*/
|
|
14
|
+
export declare const RUST_CHECK_COMMAND_HELP: string;
|
|
15
|
+
interface RustCheckCommandDeps {
|
|
16
|
+
readonly getGitTopLevel?: AffectedResolutionDeps["getGitTopLevel"];
|
|
17
|
+
readonly getStagedFiles?: AffectedResolutionDeps["getStagedFiles"];
|
|
18
|
+
readonly getBranchChangedFiles?: AffectedResolutionDeps["getBranchChangedFiles"];
|
|
19
|
+
readonly runCargo?: (args: readonly string[], cwd: string) => {
|
|
20
|
+
readonly exitCode: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export declare function registerRustCheckCommand(cli: CAC, deps?: RustCheckCommandDeps): void;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { addAffectedOptions, resolveAffectedTargets } from "#git/affected";
|
|
3
|
+
import { resolveAffectedRustManifests, trackedCrateForManifest } from "#rust/affected-manifests";
|
|
4
|
+
/**
|
|
5
|
+
* `wp rust-check` — the Rust counterpart of `wp typecheck`/`wp test`: proves
|
|
6
|
+
* an affected tracked Rust crate still compiles and passes its tests.
|
|
7
|
+
*
|
|
8
|
+
* Exists because `wp ci-preflight`'s other stages only resolve TS/JS
|
|
9
|
+
* affectedness, so a Rust-only branch previously reported every stage as
|
|
10
|
+
* "no affected files" and exited green without ever invoking `cargo` — a
|
|
11
|
+
* silent false pass (see `catalog/agent/rules/ci-cost-local-first.md`).
|
|
12
|
+
* This command always prints an explicit status line, whether or not it
|
|
13
|
+
* found Rust crates to check, so "green" is never ambiguous.
|
|
14
|
+
*/
|
|
15
|
+
export const RUST_CHECK_COMMAND_HELP = [
|
|
16
|
+
"Prove affected tracked Rust crates compile and pass tests (cargo check + cargo test).",
|
|
17
|
+
"",
|
|
18
|
+
"Examples:",
|
|
19
|
+
" wp rust-check --affected # staged changed files → owning crate(s)",
|
|
20
|
+
" wp rust-check --affected --branch # changed vs origin/${GITHUB_BASE_REF:-main}",
|
|
21
|
+
"",
|
|
22
|
+
"Tracked crates: native/session-memory-engine, native/dash-tui,",
|
|
23
|
+
"apps/desktop/src-tauri. spikes/** crates are intentionally excluded — no CI",
|
|
24
|
+
"workflow builds or tests them today.",
|
|
25
|
+
].join("\n");
|
|
26
|
+
export function registerRustCheckCommand(cli, deps = {}) {
|
|
27
|
+
addAffectedOptions(cli.command("rust-check", RUST_CHECK_COMMAND_HELP)).action(async (flags) => {
|
|
28
|
+
const affected = Boolean(flags.affected);
|
|
29
|
+
const branch = Boolean(flags.branch);
|
|
30
|
+
const cwd = process.cwd();
|
|
31
|
+
if (!affected && !branch) {
|
|
32
|
+
console.error("wp rust-check requires --affected (optionally with --branch).");
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
35
|
+
const resolution = resolveAffectedTargets({
|
|
36
|
+
commandName: "rust-check",
|
|
37
|
+
cwd,
|
|
38
|
+
affected,
|
|
39
|
+
branch,
|
|
40
|
+
policy: "fail-closed",
|
|
41
|
+
mapChangedFiles: resolveAffectedRustManifests,
|
|
42
|
+
emptyMessage: rustCheckEmptyMessage,
|
|
43
|
+
degradedFallbackMessage: rustCheckDegradedMessage,
|
|
44
|
+
degradedFailClosedMessage: rustCheckDegradedMessage,
|
|
45
|
+
}, deps);
|
|
46
|
+
if (resolution.kind === "invalid") {
|
|
47
|
+
console.error(resolution.message);
|
|
48
|
+
return 1;
|
|
49
|
+
}
|
|
50
|
+
if (resolution.kind === "degraded-fail-closed" || resolution.kind === "degraded-fallback") {
|
|
51
|
+
console.error(resolution.message);
|
|
52
|
+
return 1;
|
|
53
|
+
}
|
|
54
|
+
if (resolution.kind === "empty") {
|
|
55
|
+
console.log(resolution.message);
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
if (resolution.kind === "disabled") {
|
|
59
|
+
// Unreachable: the --affected/--branch guard above always sets
|
|
60
|
+
// `affected: true` before calling resolveAffectedTargets. Handled
|
|
61
|
+
// for exhaustiveness only.
|
|
62
|
+
console.error("wp rust-check requires --affected (optionally with --branch).");
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
const manifests = resolution.targets;
|
|
66
|
+
console.log(`wp rust-check: ${manifests.length} tracked Rust crate(s) affected: ${manifests.join(", ")}`);
|
|
67
|
+
const runCargo = deps.runCargo ?? defaultRunCargo;
|
|
68
|
+
for (const manifest of manifests) {
|
|
69
|
+
const crate = trackedCrateForManifest(manifest);
|
|
70
|
+
if (!crate) {
|
|
71
|
+
console.error(`wp rust-check: no tracked crate metadata for ${manifest}.`);
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
console.log(`wp rust-check: cargo check --manifest-path ${crate.manifest}`);
|
|
75
|
+
const checkResult = runCargo(["check", "--manifest-path", crate.manifest], resolution.cwd);
|
|
76
|
+
if (checkResult.exitCode !== 0) {
|
|
77
|
+
console.error(`wp rust-check: cargo check failed for ${crate.manifest}.`);
|
|
78
|
+
return checkResult.exitCode;
|
|
79
|
+
}
|
|
80
|
+
console.log(`wp rust-check: cargo ${crate.testArgs.join(" ")}`);
|
|
81
|
+
const testResult = runCargo(crate.testArgs, resolution.cwd);
|
|
82
|
+
if (testResult.exitCode !== 0) {
|
|
83
|
+
console.error(`wp rust-check: cargo test failed for ${crate.manifest}.`);
|
|
84
|
+
return testResult.exitCode;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
console.log(`wp rust-check: ${manifests.length} crate(s) passed: ${manifests.join(", ")}`);
|
|
88
|
+
return 0;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function rustCheckEmptyMessage(scope) {
|
|
92
|
+
const suffix = scope === "branch" ? "changed vs base ref" : "staged";
|
|
93
|
+
return (`wp rust-check: 0 tracked Rust crates affected (no ${suffix} files under ` +
|
|
94
|
+
"native/session-memory-engine, native/dash-tui, or apps/desktop/src-tauri; " +
|
|
95
|
+
"spikes/** Rust changes, if any, are intentionally not gated) — skipping cargo.");
|
|
96
|
+
}
|
|
97
|
+
function rustCheckDegradedMessage(reason) {
|
|
98
|
+
return `Unable to determine affected Rust files (${reason}); refusing to skip cargo verification.`;
|
|
99
|
+
}
|
|
100
|
+
function defaultRunCargo(args, cwd) {
|
|
101
|
+
const result = spawnSync("cargo", args, { cwd, stdio: "inherit" });
|
|
102
|
+
if (result.error) {
|
|
103
|
+
const isMissingBinary = result.error.code === "ENOENT";
|
|
104
|
+
console.error(isMissingBinary
|
|
105
|
+
? "wp rust-check: cargo not found on PATH; install the Rust toolchain (https://rustup.rs) to verify Rust changes."
|
|
106
|
+
: `wp rust-check: ${result.error.message}`);
|
|
107
|
+
return { exitCode: 1 };
|
|
108
|
+
}
|
|
109
|
+
return { exitCode: typeof result.status === "number" ? result.status : 1 };
|
|
110
|
+
}
|
|
@@ -8,7 +8,7 @@ export function getSetupHelpText(version) {
|
|
|
8
8
|
"Options:",
|
|
9
9
|
" --with <skills> Comma-separated opt-in skills and/or presets to install (non-interactive). Presets: example-skill, lore-commits, playwright-mcp, rtk, vision plus the special token `all`. Legacy compatibility presets are intentionally omitted; use wp install oh-my opencode when you want WP-owned refreshes. Opt-in skills are listed by 'wp skill list'. ",
|
|
10
10
|
" --without <skills> Comma-separated opt-in skills and/or presets to opt out of for this run. ",
|
|
11
|
-
" --host <hosts> Comma-separated host targets: codex, claude, opencode, all, none ",
|
|
11
|
+
" --host <hosts> Comma-separated host targets: codex, claude, opencode, grok, all, none ",
|
|
12
12
|
" --dry-run Show what would change without writing anything ",
|
|
13
13
|
" --cwd <dir> Working tree to scaffold into (default: process.cwd()) ",
|
|
14
14
|
" -h, --help Display this message ",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const PRIMARY_SETUP_OPTIONS = [
|
|
6
6
|
" --with <skills> Comma-separated opt-in skills and/or presets to install (non-interactive). Presets: example-skill, lore-commits, playwright-mcp, rtk, vision plus the special token `all`. Legacy compatibility presets are intentionally omitted; use wp install oh-my opencode when you want WP-owned refreshes. Opt-in skills are listed by 'wp skill list'. ",
|
|
7
7
|
" --without <skills> Comma-separated opt-in skills and/or presets to opt out of for this run. ",
|
|
8
|
-
" --host <hosts> Comma-separated host targets: codex, claude, opencode, all, none ",
|
|
8
|
+
" --host <hosts> Comma-separated host targets: codex, claude, opencode, grok, all, none ",
|
|
9
9
|
" --prune Widen stale agent-kit plugin-cache pruning from the default host set (claude, codex, opencode) to every supported host while retaining recent versions ",
|
|
10
10
|
" --dry-run Show what would change without writing anything ",
|
|
11
11
|
" --cwd <dir> Working tree to scaffold into (default: process.cwd()) ",
|
|
@@ -6,6 +6,7 @@ export interface TypecheckOptions {
|
|
|
6
6
|
readonly cwd?: string;
|
|
7
7
|
readonly files?: readonly string[];
|
|
8
8
|
readonly packages?: readonly string[];
|
|
9
|
+
readonly tests?: boolean;
|
|
9
10
|
}
|
|
10
11
|
interface TypecheckCommandDeps {
|
|
11
12
|
readonly getGitTopLevel?: AffectedResolutionDeps["getGitTopLevel"];
|
|
@@ -23,6 +23,8 @@ export const TYPECHECK_COMMAND_HELP = [
|
|
|
23
23
|
" wp typecheck --affected # staged changed source → reverse-importer closure",
|
|
24
24
|
" wp typecheck --affected --branch # changed vs origin/${GITHUB_BASE_REF:-main}",
|
|
25
25
|
" wp typecheck --pretty",
|
|
26
|
+
" wp typecheck --tests # test-surface lane (tsconfig.test.json); required in",
|
|
27
|
+
" # not part of the default gate or ci-preflight yet",
|
|
26
28
|
].join("\n");
|
|
27
29
|
export function registerTypecheckCommand(cli, deps = {}) {
|
|
28
30
|
addAffectedOptions(cli
|
|
@@ -31,6 +33,7 @@ export function registerTypecheckCommand(cli, deps = {}) {
|
|
|
31
33
|
.option("--package <name>", "Run the owning-scope typecheck for an exact package.json name (repeatable)"))
|
|
32
34
|
.option("--pretty", "Keep TypeScript pretty output enabled")
|
|
33
35
|
.option("--full", "Print the full raw output instead of the default summary-first view")
|
|
36
|
+
.option("--tests", "Run the test-surface lane (tsconfig.test.json); required by ci-preflight and CI")
|
|
34
37
|
.action(async (targetsOrFlags, maybeFlags) => {
|
|
35
38
|
const positionalTargets = Array.isArray(targetsOrFlags)
|
|
36
39
|
? targetsOrFlags.filter((target) => typeof target === "string")
|
|
@@ -45,9 +48,29 @@ export function registerTypecheckCommand(cli, deps = {}) {
|
|
|
45
48
|
const packages = toArray(flags.package);
|
|
46
49
|
const affected = Boolean(flags.affected);
|
|
47
50
|
const branch = Boolean(flags.branch);
|
|
51
|
+
const tests = Boolean(flags.tests);
|
|
48
52
|
const cwd = process.cwd();
|
|
49
53
|
let files = explicitFiles;
|
|
50
54
|
let executionCwd = cwd;
|
|
55
|
+
if (tests && (affected || branch || explicitFiles.length > 0 || packages.length > 0)) {
|
|
56
|
+
console.error("--tests cannot be combined with --affected, --branch, --file, or --package.");
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
if (tests) {
|
|
60
|
+
const result = await runTypecheckCommand({
|
|
61
|
+
pretty: Boolean(flags.pretty),
|
|
62
|
+
tests: true,
|
|
63
|
+
cwd,
|
|
64
|
+
});
|
|
65
|
+
emitCliCommandOutput({
|
|
66
|
+
entry: result.entry,
|
|
67
|
+
summary: result.entry.summary ?? "",
|
|
68
|
+
passed: result.exitCode === 0,
|
|
69
|
+
full: Boolean(flags.full),
|
|
70
|
+
toolName: "wp_typecheck",
|
|
71
|
+
});
|
|
72
|
+
return result.exitCode;
|
|
73
|
+
}
|
|
51
74
|
if (affected || branch) {
|
|
52
75
|
const resolution = resolveAffectedTargets({
|
|
53
76
|
commandName: "typecheck",
|
|
@@ -131,9 +154,14 @@ export async function runTypecheckCommand(options = {}) {
|
|
|
131
154
|
options.packages.length > 0) {
|
|
132
155
|
throw new Error("Cannot use both --file and --package for typecheck targeting.");
|
|
133
156
|
}
|
|
157
|
+
if (options.tests && ((options.files?.length ?? 0) > 0 || (options.packages?.length ?? 0) > 0)) {
|
|
158
|
+
throw new Error("Cannot use --tests together with --file or --package.");
|
|
159
|
+
}
|
|
134
160
|
const cwd = options.cwd ?? process.cwd();
|
|
135
161
|
repairCurrentManagedWorktreeDependencies(cwd);
|
|
136
|
-
const targeted = (options.files?.length ?? 0) > 0 ||
|
|
162
|
+
const targeted = (options.files?.length ?? 0) > 0 ||
|
|
163
|
+
(options.packages?.length ?? 0) > 0 ||
|
|
164
|
+
Boolean(options.tests);
|
|
137
165
|
const repoRoot = resolveProjectRoot({ cwd });
|
|
138
166
|
const plan = targeted
|
|
139
167
|
? planTypecheckExecution({
|
|
@@ -141,6 +169,7 @@ export async function runTypecheckCommand(options = {}) {
|
|
|
141
169
|
defaultScopeRoot: cwd,
|
|
142
170
|
files: options.files,
|
|
143
171
|
packages: options.packages,
|
|
172
|
+
tests: options.tests,
|
|
144
173
|
pretty: options.pretty,
|
|
145
174
|
})
|
|
146
175
|
: {
|
|
@@ -14,6 +14,12 @@ export interface WorktreeCommandOptions {
|
|
|
14
14
|
deps?: WorktreeDependencyHydration;
|
|
15
15
|
cwd?: string;
|
|
16
16
|
repo?: string;
|
|
17
|
+
/** `prune` only: filesystem-level orphan sweep instead of registry-only prune. */
|
|
18
|
+
orphans?: boolean;
|
|
19
|
+
/** `prune --orphans` only: scope the sweep to one repo namespace. */
|
|
20
|
+
repoId?: string;
|
|
21
|
+
/** `prune --orphans` only: alias for `--force` (execute the removal plan). */
|
|
22
|
+
yes?: boolean;
|
|
17
23
|
}
|
|
18
24
|
export interface WorktreeEntry {
|
|
19
25
|
path: string;
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* `wp worktree` subcommand dispatch.
|
|
3
3
|
*/
|
|
4
4
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
5
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
6
6
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
7
7
|
import { findGitRoot } from "#cli/commands/init/detect-consumer.js";
|
|
8
|
+
import { removeCodexProjectTrust, removeCodexProjectTrusts, } from "#worktrees/codex-project-trust.js";
|
|
8
9
|
import { shortId } from "#shared-utils/short-id.js";
|
|
9
10
|
import { readConfig } from "#cli/commands/init/config";
|
|
10
11
|
import { getProjectRoot } from "#cli/utils";
|
|
@@ -15,7 +16,8 @@ import { hydrateWorktreeDependencies, reconcileWorktreeDependencies, } from "#wo
|
|
|
15
16
|
import { projectWorktreeAgentSurfaces } from "#worktrees/project-agent-surfaces.js";
|
|
16
17
|
import { assertNotLocalMainBranch } from "#worktrees/main-ownership.js";
|
|
17
18
|
import { buildWorktreeInventory, canonicalizeWorktreePath, classifyMembership, isManagedWorktreePath, resolveRepoIdentity, } from "#worktrees/identity.js";
|
|
18
|
-
import { findRegistryCandidatesByPath,
|
|
19
|
+
import { findRegistryCandidatesByPath, planStaleWorktreeRegistryPrune, readWorktreeRegistry, removeWorktreeRegistryEntries, repoScopedPathPredicate, upsertWorktreeRegistryEntry, } from "#worktrees/registry.js";
|
|
20
|
+
import { buildRegistryRepoRootMap, classifyOrphanCandidate, discoverOrphanScanCandidates, resolveRepoRootFromGitPointer, } from "#worktrees/orphan-scan.js";
|
|
19
21
|
function parseDepsOption(value) {
|
|
20
22
|
if (value === undefined || value === null || value === "")
|
|
21
23
|
return undefined;
|
|
@@ -443,7 +445,7 @@ function handleRefresh(opts) {
|
|
|
443
445
|
}
|
|
444
446
|
console.log(`Refreshed ${updated} managed worktree entr${updated === 1 ? "y" : "ies"} for ${repoRoot}.`);
|
|
445
447
|
}
|
|
446
|
-
function handlePrune(opts) {
|
|
448
|
+
async function handlePrune(opts) {
|
|
447
449
|
if (!opts.all)
|
|
448
450
|
throw new Error("Usage: wp worktree prune --all");
|
|
449
451
|
// Repository-scoped, three-state prune: only THIS repo's entries that are
|
|
@@ -451,10 +453,12 @@ function handlePrune(opts) {
|
|
|
451
453
|
// other-repo, and live-legacy entries are retained.
|
|
452
454
|
const repoRoot = resolveWorktreeRepoRoot(opts.repo ?? opts.cwd ?? process.cwd());
|
|
453
455
|
const inventory = buildWorktreeInventory(repoRoot);
|
|
454
|
-
const result =
|
|
456
|
+
const result = planStaleWorktreeRegistryPrune({
|
|
455
457
|
inventory,
|
|
456
458
|
scope: { authoritativeRepoKey: resolveRepoIdentity(repoRoot) },
|
|
457
459
|
});
|
|
460
|
+
await removeCodexProjectTrusts(result.removed.map((entry) => entry.path));
|
|
461
|
+
result.commit();
|
|
458
462
|
console.log(`Pruned ${result.removed.length} stale managed registry entr${result.removed.length === 1 ? "y" : "ies"}.`);
|
|
459
463
|
for (const warning of result.warnings)
|
|
460
464
|
console.log(`warning: ${warning}`);
|
|
@@ -527,7 +531,7 @@ function handleRebind(args, opts) {
|
|
|
527
531
|
console.log(` worktree_owner_branch: ${binding.branch}`);
|
|
528
532
|
console.log(` path: ${binding.path}`);
|
|
529
533
|
}
|
|
530
|
-
function handleRemove(nameOrPath, opts) {
|
|
534
|
+
async function handleRemove(nameOrPath, opts) {
|
|
531
535
|
const cwd = opts.cwd ?? process.cwd();
|
|
532
536
|
const callerRoot = resolveWorktreeRepoRoot(cwd);
|
|
533
537
|
const entries = listEntries(callerRoot);
|
|
@@ -548,6 +552,7 @@ function handleRemove(nameOrPath, opts) {
|
|
|
548
552
|
if (result.status !== 0) {
|
|
549
553
|
throw new Error("git worktree remove failed");
|
|
550
554
|
}
|
|
555
|
+
await removeCodexProjectTrust(resolved);
|
|
551
556
|
removeWorktreeRegistryEntries(repoScopedPathPredicate(resolved, { authoritativeRepoKey: resolveRepoIdentity(repoRoot) }));
|
|
552
557
|
}
|
|
553
558
|
function isDirty(path) {
|
|
@@ -563,7 +568,114 @@ function currentBranch(repoRoot) {
|
|
|
563
568
|
});
|
|
564
569
|
return result.status === 0 ? String(result.stdout ?? "").trim() : "";
|
|
565
570
|
}
|
|
566
|
-
function
|
|
571
|
+
function formatOrphanScanBytes(bytes) {
|
|
572
|
+
if (bytes === "unknown")
|
|
573
|
+
return "-";
|
|
574
|
+
if (bytes < 1024)
|
|
575
|
+
return `${bytes}B`;
|
|
576
|
+
const units = ["K", "M", "G", "T"];
|
|
577
|
+
let value = bytes / 1024;
|
|
578
|
+
let unitIndex = 0;
|
|
579
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
580
|
+
value /= 1024;
|
|
581
|
+
unitIndex += 1;
|
|
582
|
+
}
|
|
583
|
+
return `${value.toFixed(1)}${units[unitIndex]}`;
|
|
584
|
+
}
|
|
585
|
+
function summarizeOrphanScanRows(rows) {
|
|
586
|
+
const counts = new Map();
|
|
587
|
+
for (const row of rows)
|
|
588
|
+
counts.set(row.classification, (counts.get(row.classification) ?? 0) + 1);
|
|
589
|
+
const removable = rows.filter((row) => row.removable).length;
|
|
590
|
+
const parts = [...counts.entries()].map(([classification, count]) => `${classification}=${count}`);
|
|
591
|
+
return `${parts.join(", ")}, removable=${removable}`;
|
|
592
|
+
}
|
|
593
|
+
function printOrphanScanTable(rows) {
|
|
594
|
+
if (rows.length === 0) {
|
|
595
|
+
console.log("No candidate directories found under managed worktree roots.");
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
console.log(`${"PATH".padEnd(72)} ${"CLASS".padEnd(13)} ${"DIRTY".padEnd(8)} ${"SIZE".padEnd(7)} ${"RM".padEnd(4)} REASON`);
|
|
599
|
+
for (const row of rows) {
|
|
600
|
+
const dirty = row.dirty === "unknown" ? "unknown" : row.dirty ? "yes" : "no";
|
|
601
|
+
console.log(`${row.path.padEnd(72)} ${row.classification.padEnd(13)} ${dirty.padEnd(8)} ${formatOrphanScanBytes(row.sizeBytes).padEnd(7)} ${(row.removable ? "yes" : "no").padEnd(4)} ${row.reason}`);
|
|
602
|
+
}
|
|
603
|
+
console.log("");
|
|
604
|
+
console.log(`Summary: ${summarizeOrphanScanRows(rows)}`);
|
|
605
|
+
}
|
|
606
|
+
function resolveOrphanScanDeps() {
|
|
607
|
+
const registryMap = buildRegistryRepoRootMap(readWorktreeRegistry().entries);
|
|
608
|
+
const readGitPointer = (path) => {
|
|
609
|
+
try {
|
|
610
|
+
return readFileSync(path, "utf8");
|
|
611
|
+
}
|
|
612
|
+
catch {
|
|
613
|
+
return undefined;
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
return {
|
|
617
|
+
resolveRepoRoot: (candidate) => registryMap.get(candidate.repoNamespace) ??
|
|
618
|
+
resolveRepoRootFromGitPointer(candidate.path, readGitPointer),
|
|
619
|
+
repoRootExists: existsSync,
|
|
620
|
+
buildInventory: buildWorktreeInventory,
|
|
621
|
+
probeDirty: (path) => {
|
|
622
|
+
const result = spawnSync("git", ["status", "--porcelain"], {
|
|
623
|
+
cwd: path,
|
|
624
|
+
encoding: "utf8",
|
|
625
|
+
timeout: 5000,
|
|
626
|
+
});
|
|
627
|
+
if (result.status !== 0)
|
|
628
|
+
return "unknown";
|
|
629
|
+
return String(result.stdout ?? "").trim().length > 0;
|
|
630
|
+
},
|
|
631
|
+
// Native `du` traverses in kernel/C code (no per-file V8 stat overhead),
|
|
632
|
+
// which is materially faster than the pure-JS walker at the scale a real
|
|
633
|
+
// managed-worktree tree reaches (hundreds of `node_modules` trees). This
|
|
634
|
+
// is only invoked for already-confirmed `orphan` candidates (see
|
|
635
|
+
// `finalizeRow` in orphan-scan.ts), so it never runs against `alive`
|
|
636
|
+
// worktrees. Bounded, non-retrying: a slow/failed probe throws and
|
|
637
|
+
// reports `sizeBytes: "unknown"` rather than blocking the scan.
|
|
638
|
+
measureSize: (path) => {
|
|
639
|
+
const result = spawnSync("du", ["-sk", path], { encoding: "utf8", timeout: 10000 });
|
|
640
|
+
if (result.status !== 0) {
|
|
641
|
+
throw new Error(`du -sk failed or timed out for ${path}`);
|
|
642
|
+
}
|
|
643
|
+
const kilobytes = Number.parseInt(String(result.stdout ?? "")
|
|
644
|
+
.trim()
|
|
645
|
+
.split(/\s+/u)[0] ?? "", 10);
|
|
646
|
+
if (Number.isNaN(kilobytes))
|
|
647
|
+
throw new Error(`du -sk produced unparseable output for ${path}`);
|
|
648
|
+
return kilobytes * 1024;
|
|
649
|
+
},
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Filesystem-level orphan sweep: dry-run by DEFAULT, prints a classification
|
|
654
|
+
* table, and only removes directories (via `--force`/`--yes`) that are proven
|
|
655
|
+
* `orphan` (absent from their resolved primary repo's `git worktree list`)
|
|
656
|
+
* AND proven clean (`git status --porcelain` ran successfully with no
|
|
657
|
+
* output). `broken` and `unrecognized` rows are always report-only. See
|
|
658
|
+
* `#worktrees/orphan-scan.js` for the full classification contract.
|
|
659
|
+
*/
|
|
660
|
+
async function handlePruneOrphans(opts) {
|
|
661
|
+
const roots = resolveKnownManagedWorktreeRoots();
|
|
662
|
+
const candidates = discoverOrphanScanCandidates(roots, { repoNamespaceFilter: opts.repoId });
|
|
663
|
+
const deps = resolveOrphanScanDeps();
|
|
664
|
+
const rows = candidates.map((candidate) => classifyOrphanCandidate(candidate, deps));
|
|
665
|
+
printOrphanScanTable(rows);
|
|
666
|
+
if (!(opts.force === true || opts.yes === true)) {
|
|
667
|
+
console.log("");
|
|
668
|
+
console.log("Dry run only. Re-run with --force (or --yes) to remove the directories marked removable=yes.");
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
const removable = rows.filter((row) => row.removable);
|
|
672
|
+
for (const row of removable) {
|
|
673
|
+
rmSync(row.path, { recursive: true, force: true });
|
|
674
|
+
console.log(`Removed ${row.path}`);
|
|
675
|
+
}
|
|
676
|
+
console.log(`Removed ${removable.length} orphan director${removable.length === 1 ? "y" : "ies"}.`);
|
|
677
|
+
}
|
|
678
|
+
async function handleMergeCleanup(nameOrPath, opts) {
|
|
567
679
|
const cwd = opts.cwd ?? process.cwd();
|
|
568
680
|
const callerRoot = resolveWorktreeRepoRoot(cwd);
|
|
569
681
|
const entries = listEntries(callerRoot);
|
|
@@ -628,6 +740,7 @@ function handleMergeCleanup(nameOrPath, opts) {
|
|
|
628
740
|
if (removeResult.status !== 0) {
|
|
629
741
|
throw new Error("git worktree remove failed");
|
|
630
742
|
}
|
|
743
|
+
await removeCodexProjectTrust(resolved);
|
|
631
744
|
removeWorktreeRegistryEntries(repoScopedPathPredicate(resolved, { authoritativeRepoKey: resolveRepoIdentity(repoRoot) }));
|
|
632
745
|
const fetchResult = spawnSync("git", [...plan.fetchArgs], { cwd: repoRoot, stdio: "inherit" });
|
|
633
746
|
if (fetchResult.status !== 0) {
|
|
@@ -665,7 +778,11 @@ export async function executeWorktreeSubcommand(subcommand, args, opts) {
|
|
|
665
778
|
handleRefresh(opts);
|
|
666
779
|
return;
|
|
667
780
|
case "prune":
|
|
668
|
-
|
|
781
|
+
if (opts.orphans) {
|
|
782
|
+
await handlePruneOrphans(opts);
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
await handlePrune(opts);
|
|
669
786
|
return;
|
|
670
787
|
case "migrate":
|
|
671
788
|
handleMigrate(opts);
|
|
@@ -682,7 +799,7 @@ export async function executeWorktreeSubcommand(subcommand, args, opts) {
|
|
|
682
799
|
if (!nameOrPath) {
|
|
683
800
|
throw new Error("Usage: wp worktree remove <branch-or-path> [--force]");
|
|
684
801
|
}
|
|
685
|
-
handleRemove(nameOrPath, opts);
|
|
802
|
+
await handleRemove(nameOrPath, opts);
|
|
686
803
|
return;
|
|
687
804
|
}
|
|
688
805
|
case "merge-cleanup": {
|
|
@@ -690,7 +807,7 @@ export async function executeWorktreeSubcommand(subcommand, args, opts) {
|
|
|
690
807
|
if (!nameOrPath) {
|
|
691
808
|
throw new Error("Usage: wp worktree merge-cleanup <branch-or-path> [--base <ref>] [--dry-run]");
|
|
692
809
|
}
|
|
693
|
-
handleMergeCleanup(nameOrPath, opts);
|
|
810
|
+
await handleMergeCleanup(nameOrPath, opts);
|
|
694
811
|
return;
|
|
695
812
|
}
|
|
696
813
|
default: {
|
|
@@ -8,6 +8,10 @@ const HELP_TEXT = [
|
|
|
8
8
|
" list [--all] List repo or global managed worktrees",
|
|
9
9
|
" refresh [--all|--repo <dir>] Refresh managed registry from git",
|
|
10
10
|
" prune --all Prune stale managed registry entries",
|
|
11
|
+
" prune --orphans [--repo-id <id>] [--force|--yes]",
|
|
12
|
+
" Scan managed roots for on-disk dirs absent",
|
|
13
|
+
" from git worktree list; dry-run by default,",
|
|
14
|
+
" removes only proven-clean orphans with --force",
|
|
11
15
|
" migrate Move legacy sibling _worktrees",
|
|
12
16
|
" adopt <blueprint-slug> <path> Claim existing checkout as owner",
|
|
13
17
|
" rebind <blueprint-slug> [--path <path>] Repair owner metadata",
|
|
@@ -24,6 +28,9 @@ const HELP_TEXT = [
|
|
|
24
28
|
" --no-setup Skip configured worktree.setup scripts (new only)",
|
|
25
29
|
" --force Skip configured teardown scripts and force removal",
|
|
26
30
|
" --stash-primary Stash dirty primary state and switch to the expected primary branch before merge-cleanup",
|
|
31
|
+
" --orphans Filesystem-level orphan sweep for prune (see prune --orphans above)",
|
|
32
|
+
" --repo-id <id> Scope prune --orphans to one repo namespace under repos/<id>",
|
|
33
|
+
" --yes Alias for --force (prune --orphans only)",
|
|
27
34
|
" --cwd <dir> Repo root (default: process.cwd())",
|
|
28
35
|
].join("\n");
|
|
29
36
|
export function registerWorktreeRouter(cli) {
|
|
@@ -40,6 +47,9 @@ export function registerWorktreeRouter(cli) {
|
|
|
40
47
|
.option("--stash-primary", "Stash dirty primary state and switch to the expected primary branch before merge-cleanup")
|
|
41
48
|
.option("--all", "Use global managed inventory where supported")
|
|
42
49
|
.option("--repo <dir>", "Repo root for refresh/rebind (default: cwd)")
|
|
50
|
+
.option("--orphans", "Filesystem-level orphan sweep for prune (dry-run unless --force/--yes)")
|
|
51
|
+
.option("--repo-id <id>", "Scope prune --orphans to one repo namespace under repos/<id>")
|
|
52
|
+
.option("--yes", "Alias for --force (prune --orphans only)")
|
|
43
53
|
.option("--cwd <dir>", "Repo root to operate from (default: process.cwd())")
|
|
44
54
|
.action(async (subcommand, args, options) => {
|
|
45
55
|
if (!subcommand) {
|
|
@@ -79,8 +79,8 @@ function validateDirectProviderLaunch(provider, cwd) {
|
|
|
79
79
|
? `Run \`${installCommand}\` and retry.`
|
|
80
80
|
: `Install ${ownershipName} and retry.`);
|
|
81
81
|
}
|
|
82
|
-
// External PATH hosts (Grok) do not run optional-tool freshness
|
|
83
|
-
const vpCommand = resolveGlobalCapableVpCommand();
|
|
82
|
+
// External PATH hosts (Grok) do not run optional-tool freshness.
|
|
83
|
+
const vpCommand = adapter ? resolveGlobalCapableVpCommand() : null;
|
|
84
84
|
if (adapter && !vpCommand) {
|
|
85
85
|
throw new DirectProviderLaunchPreparationError("No global-capable Vite+ runner found.", "Reinstall @webpresso/agent-kit and retry.");
|
|
86
86
|
}
|
|
@@ -105,10 +105,14 @@ function ensureCodexSessionTooling(repoRoot) {
|
|
|
105
105
|
throw new DirectProviderLaunchPreparationError(`Codex project MCP server ${project.server} is unavailable: ${project.reason}`, "Run `wp setup --yes-global` from this repo to provision project MCP servers, then retry.");
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
const PROVIDER_SESSION_PREFLIGHTS = {
|
|
109
|
+
claude: () => undefined,
|
|
110
|
+
codex: ensureCodexSessionTooling,
|
|
111
|
+
grok: () => undefined,
|
|
112
|
+
opencode: () => undefined,
|
|
113
|
+
};
|
|
108
114
|
function ensureProviderSessionTooling(provider, cwd) {
|
|
109
|
-
|
|
110
|
-
return;
|
|
111
|
-
ensureCodexSessionTooling(cwd);
|
|
115
|
+
PROVIDER_SESSION_PREFLIGHTS[provider](cwd);
|
|
112
116
|
}
|
|
113
117
|
export function isBareInteractiveProviderLaunch(args) {
|
|
114
118
|
return parseDashPermissionMode(args).args.length === 0;
|