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

@@ -27,7 +27,7 @@ const LONG_KEY_CLI_TIMEOUT_MS = 8000;
// In-process invocation, not execFileSync: cmdConfigGet is a pure CJS
// function reachable without spawning `node` as a child. The prior
// execFileSync(..., { timeout: 5000 }) raced a real subprocess's startup
// (full node boot + gsd-tools.cjs's large eager require graph — capability
// (full node boot + msd-tools.cjs's large eager require graph — capability
// registry, phase/roadmap/agent/check/task routers, verify.cjs,
// cli-skew-check, findProjectRoot, etc.) against a fixed 5s wall clock, with
// no retry. Under Docker host contention that wall clock loses
@@ -35,20 +35,20 @@ const LONG_KEY_CLI_TIMEOUT_MS = 8000;
// defect. bin/lib/config.cjs requires none of that dispatcher machinery, so
// calling cmdConfigGet directly removes the subprocess-spawn cost and the
// wall-clock race entirely: no timeout of any size can flake this.
const config = require(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'config.cjs'));
const config = require(path.join(__dirname, '..', 'msd-core', 'bin', 'lib', 'config.cjs'));
// io.cjs owns error()/output() and the JSON-error-mode toggle. cmdConfigGet's `error`
// is bound to io.error at load, so we drive io directly to (a) get structured stderr
// we can assert a typed `reason` on, and (b) restore the mode after each error probe.
const io = require(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'io.cjs'));
const io = require(path.join(__dirname, '..', 'msd-core', 'bin', 'lib', 'io.cjs'));
// ADR-3889: error() throws ExitError instead of calling process.exit()
// directly. The `runExpectError`/`runInProcessAt`/`runScopedExpectError`
// harnesses below now catch ExitError directly rather than mocking
// process.exit with a throwable sentinel — mocking process.exit no longer
// observes anything, since error() never calls it.
const { ExitError } = require(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'cli-exit.cjs'));
const { ExitError } = require(path.join(__dirname, '..', 'msd-core', 'bin', 'lib', 'cli-exit.cjs'));
/**
* cmdConfigGet's error() path (gsd-core/bin/lib/io.cjs) now throws ExitError
* cmdConfigGet's error() path (msd-core/bin/lib/io.cjs) now throws ExitError
* directly (ADR-3889) instead of calling process.exit(1). The harnesses below
* catch that ExitError directly — no process.exit mock / throwable sentinel
* is needed anymore.
@@ -77,7 +77,7 @@ function captureFdWrite(fd, fn) {
}
/**
* Parse a CLI-style config-get argv (mirrors gsd-core/bin/gsd-tools.cjs's
* Parse a CLI-style config-get argv (mirrors msd-core/bin/msd-tools.cjs's
* 'config-get' case: key is args[1], optional --default <value>, optional
* --raw) into cmdConfigGet's positional params. Keeps the test bodies below
* expressed in the same CLI-args vocabulary they always were.
@@ -100,7 +100,7 @@ describe('config-get --default flag (#1893)', () => {
let planningDir;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-config-default-'));
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-config-default-'));
planningDir = path.join(tmpDir, '.planning');
fs.mkdirSync(planningDir, { recursive: true });
});
@@ -234,7 +234,7 @@ describe('config-get --default flag (#1893)', () => {
// erroring.
// ────────────────────────────────────────────────────────────────────────
{
const configSchemaMod = require(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'config-schema.cjs'));
const configSchemaMod = require(path.join(__dirname, '..', 'msd-core', 'bin', 'lib', 'config-schema.cjs'));
// Repo idiom for property tests (matches config-schema.property.test.cjs):
// require the shared seeded/bounded wrapper, not bare 'fast-check', so this
// property run is deterministic across CI (seed 42) rather than fuzzing with
@@ -246,7 +246,7 @@ describe('config-get --default flag (#1893)', () => {
let planningDir;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-config-2256-'));
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-config-2256-'));
planningDir = path.join(tmpDir, '.planning');
});
@@ -551,7 +551,7 @@ describe('config-get --default flag (#1893)', () => {
leafValueArb,
fc.object({ maxDepth: 3 }),
(keyPath, plant, leafValue, backgroundObj) => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-proto-prop-'));
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-proto-prop-'));
try {
fs.mkdirSync(path.join(dir, '.planning'), { recursive: true });
@@ -644,7 +644,7 @@ describe('config-get --default flag (#1893)', () => {
/**
* Regression test for bug #2798
*
* `gsd-sdk query config-set context_window <n>` was rejected with
* `msd-sdk query config-set context_window <n>` was rejected with
* "Unknown config key: context_window" because context_window was missing
* from VALID_CONFIG_KEYS in sdk/src/query/config-schema.ts.
*
@@ -668,7 +668,7 @@ const SDK_CLI = path.join(REPO_ROOT, 'sdk', 'dist', 'cli.js');
function runConfigSet(key, value, projectDir) {
const argv = ['query', 'config-set', key, String(value), '--project-dir', projectDir];
const result = runNode([SDK_CLI, ...argv], {
env: { ...process.env, GSD_SESSION_KEY: '' },
env: { ...process.env, MSD_SESSION_KEY: '' },
timeoutMs: PROBE_TIMEOUT_MS,
});
let json = null;
@@ -680,7 +680,7 @@ describe('bug-2798: context_window is a valid config key', () => {
let tmpDir;
beforeEach(() => {
tmpDir = createTempProject('gsd-test-2798-');
tmpDir = createTempProject('msd-test-2798-');
fs.writeFileSync(
path.join(tmpDir, '.planning', 'config.json'),
JSON.stringify({ mode: 'balanced' })
@@ -722,7 +722,7 @@ describe('bug-2798: context_window is a valid config key', () => {
t.skip('sdk/dist/query/config-schema.js not built — run `cd sdk && npm run build` to enable this integration test');
return;
}
const cjsSchema = require(path.join(REPO_ROOT, 'gsd-core', 'bin', 'lib', 'config-schema.cjs'));
const cjsSchema = require(path.join(REPO_ROOT, 'msd-core', 'bin', 'lib', 'config-schema.cjs'));
const sdkSchema = require(path.join(REPO_ROOT, 'sdk', 'dist', 'query', 'config-schema.js'));
assert.ok(
@@ -748,7 +748,7 @@ describe('bug-2798: context_window is a valid config key', () => {
/**
* Regression test for bug #2943
*
* `gsd-tools.cjs config-get context_window` (and the SDK equivalent) threw
* `msd-tools.cjs config-get context_window` (and the SDK equivalent) threw
* "Key not found: context_window" when the key was absent from config.json,
* even though context_window has a documented schema default of 200000.
*
@@ -760,7 +760,7 @@ describe('bug-2798: context_window is a valid config key', () => {
'use strict';
// Migrated to typed-IR (#2974): the previous shape grepped stderr/stdout for
// "Key not found"; now the test passes `--json-errors` to gsd-tools and
// "Key not found"; now the test passes `--json-errors` to msd-tools and
// asserts on the structured `reason` code (a frozen-enum value from
// `core.cjs::ERROR_REASON`). Exit code is also a typed signal — together
// they fully discriminate the failure class.
@@ -772,8 +772,8 @@ const path = require('node:path');
const os = require('node:os');
const { execFileSync } = require('node:child_process');
const GSD_TOOLS = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
const { ERROR_REASON } = require(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'io.cjs'));
const MSD_TOOLS = path.join(__dirname, '..', 'msd-core', 'bin', 'msd-tools.cjs');
const { ERROR_REASON } = require(path.join(__dirname, '..', 'msd-core', 'bin', 'lib', 'io.cjs'));
const { cleanup } = require('./helpers.cjs');
const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
@@ -782,7 +782,7 @@ describe('bug-2943: config-get returns schema default for context_window', () =>
let planningDir;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-test-2943-'));
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-test-2943-'));
planningDir = path.join(tmpDir, '.planning');
fs.mkdirSync(planningDir, { recursive: true });
});
@@ -796,7 +796,7 @@ describe('bug-2943: config-get returns schema default for context_window', () =>
* Uses --raw so we get the plain scalar value, not JSON-wrapped.
*/
function runConfigGet(keyPath, extraArgs = []) {
const args = [GSD_TOOLS, 'config-get', keyPath, '--raw', '--cwd', tmpDir, ...extraArgs];
const args = [MSD_TOOLS, 'config-get', keyPath, '--raw', '--cwd', tmpDir, ...extraArgs];
let stdout = '';
let stderr = '';
let exitCode = 0;
@@ -1194,7 +1194,7 @@ test('--cwd pointing at a non-existent path fails with a typed usage reason', (_
const result = runCli(['--cwd', nonExistent, 'config-get', 'model_profile'], { cwd: process.cwd() });
assert.notEqual(result.status, 0);
assert.equal(result.hasStackTrace, false);
// gsd-tools validates --cwd up-front and emits ERROR_REASON.USAGE.
// msd-tools validates --cwd up-front and emits ERROR_REASON.USAGE.
assert.equal(result.reason, 'usage', `expected reason=usage for invalid --cwd, got: ${result.reason}`);
});
@@ -1253,7 +1253,7 @@ test('runCli rejects missing cwd with TypeError', () => {
test('runCli surfaces typed reason from a known failure path', (t) => {
const projectDir = createTempProject('cli-neg-harness-');
t.after(() => cleanup(projectDir));
// Unknown command — gsd-tools emits ERROR_REASON.SDK_UNKNOWN_COMMAND or
// Unknown command — msd-tools emits ERROR_REASON.SDK_UNKNOWN_COMMAND or
// USAGE depending on dispatch depth. Either is a real reason string;
// the contract we pin here is just "the IR carries a reason from the
// ERROR_REASON enum, never null".
@@ -1357,7 +1357,7 @@ test('runCli treats jsonErrors=false as an explicit human-formatter path', (t) =
// ─── #2702: workstream-scoped config-get inherits from root config ──────────
//
// When GSD_WORKSTREAM is set, planningDir(cwd) points at .planning/workstreams/<ws>/.
// When MSD_WORKSTREAM is set, planningDir(cwd) points at .planning/workstreams/<ws>/.
// cmdConfigGet used to read ONLY that file, so a key configured at the project root
// (.planning/config.json) but absent from the workstream's own config was reported
// "Key not found" — silently inverting boolean workflow guards. The fix adds a
@@ -1369,7 +1369,7 @@ describe('#2702: workstream config-get inherits from root config', () => {
let wsPlanningDir;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-config-ws-2702-'));
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-config-ws-2702-'));
rootPlanningDir = path.join(tmpDir, '.planning');
wsPlanningDir = path.join(rootPlanningDir, 'workstreams', 'alpha');
fs.mkdirSync(wsPlanningDir, { recursive: true });
@@ -1379,27 +1379,27 @@ describe('#2702: workstream config-get inherits from root config', () => {
cleanup(tmpDir);
});
// Run cmdConfigGet with GSD_WORKSTREAM scoped to 'alpha' (so planningDir → ws dir).
// Run cmdConfigGet with MSD_WORKSTREAM scoped to 'alpha' (so planningDir → ws dir).
function runScoped(...args) {
const { keyPath, raw, defaultValue } = parseConfigGetArgs(args);
const saved = process.env.GSD_WORKSTREAM;
process.env.GSD_WORKSTREAM = 'alpha';
const saved = process.env.MSD_WORKSTREAM;
process.env.MSD_WORKSTREAM = 'alpha';
let out;
try {
out = captureFdWrite(1, () => {
config.cmdConfigGet(tmpDir, keyPath, raw, defaultValue);
});
} finally {
if (saved === undefined) delete process.env.GSD_WORKSTREAM;
else process.env.GSD_WORKSTREAM = saved;
if (saved === undefined) delete process.env.MSD_WORKSTREAM;
else process.env.MSD_WORKSTREAM = saved;
}
return out.trim();
}
function runScopedExpectError(...args) {
const { keyPath, raw, defaultValue } = parseConfigGetArgs(args);
const saved = process.env.GSD_WORKSTREAM;
process.env.GSD_WORKSTREAM = 'alpha';
const saved = process.env.MSD_WORKSTREAM;
process.env.MSD_WORKSTREAM = 'alpha';
const origWriteSync = fs.writeSync;
io.setJsonErrorMode(true);
let stderr = '';
@@ -1420,8 +1420,8 @@ describe('#2702: workstream config-get inherits from root config', () => {
} finally {
fs.writeSync = origWriteSync;
io.setJsonErrorMode(false);
if (saved === undefined) delete process.env.GSD_WORKSTREAM;
else process.env.GSD_WORKSTREAM = saved;
if (saved === undefined) delete process.env.MSD_WORKSTREAM;
else process.env.MSD_WORKSTREAM = saved;
}
const parts = stderr.split('\n').filter(Boolean);
let payload = {};
@@ -1488,7 +1488,7 @@ describe('#2702: workstream config-get inherits from root config', () => {
writeRoot({ workflow: { use_worktrees: true } });
writeWs({ workflow: {} });
const scoped = runScoped('config-get', 'workflow.use_worktrees', '--raw');
// Unscoped read: no GSD_WORKSTREAM — reads root directly.
// Unscoped read: no MSD_WORKSTREAM — reads root directly.
const unscoped = captureFdWrite(1, () => {
config.cmdConfigGet(tmpDir, 'workflow.use_worktrees', true, undefined);
}).trim();
@@ -1510,27 +1510,27 @@ describe('#2702: workstream config-get inherits from root config', () => {
assert.equal(runScoped('config-get', 'workflow.use_worktrees', '--raw'), 'true');
});
test('GSD_PROJECT alone (no workstream) does not trigger root inheritance — matches loadConfigResolved', () => {
// GSD_PROJECT scopes planningDir to .planning/<project>/ but loadConfigResolved
test('MSD_PROJECT alone (no workstream) does not trigger root inheritance — matches loadConfigResolved', () => {
// MSD_PROJECT scopes planningDir to .planning/<project>/ but loadConfigResolved
// gates root-reading on `if (ws)`, so a project-only read must NOT inherit root.
// The fix gates on GSD_WORKSTREAM presence (not path inequality) to match.
// The fix gates on MSD_WORKSTREAM presence (not path inequality) to match.
// A --default is supplied so a non-inheriting read returns a clean sentinel
// ('not-inherited') rather than hitting the error/exit path.
const projectPlanningDir = path.join(rootPlanningDir, 'myproj');
fs.mkdirSync(projectPlanningDir, { recursive: true });
fs.writeFileSync(path.join(projectPlanningDir, 'config.json'), JSON.stringify({ workflow: {} }));
writeRoot({ workflow: { use_worktrees: true } });
const saved = process.env.GSD_PROJECT;
process.env.GSD_PROJECT = 'myproj';
const saved = process.env.MSD_PROJECT;
process.env.MSD_PROJECT = 'myproj';
try {
const out = captureFdWrite(1, () => {
config.cmdConfigGet(tmpDir, 'workflow.use_worktrees', true, 'not-inherited');
}).trim();
// No workstream → no root inheritance → returns the --default sentinel, NOT root 'true'.
assert.equal(out, 'not-inherited', 'GSD_PROJECT-only must not inherit root (matches loadConfigResolved)');
assert.equal(out, 'not-inherited', 'MSD_PROJECT-only must not inherit root (matches loadConfigResolved)');
} finally {
if (saved === undefined) delete process.env.GSD_PROJECT;
else process.env.GSD_PROJECT = saved;
if (saved === undefined) delete process.env.MSD_PROJECT;
else process.env.MSD_PROJECT = saved;
}
});
});