gsd-remix 1.0.2 → 1.1.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/README.md +21 -86
- package/README.zh-CN.md +13 -57
- package/agents/gsd-debugger.md +0 -3
- package/agents/gsd-executor.md +5 -11
- package/agents/gsd-phase-researcher.md +3 -107
- package/agents/gsd-plan-checker.md +0 -61
- package/agents/gsd-planner.md +4 -63
- package/agents/gsd-roadmapper.md +0 -29
- package/agents/gsd-security-auditor.md +62 -114
- package/agents/gsd-verifier.md +0 -3
- package/bin/install.js +20 -118
- package/commands/gsd/complete-milestone.md +0 -22
- package/commands/gsd/plan-phase.md +1 -2
- package/get-shit-done/bin/gsd-tools.cjs +5 -224
- package/get-shit-done/bin/lib/claude-md.cjs +427 -0
- package/get-shit-done/bin/lib/config-schema.cjs +2 -12
- package/get-shit-done/bin/lib/config.cjs +3 -12
- package/get-shit-done/bin/lib/core.cjs +4 -5
- package/get-shit-done/bin/lib/init.cjs +0 -163
- package/get-shit-done/bin/lib/model-profiles.cjs +12 -18
- package/get-shit-done/bin/lib/verify.cjs +0 -66
- package/get-shit-done/references/agent-contracts.md +0 -6
- package/get-shit-done/references/artifact-types.md +0 -30
- package/get-shit-done/references/continuation-format.md +0 -1
- package/get-shit-done/references/model-profiles.md +39 -37
- package/get-shit-done/references/planning-config.md +7 -12
- package/get-shit-done/references/verification-overrides.md +1 -1
- package/get-shit-done/templates/README.md +2 -9
- package/get-shit-done/templates/claude-md.md +0 -14
- package/get-shit-done/templates/config.json +5 -19
- package/get-shit-done/workflows/autonomous.md +9 -141
- package/get-shit-done/workflows/complete-milestone.md +3 -4
- package/get-shit-done/workflows/discuss-phase-assumptions.md +1 -18
- package/get-shit-done/workflows/discuss-phase.md +10 -104
- package/get-shit-done/workflows/do.md +1 -5
- package/get-shit-done/workflows/execute-phase.md +53 -103
- package/get-shit-done/workflows/execute-plan.md +4 -4
- package/get-shit-done/workflows/health.md +2 -5
- package/get-shit-done/workflows/help.md +0 -165
- package/get-shit-done/workflows/new-milestone.md +0 -51
- package/get-shit-done/workflows/new-project.md +2 -63
- package/get-shit-done/workflows/next.md +0 -23
- package/get-shit-done/workflows/pause-work.md +7 -15
- package/get-shit-done/workflows/plan-phase.md +20 -304
- package/get-shit-done/workflows/pr-branch.md +0 -1
- package/get-shit-done/workflows/progress.md +1 -68
- package/get-shit-done/workflows/quick.md +0 -3
- package/get-shit-done/workflows/research-phase.md +0 -1
- package/get-shit-done/workflows/settings.md +1 -57
- package/get-shit-done/workflows/transition.md +3 -86
- package/get-shit-done/workflows/verify-work.md +0 -64
- package/package.json +1 -1
- package/scripts/build-hooks.js +0 -2
- package/sdk/prompts/agents/gsd-executor.md +2 -0
- package/sdk/prompts/agents/gsd-plan-checker.md +0 -3
- package/sdk/prompts/agents/gsd-roadmapper.md +0 -29
- package/sdk/src/config.ts +4 -5
- package/sdk/src/golden/golden-integration-covered.ts +0 -2
- package/sdk/src/golden/golden-policy.ts +1 -1
- package/sdk/src/golden/golden.integration.test.ts +0 -27
- package/sdk/src/golden/read-only-golden-rows.ts +0 -15
- package/sdk/src/query/QUERY-HANDLERS.md +3 -34
- package/sdk/src/query/claude-md.ts +421 -0
- package/sdk/src/query/commit.test.ts +155 -1
- package/sdk/src/query/commit.ts +71 -17
- package/sdk/src/query/config-gates.test.ts +1 -2
- package/sdk/src/query/config-gates.ts +1 -5
- package/sdk/src/query/config-mutation.test.ts +0 -1
- package/sdk/src/query/config-mutation.ts +5 -6
- package/sdk/src/query/config-query.test.ts +2 -2
- package/sdk/src/query/config-query.ts +12 -18
- package/sdk/src/query/decomposed-handlers.test.ts +0 -64
- package/sdk/src/query/index.ts +4 -68
- package/sdk/src/query/init.test.ts +0 -64
- package/sdk/src/query/init.ts +0 -189
- package/sdk/src/query/normalize-query-command.ts +0 -2
- package/sdk/src/query/profile.test.ts +0 -43
- package/sdk/src/query/profile.ts +1 -141
- package/sdk/src/query/state-mutation.ts +18 -0
- package/sdk/src/runtime-health.ts +3 -3
- package/agents/gsd-ai-researcher.md +0 -133
- package/agents/gsd-doc-classifier.md +0 -168
- package/agents/gsd-doc-synthesizer.md +0 -204
- package/agents/gsd-doc-verifier.md +0 -217
- package/agents/gsd-doc-writer.md +0 -615
- package/agents/gsd-domain-researcher.md +0 -153
- package/agents/gsd-eval-auditor.md +0 -191
- package/agents/gsd-eval-planner.md +0 -154
- package/agents/gsd-framework-selector.md +0 -160
- package/agents/gsd-intel-updater.md +0 -334
- package/agents/gsd-nyquist-auditor.md +0 -203
- package/agents/gsd-ui-auditor.md +0 -495
- package/agents/gsd-ui-checker.md +0 -309
- package/agents/gsd-ui-researcher.md +0 -380
- package/agents/gsd-user-profiler.md +0 -171
- package/commands/gsd/ai-integration-phase.md +0 -36
- package/commands/gsd/analyze-dependencies.md +0 -34
- package/commands/gsd/audit-fix.md +0 -33
- package/commands/gsd/audit-milestone.md +0 -36
- package/commands/gsd/audit-uat.md +0 -24
- package/commands/gsd/docs-update.md +0 -48
- package/commands/gsd/eval-review.md +0 -32
- package/commands/gsd/explore.md +0 -27
- package/commands/gsd/extract_learnings.md +0 -22
- package/commands/gsd/forensics.md +0 -56
- package/commands/gsd/from-gsd2.md +0 -47
- package/commands/gsd/graphify.md +0 -201
- package/commands/gsd/import.md +0 -37
- package/commands/gsd/inbox.md +0 -38
- package/commands/gsd/ingest-docs.md +0 -42
- package/commands/gsd/intel.md +0 -179
- package/commands/gsd/join-discord.md +0 -19
- package/commands/gsd/list-phase-assumptions.md +0 -46
- package/commands/gsd/list-workspaces.md +0 -19
- package/commands/gsd/manager.md +0 -40
- package/commands/gsd/milestone-summary.md +0 -51
- package/commands/gsd/new-workspace.md +0 -44
- package/commands/gsd/plan-milestone-gaps.md +0 -34
- package/commands/gsd/plan-review-convergence.md +0 -52
- package/commands/gsd/plant-seed.md +0 -28
- package/commands/gsd/profile-user.md +0 -46
- package/commands/gsd/reapply-patches.md +0 -331
- package/commands/gsd/remove-workspace.md +0 -26
- package/commands/gsd/review.md +0 -40
- package/commands/gsd/scan.md +0 -26
- package/commands/gsd/secure-phase.md +0 -35
- package/commands/gsd/session-report.md +0 -19
- package/commands/gsd/set-profile.md +0 -12
- package/commands/gsd/ship.md +0 -23
- package/commands/gsd/sketch-wrap-up.md +0 -31
- package/commands/gsd/sketch.md +0 -49
- package/commands/gsd/spec-phase.md +0 -62
- package/commands/gsd/spike-wrap-up.md +0 -31
- package/commands/gsd/spike.md +0 -46
- package/commands/gsd/stats.md +0 -18
- package/commands/gsd/sync-skills.md +0 -19
- package/commands/gsd/thread.md +0 -227
- package/commands/gsd/ui-phase.md +0 -34
- package/commands/gsd/ui-review.md +0 -32
- package/commands/gsd/ultraplan-phase.md +0 -33
- package/commands/gsd/update.md +0 -37
- package/commands/gsd/validate-phase.md +0 -35
- package/commands/gsd/workstreams.md +0 -69
- package/get-shit-done/bin/lib/docs.cjs +0 -267
- package/get-shit-done/bin/lib/graphify.cjs +0 -494
- package/get-shit-done/bin/lib/gsd2-import.cjs +0 -511
- package/get-shit-done/bin/lib/intel.cjs +0 -639
- package/get-shit-done/bin/lib/profile-output.cjs +0 -1080
- package/get-shit-done/bin/lib/profile-pipeline.cjs +0 -539
- package/get-shit-done/bin/lib/workstream.cjs +0 -495
- package/get-shit-done/references/ai-evals.md +0 -156
- package/get-shit-done/references/ai-frameworks.md +0 -186
- package/get-shit-done/references/doc-conflict-engine.md +0 -91
- package/get-shit-done/references/model-profile-resolution.md +0 -38
- package/get-shit-done/references/planner-reviews.md +0 -39
- package/get-shit-done/references/sketch-interactivity.md +0 -41
- package/get-shit-done/references/sketch-theme-system.md +0 -94
- package/get-shit-done/references/sketch-tooling.md +0 -45
- package/get-shit-done/references/sketch-variant-patterns.md +0 -81
- package/get-shit-done/references/thinking-models-debug.md +0 -44
- package/get-shit-done/references/thinking-models-execution.md +0 -50
- package/get-shit-done/references/thinking-models-planning.md +0 -62
- package/get-shit-done/references/thinking-models-research.md +0 -50
- package/get-shit-done/references/thinking-models-verification.md +0 -55
- package/get-shit-done/references/thinking-partner.md +0 -96
- package/get-shit-done/references/user-profiling.md +0 -681
- package/get-shit-done/references/workstream-flag.md +0 -111
- package/get-shit-done/templates/AI-SPEC.md +0 -246
- package/get-shit-done/templates/SECURITY.md +0 -61
- package/get-shit-done/templates/UI-SPEC.md +0 -100
- package/get-shit-done/templates/VALIDATION.md +0 -76
- package/get-shit-done/templates/dev-preferences.md +0 -21
- package/get-shit-done/templates/user-profile.md +0 -146
- package/get-shit-done/workflows/ai-integration-phase.md +0 -284
- package/get-shit-done/workflows/analyze-dependencies.md +0 -96
- package/get-shit-done/workflows/audit-fix.md +0 -175
- package/get-shit-done/workflows/audit-milestone.md +0 -340
- package/get-shit-done/workflows/audit-uat.md +0 -109
- package/get-shit-done/workflows/docs-update.md +0 -1155
- package/get-shit-done/workflows/eval-review.md +0 -155
- package/get-shit-done/workflows/explore.md +0 -141
- package/get-shit-done/workflows/extract_learnings.md +0 -242
- package/get-shit-done/workflows/forensics.md +0 -265
- package/get-shit-done/workflows/import.md +0 -246
- package/get-shit-done/workflows/inbox.md +0 -387
- package/get-shit-done/workflows/ingest-docs.md +0 -328
- package/get-shit-done/workflows/list-phase-assumptions.md +0 -178
- package/get-shit-done/workflows/list-workspaces.md +0 -56
- package/get-shit-done/workflows/manager.md +0 -365
- package/get-shit-done/workflows/milestone-summary.md +0 -223
- package/get-shit-done/workflows/new-workspace.md +0 -239
- package/get-shit-done/workflows/plan-milestone-gaps.md +0 -273
- package/get-shit-done/workflows/plan-review-convergence.md +0 -254
- package/get-shit-done/workflows/plant-seed.md +0 -172
- package/get-shit-done/workflows/profile-user.md +0 -452
- package/get-shit-done/workflows/remove-workspace.md +0 -92
- package/get-shit-done/workflows/review.md +0 -344
- package/get-shit-done/workflows/scan.md +0 -102
- package/get-shit-done/workflows/secure-phase.md +0 -166
- package/get-shit-done/workflows/session-report.md +0 -146
- package/get-shit-done/workflows/ship.md +0 -302
- package/get-shit-done/workflows/sketch-wrap-up.md +0 -283
- package/get-shit-done/workflows/sketch.md +0 -286
- package/get-shit-done/workflows/spec-phase.md +0 -262
- package/get-shit-done/workflows/spike-wrap-up.md +0 -281
- package/get-shit-done/workflows/spike.md +0 -362
- package/get-shit-done/workflows/stats.md +0 -60
- package/get-shit-done/workflows/sync-skills.md +0 -182
- package/get-shit-done/workflows/ui-phase.md +0 -323
- package/get-shit-done/workflows/ui-review.md +0 -190
- package/get-shit-done/workflows/ultraplan-phase.md +0 -189
- package/get-shit-done/workflows/update.md +0 -587
- package/get-shit-done/workflows/validate-phase.md +0 -176
- package/hooks/dist/gsd-check-update-worker.js +0 -108
- package/hooks/dist/gsd-check-update.js +0 -63
- package/hooks/gsd-check-update-worker.js +0 -108
- package/hooks/gsd-check-update.js +0 -63
- package/sdk/src/golden/fixtures/profile-sample-sessions/demo-project/sample.jsonl +0 -3
- package/sdk/src/query/docs-init.ts +0 -257
- package/sdk/src/query/intel.test.ts +0 -90
- package/sdk/src/query/intel.ts +0 -404
- package/sdk/src/query/profile-extract-messages.ts +0 -247
- package/sdk/src/query/profile-output.ts +0 -908
- package/sdk/src/query/profile-questionnaire-data.ts +0 -181
- package/sdk/src/query/profile-sample.ts +0 -184
- package/sdk/src/query/profile-scan-sessions.ts +0 -174
- package/sdk/src/query/workspace.test.ts +0 -119
- package/sdk/src/query/workspace.ts +0 -131
- package/sdk/src/query/workstream.test.ts +0 -51
- package/sdk/src/query/workstream.ts +0 -434
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claude-md.cjs — CLAUDE.md generation (managed sections).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from profile-output.cjs when the profiling pipeline was removed.
|
|
5
|
+
* Provides:
|
|
6
|
+
* - generate-claude-md: full CLAUDE.md with managed sections
|
|
7
|
+
* (project, stack, conventions, architecture, skills, workflow enforcement)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const { output, safeReadFile, loadConfig } = require('./core.cjs');
|
|
15
|
+
|
|
16
|
+
const CLAUDE_MD_FALLBACKS = {
|
|
17
|
+
project: 'Project not yet initialized. Run /gsd-new-project to set up.',
|
|
18
|
+
stack: 'Technology stack not yet documented. Will populate after codebase mapping or first phase.',
|
|
19
|
+
conventions: 'Conventions not yet established. Will populate as patterns emerge during development.',
|
|
20
|
+
architecture: 'Architecture not yet mapped. Follow existing patterns found in the codebase.',
|
|
21
|
+
skills: 'No project skills found. Add skills to any of: `.claude/skills/`, `.agents/skills/`, `.cursor/skills/`, `.github/skills/`, or `.codex/skills/` with a `SKILL.md` index file.',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Directories where project skills may live (checked in order)
|
|
25
|
+
const SKILL_SEARCH_DIRS = ['.claude/skills', '.agents/skills', '.cursor/skills', '.github/skills', '.codex/skills'];
|
|
26
|
+
|
|
27
|
+
const CLAUDE_MD_WORKFLOW_ENFORCEMENT = [
|
|
28
|
+
'Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.',
|
|
29
|
+
'',
|
|
30
|
+
'Use these entry points:',
|
|
31
|
+
'- `/gsd-quick` for small fixes, doc updates, and ad-hoc tasks',
|
|
32
|
+
'- `/gsd-debug` for investigation and bug fixing',
|
|
33
|
+
'- `/gsd-execute-phase` for planned phase work',
|
|
34
|
+
'',
|
|
35
|
+
'Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.',
|
|
36
|
+
].join('\n');
|
|
37
|
+
|
|
38
|
+
// ─── Helper Functions ─────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
function extractSectionContent(fileContent, sectionName) {
|
|
41
|
+
const startMarker = `<!-- GSD:${sectionName}-start`;
|
|
42
|
+
const endMarker = `<!-- GSD:${sectionName}-end -->`;
|
|
43
|
+
const startIdx = fileContent.indexOf(startMarker);
|
|
44
|
+
const endIdx = fileContent.indexOf(endMarker);
|
|
45
|
+
if (startIdx === -1 || endIdx === -1) return null;
|
|
46
|
+
const startTagEnd = fileContent.indexOf('-->', startIdx);
|
|
47
|
+
if (startTagEnd === -1) return null;
|
|
48
|
+
return fileContent.substring(startTagEnd + 3, endIdx);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildSection(sectionName, sourceFile, content) {
|
|
52
|
+
return [
|
|
53
|
+
`<!-- GSD:${sectionName}-start source:${sourceFile} -->`,
|
|
54
|
+
content,
|
|
55
|
+
`<!-- GSD:${sectionName}-end -->`,
|
|
56
|
+
].join('\n');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function updateSection(fileContent, sectionName, newContent) {
|
|
60
|
+
const startMarker = `<!-- GSD:${sectionName}-start`;
|
|
61
|
+
const endMarker = `<!-- GSD:${sectionName}-end -->`;
|
|
62
|
+
const startIdx = fileContent.indexOf(startMarker);
|
|
63
|
+
const endIdx = fileContent.indexOf(endMarker);
|
|
64
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
65
|
+
const before = fileContent.substring(0, startIdx);
|
|
66
|
+
const after = fileContent.substring(endIdx + endMarker.length);
|
|
67
|
+
return { content: before + newContent + after, action: 'replaced' };
|
|
68
|
+
}
|
|
69
|
+
return { content: fileContent.trimEnd() + '\n\n' + newContent + '\n', action: 'appended' };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function detectManualEdit(fileContent, sectionName, expectedContent) {
|
|
73
|
+
const currentContent = extractSectionContent(fileContent, sectionName);
|
|
74
|
+
if (currentContent === null) return false;
|
|
75
|
+
const normalize = (s) => s.trim().replace(/\n{3,}/g, '\n\n');
|
|
76
|
+
return normalize(currentContent) !== normalize(expectedContent);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function extractMarkdownSection(content, sectionName) {
|
|
80
|
+
if (!content) return null;
|
|
81
|
+
const lines = content.split('\n');
|
|
82
|
+
let capturing = false;
|
|
83
|
+
const result = [];
|
|
84
|
+
const headingPattern = new RegExp(`^## ${sectionName}\\s*$`);
|
|
85
|
+
for (const line of lines) {
|
|
86
|
+
if (headingPattern.test(line)) {
|
|
87
|
+
capturing = true;
|
|
88
|
+
result.push(line);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (capturing && /^## /.test(line)) break;
|
|
92
|
+
if (capturing) result.push(line);
|
|
93
|
+
}
|
|
94
|
+
return result.length > 0 ? result.join('\n').trim() : null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ─── CLAUDE.md Section Generators ─────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
function generateProjectSection(cwd) {
|
|
100
|
+
const projectPath = path.join(cwd, '.planning', 'PROJECT.md');
|
|
101
|
+
const content = safeReadFile(projectPath);
|
|
102
|
+
if (!content) {
|
|
103
|
+
return { content: CLAUDE_MD_FALLBACKS.project, source: 'PROJECT.md', linkPath: null, hasFallback: true };
|
|
104
|
+
}
|
|
105
|
+
const parts = [];
|
|
106
|
+
const h1Match = content.match(/^# (.+)$/m);
|
|
107
|
+
if (h1Match) parts.push(`**${h1Match[1]}**`);
|
|
108
|
+
const whatThisIs = extractMarkdownSection(content, 'What This Is');
|
|
109
|
+
if (whatThisIs) {
|
|
110
|
+
const body = whatThisIs.replace(/^## What This Is\s*/i, '').trim();
|
|
111
|
+
if (body) parts.push(body);
|
|
112
|
+
}
|
|
113
|
+
const coreValue = extractMarkdownSection(content, 'Core Value');
|
|
114
|
+
if (coreValue) {
|
|
115
|
+
const body = coreValue.replace(/^## Core Value\s*/i, '').trim();
|
|
116
|
+
if (body) parts.push(`**Core Value:** ${body}`);
|
|
117
|
+
}
|
|
118
|
+
const constraints = extractMarkdownSection(content, 'Constraints');
|
|
119
|
+
if (constraints) {
|
|
120
|
+
const body = constraints.replace(/^## Constraints\s*/i, '').trim();
|
|
121
|
+
if (body) parts.push(`### Constraints\n\n${body}`);
|
|
122
|
+
}
|
|
123
|
+
if (parts.length === 0) {
|
|
124
|
+
return { content: CLAUDE_MD_FALLBACKS.project, source: 'PROJECT.md', linkPath: null, hasFallback: true };
|
|
125
|
+
}
|
|
126
|
+
return { content: parts.join('\n\n'), source: 'PROJECT.md', linkPath: '.planning/PROJECT.md', hasFallback: false };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function generateStackSection(cwd) {
|
|
130
|
+
const codebasePath = path.join(cwd, '.planning', 'codebase', 'STACK.md');
|
|
131
|
+
const researchPath = path.join(cwd, '.planning', 'research', 'STACK.md');
|
|
132
|
+
let content = safeReadFile(codebasePath);
|
|
133
|
+
let source = 'codebase/STACK.md';
|
|
134
|
+
let linkPath = '.planning/codebase/STACK.md';
|
|
135
|
+
if (!content) {
|
|
136
|
+
content = safeReadFile(researchPath);
|
|
137
|
+
source = 'research/STACK.md';
|
|
138
|
+
linkPath = '.planning/research/STACK.md';
|
|
139
|
+
}
|
|
140
|
+
if (!content) {
|
|
141
|
+
return { content: CLAUDE_MD_FALLBACKS.stack, source: 'STACK.md', linkPath: null, hasFallback: true };
|
|
142
|
+
}
|
|
143
|
+
const lines = content.split('\n');
|
|
144
|
+
const summaryLines = [];
|
|
145
|
+
let inTable = false;
|
|
146
|
+
for (const line of lines) {
|
|
147
|
+
if (line.startsWith('#')) {
|
|
148
|
+
if (!line.startsWith('# ') || summaryLines.length > 0) summaryLines.push(line);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (line.startsWith('|')) { inTable = true; summaryLines.push(line); continue; }
|
|
152
|
+
if (inTable && line.trim() === '') inTable = false;
|
|
153
|
+
if (line.startsWith('- ') || line.startsWith('* ')) summaryLines.push(line);
|
|
154
|
+
}
|
|
155
|
+
const summary = summaryLines.length > 0 ? summaryLines.join('\n') : content.trim();
|
|
156
|
+
return { content: summary, source, linkPath, hasFallback: false };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function generateConventionsSection(cwd) {
|
|
160
|
+
const conventionsPath = path.join(cwd, '.planning', 'codebase', 'CONVENTIONS.md');
|
|
161
|
+
const content = safeReadFile(conventionsPath);
|
|
162
|
+
if (!content) {
|
|
163
|
+
return { content: CLAUDE_MD_FALLBACKS.conventions, source: 'CONVENTIONS.md', linkPath: null, hasFallback: true };
|
|
164
|
+
}
|
|
165
|
+
const lines = content.split('\n');
|
|
166
|
+
const summaryLines = [];
|
|
167
|
+
for (const line of lines) {
|
|
168
|
+
if (line.startsWith('#')) { if (!line.startsWith('# ')) summaryLines.push(line); continue; }
|
|
169
|
+
if (line.startsWith('- ') || line.startsWith('* ') || line.startsWith('|')) summaryLines.push(line);
|
|
170
|
+
}
|
|
171
|
+
const summary = summaryLines.length > 0 ? summaryLines.join('\n') : content.trim();
|
|
172
|
+
return { content: summary, source: 'CONVENTIONS.md', linkPath: '.planning/codebase/CONVENTIONS.md', hasFallback: false };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function generateArchitectureSection(cwd) {
|
|
176
|
+
const architecturePath = path.join(cwd, '.planning', 'codebase', 'ARCHITECTURE.md');
|
|
177
|
+
const content = safeReadFile(architecturePath);
|
|
178
|
+
if (!content) {
|
|
179
|
+
return { content: CLAUDE_MD_FALLBACKS.architecture, source: 'ARCHITECTURE.md', linkPath: null, hasFallback: true };
|
|
180
|
+
}
|
|
181
|
+
const lines = content.split('\n');
|
|
182
|
+
const summaryLines = [];
|
|
183
|
+
for (const line of lines) {
|
|
184
|
+
if (line.startsWith('#')) { if (!line.startsWith('# ')) summaryLines.push(line); continue; }
|
|
185
|
+
if (line.startsWith('- ') || line.startsWith('* ') || line.startsWith('|') || line.startsWith('```')) summaryLines.push(line);
|
|
186
|
+
}
|
|
187
|
+
const summary = summaryLines.length > 0 ? summaryLines.join('\n') : content.trim();
|
|
188
|
+
return { content: summary, source: 'ARCHITECTURE.md', linkPath: '.planning/codebase/ARCHITECTURE.md', hasFallback: false };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function generateWorkflowSection() {
|
|
192
|
+
return {
|
|
193
|
+
content: CLAUDE_MD_WORKFLOW_ENFORCEMENT,
|
|
194
|
+
source: 'GSD defaults',
|
|
195
|
+
linkPath: null,
|
|
196
|
+
hasFallback: false,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Discover project skills from standard directories and extract frontmatter
|
|
202
|
+
* (name + description) for each. Returns a table summary for CLAUDE.md so
|
|
203
|
+
* agents know which skills are available at session startup (Layer 1 discovery).
|
|
204
|
+
*/
|
|
205
|
+
function generateSkillsSection(cwd) {
|
|
206
|
+
const discovered = [];
|
|
207
|
+
|
|
208
|
+
for (const dir of SKILL_SEARCH_DIRS) {
|
|
209
|
+
const absDir = path.join(cwd, dir);
|
|
210
|
+
if (!fs.existsSync(absDir)) continue;
|
|
211
|
+
|
|
212
|
+
let entries;
|
|
213
|
+
try {
|
|
214
|
+
entries = fs.readdirSync(absDir, { withFileTypes: true });
|
|
215
|
+
} catch {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (const entry of entries) {
|
|
220
|
+
if (!entry.isDirectory()) continue;
|
|
221
|
+
// Skip GSD's own installed skills — only surface project-specific skills
|
|
222
|
+
if (entry.name.startsWith('gsd-')) continue;
|
|
223
|
+
|
|
224
|
+
const skillMdPath = path.join(absDir, entry.name, 'SKILL.md');
|
|
225
|
+
if (!fs.existsSync(skillMdPath)) continue;
|
|
226
|
+
|
|
227
|
+
const content = safeReadFile(skillMdPath);
|
|
228
|
+
if (!content) continue;
|
|
229
|
+
|
|
230
|
+
const frontmatter = extractSkillFrontmatter(content);
|
|
231
|
+
const name = frontmatter.name || entry.name;
|
|
232
|
+
const description = frontmatter.description || '';
|
|
233
|
+
|
|
234
|
+
// Avoid duplicates when same skill dir is symlinked from multiple locations
|
|
235
|
+
if (discovered.some(s => s.name === name)) continue;
|
|
236
|
+
|
|
237
|
+
discovered.push({ name, description, path: `${dir}/${entry.name}` });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (discovered.length === 0) {
|
|
242
|
+
return { content: CLAUDE_MD_FALLBACKS.skills, source: 'skills/', hasFallback: true };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const lines = ['| Skill | Description | Path |', '|-------|-------------|------|'];
|
|
246
|
+
for (const skill of discovered) {
|
|
247
|
+
// Sanitize table cell content (escape pipes)
|
|
248
|
+
const desc = skill.description.replace(/\|/g, '\\|').replace(/\n/g, ' ').trim();
|
|
249
|
+
const safeName = skill.name.replace(/\|/g, '\\|');
|
|
250
|
+
lines.push(`| ${safeName} | ${desc} | \`${skill.path}/SKILL.md\` |`);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return { content: lines.join('\n'), source: 'skills/', hasFallback: false };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Extract name and description from YAML-like frontmatter in a SKILL.md file.
|
|
258
|
+
* Handles multi-line description values (continuation lines indented with spaces).
|
|
259
|
+
*/
|
|
260
|
+
function extractSkillFrontmatter(content) {
|
|
261
|
+
const result = { name: '', description: '' };
|
|
262
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
263
|
+
if (!fmMatch) return result;
|
|
264
|
+
|
|
265
|
+
const fmBlock = fmMatch[1];
|
|
266
|
+
const lines = fmBlock.split('\n');
|
|
267
|
+
|
|
268
|
+
let currentKey = '';
|
|
269
|
+
for (const line of lines) {
|
|
270
|
+
// Top-level key: value
|
|
271
|
+
const kvMatch = line.match(/^(\w[\w-]*):\s*(.*)/);
|
|
272
|
+
if (kvMatch) {
|
|
273
|
+
currentKey = kvMatch[1];
|
|
274
|
+
const value = kvMatch[2].trim();
|
|
275
|
+
if (currentKey === 'name') result.name = value;
|
|
276
|
+
if (currentKey === 'description') result.description = value;
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
// Continuation line (indented) for multi-line values
|
|
280
|
+
if (currentKey === 'description' && /^\s+/.test(line)) {
|
|
281
|
+
result.description += ' ' + line.trim();
|
|
282
|
+
} else {
|
|
283
|
+
currentKey = '';
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ─── Commands ─────────────────────────────────────────────────────────────────
|
|
291
|
+
|
|
292
|
+
function cmdGenerateClaudeMd(cwd, options, raw) {
|
|
293
|
+
const MANAGED_SECTIONS = ['project', 'stack', 'conventions', 'architecture', 'skills', 'workflow'];
|
|
294
|
+
const generators = {
|
|
295
|
+
project: generateProjectSection,
|
|
296
|
+
stack: generateStackSection,
|
|
297
|
+
conventions: generateConventionsSection,
|
|
298
|
+
architecture: generateArchitectureSection,
|
|
299
|
+
skills: generateSkillsSection,
|
|
300
|
+
workflow: generateWorkflowSection,
|
|
301
|
+
};
|
|
302
|
+
const sectionHeadings = {
|
|
303
|
+
project: '## Project',
|
|
304
|
+
stack: '## Technology Stack',
|
|
305
|
+
conventions: '## Conventions',
|
|
306
|
+
architecture: '## Architecture',
|
|
307
|
+
skills: '## Project Skills',
|
|
308
|
+
workflow: '## GSD Workflow Enforcement',
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const generated = {};
|
|
312
|
+
const sectionsGenerated = [];
|
|
313
|
+
const sectionsFallback = [];
|
|
314
|
+
const sectionsSkipped = [];
|
|
315
|
+
|
|
316
|
+
for (const name of MANAGED_SECTIONS) {
|
|
317
|
+
const gen = generators[name](cwd);
|
|
318
|
+
generated[name] = gen;
|
|
319
|
+
if (gen.hasFallback) {
|
|
320
|
+
sectionsFallback.push(name);
|
|
321
|
+
} else {
|
|
322
|
+
sectionsGenerated.push(name);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
let assemblyConfig = {};
|
|
327
|
+
let configClaudeMdPath = './CLAUDE.md';
|
|
328
|
+
try {
|
|
329
|
+
const config = loadConfig(cwd);
|
|
330
|
+
if (config.claude_md_path) configClaudeMdPath = config.claude_md_path;
|
|
331
|
+
if (config.claude_md_assembly) assemblyConfig = config.claude_md_assembly;
|
|
332
|
+
} catch { /* use default */ }
|
|
333
|
+
|
|
334
|
+
let outputPath = options.output;
|
|
335
|
+
if (!outputPath) {
|
|
336
|
+
outputPath = path.isAbsolute(configClaudeMdPath) ? configClaudeMdPath : path.join(cwd, configClaudeMdPath);
|
|
337
|
+
} else if (!path.isAbsolute(outputPath)) {
|
|
338
|
+
outputPath = path.join(cwd, outputPath);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const globalAssemblyMode = assemblyConfig.mode || 'embed';
|
|
342
|
+
const blockModes = assemblyConfig.blocks || {};
|
|
343
|
+
|
|
344
|
+
// Return the assembled content for a section, respecting link vs embed mode.
|
|
345
|
+
// "link" mode writes `@<linkPath>` when the generator has a real source file.
|
|
346
|
+
// Falls back to "embed" for sections without a linkable source (workflow, fallbacks).
|
|
347
|
+
function buildSectionContent(name, gen, heading) {
|
|
348
|
+
const effectiveMode = blockModes[name] || globalAssemblyMode;
|
|
349
|
+
if (effectiveMode === 'link' && gen.linkPath && !gen.hasFallback) {
|
|
350
|
+
return buildSection(name, gen.source, `${heading}\n\n@${gen.linkPath}`);
|
|
351
|
+
}
|
|
352
|
+
return buildSection(name, gen.source, `${heading}\n\n${gen.content}`);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
let existingContent = safeReadFile(outputPath);
|
|
356
|
+
let action;
|
|
357
|
+
|
|
358
|
+
if (existingContent === null) {
|
|
359
|
+
const sections = [];
|
|
360
|
+
for (const name of MANAGED_SECTIONS) {
|
|
361
|
+
const gen = generated[name];
|
|
362
|
+
const heading = sectionHeadings[name];
|
|
363
|
+
sections.push(buildSectionContent(name, gen, heading));
|
|
364
|
+
}
|
|
365
|
+
existingContent = sections.join('\n\n') + '\n';
|
|
366
|
+
action = 'created';
|
|
367
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
368
|
+
fs.writeFileSync(outputPath, existingContent, 'utf-8');
|
|
369
|
+
} else {
|
|
370
|
+
action = 'updated';
|
|
371
|
+
let fileContent = existingContent;
|
|
372
|
+
|
|
373
|
+
for (const name of MANAGED_SECTIONS) {
|
|
374
|
+
const gen = generated[name];
|
|
375
|
+
const heading = sectionHeadings[name];
|
|
376
|
+
const fullSection = buildSectionContent(name, gen, heading);
|
|
377
|
+
const hasMarkers = fileContent.indexOf(`<!-- GSD:${name}-start`) !== -1;
|
|
378
|
+
|
|
379
|
+
if (hasMarkers) {
|
|
380
|
+
if (options.auto) {
|
|
381
|
+
const effectiveMode = blockModes[name] || globalAssemblyMode;
|
|
382
|
+
const expectedBody = (effectiveMode === 'link' && gen.linkPath && !gen.hasFallback)
|
|
383
|
+
? `${heading}\n\n@${gen.linkPath}`
|
|
384
|
+
: `${heading}\n\n${gen.content}`;
|
|
385
|
+
if (detectManualEdit(fileContent, name, expectedBody)) {
|
|
386
|
+
sectionsSkipped.push(name);
|
|
387
|
+
const genIdx = sectionsGenerated.indexOf(name);
|
|
388
|
+
if (genIdx !== -1) sectionsGenerated.splice(genIdx, 1);
|
|
389
|
+
const fbIdx = sectionsFallback.indexOf(name);
|
|
390
|
+
if (fbIdx !== -1) sectionsFallback.splice(fbIdx, 1);
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const result = updateSection(fileContent, name, fullSection);
|
|
395
|
+
fileContent = result.content;
|
|
396
|
+
} else {
|
|
397
|
+
const result = updateSection(fileContent, name, fullSection);
|
|
398
|
+
fileContent = result.content;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
fs.writeFileSync(outputPath, fileContent, 'utf-8');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const genCount = sectionsGenerated.length;
|
|
407
|
+
const totalManaged = MANAGED_SECTIONS.length;
|
|
408
|
+
let message = `Generated ${genCount}/${totalManaged} sections.`;
|
|
409
|
+
if (sectionsFallback.length > 0) message += ` Fallback: ${sectionsFallback.join(', ')}.`;
|
|
410
|
+
if (sectionsSkipped.length > 0) message += ` Skipped (manually edited): ${sectionsSkipped.join(', ')}.`;
|
|
411
|
+
|
|
412
|
+
const result = {
|
|
413
|
+
claude_md_path: outputPath,
|
|
414
|
+
action,
|
|
415
|
+
sections_generated: sectionsGenerated,
|
|
416
|
+
sections_fallback: sectionsFallback,
|
|
417
|
+
sections_skipped: sectionsSkipped,
|
|
418
|
+
sections_total: totalManaged,
|
|
419
|
+
message,
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
output(result, raw);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
module.exports = {
|
|
426
|
+
cmdGenerateClaudeMd,
|
|
427
|
+
};
|
|
@@ -17,7 +17,7 @@ const VALID_CONFIG_KEYS = new Set([
|
|
|
17
17
|
'mode', 'granularity', 'parallelization', 'commit_docs', 'model_profile',
|
|
18
18
|
'search_gitignored', 'brave_search', 'firecrawl', 'exa_search',
|
|
19
19
|
'workflow.research', 'workflow.plan_check', 'workflow.verifier',
|
|
20
|
-
'workflow.nyquist_validation', 'workflow.ai_integration_phase',
|
|
20
|
+
'workflow.nyquist_validation', 'workflow.ai_integration_phase',
|
|
21
21
|
'workflow.auto_advance', 'workflow.node_repair', 'workflow.node_repair_budget',
|
|
22
22
|
'workflow.tdd_mode',
|
|
23
23
|
'workflow.text_mode',
|
|
@@ -29,21 +29,14 @@ const VALID_CONFIG_KEYS = new Set([
|
|
|
29
29
|
'workflow.use_worktrees',
|
|
30
30
|
'workflow.code_review',
|
|
31
31
|
'workflow.code_review_depth',
|
|
32
|
-
'workflow.code_review_command',
|
|
33
32
|
'workflow.pattern_mapper',
|
|
34
|
-
'workflow.plan_bounce',
|
|
35
|
-
'workflow.plan_bounce_script',
|
|
36
|
-
'workflow.plan_bounce_passes',
|
|
37
33
|
'workflow.security_enforcement',
|
|
38
|
-
'workflow.
|
|
39
|
-
'workflow.security_block_on',
|
|
34
|
+
'workflow.security_review',
|
|
40
35
|
'git.branching_strategy', 'git.base_branch', 'git.phase_branch_template', 'git.milestone_branch_template', 'git.quick_branch_template',
|
|
41
36
|
'planning.commit_docs', 'planning.search_gitignored', 'planning.sub_repos',
|
|
42
|
-
'workflow.cross_ai_execution', 'workflow.cross_ai_command', 'workflow.cross_ai_timeout',
|
|
43
37
|
'workflow.subagent_timeout',
|
|
44
38
|
'workflow.inline_plan_threshold',
|
|
45
39
|
'hooks.context_warnings',
|
|
46
|
-
'features.thinking_partner',
|
|
47
40
|
'context',
|
|
48
41
|
'features.global_learnings',
|
|
49
42
|
'learnings.max_inject',
|
|
@@ -51,8 +44,6 @@ const VALID_CONFIG_KEYS = new Set([
|
|
|
51
44
|
'manager.flags.discuss', 'manager.flags.plan', 'manager.flags.execute',
|
|
52
45
|
'response_language',
|
|
53
46
|
'intel.enabled',
|
|
54
|
-
'graphify.enabled',
|
|
55
|
-
'graphify.build_timeout',
|
|
56
47
|
'claude_md_path',
|
|
57
48
|
'claude_md_assembly.mode',
|
|
58
49
|
]);
|
|
@@ -63,7 +54,6 @@ const VALID_CONFIG_KEYS = new Set([
|
|
|
63
54
|
*/
|
|
64
55
|
const DYNAMIC_KEY_PATTERNS = [
|
|
65
56
|
{ test: (k) => /^agent_skills\.[a-zA-Z0-9_-]+$/.test(k), description: 'agent_skills.<agent-type>' },
|
|
66
|
-
{ test: (k) => /^review\.models\.[a-zA-Z0-9_-]+$/.test(k), description: 'review.models.<cli-name>' },
|
|
67
57
|
{ test: (k) => /^features\.[a-zA-Z0-9_]+$/.test(k), description: 'features.<feature_name>' },
|
|
68
58
|
{ test: (k) => /^claude_md_assembly\.blocks\.[a-zA-Z0-9_]+$/.test(k), description: 'claude_md_assembly.blocks.<section>' },
|
|
69
59
|
];
|
|
@@ -19,11 +19,9 @@ const CONFIG_KEY_SUGGESTIONS = {
|
|
|
19
19
|
'hooks.research_questions': 'workflow.research_before_questions',
|
|
20
20
|
'workflow.research_questions': 'workflow.research_before_questions',
|
|
21
21
|
'workflow.codereview': 'workflow.code_review',
|
|
22
|
-
'workflow.review_command': 'workflow.code_review_command',
|
|
23
22
|
'workflow.review': 'workflow.code_review',
|
|
24
23
|
'workflow.code_review_level': 'workflow.code_review_depth',
|
|
25
24
|
'workflow.review_depth': 'workflow.code_review_depth',
|
|
26
|
-
'review.model': 'review.models.<cli-name>',
|
|
27
25
|
};
|
|
28
26
|
|
|
29
27
|
function validateKnownConfigKeyPath(keyPath) {
|
|
@@ -97,13 +95,11 @@ function buildNewProjectConfig(userChoices) {
|
|
|
97
95
|
research: true,
|
|
98
96
|
plan_check: true,
|
|
99
97
|
verifier: true,
|
|
100
|
-
nyquist_validation:
|
|
98
|
+
nyquist_validation: false,
|
|
101
99
|
auto_advance: false,
|
|
102
100
|
node_repair: true,
|
|
103
101
|
node_repair_budget: 2,
|
|
104
|
-
|
|
105
|
-
ui_safety_gate: true,
|
|
106
|
-
ai_integration_phase: true,
|
|
102
|
+
ai_integration_phase: false,
|
|
107
103
|
tdd_mode: false,
|
|
108
104
|
text_mode: false,
|
|
109
105
|
research_before_questions: false,
|
|
@@ -111,15 +107,10 @@ function buildNewProjectConfig(userChoices) {
|
|
|
111
107
|
skip_discuss: false,
|
|
112
108
|
code_review: true,
|
|
113
109
|
code_review_depth: 'standard',
|
|
114
|
-
code_review_command: null,
|
|
115
110
|
pattern_mapper: true,
|
|
116
|
-
plan_bounce: false,
|
|
117
|
-
plan_bounce_script: null,
|
|
118
|
-
plan_bounce_passes: 2,
|
|
119
111
|
auto_prune_state: false,
|
|
120
112
|
security_enforcement: CONFIG_DEFAULTS.security_enforcement,
|
|
121
|
-
|
|
122
|
-
security_block_on: CONFIG_DEFAULTS.security_block_on,
|
|
113
|
+
security_review: CONFIG_DEFAULTS.security_review,
|
|
123
114
|
},
|
|
124
115
|
hooks: {
|
|
125
116
|
context_warnings: true,
|
|
@@ -250,8 +250,8 @@ const CONFIG_DEFAULTS = {
|
|
|
250
250
|
research: true,
|
|
251
251
|
plan_checker: true,
|
|
252
252
|
verifier: true,
|
|
253
|
-
nyquist_validation:
|
|
254
|
-
ai_integration_phase:
|
|
253
|
+
nyquist_validation: false,
|
|
254
|
+
ai_integration_phase: false,
|
|
255
255
|
parallelization: true,
|
|
256
256
|
brave_search: false,
|
|
257
257
|
firecrawl: false,
|
|
@@ -263,9 +263,8 @@ const CONFIG_DEFAULTS = {
|
|
|
263
263
|
phase_naming: 'sequential', // 'sequential' (default, auto-increment) or 'custom' (arbitrary string IDs)
|
|
264
264
|
project_code: null, // optional short prefix for phase dirs (e.g., 'CK' → 'CK-01-foundation')
|
|
265
265
|
subagent_timeout: 300000, // 5 min default; increase for large codebases or slower models (ms)
|
|
266
|
-
security_enforcement:
|
|
267
|
-
|
|
268
|
-
security_block_on: 'high', // workflow.security_block_on — minimum severity that blocks phase advancement ('high' | 'medium' | 'low')
|
|
266
|
+
security_enforcement: false, // workflow.security_enforcement — threat-model-anchored security verification (legacy; superseded by security_review)
|
|
267
|
+
security_review: 'auto', // workflow.security_review — diff-scoped security review trigger ('auto' | 'always' | 'off')
|
|
269
268
|
};
|
|
270
269
|
|
|
271
270
|
function loadConfig(cwd) {
|