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:
@@ -23,11 +23,11 @@ const { runNode } = require('./process-seam.cjs');
|
||||
|
||||
const {
|
||||
resolveRuntimeArtifactLayout,
|
||||
} = require('../../gsd-core/bin/lib/runtime-artifact-layout.cjs');
|
||||
const { escapeRegex: escapeRegExp } = require('../../gsd-core/bin/lib/pattern.cjs');
|
||||
} = require('../../msd-core/bin/lib/runtime-artifact-layout.cjs');
|
||||
const { escapeRegex: escapeRegExp } = require('../../msd-core/bin/lib/pattern.cjs');
|
||||
|
||||
const INSTALL_SCRIPT = path.join(__dirname, '..', '..', 'bin', 'install.js');
|
||||
const MANIFEST_NAME = 'gsd-file-manifest.json';
|
||||
const MANIFEST_NAME = 'msd-file-manifest.json';
|
||||
|
||||
// #3145: class-norm timeout (bounds the previously-unbounded spawnSync in
|
||||
// runMinimalInstall) — not a per-suite value. See helpers/timeouts.cjs for
|
||||
@@ -39,23 +39,23 @@ const BUILD_SCRIPT = path.join(__dirname, '..', '..', 'scripts', 'build-hooks.js
|
||||
const HOOKS_DIST = path.join(__dirname, '..', '..', 'hooks', 'dist');
|
||||
|
||||
const EXPECTED_SH_HOOKS = [
|
||||
'gsd-session-state.sh',
|
||||
'gsd-validate-commit.sh',
|
||||
'gsd-phase-boundary.sh',
|
||||
'msd-session-state.sh',
|
||||
'msd-validate-commit.sh',
|
||||
'msd-phase-boundary.sh',
|
||||
];
|
||||
|
||||
const EXPECTED_ALL_HOOKS = [
|
||||
'gsd-agent-isolation-guard.js',
|
||||
'gsd-check-update.js',
|
||||
'gsd-config-reload.js',
|
||||
'gsd-context-monitor.js',
|
||||
'msd-agent-isolation-guard.js',
|
||||
'msd-check-update.js',
|
||||
'msd-config-reload.js',
|
||||
'msd-context-monitor.js',
|
||||
// #997: SessionStart canonical-path bootstrap for plugin installs.
|
||||
'gsd-ensure-canonical-path.js',
|
||||
'gsd-prompt-guard.js',
|
||||
'gsd-read-guard.js',
|
||||
'gsd-read-injection-scanner.js',
|
||||
'gsd-statusline.js',
|
||||
'gsd-workflow-guard.js',
|
||||
'msd-ensure-canonical-path.js',
|
||||
'msd-prompt-guard.js',
|
||||
'msd-read-guard.js',
|
||||
'msd-read-injection-scanner.js',
|
||||
'msd-statusline.js',
|
||||
'msd-workflow-guard.js',
|
||||
...EXPECTED_SH_HOOKS,
|
||||
];
|
||||
|
||||
@@ -87,8 +87,8 @@ const RUNTIME_META = {
|
||||
*
|
||||
* NOT simply `Object.keys(RUNTIME_META)`: that has 18 entries while the fixture set has
|
||||
* 19. The extra one is `claude-local` — claude is the reference host and the ONLY
|
||||
* runtime with a distinct LOCAL "legacy flat-commands" layout (`commands/gsd-*.md` +
|
||||
* `agents/gsd-*.md` at project scope), which `golden-install-parity.test.cjs` guards
|
||||
* runtime with a distinct LOCAL "legacy flat-commands" layout (`commands/msd-*.md` +
|
||||
* `agents/msd-*.md` at project scope), which `golden-install-parity.test.cjs` guards
|
||||
* with a hand-coded test outside its RUNTIME_META loop (#2086).
|
||||
*
|
||||
* Enumerating from RUNTIME_META alone dropped that family from BOTH sides of the
|
||||
@@ -136,7 +136,7 @@ const SKILL_RUNTIMES = [
|
||||
|
||||
// This checkout's own package version — the DEFAULT normalized in hash computation so
|
||||
// the golden is stable across version bumps (the rc step runs `npm version X.Y.Z-rc.N`
|
||||
// before tests, which rebakes the version into hook files and gsd-core/VERSION).
|
||||
// before tests, which rebakes the version into hook files and msd-core/VERSION).
|
||||
//
|
||||
// This is only a default. buildParityManifest's `pkgVersion` option exists precisely
|
||||
// because the tree being MEASURED is not always this checkout (#2767's `repoRoot`
|
||||
@@ -147,24 +147,24 @@ const SKILL_RUNTIMES = [
|
||||
const PKG_VERSION = require('../../package.json').version;
|
||||
|
||||
// Volatile metadata files always excluded from the parity manifest.
|
||||
// .gsd-source (#1477, claude-global only) records the install-time absolute path
|
||||
// to the package's commands/gsd source tree, which is the checkout/CI workspace
|
||||
// .msd-source (#1477, claude-global only) records the install-time absolute path
|
||||
// to the package's commands/msd source tree, which is the checkout/CI workspace
|
||||
// path — NOT the temp HOME root, so it is never normalized to '<HOME>' and its
|
||||
// hash varies by environment. Excluded for the same reason as gsd-install-state.json.
|
||||
// gsd-core/CHANGELOG.md is excluded because it contains historical version strings
|
||||
// hash varies by environment. Excluded for the same reason as msd-install-state.json.
|
||||
// msd-core/CHANGELOG.md is excluded because it contains historical version strings
|
||||
// that cause hash drift between local (PKG_VERSION=1.x.x) and CI (PKG_VERSION=1.x.x-rc.N):
|
||||
// the PKG_VERSION normalization below replaces only the *current* version, but
|
||||
// CHANGELOG.md references prior-release versions, so the normalized hash diverges.
|
||||
// gsd-file-manifest.json's exclusion was revisited deliberately for #2872: the
|
||||
// msd-file-manifest.json's exclusion was revisited deliberately for #2872: the
|
||||
// manifest gained `manifestVersion`/`runtime`/`scope` fields, all of which are
|
||||
// deterministic and would not by themselves force an exclusion, but `timestamp`
|
||||
// — the original reason this file is volatile — is unchanged by #2872, so the
|
||||
// exclusion still holds for exactly the same reason it always has.
|
||||
const VOLATILE_FILES = new Set([
|
||||
'gsd-file-manifest.json',
|
||||
'gsd-install-state.json',
|
||||
'.gsd-source',
|
||||
'gsd-core/CHANGELOG.md',
|
||||
'msd-file-manifest.json',
|
||||
'msd-install-state.json',
|
||||
'.msd-source',
|
||||
'msd-core/CHANGELOG.md',
|
||||
]);
|
||||
|
||||
// Hook-registration config files excluded from the parity manifest. These are
|
||||
@@ -199,7 +199,7 @@ const HOOK_CONFIG_FILES = new Set(['settings.json', 'settings.local.json', 'hook
|
||||
// compares base-vs-current on the same machine, so the platform-varying
|
||||
// node-runner command embedded in the TOML never crosses platforms inside a
|
||||
// gate (that was a golden-content-era hazard, and the goldens are gone).
|
||||
// Kimi CLI's config.toml (KIMI_SHARE_DIR root ~/.kimi) lives OUTSIDE its GSD
|
||||
// Kimi CLI's config.toml (KIMI_SHARE_DIR root ~/.kimi) lives OUTSIDE its MSD
|
||||
// configDir (~/.config/agents) and never enters the walk. The pre-#3547
|
||||
// relative-path exclusions ('.kimi/config.toml', '.kimi-code/config.toml')
|
||||
// existed only for the collapsed shape — where the walked root was the HOME
|
||||
@@ -208,7 +208,7 @@ const HOOK_CONFIG_FILES = new Set(['settings.json', 'settings.local.json', 'hook
|
||||
// resolves its own root since #2755.
|
||||
const HOOK_CONFIG_RELATIVE_PATHS = new Set();
|
||||
|
||||
// Path prefixes excluded from the parity manifest. `gsd-core/bin/lib/` holds the
|
||||
// Path prefixes excluded from the parity manifest. `msd-core/bin/lib/` holds the
|
||||
// tsc-built runtime artifacts (compiled from src/*.cts) that the install COPIES
|
||||
// verbatim — they are NOT produced by installRuntimeArtifacts (the move's parity
|
||||
// scope), and their exact bytes depend on the BUILD environment (a clean tsc
|
||||
@@ -218,7 +218,7 @@ const HOOK_CONFIG_RELATIVE_PATHS = new Set();
|
||||
// (e.g. milestone.cjs, roadmap.cjs). The .cts sources are type-checked + drift-
|
||||
// guarded + coverage-gated elsewhere; this harness asserts the CONVERTED artifact
|
||||
// output (skills/commands/agents) that the engine actually emits.
|
||||
const EXCLUDED_PREFIXES = ['gsd-core/bin/lib/'];
|
||||
const EXCLUDED_PREFIXES = ['msd-core/bin/lib/'];
|
||||
|
||||
// ─── Helper functions ─────────────────────────────────────────────────────────
|
||||
|
||||
@@ -250,22 +250,22 @@ const SEMVER_ISH_RE = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/;
|
||||
* (false negative), while an UNCHANGED file that happens to contain a literal equal to
|
||||
* only the CURRENT version collapses on one side only and reports as spurious drift
|
||||
* (false positive). Emitted sources really do carry bare semver literals that are NOT
|
||||
* install-time stamps — e.g. gsd-core/workflows/update.md's `1.4.0`/`1.3.1` examples,
|
||||
* agents/gsd-project-researcher.md's `1.2.3`, gsd-core/workflows/help/modes/full.md's
|
||||
* install-time stamps — e.g. msd-core/workflows/update.md's `1.4.0`/`1.3.1` examples,
|
||||
* agents/msd-project-researcher.md's `1.2.3`, msd-core/workflows/help/modes/full.md's
|
||||
* `1.0.0` — and those must stay VISIBLE to the parity gate if they ever change.
|
||||
*
|
||||
* So instead of replacing the version everywhere, this only normalizes it at the
|
||||
* specific places `bin/install.js` actually stamps `pkg.version` into emitted content
|
||||
* as a version FIELD/marker (not prose):
|
||||
* - `// gsd-hook-version: <ver>` / `# gsd-hook-version: <ver>` — the
|
||||
* `{{GSD_VERSION}}` substitution done for every emitted hook file.
|
||||
* - `// msd-hook-version: <ver>` / `# msd-hook-version: <ver>` — the
|
||||
* `{{MSD_VERSION}}` substitution done for every emitted hook file.
|
||||
* - `"version": "<ver>"` — JSON manifests (plugin/extension/capability-style)
|
||||
* embedding the package version as a string field.
|
||||
* - `version: "<ver>"` / `version: <ver>` — YAML frontmatter version fields (e.g.
|
||||
* skill frontmatter's `yamlQuote(pkg.version)`, Hermes' category
|
||||
* `DESCRIPTION.md`).
|
||||
* - `@opengsd/gsd-core@<ver>` — pinned package-spec references.
|
||||
* - a file whose ENTIRE trimmed content IS the version (`gsd-core/VERSION`).
|
||||
* - `@golem15/msd-core@<ver>` — pinned package-spec references.
|
||||
* - a file whose ENTIRE trimmed content IS the version (`msd-core/VERSION`).
|
||||
* Each pattern only matches when the version in the content EQUALS the supplied
|
||||
* `pkgVersion` — this is deliberately narrow, at the cost of needing a new pattern any
|
||||
* time the installer grows a new stamp site (see the empirical repro-harness check
|
||||
@@ -281,11 +281,11 @@ function normalizeVersionStamps(content, pkgVersion) {
|
||||
// from matching as a PREFIX of a longer version-shaped string it is not equal to
|
||||
// (e.g. pkgVersion '1.9.0' must not match inside '1.9.0-rc.1' or '1.9.0.1').
|
||||
return content
|
||||
.replace(new RegExp(`((?:\\/\\/|#)\\s*gsd-hook-version:\\s*)${v}(?![\\w.+-])`, 'g'), '$1<VERSION>')
|
||||
.replace(new RegExp(`((?:\\/\\/|#)\\s*msd-hook-version:\\s*)${v}(?![\\w.+-])`, 'g'), '$1<VERSION>')
|
||||
.replace(new RegExp(`("version"\\s*:\\s*")${v}(")`, 'g'), '$1<VERSION>$2')
|
||||
.replace(new RegExp(`(version:\\s*")${v}(")`, 'g'), '$1<VERSION>$2')
|
||||
.replace(new RegExp(`(version:\\s*)${v}(?![\\w.+-])`, 'g'), '$1<VERSION>')
|
||||
.replace(new RegExp(`(@opengsd/gsd-core@)${v}(?![\\w.+-])`, 'g'), '$1<VERSION>')
|
||||
.replace(new RegExp(`(@golem15/msd-core@)${v}(?![\\w.+-])`, 'g'), '$1<VERSION>')
|
||||
.replace(new RegExp(`^(\\s*)${v}(\\s*)$`), '$1<VERSION>$2');
|
||||
}
|
||||
|
||||
@@ -582,18 +582,18 @@ function simulateHookCopy(hooksSrc, hooksDest) {
|
||||
}
|
||||
|
||||
/** Build a clean env for spawned installer processes.
|
||||
* Must strip GSD_TEST_MODE so the child runs the real install, not the no-op guard. */
|
||||
* Must strip MSD_TEST_MODE so the child runs the real install, not the no-op guard. */
|
||||
function installerEnv(overrides = {}) {
|
||||
// #3156: delegate to the ONE canonical raw-installer-spawn env rather than
|
||||
// carrying a second shape of it. The installer writes GSD's own user store to
|
||||
// <home>/.gsd/defaults.json through os.homedir() DIRECTLY
|
||||
// (bin/install.js writeNonClaudeDefaults, #2834), which reads no GSD variable,
|
||||
// carrying a second shape of it. The installer writes MSD's own user store to
|
||||
// <home>/.msd/defaults.json through os.homedir() DIRECTLY
|
||||
// (bin/install.js writeNonClaudeDefaults, #2834), which reads no MSD variable,
|
||||
// so no config-location scrub can reach it — only a sandboxed HOME can. Every
|
||||
// caller that already passes an explicit { HOME, USERPROFILE } still wins:
|
||||
// overrides spread last.
|
||||
const { installSpawnEnv } = require('../helpers.cjs');
|
||||
const env = installSpawnEnv(overrides);
|
||||
delete env.GSD_TEST_MODE;
|
||||
delete env.MSD_TEST_MODE;
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -614,7 +614,7 @@ function installerEnv(overrides = {}) {
|
||||
*/
|
||||
function runMinimalInstall({ runtime, scope, extraArgs = [], installScript = INSTALL_SCRIPT, root: providedRoot = null, extraEnv = {} }) {
|
||||
const ownsRoot = providedRoot === null;
|
||||
const root = providedRoot ?? fs.mkdtempSync(path.join(os.tmpdir(), `gsd-${runtime}-${scope}-`));
|
||||
const root = providedRoot ?? fs.mkdtempSync(path.join(os.tmpdir(), `msd-${runtime}-${scope}-`));
|
||||
try {
|
||||
let configDir;
|
||||
let cwd = process.cwd();
|
||||
@@ -625,7 +625,7 @@ function runMinimalInstall({ runtime, scope, extraArgs = [], installScript = INS
|
||||
// (RUNTIME_META.globalSuffix mirrors the registry's getGlobalConfigDir
|
||||
// for every runtime). The previous `--config-dir <root>` collapsed
|
||||
// configDir onto HOME, so computePathPrefix emitted bare `$HOME/`
|
||||
// prefixes and the emitted bytes referenced `$HOME/gsd-core/…` — a path
|
||||
// prefixes and the emitted bytes referenced `$HOME/msd-core/…` — a path
|
||||
// no real install produces — leaving every emitted-artifact gate
|
||||
// (ADR-2719 differential, install-tree fixtures, the 19-family baseline)
|
||||
// blind to drift confined to the real global shape (#3544 evidence: 54
|
||||
@@ -704,21 +704,21 @@ function manifestSkillSet(manifest) {
|
||||
const out = new Set();
|
||||
for (const key of Object.keys(manifest.files)) {
|
||||
if (key.startsWith('skills/')) {
|
||||
const seg = key.split('/')[1].replace(/^gsd-/, '').replace(/\.md$/, '');
|
||||
const seg = key.split('/')[1].replace(/^msd-/, '').replace(/\.md$/, '');
|
||||
out.add(seg);
|
||||
} else if (key.startsWith('command/')) {
|
||||
// OpenCode/Kilo: command/gsd-<cmd>.md
|
||||
// OpenCode/Kilo: command/msd-<cmd>.md
|
||||
const file = key.split('/')[1];
|
||||
out.add(file.replace(/^gsd-/, '').replace(/\.md$/, ''));
|
||||
} else if (key.startsWith('commands/gsd/')) {
|
||||
// Gemini: commands/gsd/<cmd>.toml (nested, colon-namespaced)
|
||||
out.add(file.replace(/^msd-/, '').replace(/\.md$/, ''));
|
||||
} else if (key.startsWith('commands/msd/')) {
|
||||
// Gemini: commands/msd/<cmd>.toml (nested, colon-namespaced)
|
||||
const file = key.split('/')[2];
|
||||
out.add(file.replace(/\.(md|toml)$/, ''));
|
||||
} else if (key.startsWith('commands/') && key.split('/').length === 2) {
|
||||
// Claude local (#1367 fix): flat commands/gsd-<cmd>.md
|
||||
// Claude local (#1367 fix): flat commands/msd-<cmd>.md
|
||||
const file = key.split('/')[1];
|
||||
if (file.startsWith('gsd-') && file.endsWith('.md')) {
|
||||
out.add(file.replace(/^gsd-/, '').replace(/\.md$/, ''));
|
||||
if (file.startsWith('msd-') && file.endsWith('.md')) {
|
||||
out.add(file.replace(/^msd-/, '').replace(/\.md$/, ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -731,7 +731,7 @@ function manifestAgentCount(manifest) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect gsd-* skill/command basenames actually present on disk under configDir.
|
||||
* Collect msd-* skill/command basenames actually present on disk under configDir.
|
||||
*
|
||||
* @param {string} configDir
|
||||
* @param {string} [runtime] - when provided, the skills-kind destination is
|
||||
@@ -753,35 +753,35 @@ function collectSkillBasenamesOnDisk(configDir, runtime, scope = 'global') {
|
||||
}
|
||||
if (fs.existsSync(skillsDir)) {
|
||||
for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
|
||||
if (entry.isDirectory() && entry.name.startsWith('gsd-')) {
|
||||
out.add(entry.name.replace(/^gsd-/, ''));
|
||||
} else if (entry.isFile() && entry.name.startsWith('gsd-') && entry.name.endsWith('.md')) {
|
||||
out.add(entry.name.replace(/^gsd-/, '').replace(/\.md$/, ''));
|
||||
if (entry.isDirectory() && entry.name.startsWith('msd-')) {
|
||||
out.add(entry.name.replace(/^msd-/, ''));
|
||||
} else if (entry.isFile() && entry.name.startsWith('msd-') && entry.name.endsWith('.md')) {
|
||||
out.add(entry.name.replace(/^msd-/, '').replace(/\.md$/, ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
const commandDir = path.join(configDir, 'command');
|
||||
if (fs.existsSync(commandDir)) {
|
||||
for (const file of fs.readdirSync(commandDir)) {
|
||||
if (file.startsWith('gsd-') && file.endsWith('.md')) {
|
||||
out.add(file.replace(/^gsd-/, '').replace(/\.md$/, ''));
|
||||
if (file.startsWith('msd-') && file.endsWith('.md')) {
|
||||
out.add(file.replace(/^msd-/, '').replace(/\.md$/, ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
const commandsGsdDir = path.join(configDir, 'commands', 'gsd');
|
||||
if (fs.existsSync(commandsGsdDir)) {
|
||||
for (const file of fs.readdirSync(commandsGsdDir)) {
|
||||
const commandsMsdDir = path.join(configDir, 'commands', 'msd');
|
||||
if (fs.existsSync(commandsMsdDir)) {
|
||||
for (const file of fs.readdirSync(commandsMsdDir)) {
|
||||
if (file.endsWith('.md') || file.endsWith('.toml')) {
|
||||
out.add(file.replace(/\.(md|toml)$/, ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Claude local (#1367 fix): flat gsd-*.md files at commands/ level
|
||||
// Claude local (#1367 fix): flat msd-*.md files at commands/ level
|
||||
const flatCommandsDir = path.join(configDir, 'commands');
|
||||
if (fs.existsSync(flatCommandsDir)) {
|
||||
for (const file of fs.readdirSync(flatCommandsDir)) {
|
||||
if (file.startsWith('gsd-') && file.endsWith('.md')) {
|
||||
out.add(file.replace(/^gsd-/, '').replace(/\.md$/, ''));
|
||||
if (file.startsWith('msd-') && file.endsWith('.md')) {
|
||||
out.add(file.replace(/^msd-/, '').replace(/\.md$/, ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user