fix(init,uninstall): dry-run purity, --agent filter, stale-entry prune - #852
Open
fengjunhuii wants to merge 1 commit into
Open
fengjunhuii wants to merge 1 commit into
fengjunhuii wants to merge 1 commit into
Conversation
- init --dry-run wrote to disk: it created .teamai/, the tool dirs, the hooks and the project partition config, so a preview could not be discarded and a follow-up real run stopped at 'already initialized' without --force. Every write step is now gated on dryRun and previews what a real run would do instead. - init --agent claude,codex still enabled other installed tools: the project config was re-read after the 'mode: self' marker was written, which fired the clone-time self-heal bootstrap (Tencent#198); it detected every tool in $HOME and merged them into enabledAgents ahead of the explicit selection. The pre-init config is now read once, before the marker exists. - uninstall --agent <tool> reported 'Nothing to uninstall' for a tool whose files were already gone yet left it in enabledAgents, so pull kept re-seeding it. When the targeted plan is empty but the config still references the tool, the entry is dropped from enabledAgents and recorded in disabledAgents; --dry-run previews it, and a tool the config does not reference still reports nothing to uninstall. Co-Authored-By: Claude Code <noreply@anthropic.com>
jeff-r2026
self-requested a review
September 27, 2026 10:18
|
Findings
Testing
|
jeff-r2026
requested changes
Sep 28, 2026
jeff-r2026
left a comment
Collaborator
There was a problem hiding this comment.
Please resolve the P1 findings
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.
fix(init,uninstall): dry-run purity, --agent filter, stale-entry prune
Three bugs found while setting up a single-repo (
kind: self) workspace on Windows withinit . --provider git --agent claude,codex. All three are fixed here, each with regression tests.Bug 1 —
init --dry-runwrote to diskThe preview created
.teamai/, the tool directories, the hooks and the project partition config, and saved the local config. A preview could not be discarded: a follow-up real run stopped atalready initializedunless--forcewas passed.Fix: every write step in the single-repo init path (skeleton dirs,
teamai.yaml,.gitignore, seed, hook injection, config save, state invalidation) is now gated ondryRun, and each prints what a real run would do instead:The
teamai.yamlcontent the real run would write is emitted at debug level, and the seed/hook previews print the actual target lists (localConfig.enabledAgents/ the hook filter), so a dry run is also a regression detector. The re-init guard is dry-run aware: it reportsA real run would overwrite it (--force or confirmation)instead of prompting.Bug 2 —
--agent claude,codexstill enabled other installed toolsDespite the explicit selection, a HOME-mirrored
cursorleaked intoenabledAgentsand.cursor/was seeded. Runtime tracing showedreconcileTeamHooksForConfigreceiving the correct filter whileenabledAgentswas already polluted:initSelfRepore-read the project config after Step 3 had written themode: selfmarker. That read fires the clone-time self-heal bootstrap (#198), which detects every tool installed in$HOMEand merges them intoenabledAgentswith no filter.Fix: the pre-init project config is read once, before anything is written (hoisted above the marker write), and every later consumer (
inheritUserScope,enabledAgentsunion, tool-roots carry-over, mode-switch settling) uses that snapshot. The bootstrap never sees a half-written install.Bug 3 —
uninstall --agent <tool>left a stale config entryA tool whose files were already removed by hand reported
Nothing to uninstallyet stayed inenabledAgents, so the next pull re-seeded its directories and its session-start hooks kept firing. (This is exactly how thecursorfrom bug 2 survived being "uninstalled" during setup.)Fix: when a targeted removal plan is empty but the config still references the tool, the entry is dropped from
enabledAgentsand recorded indisabledAgents— the same durable exclusion a normal targeted uninstall writes.--dry-runpreviews it; no--forceconfirmation is needed since no file is touched. A tool the config does not reference at all still reportsNothing to uninstall.Docs updated to match (
docs/usage-guide.md+docs/usage-guide.zh-CN.md: the targeted-uninstall no-op paragraph now describes the stale-entry prune), plus CHANGELOG entries under Unreleased.Test report
Unit tests (
vitest run, Windows 10, Node 20):origin/mainbaseline (e0bf2e9)init.test.tsuninstall.test.tsAll 9 failures on this branch are byte-identical (by test name) to the
origin/mainbaseline on this machine — pre-existing Windows environment issues (EPERM on symlink creation, chmod/ENOENT), untouched by this PR. Net change: +5 passing tests, 0 new failures.A full
npx vitest runon this machine is unreliable as a signal: the vitest/tinypool worker pool crashes withERR_IPC_CHANNEL_CLOSEDduring teardown (reproduced twice; 144 test files completed ✓ before the crash both times, zero test-level failures). Targeted per-suite runs are therefore the authoritative local signal above; CI on Linux runs the full suite.saveLocalConfigForScopenot called +[dry-run] Would save local configpreview).cursorabsent from the seed preview).Nothing to uninstallfor an unreferenced tool.npx tsc --noEmit— clean.npm run build— clean.End-to-end (real CLI, full offline matrix — 22/22 checks pass):
Isolated sandbox: fake
HOME/USERPROFILEwith pre-seeded.claude/.codex/.cursor, a bare git repo as the team remote, an scp-style remote (git@localhost:team/sandbox.git) driven by aGIT_SSHshim sogit-upload-pack/git-receive-packrun against the local bare repo — no network. Sandbox rebuilt fresh per run (an earlier harness revision hit a fun trap: init auto-commits the skeleton, so agit checkoutbased reset resurrected the managed dirs and made every purity check fail — worth knowing when testinginitlocally).init . --provider git --agent claude,codex --dry-run: repo.teamai/,.claude/,.codex/,.cursor/, the partitionprojects/dir all absent,git status --porcelainempty, preview lines present.--agentwins — real run:.claude/+.codex/created,.cursor/not conjured, partition configenabledAgents: [claude, codex], nocursoranywhere in the log.enabledAgentsby hand,uninstall --agent cursor --force: reports the stale prune, config ends withenabledAgents: [claude, codex],disabledAgents: [cursor].init --forceagain:.cursor/still absent, enabled/disabled lists stable.🤖 Generated with Claude Code