@c0x12c/spartan-ai-toolkit 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/.claude-plugin/marketplace.json +16 -0
  2. package/.claude-plugin/plugin.json +12 -0
  3. package/README.md +300 -0
  4. package/VERSION +1 -0
  5. package/agents/idea-killer.md +72 -0
  6. package/agents/micronaut-backend-expert.md +45 -0
  7. package/agents/research-planner.md +70 -0
  8. package/agents/solution-architect-cto.md +49 -0
  9. package/bin/cli.js +589 -0
  10. package/claude-md/00-header.md +39 -0
  11. package/claude-md/01-core.md +94 -0
  12. package/claude-md/05-database.md +20 -0
  13. package/claude-md/11-backend-micronaut.md +36 -0
  14. package/claude-md/20-frontend-react.md +23 -0
  15. package/claude-md/30-project-mgmt.md +91 -0
  16. package/claude-md/40-product.md +36 -0
  17. package/claude-md/50-ops.md +34 -0
  18. package/claude-md/60-research.md +75 -0
  19. package/claude-md/90-footer.md +21 -0
  20. package/commands/spartan/brainstorm.md +134 -0
  21. package/commands/spartan/brownfield.md +157 -0
  22. package/commands/spartan/careful.md +94 -0
  23. package/commands/spartan/content.md +17 -0
  24. package/commands/spartan/context-save.md +161 -0
  25. package/commands/spartan/daily.md +42 -0
  26. package/commands/spartan/debug.md +156 -0
  27. package/commands/spartan/deep-dive.md +55 -0
  28. package/commands/spartan/deploy.md +207 -0
  29. package/commands/spartan/e2e.md +264 -0
  30. package/commands/spartan/env-setup.md +166 -0
  31. package/commands/spartan/fe-review.md +134 -0
  32. package/commands/spartan/figma-to-code.md +244 -0
  33. package/commands/spartan/forensics.md +46 -0
  34. package/commands/spartan/freeze.md +84 -0
  35. package/commands/spartan/full-run.md +78 -0
  36. package/commands/spartan/fundraise.md +53 -0
  37. package/commands/spartan/gsd-upgrade.md +376 -0
  38. package/commands/spartan/guard.md +42 -0
  39. package/commands/spartan/init-project.md +178 -0
  40. package/commands/spartan/interview.md +154 -0
  41. package/commands/spartan/kickoff.md +52 -0
  42. package/commands/spartan/kotlin-service.md +109 -0
  43. package/commands/spartan/lean-canvas.md +222 -0
  44. package/commands/spartan/map-codebase.md +72 -0
  45. package/commands/spartan/migration.md +82 -0
  46. package/commands/spartan/next-app.md +317 -0
  47. package/commands/spartan/next-feature.md +197 -0
  48. package/commands/spartan/outreach.md +16 -0
  49. package/commands/spartan/phase.md +119 -0
  50. package/commands/spartan/pitch.md +18 -0
  51. package/commands/spartan/pr-ready.md +200 -0
  52. package/commands/spartan/project.md +106 -0
  53. package/commands/spartan/quickplan.md +122 -0
  54. package/commands/spartan/research.md +19 -0
  55. package/commands/spartan/review.md +102 -0
  56. package/commands/spartan/teardown.md +161 -0
  57. package/commands/spartan/testcontainer.md +97 -0
  58. package/commands/spartan/think.md +221 -0
  59. package/commands/spartan/unfreeze.md +13 -0
  60. package/commands/spartan/update.md +81 -0
  61. package/commands/spartan/validate.md +193 -0
  62. package/commands/spartan/workstreams.md +109 -0
  63. package/commands/spartan/write.md +16 -0
  64. package/commands/spartan.md +222 -0
  65. package/frameworks/00-framework-comparison-guide.md +317 -0
  66. package/frameworks/01-lean-canvas.md +196 -0
  67. package/frameworks/02-design-sprint.md +304 -0
  68. package/frameworks/03-foundation-sprint.md +337 -0
  69. package/frameworks/04-business-model-canvas.md +391 -0
  70. package/frameworks/05-customer-development.md +426 -0
  71. package/frameworks/06-jobs-to-be-done.md +358 -0
  72. package/frameworks/07-mom-test.md +392 -0
  73. package/frameworks/08-value-proposition-canvas.md +488 -0
  74. package/frameworks/09-javelin-board.md +428 -0
  75. package/frameworks/10-build-measure-learn.md +467 -0
  76. package/frameworks/11-mvp-approaches.md +533 -0
  77. package/frameworks/think-before-build.md +593 -0
  78. package/lib/assembler.js +52 -0
  79. package/lib/packs.js +16 -0
  80. package/lib/resolver.js +144 -0
  81. package/lib/resolver.test.js +140 -0
  82. package/package.json +48 -0
  83. package/packs/backend-micronaut.yaml +34 -0
  84. package/packs/backend-nodejs.yaml +15 -0
  85. package/packs/backend-python.yaml +15 -0
  86. package/packs/core.yaml +25 -0
  87. package/packs/database.yaml +21 -0
  88. package/packs/frontend-react.yaml +23 -0
  89. package/packs/ops.yaml +16 -0
  90. package/packs/packs.compiled.json +281 -0
  91. package/packs/product.yaml +20 -0
  92. package/packs/project-mgmt.yaml +21 -0
  93. package/packs/research.yaml +39 -0
  94. package/packs/shared-backend.yaml +14 -0
  95. package/rules/backend-micronaut/API_DESIGN.md +250 -0
  96. package/rules/backend-micronaut/CONTROLLERS.md +755 -0
  97. package/rules/backend-micronaut/KOTLIN.md +483 -0
  98. package/rules/backend-micronaut/RETROFIT_PLACEMENT.md +258 -0
  99. package/rules/backend-micronaut/SERVICES_AND_BEANS.md +673 -0
  100. package/rules/core/NAMING_CONVENTIONS.md +208 -0
  101. package/rules/database/ORM_AND_REPO.md +393 -0
  102. package/rules/database/SCHEMA.md +146 -0
  103. package/rules/database/TRANSACTIONS.md +311 -0
  104. package/rules/frontend-react/FRONTEND.md +344 -0
  105. package/rules/shared-backend/ARCHITECTURE.md +46 -0
  106. package/skills/api-endpoint-creator/SKILL.md +560 -0
  107. package/skills/api-endpoint-creator/error-handling-guide.md +244 -0
  108. package/skills/api-endpoint-creator/examples.md +522 -0
  109. package/skills/api-endpoint-creator/testing-patterns.md +302 -0
  110. package/skills/article-writing/SKILL.md +95 -0
  111. package/skills/backend-api-design/SKILL.md +187 -0
  112. package/skills/brainstorm/SKILL.md +85 -0
  113. package/skills/competitive-teardown/SKILL.md +105 -0
  114. package/skills/content-engine/SKILL.md +101 -0
  115. package/skills/database-patterns/SKILL.md +145 -0
  116. package/skills/database-table-creator/SKILL.md +588 -0
  117. package/skills/database-table-creator/examples.md +552 -0
  118. package/skills/database-table-creator/migration-template.sql +68 -0
  119. package/skills/database-table-creator/validation-checklist.md +337 -0
  120. package/skills/deep-research/SKILL.md +94 -0
  121. package/skills/idea-validation/SKILL.md +115 -0
  122. package/skills/investor-materials/SKILL.md +115 -0
  123. package/skills/investor-outreach/SKILL.md +98 -0
  124. package/skills/kotlin-best-practices/SKILL.md +145 -0
  125. package/skills/market-research/SKILL.md +113 -0
  126. package/skills/security-checklist/SKILL.md +150 -0
  127. package/skills/startup-pipeline/SKILL.md +125 -0
  128. package/skills/testing-strategies/SKILL.md +156 -0
  129. package/skills/ui-ux-pro-max/SKILL.md +377 -0
  130. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  131. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  132. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  133. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  134. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  135. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  136. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  137. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  138. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  139. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  140. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  141. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  142. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  143. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  144. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  145. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  146. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  147. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  148. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  149. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  150. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  151. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  152. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  153. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  154. package/skills/ui-ux-pro-max/scripts/core.py +253 -0
  155. package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  156. package/skills/ui-ux-pro-max/scripts/search.py +114 -0
  157. package/templates/competitor-analysis.md +60 -0
  158. package/templates/content/AGENT_TEMPLATE.md +47 -0
  159. package/templates/content/COMMAND_TEMPLATE.md +27 -0
  160. package/templates/content/RULE_TEMPLATE.md +40 -0
  161. package/templates/content/SKILL_TEMPLATE.md +41 -0
  162. package/templates/idea-canvas.md +47 -0
  163. package/templates/prd-template.md +84 -0
  164. package/templates/project-readme.md +35 -0
  165. package/templates/user-interview.md +69 -0
  166. package/templates/validation-checklist.md +108 -0
package/bin/cli.js ADDED
@@ -0,0 +1,589 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Spartan AI Toolkit — npx installer
4
+ // Usage:
5
+ // npx spartan-ai-toolkit@latest
6
+ // npx spartan-ai-toolkit@latest --agent=cursor
7
+ // npx spartan-ai-toolkit@latest --packs=backend-micronaut,product
8
+ // npx spartan-ai-toolkit@latest --all
9
+ // npx spartan-ai-toolkit@latest --local
10
+
11
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, cpSync, readdirSync } from 'node:fs';
12
+ import { join, dirname, resolve as pathResolve } from 'node:path';
13
+ import { createInterface } from 'node:readline';
14
+ import { homedir } from 'node:os';
15
+ import { fileURLToPath } from 'node:url';
16
+
17
+ // ── Resolve package root (works from npx temp dir) ──────────────
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = dirname(__filename);
20
+ const PKG_ROOT = pathResolve(__dirname, '..');
21
+
22
+ // ── Toolkit source paths ────────────────────────────────────────
23
+ const SRC = {
24
+ commands: join(PKG_ROOT, 'commands'),
25
+ commandsSub: join(PKG_ROOT, 'commands', 'spartan'),
26
+ router: join(PKG_ROOT, 'commands', 'spartan.md'),
27
+ rules: join(PKG_ROOT, 'rules'),
28
+ skills: join(PKG_ROOT, 'skills'),
29
+ agents: join(PKG_ROOT, 'agents'),
30
+ claudeMd: join(PKG_ROOT, 'claude-md'),
31
+ version: join(PKG_ROOT, 'VERSION'),
32
+ claudePlugin: join(PKG_ROOT, '.claude-plugin'),
33
+ };
34
+
35
+ // ── Colors ──────────────────────────────────────────────────────
36
+ const C = {
37
+ blue: '\x1b[34m', green: '\x1b[32m', yellow: '\x1b[33m',
38
+ red: '\x1b[31m', cyan: '\x1b[36m', bold: '\x1b[1m',
39
+ dim: '\x1b[2m', reset: '\x1b[0m',
40
+ };
41
+
42
+ function bold(s) { return `${C.bold}${s}${C.reset}`; }
43
+ function green(s) { return `${C.green}${s}${C.reset}`; }
44
+ function yellow(s) { return `${C.yellow}${s}${C.reset}`; }
45
+ function cyan(s) { return `${C.cyan}${s}${C.reset}`; }
46
+ function dim(s) { return `${C.dim}${s}${C.reset}`; }
47
+ function blue(s) { return `${C.blue}${s}${C.reset}`; }
48
+
49
+ // ── Pack definitions (loaded from YAML manifests) ───────────────
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';
53
+
54
+ const manifests = loadManifests(join(PKG_ROOT, 'packs'));
55
+
56
+ // ── Parse args ──────────────────────────────────────────────────
57
+ const args = process.argv.slice(2);
58
+
59
+ let agent = 'claude-code';
60
+ let packsArg = '';
61
+ let installAll = false;
62
+ let mode = 'global'; // default for claude-code
63
+ let showHelp = false;
64
+
65
+ for (const arg of args) {
66
+ if (arg === '--help' || arg === '-h') showHelp = true;
67
+ else if (arg.startsWith('--agent=')) agent = arg.split('=')[1];
68
+ else if (arg.startsWith('--packs=')) packsArg = arg.split('=')[1];
69
+ else if (arg === '--all') installAll = true;
70
+ else if (arg === '--global') mode = 'global';
71
+ else if (arg === '--local') mode = 'local';
72
+ }
73
+
74
+ if (showHelp) {
75
+ // Group packs by category for help display
76
+ const categories = {};
77
+ for (const name of PACK_ORDER) {
78
+ const p = PACKS[name];
79
+ if (p.hidden) continue;
80
+ const cat = p.category || 'Other';
81
+ if (!categories[cat]) categories[cat] = [];
82
+ const items = [
83
+ p.commands.length ? `${p.commands.length} commands` : '',
84
+ p.rules.length ? `${p.rules.length} rules` : '',
85
+ p.skills.length ? `${p.skills.length} skills` : '',
86
+ p.agents.length ? `${p.agents.length} agents` : '',
87
+ ].filter(Boolean).join(', ');
88
+ const tag = p.comingSoon ? ` ${dim('(coming soon)')}` : '';
89
+ categories[cat].push(` ${bold(name.padEnd(20))} ${p.description}${tag}${items ? dim(` (${items})`) : ''}`);
90
+ }
91
+
92
+ console.log(`
93
+ ${bold('Spartan AI Toolkit')} — installer
94
+
95
+ ${bold('Usage:')}
96
+ npx spartan-ai-toolkit@latest [options]
97
+
98
+ ${bold('Options:')}
99
+ --agent=NAME Agent to set up for (default: claude-code)
100
+ Choices: claude-code, cursor, windsurf, codex, copilot
101
+ --packs=LIST Comma-separated packs (claude-code only)
102
+ Example: --packs=backend-micronaut,product
103
+ --all Install all packs
104
+ --global Install to home dir (default for claude-code/codex)
105
+ --local Install to current project dir
106
+ --help Show this help
107
+
108
+ ${bold('Packs:')}
109
+ ${Object.entries(categories).map(([cat, lines]) => `\n ${bold(cat + ':')}
110
+ ${lines.join('\n')}`).join('\n')}
111
+
112
+ ${bold('Examples:')}
113
+ ${cyan('npx spartan-ai-toolkit@latest')}
114
+ Interactive — pick agent and packs from menu
115
+
116
+ ${cyan('npx spartan-ai-toolkit@latest --packs=frontend-react,product')}
117
+ Next.js app with product thinking tools
118
+
119
+ ${cyan('npx spartan-ai-toolkit@latest --packs=backend-micronaut,project-mgmt')}
120
+ Kotlin APIs with full project lifecycle
121
+
122
+ ${cyan('npx spartan-ai-toolkit@latest --all')}
123
+ Everything installed
124
+
125
+ ${cyan('npx spartan-ai-toolkit@latest --agent=cursor')}
126
+ Install rules for Cursor (rules + AGENTS.md only)
127
+ `);
128
+ process.exit(0);
129
+ }
130
+
131
+ // ── Readline helper ─────────────────────────────────────────────
132
+ let rl;
133
+
134
+ function getRL() {
135
+ if (!rl) {
136
+ rl = createInterface({ input: process.stdin, output: process.stdout });
137
+ }
138
+ return rl;
139
+ }
140
+
141
+ function ask(question) {
142
+ return new Promise(resolve => {
143
+ getRL().question(question, answer => resolve(answer.trim()));
144
+ });
145
+ }
146
+
147
+ function closeRL() {
148
+ if (rl) { rl.close(); rl = null; }
149
+ }
150
+
151
+ // ── Version ─────────────────────────────────────────────────────
152
+ const VERSION = existsSync(SRC.version)
153
+ ? readFileSync(SRC.version, 'utf-8').trim()
154
+ : '4.2.0';
155
+
156
+ // ── Target directories based on agent + mode ────────────────────
157
+ function getTargets() {
158
+ const home = homedir();
159
+ const cwd = process.cwd();
160
+
161
+ if (agent === 'claude-code') {
162
+ const base = mode === 'global' ? join(home, '.claude') : join(cwd, '.claude');
163
+ return {
164
+ base,
165
+ commands: join(base, 'commands', 'spartan'),
166
+ router: join(base, 'commands', 'spartan.md'),
167
+ rules: join(base, 'rules'),
168
+ skills: join(base, 'skills'),
169
+ agents: join(base, 'agents'),
170
+ claudeMd: mode === 'global' ? join(home, '.claude', 'CLAUDE.md') : join(cwd, 'CLAUDE.md'),
171
+ packsFile: join(base, '.spartan-packs'),
172
+ versionFile: join(base, '.spartan-version'),
173
+ };
174
+ }
175
+
176
+ if (agent === 'codex') {
177
+ const base = mode === 'global' ? join(home, '.codex') : join(cwd, '.codex');
178
+ return {
179
+ base,
180
+ commands: join(base, 'commands', 'spartan'),
181
+ router: join(base, 'commands', 'spartan.md'),
182
+ rules: join(base, 'rules'),
183
+ skills: join(base, 'skills'),
184
+ agents: join(base, 'agents'),
185
+ claudeMd: mode === 'global' ? join(home, '.codex', 'CLAUDE.md') : join(cwd, 'CLAUDE.md'),
186
+ packsFile: join(base, '.spartan-packs'),
187
+ versionFile: join(base, '.spartan-version'),
188
+ };
189
+ }
190
+
191
+ // cursor, windsurf, copilot — project-local only
192
+ const rulesDir = {
193
+ cursor: join(cwd, '.cursor', 'rules'),
194
+ windsurf: join(cwd, '.windsurf', 'rules'),
195
+ copilot: join(cwd, '.github', 'instructions'),
196
+ }[agent];
197
+
198
+ return {
199
+ base: cwd,
200
+ rules: rulesDir,
201
+ agentsMd: join(cwd, 'AGENTS.md'),
202
+ packsFile: join(cwd, '.spartan-packs'),
203
+ versionFile: null,
204
+ };
205
+ }
206
+
207
+ // ── Helpers ─────────────────────────────────────────────────────
208
+ function ensureDir(dir) {
209
+ mkdirSync(dir, { recursive: true });
210
+ }
211
+
212
+ function copyFile(src, dest) {
213
+ ensureDir(dirname(dest));
214
+ const content = readFileSync(src);
215
+ writeFileSync(dest, content);
216
+ }
217
+
218
+ function copyDir(src, dest) {
219
+ ensureDir(dest);
220
+ cpSync(src, dest, { recursive: true });
221
+ }
222
+
223
+ /** Get all items for a category across selected packs, deduplicated. */
224
+ function gatherItems(selectedPacks, category) {
225
+ const seen = new Set();
226
+ const result = [];
227
+ for (const pack of selectedPacks) {
228
+ const def = PACKS[pack];
229
+ if (!def) continue;
230
+ for (const item of def[category]) {
231
+ if (!seen.has(item)) {
232
+ seen.add(item);
233
+ result.push(item);
234
+ }
235
+ }
236
+ }
237
+ return result;
238
+ }
239
+
240
+ // ── Pack selection (grouped menu) ───────────────────────────────
241
+ async function selectPacks(targets) {
242
+ // --all flag
243
+ if (installAll) {
244
+ const all = PACK_ORDER.filter(p => !PACKS[p].hidden && !PACKS[p].comingSoon);
245
+ return resolveDeps(all, manifests);
246
+ }
247
+
248
+ // --packs flag
249
+ if (packsArg) {
250
+ let requested = packsArg.split(',').map(s => s.trim()).filter(Boolean);
251
+ const { resolved: aliased, warnings } = resolveAliases(requested);
252
+ for (const w of warnings) console.log(` ${yellow('!')} ${w}`);
253
+ return resolveDeps(aliased, manifests);
254
+ }
255
+
256
+ // Check saved packs
257
+ if (existsSync(targets.packsFile)) {
258
+ let saved = readFileSync(targets.packsFile, 'utf-8').trim().split('\n').filter(Boolean);
259
+ const { resolved: aliased, warnings } = resolveAliases(saved);
260
+ for (const w of warnings) console.log(` ${yellow('!')} ${w}`);
261
+ saved = aliased;
262
+
263
+ if (saved.length > 0) {
264
+ console.log(`\n ${cyan('Previously installed packs:')} ${saved.filter(p => !PACKS[p]?.hidden).join(', ')}`);
265
+ const reuse = await ask(' Re-install same packs? [Y/n]: ');
266
+ if (reuse !== 'n' && reuse !== 'N') {
267
+ return resolveDeps(saved, manifests);
268
+ }
269
+ }
270
+ }
271
+
272
+ // Interactive grouped menu
273
+ console.log(`\n ${bold('Choose your packs:')}\n`);
274
+
275
+ const categories = {};
276
+ const selectablePacks = [];
277
+ for (const name of PACK_ORDER) {
278
+ const p = PACKS[name];
279
+ if (p.hidden) continue;
280
+ const cat = p.category || 'Other';
281
+ if (!categories[cat]) categories[cat] = [];
282
+ categories[cat].push(name);
283
+ }
284
+
285
+ for (const [cat, packs] of Object.entries(categories)) {
286
+ console.log(` ${bold(cat + ':')}`);
287
+ for (const name of packs) {
288
+ const p = PACKS[name];
289
+ const tag = name === 'core' ? ` ${green('(always included)')}`
290
+ : p.comingSoon ? ` ${dim('(coming soon)')}`
291
+ : '';
292
+ console.log(` ${bold(name)} — ${p.description}${tag}`);
293
+ if (!p.comingSoon && name !== 'core') {
294
+ selectablePacks.push(name);
295
+ }
296
+ }
297
+ console.log('');
298
+ }
299
+
300
+ const allChoice = await ask(' Install all packs? [Y/n]: ');
301
+
302
+ if (allChoice !== 'n' && allChoice !== 'N') {
303
+ return resolveDeps(selectablePacks, manifests);
304
+ }
305
+
306
+ // Ask about each optional pack
307
+ const selected = [];
308
+ for (const pack of selectablePacks) {
309
+ const def = PACKS[pack];
310
+ const choice = await ask(` ${bold(pack)} — ${def.description}? [y/N]: `);
311
+ if (choice === 'y' || choice === 'Y') {
312
+ selected.push(pack);
313
+ }
314
+ }
315
+
316
+ return resolveDeps(selected, manifests);
317
+ }
318
+
319
+ // ── Install for claude-code / codex ─────────────────────────────
320
+ async function installFull() {
321
+ const targets = getTargets();
322
+ const selectedPacks = await selectPacks(targets);
323
+
324
+ // Show user-facing packs (hide hidden deps)
325
+ const userPacks = selectedPacks.filter(p => !PACKS[p]?.hidden);
326
+ const hiddenPacks = selectedPacks.filter(p => PACKS[p]?.hidden);
327
+ console.log(`\n ${green('Selected:')} ${bold(userPacks.join(' '))}`);
328
+ if (hiddenPacks.length > 0) {
329
+ console.log(` ${dim('Auto-included:')} ${dim(hiddenPacks.join(' '))}`);
330
+ }
331
+ console.log('');
332
+
333
+ // 1) Assemble & install CLAUDE.md
334
+ console.log(`${blue('[1/5]')} ${bold('Assembling CLAUDE.md...')}`);
335
+
336
+ if (existsSync(targets.claudeMd)) {
337
+ const backupPath = `${targets.claudeMd}.${Date.now()}.bak`;
338
+ copyFile(targets.claudeMd, backupPath);
339
+ console.log(` ${dim('Backed up existing CLAUDE.md')}`);
340
+ }
341
+
342
+ const assembled = assembleCLAUDEmd(SRC.claudeMd, selectedPacks, PACKS);
343
+ ensureDir(dirname(targets.claudeMd));
344
+ writeFileSync(targets.claudeMd, assembled, 'utf-8');
345
+
346
+ const sectionCount = 2 + 1 + gatherItems(selectedPacks, 'claudeSections').length;
347
+ console.log(` ${green('+')} CLAUDE.md assembled (${sectionCount} sections)\n`);
348
+
349
+ // 2) Commands
350
+ console.log(`${blue('[2/5]')} ${bold('Installing commands...')}`);
351
+ ensureDir(targets.commands);
352
+ let cmdCount = 0;
353
+
354
+ // Smart router (always)
355
+ if (existsSync(SRC.router)) {
356
+ copyFile(SRC.router, targets.router);
357
+ console.log(` ${green('+')} /spartan (smart router)`);
358
+ cmdCount++;
359
+ }
360
+
361
+ const selectedCommands = gatherItems(selectedPacks, 'commands');
362
+ for (const cmd of selectedCommands) {
363
+ const src = join(SRC.commandsSub, `${cmd}.md`);
364
+ if (existsSync(src)) {
365
+ copyFile(src, join(targets.commands, `${cmd}.md`));
366
+ console.log(` ${green('+')} /spartan:${cmd}`);
367
+ cmdCount++;
368
+ } else {
369
+ console.log(` ${yellow('!')} /spartan:${cmd} (not found, skipped)`);
370
+ }
371
+ }
372
+ console.log(` ${bold(cmdCount + ' commands')} installed\n`);
373
+
374
+ // 3) Rules (now with subdirectory structure)
375
+ const selectedRules = gatherItems(selectedPacks, 'rules');
376
+ if (selectedRules.length > 0) {
377
+ console.log(`${blue('[3/5]')} ${bold('Installing rules...')}`);
378
+ let ruleCount = 0;
379
+
380
+ for (const rule of selectedRules) {
381
+ // Rules now have subdir paths like "database/SCHEMA.md"
382
+ const src = join(SRC.rules, rule);
383
+ const dest = join(targets.rules, rule);
384
+ if (existsSync(src)) {
385
+ copyFile(src, dest);
386
+ console.log(` ${green('+')} ${rule}`);
387
+ ruleCount++;
388
+ }
389
+ }
390
+ console.log(` ${bold(ruleCount + ' rules')} installed\n`);
391
+ } else {
392
+ console.log(`${blue('[3/5]')} ${bold('Rules')} — ${dim('no rule packs selected, skipping')}\n`);
393
+ }
394
+
395
+ // 4) Skills
396
+ const selectedSkills = gatherItems(selectedPacks, 'skills');
397
+ if (selectedSkills.length > 0) {
398
+ console.log(`${blue('[4/5]')} ${bold('Installing skills...')}`);
399
+ ensureDir(targets.skills);
400
+ let skillCount = 0;
401
+
402
+ for (const skill of selectedSkills) {
403
+ const src = join(SRC.skills, skill);
404
+ if (existsSync(src)) {
405
+ copyDir(src, join(targets.skills, skill));
406
+ console.log(` ${green('+')} ${skill}`);
407
+ skillCount++;
408
+ }
409
+ }
410
+ console.log(` ${bold(skillCount + ' skills')} installed\n`);
411
+ } else {
412
+ console.log(`${blue('[4/5]')} ${bold('Skills')} — ${dim('no skill packs selected, skipping')}\n`);
413
+ }
414
+
415
+ // 5) Agents
416
+ const selectedAgents = gatherItems(selectedPacks, 'agents');
417
+ if (selectedAgents.length > 0) {
418
+ console.log(`${blue('[5/5]')} ${bold('Installing agents...')}`);
419
+ ensureDir(targets.agents);
420
+ let agentCount = 0;
421
+
422
+ for (const agentFile of selectedAgents) {
423
+ const src = join(SRC.agents, agentFile);
424
+ if (existsSync(src)) {
425
+ copyFile(src, join(targets.agents, agentFile));
426
+ console.log(` ${green('+')} ${agentFile.replace('.md', '')}`);
427
+ agentCount++;
428
+ }
429
+ }
430
+ console.log(` ${bold(agentCount + ' agents')} installed\n`);
431
+ } else {
432
+ console.log(`${blue('[5/5]')} ${bold('Agents')} — ${dim('no agent packs selected, skipping')}\n`);
433
+ }
434
+
435
+ // Save pack selection + version
436
+ writeFileSync(targets.packsFile, selectedPacks.join('\n') + '\n', 'utf-8');
437
+ if (targets.versionFile) {
438
+ writeFileSync(targets.versionFile, VERSION + '\n', 'utf-8');
439
+ }
440
+
441
+ return selectedPacks;
442
+ }
443
+
444
+ // ── Install for cursor / windsurf / copilot ─────────────────────
445
+ async function installRulesOnly() {
446
+ const targets = getTargets();
447
+
448
+ console.log(`\n Agent: ${bold(agent)}`);
449
+ console.log(` This installs ${bold('rules + AGENTS.md')} only.`);
450
+ console.log(` Slash commands are Claude Code specific.\n`);
451
+
452
+ // Ask which rule packs
453
+ console.log(` ${bold('Which rule packs do you need?')}\n`);
454
+
455
+ const rulePacks = PACK_ORDER.filter(p => PACKS[p].rules.length > 0 && !PACKS[p].hidden);
456
+ for (const pack of rulePacks) {
457
+ const ruleNames = PACKS[pack].rules.map(r => r.replace(/.*\//, '').replace('.md', '')).join(', ');
458
+ console.log(` ${bold(pack)} — ${dim(ruleNames)}`);
459
+ }
460
+ console.log('');
461
+
462
+ const allChoice = await ask(' Install all rule packs? [Y/n]: ');
463
+ let selectedPacks;
464
+
465
+ if (allChoice !== 'n' && allChoice !== 'N') {
466
+ selectedPacks = resolveDeps(rulePacks, manifests);
467
+ } else {
468
+ const picks = [];
469
+ for (const pack of rulePacks) {
470
+ const choice = await ask(` ${bold(pack)}? [y/N]: `);
471
+ if (choice === 'y' || choice === 'Y') {
472
+ picks.push(pack);
473
+ }
474
+ }
475
+ selectedPacks = resolveDeps(picks, manifests);
476
+ }
477
+
478
+ // Install rules
479
+ const selectedRules = gatherItems(selectedPacks, 'rules');
480
+ if (selectedRules.length > 0) {
481
+ console.log(`\n${blue('[1/2]')} ${bold('Installing rules...')}`);
482
+ ensureDir(targets.rules);
483
+ let count = 0;
484
+ for (const rule of selectedRules) {
485
+ const src = join(SRC.rules, rule);
486
+ const dest = join(targets.rules, rule);
487
+ if (existsSync(src)) {
488
+ copyFile(src, dest);
489
+ console.log(` ${green('+')} ${rule}`);
490
+ count++;
491
+ }
492
+ }
493
+ console.log(` ${bold(count + ' rules')} installed\n`);
494
+ } else {
495
+ console.log(`\n${blue('[1/2]')} ${bold('Rules')} — ${dim('no rule packs selected')}\n`);
496
+ }
497
+
498
+ // Install AGENTS.md
499
+ console.log(`${blue('[2/2]')} ${bold('Installing AGENTS.md...')}`);
500
+
501
+ const allAgents = gatherItems([...PACK_ORDER], 'agents');
502
+ if (allAgents.length > 0 && targets.agentsMd) {
503
+ let agentsContent = '# Spartan AI Toolkit — Agents\n\n';
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');
512
+ console.log(` ${green('+')} AGENTS.md\n`);
513
+ } else {
514
+ console.log(` ${dim('No agents to install')}\n`);
515
+ }
516
+
517
+ // Save selection
518
+ if (targets.packsFile) {
519
+ writeFileSync(targets.packsFile, selectedPacks.join('\n') + '\n', 'utf-8');
520
+ }
521
+
522
+ return selectedPacks;
523
+ }
524
+
525
+ // ── Main ────────────────────────────────────────────────────────
526
+ async function main() {
527
+ console.log('');
528
+ console.log(`${bold('================================================')}`);
529
+ console.log(`${bold(' Spartan AI Toolkit')} ${dim(`v${VERSION}`)}`);
530
+ console.log(`${bold('================================================')}`);
531
+ console.log('');
532
+ console.log(` Agent: ${bold(agent)} Mode: ${bold(mode)}`);
533
+
534
+ // Check Node version
535
+ const nodeVer = parseInt(process.versions.node.split('.')[0], 10);
536
+ if (nodeVer < 18) {
537
+ console.error(`\n ${C.red}Node.js ${process.versions.node} is too old. Need >= 18.${C.reset}\n`);
538
+ process.exit(1);
539
+ }
540
+
541
+ let selectedPacks;
542
+
543
+ try {
544
+ if (agent === 'claude-code' || agent === 'codex') {
545
+ selectedPacks = await installFull();
546
+ } else if (['cursor', 'windsurf', 'copilot'].includes(agent)) {
547
+ selectedPacks = await installRulesOnly();
548
+ } else {
549
+ console.error(`\n ${C.red}Unknown agent: ${agent}${C.reset}`);
550
+ console.error(` Supported: claude-code, cursor, windsurf, codex, copilot\n`);
551
+ process.exit(1);
552
+ }
553
+ } finally {
554
+ closeRL();
555
+ }
556
+
557
+ // Success
558
+ const userPacks = selectedPacks.filter(p => !PACKS[p]?.hidden);
559
+ console.log(`${bold(green('================================================'))}`);
560
+ console.log(`${bold(green(' Setup done!'))} ${dim(`v${VERSION}`)}`);
561
+ console.log(`${bold(green('================================================'))}`);
562
+ console.log('');
563
+ console.log(` Installed packs: ${cyan(userPacks.join(', '))}`);
564
+ console.log('');
565
+
566
+ if (agent === 'claude-code' || agent === 'codex') {
567
+ console.log(` ${bold('Next steps:')}`);
568
+ console.log('');
569
+ console.log(` 1. Open any project folder and type:`);
570
+ console.log(` ${cyan('/spartan')}`);
571
+ console.log('');
572
+ console.log(` 2. To change packs later, run again:`);
573
+ console.log(` ${cyan('npx spartan-ai-toolkit@latest')}`);
574
+ console.log('');
575
+ } else {
576
+ console.log(` ${bold('Next steps:')}`);
577
+ console.log('');
578
+ console.log(` 1. Rules are in your ${agent} rules folder.`);
579
+ console.log(` 2. AGENTS.md is in your project root.`);
580
+ console.log(` 3. Slash commands need Claude Code — they don't work in ${agent}.`);
581
+ console.log('');
582
+ }
583
+ }
584
+
585
+ main().catch(err => {
586
+ console.error(`\n ${C.red}Error: ${err.message}${C.reset}\n`);
587
+ closeRL();
588
+ process.exit(1);
589
+ });
@@ -0,0 +1,39 @@
1
+ # Spartan AI Toolkit — Engineering Manager Workflow
2
+
3
+ ## Why Spartan?
4
+
5
+ Spartan commands are **pre-built, high-quality prompts** for workflows where free-form chat leads to missed steps. They don't replace Claude — they make Claude more reliable for structured work.
6
+
7
+ Without Spartan: "Create a PR" → Claude pushes code. Forgets to rebase, skips tests, no PR description.
8
+ With `/spartan:pr-ready`: 6-step checklist — rebase, tests, lint, architecture check, security scan, PR description generated. Devs usually forget 3 of these.
9
+
10
+ **When commands add value:** Structured workflows with multiple steps, checklists, or scaffolding that must follow specific conventions.
11
+ **When commands don't add value:** Questions, explanations, small code changes, brainstorming — just talk to Claude.
12
+
13
+ ---
14
+
15
+ ## Command or Chat? (Decision Rule)
16
+
17
+ ```
18
+ What do you need?
19
+
20
+ ├─ Question / explanation / brainstorm → Just ask Claude
21
+ ├─ Small code change (< 30 min, ≤ 3 files) → Just ask Claude (Superpowers handles TDD/review)
22
+ ├─ Structured workflow with checklist → Use a /spartan: command
23
+ └─ Don't know which command → Type /spartan (smart router asks what you need)
24
+ ```
25
+
26
+ **Superpowers is always active.** When you say "review this" or "debug this" in normal chat, Claude auto-triggers the right skill. You don't need a command for that.
27
+
28
+ **Commands are for when the workflow matters more than the answer** — deploying, creating PRs, scaffolding new services, planning multi-day work.
29
+
30
+ ---
31
+
32
+ ## Task Size → Tool Routing
33
+
34
+ | Size | Use |
35
+ |---|---|
36
+ | < 30 min, ≤ 3 files | Just ask Claude (no command needed) |
37
+ | < 1 day | `/spartan:quickplan` |
38
+ | 1–3 days | `/spartan:project new` (lightweight lifecycle) |
39
+ | > 3 days, multi-session | `/spartan:project new` (full lifecycle) |