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.
- package/README.md +38 -20
- package/agents/DISTILLATION.md +116 -3
- package/agents/README.md +9 -0
- package/agents/approach-explorer.md +361 -0
- package/agents/planner.md +20 -5
- package/bin/adapters/claude.mjs +41 -11
- package/bin/adapters/codex.mjs +20 -1
- package/bin/adapters/opencode.mjs +37 -11
- package/bin/gsdd.mjs +44 -34
- package/bin/lib/init-flow.mjs +220 -0
- package/bin/lib/init-prompts.mjs +308 -0
- package/bin/lib/init-runtime.mjs +224 -0
- package/bin/lib/init.mjs +20 -379
- package/bin/lib/models.mjs +27 -10
- package/distilled/DESIGN.md +366 -7
- package/distilled/README.md +173 -169
- package/distilled/templates/agents.block.md +5 -3
- package/distilled/templates/approach.md +232 -0
- package/distilled/templates/delegates/approach-explorer.md +25 -0
- package/distilled/templates/delegates/plan-checker.md +11 -1
- package/distilled/workflows/audit-milestone.md +2 -0
- package/distilled/workflows/map-codebase.md +10 -5
- package/distilled/workflows/new-project.md +26 -21
- package/distilled/workflows/pause.md +2 -0
- package/distilled/workflows/plan.md +83 -12
- package/distilled/workflows/quick.md +163 -4
- package/package.json +11 -3
|
@@ -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 -
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
+
};
|