fix(hooks): don't create root dirs for uninstalled tools on hooks inject/remove - #224
Merged
Merged
Conversation
…ect/remove `teamai hooks inject` / `hooks remove` passed `force: true` to `reconcileHooksToAllTools`, which skipped the "is the tool installed?" gate. `reconcileHooks` then created the tool's root directory via `ensureDir` for *every* tool in `toolPaths` — including ones the user never installed (`.tclaude`, `.tcodex`, `.codex-internal`, all present in default toolPaths). Once those root dirs existed, `isToolInstalled` treated the tools as installed, so subsequent `pull`s copied skills into them — surfacing as mysterious `.tclaude/skills/...` directories the user never asked for. Fix: always apply the tool-installed gate. `force` only ever bypassed this check, so the option is removed entirely. Hooks are now reconciled only into tools whose root directory already exists — matching the behavior of skill/rule/agent sync and `injectHooksToAllTools`. - src/hooks.ts: drop `force`, gate every tool on root-dir existence - src/hooks-cmd.ts: stop passing `force: true` from inject/remove - tests: pre-create installed tool dirs where they relied on `force`, add an e2e regression asserting uninstalled tool dirs are never created - docs: clarify inject/remove only touch installed tools (README + guide, both langs) Co-Authored-By: Claude Opus 4.8 <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.
Problem
teamai hooks inject/hooks removewere silently creating root directories for AI tools the user never installed.The default
toolPathsincludes internal agents liketclaude,tcodex,codex-internal. When a user ranhooks inject, empty~/.tclaude/,~/.tcodex/,~/.codex-internal/directories appeared out of nowhere — each with asettings.json/hooks.jsonand emptyskills/rules/agents/subdirs. Worse: once those root dirs existed,isToolInstalledtreated the tools as installed, so subsequentteamai pulls copied skills into them too.Root cause
hooks inject/removepassedforce: truetoreconcileHooksToAllTools(introduced in #135 to make clean-env E2E tests pass).forceskipped thepathExists(toolRoot)gate, andreconcileHooksthen created the root dir viaensureDirfor every configured tool.force's only effect was bypassing this gate, so it's removed entirely. Hooks are now reconciled only into tools whose root directory already exists — consistent with skill/rule/agent sync and withinjectHooksToAllTools(thepull/initpath, which already gated correctly).Changes
src/hooks.ts: drop theforceoption; always gate each tool on root-dir existencesrc/hooks-cmd.ts: stop passingforce: truefrominject/removeforce; add an e2e regression asserting uninstalled tool dirs are never createdinject/removeonly touch installed tools (README + usage-guide, both languages)Test Plan
npx tsc --noEmit— cleannpx vitest run— 1836 passednpx vitest run --config vitest.e2e.config.ts— 56 passed, 23 skippeddoes not create root directories for uninstalled tools(hooks-team-e2e) passes$HOME: only.claude(pre-installed) exists afterhooks inject;.tclaude/.tcodex/.codex-internal/.cursor/.codex/.codebuddyare not created, and.claude/settings.jsonis written correctly🤖 Generated with Claude Code