refactor: hard-fork GSD -> MSD (Make Software Done)

Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
This commit is contained in:
Jakub Zych
2026-10-06 01:47:40 +02:00
parent fe069b2a56
commit a9a7a328e6
2763 changed files with 78465 additions and 78434 deletions

View File

@@ -1,15 +1,15 @@
'use strict';
/**
* One-shot script + library: bidirectional GSD slash-command namespace normalizer.
* One-shot script + library: bidirectional MSD slash-command namespace normalizer.
*
* - Default direction (transformContent): retired /gsd-<cmd> → /gsd:<cmd>
* - Default direction (transformContent): retired /msd-<cmd> → /msd:<cmd>
* (keeps monorepo sources, docs, and workflows in the active colon form).
* - Reverse direction (transformContentToHyphen): /gsd:<cmd> / gsd:<cmd> → gsd-<cmd>
* - Reverse direction (transformContentToHyphen): /msd:<cmd> / msd:<cmd> → msd-<cmd>
* (used during skill installation for runtimes that register skills under the
* canonical hyphen form established in #2808).
*
* Both directions only rewrite known commands from `commands/gsd/*.md` (longest-first
* matching + word-boundary safety). Non-commands (gsd-sdk, gsd-tools, etc.) are
* Both directions only rewrite known commands from `commands/msd/*.md` (longest-first
* matching + word-boundary safety). Non-commands (msd-sdk, msd-tools, etc.) are
* intentionally left untouched.
*
* The transforms are pure and exported for use by the installer and tests.
@@ -18,14 +18,14 @@
const fs = require('node:fs');
const path = require('node:path');
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'msd');
const SEARCH_DIRS = [
path.join(__dirname, '..', 'gsd-core', 'bin', 'lib'),
path.join(__dirname, '..', 'gsd-core', 'workflows'),
path.join(__dirname, '..', 'gsd-core', 'references'),
path.join(__dirname, '..', 'gsd-core', 'templates'),
path.join(__dirname, '..', 'gsd-core', 'contexts'),
path.join(__dirname, '..', 'commands', 'gsd'),
path.join(__dirname, '..', 'msd-core', 'bin', 'lib'),
path.join(__dirname, '..', 'msd-core', 'workflows'),
path.join(__dirname, '..', 'msd-core', 'references'),
path.join(__dirname, '..', 'msd-core', 'templates'),
path.join(__dirname, '..', 'msd-core', 'contexts'),
path.join(__dirname, '..', 'commands', 'msd'),
path.join(__dirname, '..', 'agents'),
path.join(__dirname, '..', 'hooks'),
];
@@ -44,30 +44,30 @@ function isTestFile(name) {
}
function buildPattern(cmdNames) {
// Empty input would compile `/gsd-()(?=[^a-zA-Z0-9_-]|$)/g`, which the regex
// engine still matches at any `/gsd-` token followed by a non-word boundary
// (e.g. EOL, whitespace, punctuation) — rewriting it to a stray `/gsd:`.
// Empty input would compile `/msd-()(?=[^a-zA-Z0-9_-]|$)/g`, which the regex
// engine still matches at any `/msd-` token followed by a non-word boundary
// (e.g. EOL, whitespace, punctuation) — rewriting it to a stray `/msd:`.
// Short-circuit so the caller can no-op on a missing/empty registry rather
// than perform an unintended broad rewrite.
if (!Array.isArray(cmdNames) || cmdNames.length === 0) return null;
const sorted = [...cmdNames].sort((a, b) => b.length - a.length); // longest first to avoid partial matches
return new RegExp(`/gsd-(${sorted.join('|')})(?=[^a-zA-Z0-9_-]|$)`, 'g');
return new RegExp(`/msd-(${sorted.join('|')})(?=[^a-zA-Z0-9_-]|$)`, 'g');
}
/**
* Pure transform: rewrite retired `/gsd-<cmd>` to `/gsd:<cmd>` for the given command names.
* Returns the rewritten string. Identifiers not in `cmdNames` (e.g. `/gsd-sdk`,
* `/gsd-tools`) are left untouched.
* Pure transform: rewrite retired `/msd-<cmd>` to `/msd:<cmd>` for the given command names.
* Returns the rewritten string. Identifiers not in `cmdNames` (e.g. `/msd-sdk`,
* `/msd-tools`) are left untouched.
*/
function transformContent(src, cmdNames) {
const pattern = buildPattern(cmdNames);
if (!pattern) return src;
return src.replace(pattern, (_, cmd) => `/gsd:${cmd}`);
return src.replace(pattern, (_, cmd) => `/msd:${cmd}`);
}
/**
* Build regex for the reverse direction (colon form → hyphen form).
* Matches both "gsd:cmd" and "/gsd:cmd" (the leading / is preserved automatically
* Matches both "msd:cmd" and "/msd:cmd" (the leading / is preserved automatically
* because it is not part of the match). Uses longest-first ordering plus
* bidirectional word-boundary safety (negative lookbehind on the left, lookahead
* on the right) so matches only occur at token boundaries.
@@ -75,20 +75,20 @@ function transformContent(src, cmdNames) {
function buildColonPattern(cmdNames) {
if (!Array.isArray(cmdNames) || cmdNames.length === 0) return null;
const sorted = [...cmdNames].sort((a, b) => b.length - a.length);
return new RegExp(`(?<![a-zA-Z0-9_-])gsd:(${sorted.join('|')})(?=[^a-zA-Z0-9_-]|$)`, 'g');
return new RegExp(`(?<![a-zA-Z0-9_-])msd:(${sorted.join('|')})(?=[^a-zA-Z0-9_-]|$)`, 'g');
}
/**
* Pure transform (reverse): rewrite `/gsd:<cmd>` / `gsd:<cmd>` to hyphen form
* for known GSD commands.
* Pure transform (reverse): rewrite `/msd:<cmd>` / `msd:<cmd>` to hyphen form
* for known MSD commands.
*
* Non-command identifiers (e.g. gsd-sdk, gsd-tools) are left untouched, matching
* Non-command identifiers (e.g. msd-sdk, msd-tools) are left untouched, matching
* the safety contract of the forward transform.
*/
function transformContentToHyphen(src, cmdNames) {
const pattern = buildColonPattern(cmdNames);
if (!pattern) return src;
return src.replace(pattern, (_, cmd) => `gsd-${cmd}`);
return src.replace(pattern, (_, cmd) => `msd-${cmd}`);
}
function readCmdNames() {
@@ -102,7 +102,7 @@ function readCmdNames() {
// not silently handed an empty registry while the real problem goes undetected.
if (err.code !== 'ENOENT') throw err;
// COMMANDS_DIR may not exist on installs that use skill-based runtimes or
// global Claude installs (no local commands/gsd/ directory). Return [] so
// global Claude installs (no local commands/msd/ directory). Return [] so
// callers that handle an empty array gracefully (buildPattern returns null,
// transformContent is a no-op) are not broken by a missing directory.
return [];