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:
@@ -331,7 +331,7 @@ function shouldResyncStateProgress(fields: Iterable<string>): boolean {
|
||||
|
||||
// Cache disk scan results from buildStateFrontmatter per cwd per process (#1967).
|
||||
// Avoids re-reading N+1 directories on every state write when the phase structure
|
||||
// hasn't changed within the same gsd-tools invocation.
|
||||
// hasn't changed within the same msd-tools invocation.
|
||||
const _diskScanCache = new Map<string, {
|
||||
// #3354: null is the milestoned-but-unbounded WITHHOLD sentinel — the scan
|
||||
// refused to substitute the on-disk dir count for a rejected whole-document
|
||||
@@ -921,7 +921,7 @@ function stateReplaceFieldWithFallback(content: string, primary: string, fallbac
|
||||
// Neither pattern matched — field may have been reformatted or removed.
|
||||
// Log diagnostic so template drift is detected early rather than silently swallowed.
|
||||
process.stderr.write(
|
||||
`[gsd-tools] WARNING: STATE.md field "${primary}"${fallback ? ` (fallback: "${fallback}")` : ''} not found — update skipped. ` +
|
||||
`[msd-tools] WARNING: STATE.md field "${primary}"${fallback ? ` (fallback: "${fallback}")` : ''} not found — update skipped. ` +
|
||||
`This may indicate STATE.md was externally modified or uses an unexpected format.\n`
|
||||
);
|
||||
return content;
|
||||
@@ -1260,7 +1260,7 @@ function cmdStateRecordMetric(cwd: string, options: StateRecordMetricOptions, ra
|
||||
// Locate THIS command's OWN metrics table by its HEADER shape, using the
|
||||
// exact same splitTableRow/isDelimiterRow header/delimiter-shape checks
|
||||
// `parseMarkdownTable` uses. A live "## Performance Metrics" section
|
||||
// (gsd-core/templates/state.md:39-56) also carries the "By Phase"
|
||||
// (msd-core/templates/state.md:39-56) also carries the "By Phase"
|
||||
// velocity table (`| Phase | Plans | Total | Avg/Plan |`) — the prior
|
||||
// "first table in the section" targeting spliced every per-plan row into
|
||||
// THAT table instead, polluting it on EVERY plan completion
|
||||
@@ -1342,7 +1342,7 @@ function cmdStateRecordMetric(cwd: string, options: StateRecordMetricOptions, ra
|
||||
if (metricsSection) {
|
||||
// Section EXISTS but carries no metrics table of its own — e.g. a live
|
||||
// STATE.md whose "## Performance Metrics" section holds only the
|
||||
// By-Phase velocity table (gsd-core/templates/state.md:48). Self-heal
|
||||
// By-Phase velocity table (msd-core/templates/state.md:48). Self-heal
|
||||
// by appending a fresh Per-Plan Metrics table to the END of the
|
||||
// section body — every existing byte (By-Phase table, Recent Trend,
|
||||
// footer) is preserved verbatim, and no second "## Performance
|
||||
@@ -1506,7 +1506,7 @@ function cmdStateUpdateProgress(cwd: string, raw: boolean): void {
|
||||
// disclosure): the JSON `reason` field alone is easy for a caller to
|
||||
// never read, and STATE.md's Progress field goes stale with no
|
||||
// user-visible signal beyond it. Mirrors the established
|
||||
// `[gsd-tools] WARNING:` stderr convention this file already uses
|
||||
// `[msd-tools] WARNING:` stderr convention this file already uses
|
||||
// (stateReplaceFieldWithFallback above) for a comparable silent no-op —
|
||||
// now routed through the shared `declineNoOp` helper (#3957) so the
|
||||
// pairing is structural rather than hand-written per arm.
|
||||
@@ -2277,12 +2277,12 @@ function matchSessionSection(body: string): string | null {
|
||||
/**
|
||||
* Match the "Current Position" section body from a STATE.md body. #2956: this
|
||||
* is the Phase analogue of matchSessionSection. `Phase` canonically lives under
|
||||
* `## Current Position` (gsd-core/templates/state.md), so — like Stopped At /
|
||||
* `## Current Position` (msd-core/templates/state.md), so — like Stopped At /
|
||||
* Paused At under `## Session` — it must be extracted from THAT section, not
|
||||
* from the first `Phase:` / `**Phase:**` line anywhere in the body. Without the
|
||||
* scope, a historical `Phase:` line in an archive section silently overwrites
|
||||
* `current_phase` on every write, and because `current_phase` is routing input
|
||||
* for gsd-progress / --next the rewind routes work to the wrong phase.
|
||||
* for msd-progress / --next the rewind routes work to the wrong phase.
|
||||
*
|
||||
* Level-flexible: the canonical template uses an h2 `## Current Position`, the
|
||||
* bootstrap template an h3 `### Current Position` (templates/state.md). Both
|
||||
@@ -2585,7 +2585,7 @@ function cmdStateSnapshot(cwd: string, raw: boolean): void {
|
||||
* #612: is the asserted milestone bounded to a heading in this ROADMAP?
|
||||
*
|
||||
* The legacy rule matches STATE's milestone STRING (`v2.0`) inside a heading.
|
||||
* The ADR-canonical bracket milestone heading is `## [GSD.02] Foundation` — a
|
||||
* The ADR-canonical bracket milestone heading is `## [MSD.02] Foundation` — a
|
||||
* name, no version — so that rule finds nothing, the milestone reads as
|
||||
* unbounded, and total_phases falls back to the on-disk directory count. Under
|
||||
* the bracket convention the milestone integer in the bracket is matched against
|
||||
@@ -2611,7 +2611,7 @@ function isMilestoneBounded(roadmapRaw: string, milestone: string, convention?:
|
||||
// was a convention two files had to keep agreeing on by hand — and the drift
|
||||
// guard could not see either copy.
|
||||
// #612 round-4 (Major 1, F12): fence-aware via tokenizeHeadings, not a raw
|
||||
// `.test(roadmapRaw)` — a FENCED `[GSD.02]` example heading (the ONLY one
|
||||
// `.test(roadmapRaw)` — a FENCED `[MSD.02]` example heading (the ONLY one
|
||||
// in the document, with no real section for the asserted milestone at
|
||||
// all) previously bounded a milestone that isn't actually in the roadmap,
|
||||
// un-suppressing a percent computed off the wrong (prior-milestone-plus-
|
||||
@@ -2698,7 +2698,7 @@ function extractRetiredPhaseNumbers(scope: string, convention?: string | null):
|
||||
* text against the phase-heading-intro grammar directly. Fence-aware by
|
||||
* construction — `tokenizeHeadings` never produces a token for a fenced
|
||||
* line — closing round-4's Major 1: a fenced EXAMPLE phase heading in the
|
||||
* preamble (`` ### [GSD.02] 05: Example phase `` inside a
|
||||
* preamble (`` ### [MSD.02] 05: Example phase `` inside a
|
||||
* ` ```markdown ` block) previously inflated this count via the raw regex
|
||||
* below, which ran over the whole scope STRING with no fence awareness at
|
||||
* all (F9, F10 — `total_phases` read 3 where the milestone has 2 real
|
||||
@@ -2740,7 +2740,7 @@ function countRoadmapPhaseHeadings(
|
||||
// numeric phases (01, 05.1) and project-code IDs (PROJ-42).
|
||||
if (!/\d/.test(token)) continue;
|
||||
// #612 READING-B: a bracket heading carries its sentinel in the
|
||||
// bracket, so `### [GSD.999] 01:` is an icebox item even though its
|
||||
// bracket, so `### [MSD.999] 01:` is an icebox item even though its
|
||||
// token is `01`.
|
||||
if (bracketId && isSentinelPhaseId(`${bracketId}-${token}`, 'bracket')) continue;
|
||||
// #612: under bracket the token rule composes with the bracket-id
|
||||
@@ -2961,7 +2961,7 @@ function buildStateFrontmatter(
|
||||
const survivor = dir < incumbent ? dir : incumbent;
|
||||
seenPhaseNums.set(key, survivor);
|
||||
process.stderr.write(
|
||||
`gsd: warning — phase directories '${incumbent}' and '${dir}' both normalize to phase key '${key}' (duplicate phase number in .planning/phases/); keeping '${survivor}' by deterministic lexicographic order. (#3355)\n`
|
||||
`msd: warning — phase directories '${incumbent}' and '${dir}' both normalize to phase key '${key}' (duplicate phase number in .planning/phases/); keeping '${survivor}' by deterministic lexicographic order. (#3355)\n`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3066,7 +3066,7 @@ function buildStateFrontmatter(
|
||||
const milestonedButUnbounded = !milestoneBounded && roadmapHasAnyMilestoneSection;
|
||||
if (milestonedButUnbounded) {
|
||||
process.stderr.write(
|
||||
`gsd: warning — milestone '${String(assertedMilestoneVersion ?? '').trim()}' is asserted in STATE.md but matches no ROADMAP heading, and the ROADMAP carries milestone section(s) — one (#3642) or several (#3354) — none matching it; the whole-document count would attribute a foreign section's phases to this milestone and the on-disk phase-directory count would understate the declared total, so the progress counters (total_phases, completed_phases, total_plans, completed_plans) are left at their stored values. (#3354/#3642/#4094)\n`
|
||||
`msd: warning — milestone '${String(assertedMilestoneVersion ?? '').trim()}' is asserted in STATE.md but matches no ROADMAP heading, and the ROADMAP carries milestone section(s) — one (#3642) or several (#3354) — none matching it; the whole-document count would attribute a foreign section's phases to this milestone and the on-disk phase-directory count would understate the declared total, so the progress counters (total_phases, completed_phases, total_plans, completed_plans) are left at their stored values. (#3354/#3642/#4094)\n`
|
||||
);
|
||||
}
|
||||
// #3573: the roadmap-absent sibling of the #3354 shape. With ROADMAP.md
|
||||
@@ -3086,7 +3086,7 @@ function buildStateFrontmatter(
|
||||
storedMilestone.trim() !== '';
|
||||
if (roadmapAbsentWithAssertedMilestone) {
|
||||
process.stderr.write(
|
||||
`gsd: warning — milestone '${storedMilestone.trim()}' is asserted in STATE.md but ROADMAP.md is absent or unreadable, so the phase-heading total cannot be derived; the on-disk phase-directory count would understate the declared total, so the progress counters (total_phases, completed_phases, total_plans, completed_plans) are left at their stored values. (#3573) (#4094)\n`
|
||||
`msd: warning — milestone '${storedMilestone.trim()}' is asserted in STATE.md but ROADMAP.md is absent or unreadable, so the phase-heading total cannot be derived; the on-disk phase-directory count would understate the declared total, so the progress counters (total_phases, completed_phases, total_plans, completed_plans) are left at their stored values. (#3573) (#4094)\n`
|
||||
);
|
||||
}
|
||||
// #4094: the withhold condition covers ALL FOUR progress counters,
|
||||
@@ -3258,7 +3258,7 @@ function buildStateFrontmatter(
|
||||
normalizedStatus = 'executing';
|
||||
}
|
||||
|
||||
const fm: Record<string, unknown> = { gsd_state_version: '1.0' };
|
||||
const fm: Record<string, unknown> = { msd_state_version: '1.0' };
|
||||
|
||||
if (milestone) fm['milestone'] = milestone;
|
||||
if (milestoneName) fm['milestone_name'] = milestoneName;
|
||||
@@ -3342,7 +3342,7 @@ function projectOwnsItsRepo(projectRoot: string): boolean {
|
||||
function readGitHeadSha(cwd: string | undefined): string | null {
|
||||
if (!cwd) return null;
|
||||
// #2573 degrade path D5. `git rev-parse HEAD` walks UP from cwd to the nearest
|
||||
// enclosing `.git`, and nothing pins that repo to the project. A GSD project
|
||||
// enclosing `.git`, and nothing pins that repo to the project. A MSD project
|
||||
// living inside an unrelated checkout — a dotfiles/notes repo, or the outer
|
||||
// workspace of a `planning.sub_repos` layout where all code commits land in
|
||||
// the sub-repos — would otherwise measure freshness against a repo it has no
|
||||
@@ -3606,7 +3606,7 @@ function syncStateFrontmatter(
|
||||
// place (re-derivation, not deletion — the document never lost its frontmatter FENCE).
|
||||
//
|
||||
// `sanctionedPermanentEmptyFallback` is threaded ONLY from `writeStateMd`, itself consumed
|
||||
// ONLY by `cmdStateSync` (#905) and `/gsd-health --repair`'s `REGENERATE_STATE` — ADR-3408
|
||||
// ONLY by `cmdStateSync` (#905) and `/msd-health --repair`'s `REGENERATE_STATE` — ADR-3408
|
||||
// §8.3's CLOSED list of commands whose documented contract is "body wins, re-derive
|
||||
// unconditionally" (a factory reset / explicit resync). Those two are untouched here: this
|
||||
// guard fires only on the OTHER call path (`syncAndPreserveStateMd`, i.e. every
|
||||
@@ -3680,7 +3680,7 @@ function syncStateFrontmatter(
|
||||
// `divergedFields` stayed empty even though a curated value had just won
|
||||
// over a genuine derived-empty.
|
||||
//
|
||||
// `writeStateMd`'s two callers — `cmdStateSync` and `/gsd-health --repair`'s
|
||||
// `writeStateMd`'s two callers — `cmdStateSync` and `/msd-health --repair`'s
|
||||
// `REGENERATE_STATE` — are §8.3's closed, sanctioned-permanent exception
|
||||
// list: NEITHER ever runs `applyStatePreservation` afterward, because their
|
||||
// whole contract is "re-derive frontmatter FROM the body, body wins" (the
|
||||
@@ -3749,7 +3749,7 @@ function syncStateFrontmatter(
|
||||
// `derive`, but they are body/disk-sourced and MUST still carry forward when
|
||||
// the writer omits them this pass — dropping `last_activity` here is silent
|
||||
// frontmatter data loss and would defeat #2570's staleness fix downstream.
|
||||
// `last_updated` and `gsd_state_version` are the only other `free` rows and are
|
||||
// `last_updated` and `msd_state_version` are the only other `free` rows and are
|
||||
// both produced unconditionally by buildStateFrontmatter, so this loop never
|
||||
// reaches them; `state_head` is the sole field the skip governs. Consult the
|
||||
// table rather than naming fields, so the policy stays single-sourced.
|
||||
@@ -4189,7 +4189,7 @@ function applyPostSyncPreservation(
|
||||
// FRESH frontmatter block from the result, destroying the raw block a second time even
|
||||
// though `syncStateFrontmatter` just finished protecting it. `applyPostSyncPreservation` is
|
||||
// reached ONLY via the non-sanctioned path (`syncAndPreserveStateMd`; `writeStateMd`'s two
|
||||
// ADR-3408 §8.3 closed-list callers — `cmdStateSync` #905 and `/gsd-health --repair`'s
|
||||
// ADR-3408 §8.3 closed-list callers — `cmdStateSync` #905 and `/msd-health --repair`'s
|
||||
// `REGENERATE_STATE` — never call it at all), so this guard needs no extra parameter to stay
|
||||
// scoped off that list. Confirmed by execution: `state begin-phase` on a conflict-marked
|
||||
// STATE.md reached exactly this second clobber even after the `syncStateFrontmatter` fix.
|
||||
@@ -5231,14 +5231,14 @@ function cmdStateBeginPhase(cwd: string, phaseNumber: string | number | null | u
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a WAITING.json signal file when GSD hits a decision point.
|
||||
* Write a WAITING.json signal file when MSD hits a decision point.
|
||||
* External watchers (fswatch, polling, orchestrators) can detect this.
|
||||
* File is written to .planning/WAITING.json (or .gsd/WAITING.json if .gsd exists).
|
||||
* File is written to .planning/WAITING.json (or .msd/WAITING.json if .msd exists).
|
||||
* Fixes #1034.
|
||||
*/
|
||||
function cmdSignalWaiting(cwd: string, type: string | undefined, question: string | undefined, options: string | undefined, phase: string | undefined, raw: boolean): void {
|
||||
const gsdDir = fs.existsSync(path.join(cwd, '.gsd')) ? path.join(cwd, '.gsd') : planningDir(cwd);
|
||||
const waitingPath = path.join(gsdDir, 'WAITING.json');
|
||||
const msdDir = fs.existsSync(path.join(cwd, '.msd')) ? path.join(cwd, '.msd') : planningDir(cwd);
|
||||
const waitingPath = path.join(msdDir, 'WAITING.json');
|
||||
|
||||
const signal = {
|
||||
status: 'waiting',
|
||||
@@ -5250,7 +5250,7 @@ function cmdSignalWaiting(cwd: string, type: string | undefined, question: strin
|
||||
};
|
||||
|
||||
try {
|
||||
platformEnsureDir(gsdDir);
|
||||
platformEnsureDir(msdDir);
|
||||
platformWriteSync(waitingPath, JSON.stringify(signal, null, 2));
|
||||
output({ signaled: true, path: waitingPath }, raw, 'true');
|
||||
} catch (e) {
|
||||
@@ -5263,7 +5263,7 @@ function cmdSignalWaiting(cwd: string, type: string | undefined, question: strin
|
||||
*/
|
||||
function cmdSignalResume(cwd: string, raw: boolean): void {
|
||||
const paths = [
|
||||
path.join(cwd, '.gsd', 'WAITING.json'),
|
||||
path.join(cwd, '.msd', 'WAITING.json'),
|
||||
path.join(planningDir(cwd), 'WAITING.json'),
|
||||
];
|
||||
|
||||
@@ -5551,7 +5551,7 @@ function cmdStatePlannedPhase(cwd: string, phaseNumber: string | number | null |
|
||||
// over `existingFm`), so an unrecognized-format STATE.md — zero fields the
|
||||
// transition could actually apply, `updated: []`, the "transition was a
|
||||
// no-op" warning above — can still make the raw returned string differ
|
||||
// from the input (frontmatter gets synthesized: `gsd_state_version`,
|
||||
// from the input (frontmatter gets synthesized: `msd_state_version`,
|
||||
// `last_updated`, a zeroed `progress` block, `current_phase_name`), so the
|
||||
// RMW guard does NOT fire and a real write happens. That write is not a
|
||||
// meaningful state transition by this command's OWN reporting contract
|
||||
@@ -5607,7 +5607,7 @@ function cmdStateMilestoneSwitch(cwd: string, version: string | undefined, name:
|
||||
// #3227: publish AFTER releaseStateLock — publishStateContract derives `next`
|
||||
// from classifyProject, which shells out to git (bounded, but up to 3 x 10s).
|
||||
// Holding the STATE.md lock across that would turn a millisecond hold into a
|
||||
// git-bound one for every concurrent GSD process.
|
||||
// git-bound one for every concurrent MSD process.
|
||||
if (switched) publishStateContract(cwd);
|
||||
}
|
||||
|
||||
@@ -5802,7 +5802,7 @@ function cmdStateValidate(cwd: string, raw: boolean, opts: { strict?: boolean }
|
||||
// directory without an explicit signal (a bracket dir is string-
|
||||
// indistinguishable from the legacy letter-prefixed-decimal family, ADR-2121),
|
||||
// so un-threaded it returns the WHOLE dir name as the key —
|
||||
// `GSD.02-05-delta` -> `GSD.02-5-DELTA` — while `selectedPhaseKey` is the bare
|
||||
// `MSD.02-05-delta` -> `MSD.02-5-DELTA` — while `selectedPhaseKey` is the bare
|
||||
// `05` that `parsePhaseFromProse` yields. The two sides of one comparison were
|
||||
// derived under different conventions, which is #2562's defect class and the
|
||||
// thing this file's other three `phaseKeyFromDir` call sites already thread
|
||||
@@ -6226,7 +6226,7 @@ function cmdStateSync(cwd: string, options: StateSyncOptions | undefined, raw: b
|
||||
const syncWillWrite = changes.length > 0 || modified !== content;
|
||||
if (syncWillWrite && syncFrontmatterWasUnparseable) {
|
||||
const unparseableWarning =
|
||||
`gsd: warning — STATE.md's existing frontmatter could not be parsed (malformed YAML, or ` +
|
||||
`msd: warning — STATE.md's existing frontmatter could not be parsed (malformed YAML, or ` +
|
||||
`unresolved content such as git merge-conflict markers) and was regenerated from the body; ` +
|
||||
`any content in the old frontmatter block — including merge-conflict markers — has been ` +
|
||||
`replaced. (#3881)`;
|
||||
@@ -6353,7 +6353,7 @@ function cmdStatePrune(cwd: string, options: StatePruneOptions, raw: boolean): v
|
||||
/**
|
||||
* Rebuild STATE.md body structure from canonical sources (ADR-1817).
|
||||
*
|
||||
* Implements the `gsd state rebuild` subcommand (issue #1817 Phase 2, #1826).
|
||||
* Implements the `msd state rebuild` subcommand (issue #1817 Phase 2, #1826).
|
||||
* Wires the pure `rebuildCore` transition (Phase 1, #1827) to the CLI:
|
||||
* - Locks via `readModifyWriteStateMd` (real path) or reads-only (dry-run).
|
||||
* - Wires `phaseInventoryProvider` to a real `.planning/phases/` disk scan.
|
||||
@@ -6518,7 +6518,7 @@ function cmdStateRebuild(cwd: string, options: StateRebuildOptions, raw: boolean
|
||||
* Mark the current phase as COMPLETE in STATE.md.
|
||||
* Updates Status, Last Activity, and the Current Position section to reflect
|
||||
* that the phase execution is finished and the project is ready for the next phase.
|
||||
* Implements the `gsd state complete-phase` subcommand (issue #2735).
|
||||
* Implements the `msd state complete-phase` subcommand (issue #2735).
|
||||
*/
|
||||
function resolvePhaseIdForCompletePhase(fm: Record<string, unknown>, body: string, overridePhase: string | undefined): string | null {
|
||||
// #3187: route through the single #1760 fallback-chain owner (fm scalar
|
||||
|
||||
Reference in New Issue
Block a user