feat: wt setup --repair, --dry-run, and idempotent Docker#3
Merged
Conversation
Adds a rebalancing repair flow that re-runs allocateServicePorts for an existing worktree (treating the slot's own current ports as not-reserved) and applies the result. --dry-run previews the change set without writing. postSetup runs on apply when ports change, gated by --install. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bundles the plain-setup Docker idempotence fix (--no-recreate) and the repair-mode targeted recreate path (stop + force-recreate just the services whose ports changed) into the same spec. Both share the same ensureDockerServices change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ashing Docker recreation is now driven by comparing per-service compose-config hashes (stored in the allocation) against current generation. Plain `wt setup` recreates only services whose hash changed; if none changed, it's a true no-op. Repair, idempotent setup, and config-change recovery all fall out of the same hash-diff mechanism — no extra flag. Migration for pre-existing allocations: missing serviceHashes treated as in-sync; current hashes are stored on first run, so future config edits are detected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ten-task TDD plan covering: PortChange type, registry schema extension, allocateServicePorts excludeSlot option, computeServiceHashes helper, ensureDockerServices recreateServices flag with hash return, formatRepairPreview output helper, setup.ts auto-detect docker, --repair / --dry-run flags + CLI wiring, README and SKILL updates, final verification. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add --repair to re-allocate ports for an existing worktree (excluding its own current ports), --dry-run to preview without writing, flag validation (--dry-run requires --repair; --repair errors on fresh worktrees), and a no-op short-circuit when nothing changed.
…ural-port-revert and env-patch Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the bug where re-running
wt setupcould break a healthy worktree's Docker services (port-bind conflicts during spurious recreates), and adds a way to repair stale port allocations in place without losing the worktree directory.Plain
wt setupis now idempotent for DockerPer-service compose-config hashing (sha256 truncated to 12 hex chars) is stored in the allocation. On every
wt setup, current hashes are compared to stored; only services whose hash actually changed are stop+force-recreated, the rest stay running. Theupinvocation is--no-recreateso Docker's own diff never triggers a surprise recreate. Migration: missingserviceHashes(pre-upgrade allocations) are treated as in-sync — current hashes are stored as a baseline without recreating anything.wt setup --repairRe-allocates ports for an existing worktree as if creating it fresh now, treating the slot's own currently-registered ports as not-reserved (
allocateServicePortsgets a newexcludeSlotoption). Useful when an external process has seized a port, or when an allocation predates port-drift (v0.4.1).wt removeis intentionally not the answer — it would delete the worktree directory and any uncommitted work.wt setup --dry-runUsed with
--repair. Prints the proposed reallocation and exits without writing to the registry, env files, Docker, or runningpostSetup. Errors out if used without--repair.Targeted Docker recreate path
When recreation is needed, the sequence is
compose stop <svcs>→compose up -d --force-recreate --no-deps <svcs>→ finalcompose up -d --no-recreate --remove-orphans. The explicit stop releases the port before the new container needs to bind it, so the original failure mode is gone.JSON output
Adds
portChanges(per-service{ service, registered, proposed, reason }),recreatedDockerServices,repaired, anddryRunto setup payloads.Spec: `docs/superpowers/specs/2026-04-25-setup-repair-design.md`
Plan: `docs/superpowers/plans/2026-04-25-setup-repair-and-idempotent-docker.md`
Bumps version to 0.4.2.
Test Plan
🤖 Generated with Claude Code