fix(#1223): install scripts/fix-slash-commands.cjs so gsd-tools loads (#1240)

* fix(#1223): install scripts/fix-slash-commands.cjs so gsd-tools loads

Before this fix, bin/install.js copied scripts/changeset/ and scripts/lib/
into the runtime config dir but omitted scripts/fix-slash-commands.cjs.
gsd-core/bin/lib/command-roster.cjs requires this file at module load via
require('../../../scripts/fix-slash-commands.cjs'), so every gsd-tools
command crashed with MODULE_NOT_FOUND on every installed runtime.

Four changes:
- bin/install.js copy step: copy fix-slash-commands.cjs into <configDir>/scripts/
  with source-missing hard-fail and verifyFileInstalled smoke check
- bin/install.js writeManifest: track scripts/fix-slash-commands.cjs (not
  covered by the changeset/lib subdir loops)
- bin/install.js uninstall: best-effort unlinkSync before scripts/ rmdir
- scripts/fix-slash-commands.cjs readCmdNames(): wrap readdirSync in
  try/catch returning [] so skill-based/global installs without a local
  commands/gsd/ directory do not throw ENOENT

Tests added to tests/install.test.cjs (6 new tests):
- smoke: install() copies fix-slash-commands.cjs
- e2e: spawned gsd-tools.cjs does not crash with MODULE_NOT_FOUND
- manifest: writeManifest() tracks the file
- uninstall: uninstall() removes the file
- readCmdNames unit: export returns an array
- readCmdNames spawn: absent COMMANDS_DIR returns exit 0 (no throw)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(#1223): backfill changeset PR number (#1240)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-14 16:03:26 -04:00
committed by GitHub
parent 0b3a2e5f9c
commit 00acbc8868
5 changed files with 208 additions and 3 deletions

View File

@@ -8314,6 +8314,10 @@ function uninstall(isGlobal, runtime = 'claude') {
console.log(` ${green}✓${reset} Removed scripts/lib/ GSD files`);
}
}
// Remove scripts/fix-slash-commands.cjs (#1223) — must come before the scripts/ rmdir
const fixSlashUninstallPath = path.join(targetDir, 'scripts', 'fix-slash-commands.cjs');
try { fs.unlinkSync(fixSlashUninstallPath); } catch (_) { /* best-effort */ }
// If scripts/ dir is now empty, remove it too
const scriptsUninstallDir = path.join(targetDir, 'scripts');
if (fs.existsSync(scriptsUninstallDir)) {
@@ -9029,6 +9033,12 @@ function writeManifest(configDir, runtime = 'claude', options = {}) {
}
}
// Track scripts/fix-slash-commands.cjs (top-level scripts/ file, not covered by changeset/lib loops)
const fixSlashInstallPath = path.join(configDir, 'scripts', 'fix-slash-commands.cjs');
if (fs.existsSync(fixSlashInstallPath)) {
manifest.files['scripts/fix-slash-commands.cjs'] = fileHash(fixSlashInstallPath);
}
fs.writeFileSync(path.join(configDir, MANIFEST_NAME), JSON.stringify(manifest, null, 2));
return manifest;
}
@@ -10421,6 +10431,25 @@ function install(isGlobal, runtime = 'claude', options = {}) {
}
}
// Copy scripts/fix-slash-commands.cjs — required by gsd-core/bin/lib/command-roster.cjs
// at load time via require('../../../scripts/fix-slash-commands.cjs'). Without this file
// every gsd-tools command crashes with MODULE_NOT_FOUND (#1223).
// This copy is independent of scripts/changeset/ — it must land even when the
// changeset CLI source is absent.
{
const fixSlashSrc = path.join(src, 'scripts', 'fix-slash-commands.cjs');
const fixSlashDest = path.join(targetDir, 'scripts', 'fix-slash-commands.cjs');
fs.mkdirSync(path.join(targetDir, 'scripts'), { recursive: true });
if (!fs.existsSync(fixSlashSrc)) {
failures.push('scripts/fix-slash-commands.cjs (source missing from package — reinstall from npm)');
} else {
fs.copyFileSync(fixSlashSrc, fixSlashDest);
if (!verifyFileInstalled(fixSlashDest, 'scripts/fix-slash-commands.cjs')) {
failures.push('scripts/fix-slash-commands.cjs');
}
}
}
// Remove legacy get-shit-done-cc artifacts and stale update caches (#607).
// cleanupLegacyGsdCc handles both the legacy shared cache and the per-package
// cache (formerly an inline unlinkSync here). A cleanup failure must never