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

@@ -40,7 +40,7 @@ const {
// eslint-disable-next-line @typescript-eslint/no-require-imports
import runtimeArtifactConversion = require('./runtime-artifact-conversion.cjs');
const conversionExports = runtimeArtifactConversion as Record<string, unknown> & {
readGsdCommandNames?: () => string[];
readMsdCommandNames?: () => string[];
};
// #2875 Part 2 (J8): shared model-override precedence resolver — see its
// module doc for why kilo/opencode MUST resolve through this ONE function
@@ -219,7 +219,7 @@ function installedManifestIsComplete(
// observed here. Same-user mutation after resolution is outside #4132's
// threat model and would require a broader snapshot/transaction design.
const io = installFs();
const manifestPath = path.join(runtimeConfigDir, 'gsd-file-manifest.json');
const manifestPath = path.join(runtimeConfigDir, 'msd-file-manifest.json');
if (!io.existsSync(manifestPath)) return false;
if (!isPhysicallyConfinedTo(runtimeConfigDir, manifestPath)) return false;
@@ -228,8 +228,8 @@ function installedManifestIsComplete(
if (manifest.manifestVersion === null) return false;
const keys = Object.keys(manifest.files);
const prefixes: string[] = [];
if (required.has('commands')) prefixes.push('gsd-core/commands/gsd/');
if (required.has('agents')) prefixes.push('gsd-core/agents/');
if (required.has('commands')) prefixes.push('msd-core/commands/msd/');
if (required.has('agents')) prefixes.push('msd-core/agents/');
for (const prefix of prefixes) {
const expected = keys.filter((key) => key.startsWith(prefix));
@@ -328,7 +328,7 @@ function providersShareRequiredRoots(
}
function markerProvider(runtimeConfigDir: string): RuntimeSurfaceSourceProvider | null {
const markerPath = path.join(runtimeConfigDir, '.gsd-source');
const markerPath = path.join(runtimeConfigDir, '.msd-source');
try {
if (!installFs().existsSync(markerPath)) return null;
const markerStat = installFs().lstatSync(markerPath);
@@ -359,7 +359,7 @@ function packageProvider(required: ReadonlySet<RuntimeSurfaceSourceClass>): Runt
for (let i = 0; i < 6; i++) {
const candidate: RuntimeSurfaceSourceProvider = {
kind: 'package',
commandsRoot: path.join(dir, 'commands', 'gsd'),
commandsRoot: path.join(dir, 'commands', 'msd'),
agentsRoot: path.join(dir, 'agents'),
};
if (providerHasRequiredClasses(candidate, required, false)) return candidate;
@@ -390,8 +390,8 @@ function resolveSourceProvider(
if (runtimeConfigDir && scope === 'global') {
const installed: RuntimeSurfaceSourceProvider = {
kind: 'installed',
commandsRoot: path.join(runtimeConfigDir, 'gsd-core', 'commands', 'gsd'),
agentsRoot: path.join(runtimeConfigDir, 'gsd-core', 'agents'),
commandsRoot: path.join(runtimeConfigDir, 'msd-core', 'commands', 'msd'),
agentsRoot: path.join(runtimeConfigDir, 'msd-core', 'agents'),
};
if (providerHasRequiredClasses(installed, required, true, runtimeConfigDir)) return installed;
rejectedInstalled = installed;
@@ -417,7 +417,7 @@ function resolveSourceProvider(
throw new Error(
`Runtime Surface source is unavailable or incomplete for ${[...required].sort().join('+')}; ` +
'install or upgrade gsd-core before materializing this surface.',
'install or upgrade msd-core before materializing this surface.',
);
}
@@ -458,7 +458,7 @@ function agentsKind(destSubpath: string, prefix: string, configDir: string, sour
prefix,
// #2995: a `converter: null` agents entry (claude local, zcode) previously
// staged via stageAgentsForProfile — a RAW byte copy that never reads content
// into JS, so gsd:section markers shipped verbatim. Route through the
// into JS, so msd:section markers shipped verbatim. Route through the
// composing stager with an identity converter instead: same output as the raw
// copy for an unmarked agent, markers stripped for a marked one. Routing both
// agent kinds through the stager collapses what were five independent agent
@@ -494,7 +494,7 @@ function agentsKind(destSubpath: string, prefix: string, configDir: string, sour
* or malformed descriptor naming an Object-prototype member (`"constructor"`,
* `"toString"`, `"hasOwnProperty"`, ...) resolves to that member instead of
* throwing, producing garbage staged content rather than a loud failure —
* pre-existing, but promoted from the `/gsd-surface`-only path to the real
* pre-existing, but promoted from the `/msd-surface`-only path to the real
* install path for seven runtimes by #2875 Part 2's agents-bypass closure.
* Required lazily (call-time, not module-top) to avoid a load-time circular
* require, the same pattern install-engine.cts's `_hostBehaviors` already
@@ -531,7 +531,7 @@ function _resolveNamedConverter(converterName: string, kindLabel: string): (...a
* during staging, writing flat `${name}.md` files to the staged directory.
*
* Agent filenames are preserved verbatim (the prefix is already embedded in the
* agent stem — e.g. `gsd-planner.md`).
* agent stem — e.g. `msd-planner.md`).
*
* #1173 SCOPE, updated by #2875 Part 2 (the agents-bypass closure) — measured
* against the tree, not the ADR-3574 framing that preceded it:
@@ -544,8 +544,8 @@ function _resolveNamedConverter(converterName: string, kindLabel: string): (...a
* `hostBehaviors.agentFileExtension`), the cross-cutting path-prefix rewrite +
* attribution (`stageAgentsForRuntimeWithConverter` already applies
* `applyAgentPathRewrites` -> `processAttribution` when `agentCtx` is
* present), and stale-file cleanup (`_removeGsdEntries` prunes every
* `gsd-`-prefixed entry in a kind's destSubpath, broader than the loop's own
* present), and stale-file cleanup (`_removeMsdEntries` prunes every
* `msd-`-prefixed entry in a kind's destSubpath, broader than the loop's own
* extension-gated check).
*
* The fourth — config-reading steps — was the real gap, and #2875 Part 2
@@ -588,7 +588,7 @@ function _resolveNamedConverter(converterName: string, kindLabel: string): (...a
* added at claude-local's own call site to cover that scope too — the
* install-tree golden fixture (`tests/fixtures/install-tree/claude-local.json`)
* is what caught the gap when it was first missed.
* 2. **`/gsd:surface` / `applySurface` activation.** Confirmed convergent,
* 2. **`/msd:surface` / `applySurface` activation.** Confirmed convergent,
* not merely non-broken: for all six runtimes (claude, cline, codex,
* hermes, kilo, opencode), staging via `applySurface` into a freshly
* wiped `agents/` directory produces byte-identical output (including
@@ -602,7 +602,7 @@ function _resolveNamedConverter(converterName: string, kindLabel: string): (...a
* (it fell through the inline loop's generic `else if` branch, same as
* claude, with no dedicated dialect arm — caught by the same golden fixture).
*
* Codex's `config.toml [agents.gsd-*]` strip (`bin/install.js`, under
* Codex's `config.toml [agents.msd-*]` strip (`bin/install.js`, under
* `isMinimalMode` + `hostBehaviors.tomlConfigInstall`) remains the one
* genuinely out-of-scope constraint: it mutates a host config file, not the
* agents directory, and no descriptor kind models host-config mutation. It
@@ -613,7 +613,7 @@ function _resolveNamedConverter(converterName: string, kindLabel: string): (...a
* @param destSubpath destination subpath within configDir (e.g. 'agents')
* @param prefix filename prefix (informational; not applied here)
* @param converterName name of converter function in Runtime Artifact Conversion exports
* @param configDir runtime config dir (for .gsd-source marker resolution)
* @param configDir runtime config dir (for .msd-source marker resolution)
*/
function convertedAgentsKind(
destSubpath: string,
@@ -649,8 +649,8 @@ function convertedAgentsKind(
let converter: (content: string, isGlobal?: boolean, meta?: { agentName: string }) => string;
if (needsModelOverride) {
const overrideTargetDir = agentCtx?.targetDir ?? configDir;
const modelOverrides = installModelOverrideResolver.readGsdEffectiveModelOverrides(overrideTargetDir);
const runtimeResolver = installModelOverrideResolver.readGsdRuntimeProfileResolver(overrideTargetDir);
const modelOverrides = installModelOverrideResolver.readMsdEffectiveModelOverrides(overrideTargetDir);
const runtimeResolver = installModelOverrideResolver.readMsdRuntimeProfileResolver(overrideTargetDir);
// #3706: the resolved reasoning effort, threaded exactly as the model is —
// config read ONCE per stage(), per-agent value resolved per file.
//
@@ -660,14 +660,14 @@ function convertedAgentsKind(
// resolution yields no value" has no trigger and would stamp `variant:`
// into every generated agent file for every existing install. OpenCode's
// built-in variant sets are provider-specific upstream (Anthropic ships
// only `high`/`max`), so a level GSD resolved is not guaranteed to name a
// only `high`/`max`), so a level MSD resolved is not guaranteed to name a
// variant the user's provider actually has — emitting one unasked-for is
// the risk this gate avoids. #1156's rule for `model: inherit` is the
// precedent: do not emit a key the runtime may not understand.
//
// OpenCode only; the kilo converter ignores the field (no EFFORT_ARGV.kilo).
const effortConfig = converterName === 'convertClaudeToOpencodeFrontmatter'
? installEffortResolver.readGsdEffectiveEffortConfig(overrideTargetDir)
? installEffortResolver.readMsdEffectiveEffortConfig(overrideTargetDir)
: null;
converter = (content, _isGlobal, meta) => {
const modelOverride = meta
@@ -741,12 +741,12 @@ function kimiAgentsKind(destSubpath: string, prefix: string, configDir: string,
}
}
const rootAgent = `---\nname: gsd\ndescription: Run GSD workflows in Kimi CLI.\ntools: Agent\n---\n\n# GSD for Kimi CLI\n\nCoordinate installed /skill:gsd-* workflows and route work to generated GSD subagents when a workflow requires an agent handoff.\n`;
const rootAgent = `---\nname: msd\ndescription: Run MSD workflows in Kimi CLI.\ntools: Agent\n---\n\n# MSD for Kimi CLI\n\nCoordinate installed /skill:msd-* workflows and route work to generated MSD subagents when a workflow requires an agent handoff.\n`;
const artifacts = buildKimiAgentArtifacts({ rootAgent, subagents });
const stageDir = mkInstallTempDir('gsd-kimi-agents-');
const stageDir = mkInstallTempDir('msd-kimi-agents-');
installProfiles.STAGED_DIRS.add(stageDir);
installFs().writeFileSync(path.join(stageDir, 'gsd.yaml'), artifacts.root.yaml);
installFs().writeFileSync(path.join(stageDir, 'gsd.md'), artifacts.root.prompt);
installFs().writeFileSync(path.join(stageDir, 'msd.yaml'), artifacts.root.yaml);
installFs().writeFileSync(path.join(stageDir, 'msd.md'), artifacts.root.prompt);
const subagentsDir = path.join(stageDir, 'subagents');
installFs().mkdirSync(subagentsDir, { recursive: true });
for (const artifact of artifacts.subagents) {
@@ -765,7 +765,7 @@ function kimiAgentsKind(destSubpath: string, prefix: string, configDir: string,
* @param prefix
* @param converterName name of converter function in Runtime Artifact Conversion exports
* @param runtime canonical runtime ID (gates Hermes/Qwen branding in converter)
* @param configDir runtime config dir (for .gsd-source marker resolution)
* @param configDir runtime config dir (for .msd-source marker resolution)
* @param nested if true, nest concrete skills under their ns-* routers (#69)
* @param scope install scope; converted to isGlobal and passed as 5th positional
* arg so scope-aware converters (antigravity, copilot) can choose
@@ -800,8 +800,8 @@ function skillsKind(
// `runtime` for the claude/kimi/cline converters, so the scope-aware
// converters (antigravity, copilot) read isGlobal from position 5 to avoid
// colliding with `runtime` and always taking the global branch.
const cmdNames = conversionExports.readGsdCommandNames
? conversionExports.readGsdCommandNames()
const cmdNames = conversionExports.readMsdCommandNames
? conversionExports.readMsdCommandNames()
: [];
// #2870: same judgment as convertedAgentsKind above — `scope` is this
// function's own parameter (default `'global'`, so it is never
@@ -837,9 +837,9 @@ function skillsKind(
* handles prefix logic via the existing layout machinery.
*
* @param destSubpath destination subpath within configDir (e.g. 'commands')
* @param prefix filename prefix, e.g. 'gsd-'
* @param prefix filename prefix, e.g. 'msd-'
* @param converterName name of converter function in Runtime Artifact Conversion exports
* @param configDir runtime config dir (for .gsd-source marker resolution)
* @param configDir runtime config dir (for .msd-source marker resolution)
*/
function convertedCommandsKind(
destSubpath: string,
@@ -895,7 +895,7 @@ function convertedCommandsKind(
// claude — https://code.claude.com/docs/en/skills + anthropics/claude-code#28266
// (one-level scan under ~/.claude/skills — but Skill-tool errors on unknown
// names rather than re-routing via the router; concrete skills must be
// at the top level so Skill(skill="gsd-plan-phase") succeeds)
// at the top level so Skill(skill="msd-plan-phase") succeeds)
//
// FLAT (nested-scan behaviour unconfirmed → conservative):
// codex — developers.openai.com/codex/skills/
@@ -1058,15 +1058,15 @@ function resolveRuntimeArtifactLayoutFromRegistry(
// Widens this module from PLACEMENT (resolveRuntimeArtifactLayout, above —
// untouched, still 7 callers) to TRIGGER resolution: "what does a user type"
// rather than "where does a file land". A new function, not a widened
// signature — see .gsd/phase/feat-2871-trigger-resolution/40-design.md.
// signature — see .msd/phase/feat-2871-trigger-resolution/40-design.md.
//
// Only `commands` and `skills` are trigger-bearing. `agents` / `kimi-agents`
// are a SEPARATE dispatch interface point (subagent invocation via
// `subagent_type` / named dispatch, never a `/gsd-<name>` a user types) — see
// `subagent_type` / named dispatch, never a `/msd-<name>` a user types) — see
// 40-design.md's "agents are not trigger-bearing" correction to ADR-2866.
// Excluding them here is deliberate, not an oversight: including `agents`
// would misreport windsurf (whose global scope emits agents only) as fully
// shadowing its local `/gsd-*` surface, when in fact nothing shadows it.
// shadowing its local `/msd-*` surface, when in fact nothing shadows it.
/** The trigger-bearing subset of ArtifactKindName — mirrors
* VALID_TRIGGER_PRECEDENCE_KINDS in capability-validator.cjs (kept as two
@@ -1094,7 +1094,7 @@ interface TriggerShadower {
}
interface TriggerSurface {
/** What the user types, e.g. `gsd-plan-phase`. Always `${prefix}${stem}` —
/** What the user types, e.g. `msd-plan-phase`. Always `${prefix}${stem}` —
* unaffected by the destPath branch below (see `destPath`). */
trigger: string;
kind: TriggerKindName;
@@ -1172,8 +1172,8 @@ function getDefaultTriggerPrecedence(): string[] {
/**
* True when a `commands` kind entry is namespaced by its destination
* directory rather than by a filename prefix — i.e. `destSubpath`'s basename
* equals `prefix` with its trailing hyphen stripped (e.g. `commands/gsd` +
* `gsd-`). When true, `_copyStaged` (`install-engine.cts`) and `surface.cts`
* equals `prefix` with its trailing hyphen stripped (e.g. `commands/msd` +
* `msd-`). When true, `_copyStaged` (`install-engine.cts`) and `surface.cts`
* both write the bare stem filename (no prefix) because the directory itself
* already carries the namespace; `resolveTriggerSurface` mirrors that in its
* own `destPath` computation. Single source of truth for the three sites
@@ -1229,7 +1229,7 @@ function isHigherPriority(a: TriggerSurface, b: TriggerSurface, precedenceRank:
}
/**
* Resolve the `/gsd-<name>`-style trigger surface for a runtime: what the
* Resolve the `/msd-<name>`-style trigger surface for a runtime: what the
* user types, at which scope, whether it wins or is shadowed, and (for
* nested-router runtimes) whether the host registers it directly or only
* reaches it through a router. Pure — no filesystem, no mutation of `scopes`