gsdd-cli 0.18.5 → 0.19.0

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.
Files changed (100) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +609 -608
  3. package/agents/DISTILLATION.md +421 -421
  4. package/agents/README.md +62 -62
  5. package/agents/approach-explorer.md +361 -361
  6. package/agents/debugger.md +82 -82
  7. package/agents/executor.md +394 -394
  8. package/agents/integration-checker.md +318 -318
  9. package/agents/mapper.md +103 -103
  10. package/agents/planner.md +313 -313
  11. package/agents/researcher.md +84 -84
  12. package/agents/roadmapper.md +296 -296
  13. package/agents/synthesizer.md +236 -236
  14. package/agents/verifier.md +337 -337
  15. package/bin/adapters/agents.mjs +34 -34
  16. package/bin/adapters/claude.mjs +191 -191
  17. package/bin/adapters/codex.mjs +85 -85
  18. package/bin/adapters/index.mjs +20 -20
  19. package/bin/adapters/opencode.mjs +278 -278
  20. package/bin/gsdd.mjs +123 -116
  21. package/bin/lib/cli-utils.mjs +28 -28
  22. package/bin/lib/evidence-contract.mjs +112 -112
  23. package/bin/lib/file-ops.mjs +186 -144
  24. package/bin/lib/health-truth.mjs +181 -178
  25. package/bin/lib/health.mjs +246 -226
  26. package/bin/lib/init-flow.mjs +247 -231
  27. package/bin/lib/init-prompts.mjs +248 -247
  28. package/bin/lib/init-runtime.mjs +191 -190
  29. package/bin/lib/init.mjs +17 -17
  30. package/bin/lib/lifecycle-preflight.mjs +347 -325
  31. package/bin/lib/lifecycle-state.mjs +351 -267
  32. package/bin/lib/manifest.mjs +116 -114
  33. package/bin/lib/models.mjs +411 -411
  34. package/bin/lib/phase.mjs +360 -358
  35. package/bin/lib/plan-constants.mjs +30 -30
  36. package/bin/lib/provenance.mjs +109 -106
  37. package/bin/lib/rendering.mjs +115 -83
  38. package/bin/lib/runtime-freshness.mjs +214 -214
  39. package/bin/lib/templates.mjs +225 -224
  40. package/bin/lib/workspace-root.mjs +2 -1
  41. package/distilled/DESIGN.md +2333 -2323
  42. package/distilled/EVIDENCE-INDEX.md +394 -392
  43. package/distilled/README.md +196 -193
  44. package/distilled/SKILL.md +86 -85
  45. package/distilled/templates/agents.block.md +21 -21
  46. package/distilled/templates/agents.md +6 -6
  47. package/distilled/templates/approach.md +232 -232
  48. package/distilled/templates/auth-matrix.md +78 -78
  49. package/distilled/templates/brownfield-change/CHANGE.md +99 -0
  50. package/distilled/templates/brownfield-change/HANDOFF.md +38 -0
  51. package/distilled/templates/brownfield-change/VERIFICATION.md +56 -0
  52. package/distilled/templates/codebase/architecture.md +110 -110
  53. package/distilled/templates/codebase/concerns.md +95 -95
  54. package/distilled/templates/codebase/conventions.md +193 -193
  55. package/distilled/templates/codebase/stack.md +96 -96
  56. package/distilled/templates/delegates/approach-explorer.md +25 -25
  57. package/distilled/templates/delegates/mapper-arch.md +26 -26
  58. package/distilled/templates/delegates/mapper-concerns.md +27 -27
  59. package/distilled/templates/delegates/mapper-quality.md +28 -28
  60. package/distilled/templates/delegates/mapper-tech.md +25 -25
  61. package/distilled/templates/delegates/plan-checker.md +68 -68
  62. package/distilled/templates/delegates/researcher-architecture.md +30 -30
  63. package/distilled/templates/delegates/researcher-features.md +30 -30
  64. package/distilled/templates/delegates/researcher-pitfalls.md +30 -30
  65. package/distilled/templates/delegates/researcher-stack.md +30 -30
  66. package/distilled/templates/delegates/researcher-synthesizer.md +31 -31
  67. package/distilled/templates/research/architecture.md +57 -57
  68. package/distilled/templates/research/features.md +23 -23
  69. package/distilled/templates/research/pitfalls.md +46 -46
  70. package/distilled/templates/research/stack.md +45 -45
  71. package/distilled/templates/research/summary.md +67 -67
  72. package/distilled/templates/roadmap.md +74 -62
  73. package/distilled/templates/spec.md +110 -110
  74. package/distilled/workflows/audit-milestone.md +275 -271
  75. package/distilled/workflows/complete-milestone.md +336 -332
  76. package/distilled/workflows/execute.md +454 -449
  77. package/distilled/workflows/map-codebase.md +253 -253
  78. package/distilled/workflows/new-milestone.md +242 -238
  79. package/distilled/workflows/new-project.md +398 -398
  80. package/distilled/workflows/pause.md +160 -156
  81. package/distilled/workflows/plan-milestone-gaps.md +183 -183
  82. package/distilled/workflows/plan.md +451 -447
  83. package/distilled/workflows/progress.md +227 -223
  84. package/distilled/workflows/quick.md +351 -347
  85. package/distilled/workflows/resume.md +220 -212
  86. package/distilled/workflows/verify-work.md +260 -260
  87. package/distilled/workflows/verify.md +431 -429
  88. package/docs/BROWNFIELD-PROOF.md +95 -95
  89. package/docs/RUNTIME-SUPPORT.md +80 -69
  90. package/docs/USER-GUIDE.md +394 -386
  91. package/docs/VERIFICATION-DISCIPLINE.md +59 -59
  92. package/docs/claude/context-monitor.md +98 -98
  93. package/docs/proof/consumer-node-cli/README.md +37 -37
  94. package/docs/proof/consumer-node-cli/ROADMAP.md +14 -14
  95. package/docs/proof/consumer-node-cli/SPEC.md +17 -17
  96. package/docs/proof/consumer-node-cli/brief.md +9 -9
  97. package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-PLAN.md +34 -34
  98. package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-SUMMARY.md +10 -10
  99. package/docs/proof/consumer-node-cli/phases/01-foundation/01-VERIFICATION.md +30 -30
  100. package/package.json +62 -61
@@ -1,92 +1,95 @@
1
- import { existsSync, readFileSync, readdirSync } from 'fs';
2
- import { join } from 'path';
3
- import { evaluateLifecycleState } from './lifecycle-state.mjs';
4
- import {
5
- getRuntimeFreshnessRepairGuidance,
6
- summarizeRuntimeFreshnessIssues,
7
- } from './runtime-freshness.mjs';
8
- import { checkDrift } from './session-fingerprint.mjs';
9
-
10
- export const TRUTH_CHECK_IDS = ['W7', 'W8', 'W9', 'W10', 'W11', 'W12'];
11
-
12
- export function runTruthChecks(planningDir, frameworkDir, actualCheckIds, options = {}) {
13
- const warnings = [];
14
- const designPath = join(frameworkDir, 'distilled', 'DESIGN.md');
15
- const readmePath = join(frameworkDir, 'distilled', 'README.md');
16
- const workflowsDir = join(frameworkDir, 'distilled', 'workflows');
17
- const gapsPath = join(frameworkDir, '.internal-research', 'gaps.md');
18
- const specPath = join(planningDir, 'SPEC.md');
19
- const roadmapPath = join(planningDir, 'ROADMAP.md');
20
- const lifecycle = evaluateLifecycleState({ planningDir });
21
-
22
- if (existsSync(designPath)) {
23
- const documentedIds = extractHealthTableIds(readFileSync(designPath, 'utf-8'));
24
- const missingFromDesign = actualCheckIds.filter((id) => !documentedIds.includes(id));
25
- const extraInDesign = documentedIds.filter((id) => !actualCheckIds.includes(id));
26
- if (missingFromDesign.length > 0 || extraInDesign.length > 0) {
27
- const parts = [];
28
- if (missingFromDesign.length > 0) parts.push(`missing in DESIGN.md: ${missingFromDesign.join(', ')}`);
29
- if (extraInDesign.length > 0) parts.push(`extra in DESIGN.md: ${extraInDesign.join(', ')}`);
30
- warnings.push({
31
- id: 'W7',
32
- severity: 'WARN',
33
- message: `DESIGN.md health check table is out of sync (${parts.join('; ')})`,
34
- fix: 'Update distilled/DESIGN.md section 20 to match the implemented health checks',
35
- });
36
- }
37
- }
38
-
39
- if (existsSync(readmePath) && existsSync(workflowsDir)) {
40
- const readme = readFileSync(readmePath, 'utf-8');
41
- const workflowFiles = readdirSync(workflowsDir).filter((entry) => entry.endsWith('.md')).sort();
42
- const statusEntries = extractReadmeStatusEntries(readme);
43
- const treeEntries = extractReadmeWorkflowTreeEntries(readme);
44
- const issues = [];
45
- if (statusEntries.length !== workflowFiles.length) {
46
- issues.push(`status table ${statusEntries.length} != workflows dir ${workflowFiles.length}`);
47
- }
48
- if (treeEntries.length !== workflowFiles.length) {
49
- issues.push(`framework tree ${treeEntries.length} != workflows dir ${workflowFiles.length}`);
50
- }
51
- const missingStatus = workflowFiles.filter((name) => !statusEntries.includes(name));
52
- const missingTree = workflowFiles.filter((name) => !treeEntries.includes(name));
53
- if (missingStatus.length > 0) issues.push(`missing from status table: ${missingStatus.join(', ')}`);
54
- if (missingTree.length > 0) issues.push(`missing from framework tree: ${missingTree.join(', ')}`);
55
- if (issues.length > 0) {
56
- warnings.push({
57
- id: 'W8',
58
- severity: 'WARN',
59
- message: `distilled/README.md workflow inventory is out of sync (${issues.join('; ')})`,
60
- fix: 'Update distilled/README.md workflow status table and framework file tree to match distilled/workflows/',
61
- });
62
- }
63
- }
64
-
65
- if (existsSync(gapsPath)) {
66
- const gapRefs = extractRepoLocalPaths(readFileSync(gapsPath, 'utf-8'));
67
- const missingRefs = gapRefs.filter((ref) => !existsSync(join(frameworkDir, ref)));
68
- if (missingRefs.length > 0) {
69
- warnings.push({
70
- id: 'W9',
71
- severity: 'WARN',
72
- message: `gaps.md references missing repo-local paths (${missingRefs.join(', ')})`,
73
- fix: 'Annotate stale gap references as resolved or update them to current repo truth',
74
- });
75
- }
76
- }
77
-
78
- if (existsSync(specPath) && existsSync(roadmapPath)) {
79
- const mismatches = lifecycle.requirementAlignment.mismatches;
80
- if (mismatches.length > 0) {
81
- warnings.push({
82
- id: 'W10',
83
- severity: 'WARN',
84
- message: `ROADMAP/SPEC requirement status drift (${mismatches.join('; ')})`,
85
- fix: 'Reconcile .planning/ROADMAP.md phase completion markers with .planning/SPEC.md requirement checkboxes',
86
- });
87
- }
88
- }
89
-
1
+ import { existsSync, readFileSync, readdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { evaluateLifecycleState } from './lifecycle-state.mjs';
4
+ import {
5
+ getRuntimeFreshnessRepairGuidance,
6
+ summarizeRuntimeFreshnessIssues,
7
+ } from './runtime-freshness.mjs';
8
+ import { checkDrift } from './session-fingerprint.mjs';
9
+
10
+ export const TRUTH_CHECK_IDS = ['W7', 'W8', 'W9', 'W10', 'W11', 'W12'];
11
+
12
+ export function runTruthChecks(planningDir, frameworkDir, actualCheckIds, options = {}) {
13
+ const warnings = [];
14
+ const designPath = join(frameworkDir, 'distilled', 'DESIGN.md');
15
+ const readmePath = join(frameworkDir, 'distilled', 'README.md');
16
+ const workflowsDir = join(frameworkDir, 'distilled', 'workflows');
17
+ const gapsPath = join(frameworkDir, '.internal-research', 'gaps.md');
18
+ const specPath = join(planningDir, 'SPEC.md');
19
+ const roadmapPath = join(planningDir, 'ROADMAP.md');
20
+ const lifecycle = evaluateLifecycleState({ planningDir });
21
+
22
+ if (existsSync(designPath)) {
23
+ const documentedIds = extractHealthTableIds(readFileSync(designPath, 'utf-8'));
24
+ const missingFromDesign = actualCheckIds.filter((id) => !documentedIds.includes(id));
25
+ const extraInDesign = documentedIds.filter((id) => !actualCheckIds.includes(id));
26
+ if (missingFromDesign.length > 0 || extraInDesign.length > 0) {
27
+ const parts = [];
28
+ if (missingFromDesign.length > 0) parts.push(`missing in DESIGN.md: ${missingFromDesign.join(', ')}`);
29
+ if (extraInDesign.length > 0) parts.push(`extra in DESIGN.md: ${extraInDesign.join(', ')}`);
30
+ warnings.push({
31
+ id: 'W7',
32
+ severity: 'WARN',
33
+ message: `DESIGN.md health check table is out of sync (${parts.join('; ')})`,
34
+ fix: 'Update distilled/DESIGN.md section 20 to match the implemented health checks',
35
+ });
36
+ }
37
+ }
38
+
39
+ if (existsSync(readmePath) && existsSync(workflowsDir)) {
40
+ const readme = readFileSync(readmePath, 'utf-8');
41
+ const workflowFiles = readdirSync(workflowsDir).filter((entry) => entry.endsWith('.md')).sort();
42
+ const statusEntries = extractReadmeStatusEntries(readme);
43
+ const treeEntries = extractReadmeWorkflowTreeEntries(readme);
44
+ const issues = [];
45
+ if (statusEntries.length !== workflowFiles.length) {
46
+ issues.push(`status table ${statusEntries.length} != workflows dir ${workflowFiles.length}`);
47
+ }
48
+ if (treeEntries.length !== workflowFiles.length) {
49
+ issues.push(`framework tree ${treeEntries.length} != workflows dir ${workflowFiles.length}`);
50
+ }
51
+ const missingStatus = workflowFiles.filter((name) => !statusEntries.includes(name));
52
+ const missingTree = workflowFiles.filter((name) => !treeEntries.includes(name));
53
+ if (missingStatus.length > 0) issues.push(`missing from status table: ${missingStatus.join(', ')}`);
54
+ if (missingTree.length > 0) issues.push(`missing from framework tree: ${missingTree.join(', ')}`);
55
+ if (issues.length > 0) {
56
+ warnings.push({
57
+ id: 'W8',
58
+ severity: 'WARN',
59
+ message: `distilled/README.md workflow inventory is out of sync (${issues.join('; ')})`,
60
+ fix: 'Update distilled/README.md workflow status table and framework file tree to match distilled/workflows/',
61
+ });
62
+ }
63
+ }
64
+
65
+ if (existsSync(gapsPath)) {
66
+ const gapRefs = extractRepoLocalPaths(readFileSync(gapsPath, 'utf-8'));
67
+ const missingRefs = gapRefs.filter((ref) => !existsSync(join(frameworkDir, ref)));
68
+ if (missingRefs.length > 0) {
69
+ warnings.push({
70
+ id: 'W9',
71
+ severity: 'WARN',
72
+ message: `gaps.md references missing repo-local paths (${missingRefs.join(', ')})`,
73
+ fix: 'Annotate stale gap references as resolved or update them to current repo truth',
74
+ });
75
+ }
76
+ }
77
+
78
+ if (existsSync(roadmapPath)) {
79
+ const mismatches = [
80
+ ...(existsSync(specPath) ? lifecycle.requirementAlignment.mismatches : []),
81
+ ...lifecycle.phaseStatusAlignment.mismatches,
82
+ ];
83
+ if (mismatches.length > 0) {
84
+ warnings.push({
85
+ id: 'W10',
86
+ severity: 'WARN',
87
+ message: `ROADMAP/SPEC requirement status drift (${mismatches.join('; ')})`,
88
+ fix: 'Reconcile .planning/ROADMAP.md phase completion markers with .planning/SPEC.md requirement checkboxes',
89
+ });
90
+ }
91
+ }
92
+
90
93
  if (options.runtimeFreshnessReport?.issueCount > 0) {
91
94
  warnings.push({
92
95
  id: 'W11',
@@ -95,92 +98,92 @@ export function runTruthChecks(planningDir, frameworkDir, actualCheckIds, option
95
98
  fix: getRuntimeFreshnessRepairGuidance(options.runtimeFreshnessReport),
96
99
  });
97
100
  }
98
-
99
- const drift = checkDrift(planningDir);
100
- if (drift.drifted) {
101
- warnings.push({
102
- id: 'W12',
103
- severity: 'WARN',
104
- message: `Planning state drifted since last recorded session (${drift.details.join('; ')})`,
105
- fix: 'Review the changes, then run a lifecycle workflow to update the fingerprint',
106
- });
107
- }
108
-
109
- return warnings;
110
- }
111
-
112
- function extractHealthTableIds(content) {
113
- const section = extractSection(content, '## 20. Workspace Health Diagnostics', '## 21.');
114
- if (!section) return [];
115
- return [...normalizeContent(section).matchAll(/^\|\s*([EWI]\d+)\s*\|/gm)].map((result) => result[1]);
116
- }
117
-
118
- function extractReadmeStatusEntries(content) {
119
- const section = extractSection(content, '## Current Status', 'Architecture notes:');
120
- if (!section) return [];
121
- return [...normalizeContent(section).matchAll(/\|\s*`([^`]+\.md)`\s*\|/g)].map((result) => result[1]);
122
- }
123
-
124
- function extractReadmeWorkflowTreeEntries(content) {
125
- const section = extractSection(content, '## Files In This Framework', '## ');
126
- const match = normalizeContent(section || '').match(/```[\s\S]*?workflows\/\n([\s\S]*?)\n\s*templates\//);
127
- if (!match) return [];
128
- return match[1]
129
- .split('\n')
130
- .map((line) => line.trim())
131
- .filter((line) => line.endsWith('.md'));
132
- }
133
-
134
- function extractRepoLocalPaths(content) {
135
- const allowedRoots = [
136
- 'AGENTS.md',
137
- 'README.md',
138
- 'CHANGELOG.md',
139
- 'SPEC.md',
140
- 'package.json',
141
- '.planning/',
142
- '.internal-research/',
143
- '.agents/',
144
- '.claude/',
145
- '.opencode/',
146
- '.codex/',
147
- '.worktrees/',
148
- 'bin/',
149
- 'distilled/',
150
- 'tests/',
151
- 'fixtures/',
152
- 'agents/',
153
- ];
154
- const refs = new Set();
155
- for (const result of content.matchAll(/`([^`]+)`/g)) {
156
- const value = result[1].trim();
157
- if (!looksLikeRepoLocalPath(value, allowedRoots)) continue;
158
- refs.add(value.replace(/\\/g, '/').replace(/\/$/, ''));
159
- }
160
- return [...refs];
161
- }
162
-
163
- function looksLikeRepoLocalPath(value, allowedRoots) {
164
- if (value.includes(' ')) return false;
165
- if (value.startsWith('/')) return false;
166
- if (value.startsWith('$')) return false;
167
- if (value.startsWith('..')) return false;
168
- if (value.includes('://')) return false;
169
- if (value.startsWith('feat/') || value.startsWith('fix/') || value.startsWith('pr') || value.startsWith('origin/')) return false;
170
- if (allowedRoots.some((root) => value === root || value.startsWith(root))) return true;
171
- return false;
172
- }
173
-
174
- function extractSection(content, startMarker, endMarker) {
175
- const normalized = normalizeContent(content);
176
- const start = normalized.indexOf(startMarker);
177
- if (start === -1) return '';
178
- const rest = normalized.slice(start);
179
- if (!endMarker) return rest;
180
- const end = rest.indexOf(endMarker, startMarker.length);
181
- return end === -1 ? rest : rest.slice(0, end);
182
- }
183
-
184
- function normalizeContent(content) {
185
- return content.replace(/\r\n/g, '\n');
186
- }
101
+
102
+ const drift = checkDrift(planningDir);
103
+ if (drift.drifted) {
104
+ warnings.push({
105
+ id: 'W12',
106
+ severity: 'WARN',
107
+ message: `Planning state drifted since last recorded session (${drift.details.join('; ')})`,
108
+ fix: 'Review the changes, then run a lifecycle workflow to update the fingerprint',
109
+ });
110
+ }
111
+
112
+ return warnings;
113
+ }
114
+
115
+ function extractHealthTableIds(content) {
116
+ const section = extractSection(content, '## 20. Workspace Health Diagnostics', '## 21.');
117
+ if (!section) return [];
118
+ return [...normalizeContent(section).matchAll(/^\|\s*([EWI]\d+)\s*\|/gm)].map((result) => result[1]);
119
+ }
120
+
121
+ function extractReadmeStatusEntries(content) {
122
+ const section = extractSection(content, '## Current Status', 'Architecture notes:');
123
+ if (!section) return [];
124
+ return [...normalizeContent(section).matchAll(/\|\s*`([^`]+\.md)`\s*\|/g)].map((result) => result[1]);
125
+ }
126
+
127
+ function extractReadmeWorkflowTreeEntries(content) {
128
+ const section = extractSection(content, '## Files In This Framework', '## ');
129
+ const match = normalizeContent(section || '').match(/```[\s\S]*?workflows\/\n([\s\S]*?)\n\s*templates\//);
130
+ if (!match) return [];
131
+ return match[1]
132
+ .split('\n')
133
+ .map((line) => line.trim())
134
+ .filter((line) => line.endsWith('.md'));
135
+ }
136
+
137
+ function extractRepoLocalPaths(content) {
138
+ const allowedRoots = [
139
+ 'AGENTS.md',
140
+ 'README.md',
141
+ 'CHANGELOG.md',
142
+ 'SPEC.md',
143
+ 'package.json',
144
+ '.planning/',
145
+ '.internal-research/',
146
+ '.agents/',
147
+ '.claude/',
148
+ '.opencode/',
149
+ '.codex/',
150
+ '.worktrees/',
151
+ 'bin/',
152
+ 'distilled/',
153
+ 'tests/',
154
+ 'fixtures/',
155
+ 'agents/',
156
+ ];
157
+ const refs = new Set();
158
+ for (const result of content.matchAll(/`([^`]+)`/g)) {
159
+ const value = result[1].trim();
160
+ if (!looksLikeRepoLocalPath(value, allowedRoots)) continue;
161
+ refs.add(value.replace(/\\/g, '/').replace(/\/$/, ''));
162
+ }
163
+ return [...refs];
164
+ }
165
+
166
+ function looksLikeRepoLocalPath(value, allowedRoots) {
167
+ if (value.includes(' ')) return false;
168
+ if (value.startsWith('/')) return false;
169
+ if (value.startsWith('$')) return false;
170
+ if (value.startsWith('..')) return false;
171
+ if (value.includes('://')) return false;
172
+ if (value.startsWith('feat/') || value.startsWith('fix/') || value.startsWith('pr') || value.startsWith('origin/')) return false;
173
+ if (allowedRoots.some((root) => value === root || value.startsWith(root))) return true;
174
+ return false;
175
+ }
176
+
177
+ function extractSection(content, startMarker, endMarker) {
178
+ const normalized = normalizeContent(content);
179
+ const start = normalized.indexOf(startMarker);
180
+ if (start === -1) return '';
181
+ const rest = normalized.slice(start);
182
+ if (!endMarker) return rest;
183
+ const end = rest.indexOf(endMarker, startMarker.length);
184
+ return end === -1 ? rest : rest.slice(0, end);
185
+ }
186
+
187
+ function normalizeContent(content) {
188
+ return content.replace(/\r\n/g, '\n');
189
+ }