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

@@ -2,7 +2,7 @@
* #1928 — Gemini CLI runtime removal + Antigravity redirect.
*
* Google sunset Gemini CLI on 2026-06-18; Antigravity CLI is the official
* successor. GSD removes the `gemini` runtime and turns `--gemini` into an
* successor. MSD removes the `gemini` runtime and turns `--gemini` into an
* explicit deprecation redirect (NOT a silent alias — Hyrum's Law, per the
* issue's rejected alternative #2).
*
@@ -48,10 +48,10 @@ const {
getRuntimeNewProjectCommand,
runtimeFlags,
getProjectInstructionFile,
} = require(path.join(ROOT, 'gsd-core', 'bin', 'lib', 'runtime-name-policy.cjs'));
} = require(path.join(ROOT, 'msd-core', 'bin', 'lib', 'runtime-name-policy.cjs'));
const registry = require(path.join(ROOT, 'gsd-core', 'bin', 'lib', 'capability-registry.cjs'));
const catalog = require(path.join(ROOT, 'gsd-core', 'bin', 'shared', 'model-catalog.json'));
const registry = require(path.join(ROOT, 'msd-core', 'bin', 'lib', 'capability-registry.cjs'));
const catalog = require(path.join(ROOT, 'msd-core', 'bin', 'shared', 'model-catalog.json'));
const { convertClaudeAgentToAntigravityAgent } = require('../bin/install.js');
@@ -59,7 +59,7 @@ const { convertClaudeAgentToAntigravityAgent } = require('../bin/install.js');
// touch the real machine. Runtime-config env overrides are stripped so the
// child resolves config dirs strictly under the temp HOME.
function runInstaller(args, homeDir) {
const env = { ...process.env, HOME: homeDir, USERPROFILE: homeDir, GSD_TEST_MODE: '1' };
const env = { ...process.env, HOME: homeDir, USERPROFILE: homeDir, MSD_TEST_MODE: '1' };
for (const k of [
'CLAUDE_CONFIG_DIR', 'GEMINI_CONFIG_DIR', 'ANTIGRAVITY_CONFIG_DIR',
'XDG_CONFIG_HOME', 'CODEX_CONFIG_DIR', 'OPENCODE_CONFIG_DIR', 'KILO_CONFIG_DIR',
@@ -71,7 +71,7 @@ function runInstaller(args, homeDir) {
describe('#1928 --gemini CLI deprecation redirect', () => {
test('--gemini alone prints the sunset notice and exits non-zero without installing', (t) => {
const home = createTempDir('gsd-1928-gemini-only-');
const home = createTempDir('msd-1928-gemini-only-');
t.after(() => cleanup(home));
const r = runInstaller(['--gemini'], home);
@@ -87,7 +87,7 @@ describe('#1928 --gemini CLI deprecation redirect', () => {
});
test('--gemini --global still exits 1 (removed flag regardless of scope)', (t) => {
const home = createTempDir('gsd-1928-gemini-global-');
const home = createTempDir('msd-1928-gemini-global-');
t.after(() => cleanup(home));
const r = runInstaller(['--gemini', '--global'], home);
@@ -96,7 +96,7 @@ describe('#1928 --gemini CLI deprecation redirect', () => {
});
test('the redirect is a clean message — no stack trace leaks to the user', (t) => {
const home = createTempDir('gsd-1928-gemini-clean-');
const home = createTempDir('msd-1928-gemini-clean-');
t.after(() => cleanup(home));
const r = runInstaller(['--gemini'], home);
@@ -106,7 +106,7 @@ describe('#1928 --gemini CLI deprecation redirect', () => {
});
test('--gemini --help still prints usage (the redirect must not suppress help)', (t) => {
const home = createTempDir('gsd-1928-gemini-help-');
const home = createTempDir('msd-1928-gemini-help-');
t.after(() => cleanup(home));
const r = runInstaller(['--gemini', '--help'], home);
@@ -116,16 +116,16 @@ describe('#1928 --gemini CLI deprecation redirect', () => {
});
test('--gemini --uninstall guides manual cleanup and does NOT uninstall Claude', (t) => {
const home = createTempDir('gsd-1928-gemini-uninstall-');
const home = createTempDir('msd-1928-gemini-uninstall-');
t.after(() => cleanup(home));
// Sentinel: a pre-existing Claude install that must survive. Run WITHOUT
// GSD_TEST_MODE so the real uninstall dispatch is active — the redirect must
// MSD_TEST_MODE so the real uninstall dispatch is active — the redirect must
// exit before it (the dispatch defaults an empty selection to 'claude').
fs.mkdirSync(path.join(home, '.claude'), { recursive: true });
fs.writeFileSync(path.join(home, '.claude', 'sentinel.txt'), 'keep me');
const env = { ...process.env, HOME: home, USERPROFILE: home };
delete env.GSD_TEST_MODE;
delete env.MSD_TEST_MODE;
delete env.CLAUDE_CONFIG_DIR;
const r = spawnSync(process.execPath, [INSTALL_JS, '--gemini', '--uninstall', '--global'], {
cwd: home, env, encoding: 'utf8', timeout: INSTALL_TIMEOUT_MS,
@@ -180,7 +180,7 @@ describe('#1928 gemini removed from every runtime-name-policy surface', () => {
/retired by #1928/,
'config-home fragment removed → must now refuse, not fail-closed-default',
);
assert.strictEqual(getRuntimeNewProjectCommand('gemini'), '/gsd-new-project', 'new-project override removed → default (unchanged by #4709)');
assert.strictEqual(getRuntimeNewProjectCommand('gemini'), '/msd-new-project', 'new-project override removed → default (unchanged by #4709)');
});
test('runtimeFlags has no isGemini and covers exactly the non-claude, CLI-installable registry runtimes (count-agnostic)', () => {
@@ -218,7 +218,7 @@ describe('#1928 Antigravity preserved (shared surface with the removed gemini ru
});
test('the Antigravity-native tool vocabulary powers Antigravity agent conversion (#4705)', () => {
const input = ['---', 'name: gsd-x', 'description: d', 'tools: Read, Write, WebFetch, Skill', '---', '', 'body'].join('\n');
const input = ['---', 'name: msd-x', 'description: d', 'tools: Read, Write, WebFetch, Skill', '---', '', 'body'].join('\n');
const result = convertClaudeAgentToAntigravityAgent(input);
const toolsBlock = result.slice(result.indexOf('tools:')).split('\n').filter((l) => l.startsWith('- '));
assert.ok(toolsBlock.includes('- view_file'), 'Read → view_file (native name, #4705)');
@@ -232,7 +232,7 @@ describe('#1928 Antigravity preserved (shared surface with the removed gemini ru
// claudeToGeminiTools/convertGeminiToolName to claudeToAntigravityTools/convertAntigravityToolName
// in place; a partial rename would leave BOTH names live as two aliases for one concept, which
// is exactly the drift this epic exists to end.
const mod = require(path.join(ROOT, 'gsd-core', 'bin', 'lib', 'runtime-artifact-conversion.cjs'));
const mod = require(path.join(ROOT, 'msd-core', 'bin', 'lib', 'runtime-artifact-conversion.cjs'));
assert.ok(
Object.prototype.hasOwnProperty.call(mod, 'claudeToAntigravityTools'),
@@ -324,7 +324,7 @@ describe('#4709 no shipped surface mints a retired runtime id', () => {
*/
function shippedMarkdown() {
return [
...markdownFilesUnder(path.join(ROOT, 'gsd-core', 'workflows')),
...markdownFilesUnder(path.join(ROOT, 'msd-core', 'workflows')),
...markdownFilesUnder(path.join(ROOT, 'commands')),
...markdownFilesUnder(path.join(ROOT, 'skills')),
...markdownFilesUnder(path.join(ROOT, 'agents')),
@@ -334,7 +334,7 @@ describe('#4709 no shipped surface mints a retired runtime id', () => {
const relPath = (p) => path.relative(ROOT, p).split(path.sep).join('/');
const linesOf = (file) => fs.readFileSync(file, 'utf8').split(/\r?\n/);
const SETTINGS_ADVANCED = path.join(ROOT, 'gsd-core', 'workflows', 'settings-advanced.md');
const SETTINGS_ADVANCED = path.join(ROOT, 'msd-core', 'workflows', 'settings-advanced.md');
test('every RUNTIME= assignment in workflow text names a canonical runtime', () => {
// Bare-literal assignments only: RUNTIME=codex / RUNTIME="codex". A `$VAR`, `$(cmd)` or
@@ -403,7 +403,7 @@ describe('#4709 no shipped surface mints a retired runtime id', () => {
});
assert.deepStrictEqual(offenders, [],
'a runtime selection menu offers a runtime GSD does not support — selecting it writes a '
'a runtime selection menu offers a runtime MSD does not support — selecting it writes a '
+ `config value that silently resolves to Claude Code. Offenders:\n ${offenders.join('\n ')}`);
});
@@ -455,7 +455,7 @@ describe('#4709 no shipped surface mints a retired runtime id', () => {
'antigravity must remain a model-catalog runtime');
// The three model IDs the stale `gemini` table row carried belong to the google PROVIDER
// preset and must survive — they name real Google models, not a GSD runtime.
// preset and must survive — they name real Google models, not a MSD runtime.
const google = JSON.stringify(catalog.providerPresets.google);
for (const model of ['gemini-3.1-pro-preview', 'gemini-3-flash', 'gemini-2.5-flash-lite']) {
assert.ok(google.includes(model), `google provider preset must still offer ${model}`);
@@ -501,7 +501,7 @@ describe('#4709 no shipped surface mints a retired runtime id', () => {
}
assert.deepStrictEqual(offenders, [],
'a PR template asks contributors which runtime they tested and lists one GSD does not '
'a PR template asks contributors which runtime they tested and lists one MSD does not '
+ 'support. Labels must match the runtime label table (src/runtime-name-policy.cts '
+ `RUNTIME_LABELS), so a retired runtime cannot linger here. Offenders:\n ${offenders.join('\n ')}`);
});
@@ -515,7 +515,7 @@ describe('#4709 no shipped surface mints a retired runtime id', () => {
* decision, so retiring it corrects a mistake and needs no ADR-2782 amendment.
*
* The lane spawned `gemini {{model}} -p -`, a binary Google no longer serves for the
* free/Pro/Ultra tiers that ARE GSD's audience.
* free/Pro/Ultra tiers that ARE MSD's audience.
*
* Every assertion below is STRUCTURAL — a declared lane, an owned config key, a capability count.
* None asserts that the string "gemini" is absent, because that string is load-bearing across
@@ -553,7 +553,7 @@ describe('#4709 the Gemini CLI reviewer lane is retired', () => {
assert.deepStrictEqual(
offenders,
[],
'the retired lane still owns config keys, so `gsd config-set` would accept settings for a '
'the retired lane still owns config keys, so `msd config-set` would accept settings for a '
+ `lane that cannot run. Offenders:\n ${offenders.join('\n ')}`,
);
});
@@ -665,7 +665,7 @@ describe('#4728 Gemini CLI prose retired from localized docs and runtime-loaded
});
test('no runtime-loaded workflow file names the retired Gemini runtime', () => {
// Walk gsd-core/workflows/ recursively (this MUST cover nested dirs like
// Walk msd-core/workflows/ recursively (this MUST cover nested dirs like
// new-project/steps/, where #4728's auto-mode-config.md defect lived) and assert no `.md`
// file contains a case-sensitive standalone `Gemini` token, i.e. no match for /\bGemini\b/.
//
@@ -678,11 +678,11 @@ describe('#4728 Gemini CLI prose retired from localized docs and runtime-loaded
// gemini-2.5-flash-lite
// - env vars are uppercase: GEMINI_CONFIG_DIR, GEMINI_SESSION_ID, GEMINI_API_KEY
// - the generated runtime-launcher preamble only ever uses GEMINI_CONFIG_DIR / $HOME/.gemini
// So a bare capitalised `Gemini` anywhere under gsd-core/workflows/ can only mean the retired
// So a bare capitalised `Gemini` anywhere under msd-core/workflows/ can only mean the retired
// RUNTIME is being named — which is exactly the defect this test exists to catch. These files
// are runtime-loaded (read by the agent at execution time), so a stale "Gemini" mention here
// actively steers execution toward a retired runtime, not merely misinforms a reader.
const WORKFLOWS_ROOT = path.join(ROOT, 'gsd-core', 'workflows');
const WORKFLOWS_ROOT = path.join(ROOT, 'msd-core', 'workflows');
const GEMINI_TOKEN = /\bGemini\b/;
// Two allowlisted exceptions, both matched by line CONTENT (never line number, so neither can
// silently drift if the file is edited above the matched line):
@@ -698,10 +698,10 @@ describe('#4728 Gemini CLI prose retired from localized docs and runtime-loaded
// taxonomy the whole #4709 epic rests on, so this line is correct as written and must
// keep working, not get rewritten to dodge the predicate.
const isAllowlistedLegacyLine = (file, line) =>
(relPath(file) === 'gsd-core/workflows/reapply-patches.md'
(relPath(file) === 'msd-core/workflows/reapply-patches.md'
&& line.includes('Legacy:')
&& line.includes('pre-#1928'))
|| (relPath(file) === 'gsd-core/workflows/settings-advanced.md'
|| (relPath(file) === 'msd-core/workflows/settings-advanced.md'
&& line.includes('Known provider'));
/** Recursively collect every `.md` file under `dir`. */
@@ -721,7 +721,7 @@ describe('#4728 Gemini CLI prose retired from localized docs and runtime-loaded
const files = markdownFilesUnder(WORKFLOWS_ROOT);
// Guard against an empty or failed walk making this test pass vacuously.
assert.ok(files.length >= 50,
`expected at least 50 .md files under gsd-core/workflows/, found ${files.length} — the `
`expected at least 50 .md files under msd-core/workflows/, found ${files.length} — the `
+ 'recursive walk may be broken');
const offenders = [];
@@ -735,7 +735,7 @@ describe('#4728 Gemini CLI prose retired from localized docs and runtime-loaded
}
assert.deepStrictEqual(offenders, [],
'a runtime-loaded workflow file under gsd-core/workflows/ still names the retired Gemini '
'a runtime-loaded workflow file under msd-core/workflows/ still names the retired Gemini '
+ 'runtime, steering the agent (these files are read at execution time, not just by a '
+ `reader) toward a retired runtime. Offenders:\n ${offenders.join('\n ')}`);
});