@c0x12c/spartan-ai-toolkit 1.2.0 → 1.3.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/README.md +6 -4
- package/VERSION +2 -1
- package/bin/cli.js +155 -31
- package/claude-md/00-header.md +2 -2
- package/claude-md/01-core.md +30 -8
- package/claude-md/20-frontend-react.md +2 -1
- package/claude-md/30-project-mgmt.md +1 -0
- package/claude-md/40-product.md +3 -1
- package/commands/spartan/brownfield.md +1 -1
- package/commands/spartan/build.md +22 -3
- package/commands/spartan/contribute.md +140 -0
- package/commands/spartan/epic.md +190 -0
- package/commands/spartan/kotlin-service.md +4 -4
- package/commands/spartan/map-codebase.md +1 -1
- package/commands/spartan/migration.md +1 -1
- package/commands/spartan/plan.md +210 -0
- package/commands/spartan/qa.md +222 -0
- package/commands/spartan/sessions.md +143 -0
- package/commands/spartan/spec.md +131 -0
- package/commands/spartan/testcontainer.md +1 -1
- package/commands/spartan/think.md +1 -1
- package/commands/spartan/workstreams.md +1 -1
- package/commands/spartan.md +142 -2
- package/lib/assembler.js +147 -2
- package/lib/assembler.test.js +159 -0
- package/lib/detector.js +166 -0
- package/lib/detector.test.js +221 -0
- package/lib/resolver.js +129 -1
- package/lib/resolver.test.js +159 -1
- package/package.json +2 -2
- package/packs/core.yaml +4 -1
- package/packs/frontend-react.yaml +2 -0
- package/packs/packs.compiled.json +10 -4
- package/packs/project-mgmt.yaml +1 -0
- package/skills/browser-qa/SKILL.md +180 -0
- package/skills/database-table-creator/SKILL.md +12 -394
- package/skills/database-table-creator/kotlin-templates.md +400 -0
- package/skills/database-table-creator/migration-template.sql +1 -1
- package/templates/epic.md +1 -1
- package/commands/spartan/quickplan.md +0 -122
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"plugins": [
|
|
9
9
|
{
|
|
10
10
|
"name": "spartan-ai-toolkit",
|
|
11
|
-
"description": "5 workflows,
|
|
11
|
+
"description": "5 workflows, 53 commands, 11 rules, 19 skills, 4 agents — organized in 11 packs with dependencies",
|
|
12
12
|
"source": "./toolkit",
|
|
13
|
-
"version": "1.
|
|
13
|
+
"version": "1.3.0"
|
|
14
14
|
}
|
|
15
15
|
]
|
|
16
16
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spartan-ai-toolkit",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Engineering discipline layer for Claude Code — 5 workflows,
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Engineering discipline layer for Claude Code — 5 workflows, 53 commands, 11 rules, 19 skills, 4 agents organized in 11 packs",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Khoa Tran",
|
|
7
7
|
"url": "https://github.com/spartan-stratos"
|
package/README.md
CHANGED
|
@@ -66,7 +66,8 @@ After install, open any project, run `claude`, then type `/spartan`.
|
|
|
66
66
|
**Direct commands** — one command, one job. Best when you know what step you need. Saves tokens.
|
|
67
67
|
|
|
68
68
|
```
|
|
69
|
-
/spartan:
|
|
69
|
+
/spartan:spec "feature" ← write the spec
|
|
70
|
+
/spartan:plan "feature" ← plan the implementation
|
|
70
71
|
/spartan:review ← just the code review
|
|
71
72
|
/spartan:pr-ready ← just the PR creation
|
|
72
73
|
/spartan:migration "desc" ← just the migration
|
|
@@ -135,7 +136,7 @@ npx @c0x12c/spartan-ai-toolkit@latest --all
|
|
|
135
136
|
|
|
136
137
|
| Pack | Category | Depends on | What you get |
|
|
137
138
|
|------|----------|------------|--------------|
|
|
138
|
-
| **core** | Core | — | Always installed. Workflows (build, fix, onboard),
|
|
139
|
+
| **core** | Core | — | Always installed. Workflows (build, fix, onboard), spec, plan, pr-ready, daily, safety commands |
|
|
139
140
|
| **backend-micronaut** | Backend | database, shared-backend | Kotlin service scaffold, code review, testcontainers, API/DB/Kotlin rules, 5 skills, 2 agents |
|
|
140
141
|
| **backend-nodejs** | Backend | database, shared-backend | Coming soon |
|
|
141
142
|
| **backend-python** | Backend | database, shared-backend | Coming soon |
|
|
@@ -151,7 +152,7 @@ Hidden packs (`database`, `shared-backend`) get pulled in as dependencies — yo
|
|
|
151
152
|
|
|
152
153
|
## Commands
|
|
153
154
|
|
|
154
|
-
All commands start with `/spartan:` (e.g., `/spartan:
|
|
155
|
+
All commands start with `/spartan:` (e.g., `/spartan:spec "feature"`).
|
|
155
156
|
|
|
156
157
|
Type `/spartan` to get the smart router — it asks what you need and picks the right command.
|
|
157
158
|
|
|
@@ -167,7 +168,8 @@ Type `/spartan` to get the smart router — it asks what you need and picks the
|
|
|
167
168
|
### Core (always installed)
|
|
168
169
|
| Command | What it does |
|
|
169
170
|
|---------|-------------|
|
|
170
|
-
| `
|
|
171
|
+
| `spec "feature"` | Write a feature spec — saves to `.planning/specs/` |
|
|
172
|
+
| `plan "feature"` | Write implementation plan from spec — saves to `.planning/plans/` |
|
|
171
173
|
| `daily` | Standup summary from git history |
|
|
172
174
|
| `pr-ready` | Full checklist before creating any PR |
|
|
173
175
|
| `init-project` | Auto-generate CLAUDE.md from codebase scan |
|
package/VERSION
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.3.0
|
|
2
|
+
|
package/bin/cli.js
CHANGED
|
@@ -48,11 +48,15 @@ function blue(s) { return `${C.blue}${s}${C.reset}`; }
|
|
|
48
48
|
|
|
49
49
|
// ── Pack definitions (loaded from YAML manifests) ───────────────
|
|
50
50
|
import { PACKS, PACK_ORDER } from '../lib/packs.js';
|
|
51
|
-
import { assembleCLAUDEmd } from '../lib/assembler.js';
|
|
52
|
-
import { resolve as resolveDeps, resolveAliases, loadManifests } from '../lib/resolver.js';
|
|
51
|
+
import { assembleCLAUDEmd, assembleAGENTSmd } from '../lib/assembler.js';
|
|
52
|
+
import { resolve as resolveDeps, resolveAliases, loadManifests, loadExternalPacks } from '../lib/resolver.js';
|
|
53
|
+
import { detectStacks } from '../lib/detector.js';
|
|
53
54
|
|
|
54
55
|
const manifests = loadManifests(join(PKG_ROOT, 'packs'));
|
|
55
56
|
|
|
57
|
+
// Maps community pack names to their source directory (for file resolution)
|
|
58
|
+
const externalPackSources = {};
|
|
59
|
+
|
|
56
60
|
// ── Parse args ──────────────────────────────────────────────────
|
|
57
61
|
const args = process.argv.slice(2);
|
|
58
62
|
|
|
@@ -61,12 +65,18 @@ let packsArg = '';
|
|
|
61
65
|
let installAll = false;
|
|
62
66
|
let mode = 'global'; // default for claude-code
|
|
63
67
|
let showHelp = false;
|
|
68
|
+
let format = ''; // '' = default, 'agents-md' = export AGENTS.md
|
|
69
|
+
let autoDetect = false;
|
|
70
|
+
let packDirArg = ''; // external community pack directory
|
|
64
71
|
|
|
65
72
|
for (const arg of args) {
|
|
66
73
|
if (arg === '--help' || arg === '-h') showHelp = true;
|
|
67
74
|
else if (arg.startsWith('--agent=')) agent = arg.split('=')[1];
|
|
68
75
|
else if (arg.startsWith('--packs=')) packsArg = arg.split('=')[1];
|
|
76
|
+
else if (arg.startsWith('--format=')) format = arg.split('=')[1];
|
|
77
|
+
else if (arg.startsWith('--pack-dir=')) packDirArg = arg.split('=')[1];
|
|
69
78
|
else if (arg === '--all') installAll = true;
|
|
79
|
+
else if (arg === '--auto') autoDetect = true;
|
|
70
80
|
else if (arg === '--global') mode = 'global';
|
|
71
81
|
else if (arg === '--local') mode = 'local';
|
|
72
82
|
}
|
|
@@ -100,6 +110,9 @@ if (showHelp) {
|
|
|
100
110
|
Choices: claude-code, cursor, windsurf, codex, copilot
|
|
101
111
|
--packs=LIST Comma-separated packs (claude-code only)
|
|
102
112
|
Example: --packs=backend-micronaut,product
|
|
113
|
+
--auto Auto-detect tech stack and suggest packs (no menu)
|
|
114
|
+
--pack-dir=DIR Load community packs from an external directory
|
|
115
|
+
--format=NAME Output format: agents-md (exports AGENTS.md for cross-tool use)
|
|
103
116
|
--all Install all packs
|
|
104
117
|
--global Install to home dir (default for claude-code/codex)
|
|
105
118
|
--local Install to current project dir
|
|
@@ -124,6 +137,12 @@ ${lines.join('\n')}`).join('\n')}
|
|
|
124
137
|
|
|
125
138
|
${cyan('npx spartan-ai-toolkit@latest --agent=cursor')}
|
|
126
139
|
Install rules for Cursor (rules + AGENTS.md only)
|
|
140
|
+
|
|
141
|
+
${cyan('npx spartan-ai-toolkit@latest --auto')}
|
|
142
|
+
Auto-detect your tech stack and install matching packs
|
|
143
|
+
|
|
144
|
+
${cyan('npx spartan-ai-toolkit@latest --format=agents-md --packs=backend-micronaut')}
|
|
145
|
+
Export AGENTS.md for any AI coding tool
|
|
127
146
|
`);
|
|
128
147
|
process.exit(0);
|
|
129
148
|
}
|
|
@@ -220,6 +239,11 @@ function copyDir(src, dest) {
|
|
|
220
239
|
cpSync(src, dest, { recursive: true });
|
|
221
240
|
}
|
|
222
241
|
|
|
242
|
+
/** Get the source root for a pack (built-in uses PKG_ROOT, community uses pack-dir). */
|
|
243
|
+
function getPackSource(packName) {
|
|
244
|
+
return externalPackSources[packName] || PKG_ROOT;
|
|
245
|
+
}
|
|
246
|
+
|
|
223
247
|
/** Get all items for a category across selected packs, deduplicated. */
|
|
224
248
|
function gatherItems(selectedPacks, category) {
|
|
225
249
|
const seen = new Set();
|
|
@@ -237,6 +261,24 @@ function gatherItems(selectedPacks, category) {
|
|
|
237
261
|
return result;
|
|
238
262
|
}
|
|
239
263
|
|
|
264
|
+
/** Like gatherItems but includes the source root for each item (for community pack support). */
|
|
265
|
+
function gatherItemsWithSource(selectedPacks, category) {
|
|
266
|
+
const seen = new Set();
|
|
267
|
+
const result = [];
|
|
268
|
+
for (const pack of selectedPacks) {
|
|
269
|
+
const def = PACKS[pack];
|
|
270
|
+
if (!def) continue;
|
|
271
|
+
const srcRoot = getPackSource(pack);
|
|
272
|
+
for (const item of def[category]) {
|
|
273
|
+
if (!seen.has(item)) {
|
|
274
|
+
seen.add(item);
|
|
275
|
+
result.push({ item, srcRoot });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
280
|
+
}
|
|
281
|
+
|
|
240
282
|
// ── Pack selection (grouped menu) ───────────────────────────────
|
|
241
283
|
async function selectPacks(targets) {
|
|
242
284
|
// --all flag
|
|
@@ -253,6 +295,44 @@ async function selectPacks(targets) {
|
|
|
253
295
|
return resolveDeps(aliased, manifests);
|
|
254
296
|
}
|
|
255
297
|
|
|
298
|
+
// --auto flag: detect tech stack
|
|
299
|
+
if (autoDetect) {
|
|
300
|
+
const cwd = process.cwd();
|
|
301
|
+
console.log(`\n ${blue('Scanning')} ${dim(cwd)} ${blue('for tech stack...')}\n`);
|
|
302
|
+
const { detected, comingSoon } = detectStacks(cwd);
|
|
303
|
+
|
|
304
|
+
if (detected.length > 0) {
|
|
305
|
+
console.log(` ${bold('Detected stacks:')}`);
|
|
306
|
+
for (const d of detected) {
|
|
307
|
+
console.log(` ${green('✓')} ${bold(d.pack)} ${dim(`(${d.reason})`)}`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (comingSoon.length > 0) {
|
|
311
|
+
console.log('');
|
|
312
|
+
for (const d of comingSoon) {
|
|
313
|
+
console.log(` ${yellow('~')} ${d.pack} ${dim(`(${d.reason})`)} ${dim('— coming soon, skipped')}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
console.log('');
|
|
317
|
+
|
|
318
|
+
const packNames = detected.map(d => d.pack);
|
|
319
|
+
const confirm = await ask(` Install ${bold(packNames.join(' + '))}? [Y/n]: `);
|
|
320
|
+
if (confirm !== 'n' && confirm !== 'N') {
|
|
321
|
+
return resolveDeps(packNames, manifests);
|
|
322
|
+
}
|
|
323
|
+
// User said no — fall through to interactive menu
|
|
324
|
+
console.log('');
|
|
325
|
+
} else {
|
|
326
|
+
console.log(` ${dim('No stacks detected.')}`);
|
|
327
|
+
if (comingSoon.length > 0) {
|
|
328
|
+
for (const d of comingSoon) {
|
|
329
|
+
console.log(` ${yellow('~')} ${d.pack} ${dim(`(${d.reason})`)} ${dim('— coming soon')}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
console.log(` ${dim('Falling back to interactive menu...')}\n`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
256
336
|
// Check saved packs
|
|
257
337
|
if (existsSync(targets.packsFile)) {
|
|
258
338
|
let saved = readFileSync(targets.packsFile, 'utf-8').trim().split('\n').filter(Boolean);
|
|
@@ -358,9 +438,9 @@ async function installFull() {
|
|
|
358
438
|
cmdCount++;
|
|
359
439
|
}
|
|
360
440
|
|
|
361
|
-
const selectedCommands =
|
|
362
|
-
for (const cmd of selectedCommands) {
|
|
363
|
-
const src = join(
|
|
441
|
+
const selectedCommands = gatherItemsWithSource(selectedPacks, 'commands');
|
|
442
|
+
for (const { item: cmd, srcRoot } of selectedCommands) {
|
|
443
|
+
const src = join(srcRoot, 'commands', 'spartan', `${cmd}.md`);
|
|
364
444
|
if (existsSync(src)) {
|
|
365
445
|
copyFile(src, join(targets.commands, `${cmd}.md`));
|
|
366
446
|
console.log(` ${green('+')} /spartan:${cmd}`);
|
|
@@ -372,14 +452,13 @@ async function installFull() {
|
|
|
372
452
|
console.log(` ${bold(cmdCount + ' commands')} installed\n`);
|
|
373
453
|
|
|
374
454
|
// 3) Rules (now with subdirectory structure)
|
|
375
|
-
const
|
|
376
|
-
if (
|
|
455
|
+
const rulesWithSource = gatherItemsWithSource(selectedPacks, 'rules');
|
|
456
|
+
if (rulesWithSource.length > 0) {
|
|
377
457
|
console.log(`${blue('[3/5]')} ${bold('Installing rules...')}`);
|
|
378
458
|
let ruleCount = 0;
|
|
379
459
|
|
|
380
|
-
for (const rule of
|
|
381
|
-
|
|
382
|
-
const src = join(SRC.rules, rule);
|
|
460
|
+
for (const { item: rule, srcRoot } of rulesWithSource) {
|
|
461
|
+
const src = join(srcRoot, 'rules', rule);
|
|
383
462
|
const dest = join(targets.rules, rule);
|
|
384
463
|
if (existsSync(src)) {
|
|
385
464
|
copyFile(src, dest);
|
|
@@ -393,14 +472,14 @@ async function installFull() {
|
|
|
393
472
|
}
|
|
394
473
|
|
|
395
474
|
// 4) Skills
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
475
|
+
const skillsWithSource = gatherItemsWithSource(selectedPacks, 'skills');
|
|
476
|
+
if (skillsWithSource.length > 0) {
|
|
398
477
|
console.log(`${blue('[4/5]')} ${bold('Installing skills...')}`);
|
|
399
478
|
ensureDir(targets.skills);
|
|
400
479
|
let skillCount = 0;
|
|
401
480
|
|
|
402
|
-
for (const skill of
|
|
403
|
-
const src = join(
|
|
481
|
+
for (const { item: skill, srcRoot } of skillsWithSource) {
|
|
482
|
+
const src = join(srcRoot, 'skills', skill);
|
|
404
483
|
if (existsSync(src)) {
|
|
405
484
|
copyDir(src, join(targets.skills, skill));
|
|
406
485
|
console.log(` ${green('+')} ${skill}`);
|
|
@@ -413,14 +492,14 @@ async function installFull() {
|
|
|
413
492
|
}
|
|
414
493
|
|
|
415
494
|
// 5) Agents
|
|
416
|
-
const
|
|
417
|
-
if (
|
|
495
|
+
const agentsWithSource = gatherItemsWithSource(selectedPacks, 'agents');
|
|
496
|
+
if (agentsWithSource.length > 0) {
|
|
418
497
|
console.log(`${blue('[5/5]')} ${bold('Installing agents...')}`);
|
|
419
498
|
ensureDir(targets.agents);
|
|
420
499
|
let agentCount = 0;
|
|
421
500
|
|
|
422
|
-
for (const agentFile of
|
|
423
|
-
const src = join(
|
|
501
|
+
for (const { item: agentFile, srcRoot } of agentsWithSource) {
|
|
502
|
+
const src = join(srcRoot, 'agents', agentFile);
|
|
424
503
|
if (existsSync(src)) {
|
|
425
504
|
copyFile(src, join(targets.agents, agentFile));
|
|
426
505
|
console.log(` ${green('+')} ${agentFile.replace('.md', '')}`);
|
|
@@ -495,23 +574,15 @@ async function installRulesOnly() {
|
|
|
495
574
|
console.log(`\n${blue('[1/2]')} ${bold('Rules')} — ${dim('no rule packs selected')}\n`);
|
|
496
575
|
}
|
|
497
576
|
|
|
498
|
-
// Install AGENTS.md
|
|
577
|
+
// Install AGENTS.md — assembled from pack sections + agents
|
|
499
578
|
console.log(`${blue('[2/2]')} ${bold('Installing AGENTS.md...')}`);
|
|
500
579
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
agentsContent += 'Expert agents for your AI coding assistant.\n\n---\n\n';
|
|
505
|
-
for (const agentFile of allAgents) {
|
|
506
|
-
const src = join(SRC.agents, agentFile);
|
|
507
|
-
if (existsSync(src)) {
|
|
508
|
-
agentsContent += readFileSync(src, 'utf-8') + '\n\n---\n\n';
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
writeFileSync(targets.agentsMd, agentsContent.trimEnd() + '\n', 'utf-8');
|
|
580
|
+
if (targets.agentsMd) {
|
|
581
|
+
const agentsContent = assembleAGENTSmd(SRC.claudeMd, SRC.agents, selectedPacks, PACKS);
|
|
582
|
+
writeFileSync(targets.agentsMd, agentsContent, 'utf-8');
|
|
512
583
|
console.log(` ${green('+')} AGENTS.md\n`);
|
|
513
584
|
} else {
|
|
514
|
-
console.log(` ${dim('No
|
|
585
|
+
console.log(` ${dim('No AGENTS.md target')}\n`);
|
|
515
586
|
}
|
|
516
587
|
|
|
517
588
|
// Save selection
|
|
@@ -538,6 +609,49 @@ async function main() {
|
|
|
538
609
|
process.exit(1);
|
|
539
610
|
}
|
|
540
611
|
|
|
612
|
+
// Load community packs if --pack-dir is set
|
|
613
|
+
if (packDirArg) {
|
|
614
|
+
const packDirPath = pathResolve(process.cwd(), packDirArg);
|
|
615
|
+
const builtinNames = new Set(manifests.keys());
|
|
616
|
+
console.log(`\n ${blue('Loading community packs from')} ${dim(packDirPath)}`);
|
|
617
|
+
const { loaded, errors } = loadExternalPacks(packDirPath, builtinNames);
|
|
618
|
+
|
|
619
|
+
if (errors.length > 0) {
|
|
620
|
+
for (const err of errors) {
|
|
621
|
+
console.log(` ${yellow('!')} ${err}`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (loaded.size > 0) {
|
|
626
|
+
for (const [name, manifest] of loaded) {
|
|
627
|
+
manifests.set(name, manifest);
|
|
628
|
+
externalPackSources[name] = packDirPath;
|
|
629
|
+
// Add to PACKS and PACK_ORDER so menus and install work
|
|
630
|
+
PACKS[name] = {
|
|
631
|
+
description: manifest.description,
|
|
632
|
+
category: manifest.category || 'Community',
|
|
633
|
+
priority: manifest.priority ?? 500,
|
|
634
|
+
hidden: manifest.hidden || false,
|
|
635
|
+
comingSoon: manifest['coming-soon'] || false,
|
|
636
|
+
depends: manifest.depends || [],
|
|
637
|
+
commands: manifest.commands || [],
|
|
638
|
+
rules: manifest.rules || [],
|
|
639
|
+
skills: manifest.skills || [],
|
|
640
|
+
agents: manifest.agents || [],
|
|
641
|
+
claudeSections: manifest['claude-sections'] || [],
|
|
642
|
+
};
|
|
643
|
+
PACK_ORDER.push(name);
|
|
644
|
+
}
|
|
645
|
+
// Re-sort PACK_ORDER by priority
|
|
646
|
+
PACK_ORDER.sort((a, b) => (PACKS[a]?.priority ?? 999) - (PACKS[b]?.priority ?? 999));
|
|
647
|
+
|
|
648
|
+
const names = [...loaded.keys()].join(', ');
|
|
649
|
+
console.log(` ${green('+')} Loaded: ${bold(names)}\n`);
|
|
650
|
+
} else {
|
|
651
|
+
console.log(` ${dim('No valid community packs found')}\n`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
541
655
|
let selectedPacks;
|
|
542
656
|
|
|
543
657
|
try {
|
|
@@ -554,6 +668,16 @@ async function main() {
|
|
|
554
668
|
closeRL();
|
|
555
669
|
}
|
|
556
670
|
|
|
671
|
+
// Export AGENTS.md alongside normal install when --format=agents-md
|
|
672
|
+
if (format === 'agents-md' && (agent === 'claude-code' || agent === 'codex')) {
|
|
673
|
+
const cwd = process.cwd();
|
|
674
|
+
const agentsMdPath = join(cwd, 'AGENTS.md');
|
|
675
|
+
console.log(`${blue('[+]')} ${bold('Exporting AGENTS.md for cross-tool use...')}`);
|
|
676
|
+
const agentsContent = assembleAGENTSmd(SRC.claudeMd, SRC.agents, selectedPacks, PACKS);
|
|
677
|
+
writeFileSync(agentsMdPath, agentsContent, 'utf-8');
|
|
678
|
+
console.log(` ${green('+')} AGENTS.md (works with Cursor, Copilot, Windsurf, Codex, and 20+ tools)\n`);
|
|
679
|
+
}
|
|
680
|
+
|
|
557
681
|
// Success
|
|
558
682
|
const userPacks = selectedPacks.filter(p => !PACKS[p]?.hidden);
|
|
559
683
|
console.log(`${bold(green('================================================'))}`);
|
package/claude-md/00-header.md
CHANGED
|
@@ -34,6 +34,6 @@ What do you need?
|
|
|
34
34
|
| Size | Use |
|
|
35
35
|
|---|---|
|
|
36
36
|
| < 30 min, ≤ 3 files | Just ask Claude (no command needed) |
|
|
37
|
-
| < 1 day | `/spartan:
|
|
38
|
-
| 1–3 days | `/spartan:
|
|
37
|
+
| < 1 day | `/spartan:spec` → `/spartan:build` |
|
|
38
|
+
| 1–3 days | `/spartan:spec` → `/spartan:plan` → `/spartan:build` |
|
|
39
39
|
| > 3 days, multi-session | `/spartan:project new` (full lifecycle) |
|
package/claude-md/01-core.md
CHANGED
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
|
|
4
4
|
## Core Principles (Always Enforce)
|
|
5
5
|
|
|
6
|
-
### 1.
|
|
7
|
-
|
|
6
|
+
### 1. Match the User's Language
|
|
7
|
+
**Detect the language of the user's message and respond entirely in that same language.** This is not optional — it overrides the default English behavior of all commands. If the user writes in Vietnamese, ALL output must be in Vietnamese. If in French, respond in French. If in English, respond in English. This applies to everything: explanations, questions, gate prompts, debug reports, summaries, and PR descriptions. Only code syntax, variable names, file paths, and command names (e.g., `/spartan:fix`) stay in their original form.
|
|
8
|
+
|
|
9
|
+
### 2. Spec Before Code
|
|
10
|
+
- Task < 1 day → `/spartan:spec` + `/spartan:plan` + `/spartan:build`
|
|
8
11
|
- Task > 1 day → `/spartan:project new` or `/spartan:project milestone-new`
|
|
9
12
|
- Never write production code without a written spec or plan
|
|
10
13
|
|
|
11
|
-
###
|
|
14
|
+
### 3. TDD is Non-Negotiable
|
|
12
15
|
- Red → Green → Refactor, always
|
|
13
16
|
- Write tests first, then the code that makes them pass
|
|
14
17
|
|
|
15
|
-
###
|
|
18
|
+
### 4. Atomic Commits
|
|
16
19
|
Each commit = one task, tests passing:
|
|
17
20
|
```
|
|
18
21
|
type(scope): what changed
|
|
@@ -21,7 +24,7 @@ type(scope): what changed
|
|
|
21
24
|
```
|
|
22
25
|
Types: `feat` · `fix` · `test` · `refactor` · `chore` · `docs`
|
|
23
26
|
|
|
24
|
-
###
|
|
27
|
+
### 5. Context Hygiene (Auto-Managed)
|
|
25
28
|
Claude proactively manages its own context window:
|
|
26
29
|
- When detecting context pressure (slow responses, forgetting earlier context, long conversation) → auto-run `/compact` to summarize and free space
|
|
27
30
|
- If compaction isn't enough → auto-save critical state to `.handoff/` and `.memory/`, then tell user to start a fresh session
|
|
@@ -35,7 +38,7 @@ Claude proactively manages its own context window:
|
|
|
35
38
|
- Response quality dropping → warn user + compact
|
|
36
39
|
- Multi-step command taking unusually long → consider compacting between steps
|
|
37
40
|
|
|
38
|
-
###
|
|
41
|
+
### 6. Auto Mode
|
|
39
42
|
When user says **"auto on"** or **"auto mode"**, all Spartan commands skip confirmation prompts and execute straight through. Claude will:
|
|
40
43
|
- Show the spec/plan/output but NOT pause to ask "does this match?" or "shall I proceed?"
|
|
41
44
|
- Continue to the next step automatically after each step completes
|
|
@@ -46,7 +49,7 @@ Turn off with **"auto off"**. Default is **auto off** (commands ask for confirma
|
|
|
46
49
|
|
|
47
50
|
Auto mode is ideal for experienced users who trust the workflow and want maximum velocity.
|
|
48
51
|
|
|
49
|
-
###
|
|
52
|
+
### 7. Safety Guardrails
|
|
50
53
|
|
|
51
54
|
| Command | What it does |
|
|
52
55
|
|---|---|
|
|
@@ -58,6 +61,19 @@ Auto mode is ideal for experienced users who trust the workflow and want maximum
|
|
|
58
61
|
|
|
59
62
|
## Core Commands (always available)
|
|
60
63
|
|
|
64
|
+
### Feature Workflow
|
|
65
|
+
```
|
|
66
|
+
/spartan:epic → /spartan:spec → [/spartan:design] → /spartan:plan → /spartan:build → /spartan:pr-ready
|
|
67
|
+
↑ ↑ ↑ ↑
|
|
68
|
+
Gate 1 Gate 2 Gate 3 Gate 4
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| Size | Path |
|
|
72
|
+
|---|---|
|
|
73
|
+
| Single feature | `/spartan:spec` → `/spartan:plan` → `/spartan:build` |
|
|
74
|
+
| Batch of features (1-2 weeks) | `/spartan:epic` → then spec/plan/build each feature |
|
|
75
|
+
| Multi-week project | `/spartan:project new` → milestones + phases |
|
|
76
|
+
|
|
61
77
|
### Workflows (start here)
|
|
62
78
|
| Command | Purpose |
|
|
63
79
|
|---|---|
|
|
@@ -66,10 +82,16 @@ Auto mode is ideal for experienced users who trust the workflow and want maximum
|
|
|
66
82
|
| `/spartan:fix "symptom"` | Bug workflow: reproduce → investigate → fix → PR |
|
|
67
83
|
| `/spartan:onboard` | Codebase understanding: scan → map → setup |
|
|
68
84
|
|
|
85
|
+
### Spec & Plan (saved artifacts)
|
|
86
|
+
| Command | Purpose |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `/spartan:spec "feature"` | Write a feature spec → saves to `.planning/specs/` → Gate 1 |
|
|
89
|
+
| `/spartan:plan "feature"` | Write implementation plan from spec → saves to `.planning/plans/` → Gate 2 |
|
|
90
|
+
| `/spartan:epic "name"` | Break big work into ordered features → saves to `.planning/epics/` |
|
|
91
|
+
|
|
69
92
|
### Individual Commands
|
|
70
93
|
| Command | Purpose |
|
|
71
94
|
|---|---|
|
|
72
|
-
| `/spartan:quickplan "task"` | Spec + plan + branch in one shot (< 1 day) |
|
|
73
95
|
| `/spartan:pr-ready` | Pre-PR checklist + auto PR description |
|
|
74
96
|
| `/spartan:daily` | Standup summary from git log |
|
|
75
97
|
| `/spartan:init-project` | Auto-generate CLAUDE.md from codebase |
|
|
@@ -27,7 +27,7 @@ See `templates/workflow-frontend-react.md` for the full workflow with:
|
|
|
27
27
|
- File location guide (App Router conventions)
|
|
28
28
|
- Parallel vs sequential task planning
|
|
29
29
|
|
|
30
|
-
For
|
|
30
|
+
For any feature, use `/spartan:spec` → `/spartan:plan` → `/spartan:build`.
|
|
31
31
|
|
|
32
32
|
### Frontend Skills
|
|
33
33
|
|
|
@@ -42,3 +42,4 @@ For small tasks (< 1 day), `/spartan:quickplan` covers spec + plan in one shot.
|
|
|
42
42
|
| `/spartan:fe-review` | PR review with Next.js App Router conventions |
|
|
43
43
|
| `/spartan:figma-to-code [url]` | Convert Figma screen to production code via MCP |
|
|
44
44
|
| `/spartan:e2e [feature]` | Scaffold Playwright E2E testing |
|
|
45
|
+
| `/spartan:qa [url] [feature]` | Real browser QA — opens Chromium, tests flows, finds bugs |
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
| Command | Purpose |
|
|
7
7
|
|---|---|
|
|
8
|
+
| `/spartan:epic "name"` | Break big work into ordered features → each goes through spec → plan → build |
|
|
8
9
|
| `/spartan:project [action]` | Manage large projects: `new`, `status`, `milestone-new`, `milestone-complete`, `milestone-summary`, `manager` |
|
|
9
10
|
| `/spartan:phase [action] [N]` | Manage phases: `discuss`, `plan`, `execute`, `verify` |
|
|
10
11
|
| `/spartan:workstreams [action]` | Parallel workstreams: `list`, `create`, `switch`, `status`, `progress`, `complete`, `resume` |
|
package/claude-md/40-product.md
CHANGED
|
@@ -19,7 +19,9 @@ These commands help you think deep before writing code. Use them when starting a
|
|
|
19
19
|
↓
|
|
20
20
|
/spartan:think "feature" ← 6-phase deep thinking before code
|
|
21
21
|
↓
|
|
22
|
-
/spartan:
|
|
22
|
+
/spartan:spec "task" ← Write the spec
|
|
23
|
+
/spartan:plan "task" ← Plan the work
|
|
24
|
+
/spartan:build "task" ← Then build it
|
|
23
25
|
```
|
|
24
26
|
|
|
25
27
|
You don't have to use all of them. Pick what fits your stage.
|
|
@@ -154,4 +154,4 @@ This prevents scope creep and keeps each change independently reviewable.
|
|
|
154
154
|
|
|
155
155
|
After analysis, present the Context Map summary and ask:
|
|
156
156
|
"Analysis complete. What change would you like to make first?
|
|
157
|
-
I'll create a change folder and use `/spartan:
|
|
157
|
+
I'll create a change folder and use `/spartan:spec` → `/spartan:build` for it."
|
|
@@ -52,13 +52,21 @@ ls .planning/PROJECT.md 2>/dev/null && echo "GSD_ACTIVE"
|
|
|
52
52
|
|
|
53
53
|
## Stage 1: Understand
|
|
54
54
|
|
|
55
|
-
**
|
|
55
|
+
**First, check for a saved spec:**
|
|
56
|
+
```bash
|
|
57
|
+
ls .planning/specs/*.md 2>/dev/null
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If a spec exists for this feature (matching the feature name), read it and use it as the scope. Skip the 3 questions — the spec already answered them. Show:
|
|
61
|
+
> "Found spec: `.planning/specs/{name}.md` — using it as scope."
|
|
62
|
+
|
|
63
|
+
If no spec exists, **ask 3 forcing questions. Always. Even in auto mode.**
|
|
56
64
|
|
|
57
65
|
1. **"What pain does this solve?"** — Not the feature. The pain. If the user says "add a profiles endpoint" ask what user problem it fixes.
|
|
58
66
|
2. **"What's the narrowest version we can ship?"** — Force MVP thinking. Cut scope until it hurts.
|
|
59
67
|
3. **"What assumption could be wrong?"** — Surface hidden risks early.
|
|
60
68
|
|
|
61
|
-
After the user answers, produce a scope block:
|
|
69
|
+
After the user answers (or after reading the spec), produce a scope block:
|
|
62
70
|
|
|
63
71
|
```markdown
|
|
64
72
|
## Scope: [feature name]
|
|
@@ -86,10 +94,21 @@ After the user answers, produce a scope block:
|
|
|
86
94
|
|
|
87
95
|
## Stage 2: Plan
|
|
88
96
|
|
|
97
|
+
### Check for saved plan
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
ls .planning/plans/*.md 2>/dev/null
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
If a plan exists for this feature, read it and use it. Skip the inline planning — go straight to Stage 3 (Implement). Show:
|
|
104
|
+
> "Found plan: `.planning/plans/{name}.md` — using it."
|
|
105
|
+
|
|
106
|
+
If no plan exists, do the size check below.
|
|
107
|
+
|
|
89
108
|
### Size check
|
|
90
109
|
|
|
91
110
|
Count the expected work:
|
|
92
|
-
- **Small** (1-4 tasks, < 1 day): Inline plan right here.
|
|
111
|
+
- **Small** (1-4 tasks, < 1 day): Inline plan right here.
|
|
93
112
|
- **Big** (5+ tasks, multi-day): Use `/spartan:phase plan` for a full wave-parallel plan.
|
|
94
113
|
|
|
95
114
|
### Inline plan format (small features)
|