@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
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Roadmap Progress Module (#5761, Phase 1 of epic #5692): the single owner of
|
|
4
|
+
* "which table is this ROADMAP's Progress table, and what is its milestone
|
|
5
|
+
* slice".
|
|
6
|
+
*
|
|
7
|
+
* Before this module the question was answered by six locators/scopers that
|
|
8
|
+
* disagreed on `## Progress Tracker`, on a `## Progress` inside a fenced block,
|
|
9
|
+
* and on the headingless fallback. Every READER now asks `locateRoadmapProgress`
|
|
10
|
+
* (or, for the "does this span hold the Progress section" probe,
|
|
11
|
+
* `findProgressSection`); a second hand-written `## Progress` regex or
|
|
12
|
+
* table-locating call in a reader is the DEFECT.GENERATIVE-FIX shape.
|
|
13
|
+
*
|
|
14
|
+
* The rule, defined once:
|
|
15
|
+
* - The Progress section is the first level-2 ATX heading, outside fenced
|
|
16
|
+
* code, whose text starts with the word `Progress` (`## Progress`,
|
|
17
|
+
* `## Progress Tracker`). It runs to the next level-1/2 heading outside
|
|
18
|
+
* fenced code.
|
|
19
|
+
* - The table is the first table in that section whose header is a SUPERSET
|
|
20
|
+
* of the requested column set (ADR-2143 §3: addressed by NAME, never
|
|
21
|
+
* ordinal). A section with no matching table yields no table; it does not
|
|
22
|
+
* fall through to the rest of the document (#2012 decoy avoidance).
|
|
23
|
+
* - A document with no Progress heading is scanned whole (a headingless
|
|
24
|
+
* milestone slice, #1445, keeps resolving).
|
|
25
|
+
* - Two readers had a wider pre-owner reach and ask for it by name, so the
|
|
26
|
+
* rule stays single (#5692: no behavior change for existing ROADMAP.md
|
|
27
|
+
* files): `levels: [1, 2]` for the archive-span probe, which always took a
|
|
28
|
+
* level-1 `# Progress`, and `sectionMiss: 'document'` for the workstream
|
|
29
|
+
* inventory, which always read a table outside a table-less section.
|
|
30
|
+
* - The milestone slice (#5165): when the caller names a milestone and the
|
|
31
|
+
* table carries a `Milestone` column, only that milestone's rows.
|
|
32
|
+
*
|
|
33
|
+
* The writers (`roadmap.cts` update-plan-progress / phase add, `phase.cts`
|
|
34
|
+
* complete / remove) cut their slice with `editRoadmapProgress` (#5762), the
|
|
35
|
+
* write side of the same rule, so a writer edits only the section the readers
|
|
36
|
+
* read. `phase.cts`'s `cmdPhaseComplete` already-complete check still slices
|
|
37
|
+
* the Milestone column itself, with a blank-milestone-matches-nothing rule this
|
|
38
|
+
* owner deliberately does not share.
|
|
39
|
+
*/
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.isProgressHeadingTitle = isProgressHeadingTitle;
|
|
42
|
+
exports.normalizeMilestoneToken = normalizeMilestoneToken;
|
|
43
|
+
exports.milestoneVersionOf = milestoneVersionOf;
|
|
44
|
+
exports.findProgressSection = findProgressSection;
|
|
45
|
+
exports.editRoadmapProgress = editRoadmapProgress;
|
|
46
|
+
exports.locateRoadmapProgress = locateRoadmapProgress;
|
|
47
|
+
const markdown_table_cjs_1 = require("./markdown-table.cjs");
|
|
48
|
+
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
49
|
+
/** The canonical column set both RoadmapProgress variants carry. */
|
|
50
|
+
const CANONICAL_COLUMNS = ['Phase', 'Plans Complete', 'Status', 'Completed'];
|
|
51
|
+
/**
|
|
52
|
+
* The ONE textual expression of "this heading is titled Progress": the title
|
|
53
|
+
* starts with the word `Progress`, any suffix admitted (`Progress`,
|
|
54
|
+
* `Progress Tracker`, `Progress (v2.1)`), case-insensitive. `findProgressSection`
|
|
55
|
+
* adds the level-2 anchor; the bracket writers (`phase.cts`) reuse the title
|
|
56
|
+
* test at their own levels (#4304).
|
|
57
|
+
*/
|
|
58
|
+
function isProgressHeadingTitle(text) {
|
|
59
|
+
return /^Progress\b/i.test(text.trim());
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* #5165: a milestone token compared by identity, not spelling — `v1.1`, `V1.1`
|
|
63
|
+
* and ` 1.1 ` name one milestone. A hand-decorated Progress cell
|
|
64
|
+
* (`**v1.1**`, `` `v1.1` ``, `v1.1 (current)`) still names its first
|
|
65
|
+
* whitespace-separated token. Absent/blank tokens normalize to `''`.
|
|
66
|
+
*/
|
|
67
|
+
function normalizeMilestoneToken(value) {
|
|
68
|
+
// `[v1.1](ROADMAP.md#v11)` names its link text.
|
|
69
|
+
const unlinked = (milestoneVersionOf(value) ?? '').replace(/\[([^\]]*)\]\([^)]*\)/g, '$1');
|
|
70
|
+
const first = unlinked.split(/\s+/)[0] ?? '';
|
|
71
|
+
return first.replace(/^[*_`]+|[*_`:,;]+$/g, '').replace(/^v/i, '').toLowerCase();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* #5165: a STATE.md `milestone:` frontmatter value as a trimmed version string,
|
|
75
|
+
* or null when it is absent, blank or not scalar text.
|
|
76
|
+
*/
|
|
77
|
+
function milestoneVersionOf(value) {
|
|
78
|
+
if (typeof value !== 'string' && typeof value !== 'number')
|
|
79
|
+
return null;
|
|
80
|
+
const text = String(value).trim();
|
|
81
|
+
return text === '' ? null : text;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The Progress section of `content`: the first level-2 heading (`levels` widens
|
|
85
|
+
* this) outside fenced code whose text starts with the word `Progress`, up to
|
|
86
|
+
* the next level-1/2 heading. Null when the document has no such heading.
|
|
87
|
+
*/
|
|
88
|
+
function findProgressSection(content, options = {}) {
|
|
89
|
+
const headings = (0, markdown_sectionizer_cjs_1.tokenizeHeadings)(content);
|
|
90
|
+
const { active, exclude, levels = [2] } = options;
|
|
91
|
+
const isProgress = (h) => levels.includes(h.level) && isProgressHeadingTitle(h.text) && !(exclude && exclude(h.offset));
|
|
92
|
+
// #5553: with an active-milestone range, the first Progress heading INSIDE it wins over an
|
|
93
|
+
// earlier one (a shipped plain section's own table); with none in range, the first overall.
|
|
94
|
+
const inActive = active ? headings.findIndex((h) => isProgress(h) && h.offset >= active.start && h.offset < active.end) : -1;
|
|
95
|
+
const index = inActive !== -1 ? inActive : headings.findIndex(isProgress);
|
|
96
|
+
if (index === -1)
|
|
97
|
+
return null;
|
|
98
|
+
return (0, markdown_sectionizer_cjs_1.headingSliceRange)(content, headings, index, headings[index].level);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The WRITE side of the same rule (#5762): run `edit` on the Progress section
|
|
102
|
+
* `findProgressSection` locates and splice the result back byte-exact, so a
|
|
103
|
+
* writer can only ever edit the section the readers read.
|
|
104
|
+
*
|
|
105
|
+
* A document with no Progress heading is what the readers scan whole;
|
|
106
|
+
* `headingless: 'whole'` (default) gives `edit` that same whole document,
|
|
107
|
+
* `'skip'` leaves it untouched (a destructive writer that must not guess a
|
|
108
|
+
* table by column names alone).
|
|
109
|
+
*/
|
|
110
|
+
function editRoadmapProgress(content, edit, options = {}) {
|
|
111
|
+
const section = findProgressSection(content, { active: options.active });
|
|
112
|
+
if (!section)
|
|
113
|
+
return options.headingless === 'skip' ? content : edit(content);
|
|
114
|
+
return (0, markdown_sectionizer_cjs_1.editHeadingSlice)(content, section, edit);
|
|
115
|
+
}
|
|
116
|
+
/** Which table is the Progress table, and what is its milestone slice. */
|
|
117
|
+
function locateRoadmapProgress(content, options = {}) {
|
|
118
|
+
const section = findProgressSection(content);
|
|
119
|
+
const scoped = section ? content.slice(section.start, section.end) : content;
|
|
120
|
+
// `sectionMiss: 'document'` widens each column set's probe from the section to the whole
|
|
121
|
+
// document, set by set, so an earlier set found anywhere still beats a later set in the section.
|
|
122
|
+
const widen = section !== null && options.sectionMiss === 'document';
|
|
123
|
+
let table = null;
|
|
124
|
+
for (const columns of options.columns ?? [CANONICAL_COLUMNS]) {
|
|
125
|
+
table = (0, markdown_table_cjs_1.findTableWithColumns)(scoped, [...columns]) ?? (widen ? (0, markdown_table_cjs_1.findTableWithColumns)(content, [...columns]) : null);
|
|
126
|
+
if (table)
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
if (!table)
|
|
130
|
+
return { table: null, rows: [], section };
|
|
131
|
+
const want = normalizeMilestoneToken(options.milestone);
|
|
132
|
+
const rows = want !== '' && table.columns.includes('Milestone')
|
|
133
|
+
? table.rows.filter((r) => normalizeMilestoneToken(r['Milestone']) === want)
|
|
134
|
+
: table.rows;
|
|
135
|
+
return { table, rows, section };
|
|
136
|
+
}
|
|
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
14
|
const node_path_1 = __importDefault(require("node:path"));
|
|
15
15
|
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
16
|
+
const phase_entry_grammar_cjs_1 = require("./phase-entry-grammar.cjs");
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
17
18
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
18
19
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
@@ -1397,10 +1398,11 @@ function computeBracketPlan(cwd) {
|
|
|
1397
1398
|
// bullet stayed legacy after an otherwise-done migration, so the
|
|
1398
1399
|
// bracket-mode milestone id set carried the stale legacy token alongside
|
|
1399
1400
|
// the bracket ones.
|
|
1400
|
-
|
|
1401
|
+
// #5764: the prefix is the phase-entry grammar's (line-anchored, indent included).
|
|
1402
|
+
const CHECKLIST_BULLET_PREFIX_SRC = (0, phase_entry_grammar_cjs_1.phaseEntryPrefixSrc)();
|
|
1401
1403
|
const CHECKLIST_PHASE_INTRO_SRC = phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.LABEL_ONLY, undefined, true);
|
|
1402
|
-
const mnnChecklistRe = new RegExp(
|
|
1403
|
-
const legacyChecklistRe = new RegExp(
|
|
1404
|
+
const mnnChecklistRe = new RegExp(`(${CHECKLIST_BULLET_PREFIX_SRC})${CHECKLIST_PHASE_INTRO_SRC}(${MNN_SOURCE_TOKEN_SOURCE})(${OPTIONAL_PHASE_TAG_SOURCE})`, 'i');
|
|
1405
|
+
const legacyChecklistRe = new RegExp(`(${CHECKLIST_BULLET_PREFIX_SRC})${CHECKLIST_PHASE_INTRO_SRC}(${PHASE_NUMBER_TOKEN_SOURCE})(${OPTIONAL_PHASE_TAG_SOURCE})`, 'i');
|
|
1404
1406
|
// #4144 round 8 I1: `legacyChecklistRe` above requires nothing at all
|
|
1405
1407
|
// after the number/tag — deliberately, since Tier 1 (reader-recognized,
|
|
1406
1408
|
// `isReaderRecognizedBullet` below) must match exactly what the readers'
|
|
@@ -1752,7 +1754,8 @@ function computeMigrationPlan(cwd, options = {}) {
|
|
|
1752
1754
|
if (roadmapEdits.some(e => e.lineIndex === i))
|
|
1753
1755
|
continue;
|
|
1754
1756
|
// Match checklist items: "- [ ] **Phase N:**" or "- [x] Phase N:" (also decimal)
|
|
1755
|
-
|
|
1757
|
+
// The entry prefix (marker, box, bold token) is the phase-entry grammar's (#5764).
|
|
1758
|
+
const checklistMatch = line.match(new RegExp(`(${(0, phase_entry_grammar_cjs_1.phaseEntryPrefixSrc)()}Phase[ \\t]+)(${PHASE_NUMBER_TOKEN_SOURCE})(\\s*[:\\s*])`, 'i'));
|
|
1756
1759
|
if (checklistMatch) {
|
|
1757
1760
|
const legacyNum = checklistMatch[2];
|
|
1758
1761
|
const cIntPart = parseInt(legacyNum, 10);
|
|
@@ -1778,7 +1781,7 @@ function computeMigrationPlan(cwd, options = {}) {
|
|
|
1778
1781
|
newId = found.newId;
|
|
1779
1782
|
}
|
|
1780
1783
|
if (newId) {
|
|
1781
|
-
const newLine = line.replace(new RegExp(
|
|
1784
|
+
const newLine = line.replace(new RegExp(`(${(0, phase_entry_grammar_cjs_1.phaseEntryPrefixSrc)()}Phase[ \\t]+)${PHASE_NUMBER_TOKEN_SOURCE}(\\s*[:\\s*])`, 'i'), `$1${newId}$2`);
|
|
1782
1785
|
if (newLine !== line) {
|
|
1783
1786
|
roadmapEdits.push({ lineIndex: i, from: line, to: newLine });
|
|
1784
1787
|
}
|