@opengsd/gsd-core 1.19.0 → 1.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-code-fixer.compact.md +5 -5
- package/agents/gsd-code-fixer.md +9 -4
- package/agents/gsd-code-reviewer.compact.md +49 -8
- package/agents/gsd-code-reviewer.md +53 -14
- package/agents/gsd-executor.md +8 -4
- package/bin/install.js +36 -40
- package/commands/gsd/new-milestone.md +2 -2
- package/commands/gsd/new-project.md +2 -2
- package/commands/gsd/update.md +5 -2
- package/gsd-core/bin/gsd-tools.cjs +177 -93
- package/gsd-core/bin/lib/capability-lifecycle.cjs +1 -12
- package/gsd-core/bin/lib/capability-registry.cjs +284 -93
- package/gsd-core/bin/lib/capability-validator.cjs +15 -0
- package/gsd-core/bin/lib/commands.cjs +46 -17
- package/gsd-core/bin/lib/config-loader.cjs +3 -3
- package/gsd-core/bin/lib/core-utils.cjs +11 -0
- package/gsd-core/bin/lib/frontmatter.cjs +21 -3
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +2 -2
- package/gsd-core/bin/lib/gate-context-drift.cjs +1 -1
- package/gsd-core/bin/lib/gate-phase-context.cjs +7 -8
- package/gsd-core/bin/lib/gate-schema-drift.cjs +1 -1
- package/gsd-core/bin/lib/git-info-exclude.cjs +1 -6
- package/gsd-core/bin/lib/gsd-tool-dir.cjs +134 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +13 -9
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +9 -7
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +3 -3
- package/gsd-core/bin/lib/init.cjs +181 -68
- package/gsd-core/bin/lib/install-engine.cjs +9 -9
- package/gsd-core/bin/lib/install-manifest-record.cjs +86 -0
- package/gsd-core/bin/lib/install-profiles.cjs +4 -2
- package/gsd-core/bin/lib/io.cjs +6 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +34 -1
- package/gsd-core/bin/lib/markdown-table.cjs +23 -0
- package/gsd-core/bin/lib/mcp-server.cjs +8 -5
- package/gsd-core/bin/lib/milestone.cjs +18 -50
- package/gsd-core/bin/lib/phase-entry-grammar.cjs +119 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +2 -0
- package/gsd-core/bin/lib/phase-id.cjs +627 -36
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -74
- package/gsd-core/bin/lib/phase-locator.cjs +328 -19
- package/gsd-core/bin/lib/phase.cjs +3039 -666
- package/gsd-core/bin/lib/planning-document.cjs +26 -5
- package/gsd-core/bin/lib/planning-inspect.cjs +27 -35
- package/gsd-core/bin/lib/planning-snapshot.cjs +12 -7
- package/gsd-core/bin/lib/planning-workspace.cjs +3 -3
- package/gsd-core/bin/lib/read-only-git-env.cjs +23 -2
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +2 -2
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -0
- package/gsd-core/bin/lib/review-lane-invocation.cjs +125 -18
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +11 -9
- package/gsd-core/bin/lib/roadmap-parser.cjs +759 -144
- package/gsd-core/bin/lib/roadmap-progress.cjs +136 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +8 -5
- package/gsd-core/bin/lib/roadmap.cjs +358 -106
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -130
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +6 -0
- package/gsd-core/bin/lib/shell-command-projection.cjs +36 -9
- package/gsd-core/bin/lib/smart-entry.cjs +22 -11
- package/gsd-core/bin/lib/state-contract.cjs +11 -7
- package/gsd-core/bin/lib/state-document.cjs +332 -23
- package/gsd-core/bin/lib/state-transition.cjs +51 -15
- package/gsd-core/bin/lib/state.cjs +499 -180
- package/gsd-core/bin/lib/template.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +3 -2
- package/gsd-core/bin/lib/vendor/re2js.cjs +863 -577
- package/gsd-core/bin/lib/vendor/re2js.d.cts +284 -219
- package/gsd-core/bin/lib/verify.cjs +2 -2
- package/gsd-core/bin/lib/workstream-inventory.cjs +27 -21
- package/gsd-core/bin/lib/worktree-base-ref.cjs +32 -2
- package/gsd-core/bin/verify-reapply-patches.cjs +411 -10
- package/gsd-core/references/cicd-review-patterns.md +45 -0
- package/gsd-core/references/necessity-review.md +48 -0
- package/gsd-core/workflows/code-review-fix.md +46 -5
- package/gsd-core/workflows/code-review.md +3 -0
- package/gsd-core/workflows/execute-phase.md +1 -1
- package/gsd-core/workflows/execute-plan.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +13 -9
- package/gsd-core/workflows/plan-phase.md +1 -1
- package/gsd-core/workflows/pr-branch.md +2 -0
- package/gsd-core/workflows/reapply-patches.md +104 -0
- package/gsd-core/workflows/review.md +54 -141
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/settings-advanced.md +57 -9
- package/gsd-core/workflows/ship.md +12 -0
- package/hooks/dist/gsd-agent-isolation-guard.js +1 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +1 -1
- package/hooks/dist/gsd-graphify-update.sh +6 -0
- package/hooks/dist/gsd-statusline.js +3 -2
- package/hooks/dist/gsd-windsurf-pre-write.js +4 -4
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- package/hooks/dist/gsd-worktree-path-guard.js +4 -4
- package/hooks/dist/lib/git-probe.js +16 -0
- package/hooks/dist/lib/isolation-sentinel.js +77 -2
- package/hooks/gsd-agent-isolation-guard.js +1 -1
- package/hooks/gsd-cursor-subagent-start.js +1 -1
- package/hooks/gsd-graphify-update.sh +6 -0
- package/hooks/gsd-statusline.js +3 -2
- package/hooks/gsd-windsurf-pre-write.js +4 -4
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/gsd-worktree-path-guard.js +4 -4
- package/hooks/lib/git-probe.js +16 -0
- package/hooks/lib/isolation-sentinel.js +77 -2
- package/package.json +3 -3
- package/pi/package-agents/gsd-code-fixer.md +9 -4
- package/pi/package-agents/gsd-code-reviewer.md +53 -14
- package/pi/package-agents/gsd-executor.md +8 -4
- package/pi/package-agents/manifest.json +3 -3
- package/pi/package-skills/gsd-new-milestone/SKILL.md +1 -1
- package/pi/package-skills/gsd-new-project/SKILL.md +1 -1
- package/pi/package-skills/gsd-update/SKILL.md +4 -1
- package/scripts/changeset/lint.cjs +28 -3
- package/scripts/ci-next-health.cjs +246 -23
- package/scripts/docs-guard-registry.cjs +2 -0
- package/scripts/gen-features.cjs +14 -2
- package/scripts/lib/drift-scan.cjs +27 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +10 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +15 -0
- package/scripts/lint-phase-enumeration-drift.cjs +8 -4
- package/scripts/lint-roadmap-progress-drift.cjs +421 -0
- package/scripts/merge-commit-pr.cjs +186 -0
- package/scripts/mutation-matrix.cjs +23 -1
- package/scripts/release-ancestry.cjs +86 -0
- package/scripts/release-pipeline-pr.cjs +92 -0
- package/scripts/require-issue-link-policy.cjs +18 -9
- package/scripts/sync-next-version.cjs +48 -7
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-new-project/SKILL.md +1 -1
- package/skills/gsd-update/SKILL.md +5 -2
- package/vscode/package.json +1 -1
|
@@ -25,12 +25,12 @@ const { readSubdirectories } = coreUtilsMod;
|
|
|
25
25
|
const planScan = require("./plan-scan.cjs");
|
|
26
26
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
27
27
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
28
|
-
const { planningPaths, planningRoot, getActiveWorkstream } = planningWorkspace;
|
|
28
|
+
const { planningPaths, planningRoot, getActiveWorkstream, resolvePhaseIdConvention } = planningWorkspace;
|
|
29
29
|
const state_document_cjs_1 = require("./state-document.cjs");
|
|
30
30
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- frontmatter.cjs is an export= CommonJS module
|
|
31
31
|
const frontmatterMod = require("./frontmatter.cjs");
|
|
32
32
|
const { extractFrontmatter, stripFrontmatter } = frontmatterMod;
|
|
33
|
-
const
|
|
33
|
+
const roadmap_progress_cjs_1 = require("./roadmap-progress.cjs");
|
|
34
34
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- verification.cjs is an export= CommonJS module
|
|
35
35
|
const verificationMod = require("./verification.cjs");
|
|
36
36
|
const { isPhaseComplete, isVerificationStatus, VERIFICATION_STATUS } = verificationMod;
|
|
@@ -41,6 +41,9 @@ const { phaseKeyFromDir, phaseKeyFromProse, parentPhaseKey } = phaseIdMod;
|
|
|
41
41
|
const roadmapParserMod = require("./roadmap-parser.cjs");
|
|
42
42
|
const { getMilestonePhaseFilter, isMilestoneShippedInRoadmap } = roadmapParserMod;
|
|
43
43
|
const workstream_inventory_builder_cjs_1 = require("./workstream-inventory-builder.cjs");
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
45
|
+
const phaseLocatorMod = require("./phase-locator.cjs");
|
|
46
|
+
const { phaseDirectoryOptions } = phaseLocatorMod;
|
|
44
47
|
// ─── Implementation ───────────────────────────────────────────────────────────
|
|
45
48
|
function workstreamsRoot(cwd) {
|
|
46
49
|
return node_path_1.default.join(planningRoot(cwd), 'workstreams');
|
|
@@ -75,7 +78,7 @@ function countRoadmapPhases(roadmapPath, fallbackCount, cwd, ws, versionOverride
|
|
|
75
78
|
// `null` -> 0 (fallback), `undefined` -> 3. A non-bracket workstream
|
|
76
79
|
// resolves to a value that compiles the same base grammar `null` did, so
|
|
77
80
|
// its count is unchanged (verified against a legacy control).
|
|
78
|
-
const filter = getMilestonePhaseFilter(cwd, versionOverride ?? null, undefined, ws ?? null);
|
|
81
|
+
const filter = getMilestonePhaseFilter(cwd, versionOverride ?? null, undefined, ws ?? null, phaseDirectoryOptions(cwd, undefined, undefined, ws ?? null));
|
|
79
82
|
// A pass-all degrade (phaseCount 0) means the window declared no phases —
|
|
80
83
|
// fall back rather than reporting a confident zero.
|
|
81
84
|
return filter.phaseCount > 0 ? filter.phaseCount : fallbackCount;
|
|
@@ -98,25 +101,22 @@ function countRoadmapPhases(roadmapPath, fallbackCount, cwd, ws, versionOverride
|
|
|
98
101
|
* `phaseKeyFromDir` uses for directories, so a `| 01. … |` row and a `1-slug`
|
|
99
102
|
* directory cannot land in different key spaces (the padding-asymmetry defect).
|
|
100
103
|
*/
|
|
101
|
-
function parseRoadmapProgressRows(
|
|
102
|
-
let content;
|
|
103
|
-
try {
|
|
104
|
-
content = node_fs_1.default.readFileSync(roadmapPath, 'utf-8');
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
return []; /* no roadmap */
|
|
108
|
-
}
|
|
104
|
+
function parseRoadmapProgressRows(content, directoryContext, convention) {
|
|
109
105
|
// Milestone-ATTRIBUTING shape first. Both shapes carry `Plans Complete`, so
|
|
110
106
|
// probing that column first would pick a flat table appearing earlier in the
|
|
111
107
|
// document over a milestone-grouped one later — every row would come back
|
|
112
108
|
// unattributed and be treated as current-milestone, silently over-including.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
109
|
+
// #5761: the roadmap-progress owner picks the table (heading-scoped, so a
|
|
110
|
+
// decoy table elsewhere cannot be mistaken for it); this reader only supplies
|
|
111
|
+
// the probe order. A table outside a table-less `## Progress` section has
|
|
112
|
+
// always been read here (#5692: no behavior change), hence `sectionMiss`.
|
|
113
|
+
const { rows: tableRows } = (0, roadmap_progress_cjs_1.locateRoadmapProgress)(content, {
|
|
114
|
+
columns: [['Phase', 'Milestone'], ['Phase', 'Plans Complete']],
|
|
115
|
+
sectionMiss: 'document',
|
|
116
|
+
});
|
|
117
117
|
const rows = [];
|
|
118
|
-
for (const row of
|
|
119
|
-
const key = phaseKeyFromProse(row['Phase']);
|
|
118
|
+
for (const row of tableRows) {
|
|
119
|
+
const key = phaseKeyFromProse(row['Phase'], directoryContext, convention);
|
|
120
120
|
if (key === null)
|
|
121
121
|
continue;
|
|
122
122
|
const cell = (row['Milestone'] ?? '').trim();
|
|
@@ -428,12 +428,18 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
428
428
|
const writeDiagnostic = options.writeDiagnostic ?? ((message) => process.stderr.write(message));
|
|
429
429
|
const p = planningPaths(cwd, name);
|
|
430
430
|
const phaseDirNames = readSubdirectories(p.phases);
|
|
431
|
+
let roadmap = '';
|
|
432
|
+
try {
|
|
433
|
+
roadmap = node_fs_1.default.readFileSync(p.roadmap, 'utf8');
|
|
434
|
+
}
|
|
435
|
+
catch { /* no roadmap */ }
|
|
436
|
+
const directoryContext = phaseDirectoryOptions(cwd, undefined, roadmap, name);
|
|
431
437
|
// #2562: scope progress to the CURRENT milestone. Membership and the
|
|
432
438
|
// denominator are derived in ONE key space (`phaseKeyFromDir` /
|
|
433
439
|
// `phaseKeyFromProse`, both from the phase-id owner module) so the two sides
|
|
434
440
|
// of the rollup cannot disagree.
|
|
435
441
|
const currentVersion = readCurrentMilestoneVersion(p.state, p.roadmap);
|
|
436
|
-
const progressRows = parseRoadmapProgressRows(
|
|
442
|
+
const progressRows = parseRoadmapProgressRows(roadmap, directoryContext, resolvePhaseIdConvention(cwd, name));
|
|
437
443
|
// Phase keys the ROADMAP attributes to the current milestone. A row whose
|
|
438
444
|
// Milestone cell is blank or malformed is INCLUDED rather than dropped: a
|
|
439
445
|
// phase we cannot attribute must still be visible to the rollup. Dropping it
|
|
@@ -458,7 +464,7 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
458
464
|
// it is exactly the caller that cannot set `GSD_WORKSTREAM`; spelling `null`
|
|
459
465
|
// pinned every workstream to the legacy grammar and made `headingScoped`
|
|
460
466
|
// unreachable (`phaseCount > 0` never held) on a bracket workstream.
|
|
461
|
-
const headingFilter = getMilestonePhaseFilter(cwd, currentVersion, undefined, name);
|
|
467
|
+
const headingFilter = getMilestonePhaseFilter(cwd, currentVersion, undefined, name, directoryContext);
|
|
462
468
|
const headingScoped = headingFilter.versionScoped && headingFilter.phaseCount > 0;
|
|
463
469
|
// Phase keys the ROADMAP attributes to some OTHER milestone. A row carrying an
|
|
464
470
|
// explicit version that is not the current one is a positive claim by a prior
|
|
@@ -507,7 +513,7 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
507
513
|
const isDirInCurrentMilestone = (dir) => {
|
|
508
514
|
if (!scoped)
|
|
509
515
|
return true;
|
|
510
|
-
const key = phaseKeyFromDir(dir);
|
|
516
|
+
const key = phaseKeyFromDir(dir, undefined, directoryContext);
|
|
511
517
|
if (currentMilestoneKeys.has(key))
|
|
512
518
|
return true;
|
|
513
519
|
const parent = parentPhaseKey(key);
|
|
@@ -563,7 +569,7 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
563
569
|
}
|
|
564
570
|
return {
|
|
565
571
|
directory: dir,
|
|
566
|
-
phaseKey: phaseKeyFromDir(dir),
|
|
572
|
+
phaseKey: phaseKeyFromDir(dir, undefined, directoryContext),
|
|
567
573
|
mtimeMs: phaseDirMtime(phaseDir),
|
|
568
574
|
planCount: counts.planCount,
|
|
569
575
|
summaryCount: counts.summaryCount,
|
|
@@ -24,8 +24,10 @@ exports.cmdWorktreeSetBaseRef = cmdWorktreeSetBaseRef;
|
|
|
24
24
|
exports.classifyGitHead = classifyGitHead;
|
|
25
25
|
exports.observeHarnessForkFromHead = observeHarnessForkFromHead;
|
|
26
26
|
exports.evaluateWorktreeBaseDegrade = evaluateWorktreeBaseDegrade;
|
|
27
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
27
28
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
28
29
|
const node_path_1 = __importDefault(require("node:path"));
|
|
30
|
+
const gsd_tool_dir_cjs_1 = require("./gsd-tool-dir.cjs");
|
|
29
31
|
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
30
32
|
const runtime_homes_cjs_1 = require("./runtime-homes.cjs");
|
|
31
33
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
@@ -572,13 +574,41 @@ function observeHarnessForkFromHead(deps) {
|
|
|
572
574
|
}
|
|
573
575
|
});
|
|
574
576
|
const stateWrite = deps.stateWrite ?? ((file, content) => {
|
|
577
|
+
let tmpPath = null;
|
|
575
578
|
try {
|
|
576
|
-
|
|
577
|
-
|
|
579
|
+
// #5757: the shared owner refuses a symlinked/escaping .gsd and keeps the
|
|
580
|
+
// directory git-ignored; the write is an exclusive random tmp + rename so
|
|
581
|
+
// a planted cache-file symlink is replaced, never followed.
|
|
582
|
+
const dir = (0, gsd_tool_dir_cjs_1.ensureToolOwnedGsdDir)(cwd, {
|
|
583
|
+
marker: '# gsd-core harness fork probe',
|
|
584
|
+
rules: ['/harness-fork-probe.json', '/harness-fork-probe.json.tmp-*', '/.gitignore'],
|
|
585
|
+
});
|
|
586
|
+
const target = node_path_1.default.join(dir, node_path_1.default.basename(file));
|
|
587
|
+
// `tmpPath` is assigned only once the exclusive create succeeded, so an
|
|
588
|
+
// EEXIST never unlinks an entry this process did not create.
|
|
589
|
+
const candidateTmp = `${target}.tmp-${process.pid}-${node_crypto_1.default.randomBytes(6).toString('hex')}`;
|
|
590
|
+
const tmpFd = node_fs_1.default.openSync(candidateTmp, 'wx');
|
|
591
|
+
tmpPath = candidateTmp;
|
|
592
|
+
try {
|
|
593
|
+
node_fs_1.default.writeFileSync(tmpFd, content, 'utf8');
|
|
594
|
+
}
|
|
595
|
+
finally {
|
|
596
|
+
node_fs_1.default.closeSync(tmpFd);
|
|
597
|
+
}
|
|
598
|
+
(0, shell_command_projection_cjs_1.retryRenameSync)(tmpPath, target);
|
|
599
|
+
tmpPath = null;
|
|
578
600
|
}
|
|
579
601
|
catch {
|
|
580
602
|
// A cache write must never break the check that produced the verdict.
|
|
581
603
|
}
|
|
604
|
+
finally {
|
|
605
|
+
if (tmpPath) {
|
|
606
|
+
try {
|
|
607
|
+
node_fs_1.default.unlinkSync(tmpPath);
|
|
608
|
+
}
|
|
609
|
+
catch { /* best-effort cleanup */ }
|
|
610
|
+
}
|
|
611
|
+
}
|
|
582
612
|
});
|
|
583
613
|
// 1. Cache — trusted only while the orchestrator HEAD is unchanged.
|
|
584
614
|
try {
|