mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
Commands are now installed as commands/gsd/<name>.md and invoked as /gsd:<name> in Claude Code. The old hyphen form /gsd-<name> was still hardcoded in hundreds of places across workflows, references, templates, lib modules, and command files — causing "Unknown command" errors whenever GSD suggested a command to the user. Replace all /gsd-<cmd> occurrences where <cmd> is a known command name (derived at runtime from commands/gsd/*.md) using a targeted Node.js script. Agent names, tool names (gsd-sdk, gsd-tools), directory names, and path fragments are not touched. Adds regression test tests/bug-2543-gsd-slash-namespace.test.cjs that enforces zero legacy occurrences going forward. Removes inverted tests/stale-colon-refs.test.cjs (bug #1748) which enforced the now-obsolete hyphen form; the new bug-2543 test supersedes it. Updates 5 assertion tests that hardcoded the old hyphen form to accept the new colon form. Closes #2543 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
1.8 KiB
JavaScript
53 lines
1.8 KiB
JavaScript
'use strict';
|
|
/**
|
|
* One-shot script: replace /gsd-<cmd> with /gsd:<cmd> for known command names.
|
|
* Only replaces when followed by a word boundary (space, newline, quote, backtick, ), end).
|
|
*/
|
|
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
|
|
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
|
|
const cmdNames = fs.readdirSync(COMMANDS_DIR)
|
|
.filter(f => f.endsWith('.md'))
|
|
.map(f => f.replace(/\.md$/, ''))
|
|
.sort((a, b) => b.length - a.length); // longest first to avoid partial matches
|
|
|
|
// Build regex: /gsd-(cmd1|cmd2|...) followed by non-word-char or end
|
|
const pattern = new RegExp(`/gsd-(${cmdNames.join('|')})(?=[^a-zA-Z0-9_-]|$)`, 'g');
|
|
|
|
const SEARCH_DIRS = [
|
|
path.join(__dirname, '..', 'get-shit-done', 'bin', 'lib'),
|
|
path.join(__dirname, '..', 'get-shit-done', 'workflows'),
|
|
path.join(__dirname, '..', 'get-shit-done', 'references'),
|
|
path.join(__dirname, '..', 'get-shit-done', 'templates'),
|
|
path.join(__dirname, '..', 'get-shit-done', 'contexts'),
|
|
path.join(__dirname, '..', 'commands', 'gsd'),
|
|
];
|
|
const EXTENSIONS = new Set(['.md', '.cjs', '.js']);
|
|
|
|
function processDir(dir) {
|
|
let entries;
|
|
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
for (const e of entries) {
|
|
const full = path.join(dir, e.name);
|
|
if (e.isDirectory()) {
|
|
processDir(full);
|
|
} else if (EXTENSIONS.has(path.extname(e.name))) {
|
|
const src = fs.readFileSync(full, 'utf-8');
|
|
const replaced = src.replace(pattern, (_, cmd) => `/gsd:${cmd}`);
|
|
if (replaced !== src) {
|
|
fs.writeFileSync(full, replaced, 'utf-8');
|
|
const count = (src.match(pattern) || []).length;
|
|
console.log(` ${count} replacements: ${path.relative(path.join(__dirname, '..'), full)}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let totalFiles = 0;
|
|
for (const dir of SEARCH_DIRS) {
|
|
processDir(dir);
|
|
}
|
|
console.log('Done.');
|