gsdd-cli 0.1.0 → 0.3.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.
@@ -0,0 +1,224 @@
1
+ const RUNTIME_OPTIONS = [
2
+ {
3
+ id: 'claude',
4
+ label: 'Claude Code',
5
+ description: 'Native skills, commands, and agents',
6
+ kind: 'native',
7
+ },
8
+ {
9
+ id: 'opencode',
10
+ label: 'OpenCode',
11
+ description: 'Native slash commands and agents',
12
+ kind: 'native',
13
+ },
14
+ {
15
+ id: 'codex',
16
+ label: 'Codex CLI',
17
+ description: 'Portable skills plus native checker agents',
18
+ kind: 'native',
19
+ },
20
+ {
21
+ id: 'cursor',
22
+ label: 'Cursor',
23
+ description: 'Skills-native slash commands from .agents/skills/',
24
+ kind: 'skills_native',
25
+ },
26
+ {
27
+ id: 'copilot',
28
+ label: 'GitHub Copilot',
29
+ description: 'Skills-native slash commands from .agents/skills/',
30
+ kind: 'skills_native',
31
+ },
32
+ {
33
+ id: 'gemini',
34
+ label: 'Gemini CLI',
35
+ description: '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-based surfaces)
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
+ - --tools remains the advanced/manual path and preserves legacy runtime aliases for backward compatibility
199
+ - --tools codex generates .codex/agents/gsdd-plan-checker.toml (portable skill is the entry surface)
200
+ - root AGENTS.md is only written on init when explicitly requested via --tools agents, --tools all, or the wizard governance opt-in
201
+
202
+ Examples:
203
+ npx gsdd-cli init
204
+ npx gsdd-cli init --tools claude
205
+ npx gsdd-cli init --tools cursor
206
+ npx gsdd-cli init --auto --tools claude --brief project-idea.md
207
+ npx gsdd-cli init --auto --tools all
208
+ npx gsdd-cli models show
209
+ npx gsdd-cli models profile quality
210
+ npx gsdd-cli models agent-profile --agent plan-checker --profile quality
211
+ npx gsdd-cli models set --runtime opencode --agent plan-checker --model anthropic/claude-opus-4-6
212
+ npx gsdd-cli models clear --runtime opencode --agent plan-checker
213
+ npx gsdd-cli init --tools agents
214
+ npx gsdd-cli init --tools all
215
+ npx gsdd-cli update
216
+ npx gsdd-cli find-phase
217
+ npx gsdd-cli verify 1
218
+ npx gsdd-cli scaffold phase 4 Payments
219
+
220
+ Workflows (run via skills/adapters generated by init, not direct CLI):
221
+ map-codebase Map or refresh codebase (.agents/skills/gsdd-map-codebase/)
222
+ audit-milestone Audit a completed milestone (.agents/skills/gsdd-audit-milestone/)
223
+ `;
224
+ }
package/bin/lib/init.mjs CHANGED
@@ -1,379 +1,20 @@
1
- // init.mjs - CLI bootstrap, update, and help command implementations
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';
11
-
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/)
205
- `);
206
- }
207
-
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 planCheckInput = await askQuestion(' Verify plans achieve their goals before executing? [yes/no] (default: yes): ');
321
- const workflowPlanCheck = planCheckInput.trim().toLowerCase() !== 'no';
322
-
323
- let verifierInput = await askQuestion(' Verify phase deliverables after execution? [yes/no] (default: yes): ');
324
- const workflowVerifier = verifierInput.trim().toLowerCase() !== 'no';
325
-
326
- console.log('\n Version Control Protocol (Advisory)');
327
- console.log(' This captures preferred guidance. Repo/user conventions still win over framework defaults.');
328
-
329
- let branchStrategy = await askQuestion(' Branching guidance (default: follow existing repo conventions; use feature branches for significant changes): ');
330
- branchStrategy = branchStrategy.trim() || DEFAULT_GIT_PROTOCOL.branch;
331
-
332
- let commitStrategy = await askQuestion(' Commit guidance (default: logical grouping, no phase/plan/task IDs unless requested): ');
333
- commitStrategy = commitStrategy.trim() || DEFAULT_GIT_PROTOCOL.commit;
334
-
335
- let prStrategy = await askQuestion(' PR guidance (default: follow existing repo review workflow): ');
336
- prStrategy = prStrategy.trim() || DEFAULT_GIT_PROTOCOL.pr;
337
-
338
- if (!commitDocs) {
339
- ensureGitignoreEntry(cwd);
340
- }
341
-
342
- return {
343
- researchDepth,
344
- parallelization,
345
- commitDocs,
346
- modelProfile,
347
- workflow: {
348
- research: workflowResearch,
349
- planCheck: workflowPlanCheck,
350
- verifier: workflowVerifier,
351
- },
352
- gitProtocol: {
353
- branch: branchStrategy,
354
- commit: commitStrategy,
355
- pr: prStrategy,
356
- },
357
- initVersion: 'v1.1',
358
- };
359
- } finally {
360
- rl.close();
361
- }
362
- }
363
-
364
- function ensureGitignoreEntry(cwd) {
365
- const gitignorePath = join(cwd, '.gitignore');
366
- const ignoreEntry = '\n# GSDD planning docs (local only)\n.planning/\n';
367
-
368
- if (existsSync(gitignorePath)) {
369
- const existing = readFileSync(gitignorePath, 'utf-8');
370
- if (!existing.includes('.planning/')) {
371
- writeFileSync(gitignorePath, existing + ignoreEntry);
372
- console.log(' - added .planning/ to .gitignore');
373
- }
374
- return;
375
- }
376
-
377
- writeFileSync(gitignorePath, ignoreEntry.trimStart());
378
- console.log(' - created .gitignore with .planning/ entry');
379
- }
1
+ // init.mjs - thin public facade for init/update commands and prompt helpers
2
+
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';
6
+
7
+ function cmdHelp() {
8
+ console.log(getHelpText());
9
+ }
10
+
11
+ export {
12
+ buildRuntimeChoices,
13
+ cmdHelp,
14
+ createCmdInit,
15
+ createCmdUpdate,
16
+ createInitPromptApi,
17
+ detectPlatforms,
18
+ normalizeRequestedTools,
19
+ promptChoiceList,
20
+ };