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

@@ -4,40 +4,40 @@
*
* Enforces the human-facing command form in docs/ (#2903).
*
* `/gsd:<cmd>` (and bare `gsd:<cmd>`) is a SOURCE-AUTHORING token: install-time
* `/msd:<cmd>` (and bare `msd:<cmd>`) is a SOURCE-AUTHORING token: install-time
* converters (`transformContentToHyphen`, `convertSlashCommandsTo<Runtime>SkillMentions`)
* rewrite it to `/gsd-<cmd>` per-runtime. It is correct in `commands/gsd/**`,
* `gsd-core/workflows/**`, and `agents/**` — but docs are never passed through a
* converter, so a doc telling a reader to type `/gsd:<cmd>` names a command no
* runtime registers. The real user-facing form is `/gsd-<cmd>`.
* rewrite it to `/msd-<cmd>` per-runtime. It is correct in `commands/msd/**`,
* `msd-core/workflows/**`, and `agents/**` — but docs are never passed through a
* converter, so a doc telling a reader to type `/msd:<cmd>` names a command no
* runtime registers. The real user-facing form is `/msd-<cmd>`.
*
* This guard fails any `docs/**\/*.md` file that still contains `/gsd:<cmd>` or
* bare `gsd:<cmd>` where `<cmd>` is a real command name (drawn from the
* `commands/gsd/*.md` roster). It explicitly permits `/gsd-core:<cmd>` (the
* Claude Code plugin namespace) and any `gsd:<token>` whose `<token>` is not a
* real command (e.g. the `gsd:section` / `gsd:loop-host` workflow-fragment
* This guard fails any `docs/**\/*.md` file that still contains `/msd:<cmd>` or
* bare `msd:<cmd>` where `<cmd>` is a real command name (drawn from the
* `commands/msd/*.md` roster). It explicitly permits `/msd-core:<cmd>` (the
* Claude Code plugin namespace) and any `msd:<token>` whose `<token>` is not a
* real command (e.g. the `msd:section` / `msd:loop-host` workflow-fragment
* marker syntax documented in docs/reference/workflow-fragments.md, or
* `gsd:command-name` used as a placeholder while explaining the Gemini CLI
* `msd:command-name` used as a placeholder while explaining the Gemini CLI
* colon-form convention).
*
* Exclusions (never checked):
* - docs/adr/** (historical record)
* - docs/RELEASE-NOTES-LEGACY.md (maintainer question still open)
* - commands/gsd/**, gsd-core/workflows/**, agents/** — never touched by this
* - commands/msd/**, msd-core/workflows/**, agents/** — never touched by this
* guard at all; the colon form is correct there.
*
* Exemption — `name:` frontmatter key citations: source command files
* (`commands/gsd/*.md`) carry the colon form in their `name:` YAML frontmatter
* key (e.g. `name: gsd:next`). A doc that quotes that key verbatim — e.g.
* `` `name: gsd:next` `` or `name: gsd:next` — is citing the real source file,
* not telling a reader what to type. Rewriting that citation to `gsd-next`
* would make the doc lie about the source it's quoting, so a `gsd:<cmd>` token
* (`commands/msd/*.md`) carry the colon form in their `name:` YAML frontmatter
* key (e.g. `name: msd:next`). A doc that quotes that key verbatim — e.g.
* `` `name: msd:next` `` or `name: msd:next` — is citing the real source file,
* not telling a reader what to type. Rewriting that citation to `msd-next`
* would make the doc lie about the source it's quoting, so a `msd:<cmd>` token
* immediately preceded by `name:` (optionally with a backtick/whitespace in
* between) is permitted. This is narrow: it does not exempt `gsd:<cmd>`
* anywhere else on the line or file, including the reader-facing `/gsd-<cmd>`
* between) is permitted. This is narrow: it does not exempt `msd:<cmd>`
* anywhere else on the line or file, including the reader-facing `/msd-<cmd>`
* form that may appear later in the same sentence.
*
* Detection is case-insensitive (`/GSD:next`, `Gsd:Next`, etc. are all
* Detection is case-insensitive (`/MSD:next`, `Msd:Next`, etc. are all
* flagged) since the install-time converters and runtimes treat command names
* case-insensitively in practice, and a doc typo in casing is still a lie
* about the real command form.
@@ -53,23 +53,23 @@ const path = require('path');
const { ExitError, runMain } = require('./lib/cli-exit.cjs');
const SELF_PATH = path.resolve(__filename);
// GSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT is used by tests to redirect the guard to
// MSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT is used by tests to redirect the guard to
// a temporary fixture git repo without touching the real working tree.
const REPO_ROOT = process.env.GSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT
? path.resolve(process.env.GSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT)
const REPO_ROOT = process.env.MSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT
? path.resolve(process.env.MSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT)
: path.resolve(__dirname, '..');
const DOCS_PREFIX = 'docs/';
const ADR_PREFIX = 'docs/adr/';
const RELEASE_NOTES_LEGACY = 'docs/RELEASE-NOTES-LEGACY.md';
const COMMANDS_DIR = path.join(REPO_ROOT, 'commands/gsd');
const COMMANDS_DIR = path.join(REPO_ROOT, 'commands/msd');
// Matches `/gsd:<cmd>` and bare `gsd:<cmd>` (not part of `/gsd-core:<cmd>`,
// which does not contain the substring `gsd:` — the hyphen breaks it).
// Case-insensitive so `/GSD:next` / `Gsd:Next` are also caught.
const COMMAND_FORM_RE = /(^|[^A-Za-z0-9_-])(\/)?gsd:([A-Za-z0-9_-]+)/gi;
// Matches `/msd:<cmd>` and bare `msd:<cmd>` (not part of `/msd-core:<cmd>`,
// which does not contain the substring `msd:` — the hyphen breaks it).
// Case-insensitive so `/MSD:next` / `Msd:Next` are also caught.
const COMMAND_FORM_RE = /(^|[^A-Za-z0-9_-])(\/)?msd:([A-Za-z0-9_-]+)/gi;
// A `gsd:<cmd>` token is exempt when it is a citation of a source file's
// A `msd:<cmd>` token is exempt when it is a citation of a source file's
// YAML `name:` frontmatter key — i.e. the text immediately before the match
// (ending exactly where the match begins) is `name:` followed by optional
// whitespace and/or a backtick. Only applies to the bare (non-`/`) form,
@@ -81,7 +81,7 @@ function loadRoster() {
try {
entries = fs.readdirSync(COMMANDS_DIR);
} catch (err) {
throw new ExitError(1, 'ERROR lint-docs-command-form: could not read commands/gsd: ' + err.message);
throw new ExitError(1, 'ERROR lint-docs-command-form: could not read commands/msd: ' + err.message);
}
return new Set(
entries.filter((f) => f.endsWith('.md')).map((f) => f.replace(/\.md$/, '')),
@@ -117,7 +117,7 @@ function scanContent(relPath, content, roster) {
const preContext = line.slice(0, match.index + pre.length);
if (NAME_KEY_CITATION_RE.test(preContext)) continue;
}
const matchedToken = (slash || '') + 'gsd:' + cmd;
const matchedToken = (slash || '') + 'msd:' + cmd;
violations.push({
file: relPath,
line: i + 1,
@@ -179,7 +179,7 @@ function main() {
' colon form names a command no runtime registers. Rewrite to the hyphen form\n',
);
process.stderr.write(
' (`/gsd-<cmd>`), or `/gsd-core:<cmd>` if this is genuinely the Claude Code\n',
' (`/msd-<cmd>`), or `/msd-core:<cmd>` if this is genuinely the Claude Code\n',
);
process.stderr.write(' plugin namespace.\n\n');
return 1;