From 6bc2f26a1173c36725565de7c1bca5c4a0381f79 Mon Sep 17 00:00:00 2001 From: voidborne-d Date: Mon, 4 May 2026 22:23:43 +0800 Subject: [PATCH] fix: sync HARNESS_DIRS / PROVIDER_DIRS with providers.js (add .github, .qoder, .rovodev) cleanup-deprecated.mjs HARNESS_DIRS was missing .github and .qoder, so users who installed via GitHub Copilot or Qoder kept stale deprecated skill directories forever (the cleanup script silently skipped those harness roots). bin/commands/skills.mjs PROVIDER_DIRS was missing .rovodev, so the isAlreadyInstalled / findInstalledProviders / check / update flow did not detect or update Rovo Dev installs. scripts/lib/transformers/providers.js declares 13 configDirs as build targets; the two runtime arrays now mirror that list (modulo .codex, which the build deliberately skips because Codex CLI consumes .agents/skills/). Comments added so the next addition catches both arrays. Tests: new regression in tests/cleanup-deprecated.test.mjs covers .github and .qoder cleanup paths. --- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- bin/commands/skills.mjs | 6 ++++-- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- .../impeccable/scripts/cleanup-deprecated.mjs | 4 +++- tests/cleanup-deprecated.test.mjs | 13 +++++++++++++ 16 files changed, 59 insertions(+), 16 deletions(-) diff --git a/.agents/skills/impeccable/scripts/cleanup-deprecated.mjs b/.agents/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.agents/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.agents/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.claude/skills/impeccable/scripts/cleanup-deprecated.mjs b/.claude/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.claude/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.claude/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.cursor/skills/impeccable/scripts/cleanup-deprecated.mjs b/.cursor/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.cursor/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.cursor/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.gemini/skills/impeccable/scripts/cleanup-deprecated.mjs b/.gemini/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.gemini/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.gemini/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.github/skills/impeccable/scripts/cleanup-deprecated.mjs b/.github/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.github/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.github/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.kiro/skills/impeccable/scripts/cleanup-deprecated.mjs b/.kiro/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.kiro/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.kiro/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.opencode/skills/impeccable/scripts/cleanup-deprecated.mjs b/.opencode/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.opencode/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.opencode/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.pi/skills/impeccable/scripts/cleanup-deprecated.mjs b/.pi/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.pi/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.pi/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.qoder/skills/impeccable/scripts/cleanup-deprecated.mjs b/.qoder/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.qoder/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.qoder/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.rovodev/skills/impeccable/scripts/cleanup-deprecated.mjs b/.rovodev/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.rovodev/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.rovodev/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.trae-cn/skills/impeccable/scripts/cleanup-deprecated.mjs b/.trae-cn/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.trae-cn/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.trae-cn/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/.trae/skills/impeccable/scripts/cleanup-deprecated.mjs b/.trae/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/.trae/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/.trae/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/bin/commands/skills.mjs b/bin/commands/skills.mjs index 1029605e..9289933e 100644 --- a/bin/commands/skills.mjs +++ b/bin/commands/skills.mjs @@ -19,8 +19,10 @@ import { tmpdir } from 'node:os'; const __dirname = dirname(fileURLToPath(import.meta.url)); const API_BASE = 'https://impeccable.style'; -// Provider folder names in project roots -const PROVIDER_DIRS = ['.claude', '.cursor', '.gemini', '.agents', '.github', '.kiro', '.opencode', '.pi', '.qoder', '.trae', '.trae-cn']; +// Provider folder names in project roots. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js +// (.codex is intentionally excluded -- Codex CLI consumes .agents/skills/). +const PROVIDER_DIRS = ['.claude', '.cursor', '.gemini', '.agents', '.github', '.kiro', '.opencode', '.pi', '.qoder', '.rovodev', '.trae', '.trae-cn']; function ask(question) { const rl = createInterface({ input: process.stdin, output: process.stdout }); diff --git a/plugin/skills/impeccable/scripts/cleanup-deprecated.mjs b/plugin/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/plugin/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/plugin/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/source/skills/impeccable/scripts/cleanup-deprecated.mjs b/source/skills/impeccable/scripts/cleanup-deprecated.mjs index 6aee4710..f079b8b6 100644 --- a/source/skills/impeccable/scripts/cleanup-deprecated.mjs +++ b/source/skills/impeccable/scripts/cleanup-deprecated.mjs @@ -52,9 +52,11 @@ const DEPRECATED_NAMES = [ ]; // All known harness directories that may contain a skills/ subfolder. +// Must stay in sync with configDir entries in scripts/lib/transformers/providers.js. const HARNESS_DIRS = [ '.claude', '.cursor', '.gemini', '.codex', '.agents', - '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev', + '.github', '.trae', '.trae-cn', '.pi', '.opencode', + '.kiro', '.qoder', '.rovodev', ]; // Per-skill fingerprints for SKILL.md bodies that never mentioned diff --git a/tests/cleanup-deprecated.test.mjs b/tests/cleanup-deprecated.test.mjs index 9d4dfb77..6ffcaa48 100644 --- a/tests/cleanup-deprecated.test.mjs +++ b/tests/cleanup-deprecated.test.mjs @@ -167,6 +167,19 @@ describe('cleanup-deprecated', () => { assert.equal(deleted.length, 3); }); + it('cleans GitHub Copilot and Qoder harness installs', () => { + // Regression: HARNESS_DIRS used to omit .github and .qoder, so users + // who installed via those harnesses kept stale skill directories + // forever. providers.js declares both as build targets, so they need + // to round-trip through cleanup as well. + writeSkill(tmp, '.github', 'arrange', 'Invoke /impeccable first.'); + writeSkill(tmp, '.qoder', 'normalize', 'Run impeccable teach.'); + const deleted = removeDeprecatedSkills(tmp); + assert.equal(deleted.length, 2); + assert.equal(existsSync(join(tmp, '.github', 'skills', 'arrange')), false); + assert.equal(existsSync(join(tmp, '.qoder', 'skills', 'normalize')), false); + }); + it('leaves non-deprecated skills alone', () => { writeSkill(tmp, '.claude', 'my-custom-skill', 'Invoke /impeccable first.'); writeSkill(tmp, '.claude', 'arrange', 'Invoke /impeccable first.');