gspec 1.7.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/gspec.js +275 -8
- package/commands/gspec.analyze.md +1 -1
- package/commands/gspec.implement.md +3 -3
- package/commands/gspec.practices.md +3 -1
- package/commands/gspec.stack.md +11 -6
- package/commands/gspec.style.md +18 -23
- package/dist/antigravity/gspec-analyze/SKILL.md +1 -1
- package/dist/antigravity/gspec-architect/SKILL.md +1 -1
- package/dist/antigravity/gspec-feature/SKILL.md +1 -1
- package/dist/antigravity/gspec-implement/SKILL.md +4 -4
- package/dist/antigravity/gspec-migrate/SKILL.md +5 -5
- package/dist/antigravity/gspec-practices/SKILL.md +4 -2
- package/dist/antigravity/gspec-profile/SKILL.md +1 -1
- package/dist/antigravity/gspec-research/SKILL.md +3 -3
- package/dist/antigravity/gspec-stack/SKILL.md +12 -7
- package/dist/antigravity/gspec-style/SKILL.md +19 -24
- package/dist/claude/gspec-analyze/SKILL.md +1 -1
- package/dist/claude/gspec-architect/SKILL.md +1 -1
- package/dist/claude/gspec-feature/SKILL.md +1 -1
- package/dist/claude/gspec-implement/SKILL.md +4 -4
- package/dist/claude/gspec-migrate/SKILL.md +5 -5
- package/dist/claude/gspec-practices/SKILL.md +4 -2
- package/dist/claude/gspec-profile/SKILL.md +1 -1
- package/dist/claude/gspec-research/SKILL.md +3 -3
- package/dist/claude/gspec-stack/SKILL.md +12 -7
- package/dist/claude/gspec-style/SKILL.md +19 -24
- package/dist/codex/gspec-analyze/SKILL.md +1 -1
- package/dist/codex/gspec-architect/SKILL.md +1 -1
- package/dist/codex/gspec-feature/SKILL.md +1 -1
- package/dist/codex/gspec-implement/SKILL.md +4 -4
- package/dist/codex/gspec-migrate/SKILL.md +5 -5
- package/dist/codex/gspec-practices/SKILL.md +4 -2
- package/dist/codex/gspec-profile/SKILL.md +1 -1
- package/dist/codex/gspec-research/SKILL.md +3 -3
- package/dist/codex/gspec-stack/SKILL.md +12 -7
- package/dist/codex/gspec-style/SKILL.md +19 -24
- package/dist/cursor/gspec-analyze.mdc +1 -1
- package/dist/cursor/gspec-architect.mdc +1 -1
- package/dist/cursor/gspec-feature.mdc +1 -1
- package/dist/cursor/gspec-implement.mdc +4 -4
- package/dist/cursor/gspec-migrate.mdc +5 -5
- package/dist/cursor/gspec-practices.mdc +4 -2
- package/dist/cursor/gspec-profile.mdc +1 -1
- package/dist/cursor/gspec-research.mdc +3 -3
- package/dist/cursor/gspec-stack.mdc +12 -7
- package/dist/cursor/gspec-style.mdc +19 -24
- package/dist/opencode/gspec-analyze/SKILL.md +168 -0
- package/dist/opencode/gspec-architect/SKILL.md +361 -0
- package/dist/opencode/gspec-feature/SKILL.md +204 -0
- package/dist/opencode/gspec-implement/SKILL.md +200 -0
- package/dist/opencode/gspec-migrate/SKILL.md +118 -0
- package/dist/opencode/gspec-practices/SKILL.md +137 -0
- package/dist/opencode/gspec-profile/SKILL.md +221 -0
- package/dist/opencode/gspec-research/SKILL.md +302 -0
- package/dist/opencode/gspec-stack/SKILL.md +305 -0
- package/dist/opencode/gspec-style/SKILL.md +224 -0
- package/package.json +3 -1
- package/starters/features/about-page.md +98 -0
- package/starters/features/contact-form.md +147 -0
- package/starters/features/contact-page.md +103 -0
- package/starters/features/home-page.md +103 -0
- package/starters/features/responsive-navbar.md +113 -0
- package/starters/features/services-page.md +103 -0
- package/starters/features/site-footer.md +121 -0
- package/starters/features/theme-switcher.md +124 -0
- package/starters/practices/tdd-pipeline-first.md +192 -0
- package/starters/stacks/astro-tailwind-github-pages.md +283 -0
- package/starters/stacks/nextjs-supabase-vercel.md +319 -0
- package/starters/stacks/nextjs-vercel-typescript.md +264 -0
- package/starters/styles/clean-professional.md +316 -0
- package/starters/styles/dark-minimal-developer.md +442 -0
- package/templates/spec-sync.md +1 -1
package/bin/gspec.js
CHANGED
|
@@ -9,6 +9,7 @@ import chalk from 'chalk';
|
|
|
9
9
|
|
|
10
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
const DIST_DIR = join(__dirname, '..', 'dist');
|
|
12
|
+
const STARTERS_DIR = join(__dirname, '..', 'starters');
|
|
12
13
|
const pkg = JSON.parse(await readFile(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
13
14
|
|
|
14
15
|
const BANNER = `
|
|
@@ -51,6 +52,12 @@ const TARGETS = {
|
|
|
51
52
|
label: 'Codex',
|
|
52
53
|
layout: 'directory',
|
|
53
54
|
},
|
|
55
|
+
opencode: {
|
|
56
|
+
sourceDir: join(DIST_DIR, 'opencode'),
|
|
57
|
+
installDir: '.opencode/skills',
|
|
58
|
+
label: 'Open Code',
|
|
59
|
+
layout: 'directory',
|
|
60
|
+
},
|
|
54
61
|
};
|
|
55
62
|
|
|
56
63
|
const TARGET_CHOICES = [
|
|
@@ -58,6 +65,7 @@ const TARGET_CHOICES = [
|
|
|
58
65
|
{ key: '2', name: 'cursor', label: 'Cursor' },
|
|
59
66
|
{ key: '3', name: 'antigravity', label: 'Antigravity' },
|
|
60
67
|
{ key: '4', name: 'codex', label: 'Codex' },
|
|
68
|
+
{ key: '5', name: 'opencode', label: 'Open Code' },
|
|
61
69
|
];
|
|
62
70
|
|
|
63
71
|
function promptTarget() {
|
|
@@ -70,7 +78,7 @@ function promptTarget() {
|
|
|
70
78
|
console.log();
|
|
71
79
|
|
|
72
80
|
return new Promise((resolve) => {
|
|
73
|
-
rl.question(chalk.bold(' Select [1-
|
|
81
|
+
rl.question(chalk.bold(' Select [1-5]: '), (answer) => {
|
|
74
82
|
rl.close();
|
|
75
83
|
const trimmed = answer.trim().toLowerCase();
|
|
76
84
|
|
|
@@ -83,7 +91,7 @@ function promptTarget() {
|
|
|
83
91
|
if (byName) return resolve(byName.name);
|
|
84
92
|
|
|
85
93
|
console.error(chalk.red(`\nInvalid selection: "${answer.trim()}"`));
|
|
86
|
-
console.error(`Valid options: 1, 2, 3, 4, claude, cursor, antigravity, codex`);
|
|
94
|
+
console.error(`Valid options: 1, 2, 3, 4, 5, claude, cursor, antigravity, codex, opencode`);
|
|
87
95
|
process.exit(1);
|
|
88
96
|
});
|
|
89
97
|
});
|
|
@@ -109,6 +117,246 @@ function promptConfirmNo(message) {
|
|
|
109
117
|
});
|
|
110
118
|
}
|
|
111
119
|
|
|
120
|
+
// --- Feature dependency map ---
|
|
121
|
+
// Maps feature slugs to their required feature dependencies (other feature slugs).
|
|
122
|
+
// This is used to auto-include dependencies when a user selects a feature.
|
|
123
|
+
const FEATURE_DEPENDENCIES = {
|
|
124
|
+
'home-page': [],
|
|
125
|
+
'about-page': ['home-page'],
|
|
126
|
+
'contact-page': ['home-page'],
|
|
127
|
+
'services-page': ['home-page'],
|
|
128
|
+
'responsive-navbar': ['home-page'],
|
|
129
|
+
'contact-form': ['contact-page'],
|
|
130
|
+
'site-footer': ['home-page', 'about-page', 'contact-page'],
|
|
131
|
+
'theme-switcher': ['home-page', 'about-page', 'contact-page'],
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
function resolveFeatureDependencies(selectedSlugs) {
|
|
135
|
+
const resolved = new Set(selectedSlugs);
|
|
136
|
+
let changed = true;
|
|
137
|
+
while (changed) {
|
|
138
|
+
changed = false;
|
|
139
|
+
for (const slug of [...resolved]) {
|
|
140
|
+
const deps = FEATURE_DEPENDENCIES[slug] || [];
|
|
141
|
+
for (const dep of deps) {
|
|
142
|
+
if (!resolved.has(dep)) {
|
|
143
|
+
resolved.add(dep);
|
|
144
|
+
changed = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return [...resolved];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// --- Starter template utilities ---
|
|
153
|
+
|
|
154
|
+
async function parseStarterDescription(filePath) {
|
|
155
|
+
const content = await readFile(filePath, 'utf-8');
|
|
156
|
+
const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
157
|
+
if (!match) return '';
|
|
158
|
+
const descLine = match[1].split('\n').find((l) => l.startsWith('description:'));
|
|
159
|
+
return descLine ? descLine.replace(/^description:\s*/, '').trim() : '';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function listStarterTemplates(category) {
|
|
163
|
+
const dir = join(STARTERS_DIR, category);
|
|
164
|
+
let entries;
|
|
165
|
+
try {
|
|
166
|
+
entries = await readdir(dir);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
if (e.code === 'ENOENT') return [];
|
|
169
|
+
throw e;
|
|
170
|
+
}
|
|
171
|
+
const mdFiles = entries.filter((f) => f.endsWith('.md'));
|
|
172
|
+
const templates = [];
|
|
173
|
+
for (const f of mdFiles) {
|
|
174
|
+
const slug = f.replace(/\.md$/, '');
|
|
175
|
+
const description = await parseStarterDescription(join(dir, f));
|
|
176
|
+
templates.push({ slug, description });
|
|
177
|
+
}
|
|
178
|
+
return templates;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function formatStarterName(slug) {
|
|
182
|
+
if (slug === '_none') return 'None';
|
|
183
|
+
return slug
|
|
184
|
+
.split('-')
|
|
185
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
186
|
+
.join(' ');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function stampVersion(content) {
|
|
190
|
+
return content.replace(/^(---\s*\n[\s\S]*?)gspec-version:\s*.+/m, `$1gspec-version: ${pkg.version}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function promptSelect(message, choices) {
|
|
194
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
195
|
+
console.log(chalk.bold(`\n${message}\n`));
|
|
196
|
+
for (let i = 0; i < choices.length; i++) {
|
|
197
|
+
const label = formatStarterName(choices[i].slug);
|
|
198
|
+
const desc = choices[i].description ? ` — ${choices[i].description}` : '';
|
|
199
|
+
console.log(` ${chalk.cyan(String(i + 1))}) ${label}${desc}`);
|
|
200
|
+
}
|
|
201
|
+
console.log();
|
|
202
|
+
|
|
203
|
+
return new Promise((resolve) => {
|
|
204
|
+
rl.question(chalk.bold(` Select [1-${choices.length}]: `), (answer) => {
|
|
205
|
+
rl.close();
|
|
206
|
+
const num = parseInt(answer.trim(), 10);
|
|
207
|
+
if (num >= 1 && num <= choices.length) return resolve(choices[num - 1].slug);
|
|
208
|
+
console.error(chalk.red(`\nInvalid selection: "${answer.trim()}"`));
|
|
209
|
+
process.exit(1);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function promptMultiSelect(message, choices) {
|
|
215
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
216
|
+
console.log(chalk.bold(`\n${message}\n`));
|
|
217
|
+
for (let i = 0; i < choices.length; i++) {
|
|
218
|
+
const label = formatStarterName(choices[i].slug);
|
|
219
|
+
const desc = choices[i].description ? ` — ${choices[i].description}` : '';
|
|
220
|
+
console.log(` ${chalk.cyan(String(i + 1))}) ${label}${desc}`);
|
|
221
|
+
}
|
|
222
|
+
console.log();
|
|
223
|
+
|
|
224
|
+
return new Promise((resolve) => {
|
|
225
|
+
rl.question(chalk.bold(' Enter numbers (comma-separated), "all", or press Enter to skip: '), (answer) => {
|
|
226
|
+
rl.close();
|
|
227
|
+
const trimmed = answer.trim().toLowerCase();
|
|
228
|
+
if (trimmed === '') return resolve([]);
|
|
229
|
+
if (trimmed === 'all') return resolve(choices.map((c) => c.slug));
|
|
230
|
+
|
|
231
|
+
const nums = trimmed.split(',').map((s) => parseInt(s.trim(), 10));
|
|
232
|
+
const invalid = nums.find((n) => isNaN(n) || n < 1 || n > choices.length);
|
|
233
|
+
if (invalid !== undefined) {
|
|
234
|
+
console.error(chalk.red(`\nInvalid selection: "${answer.trim()}"`));
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
resolve(nums.map((n) => choices[n - 1].slug));
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function seedStarterTemplates(cwd) {
|
|
243
|
+
const wantStarters = await promptConfirm(chalk.bold(' Would you like to start from a starter template? [y/N]: '));
|
|
244
|
+
if (!wantStarters) {
|
|
245
|
+
console.log(chalk.dim('\n Skipped starter templates.\n'));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const practices = await listStarterTemplates('practices');
|
|
250
|
+
const stacks = await listStarterTemplates('stacks');
|
|
251
|
+
const styles = await listStarterTemplates('styles');
|
|
252
|
+
const features = await listStarterTemplates('features');
|
|
253
|
+
|
|
254
|
+
if (practices.length === 0 || stacks.length === 0 || styles.length === 0) {
|
|
255
|
+
console.log(chalk.yellow(' Missing starter templates (practices, stacks, or styles). Skipping.\n'));
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const NONE_OPTION = { slug: '_none', description: 'I will define my own' };
|
|
260
|
+
|
|
261
|
+
// Single-select with auto-select for single-option categories
|
|
262
|
+
const practice = practices.length === 1
|
|
263
|
+
? (console.log(chalk.dim(`\n Using practice: ${formatStarterName(practices[0].slug)}`)), practices[0].slug)
|
|
264
|
+
: await promptSelect('Select a development practice', [...practices, NONE_OPTION]);
|
|
265
|
+
|
|
266
|
+
const stack = stacks.length === 1
|
|
267
|
+
? (console.log(chalk.dim(` Using stack: ${formatStarterName(stacks[0].slug)}`)), stacks[0].slug)
|
|
268
|
+
: await promptSelect('Select a technology stack', [...stacks, NONE_OPTION]);
|
|
269
|
+
|
|
270
|
+
const style = styles.length === 1
|
|
271
|
+
? (console.log(chalk.dim(` Using style: ${formatStarterName(styles[0].slug)}`)), styles[0].slug)
|
|
272
|
+
: await promptSelect('Select a visual style', [...styles, NONE_OPTION]);
|
|
273
|
+
|
|
274
|
+
let selectedFeatures = [];
|
|
275
|
+
if (features.length > 0) {
|
|
276
|
+
selectedFeatures = await promptMultiSelect('Select features (optional)', [...features, NONE_OPTION]);
|
|
277
|
+
selectedFeatures = selectedFeatures.filter(f => f !== '_none');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Auto-include feature dependencies
|
|
281
|
+
if (selectedFeatures.length > 0) {
|
|
282
|
+
const resolved = resolveFeatureDependencies(selectedFeatures);
|
|
283
|
+
const added = resolved.filter((f) => !selectedFeatures.includes(f));
|
|
284
|
+
if (added.length > 0) {
|
|
285
|
+
console.log(chalk.cyan(`\n Auto-including dependencies: ${added.map(formatStarterName).join(', ')}`));
|
|
286
|
+
selectedFeatures = resolved;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Check for existing files
|
|
291
|
+
const gspecDir = join(cwd, 'gspec');
|
|
292
|
+
const filesToWrite = [];
|
|
293
|
+
if (practice !== '_none') {
|
|
294
|
+
filesToWrite.push({ src: join(STARTERS_DIR, 'practices', `${practice}.md`), dest: join(gspecDir, 'practices.md'), label: 'gspec/practices.md' });
|
|
295
|
+
}
|
|
296
|
+
if (stack !== '_none') {
|
|
297
|
+
filesToWrite.push({ src: join(STARTERS_DIR, 'stacks', `${stack}.md`), dest: join(gspecDir, 'stack.md'), label: 'gspec/stack.md' });
|
|
298
|
+
}
|
|
299
|
+
if (style !== '_none') {
|
|
300
|
+
filesToWrite.push({ src: join(STARTERS_DIR, 'styles', `${style}.md`), dest: join(gspecDir, 'style.md'), label: 'gspec/style.md' });
|
|
301
|
+
}
|
|
302
|
+
for (const feature of selectedFeatures) {
|
|
303
|
+
filesToWrite.push({
|
|
304
|
+
src: join(STARTERS_DIR, 'features', `${feature}.md`),
|
|
305
|
+
dest: join(gspecDir, 'features', `${feature}.md`),
|
|
306
|
+
label: `gspec/features/${feature}.md`,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const existingFiles = [];
|
|
311
|
+
for (const f of filesToWrite) {
|
|
312
|
+
try {
|
|
313
|
+
await stat(f.dest);
|
|
314
|
+
existingFiles.push(f.label);
|
|
315
|
+
} catch (e) {
|
|
316
|
+
if (e.code !== 'ENOENT') throw e;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (filesToWrite.length === 0) {
|
|
321
|
+
console.log(chalk.dim('\n No starter templates selected. You can define these files using gspec commands.\n'));
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (existingFiles.length > 0) {
|
|
326
|
+
console.log(chalk.yellow(`\n The following files already exist and will be overwritten:\n`));
|
|
327
|
+
for (const label of existingFiles) {
|
|
328
|
+
console.log(` ${chalk.yellow('!')} ${label}`);
|
|
329
|
+
}
|
|
330
|
+
console.log();
|
|
331
|
+
const confirmed = await promptConfirm(chalk.bold(' Continue and overwrite? [y/N]: '));
|
|
332
|
+
if (!confirmed) {
|
|
333
|
+
console.log(chalk.dim('\n Skipped starter templates.\n'));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Copy files with version stamping
|
|
339
|
+
console.log(chalk.bold('\n Seeding starter templates...\n'));
|
|
340
|
+
for (const f of filesToWrite) {
|
|
341
|
+
await mkdir(dirname(f.dest), { recursive: true });
|
|
342
|
+
const content = await readFile(f.src, 'utf-8');
|
|
343
|
+
await writeFile(f.dest, stampVersion(content), 'utf-8');
|
|
344
|
+
console.log(` ${chalk.green('+')} ${f.label}`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Summary
|
|
348
|
+
console.log(chalk.bold('\n Seeded gspec/ with:'));
|
|
349
|
+
console.log(` Practice: ${practice === '_none' ? chalk.dim('(will define)') : formatStarterName(practice)}`);
|
|
350
|
+
console.log(` Stack: ${stack === '_none' ? chalk.dim('(will define)') : formatStarterName(stack)}`);
|
|
351
|
+
console.log(` Style: ${style === '_none' ? chalk.dim('(will define)') : formatStarterName(style)}`);
|
|
352
|
+
if (selectedFeatures.length > 0) {
|
|
353
|
+
console.log(` Features: ${selectedFeatures.map(formatStarterName).join(', ')}`);
|
|
354
|
+
} else {
|
|
355
|
+
console.log(` Features: ${chalk.dim('(will define)')}`);
|
|
356
|
+
}
|
|
357
|
+
console.log();
|
|
358
|
+
}
|
|
359
|
+
|
|
112
360
|
async function findExistingFiles(target, cwd) {
|
|
113
361
|
const existing = [];
|
|
114
362
|
const destBase = join(cwd, target.installDir);
|
|
@@ -257,6 +505,11 @@ const SPEC_SYNC = {
|
|
|
257
505
|
mode: 'append',
|
|
258
506
|
wrap: (content) => content,
|
|
259
507
|
},
|
|
508
|
+
opencode: {
|
|
509
|
+
file: 'AGENTS.md',
|
|
510
|
+
mode: 'append',
|
|
511
|
+
wrap: (content) => content,
|
|
512
|
+
},
|
|
260
513
|
};
|
|
261
514
|
|
|
262
515
|
const GSPEC_SECTION_MARKER = '<!-- gspec:spec-sync -->';
|
|
@@ -312,6 +565,7 @@ const MIGRATE_COMMANDS = {
|
|
|
312
565
|
cursor: '/gspec-migrate',
|
|
313
566
|
antigravity: '/gspec-migrate',
|
|
314
567
|
codex: '/gspec-migrate',
|
|
568
|
+
opencode: '/gspec-migrate',
|
|
315
569
|
};
|
|
316
570
|
|
|
317
571
|
function parseGspecVersion(content) {
|
|
@@ -326,7 +580,7 @@ async function collectGspecFiles(gspecDir) {
|
|
|
326
580
|
|
|
327
581
|
const topEntries = await readdir(gspecDir);
|
|
328
582
|
for (const entry of topEntries) {
|
|
329
|
-
if (entry.endsWith('.md')) {
|
|
583
|
+
if (entry.endsWith('.md') && entry.toLowerCase() !== 'readme.md') {
|
|
330
584
|
files.push({ path: join(gspecDir, entry), label: `gspec/${entry}` });
|
|
331
585
|
}
|
|
332
586
|
}
|
|
@@ -394,7 +648,7 @@ program
|
|
|
394
648
|
.name('gspec')
|
|
395
649
|
.description('Install gspec specification commands')
|
|
396
650
|
.version(pkg.version)
|
|
397
|
-
.option('-t, --target <target>', 'target platform (claude, cursor, antigravity, codex)')
|
|
651
|
+
.option('-t, --target <target>', 'target platform (claude, cursor, antigravity, codex, opencode)')
|
|
398
652
|
.action(async (opts) => {
|
|
399
653
|
console.log(BANNER);
|
|
400
654
|
|
|
@@ -406,12 +660,25 @@ program
|
|
|
406
660
|
|
|
407
661
|
await install(targetName, process.cwd());
|
|
408
662
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
663
|
+
await seedStarterTemplates(process.cwd());
|
|
664
|
+
|
|
665
|
+
await installSpecSync(targetName, process.cwd());
|
|
413
666
|
|
|
414
667
|
await checkGspecFiles(process.cwd(), targetName);
|
|
668
|
+
|
|
669
|
+
// Post-install: instruct user to generate profile.md
|
|
670
|
+
const targetLabel = TARGETS[targetName].label;
|
|
671
|
+
console.log();
|
|
672
|
+
console.log(chalk.bold.cyan(' ═══ Next Step ═══════════════════════════════════════════════'));
|
|
673
|
+
console.log();
|
|
674
|
+
console.log(chalk.bold.white(' Generate your product profile before continuing.'));
|
|
675
|
+
console.log();
|
|
676
|
+
console.log(` Run ${chalk.bold.yellow('/gspec-profile')} in ${targetLabel} to create gspec/profile.md`);
|
|
677
|
+
console.log(` — it defines what your product is, who it serves, and why it`);
|
|
678
|
+
console.log(` exists. All other gspec commands use the profile as their foundation.`);
|
|
679
|
+
console.log();
|
|
680
|
+
console.log(chalk.bold.cyan(' ═════════════════════════════════════════════════════════════'));
|
|
681
|
+
console.log();
|
|
415
682
|
});
|
|
416
683
|
|
|
417
684
|
program.parse();
|
|
@@ -23,7 +23,7 @@ Read **every** available gspec document in this order:
|
|
|
23
23
|
|
|
24
24
|
1. `gspec/profile.md` — Product identity, scope, audience, and positioning
|
|
25
25
|
2. `gspec/stack.md` — Technology choices, frameworks, infrastructure
|
|
26
|
-
3. `gspec/style.md` — Visual design language, tokens, component
|
|
26
|
+
3. `gspec/style.md` — Visual design language, tokens, component styling
|
|
27
27
|
4. `gspec/practices.md` — Development standards, testing, conventions
|
|
28
28
|
5. `gspec/architecture.md` — Technical blueprint: project structure, data model, API design, environment
|
|
29
29
|
6. `gspec/research.md` — Competitive analysis and feature proposals
|
|
@@ -100,9 +100,9 @@ Present a brief scaffold summary to the user before proceeding to feature implem
|
|
|
100
100
|
|
|
101
101
|
1. **Announce the phase** — State which phase you're starting, what it covers, and what capabilities will be implemented
|
|
102
102
|
2. **Implement the phase:**
|
|
103
|
-
a. **Follow the stack** — Use the exact technologies, frameworks, and patterns defined in `gspec/stack.md`
|
|
104
|
-
b. **Follow the practices** — Adhere to coding standards, testing
|
|
105
|
-
c. **Follow the style** — Apply the design system, tokens, and
|
|
103
|
+
a. **Follow the stack** — Use the exact technologies, frameworks, and patterns defined in `gspec/stack.md`. The stack is the single authority for technology choices (testing tools, CI/CD platform, package manager). Where stack-specific practices (Section 15 of `stack.md`) conflict with general practices in `practices.md`, the stack's technology-specific guidance takes precedence for framework-specific concerns.
|
|
104
|
+
b. **Follow the practices** — Adhere to coding standards, testing philosophy, pipeline structure, and conventions from `gspec/practices.md`
|
|
105
|
+
c. **Follow the style** — Apply the design system, tokens, and icon library from `gspec/style.md`. The style is the single authority for icon library choices. Component libraries (e.g., shadcn/ui) are defined in `gspec/stack.md`.
|
|
106
106
|
d. **Satisfy the requirements** — Trace each piece of code back to a functional requirement in the feature PRD (if available) or to the user's stated goals and the approved implementation plan
|
|
107
107
|
3. **Mark capabilities as implemented** — After successfully implementing each capability, immediately update the feature PRD by changing its checkbox from `- [ ]` to `- [x]`. Do this incrementally as each capability is completed, not in a batch at the end. If a capability line did not have a checkbox prefix, add one as `- [x]`. This ensures that if the session is interrupted, progress is not lost. When updating gspec files, preserve existing `gspec-version` YAML frontmatter. If a file lacks frontmatter, add `---\ngspec-version: <<<VERSION>>>\n---` at the top.
|
|
108
108
|
4. **Run tests** — Execute the tests defined for this phase (and any existing tests to catch regressions). Fix any failures before proceeding.
|
|
@@ -34,8 +34,10 @@ You should:
|
|
|
34
34
|
- Focus on practices that matter for this specific project
|
|
35
35
|
- Avoid generic advice that doesn't apply
|
|
36
36
|
- **Do NOT include technology stack information** — this is documented separately
|
|
37
|
-
- **Do NOT prescribe specific testing frameworks, tools, or libraries** — focus on testing principles, patterns, and practices
|
|
37
|
+
- **Do NOT prescribe specific testing frameworks, tools, or libraries** — focus on testing principles, patterns, and practices. The stack document (`gspec/stack.md`) is the single authority for which test tools are used.
|
|
38
|
+
- **DO define CI/CD pipeline structure** — the practices document defines pipeline stages, gates, and ordering (lint → typecheck → test → build → deploy). The stack document defines which CI/CD platform technology is used (GitHub Actions, GitLab CI, etc.).
|
|
38
39
|
- **Mark sections as "Not Applicable"** when they don't apply to this project
|
|
40
|
+
- **Precedence rule**: Where this document conflicts with technology-specific practices in `gspec/stack.md`, the stack's technology-specific practices take precedence for framework-specific concerns (e.g., file naming conventions dictated by a framework). This document governs general engineering principles.
|
|
39
41
|
|
|
40
42
|
---
|
|
41
43
|
|
package/commands/gspec.stack.md
CHANGED
|
@@ -91,6 +91,8 @@ You should:
|
|
|
91
91
|
- Responsive design tooling
|
|
92
92
|
|
|
93
93
|
- **Note**: Visual design values (colors, typography, spacing) are documented separately as framework-agnostic design tokens; include here how the chosen CSS framework maps to those tokens
|
|
94
|
+
- **Component library** (if applicable) — e.g., shadcn/ui, Headless UI, Radix UI. Component libraries are framework-specific technology choices and belong in the stack, not the style guide.
|
|
95
|
+
- **Note**: Icon libraries (e.g., HeroIcons, Lucide) are defined in `gspec/style.md`, not here. The stack defines the CSS framework and component library; the style defines the icon set. Do NOT include an iconography section in the stack document.
|
|
94
96
|
|
|
95
97
|
### 5. Backend Stack
|
|
96
98
|
**Mark as N/A if this is a frontend-only or static site project**
|
|
@@ -129,9 +131,9 @@ You should:
|
|
|
129
131
|
- Scaling approach
|
|
130
132
|
|
|
131
133
|
#### CI/CD Pipeline
|
|
132
|
-
- CI/CD platform (GitHub Actions, GitLab CI, Jenkins, etc.)
|
|
133
|
-
-
|
|
134
|
-
-
|
|
134
|
+
- CI/CD platform technology (GitHub Actions, GitLab CI, Jenkins, etc.) and rationale
|
|
135
|
+
- Deployment automation and trigger configuration
|
|
136
|
+
- **Note**: The stack defines *which CI/CD technology* is used. The pipeline structure (stages, gates, ordering) is defined in `gspec/practices.md`. Include platform-specific configuration details here (e.g., workflow YAML format, runner setup), not pipeline philosophy.
|
|
135
137
|
|
|
136
138
|
#### Infrastructure as Code
|
|
137
139
|
- IaC tool (Terraform, CloudFormation, Pulumi, etc.)
|
|
@@ -189,10 +191,13 @@ You should:
|
|
|
189
191
|
|
|
190
192
|
### 10. Testing Infrastructure
|
|
191
193
|
|
|
194
|
+
> **The stack is the single authority for test tooling choices.** Define which frameworks and tools are used here. Testing philosophy, patterns, and coverage requirements are defined in `gspec/practices.md`.
|
|
195
|
+
|
|
192
196
|
#### Testing Frameworks
|
|
193
|
-
- Unit testing framework
|
|
197
|
+
- Unit testing framework (Vitest, Jest, pytest, etc.) and rationale
|
|
194
198
|
- Integration testing tools
|
|
195
|
-
- E2E testing framework (Playwright, Cypress, etc.)
|
|
199
|
+
- E2E testing framework (Playwright, Cypress, etc.) and rationale
|
|
200
|
+
- Component testing tools (if applicable)
|
|
196
201
|
|
|
197
202
|
#### Test Data Management
|
|
198
203
|
- Test database strategy
|
|
@@ -219,7 +224,7 @@ You should:
|
|
|
219
224
|
### 12. Development Tools
|
|
220
225
|
|
|
221
226
|
#### Package Management
|
|
222
|
-
- Package manager (npm, yarn, pnpm, pip, maven, etc.)
|
|
227
|
+
- **Package manager** — Explicitly declare the package manager (npm, yarn, pnpm, pip, maven, etc.) with rationale for the choice. This must be stated clearly so all other gspec commands and CI/CD configuration use the correct tool.
|
|
223
228
|
- Dependency management strategy
|
|
224
229
|
- Private package registry (if applicable)
|
|
225
230
|
|
package/commands/gspec.style.md
CHANGED
|
@@ -110,34 +110,27 @@ You should:
|
|
|
110
110
|
- Component color adjustments
|
|
111
111
|
- Contrast considerations
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
- How themes interact with the color palette
|
|
115
|
-
- Token mapping between themes
|
|
113
|
+
### 6. Component Styling
|
|
116
114
|
|
|
117
|
-
|
|
115
|
+
> **Focus on visual styling only** — colors, borders, typography, spacing, and state appearances. Do NOT define component structure, layout behavior, or interaction patterns (those belong in feature PRDs). The goal is to answer "what does it look like?" not "how does it work?"
|
|
118
116
|
|
|
119
117
|
#### Buttons
|
|
120
|
-
-
|
|
121
|
-
- States
|
|
122
|
-
- Sizes and
|
|
123
|
-
- Border radius
|
|
118
|
+
- Color treatments for primary, secondary, ghost variants
|
|
119
|
+
- States: default, hover, active, disabled appearances
|
|
120
|
+
- Sizes and border radius
|
|
124
121
|
|
|
125
122
|
#### Form Elements
|
|
126
|
-
- Input
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
- Validation states
|
|
123
|
+
- Input field colors, borders, and focus ring styles
|
|
124
|
+
- Label and helper text typography
|
|
125
|
+
- Validation state colors (error, success)
|
|
130
126
|
|
|
131
127
|
#### Cards & Containers
|
|
132
|
-
- Background colors
|
|
133
|
-
-
|
|
134
|
-
- Shadow elevations
|
|
135
|
-
- Corner radius
|
|
128
|
+
- Background colors and border styles
|
|
129
|
+
- Shadow elevations and corner radius
|
|
136
130
|
|
|
137
|
-
#### Navigation
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
- Active states
|
|
131
|
+
#### Navigation Elements
|
|
132
|
+
- Link colors: default, hover, active states
|
|
133
|
+
- Background treatments for navigation surfaces
|
|
141
134
|
|
|
142
135
|
### 7. Visual Effects
|
|
143
136
|
|
|
@@ -157,11 +150,13 @@ You should:
|
|
|
157
150
|
|
|
158
151
|
### 8. Iconography
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
|
|
153
|
+
> **The style guide is the single authority for icon library choices.** The stack document defines the CSS framework and component library (e.g., shadcn/ui); the style guide defines which icon set is used. This separation ensures icon decisions are driven by design rationale (visual consistency, stroke style) while component library decisions remain with the technology stack (framework compatibility).
|
|
154
|
+
|
|
155
|
+
#### Icon Library
|
|
156
|
+
- Specific icon library recommendation with rationale
|
|
157
|
+
- Outlined vs filled style
|
|
162
158
|
- Stroke width
|
|
163
159
|
- Size standards
|
|
164
|
-
- Icon library recommendation
|
|
165
160
|
|
|
166
161
|
#### Usage Guidelines
|
|
167
162
|
- When to use icons
|
|
@@ -28,7 +28,7 @@ Read **every** available gspec document in this order:
|
|
|
28
28
|
|
|
29
29
|
1. `gspec/profile.md` — Product identity, scope, audience, and positioning
|
|
30
30
|
2. `gspec/stack.md` — Technology choices, frameworks, infrastructure
|
|
31
|
-
3. `gspec/style.md` — Visual design language, tokens, component
|
|
31
|
+
3. `gspec/style.md` — Visual design language, tokens, component styling
|
|
32
32
|
4. `gspec/practices.md` — Development standards, testing, conventions
|
|
33
33
|
5. `gspec/architecture.md` — Technical blueprint: project structure, data model, API design, environment
|
|
34
34
|
6. `gspec/research.md` — Competitive analysis and feature proposals
|
|
@@ -45,7 +45,7 @@ All of these provide essential context. If any are missing, note the gap and mak
|
|
|
45
45
|
- Begin the file with YAML frontmatter containing the gspec version:
|
|
46
46
|
```
|
|
47
47
|
---
|
|
48
|
-
gspec-version: 1.
|
|
48
|
+
gspec-version: 1.10.0
|
|
49
49
|
---
|
|
50
50
|
```
|
|
51
51
|
The frontmatter must be the very first content in the file, before the main heading.
|
|
@@ -85,7 +85,7 @@ Feature PRDs are designed to be **portable across projects**. A feature spec wri
|
|
|
85
85
|
- Begin each file with YAML frontmatter containing the gspec version:
|
|
86
86
|
```
|
|
87
87
|
---
|
|
88
|
-
gspec-version: 1.
|
|
88
|
+
gspec-version: 1.10.0
|
|
89
89
|
---
|
|
90
90
|
```
|
|
91
91
|
The frontmatter must be the very first content in the file, before the main heading.
|
|
@@ -105,11 +105,11 @@ Present a brief scaffold summary to the user before proceeding to feature implem
|
|
|
105
105
|
|
|
106
106
|
1. **Announce the phase** — State which phase you're starting, what it covers, and what capabilities will be implemented
|
|
107
107
|
2. **Implement the phase:**
|
|
108
|
-
a. **Follow the stack** — Use the exact technologies, frameworks, and patterns defined in `gspec/stack.md`
|
|
109
|
-
b. **Follow the practices** — Adhere to coding standards, testing
|
|
110
|
-
c. **Follow the style** — Apply the design system, tokens, and
|
|
108
|
+
a. **Follow the stack** — Use the exact technologies, frameworks, and patterns defined in `gspec/stack.md`. The stack is the single authority for technology choices (testing tools, CI/CD platform, package manager). Where stack-specific practices (Section 15 of `stack.md`) conflict with general practices in `practices.md`, the stack's technology-specific guidance takes precedence for framework-specific concerns.
|
|
109
|
+
b. **Follow the practices** — Adhere to coding standards, testing philosophy, pipeline structure, and conventions from `gspec/practices.md`
|
|
110
|
+
c. **Follow the style** — Apply the design system, tokens, and icon library from `gspec/style.md`. The style is the single authority for icon library choices. Component libraries (e.g., shadcn/ui) are defined in `gspec/stack.md`.
|
|
111
111
|
d. **Satisfy the requirements** — Trace each piece of code back to a functional requirement in the feature PRD (if available) or to the user's stated goals and the approved implementation plan
|
|
112
|
-
3. **Mark capabilities as implemented** — After successfully implementing each capability, immediately update the feature PRD by changing its checkbox from `- [ ]` to `- [x]`. Do this incrementally as each capability is completed, not in a batch at the end. If a capability line did not have a checkbox prefix, add one as `- [x]`. This ensures that if the session is interrupted, progress is not lost. When updating gspec files, preserve existing `gspec-version` YAML frontmatter. If a file lacks frontmatter, add `---\ngspec-version: 1.
|
|
112
|
+
3. **Mark capabilities as implemented** — After successfully implementing each capability, immediately update the feature PRD by changing its checkbox from `- [ ]` to `- [x]`. Do this incrementally as each capability is completed, not in a batch at the end. If a capability line did not have a checkbox prefix, add one as `- [x]`. This ensures that if the session is interrupted, progress is not lost. When updating gspec files, preserve existing `gspec-version` YAML frontmatter. If a file lacks frontmatter, add `---\ngspec-version: 1.10.0\n---` at the top.
|
|
113
113
|
4. **Run tests** — Execute the tests defined for this phase (and any existing tests to catch regressions). Fix any failures before proceeding.
|
|
114
114
|
6. **Surface new gaps** — If implementation reveals new ambiguities, pause and consult the user rather than making silent assumptions
|
|
115
115
|
7. **Pause and report** — After completing the phase and confirming tests pass, present a phase completion summary to the user:
|
|
@@ -5,7 +5,7 @@ description: Migrate existing gspec files to the current format when upgrading t
|
|
|
5
5
|
|
|
6
6
|
You are a Technical Documentation Migration Specialist.
|
|
7
7
|
|
|
8
|
-
Your task is to update existing gspec specification documents to match the current gspec format (version 1.
|
|
8
|
+
Your task is to update existing gspec specification documents to match the current gspec format (version 1.10.0). You preserve all substantive content while ensuring documents follow the latest structural conventions.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -21,14 +21,14 @@ Scan the `gspec/` directory for all Markdown files:
|
|
|
21
21
|
For each file, check the YAML frontmatter at the top of the file:
|
|
22
22
|
- If the file starts with `---` followed by YAML content and another `---`, read the `gspec-version` field
|
|
23
23
|
- If no frontmatter exists, the file predates version tracking
|
|
24
|
-
- If `gspec-version` matches `1.
|
|
24
|
+
- If `gspec-version` matches `1.10.0`, the file is current — skip it
|
|
25
25
|
|
|
26
26
|
Present an inventory to the user:
|
|
27
27
|
|
|
28
28
|
> **gspec File Inventory:**
|
|
29
29
|
> - `gspec/profile.md` — no version (needs migration)
|
|
30
30
|
> - `gspec/stack.md` — version 1.0.3 (needs migration)
|
|
31
|
-
> - `gspec/style.md` — version 1.
|
|
31
|
+
> - `gspec/style.md` — version 1.10.0 (current, skipping)
|
|
32
32
|
> - `gspec/features/user-auth.md` — no version (needs migration)
|
|
33
33
|
|
|
34
34
|
Ask the user to confirm which files to migrate, or confirm all.
|
|
@@ -63,7 +63,7 @@ For each file to migrate:
|
|
|
63
63
|
5. **Add or update the frontmatter** — Ensure the file starts with:
|
|
64
64
|
```
|
|
65
65
|
---
|
|
66
|
-
gspec-version: 1.
|
|
66
|
+
gspec-version: 1.10.0
|
|
67
67
|
---
|
|
68
68
|
```
|
|
69
69
|
6. **Present the proposed changes** to the user before writing. Show what sections are being reorganized, what is being added, and confirm no content is being lost.
|
|
@@ -77,7 +77,7 @@ After migrating all files:
|
|
|
77
77
|
3. **Present a completion summary**:
|
|
78
78
|
|
|
79
79
|
> **Migration Complete:**
|
|
80
|
-
> - 4 files migrated to version 1.
|
|
80
|
+
> - 4 files migrated to version 1.10.0
|
|
81
81
|
> - 2 files were already current (skipped)
|
|
82
82
|
> - Content preserved in all files
|
|
83
83
|
> - Sections reorganized: [list any structural changes]
|
|
@@ -25,7 +25,7 @@ You should:
|
|
|
25
25
|
- Begin the file with YAML frontmatter containing the gspec version:
|
|
26
26
|
```
|
|
27
27
|
---
|
|
28
|
-
gspec-version: 1.
|
|
28
|
+
gspec-version: 1.10.0
|
|
29
29
|
---
|
|
30
30
|
```
|
|
31
31
|
The frontmatter must be the very first content in the file, before the main heading.
|
|
@@ -39,8 +39,10 @@ You should:
|
|
|
39
39
|
- Focus on practices that matter for this specific project
|
|
40
40
|
- Avoid generic advice that doesn't apply
|
|
41
41
|
- **Do NOT include technology stack information** — this is documented separately
|
|
42
|
-
- **Do NOT prescribe specific testing frameworks, tools, or libraries** — focus on testing principles, patterns, and practices
|
|
42
|
+
- **Do NOT prescribe specific testing frameworks, tools, or libraries** — focus on testing principles, patterns, and practices. The stack document (`gspec/stack.md`) is the single authority for which test tools are used.
|
|
43
|
+
- **DO define CI/CD pipeline structure** — the practices document defines pipeline stages, gates, and ordering (lint → typecheck → test → build → deploy). The stack document defines which CI/CD platform technology is used (GitHub Actions, GitLab CI, etc.).
|
|
43
44
|
- **Mark sections as "Not Applicable"** when they don't apply to this project
|
|
45
|
+
- **Precedence rule**: Where this document conflicts with technology-specific practices in `gspec/stack.md`, the stack's technology-specific practices take precedence for framework-specific concerns (e.g., file naming conventions dictated by a framework). This document governs general engineering principles.
|
|
44
46
|
|
|
45
47
|
---
|
|
46
48
|
|
|
@@ -162,7 +162,7 @@ After writing `gspec/research.md`, ask the user:
|
|
|
162
162
|
- Assumptions & Risks (assumptions, open questions, key risks and mitigations)
|
|
163
163
|
- Success Metrics
|
|
164
164
|
- Implementation Context (standard portability note)
|
|
165
|
-
- Begin the file with YAML frontmatter: `---\ngspec-version: 1.
|
|
165
|
+
- Begin the file with YAML frontmatter: `---\ngspec-version: 1.10.0\n---`
|
|
166
166
|
2. **Name the file** descriptively based on the feature (e.g., `gspec/features/csv-export.md`, `gspec/features/onboarding-wizard.md`)
|
|
167
167
|
3. **Keep the PRD portable** — use generic role descriptions (not project-specific persona names), define success metrics in terms of the feature's own outcomes (not project-level KPIs), and describe UX behavior generically (not tied to a specific design system). The PRD should be reusable across projects.
|
|
168
168
|
4. **Keep the PRD product-focused** — describe *what* and *why*, not *how*. Implementation details belong in the code, not the PRD.
|
|
@@ -181,7 +181,7 @@ After writing `gspec/research.md`, ask the user:
|
|
|
181
181
|
- Begin `gspec/research.md` with YAML frontmatter containing the gspec version:
|
|
182
182
|
```
|
|
183
183
|
---
|
|
184
|
-
gspec-version: 1.
|
|
184
|
+
gspec-version: 1.10.0
|
|
185
185
|
---
|
|
186
186
|
```
|
|
187
187
|
The frontmatter must be the very first content in the file, before the main heading.
|
|
@@ -198,7 +198,7 @@ The `gspec/research.md` file must follow this structure:
|
|
|
198
198
|
|
|
199
199
|
```markdown
|
|
200
200
|
---
|
|
201
|
-
gspec-version: 1.
|
|
201
|
+
gspec-version: 1.10.0
|
|
202
202
|
---
|
|
203
203
|
|
|
204
204
|
# Competitive Research
|