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

@@ -52,7 +52,7 @@ const {
const SUITES = ['all', 'unit', 'integration', 'install', 'security', 'slow', 'qa'];
// ADR-457 build-at-publish: gsd-core/bin/lib/*.cjs is generated from
// ADR-457 build-at-publish: msd-core/bin/lib/*.cjs is generated from
// src/*.cts and gitignored, so on a clean checkout (fresh CI, before any build)
// the artifact is absent — yet test files require it. This is the universal
// chokepoint every test path funnels through (test:unit, --files-from, direct
@@ -60,19 +60,19 @@ const SUITES = ['all', 'unit', 'integration', 'install', 'security', 'slow', 'qa
//
// Strategy (incremental + re-emit-on-missing, closes both #969 failure modes):
// 1. Run tsc incrementally (fast ~380ms no-op when sources unchanged).
// 2. Verify every src/*.cts (non-.d.cts) maps to a non-empty gsd-core/bin/lib/*.cjs.
// 2. Verify every src/*.cts (non-.d.cts) maps to a non-empty msd-core/bin/lib/*.cjs.
// 3. If any expected .cjs is missing or zero-bytes (persistent-mirror scenario:
// tsc no-ops because tsbuildinfo looks current even though the file was deleted),
// delete the tsbuildinfo and run tsc ONCE MORE (clean re-emit), then re-verify.
//
// Common case: fast incremental no-op. Stale/deleted-output case: detected by
// the cheap existsSync loop and force-rebuilt. Paths resolve from __dirname so
// it works regardless of GSD_TEST_DIR / temp-dir cwd.
// it works regardless of MSD_TEST_DIR / temp-dir cwd.
function ensureBuiltArtifacts(overrides = {}) {
const { existsSync, readdirSync, statSync, unlinkSync } = require('fs');
const root = overrides.root || join(__dirname, '..');
const srcDir = overrides.srcDir || join(root, 'src');
const outDir = overrides.outDir || join(root, 'gsd-core', 'bin', 'lib');
const outDir = overrides.outDir || join(root, 'msd-core', 'bin', 'lib');
const tsBuildInfoPath = overrides.tsBuildInfoPath || join(root, 'tsconfig.build.tsbuildinfo');
const tsconfigPath = overrides.tsconfigPath || join(root, 'tsconfig.build.json');
const tscBin = require.resolve('typescript/bin/tsc');
@@ -80,7 +80,7 @@ function ensureBuiltArtifacts(overrides = {}) {
// Build the 1:1 map of expected output paths from src/*.cts sources.
// Excludes *.d.cts (declaration-only files that produce no output).
// Handles subdirectories (e.g. src/installer-migrations/*.cts → gsd-core/bin/lib/installer-migrations/*.cjs).
// Handles subdirectories (e.g. src/installer-migrations/*.cts → msd-core/bin/lib/installer-migrations/*.cjs).
function gatherExpectedOutputs() {
const expected = [];
function scan(dir, relBase) {
@@ -102,11 +102,11 @@ function ensureBuiltArtifacts(overrides = {}) {
return expectedPaths.filter(p => !existsSync(p) || statSync(p).size === 0);
}
// #996 placed the tsbuildinfo inside gsd-core/bin/ (a copied/shipped tree), which
// #996 placed the tsbuildinfo inside msd-core/bin/ (a copied/shipped tree), which
// raced install-test copies. It now lives at the repo root. Best-effort purge any
// stale bin-local copy so persistent workspaces/mirrors self-heal (no-op on a temp
// override root or a clean checkout).
const legacyTsBuildInfo = join(root, 'gsd-core', 'bin', 'tsconfig.build.tsbuildinfo');
const legacyTsBuildInfo = join(root, 'msd-core', 'bin', 'tsconfig.build.tsbuildinfo');
try { if (existsSync(legacyTsBuildInfo)) unlinkSync(legacyTsBuildInfo); } catch { /* best-effort */ }
// Step 1: incremental build (fast no-op when sources unchanged).
@@ -380,17 +380,17 @@ function defaultMaxUnmeasuredPerChunk(platform) {
// place and every future fixture reintroduces the hazard, while a run-private
// root + between-chunk sweep caps peak usage for every fixture at once.
const RUN_TEMP_ROOT_PREFIX = 'gsd-test-run-';
const RUN_TEMP_ROOT_PREFIX = 'msd-test-run-';
// Children the runner itself keeps alive across chunks — the sweep must spare
// them (GSD_HOME's nested-spawn REUSE contract; the chunk-diagnostics events dir).
const RESERVED_TEMP_PREFIXES = ['gsd-test-home-', 'gsd-run-tests-events-'];
// them (MSD_HOME's nested-spawn REUSE contract; the chunk-diagnostics events dir).
const RESERVED_TEMP_PREFIXES = ['msd-test-home-', 'msd-run-tests-events-'];
/**
* Create (or reuse) this run's private temp root and repoint the env at it.
*
* TMPDIR/TEMP/TMP all move, so every `mkdtempSync(os.tmpdir())` in a spawned
* test child lands inside the root — that is what makes a sweep scoped and
* safe. IDEMPOTENT exactly like the GSD_HOME sandbox below: a nested run-tests
* safe. IDEMPOTENT exactly like the MSD_HOME sandbox below: a nested run-tests
* spawn (tests/run-tests-harness.test.cjs) inherits the root via env and must
* REUSE it, never mkdtemp a fresh root per invocation. An operator's TMPDIR
* redirect (the tmpfs workaround) keeps working: the root is created INSIDE the
@@ -489,7 +489,7 @@ function assertTempRootBounded(root, limit) {
}
// Per-file measured durations, regenerated by scripts/gen-test-timings.cjs from
// gsd-test reporter event streams. Overridable so tests can inject a synthetic
// msd-test reporter event streams. Overridable so tests can inject a synthetic
// table instead of depending on the real suite's cost profile.
const DEFAULT_TIMINGS_PATH = join(__dirname, '..', 'tests', 'test-timings.json');
// Must track SCHEMA_VERSION in scripts/gen-test-timings.cjs.
@@ -1079,7 +1079,7 @@ function analyzeChunkEvents(eventsPath) {
try {
raw = readFileSync(eventsPath, 'utf8');
} catch {
// The events file never existed — either GSD_RUN_TESTS_EVENTS_FILE never
// The events file never existed — either MSD_RUN_TESTS_EVENTS_FILE never
// resolved to a writable path, or the reporter module never loaded in the
// child at all (the `reporter:init` marker below is the reporter's very
// FIRST action, before any test can run, so its absence pins the failure
@@ -1204,8 +1204,8 @@ function main() {
throw new ExitError(2);
}
const testDir = process.env.GSD_TEST_DIR
? process.env.GSD_TEST_DIR
const testDir = process.env.MSD_TEST_DIR
? process.env.MSD_TEST_DIR
: join(__dirname, '..', 'tests');
const allFiles = walkTestFiles(testDir, '').sort();
@@ -1332,9 +1332,9 @@ function main() {
return 0;
}
// Empty suite/default run: this means discovery or the suite filter is broken.
// Allow GSD_ALLOW_EMPTY_SUITE=1 as an escape hatch (downgrades to a warning).
if (process.env.GSD_ALLOW_EMPTY_SUITE === '1') {
console.error(`run-tests: WARNING: 0 test files selected for suite "${suite || 'all'}" — discovery or suite filter may be broken (GSD_ALLOW_EMPTY_SUITE=1 suppressed the error)`);
// Allow MSD_ALLOW_EMPTY_SUITE=1 as an escape hatch (downgrades to a warning).
if (process.env.MSD_ALLOW_EMPTY_SUITE === '1') {
console.error(`run-tests: WARNING: 0 test files selected for suite "${suite || 'all'}" — discovery or suite filter may be broken (MSD_ALLOW_EMPTY_SUITE=1 suppressed the error)`);
return 0;
}
console.error(`run-tests: ERROR: 0 test files selected for suite "${suite || 'all'}" — discovery or suite filter is broken`);
@@ -1350,16 +1350,16 @@ function main() {
ensureBuiltHooks();
// Hermeticity: in-process tests resolve `.planning` via planningDir(cwd), which
// honours GSD_PROJECT/GSD_WORKSTREAM. A developer shell inside a GSD workstream
// exports GSD_WORKSTREAM, which would redirect fixture STATE.md reads away from
// honours MSD_PROJECT/MSD_WORKSTREAM. A developer shell inside a MSD workstream
// exports MSD_WORKSTREAM, which would redirect fixture STATE.md reads away from
// each <tmp>/.planning and silently diverge from the clean CI/Docker env. Strip
// them so the local runner matches CI; tests that need them set them explicitly.
delete process.env.GSD_PROJECT;
delete process.env.GSD_WORKSTREAM;
delete process.env.MSD_PROJECT;
delete process.env.MSD_WORKSTREAM;
delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
// #4020: bound the run's temp footprint BEFORE any sandbox below mkdtemps, so
// every child allocation (fixtures, GSD_HOME, events) lands inside one root
// every child allocation (fixtures, MSD_HOME, events) lands inside one root
// that is swept between chunks and removed on exit. Announced on stderr so an
// operator (and tests/run-tests-temp-root.test.cjs) can observe it.
const runTempRoot = setupRunTempRoot();
@@ -1383,7 +1383,7 @@ function main() {
// every ancestor of every selected file that lies INSIDE the run root.
const sweepProtectSet = computeSweepProtectSet(selected, runTempRoot);
// Sandbox the overlay home so the loader's global scan ($GSD_HOME/.gsd/capabilities)
// Sandbox the overlay home so the loader's global scan ($MSD_HOME/.msd/capabilities)
// cannot read a developer's real installed capabilities during tests (ADR-1244 D2).
// IDEMPOTENT: a nested run-tests spawn (e.g. tests/run-tests-harness.test.cjs)
// inherits this sandbox via env — it must REUSE it, never mkdtemp a fresh dir per
@@ -1392,9 +1392,9 @@ function main() {
const { mkdtempSync } = require('fs');
const { join: _join, basename: _basename } = require('path');
const { tmpdir } = require('os');
const _gh = process.env.GSD_HOME;
if (!_gh || !_basename(_gh).startsWith('gsd-test-home-')) {
process.env.GSD_HOME = mkdtempSync(_join(tmpdir(), 'gsd-test-home-'));
const _gh = process.env.MSD_HOME;
if (!_gh || !_basename(_gh).startsWith('msd-test-home-')) {
process.env.MSD_HOME = mkdtempSync(_join(tmpdir(), 'msd-test-home-'));
}
}
@@ -1604,7 +1604,7 @@ function main() {
// human one so a chunk timeout can name the file that was in flight (see
// scripts/lib/ndjson-reporter.cjs for the full contract writeup, its
// Node-docs citation, and — load-bearing — why it writes via
// `fs.appendFileSync` to a path passed through GSD_RUN_TESTS_EVENTS_FILE
// `fs.appendFileSync` to a path passed through MSD_RUN_TESTS_EVENTS_FILE
// instead of yielding strings for Node to pipe through
// `--test-reporter-destination`: that destination is backed by an
// `fs.WriteStream`, which BUFFERS, and execFileSync's timeout SIGKILLs the
@@ -1631,7 +1631,7 @@ function main() {
// each chunk gets its own events file inside it so a diagnostic read never
// races with, or is polluted by, another chunk's events. Deleted on the
// success path; kept only long enough to read back on a timeout.
const eventsDir = mkdtempSync(join(tmpdir(), 'gsd-run-tests-events-'));
const eventsDir = mkdtempSync(join(tmpdir(), 'msd-run-tests-events-'));
// #3889: Node documents `--test-reporter`'s value as "a string similar to
// those used in import() statements" (https://nodejs.org/api/test.html#--test-reporter),
// NOT a bare filesystem path — a bare absolute path is not a portable
@@ -1652,12 +1652,12 @@ function main() {
// close to that ceiling.
const eventsPathFor = (i) => join(eventsDir, `chunk-${String(i).padStart(3, '0')}.ndjson`);
// Fixed argv for every chunk: the events path moved to the environment
// (GSD_RUN_TESTS_EVENTS_FILE, set per-chunk below in execFileSync's `env`),
// (MSD_RUN_TESTS_EVENTS_FILE, set per-chunk below in execFileSync's `env`),
// which does NOT count toward the Windows 32,767-char argv ceiling — only
// this fixed sink destination does.
//
// The ndjson reporter yields nothing and ignores its own destination — the
// durable write path is GSD_RUN_TESTS_EVENTS_FILE above — but Node still
// durable write path is MSD_RUN_TESTS_EVENTS_FILE above — but Node still
// opens this destination as a real fs.WriteStream and fsyncs it on close,
// so it MUST be a regular file. os.devNull (a character device on every
// platform) fails that fsync with EINVAL, crashing every chunk, not just
@@ -1724,18 +1724,18 @@ function main() {
// different evidence.
const chunkTimeoutMs = positiveNumberEnv(process.env.RUN_TESTS_CHUNK_TIMEOUT_MS, 600000);
// #2665: snapshot GSD's install footprint in every LIVE runtime config dir
// #2665: snapshot MSD's install footprint in every LIVE runtime config dir
// before a single test runs. The suite must not write there; the check after
// the chunk loop is what makes a violation loud instead of silent. See
// scripts/live-config-guard.cjs for why the scope is narrow (it is deliberately
// NOT under scripts/lib/, which the installer copies to users wholesale).
const liveConfigGuardEnabled = process.env.GSD_SKIP_LIVE_CONFIG_GUARD !== '1';
const liveConfigGuardEnabled = process.env.MSD_SKIP_LIVE_CONFIG_GUARD !== '1';
let liveConfigRoots = [];
let liveConfigExtras = [];
let liveConfigBefore = null;
if (liveConfigGuardEnabled) {
liveConfigRoots = resolveLiveConfigRoots();
// #2665 round 3: $GSD_HOME/.gsd, and one native config.toml per non-registry
// #2665 round 3: $MSD_HOME/.msd, and one native config.toml per non-registry
// config-home descriptor (Kimi CLI's and, since #2755, Kimi Code's), are live
// write surfaces that are not runtime config ROOTS, so they are invisible to the
// line above. Watched independently — and note the OR: the extras alone are
@@ -1766,7 +1766,7 @@ function main() {
],
{
stdio: 'inherit',
env: { ...process.env, GSD_RUN_TESTS_EVENTS_FILE: chunkEventsPath },
env: { ...process.env, MSD_RUN_TESTS_EVENTS_FILE: chunkEventsPath },
timeout: chunkTimeoutMs,
},
);
@@ -1930,7 +1930,7 @@ function main() {
console.error(formatViolations(violations));
// Reports by default; fails only under opt-in strict mode. See the
// SEVERITY note in scripts/live-config-guard.cjs for why.
if (process.env.GSD_STRICT_LIVE_CONFIG_GUARD === '1' && firstFailureExit === 0) {
if (process.env.MSD_STRICT_LIVE_CONFIG_GUARD === '1' && firstFailureExit === 0) {
firstFailureExit = 1;
}
}