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:
@@ -16,34 +16,34 @@ const BASELINE_MIGRATION_ID = '2026-05-11-first-time-baseline-scan';
|
||||
// - docs/installer-migrations.md#runtime-configuration-contract-registry
|
||||
// - docs/ARCHITECTURE.md#runtime-install-contract-matrix
|
||||
const RUNTIME_SURFACES: Record<string, string[]> = {
|
||||
claude: ['gsd-core', 'commands/gsd', 'skills', 'agents', 'hooks', 'settings.json'],
|
||||
codex: ['gsd-core', 'skills', 'agents', 'hooks', 'config.toml', 'hooks.json'],
|
||||
gemini: ['gsd-core', 'commands/gsd', 'hooks'],
|
||||
opencode: ['gsd-core', 'command', 'skills', 'agents'],
|
||||
kilo: ['gsd-core', 'command', 'skills', 'agents'],
|
||||
copilot: ['gsd-core', 'skills', 'agents'],
|
||||
antigravity: ['gsd-core', 'skills', 'agents'],
|
||||
cursor: ['gsd-core', 'skills', 'agents', 'hooks', 'hooks.json'],
|
||||
windsurf: ['gsd-core', 'skills', 'agents', 'rules'],
|
||||
augment: ['gsd-core', 'skills', 'agents'],
|
||||
trae: ['gsd-core', 'skills', 'agents', 'rules'],
|
||||
qwen: ['gsd-core', 'skills', 'agents'],
|
||||
hermes: ['gsd-core', 'skills/gsd', 'agents'],
|
||||
cline: ['gsd-core', 'skills', 'agents'],
|
||||
codebuddy: ['gsd-core', 'skills', 'agents'],
|
||||
claude: ['msd-core', 'commands/msd', 'skills', 'agents', 'hooks', 'settings.json'],
|
||||
codex: ['msd-core', 'skills', 'agents', 'hooks', 'config.toml', 'hooks.json'],
|
||||
gemini: ['msd-core', 'commands/msd', 'hooks'],
|
||||
opencode: ['msd-core', 'command', 'skills', 'agents'],
|
||||
kilo: ['msd-core', 'command', 'skills', 'agents'],
|
||||
copilot: ['msd-core', 'skills', 'agents'],
|
||||
antigravity: ['msd-core', 'skills', 'agents'],
|
||||
cursor: ['msd-core', 'skills', 'agents', 'hooks', 'hooks.json'],
|
||||
windsurf: ['msd-core', 'skills', 'agents', 'rules'],
|
||||
augment: ['msd-core', 'skills', 'agents'],
|
||||
trae: ['msd-core', 'skills', 'agents', 'rules'],
|
||||
qwen: ['msd-core', 'skills', 'agents'],
|
||||
hermes: ['msd-core', 'skills/msd', 'agents'],
|
||||
cline: ['msd-core', 'skills', 'agents'],
|
||||
codebuddy: ['msd-core', 'skills', 'agents'],
|
||||
};
|
||||
|
||||
const COMMON_SURFACES = ['gsd-core', 'skills', 'agents', 'hooks'];
|
||||
const COMMON_SURFACES = ['msd-core', 'skills', 'agents', 'hooks'];
|
||||
const INTERNAL_TOP_LEVEL_NAMES = new Set([
|
||||
'gsd-file-manifest.json',
|
||||
'gsd-install-state.json',
|
||||
'gsd-migration-backups',
|
||||
'gsd-migration-journal',
|
||||
'msd-file-manifest.json',
|
||||
'msd-install-state.json',
|
||||
'msd-migration-backups',
|
||||
'msd-migration-journal',
|
||||
]);
|
||||
const USER_OWNED_PATHS = new Set([
|
||||
'gsd-core/USER-PROFILE.md',
|
||||
'commands/gsd/dev-preferences.md',
|
||||
'skills/gsd-dev-preferences/SKILL.md',
|
||||
'msd-core/USER-PROFILE.md',
|
||||
'commands/msd/dev-preferences.md',
|
||||
'skills/msd-dev-preferences/SKILL.md',
|
||||
]);
|
||||
let knownGeneratedAgentNames: Set<string> | null = null;
|
||||
|
||||
@@ -90,8 +90,8 @@ function scanBaselineFiles(configDir: string, runtime: string | undefined): stri
|
||||
function isUserOwnedBaselinePath(relPath: string): boolean {
|
||||
if (USER_OWNED_PATHS.has(relPath)) return true;
|
||||
const parts = relPath.split('/');
|
||||
if (parts[0] === 'skills' && parts[1] && !parts[1].startsWith('gsd-')) return true;
|
||||
if (parts[0] === 'agents' && parts[1] && !parts[1].startsWith('gsd-')) return true;
|
||||
if (parts[0] === 'skills' && parts[1] && !parts[1].startsWith('msd-')) return true;
|
||||
if (parts[0] === 'agents' && parts[1] && !parts[1].startsWith('msd-')) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,13 +102,13 @@ function listKnownGeneratedAgentNames(): Set<string> {
|
||||
const agentsDir = path.resolve(__dirname, '..', '..', '..', '..', 'agents');
|
||||
try {
|
||||
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
||||
if (entry.isFile() && entry.name.startsWith('gsd-') && entry.name.endsWith('.md')) {
|
||||
if (entry.isFile() && entry.name.startsWith('msd-') && entry.name.endsWith('.md')) {
|
||||
knownGeneratedAgentNames.add(entry.name.replace(/\.md$/, ''));
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// If the source agent directory is unavailable, fail closed and treat
|
||||
// GSD-looking agent files as user-choice artifacts.
|
||||
// MSD-looking agent files as user-choice artifacts.
|
||||
}
|
||||
|
||||
return knownGeneratedAgentNames;
|
||||
@@ -125,11 +125,11 @@ function isKnownGeneratedAgentPath(relPath: string, runtime: string | undefined)
|
||||
return listKnownGeneratedAgentNames().has(agentName);
|
||||
}
|
||||
|
||||
function isStaleGsdLookingPath(relPath: string): boolean {
|
||||
function isStaleMsdLookingPath(relPath: string): boolean {
|
||||
const baseName = path.posix.basename(relPath);
|
||||
if (/^gsd[-_]/.test(baseName)) return true;
|
||||
if (/^msd[-_]/.test(baseName)) return true;
|
||||
const parts = relPath.split('/');
|
||||
if ((parts[0] === 'skills' || parts[0] === 'agents') && parts[1] && parts[1].startsWith('gsd-')) {
|
||||
if ((parts[0] === 'skills' || parts[0] === 'agents') && parts[1] && parts[1].startsWith('msd-')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -225,15 +225,15 @@ const migration: InstallerMigration = {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isStaleGsdLookingPath(relPath)) {
|
||||
if (isStaleMsdLookingPath(relPath)) {
|
||||
actions.push({
|
||||
type: 'prompt-user',
|
||||
relPath,
|
||||
reason: 'GSD-looking file is not proven manifest-managed and needs explicit user choice',
|
||||
classification: 'stale-gsd-looking',
|
||||
reason: 'MSD-looking file is not proven manifest-managed and needs explicit user choice',
|
||||
classification: 'stale-msd-looking',
|
||||
originalHash: artifact.originalHash ?? null,
|
||||
currentHash,
|
||||
prompt: 'Choose whether to remove this stale-looking GSD artifact or keep it as user-owned.',
|
||||
prompt: 'Choose whether to remove this stale-looking MSD artifact or keep it as user-owned.',
|
||||
choices: ['keep', 'remove'],
|
||||
});
|
||||
continue;
|
||||
|
||||
@@ -37,7 +37,7 @@ interface InstallerMigration {
|
||||
}
|
||||
|
||||
const LEGACY_ORPHAN_FILES: ReadonlyArray<string> = [
|
||||
'hooks/gsd-notify.sh',
|
||||
'hooks/msd-notify.sh',
|
||||
'hooks/statusline.js',
|
||||
];
|
||||
|
||||
@@ -61,14 +61,14 @@ const migration: InstallerMigration = {
|
||||
type: 'remove-managed',
|
||||
relPath,
|
||||
reason: 'legacy orphan hook file retired by installer migration',
|
||||
ownershipEvidence: 'legacy hook path is manifest-managed in gsd-file-manifest.json',
|
||||
ownershipEvidence: 'legacy hook path is manifest-managed in msd-file-manifest.json',
|
||||
});
|
||||
} else if (artifact.classification === 'managed-modified') {
|
||||
actions.push({
|
||||
type: 'backup-and-remove',
|
||||
relPath,
|
||||
reason: 'legacy orphan hook file retired by installer migration',
|
||||
ownershipEvidence: 'legacy hook path is manifest-managed in gsd-file-manifest.json',
|
||||
ownershipEvidence: 'legacy hook path is manifest-managed in msd-file-manifest.json',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Installer migration: remove legacy Codex hooks.json GSD hook registrations.
|
||||
* Installer migration: remove legacy Codex hooks.json MSD hook registrations.
|
||||
*
|
||||
* ADR-457 build-at-publish: the hand-written
|
||||
* bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs collapsed to a
|
||||
@@ -107,8 +107,8 @@ function pruneLegacyCodexHooksJsonValue(value: JsonValue, configDir: string): Pr
|
||||
|
||||
const migration: InstallerMigration = {
|
||||
id: '2026-05-11-codex-legacy-hooks-json',
|
||||
title: 'Remove legacy Codex hooks.json GSD hook registrations',
|
||||
description: 'Remove legacy Codex hooks.json GSD hook registrations after config.toml migration.',
|
||||
title: 'Remove legacy Codex hooks.json MSD hook registrations',
|
||||
description: 'Remove legacy Codex hooks.json MSD hook registrations after config.toml migration.',
|
||||
introducedIn: '1.50.0',
|
||||
runtimes: ['codex'],
|
||||
scopes: ['global', 'local'],
|
||||
@@ -128,8 +128,8 @@ const migration: InstallerMigration = {
|
||||
relPath: 'hooks.json',
|
||||
value: pruned.value,
|
||||
deleteIfEmpty: true,
|
||||
reason: 'legacy Codex hooks.json GSD registration retired by installer migration',
|
||||
ownershipEvidence: 'pruned command matches generated GSD hook command under the install hooks directory',
|
||||
reason: 'legacy Codex hooks.json MSD registration retired by installer migration',
|
||||
ownershipEvidence: 'pruned command matches generated MSD hook command under the install hooks directory',
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Installer migration 003: remove stale legacy get-shit-done/ runtime directory // gsd-allow-legacy-name
|
||||
* files after the rename to gsd-core/ (#604).
|
||||
* Installer migration 003: remove stale legacy get-shit-done/ runtime directory // msd-allow-legacy-name
|
||||
* files after the rename to msd-core/ (#604).
|
||||
*
|
||||
* Background: the GSD runtime config subdirectory was renamed from
|
||||
* get-shit-done/ to gsd-core/ in #604. On upgrade, both directories can exist // gsd-allow-legacy-name
|
||||
* Background: the MSD runtime config subdirectory was renamed from
|
||||
* get-shit-done/ to msd-core/ in #604. On upgrade, both directories can exist // msd-allow-legacy-name
|
||||
* simultaneously. This migration removes prior-manifest-managed files from the
|
||||
* legacy get-shit-done/ directory during install. Migrations run BEFORE the new // gsd-allow-legacy-name
|
||||
* runtime is materialized, so gsd-core/ will not yet exist on the first upgrade
|
||||
* legacy get-shit-done/ directory during install. Migrations run BEFORE the new // msd-allow-legacy-name
|
||||
* runtime is materialized, so msd-core/ will not yet exist on the first upgrade
|
||||
* run — the migration must not gate on its presence. If the install fails after
|
||||
* migrations apply, the framework rolls back by restoring files from rollback
|
||||
* storage (copied before deletion), so removing legacy files pre-materialization
|
||||
@@ -58,7 +58,7 @@ function walkLegacyFiles(root: string, relDir: string, baseResolved: string, res
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
// Do not follow symlinks — skip them entirely to avoid out-of-tree traversal.
|
||||
if (entry.isSymbolicLink()) continue; // gsd-allow-legacy-name (entry under legacy get-shit-done/ dir)
|
||||
if (entry.isSymbolicLink()) continue; // msd-allow-legacy-name (entry under legacy get-shit-done/ dir)
|
||||
const relPath = path.posix.join(relDir, entry.name);
|
||||
// Bounds check: ensure the resolved path stays under configDir.
|
||||
const resolved = path.resolve(root, relPath);
|
||||
@@ -71,30 +71,30 @@ function walkLegacyFiles(root: string, relDir: string, baseResolved: string, res
|
||||
}
|
||||
}
|
||||
|
||||
const REASON = 'legacy runtime directory renamed to gsd-core (#604)';
|
||||
const REASON = 'legacy runtime directory renamed to msd-core (#604)';
|
||||
|
||||
const migration: InstallerMigration = {
|
||||
id: '2026-06-02-rename-get-shit-done-to-gsd-core', // gsd-allow-legacy-name
|
||||
title: 'Remove stale legacy get-shit-done/ runtime directory files (#604)', // gsd-allow-legacy-name
|
||||
id: '2026-06-02-rename-get-shit-done-to-msd-core', // msd-allow-legacy-name
|
||||
title: 'Remove stale legacy get-shit-done/ runtime directory files (#604)', // msd-allow-legacy-name
|
||||
description:
|
||||
'After the config dir rename from get-shit-done/ to gsd-core/ (#604), remove prior-manifest-managed files ' + // gsd-allow-legacy-name
|
||||
'After the config dir rename from get-shit-done/ to msd-core/ (#604), remove prior-manifest-managed files ' + // msd-allow-legacy-name
|
||||
'from the stale legacy directory during install (framework rollback restores them if install fails). User-added files are preserved.',
|
||||
introducedIn: '1.2.0',
|
||||
scopes: ['global', 'local'],
|
||||
destructive: true,
|
||||
plan(ctx: MigrationPlanContext): MigrationAction[] {
|
||||
const legacyRoot = path.join(ctx.configDir, 'get-shit-done'); // gsd-allow-legacy-name
|
||||
const legacyRoot = path.join(ctx.configDir, 'get-shit-done'); // msd-allow-legacy-name
|
||||
|
||||
// Idempotency: if the legacy directory doesn't exist, nothing to do.
|
||||
if (!fs.existsSync(legacyRoot)) return [];
|
||||
|
||||
// Safety: if the legacy root itself is a symlink to an out-of-tree location,
|
||||
// do not process it — walking a symlinked dir could emit removes outside configDir.
|
||||
if (fs.lstatSync(legacyRoot).isSymbolicLink()) return []; // gsd-allow-legacy-name
|
||||
if (fs.lstatSync(legacyRoot).isSymbolicLink()) return []; // msd-allow-legacy-name
|
||||
|
||||
const baseResolved = path.resolve(ctx.configDir);
|
||||
const relPaths: string[] = [];
|
||||
walkLegacyFiles(ctx.configDir, 'get-shit-done', baseResolved, relPaths); // gsd-allow-legacy-name
|
||||
walkLegacyFiles(ctx.configDir, 'get-shit-done', baseResolved, relPaths); // msd-allow-legacy-name
|
||||
|
||||
const actions: MigrationAction[] = [];
|
||||
for (const relPath of relPaths) {
|
||||
@@ -108,7 +108,7 @@ const migration: InstallerMigration = {
|
||||
relPath,
|
||||
reason: REASON,
|
||||
ownershipEvidence:
|
||||
'present in prior install manifest as a managed GSD runtime file',
|
||||
'present in prior install manifest as a managed MSD runtime file',
|
||||
});
|
||||
} else if (classification === 'managed-modified') {
|
||||
actions.push({
|
||||
@@ -116,7 +116,7 @@ const migration: InstallerMigration = {
|
||||
relPath,
|
||||
reason: REASON,
|
||||
ownershipEvidence:
|
||||
'managed GSD runtime file, locally modified; backed up before removal',
|
||||
'managed MSD runtime file, locally modified; backed up before removal',
|
||||
});
|
||||
} else if (classification === 'unknown') {
|
||||
actions.push({
|
||||
@@ -1,20 +1,20 @@
|
||||
/**
|
||||
* Installer migration 004: remove stale gsd-pristine/get-shit-done/ snapshot // gsd-allow-legacy-name
|
||||
* files after the get-shit-done → gsd-core rename (#604, #934). // gsd-allow-legacy-name
|
||||
* Installer migration 004: remove stale msd-pristine/get-shit-done/ snapshot // msd-allow-legacy-name
|
||||
* files after the get-shit-done → msd-core rename (#604, #934). // msd-allow-legacy-name
|
||||
*
|
||||
* Background: migration 003 removed legacy runtime files from
|
||||
* get-shit-done/ but did not touch gsd-pristine/get-shit-done/, the // gsd-allow-legacy-name
|
||||
* get-shit-done/ but did not touch msd-pristine/get-shit-done/, the // msd-allow-legacy-name
|
||||
* parallel directory that holds pristine snapshots captured before the rename.
|
||||
* These snapshot files are GSD-managed (written by the installer, never by the
|
||||
* user) and reference stale get-shit-done/... key paths that no longer exist // gsd-allow-legacy-name
|
||||
* These snapshot files are MSD-managed (written by the installer, never by the
|
||||
* user) and reference stale get-shit-done/... key paths that no longer exist // msd-allow-legacy-name
|
||||
* in the active layout. When verify-reapply-patches.cjs looks up a backup entry
|
||||
* keyed under gsd-core/... it finds no matching gsd-pristine/ snapshot, falls
|
||||
* to over-broad mode, and reports false FAIL_INSTALLED_MISSING / // gsd-allow-legacy-name
|
||||
* keyed under msd-core/... it finds no matching msd-pristine/ snapshot, falls
|
||||
* to over-broad mode, and reports false FAIL_INSTALLED_MISSING / // msd-allow-legacy-name
|
||||
* FAIL_USER_LINES_MISSING for every backed-up pre-rename file (#934).
|
||||
*
|
||||
* Fix: walk gsd-pristine/get-shit-done/ and emit remove-managed for each file. // gsd-allow-legacy-name
|
||||
* These files are always GSD-written snapshots — users never place their own
|
||||
* files inside gsd-pristine/ — so the classification override
|
||||
* Fix: walk msd-pristine/get-shit-done/ and emit remove-managed for each file. // msd-allow-legacy-name
|
||||
* These files are always MSD-written snapshots — users never place their own
|
||||
* files inside msd-pristine/ — so the classification override
|
||||
* (managed-pristine) is safe: there is no user content to protect.
|
||||
*
|
||||
* Checksum safety: migration 003's body is left untouched. Adding this
|
||||
@@ -76,44 +76,44 @@ function walkPristineFiles(root: string, relDir: string, baseResolved: string, r
|
||||
}
|
||||
}
|
||||
|
||||
const REASON = 'stale pristine snapshot from legacy get-shit-done/ dir, orphaned by rename migration 003 (#604, #934)'; // gsd-allow-legacy-name
|
||||
const REASON = 'stale pristine snapshot from legacy get-shit-done/ dir, orphaned by rename migration 003 (#604, #934)'; // msd-allow-legacy-name
|
||||
|
||||
const migration: InstallerMigration = {
|
||||
id: '2026-06-09-prune-stale-pristine-get-shit-done', // gsd-allow-legacy-name
|
||||
title: 'Remove stale gsd-pristine/get-shit-done/ snapshot files (#934)', // gsd-allow-legacy-name
|
||||
id: '2026-06-09-prune-stale-pristine-get-shit-done', // msd-allow-legacy-name
|
||||
title: 'Remove stale msd-pristine/get-shit-done/ snapshot files (#934)', // msd-allow-legacy-name
|
||||
description:
|
||||
'Migration 003 removed runtime files from get-shit-done/ but left the matching pristine snapshot ' + // gsd-allow-legacy-name
|
||||
'directory gsd-pristine/get-shit-done/ intact. Those snapshots reference stale key paths and cause ' + // gsd-allow-legacy-name
|
||||
'verify-reapply-patches false positives (#934). Remove all files under gsd-pristine/get-shit-done/ ' + // gsd-allow-legacy-name
|
||||
'as they are GSD-managed snapshots, never user content.',
|
||||
'Migration 003 removed runtime files from get-shit-done/ but left the matching pristine snapshot ' + // msd-allow-legacy-name
|
||||
'directory msd-pristine/get-shit-done/ intact. Those snapshots reference stale key paths and cause ' + // msd-allow-legacy-name
|
||||
'verify-reapply-patches false positives (#934). Remove all files under msd-pristine/get-shit-done/ ' + // msd-allow-legacy-name
|
||||
'as they are MSD-managed snapshots, never user content.',
|
||||
introducedIn: '1.4.3',
|
||||
scopes: ['global', 'local'],
|
||||
destructive: true,
|
||||
plan(ctx: MigrationPlanContext): MigrationAction[] {
|
||||
const pristineGsdRoot = path.join(ctx.configDir, 'gsd-pristine', 'get-shit-done'); // gsd-allow-legacy-name
|
||||
const pristineMsdRoot = path.join(ctx.configDir, 'msd-pristine', 'get-shit-done'); // msd-allow-legacy-name
|
||||
|
||||
// Idempotency: if the stale pristine subdir doesn't exist, nothing to do.
|
||||
if (!fs.existsSync(pristineGsdRoot)) return [];
|
||||
if (!fs.existsSync(pristineMsdRoot)) return [];
|
||||
|
||||
// Safety: reject symlinks in ANY ancestor component of the path we will walk
|
||||
// to prevent following a symlink out of configDir. Check both gsd-pristine/
|
||||
// and gsd-pristine/get-shit-done/ — either being a symlink could redirect // gsd-allow-legacy-name
|
||||
// to prevent following a symlink out of configDir. Check both msd-pristine/
|
||||
// and msd-pristine/get-shit-done/ — either being a symlink could redirect // msd-allow-legacy-name
|
||||
// the walk to an out-of-tree location.
|
||||
const pristineParent = path.join(ctx.configDir, 'gsd-pristine');
|
||||
const pristineParent = path.join(ctx.configDir, 'msd-pristine');
|
||||
try {
|
||||
if (fs.lstatSync(pristineParent).isSymbolicLink()) return [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
if (fs.lstatSync(pristineGsdRoot).isSymbolicLink()) return []; // gsd-allow-legacy-name
|
||||
if (fs.lstatSync(pristineMsdRoot).isSymbolicLink()) return []; // msd-allow-legacy-name
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
|
||||
const baseResolved = path.resolve(ctx.configDir);
|
||||
const relPaths: string[] = [];
|
||||
walkPristineFiles(ctx.configDir, path.posix.join('gsd-pristine', 'get-shit-done'), baseResolved, relPaths); // gsd-allow-legacy-name
|
||||
walkPristineFiles(ctx.configDir, path.posix.join('msd-pristine', 'get-shit-done'), baseResolved, relPaths); // msd-allow-legacy-name
|
||||
|
||||
const actions: MigrationAction[] = [];
|
||||
for (const relPath of relPaths) {
|
||||
@@ -121,19 +121,19 @@ const migration: InstallerMigration = {
|
||||
const resolved = path.resolve(ctx.configDir, relPath);
|
||||
if (resolved !== baseResolved && !resolved.startsWith(baseResolved + path.sep)) continue;
|
||||
|
||||
// These files are GSD-managed pristine snapshots — the installer writes
|
||||
// These files are MSD-managed pristine snapshots — the installer writes
|
||||
// them during install/upgrade; users never place personal files inside
|
||||
// gsd-pristine/. Pass classification: 'managed-pristine' explicitly so
|
||||
// msd-pristine/. Pass classification: 'managed-pristine' explicitly so
|
||||
// the framework does not downgrade remove-managed to preserve-user when
|
||||
// the manifest has no entry (these paths were never in the manifest since
|
||||
// they live under gsd-pristine/, not the tracked runtime dir).
|
||||
// they live under msd-pristine/, not the tracked runtime dir).
|
||||
actions.push({
|
||||
type: 'remove-managed',
|
||||
relPath,
|
||||
reason: REASON,
|
||||
ownershipEvidence:
|
||||
'GSD-written pristine snapshot under gsd-pristine/get-shit-done/; ' + // gsd-allow-legacy-name
|
||||
'installer is the sole author of gsd-pristine/ contents; no user content lives here',
|
||||
'MSD-written pristine snapshot under msd-pristine/get-shit-done/; ' + // msd-allow-legacy-name
|
||||
'installer is the sole author of msd-pristine/ contents; no user content lives here',
|
||||
classification: 'managed-pristine',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
* `commands/` before this fix.
|
||||
*
|
||||
* Consequence proven by probe (see tests/installer-migrations.test.cjs): a
|
||||
* pre-existing, unmanifested file at `commands/gsd-<name>.md` that predates
|
||||
* any GSD install is silently destroyed by ordinary OpenCode command
|
||||
* materialization (which unconditionally removes every `gsd-*.md` file under
|
||||
* pre-existing, unmanifested file at `commands/msd-<name>.md` that predates
|
||||
* any MSD install is silently destroyed by ordinary OpenCode command
|
||||
* materialization (which unconditionally removes every `msd-*.md` file under
|
||||
* its destination before writing the fresh set) with a clean exit code — no
|
||||
* report, no backup, no prompt. The identical scenario under the
|
||||
* already-covered legacy `command/` surface instead halts the install with a
|
||||
@@ -39,7 +39,7 @@
|
||||
* scoping below.
|
||||
*
|
||||
* Classification mirrors 000-first-time-baseline.cts exactly (record-baseline
|
||||
* for manifest-proven files, prompt-user for stale-GSD-looking unmanifested
|
||||
* for manifest-proven files, prompt-user for stale-MSD-looking unmanifested
|
||||
* files, baseline-preserve-user for everything else) — this migration only
|
||||
* widens the surface scanned, not the classification policy.
|
||||
*/
|
||||
@@ -115,8 +115,8 @@ function scanCommandsSurface(configDir: string): string[] {
|
||||
return [...relPaths];
|
||||
}
|
||||
|
||||
function isStaleGsdLookingPath(relPath: string): boolean {
|
||||
return /^gsd[-_]/.test(path.posix.basename(relPath));
|
||||
function isStaleMsdLookingPath(relPath: string): boolean {
|
||||
return /^msd[-_]/.test(path.posix.basename(relPath));
|
||||
}
|
||||
|
||||
function baselineActionRank(action: BaselineAction): number {
|
||||
@@ -153,15 +153,15 @@ const migration: InstallerMigration = {
|
||||
}
|
||||
|
||||
const currentHash = artifact.currentHash ?? null;
|
||||
if (isStaleGsdLookingPath(relPath)) {
|
||||
if (isStaleMsdLookingPath(relPath)) {
|
||||
actions.push({
|
||||
type: 'prompt-user',
|
||||
relPath,
|
||||
reason: 'GSD-looking file is not proven manifest-managed and needs explicit user choice',
|
||||
classification: 'stale-gsd-looking',
|
||||
reason: 'MSD-looking file is not proven manifest-managed and needs explicit user choice',
|
||||
classification: 'stale-msd-looking',
|
||||
originalHash: artifact.originalHash ?? null,
|
||||
currentHash,
|
||||
prompt: 'Choose whether to remove this stale-looking GSD artifact or keep it as user-owned.',
|
||||
prompt: 'Choose whether to remove this stale-looking MSD artifact or keep it as user-owned.',
|
||||
choices: ['keep', 'remove'],
|
||||
});
|
||||
continue;
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
/**
|
||||
* Installer migration: retire pi's stale `extensions/gsd.cjs` after #2470
|
||||
* renamed the installed native extension to `extensions/gsd.js`.
|
||||
* Installer migration: retire pi's stale `extensions/msd.cjs` after #2470
|
||||
* renamed the installed native extension to `extensions/msd.js`.
|
||||
*
|
||||
* What old artifact is being retired?
|
||||
* `extensions/gsd.cjs` — the pre-#2470 dest filename for pi's native
|
||||
* `extensions/msd.cjs` — the pre-#2470 dest filename for pi's native
|
||||
* extension. pi auto-discovers extensions by scanning `<agentDir>/extensions/`
|
||||
* and keeping only names accepted by its own predicate
|
||||
* (`isExtensionFile()` in @earendil-works/pi-coding-agent:
|
||||
* `name.endsWith(".ts") || name.endsWith(".js")`). A `.cjs` file is skipped
|
||||
* SILENTLY — no `/gsd` command, no error, no log line. The file is therefore
|
||||
* SILENTLY — no `/msd` command, no error, no log line. The file is therefore
|
||||
* permanently inert, not merely redundant.
|
||||
*
|
||||
* How do we prove it is GSD-owned?
|
||||
* How do we prove it is MSD-owned?
|
||||
* The installer records the native plugin in the install manifest as
|
||||
* `<nativePlugin.dir>/<nativePlugin.file>` (bin/install.js, the
|
||||
* `_hostBehaviors(runtime).nativePlugin` manifest block), so a pre-#2470 pi
|
||||
* install carries `extensions/gsd.cjs` as a manifest-managed entry. Only a
|
||||
* install carries `extensions/msd.cjs` as a manifest-managed entry. Only a
|
||||
* manifest-managed classification produces an action here; an unmanifested
|
||||
* `gsd.cjs` is treated as a user's own file and preserved.
|
||||
* `msd.cjs` is treated as a user's own file and preserved.
|
||||
*
|
||||
* What happens if the user modified it?
|
||||
* `backup-and-remove` instead of `remove-managed`, so a patched extension is
|
||||
@@ -30,13 +30,13 @@
|
||||
* What runtime and scope does it affect?
|
||||
* pi only, global and local. No other runtime ever installed this path:
|
||||
* OpenCode and Kilo — the only other runtimes declaring
|
||||
* `hostBehaviors.nativePlugin` — both ship `plugins/gsd-core.js`.
|
||||
* `hostBehaviors.nativePlugin` — both ship `plugins/msd-core.js`.
|
||||
*
|
||||
* Is the action safe in non-interactive install?
|
||||
* Yes. Both emitted action types are non-interactive and journaled; neither
|
||||
* requires a user choice, and unknown files never produce an action.
|
||||
*
|
||||
* Why not `move-managed`? The installer materializes the new `extensions/gsd.js`
|
||||
* Why not `move-managed`? The installer materializes the new `extensions/msd.js`
|
||||
* from the package payload in the same run, so moving the stale file onto that
|
||||
* path would just be overwritten. Retiring the old path is the accurate
|
||||
* description of the change.
|
||||
@@ -77,22 +77,22 @@ interface InstallerMigration {
|
||||
}
|
||||
|
||||
/** Pre-#2470 dest filename for pi's native extension. */
|
||||
const STALE_PI_EXTENSION = 'extensions/gsd.cjs';
|
||||
const STALE_PI_EXTENSION = 'extensions/msd.cjs';
|
||||
|
||||
const OWNERSHIP_EVIDENCE =
|
||||
'pre-#2470 pi installs record the native extension at extensions/gsd.cjs in ' +
|
||||
'gsd-file-manifest.json (installer nativePlugin manifest entry)';
|
||||
'pre-#2470 pi installs record the native extension at extensions/msd.cjs in ' +
|
||||
'msd-file-manifest.json (installer nativePlugin manifest entry)';
|
||||
|
||||
const REASON =
|
||||
'pi cannot auto-discover a .cjs extension (isExtensionFile accepts only .ts/.js), ' +
|
||||
'so this file is inert; superseded by extensions/gsd.js (#2470)';
|
||||
'so this file is inert; superseded by extensions/msd.js (#2470)';
|
||||
|
||||
const migration: InstallerMigration = {
|
||||
id: '2026-07-20-pi-extension-cjs-to-js',
|
||||
title: 'Retire pi\'s undiscoverable extensions/gsd.cjs',
|
||||
title: 'Retire pi\'s undiscoverable extensions/msd.cjs',
|
||||
description:
|
||||
'Remove the stale extensions/gsd.cjs left by pre-#2470 pi installs, superseded by ' +
|
||||
'extensions/gsd.js — the suffix pi\'s extension auto-discovery actually accepts.',
|
||||
'Remove the stale extensions/msd.cjs left by pre-#2470 pi installs, superseded by ' +
|
||||
'extensions/msd.js — the suffix pi\'s extension auto-discovery actually accepts.',
|
||||
introducedIn: '1.7.1',
|
||||
runtimes: ['pi'],
|
||||
scopes: ['global', 'local'],
|
||||
@@ -119,7 +119,7 @@ const migration: InstallerMigration = {
|
||||
},
|
||||
];
|
||||
}
|
||||
// 'unknown' (never GSD-managed), 'missing', and 'managed-missing' all plan
|
||||
// 'unknown' (never MSD-managed), 'missing', and 'managed-missing' all plan
|
||||
// nothing: unknown files are preserved by policy, and an absent file needs
|
||||
// no retirement.
|
||||
return [];
|
||||
|
||||
@@ -5,27 +5,27 @@
|
||||
* What old artifact is being retired?
|
||||
* `package.json` at the runtime config root. Before #2544,
|
||||
* `installSharedHooksBundle(destRootDir)` wrote `{"type":"commonjs"}` there
|
||||
* unconditionally on every install and every re-install, to pin GSD's staged
|
||||
* unconditionally on every install and every re-install, to pin MSD's staged
|
||||
* `.js` hook scripts to CommonJS via Node's ancestor walk. #2544 moved that
|
||||
* marker into the directories GSD actually fills (`hooks/`, and the
|
||||
* marker into the directories MSD actually fills (`hooks/`, and the
|
||||
* `nativePlugin.dir` for runtimes declaring one) and stopped writing the
|
||||
* config root at all. Without this migration an upgrader keeps BOTH markers:
|
||||
* the new one under `hooks/` and the stale one at the root, so the config
|
||||
* root stays pinned to CommonJS and the PR's own claim — that GSD no longer
|
||||
* root stays pinned to CommonJS and the PR's own claim — that MSD no longer
|
||||
* writes the shared config root — is false for every install made since the
|
||||
* marker was introduced, until the user uninstalls.
|
||||
*
|
||||
* How do we prove it is GSD-owned?
|
||||
* How do we prove it is MSD-owned?
|
||||
* By exact content match, NOT by the manifest. The config-root marker was
|
||||
* never recorded in `gsd-file-manifest.json` — `writeManifest()` records
|
||||
* never recorded in `msd-file-manifest.json` — `writeManifest()` records
|
||||
* `hooks/`, `agents/`, `commands/`, `scripts/`, and the native plugin, and
|
||||
* has never had a `manifest.files['package.json']` entry — so
|
||||
* `classifyArtifact('package.json')` answers `unknown` and the planner's
|
||||
* own guard would downgrade a `remove-managed` to `preserve-user`.
|
||||
* This migration therefore supplies the "purpose-built detector for an old
|
||||
* GSD-owned shape" that `docs/installer-migrations.md#remove-managed`
|
||||
* MSD-owned shape" that `docs/installer-migrations.md#remove-managed`
|
||||
* sanctions, and declares the resulting classification on the action: the
|
||||
* file is removed only when its bytes are exactly the marker GSD writes
|
||||
* file is removed only when its bytes are exactly the marker MSD writes
|
||||
* (`{"type":"commonjs"}`, trailing whitespace tolerated). That is the same
|
||||
* predicate `removeCommonJsMarker` has always used on the uninstall side, so
|
||||
* install, uninstall, and migration cannot drift apart.
|
||||
@@ -36,7 +36,7 @@
|
||||
* beyond the single `type` — i.e. every file the #2544 defect destroyed —
|
||||
* fails the exact-content test and is left exactly as found. There is
|
||||
* deliberately no `backup-and-remove` branch: a modified file here is not a
|
||||
* patched GSD artifact, it is somebody else's file.
|
||||
* patched MSD artifact, it is somebody else's file.
|
||||
*
|
||||
* What happens if it is missing?
|
||||
* No actions. Fresh post-#2544 installs never wrote it, already-migrated
|
||||
@@ -67,7 +67,7 @@
|
||||
* Is the action safe in non-interactive install?
|
||||
* Yes. `remove-managed` is non-interactive and journaled, the executor takes
|
||||
* a rollback snapshot before unlinking, and no branch of this migration can
|
||||
* emit `prompt-user`. A file that is not byte-identical to GSD's marker
|
||||
* emit `prompt-user`. A file that is not byte-identical to MSD's marker
|
||||
* produces no action at all.
|
||||
*
|
||||
* See docs/installer-migrations.md#shipped-migrations and #action-types.
|
||||
@@ -123,7 +123,7 @@ interface InstallerMigration {
|
||||
const STALE_ROOT_MARKER = 'package.json';
|
||||
|
||||
/**
|
||||
* The exact marker content GSD wrote. Duplicated as a literal rather than
|
||||
* The exact marker content MSD wrote. Duplicated as a literal rather than
|
||||
* imported from `src/commonjs-marker.cts` on purpose: a migration record is a
|
||||
* frozen historical statement about what a PAST version installed, and it must
|
||||
* keep matching those bytes even if the live module's constant is ever changed.
|
||||
@@ -139,7 +139,7 @@ const OWNERSHIP_EVIDENCE =
|
||||
|
||||
const REASON =
|
||||
'superseded by the hooks/ and plugin-dir markers (#2544); leaving it pins the shared '
|
||||
+ 'config root to CommonJS and keeps GSD occupying a file it no longer writes';
|
||||
+ 'config root to CommonJS and keeps MSD occupying a file it no longer writes';
|
||||
|
||||
const migration: InstallerMigration = {
|
||||
id: '2026-07-28-retire-config-root-commonjs-marker',
|
||||
@@ -147,7 +147,7 @@ const migration: InstallerMigration = {
|
||||
description:
|
||||
'Remove <configRoot>/package.json when it is exactly the {"type":"commonjs"} marker '
|
||||
+ 'pre-#2544 installs wrote there, now superseded by markers scoped to the directories '
|
||||
+ 'GSD owns. A package.json with any other content is left untouched.',
|
||||
+ 'MSD owns. A package.json with any other content is left untouched.',
|
||||
introducedIn: '1.8.0',
|
||||
scopes: ['global', 'local'],
|
||||
destructive: true,
|
||||
@@ -157,7 +157,7 @@ const migration: InstallerMigration = {
|
||||
let stat: import('node:fs').Stats;
|
||||
try {
|
||||
// lstat, not existsSync: existsSync follows symlinks and reports false for
|
||||
// a dangling one. A symlink here is not something GSD wrote, and removing
|
||||
// a dangling one. A symlink here is not something MSD wrote, and removing
|
||||
// it is never ours to do — mirrors classifyMarker's fail-closed posture.
|
||||
stat = fs.lstatSync(markerPath);
|
||||
} catch {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* Installer migration: retire Cursor's duplicate commands/ surface (#2644).
|
||||
*
|
||||
* Cursor discovers GSD skills as slash-menu entries while also keeping them
|
||||
* model-invocable. Older GSD releases installed the same workflows again as
|
||||
* commands/gsd-*.md, so every action appeared twice. The skills remain the
|
||||
* Cursor discovers MSD skills as slash-menu entries while also keeping them
|
||||
* model-invocable. Older MSD releases installed the same workflows again as
|
||||
* commands/msd-*.md, so every action appeared twice. The skills remain the
|
||||
* sole workflow surface; this migration removes only old command files proven
|
||||
* managed by gsd-file-manifest.json. Modified files are backed up first and
|
||||
* managed by msd-file-manifest.json. Modified files are backed up first and
|
||||
* unmanifested files are preserved.
|
||||
*/
|
||||
|
||||
@@ -30,15 +30,15 @@ interface MigrationPlanContext {
|
||||
|
||||
const COMMANDS_DIR = 'commands';
|
||||
const REASON =
|
||||
'Cursor exposes skills directly in the slash menu; the parallel command file duplicated the same GSD action (#2644)';
|
||||
'Cursor exposes skills directly in the slash menu; the parallel command file duplicated the same MSD action (#2644)';
|
||||
const OWNERSHIP_EVIDENCE =
|
||||
'pre-#2644 Cursor installs record commands/gsd-*.md in gsd-file-manifest.json';
|
||||
'pre-#2644 Cursor installs record commands/msd-*.md in msd-file-manifest.json';
|
||||
|
||||
const migration = {
|
||||
id: '2026-07-29-cursor-retire-commands-surface',
|
||||
title: 'Retire Cursor duplicate commands surface',
|
||||
description:
|
||||
'Remove manifest-managed Cursor commands/gsd-*.md files now that skills are the single slash-menu and model-invocation surface.',
|
||||
'Remove manifest-managed Cursor commands/msd-*.md files now that skills are the single slash-menu and model-invocation surface.',
|
||||
introducedIn: '1.8.1',
|
||||
runtimes: ['cursor'],
|
||||
scopes: ['global', 'local'],
|
||||
@@ -55,7 +55,7 @@ const migration = {
|
||||
|
||||
const actions: MigrationAction[] = [];
|
||||
for (const entry of entries) {
|
||||
if (!entry.isFile() || !entry.name.startsWith('gsd-') || !entry.name.endsWith('.md')) continue;
|
||||
if (!entry.isFile() || !entry.name.startsWith('msd-') || !entry.name.endsWith('.md')) continue;
|
||||
const relPath = path.posix.join(COMMANDS_DIR, entry.name);
|
||||
const artifact = ctx.classifyArtifact(relPath);
|
||||
if (artifact.classification === 'managed-pristine') {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Installer migration: retire pi's legacy `<piConfigDir>/hooks/` directory
|
||||
* after GSD's shared hook bundle moved to `<piConfigDir>/gsd-hooks/` (#3023).
|
||||
* after MSD's shared hook bundle moved to `<piConfigDir>/msd-hooks/` (#3023).
|
||||
*
|
||||
* What old artifact is being retired?
|
||||
* `hooks/` (and its `hooks/lib/` subdirectory) at the pi config root. pi
|
||||
@@ -8,19 +8,19 @@
|
||||
* warns on every startup whenever it exists — pi's
|
||||
* `checkDeprecatedExtensionDirs()` fires on mere PATH EXISTENCE, not on the
|
||||
* directory having contents (unlike the sibling `tools/` check, which does
|
||||
* `readdir` first). GSD used to install its shared hook bundle at exactly
|
||||
* `readdir` first). MSD used to install its shared hook bundle at exactly
|
||||
* that reserved path, so every pi install carried the warning permanently.
|
||||
* The fix moved the install target to `gsd-hooks/`
|
||||
* The fix moved the install target to `msd-hooks/`
|
||||
* (`hostBehaviors.sharedHooksDirName`), but an EXISTING install that
|
||||
* upgrades still has the old `hooks/` tree sitting on disk — nothing
|
||||
* removes it on its own, so the warning would persist forever without this
|
||||
* migration.
|
||||
*
|
||||
* How do we prove it is GSD-owned?
|
||||
* How do we prove it is MSD-owned?
|
||||
* Per file, by manifest membership — the same `classifyArtifact()` check
|
||||
* every other migration in this directory uses. Pre-#3023 pi installs
|
||||
* record the shared hook bundle under `hooks/…` keys in
|
||||
* `gsd-file-manifest.json`; the new install target writes `gsd-hooks/…`
|
||||
* `msd-file-manifest.json`; the new install target writes `msd-hooks/…`
|
||||
* keys instead, which this migration structurally never sees because it
|
||||
* only ever walks the `hooks/` subtree.
|
||||
*
|
||||
@@ -108,24 +108,24 @@ interface InstallerMigration {
|
||||
plan: (ctx: MigrationPlanContext) => MigrationAction[];
|
||||
}
|
||||
|
||||
/** pi's reserved (and, pre-#3023, GSD-populated) legacy hook directory name. */
|
||||
/** pi's reserved (and, pre-#3023, MSD-populated) legacy hook directory name. */
|
||||
const HOOKS_DIR = 'hooks';
|
||||
|
||||
const FILE_REASON =
|
||||
"pi's startup check warns whenever hooks/ exists (checkDeprecatedExtensionDirs), and GSD's shared " +
|
||||
'hook bundle now installs at gsd-hooks/ instead (#3023), so the legacy files are superseded';
|
||||
"pi's startup check warns whenever hooks/ exists (checkDeprecatedExtensionDirs), and MSD's shared " +
|
||||
'hook bundle now installs at msd-hooks/ instead (#3023), so the legacy files are superseded';
|
||||
|
||||
const FILE_OWNERSHIP_EVIDENCE =
|
||||
'pre-#3023 pi installs record the shared hook bundle under hooks/… keys in gsd-file-manifest.json; ' +
|
||||
'the new install target is gsd-hooks/…, which this migration never touches because it only walks the ' +
|
||||
'pre-#3023 pi installs record the shared hook bundle under hooks/… keys in msd-file-manifest.json; ' +
|
||||
'the new install target is msd-hooks/…, which this migration never touches because it only walks the ' +
|
||||
'hooks/ subtree';
|
||||
|
||||
const DIR_REASON =
|
||||
"pi's checkDeprecatedExtensionDirs() warns on hooks/'s mere existence, not its contents (#3023); the " +
|
||||
'reserved container is retired once every GSD-owned entry inside it is gone';
|
||||
'reserved container is retired once every MSD-owned entry inside it is gone';
|
||||
|
||||
const DIR_OWNERSHIP_EVIDENCE =
|
||||
'hooks/ and hooks/lib/ are GSD-installed container directories under the pi config root (the pre-#3023 ' +
|
||||
'hooks/ and hooks/lib/ are MSD-installed container directories under the pi config root (the pre-#3023 ' +
|
||||
'default of hostBehaviors.sharedHooksDirName); removal is gated on emptiness by the shared ' +
|
||||
'remove-empty-dir action, so a directory that still holds an unmanifested user file — or any file-level ' +
|
||||
'action that failed to apply — is left in place rather than assumed empty';
|
||||
@@ -160,7 +160,7 @@ const migration: InstallerMigration = {
|
||||
title: "Retire pi's reserved hooks/ directory",
|
||||
description:
|
||||
'Remove manifest-managed files under <piConfigDir>/hooks/ and, once empty, the directory itself ' +
|
||||
'(and its hooks/lib/ subdirectory), now that the shared hook bundle installs at gsd-hooks/ instead. pi ' +
|
||||
'(and its hooks/lib/ subdirectory), now that the shared hook bundle installs at msd-hooks/ instead. pi ' +
|
||||
'reserves hooks/ as its own deprecated extension directory and warns on every startup while it exists (#3023).',
|
||||
introducedIn: '1.9.2',
|
||||
runtimes: ['pi'],
|
||||
|
||||
@@ -64,8 +64,8 @@ interface InstallerMigration {
|
||||
/** The two retired configHome-relative artifact subpaths. */
|
||||
const RETIRED_SUBPATHS = ['skills', 'agents'] as const;
|
||||
|
||||
/** Only GSD-owned top-level entries are retirement candidates. */
|
||||
const GSD_PREFIX = 'gsd-';
|
||||
/** Only MSD-owned top-level entries are retirement candidates. */
|
||||
const MSD_PREFIX = 'msd-';
|
||||
|
||||
const FILE_REASON =
|
||||
'Antigravity scans ~/.gemini/config/{skills,agents} for global discovery and does not scan the ' +
|
||||
@@ -73,17 +73,17 @@ const FILE_REASON =
|
||||
"under the global layout's .gemini/config home override";
|
||||
|
||||
const FILE_OWNERSHIP_EVIDENCE =
|
||||
'pre-#3738 antigravity installs record skills/gsd-*/** and agents/gsd-*.md keys in ' +
|
||||
'gsd-file-manifest.json at the configHome root; the migration only walks gsd--prefixed entries ' +
|
||||
'pre-#3738 antigravity installs record skills/msd-*/** and agents/msd-*.md keys in ' +
|
||||
'msd-file-manifest.json at the configHome root; the migration only walks msd--prefixed entries ' +
|
||||
'under the two retired subpaths';
|
||||
|
||||
const DIR_REASON =
|
||||
'the retired container directory is removed only once every GSD-owned entry inside it is gone; a ' +
|
||||
'the retired container directory is removed only once every MSD-owned entry inside it is gone; a ' +
|
||||
'directory that still holds an unmanifested user file — or any file-level action that failed to ' +
|
||||
'apply — is left in place by the emptiness re-check';
|
||||
|
||||
const DIR_OWNERSHIP_EVIDENCE =
|
||||
'skills/ and agents/ at the antigravity configHome root are GSD-installed container directories ' +
|
||||
'skills/ and agents/ at the antigravity configHome root are MSD-installed container directories ' +
|
||||
'from the pre-#3738 layout; removal is gated on emptiness by the shared remove-empty-dir action';
|
||||
|
||||
/**
|
||||
@@ -115,7 +115,7 @@ const migration: InstallerMigration = {
|
||||
id: '2026-08-26-antigravity-retire-confighome-artifacts',
|
||||
title: "Retire Antigravity's configHome skills/agents surfaces",
|
||||
description:
|
||||
'Remove manifest-managed skills/gsd-*/ and agents/gsd-*.md under the Antigravity configHome ' +
|
||||
'Remove manifest-managed skills/msd-*/ and agents/msd-*.md under the Antigravity configHome ' +
|
||||
'(~/.gemini/antigravity{,-ide,-cli}) — a location Antigravity does not scan for global discovery — ' +
|
||||
'and retire the now-empty container directories, now that the global layout installs both kinds ' +
|
||||
'under the ~/.gemini/config home override (#3738). Global scope only; the local .agents workspace ' +
|
||||
@@ -152,7 +152,7 @@ const migration: InstallerMigration = {
|
||||
try {
|
||||
const entries = fs.readdirSync(surfaceRoot, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (entry.isSymbolicLink() || !entry.name.startsWith(GSD_PREFIX)) continue;
|
||||
if (entry.isSymbolicLink() || !entry.name.startsWith(MSD_PREFIX)) continue;
|
||||
const relPath = path.posix.join(subpath, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
dirs.push(relPath);
|
||||
|
||||
Reference in New Issue
Block a user