From 5b5fdc12f375bcf66107928ed346567421f7ecf9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 22:22:06 +0000 Subject: [PATCH] Sync generated provider output --- .agents/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .claude/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .cursor/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .gemini/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .github/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .grok/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .hermes/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .kiro/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .../skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .pi/skills/impeccable/reference/hooks.md | 2 +- .pi/skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .qoder/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .rovodev/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .trae-cn/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .trae/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- .vibe/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- plugin/skills/impeccable/reference/hooks.md | 2 +- .../skills/impeccable/scripts/hook-admin.mjs | 19 ++++++++++++++++--- 32 files changed, 272 insertions(+), 64 deletions(-) diff --git a/.agents/skills/impeccable/reference/hooks.md b/.agents/skills/impeccable/reference/hooks.md index d77237cc7..80256b80e 100644 --- a/.agents/skills/impeccable/reference/hooks.md +++ b/.agents/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.agents/skills/impeccable/scripts/hook-admin.mjs b/.agents/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.agents/skills/impeccable/scripts/hook-admin.mjs +++ b/.agents/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.claude/skills/impeccable/reference/hooks.md b/.claude/skills/impeccable/reference/hooks.md index 0317b192b..14ea99636 100644 --- a/.claude/skills/impeccable/reference/hooks.md +++ b/.claude/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.claude/skills/impeccable/scripts/hook-admin.mjs b/.claude/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.claude/skills/impeccable/scripts/hook-admin.mjs +++ b/.claude/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.cursor/skills/impeccable/reference/hooks.md b/.cursor/skills/impeccable/reference/hooks.md index ea788f7fd..649b190e2 100644 --- a/.cursor/skills/impeccable/reference/hooks.md +++ b/.cursor/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.cursor/skills/impeccable/scripts/hook-admin.mjs b/.cursor/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.cursor/skills/impeccable/scripts/hook-admin.mjs +++ b/.cursor/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.gemini/skills/impeccable/reference/hooks.md b/.gemini/skills/impeccable/reference/hooks.md index fb3b505b9..492098b57 100644 --- a/.gemini/skills/impeccable/reference/hooks.md +++ b/.gemini/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.gemini/skills/impeccable/scripts/hook-admin.mjs b/.gemini/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.gemini/skills/impeccable/scripts/hook-admin.mjs +++ b/.gemini/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.github/skills/impeccable/reference/hooks.md b/.github/skills/impeccable/reference/hooks.md index 980dd1de3..e58ae4c06 100644 --- a/.github/skills/impeccable/reference/hooks.md +++ b/.github/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.github/skills/impeccable/scripts/hook-admin.mjs b/.github/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.github/skills/impeccable/scripts/hook-admin.mjs +++ b/.github/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.grok/skills/impeccable/reference/hooks.md b/.grok/skills/impeccable/reference/hooks.md index 4c2b8a82a..00d2bce8a 100644 --- a/.grok/skills/impeccable/reference/hooks.md +++ b/.grok/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.grok/skills/impeccable/scripts/hook-admin.mjs b/.grok/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.grok/skills/impeccable/scripts/hook-admin.mjs +++ b/.grok/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.hermes/skills/impeccable/reference/hooks.md b/.hermes/skills/impeccable/reference/hooks.md index c7ac6502d..2cf76a568 100644 --- a/.hermes/skills/impeccable/reference/hooks.md +++ b/.hermes/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.hermes/skills/impeccable/scripts/hook-admin.mjs b/.hermes/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.hermes/skills/impeccable/scripts/hook-admin.mjs +++ b/.hermes/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.kiro/skills/impeccable/reference/hooks.md b/.kiro/skills/impeccable/reference/hooks.md index 95d359ee7..a2d4827ac 100644 --- a/.kiro/skills/impeccable/reference/hooks.md +++ b/.kiro/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.kiro/skills/impeccable/scripts/hook-admin.mjs b/.kiro/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.kiro/skills/impeccable/scripts/hook-admin.mjs +++ b/.kiro/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.opencode/skills/impeccable/reference/hooks.md b/.opencode/skills/impeccable/reference/hooks.md index 0c1c8a8bf..d3662f3b8 100644 --- a/.opencode/skills/impeccable/reference/hooks.md +++ b/.opencode/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.opencode/skills/impeccable/scripts/hook-admin.mjs b/.opencode/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.opencode/skills/impeccable/scripts/hook-admin.mjs +++ b/.opencode/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.pi/skills/impeccable/reference/hooks.md b/.pi/skills/impeccable/reference/hooks.md index e543f6866..ce4b17cd6 100644 --- a/.pi/skills/impeccable/reference/hooks.md +++ b/.pi/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.pi/skills/impeccable/scripts/hook-admin.mjs b/.pi/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.pi/skills/impeccable/scripts/hook-admin.mjs +++ b/.pi/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.qoder/skills/impeccable/reference/hooks.md b/.qoder/skills/impeccable/reference/hooks.md index cc9413017..f78c1320e 100644 --- a/.qoder/skills/impeccable/reference/hooks.md +++ b/.qoder/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.qoder/skills/impeccable/scripts/hook-admin.mjs b/.qoder/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.qoder/skills/impeccable/scripts/hook-admin.mjs +++ b/.qoder/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.rovodev/skills/impeccable/reference/hooks.md b/.rovodev/skills/impeccable/reference/hooks.md index fa7abbed7..95a8980de 100644 --- a/.rovodev/skills/impeccable/reference/hooks.md +++ b/.rovodev/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.rovodev/skills/impeccable/scripts/hook-admin.mjs b/.rovodev/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.rovodev/skills/impeccable/scripts/hook-admin.mjs +++ b/.rovodev/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.trae-cn/skills/impeccable/reference/hooks.md b/.trae-cn/skills/impeccable/reference/hooks.md index 3d52ea0a4..e178988e3 100644 --- a/.trae-cn/skills/impeccable/reference/hooks.md +++ b/.trae-cn/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.trae-cn/skills/impeccable/scripts/hook-admin.mjs b/.trae-cn/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.trae-cn/skills/impeccable/scripts/hook-admin.mjs +++ b/.trae-cn/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.trae/skills/impeccable/reference/hooks.md b/.trae/skills/impeccable/reference/hooks.md index 7545b9362..dbaf73a99 100644 --- a/.trae/skills/impeccable/reference/hooks.md +++ b/.trae/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.trae/skills/impeccable/scripts/hook-admin.mjs b/.trae/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.trae/skills/impeccable/scripts/hook-admin.mjs +++ b/.trae/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/.vibe/skills/impeccable/reference/hooks.md b/.vibe/skills/impeccable/reference/hooks.md index 98a6e1d9d..ad75c667b 100644 --- a/.vibe/skills/impeccable/reference/hooks.md +++ b/.vibe/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/.vibe/skills/impeccable/scripts/hook-admin.mjs b/.vibe/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/.vibe/skills/impeccable/scripts/hook-admin.mjs +++ b/.vibe/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() { diff --git a/plugin/skills/impeccable/reference/hooks.md b/plugin/skills/impeccable/reference/hooks.md index 0317b192b..14ea99636 100644 --- a/plugin/skills/impeccable/reference/hooks.md +++ b/plugin/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). | ## Flow diff --git a/plugin/skills/impeccable/scripts/hook-admin.mjs b/plugin/skills/impeccable/scripts/hook-admin.mjs index 28677c483..b8af51975 100644 --- a/plugin/skills/impeccable/scripts/hook-admin.mjs +++ b/plugin/skills/impeccable/scripts/hook-admin.mjs @@ -770,9 +770,22 @@ function reset(cwd) { } } catch { /* ignore */ } } - return removed.length - ? `Reset design hook config and cache (removed: ${removed.join(', ')}).` - : 'No hook config or cache to remove. Already at defaults.'; + // `on` writes three things: config, consent, and hook entries in the + // provider manifests. Reset must undo all three (issue #512): a leftover + // manifest entry kept invoking the hook after the config that said "off" + // was deleted. Local destRel only, since `on` never writes the team-shared + // sharedDestRel. No skill-folder gate: a reset mid-uninstall (skill files + // gone, manifest still wired) is the case that most needs the prune. + const pruned = []; + for (const target of HOOK_MANIFEST_TARGETS) { + try { + if (pruneImpeccableHookFromManifest(path.join(cwd, target.destRel))) pruned.push(target.provider); + } catch { /* ignore */ } + } + const parts = []; + if (removed.length) parts.push(`Reset design hook config and cache (removed: ${removed.join(', ')}).`); + if (pruned.length) parts.push(`Removed hook entries from: ${pruned.join(', ')}.`); + return parts.length ? parts.join(' ') : 'No hook config or cache to remove. Already at defaults.'; } function main() {