gsdd-cli 0.2.0 → 0.16.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.
Files changed (43) hide show
  1. package/README.md +67 -34
  2. package/agents/DISTILLATION.md +15 -13
  3. package/agents/planner.md +2 -0
  4. package/bin/adapters/agents.mjs +1 -0
  5. package/bin/adapters/claude.mjs +12 -3
  6. package/bin/adapters/codex.mjs +4 -0
  7. package/bin/adapters/opencode.mjs +13 -4
  8. package/bin/gsdd.mjs +64 -39
  9. package/bin/lib/cli-utils.mjs +1 -1
  10. package/bin/lib/file-ops.mjs +161 -0
  11. package/bin/lib/health-truth.mjs +188 -0
  12. package/bin/lib/health.mjs +65 -12
  13. package/bin/lib/init-flow.mjs +267 -0
  14. package/bin/lib/init-prompts.mjs +247 -0
  15. package/bin/lib/init-runtime.mjs +226 -0
  16. package/bin/lib/init.mjs +19 -378
  17. package/bin/lib/models.mjs +19 -4
  18. package/bin/lib/phase.mjs +100 -14
  19. package/bin/lib/plan-constants.mjs +30 -0
  20. package/bin/lib/provenance.mjs +146 -0
  21. package/bin/lib/templates.mjs +17 -0
  22. package/distilled/DESIGN.md +625 -41
  23. package/distilled/EVIDENCE-INDEX.md +297 -0
  24. package/distilled/README.md +49 -21
  25. package/distilled/SKILL.md +89 -85
  26. package/distilled/templates/agents.block.md +13 -82
  27. package/distilled/templates/agents.md +0 -7
  28. package/distilled/templates/delegates/plan-checker.md +11 -4
  29. package/distilled/workflows/audit-milestone.md +7 -5
  30. package/distilled/workflows/complete-milestone.md +297 -0
  31. package/distilled/workflows/execute.md +188 -19
  32. package/distilled/workflows/map-codebase.md +14 -7
  33. package/distilled/workflows/new-milestone.md +249 -0
  34. package/distilled/workflows/new-project.md +28 -24
  35. package/distilled/workflows/pause.md +42 -6
  36. package/distilled/workflows/plan-milestone-gaps.md +183 -0
  37. package/distilled/workflows/plan.md +78 -13
  38. package/distilled/workflows/progress.md +42 -19
  39. package/distilled/workflows/quick.md +171 -8
  40. package/distilled/workflows/resume.md +121 -11
  41. package/distilled/workflows/verify-work.md +260 -0
  42. package/distilled/workflows/verify.md +124 -33
  43. package/package.json +9 -7
@@ -0,0 +1,226 @@
1
+ const RUNTIME_OPTIONS = [
2
+ {
3
+ id: 'claude',
4
+ label: 'Claude Code',
5
+ description: 'Directly validated native skills, commands, and agents',
6
+ kind: 'native',
7
+ },
8
+ {
9
+ id: 'opencode',
10
+ label: 'OpenCode',
11
+ description: 'Directly validated native slash commands and agents',
12
+ kind: 'native',
13
+ },
14
+ {
15
+ id: 'codex',
16
+ label: 'Codex CLI',
17
+ description: 'Directly validated portable skills plus native checker agents',
18
+ kind: 'native',
19
+ },
20
+ {
21
+ id: 'cursor',
22
+ label: 'Cursor',
23
+ description: 'Qualified support via skills-native slash commands from .agents/skills/',
24
+ kind: 'skills_native',
25
+ },
26
+ {
27
+ id: 'copilot',
28
+ label: 'GitHub Copilot',
29
+ description: 'Qualified support via skills-native slash commands from .agents/skills/',
30
+ kind: 'skills_native',
31
+ },
32
+ {
33
+ id: 'gemini',
34
+ label: 'Gemini CLI',
35
+ description: 'Qualified support via skills-native slash commands from .agents/skills/',
36
+ kind: 'skills_native',
37
+ },
38
+ ];
39
+
40
+ export const INIT_VERSION = 'v1.1';
41
+
42
+ export function normalizeRequestedTools(requestedTools) {
43
+ const selectedRuntimes = [];
44
+ const adapterTargets = [];
45
+ const addRuntime = (runtime) => {
46
+ if (!selectedRuntimes.includes(runtime)) selectedRuntimes.push(runtime);
47
+ };
48
+ const addAdapter = (adapter) => {
49
+ if (!adapterTargets.includes(adapter)) adapterTargets.push(adapter);
50
+ };
51
+
52
+ for (const tool of requestedTools) {
53
+ if (tool === 'claude' || tool === 'opencode' || tool === 'codex') {
54
+ addRuntime(tool);
55
+ addAdapter(tool);
56
+ continue;
57
+ }
58
+ if (tool === 'cursor' || tool === 'copilot' || tool === 'gemini') {
59
+ addRuntime(tool);
60
+ addAdapter(tool);
61
+ continue;
62
+ }
63
+ if (tool === 'agents') {
64
+ addAdapter('agents');
65
+ }
66
+ }
67
+
68
+ return { selectedRuntimes, adapterTargets };
69
+ }
70
+
71
+ export function detectPlatforms(adapters) {
72
+ return Object.values(adapters)
73
+ .filter((adapter, index, arr) => arr.findIndex((other) => other.id === adapter.id) === index)
74
+ .filter((adapter) => adapter.detect())
75
+ .map((adapter) => adapter.name);
76
+ }
77
+
78
+ export function buildRuntimeChoices(adapters) {
79
+ const detected = new Set(detectPlatforms(adapters));
80
+ return RUNTIME_OPTIONS.map((option) => ({
81
+ ...option,
82
+ detected: detected.has(option.id),
83
+ selected: detected.has(option.id),
84
+ }));
85
+ }
86
+
87
+ export function resolveAdapters(adapters, platformNames) {
88
+ const seen = new Set();
89
+ const resolved = [];
90
+
91
+ for (const platformName of platformNames) {
92
+ const adapter = adapters[platformName];
93
+ if (!adapter || seen.has(adapter.id)) continue;
94
+ seen.add(adapter.id);
95
+ resolved.push(adapter);
96
+ }
97
+
98
+ return resolved;
99
+ }
100
+
101
+ export function getAdaptersToUpdate(adapters, platformNames) {
102
+ const requested = new Set(platformNames);
103
+ const seen = new Set();
104
+ const installed = [];
105
+
106
+ for (const [platformName, adapter] of Object.entries(adapters)) {
107
+ if (seen.has(adapter.id)) continue;
108
+ if (!requested.has(platformName) && !adapter.isInstalled()) continue;
109
+ seen.add(adapter.id);
110
+ installed.push(adapter);
111
+ }
112
+
113
+ return installed;
114
+ }
115
+
116
+ export async function resolveInteractiveInitSession({ ctx, promptApi, parsedTools, isAuto }) {
117
+ if (parsedTools.length > 0) {
118
+ return {
119
+ ...normalizeRequestedTools(parsedTools),
120
+ config: null,
121
+ };
122
+ }
123
+
124
+ if (isAuto) {
125
+ return { selectedRuntimes: [], adapterTargets: [], config: null };
126
+ }
127
+
128
+ if (!process.stdin.isTTY) {
129
+ return {
130
+ selectedRuntimes: detectPlatforms(ctx.adapters),
131
+ adapterTargets: detectPlatforms(ctx.adapters),
132
+ config: null,
133
+ };
134
+ }
135
+
136
+ return promptApi.runInitWizard({ cwd: ctx.cwd, adapters: ctx.adapters });
137
+ }
138
+
139
+ export function resolveWizardAdapterTargets(selectedRuntimes, installGovernance) {
140
+ const adapterTargets = [];
141
+ for (const runtime of selectedRuntimes) {
142
+ if (runtime === 'claude' || runtime === 'opencode' || runtime === 'codex') {
143
+ adapterTargets.push(runtime);
144
+ }
145
+ }
146
+ if (installGovernance) adapterTargets.push('agents');
147
+ return adapterTargets;
148
+ }
149
+
150
+ export function getPostInitRoutingLines(selectedRuntimes) {
151
+ const lines = [];
152
+ if (selectedRuntimes.includes('claude')) lines.push(' Claude Code: /gsdd-new-project');
153
+ if (selectedRuntimes.includes('opencode')) lines.push(' OpenCode: /gsdd-new-project');
154
+ if (selectedRuntimes.includes('codex')) lines.push(' Codex CLI: $gsdd-new-project');
155
+ if (selectedRuntimes.includes('cursor')) lines.push(' Cursor: /gsdd-new-project');
156
+ if (selectedRuntimes.includes('copilot')) lines.push(' Copilot: /gsdd-new-project');
157
+ if (selectedRuntimes.includes('gemini')) lines.push(' Gemini CLI: /gsdd-new-project');
158
+ lines.push(' Any tool: open .agents/skills/gsdd-new-project/SKILL.md');
159
+ return lines;
160
+ }
161
+
162
+ export function getHelpText() {
163
+ return `
164
+ gsdd - GSD Distilled CLI
165
+ Spec-Driven Development for AI coding agents.
166
+
167
+ Usage: gsdd <command> [args]
168
+
169
+ Commands:
170
+ init [--tools <platform>] [--auto] [--brief <file>]
171
+ Launch guided install wizard in TTYs, or use --tools for manual/headless setup
172
+ --auto: non-interactive mode with smart defaults (requires --tools)
173
+ --brief <file>: copy project brief to .planning/PROJECT_BRIEF.md
174
+ update [--tools <platform>] [--templates] [--dry]
175
+ Regenerate adapters from latest framework sources
176
+ --templates: also refresh .planning/templates/ and roles
177
+ --dry: preview changes without writing files
178
+ health [--json] Check workspace integrity (healthy/degraded/broken)
179
+ models [subcommand] Inspect or update model profile / runtime overrides
180
+ find-phase [N] Show phase info as JSON (for agent consumption)
181
+ verify <N> Run artifact checks for phase N
182
+ scaffold phase <N> [name] Create a new phase plan file
183
+
184
+ Platforms (for --tools):
185
+ claude Generate Claude Code skills (.claude/skills/gsdd-*), commands (.claude/commands/gsdd-*.md), and native agents (.claude/agents/gsdd-*.md)
186
+ opencode Generate OpenCode local slash commands (.opencode/commands/gsdd-*.md) + native agents (.opencode/agents/gsdd-*.md)
187
+ codex Generate Codex CLI native plan-checker agent (.codex/agents/gsdd-plan-checker.toml)
188
+ agents Generate/Update root AGENTS.md (bounded GSDD block)
189
+ cursor Generate root AGENTS.md governance block; workflows are already discovered natively from .agents/skills/ (legacy alias kept for backward compatibility)
190
+ copilot Generate root AGENTS.md governance block; workflows are already discovered natively from .agents/skills/ (legacy alias kept for backward compatibility)
191
+ gemini Generate root AGENTS.md governance block; workflows are already discovered natively from .agents/skills/ (legacy alias kept for backward compatibility)
192
+ all Generate all adapters (Claude, OpenCode, Codex, AGENTS.md, Cursor, Copilot, Gemini)
193
+
194
+ Notes:
195
+ - init always generates open-standard skills at .agents/skills/gsdd-* (portable workflow entrypoints)
196
+ - running plain \`gsdd init\` in a terminal opens the guided runtime-selection wizard
197
+ - the wizard lets you pick runtimes first, then separately decide whether repo-wide AGENTS.md governance is worth installing
198
+ - directly validated launch surfaces in this repo are Claude Code, OpenCode, and Codex CLI
199
+ - Cursor, Copilot, and Gemini are qualified support through the shared .agents/skills/ surface plus optional governance
200
+ - --tools remains the advanced/manual path and preserves legacy runtime aliases for backward compatibility
201
+ - --tools codex generates .codex/agents/gsdd-plan-checker.toml (portable skill is the entry surface)
202
+ - root AGENTS.md is only written on init when explicitly requested via --tools agents, --tools all, or the wizard governance opt-in
203
+
204
+ Examples:
205
+ npx gsdd-cli init
206
+ npx gsdd-cli init --tools claude
207
+ npx gsdd-cli init --tools cursor
208
+ npx gsdd-cli init --auto --tools claude --brief project-idea.md
209
+ npx gsdd-cli init --auto --tools all
210
+ npx gsdd-cli models show
211
+ npx gsdd-cli models profile quality
212
+ npx gsdd-cli models agent-profile --agent plan-checker --profile quality
213
+ npx gsdd-cli models set --runtime opencode --agent plan-checker --model anthropic/claude-opus-4-6
214
+ npx gsdd-cli models clear --runtime opencode --agent plan-checker
215
+ npx gsdd-cli init --tools agents
216
+ npx gsdd-cli init --tools all
217
+ npx gsdd-cli update
218
+ npx gsdd-cli find-phase
219
+ npx gsdd-cli verify 1
220
+ npx gsdd-cli scaffold phase 4 Payments
221
+
222
+ Workflows (run via skills/adapters generated by init, not direct CLI):
223
+ map-codebase Map or refresh codebase (.agents/skills/gsdd-map-codebase/)
224
+ audit-milestone Audit a completed milestone (.agents/skills/gsdd-audit-milestone/)
225
+ `;
226
+ }
package/bin/lib/init.mjs CHANGED
@@ -1,383 +1,24 @@
1
- // init.mjs - CLI bootstrap, update, and help command implementations
1
+ // init.mjs - thin public facade for init/update commands and prompt helpers
2
2
 
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync, cpSync } from 'fs';
4
- import { join, isAbsolute } from 'path';
5
- import * as readline from 'readline';
6
- import { renderSkillContent } from './rendering.mjs';
7
- import { buildManifest, writeManifest } from './manifest.mjs';
8
- import { parseFlagValue, parseToolsFlag, parseAutoFlag } from './cli-utils.mjs';
9
- import { DEFAULT_GIT_PROTOCOL, buildDefaultConfig, normalizeModelProfile } from './models.mjs';
10
- import { installProjectTemplates, refreshTemplates } from './templates.mjs';
3
+ import { createCmdInit, createCmdUpdate } from './init-flow.mjs';
4
+ import { createInitPromptApi, promptChoiceList } from './init-prompts.mjs';
5
+ import { buildRuntimeChoices, detectPlatforms, getHelpText, normalizeRequestedTools } from './init-runtime.mjs';
11
6
 
12
- export function createCmdInit(ctx) {
13
- return async function cmdInit(...initArgs) {
14
- console.log('gsdd init - setting up SDD workflow\n');
15
-
16
- const isAuto = parseAutoFlag(initArgs);
17
- const toolsFlag = parseFlagValue(initArgs, '--tools');
18
- const briefFlag = parseFlagValue(initArgs, '--brief');
19
- let briefSource = null;
20
-
21
- if (toolsFlag.invalid) {
22
- console.error('ERROR: --tools requires a value. Example: gsdd init --tools claude');
23
- process.exitCode = 1;
24
- return;
25
- }
26
-
27
- if (briefFlag.invalid) {
28
- console.error('ERROR: --brief requires a file path. Example: gsdd init --brief project-idea.md');
29
- process.exitCode = 1;
30
- return;
31
- }
32
-
33
- if (briefFlag.value) {
34
- briefSource = isAbsolute(briefFlag.value) ? briefFlag.value : join(ctx.cwd, briefFlag.value);
35
- if (!existsSync(briefSource)) {
36
- console.error(`ERROR: Brief file not found: ${briefFlag.value}`);
37
- process.exitCode = 1;
38
- return;
39
- }
40
- }
41
-
42
- const parsedTools = parseToolsFlag(initArgs);
43
- if (isAuto && parsedTools.length === 0) {
44
- console.error('ERROR: --auto requires --tools <platform>. Example: gsdd init --auto --tools claude');
45
- process.exitCode = 1;
46
- return;
47
- }
48
-
49
- const existed = existsSync(ctx.planningDir);
50
- mkdirSync(join(ctx.planningDir, 'phases'), { recursive: true });
51
- mkdirSync(join(ctx.planningDir, 'research'), { recursive: true });
52
- console.log(existed
53
- ? ' - .planning/ already exists (ensured subdirectories)'
54
- : ' - created .planning/ directory structure');
55
-
56
- installProjectTemplates(ctx);
57
- await ensureConfig(ctx.cwd, ctx.planningDir, isAuto);
58
-
59
- if (briefSource) {
60
- cpSync(briefSource, join(ctx.planningDir, 'PROJECT_BRIEF.md'));
61
- console.log(' - copied project brief to .planning/PROJECT_BRIEF.md');
62
- }
63
-
64
- generateOpenStandardSkills(ctx.cwd, ctx.workflows);
65
- console.log(' - generated open-standard skills (.agents/skills/gsdd-*)');
66
-
67
- const requestedTools = normalizeRequestedTools(parsedTools);
68
- const platforms = parsedTools.length > 0 ? requestedTools : detectPlatforms(ctx.adapters);
69
- for (const adapter of resolveAdapters(ctx.adapters, platforms)) {
70
- adapter.generate();
71
- console.log(` - ${adapter.summary('generated')}`);
72
- }
73
-
74
- const manifest = buildManifest({ planningDir: ctx.planningDir, frameworkVersion: ctx.frameworkVersion });
75
- writeManifest(ctx.planningDir, manifest);
76
- console.log(' - wrote generation manifest');
77
-
78
- console.log('\nSDD initialized.');
79
- console.log('Next: run the new-project workflow to produce SPEC.md and ROADMAP.md:\n');
80
-
81
- if (platforms.includes('claude'))
82
- console.log(' Claude Code: /gsdd-new-project');
83
- if (platforms.includes('opencode'))
84
- console.log(' OpenCode: /gsdd-new-project');
85
- if (platforms.includes('codex'))
86
- console.log(' Codex CLI: $gsdd-new-project');
87
-
88
- // Always show the portable fallback
89
- console.log(' Any tool: open .agents/skills/gsdd-new-project/SKILL.md\n');
90
- };
91
- }
92
-
93
- export function createCmdUpdate(ctx) {
94
- return function cmdUpdate(...updateArgs) {
95
- const isDry = updateArgs.includes('--dry');
96
- const doTemplates = updateArgs.includes('--templates');
97
-
98
- console.log(`gsdd update - regenerating adapter files${isDry ? ' (dry run)' : ''}\n`);
99
-
100
- const parsedTools = parseToolsFlag(updateArgs);
101
- const requestedTools = normalizeRequestedTools(parsedTools);
102
- const platforms = parsedTools.length > 0 ? requestedTools : detectPlatforms(ctx.adapters);
103
-
104
- let updated = false;
105
-
106
- if (doTemplates) {
107
- refreshTemplates({ ...ctx, isDry });
108
- updated = true;
109
- }
110
-
111
- if (platforms.length > 0 || existsSync(join(ctx.cwd, '.agents', 'skills'))) {
112
- if (isDry) {
113
- console.log(' - would update open-standard skills (.agents/skills/gsdd-*)');
114
- } else {
115
- generateOpenStandardSkills(ctx.cwd, ctx.workflows);
116
- console.log(' - updated open-standard skills (.agents/skills/gsdd-*)');
117
- }
118
- updated = true;
119
- }
120
-
121
- for (const adapter of getAdaptersToUpdate(ctx.adapters, platforms)) {
122
- if (isDry) {
123
- console.log(` - would update ${adapter.name} adapter`);
124
- } else {
125
- adapter.generate();
126
- console.log(` - ${adapter.summary('updated')}`);
127
- }
128
- updated = true;
129
- }
130
-
131
- if (!updated) {
132
- console.log(' - no adapters found to update (run `gsdd init` first)');
133
- } else if (isDry) {
134
- console.log('\nDry run complete. No files were written.\n');
135
- } else {
136
- if (doTemplates && existsSync(ctx.planningDir)) {
137
- const manifest = buildManifest({ planningDir: ctx.planningDir, frameworkVersion: ctx.frameworkVersion });
138
- writeManifest(ctx.planningDir, manifest);
139
- console.log(' - updated generation manifest');
140
- }
141
- console.log('\nAdapters updated.\n');
142
- }
143
- };
144
- }
145
-
146
- export function cmdHelp() {
147
- console.log(`
148
- gsdd - GSD Distilled CLI
149
- Spec-Driven Development for AI coding agents.
150
-
151
- Usage: gsdd <command> [args]
152
-
153
- Commands:
154
- init [--tools <platform>] [--auto] [--brief <file>]
155
- Set up SDD + generate adapters
156
- --auto: non-interactive mode with smart defaults (requires --tools)
157
- --brief <file>: copy project brief to .planning/PROJECT_BRIEF.md
158
- update [--tools <platform>] [--templates] [--dry]
159
- Regenerate adapters from latest framework sources
160
- --templates: also refresh .planning/templates/ and roles
161
- --dry: preview changes without writing files
162
- health [--json] Check workspace integrity (healthy/degraded/broken)
163
- models [subcommand] Inspect or update model profile / runtime overrides
164
- find-phase [N] Show phase info as JSON (for agent consumption)
165
- verify <N> Run artifact checks for phase N
166
- scaffold phase <N> [name] Create a new phase plan file
167
-
168
- Platforms (for --tools):
169
- claude Generate Claude Code skills (.claude/skills/gsdd-*), commands (.claude/commands/gsdd-*.md), and native agents (.claude/agents/gsdd-*.md)
170
- opencode Generate OpenCode local slash commands (.opencode/commands/gsdd-*.md) + native agents (.opencode/agents/gsdd-*.md)
171
- codex Generate Codex CLI native plan-checker agent (.codex/agents/gsdd-plan-checker.toml)
172
- agents Generate/Update root AGENTS.md (bounded GSDD block)
173
- cursor Same as 'agents'
174
- copilot Same as 'agents'
175
- gemini Same as 'agents'
176
- all Generate all adapters (Claude, OpenCode, Codex, AGENTS-based surfaces)
177
-
178
- Notes:
179
- - init always generates open-standard skills at .agents/skills/gsdd-* (portable workflow entrypoints)
180
- - --tools claude also generates native commands at .claude/commands/gsdd-*.md and native agents at .claude/agents/gsdd-*.md
181
- - --tools opencode also generates native agents at .opencode/agents/gsdd-*.md
182
- - --tools codex generates .codex/agents/gsdd-plan-checker.toml (portable skill is the entry surface)
183
- - root AGENTS.md is only written on init when explicitly requested via --tools agents (or all)
184
-
185
- Examples:
186
- npx gsdd-cli init
187
- npx gsdd-cli init --tools claude
188
- npx gsdd-cli init --auto --tools claude --brief project-idea.md
189
- npx gsdd-cli init --auto --tools all
190
- npx gsdd-cli models show
191
- npx gsdd-cli models profile quality
192
- npx gsdd-cli models agent-profile --agent plan-checker --profile quality
193
- npx gsdd-cli models set --runtime opencode --agent plan-checker --model anthropic/claude-opus-4-6
194
- npx gsdd-cli models clear --runtime opencode --agent plan-checker
195
- npx gsdd-cli init --tools agents
196
- npx gsdd-cli init --tools all
197
- npx gsdd-cli update
198
- npx gsdd-cli find-phase
199
- npx gsdd-cli verify 1
200
- npx gsdd-cli scaffold phase 4 Payments
201
-
202
- Workflows (run via skills/adapters generated by init, not direct CLI):
203
- map-codebase Map or refresh codebase (.agents/skills/gsdd-map-codebase/)
204
- audit-milestone Audit a completed milestone (.agents/skills/gsdd-audit-milestone/)
7
+ function cmdHelp() {
8
+ console.log(`${getHelpText().trimEnd()}
9
+ file-op <copy|delete|regex-sub>
10
+ Run deterministic workspace-confined file copy/delete/text mutation
11
+ phase-status <N> <status> Update ROADMAP.md phase status ([ ] / [-] / [x])
205
12
  `);
206
13
  }
207
14
 
208
- function detectPlatforms(adapters) {
209
- return Object.values(adapters)
210
- .filter((adapter, index, arr) => arr.findIndex((other) => other.id === adapter.id) === index)
211
- .filter((adapter) => adapter.detect())
212
- .map((adapter) => adapter.name);
213
- }
214
-
215
- function normalizeRequestedTools(requestedTools) {
216
- return requestedTools;
217
- }
218
-
219
- function generateOpenStandardSkills(cwd, workflows) {
220
- for (const workflow of workflows) {
221
- const dir = join(cwd, '.agents', 'skills', workflow.name);
222
- mkdirSync(dir, { recursive: true });
223
- writeFileSync(join(dir, 'SKILL.md'), renderSkillContent(workflow));
224
- }
225
- }
226
-
227
- function resolveAdapters(adapters, platformNames) {
228
- const seen = new Set();
229
- const resolved = [];
230
-
231
- for (const platformName of platformNames) {
232
- const adapter = adapters[platformName];
233
- if (!adapter || seen.has(adapter.id)) continue;
234
- seen.add(adapter.id);
235
- resolved.push(adapter);
236
- }
237
-
238
- return resolved;
239
- }
240
-
241
- function getAdaptersToUpdate(adapters, platformNames) {
242
- const requested = new Set(platformNames);
243
- const seen = new Set();
244
- const installed = [];
245
-
246
- for (const [platformName, adapter] of Object.entries(adapters)) {
247
- if (seen.has(adapter.id)) continue;
248
- if (!requested.has(platformName) && !adapter.isInstalled()) continue;
249
- seen.add(adapter.id);
250
- installed.push(adapter);
251
- }
252
-
253
- return installed;
254
- }
255
-
256
- async function ensureConfig(cwd, planningDir, isAuto) {
257
- const configFile = join(planningDir, 'config.json');
258
- if (existsSync(configFile)) {
259
- console.log(' - .planning/config.json already exists');
260
- return;
261
- }
262
-
263
- if (isAuto) {
264
- console.log(' - auto mode: writing config.json with defaults');
265
- writeFileSync(configFile, JSON.stringify(buildDefaultConfig({ autoAdvance: true }), null, 2));
266
- console.log(' - saved .planning/config.json (auto mode - autoAdvance enabled)\n');
267
- return;
268
- }
269
-
270
- if (!process.stdin.isTTY) {
271
- console.log(' - non-interactive mode detected: writing config.json with defaults');
272
- writeFileSync(configFile, JSON.stringify(buildDefaultConfig(), null, 2));
273
- console.log(' - saved .planning/config.json (defaults - re-run gsdd init in a terminal to customize)\n');
274
- return;
275
- }
276
-
277
- const config = await promptForConfig(cwd);
278
- writeFileSync(configFile, JSON.stringify(config, null, 2));
279
- console.log('\n - saved .planning/config.json\n');
280
- }
281
-
282
- async function promptForConfig(cwd) {
283
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
284
- const askQuestion = (query) => new Promise((resolve) => rl.question(query, resolve));
285
-
286
- try {
287
- console.log(" Let's configure the planning strategy for this project:\n");
288
-
289
- console.log(' Research depth:');
290
- console.log(' - balanced: SOTA research per phase (recommended)');
291
- console.log(' - fast: skip deep domain research, plan from existing knowledge');
292
- console.log(' - deep: exhaustive web sweeps + parallel researchers for every feature');
293
- let researchDepth = await askQuestion(' Depth [balanced/fast/deep] (default: balanced): ');
294
- researchDepth = researchDepth.trim().toLowerCase();
295
- if (!['balanced', 'fast', 'deep'].includes(researchDepth)) researchDepth = 'balanced';
296
-
297
- console.log('\n Parallelization (run independent agents simultaneously):');
298
- console.log(' - yes: faster, uses more tokens (recommended for non-trivial projects)');
299
- console.log(' - no: sequential, lower token usage');
300
- let parallelInput = await askQuestion(' Parallelize agents? [yes/no] (default: yes): ');
301
- const parallelization = parallelInput.trim().toLowerCase() !== 'no';
302
-
303
- console.log('\n Version control for planning docs:');
304
- console.log(' - yes: .planning/ tracked in git (recommended - enables history + recovery)');
305
- console.log(' - no: .planning/ added to .gitignore (local only)');
306
- let commitInput = await askQuestion(' Commit planning docs to git? [yes/no] (default: yes): ');
307
- const commitDocs = commitInput.trim().toLowerCase() !== 'no';
308
-
309
- console.log('\n AI model profile for planning agents:');
310
- console.log(' - balanced: capable model for most agents (recommended)');
311
- console.log(' - quality: most capable model for research/roadmap (higher cost)');
312
- console.log(' - budget: fastest/cheapest model (lower quality for complex tasks)');
313
- let modelProfile = await askQuestion(' Model profile [balanced/quality/budget] (default: balanced): ');
314
- modelProfile = normalizeModelProfile(modelProfile.trim().toLowerCase());
315
-
316
- console.log('\n Workflow agents (each adds quality but costs tokens/time):');
317
- let researchInput = await askQuestion(' Research before planning each phase? [yes/no] (default: yes): ');
318
- const workflowResearch = researchInput.trim().toLowerCase() !== 'no';
319
-
320
- let discussInput = await askQuestion(' Explore approaches with user before planning? [yes/no] (default: no): ');
321
- const workflowDiscuss = discussInput.trim().toLowerCase() === 'yes';
322
-
323
- let planCheckInput = await askQuestion(' Verify plans achieve their goals before executing? [yes/no] (default: yes): ');
324
- const workflowPlanCheck = planCheckInput.trim().toLowerCase() !== 'no';
325
-
326
- let verifierInput = await askQuestion(' Verify phase deliverables after execution? [yes/no] (default: yes): ');
327
- const workflowVerifier = verifierInput.trim().toLowerCase() !== 'no';
328
-
329
- console.log('\n Version Control Protocol (Advisory)');
330
- console.log(' This captures preferred guidance. Repo/user conventions still win over framework defaults.');
331
-
332
- let branchStrategy = await askQuestion(' Branching guidance (default: follow existing repo conventions; use feature branches for significant changes): ');
333
- branchStrategy = branchStrategy.trim() || DEFAULT_GIT_PROTOCOL.branch;
334
-
335
- let commitStrategy = await askQuestion(' Commit guidance (default: logical grouping, no phase/plan/task IDs unless requested): ');
336
- commitStrategy = commitStrategy.trim() || DEFAULT_GIT_PROTOCOL.commit;
337
-
338
- let prStrategy = await askQuestion(' PR guidance (default: follow existing repo review workflow): ');
339
- prStrategy = prStrategy.trim() || DEFAULT_GIT_PROTOCOL.pr;
340
-
341
- if (!commitDocs) {
342
- ensureGitignoreEntry(cwd);
343
- }
344
-
345
- return {
346
- researchDepth,
347
- parallelization,
348
- commitDocs,
349
- modelProfile,
350
- workflow: {
351
- research: workflowResearch,
352
- discuss: workflowDiscuss,
353
- planCheck: workflowPlanCheck,
354
- verifier: workflowVerifier,
355
- },
356
- gitProtocol: {
357
- branch: branchStrategy,
358
- commit: commitStrategy,
359
- pr: prStrategy,
360
- },
361
- initVersion: 'v1.1',
362
- };
363
- } finally {
364
- rl.close();
365
- }
366
- }
367
-
368
- function ensureGitignoreEntry(cwd) {
369
- const gitignorePath = join(cwd, '.gitignore');
370
- const ignoreEntry = '\n# GSDD planning docs (local only)\n.planning/\n';
371
-
372
- if (existsSync(gitignorePath)) {
373
- const existing = readFileSync(gitignorePath, 'utf-8');
374
- if (!existing.includes('.planning/')) {
375
- writeFileSync(gitignorePath, existing + ignoreEntry);
376
- console.log(' - added .planning/ to .gitignore');
377
- }
378
- return;
379
- }
380
-
381
- writeFileSync(gitignorePath, ignoreEntry.trimStart());
382
- console.log(' - created .gitignore with .planning/ entry');
383
- }
15
+ export {
16
+ buildRuntimeChoices,
17
+ cmdHelp,
18
+ createCmdInit,
19
+ createCmdUpdate,
20
+ createInitPromptApi,
21
+ detectPlatforms,
22
+ normalizeRequestedTools,
23
+ promptChoiceList,
24
+ };
@@ -15,6 +15,21 @@ export const DEFAULT_GIT_PROTOCOL = {
15
15
  pr: 'Follow the existing repo or team review workflow. Do not assume PR creation, timing, or naming unless explicitly requested.',
16
16
  };
17
17
 
18
+ export const RIGOR_PROFILES = {
19
+ quick: { researchDepth: 'fast', workflow: { research: false, discuss: false, planCheck: false, verifier: true } },
20
+ balanced: { researchDepth: 'balanced', workflow: { research: true, discuss: false, planCheck: true, verifier: true } },
21
+ thorough: { researchDepth: 'deep', workflow: { research: true, discuss: true, planCheck: true, verifier: true } },
22
+ };
23
+
24
+ export const COST_PROFILES = {
25
+ budget: { modelProfile: 'budget', parallelization: false },
26
+ balanced: { modelProfile: 'balanced', parallelization: true },
27
+ quality: { modelProfile: 'quality', parallelization: true },
28
+ };
29
+
30
+ export function resolveRigor(id) { return RIGOR_PROFILES[id] ?? RIGOR_PROFILES.balanced; }
31
+ export function resolveCost(id) { return COST_PROFILES[id] ?? COST_PROFILES.balanced; }
32
+
18
33
  export const VALID_MODEL_PROFILES = ['quality', 'balanced', 'budget'];
19
34
  export const PORTABLE_AGENT_IDS = ['plan-checker', 'approach-explorer'];
20
35
  export const MODEL_RUNTIME_IDS = ['claude', 'opencode', 'codex'];
@@ -25,12 +40,12 @@ export function normalizeModelProfile(value) {
25
40
  }
26
41
 
27
42
  export function buildDefaultConfig({ autoAdvance = false } = {}) {
43
+ const rigor = resolveRigor('balanced');
44
+ const cost = resolveCost('balanced');
28
45
  const config = {
29
- researchDepth: 'balanced',
30
- parallelization: true,
46
+ ...rigor,
47
+ ...cost,
31
48
  commitDocs: true,
32
- modelProfile: 'balanced',
33
- workflow: { research: true, discuss: false, planCheck: true, verifier: true },
34
49
  gitProtocol: { ...DEFAULT_GIT_PROTOCOL },
35
50
  initVersion: 'v1.1',
36
51
  };