@c0x12c/spartan-ai-toolkit 1.6.5 → 1.7.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.
@@ -10,7 +10,7 @@
10
10
  "name": "spartan-ai-toolkit",
11
11
  "description": "5 workflows, 56 commands, 12 rules, 22 skills, 7 agents — organized in 11 packs with dependencies",
12
12
  "source": "./toolkit",
13
- "version": "1.6.5"
13
+ "version": "1.7.1"
14
14
  }
15
15
  ]
16
16
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spartan-ai-toolkit",
3
- "version": "1.6.5",
3
+ "version": "1.7.1",
4
4
  "description": "Engineering discipline layer for Claude Code — 5 workflows, 56 commands, 12 rules, 22 skills, 7 agents organized in 11 packs",
5
5
  "author": {
6
6
  "name": "Khoa Tran",
package/VERSION CHANGED
@@ -1 +1 @@
1
- 1.6.5
1
+ 1.7.1
@@ -81,26 +81,23 @@ Pick the right checks based on file types:
81
81
 
82
82
  ## How You Work
83
83
 
84
- 1. **Load project rules first.** Before looking at any code, read the rule files that match the stack. These are the source of truth — they override your defaults.
84
+ 1. **Load rules from config.** Before looking at any code, find and read the project's rules.
85
85
 
86
- **Find rules in this order** (use the first location that exists):
86
+ **Check for config first:**
87
+ ```bash
88
+ cat .spartan/config.yaml 2>/dev/null
89
+ ```
90
+
91
+ **If config exists:** read the `rules` section. Load all rule files listed for the current mode (backend/frontend/shared). If `extends` is set, load the base profile first, then apply overrides. If `conditional-rules` is set, match rules to changed files.
92
+
93
+ **If no config, scan for rules** (use the first location that has files):
87
94
  ```bash
88
95
  ls rules/ 2>/dev/null # project root
89
96
  ls .claude/rules/ 2>/dev/null # project .claude dir
90
97
  ls ~/.claude/rules/ 2>/dev/null # global install
91
98
  ```
92
99
 
93
- **Backend rules (read if .kt files changed):**
94
- - `rules/backend-micronaut/KOTLIN.md`
95
- - `rules/backend-micronaut/CONTROLLERS.md`
96
- - `rules/backend-micronaut/API_DESIGN.md`
97
- - `rules/backend-micronaut/SERVICES_AND_BEANS.md`
98
- - `rules/database/SCHEMA.md`
99
- - `rules/database/ORM_AND_REPO.md`
100
- - `rules/database/TRANSACTIONS.md`
101
-
102
- **Frontend rules (read if .tsx/.ts files changed):**
103
- - `rules/frontend-react/FRONTEND.md`
100
+ Read all `.md` files in the found rules directory. Group by subdirectory name to determine which mode they apply to.
104
101
 
105
102
  If a rule file doesn't exist, skip it. Don't guess what it says.
106
103
 
package/bin/cli.js CHANGED
@@ -27,6 +27,7 @@ const SRC = {
27
27
  rules: join(PKG_ROOT, 'rules'),
28
28
  skills: join(PKG_ROOT, 'skills'),
29
29
  agents: join(PKG_ROOT, 'agents'),
30
+ profiles: join(PKG_ROOT, 'profiles'),
30
31
  claudeMd: join(PKG_ROOT, 'claude-md'),
31
32
  version: join(PKG_ROOT, 'VERSION'),
32
33
  claudePlugin: join(PKG_ROOT, '.claude-plugin'),
@@ -411,7 +412,7 @@ async function installFull() {
411
412
  console.log('');
412
413
 
413
414
  // 1) Assemble & install CLAUDE.md
414
- console.log(`${blue('[1/5]')} ${bold('Assembling CLAUDE.md...')}`);
415
+ console.log(`${blue('[1/6]')} ${bold('Assembling CLAUDE.md...')}`);
415
416
 
416
417
  if (existsSync(targets.claudeMd)) {
417
418
  const backupPath = `${targets.claudeMd}.${Date.now()}.bak`;
@@ -427,7 +428,7 @@ async function installFull() {
427
428
  console.log(` ${green('+')} CLAUDE.md assembled (${sectionCount} sections)\n`);
428
429
 
429
430
  // 2) Commands
430
- console.log(`${blue('[2/5]')} ${bold('Installing commands...')}`);
431
+ console.log(`${blue('[2/6]')} ${bold('Installing commands...')}`);
431
432
  ensureDir(targets.commands);
432
433
  let cmdCount = 0;
433
434
 
@@ -454,7 +455,7 @@ async function installFull() {
454
455
  // 3) Rules (now with subdirectory structure)
455
456
  const rulesWithSource = gatherItemsWithSource(selectedPacks, 'rules');
456
457
  if (rulesWithSource.length > 0) {
457
- console.log(`${blue('[3/5]')} ${bold('Installing rules...')}`);
458
+ console.log(`${blue('[3/6]')} ${bold('Installing rules...')}`);
458
459
  let ruleCount = 0;
459
460
 
460
461
  for (const { item: rule, srcRoot } of rulesWithSource) {
@@ -468,13 +469,13 @@ async function installFull() {
468
469
  }
469
470
  console.log(` ${bold(ruleCount + ' rules')} installed\n`);
470
471
  } else {
471
- console.log(`${blue('[3/5]')} ${bold('Rules')} — ${dim('no rule packs selected, skipping')}\n`);
472
+ console.log(`${blue('[3/6]')} ${bold('Rules')} — ${dim('no rule packs selected, skipping')}\n`);
472
473
  }
473
474
 
474
475
  // 4) Skills
475
476
  const skillsWithSource = gatherItemsWithSource(selectedPacks, 'skills');
476
477
  if (skillsWithSource.length > 0) {
477
- console.log(`${blue('[4/5]')} ${bold('Installing skills...')}`);
478
+ console.log(`${blue('[4/6]')} ${bold('Installing skills...')}`);
478
479
  ensureDir(targets.skills);
479
480
  let skillCount = 0;
480
481
 
@@ -488,13 +489,13 @@ async function installFull() {
488
489
  }
489
490
  console.log(` ${bold(skillCount + ' skills')} installed\n`);
490
491
  } else {
491
- console.log(`${blue('[4/5]')} ${bold('Skills')} — ${dim('no skill packs selected, skipping')}\n`);
492
+ console.log(`${blue('[4/6]')} ${bold('Skills')} — ${dim('no skill packs selected, skipping')}\n`);
492
493
  }
493
494
 
494
495
  // 5) Agents
495
496
  const agentsWithSource = gatherItemsWithSource(selectedPacks, 'agents');
496
497
  if (agentsWithSource.length > 0) {
497
- console.log(`${blue('[5/5]')} ${bold('Installing agents...')}`);
498
+ console.log(`${blue('[5/6]')} ${bold('Installing agents...')}`);
498
499
  ensureDir(targets.agents);
499
500
  let agentCount = 0;
500
501
 
@@ -508,7 +509,27 @@ async function installFull() {
508
509
  }
509
510
  console.log(` ${bold(agentCount + ' agents')} installed\n`);
510
511
  } else {
511
- console.log(`${blue('[5/5]')} ${bold('Agents')} — ${dim('no agent packs selected, skipping')}\n`);
512
+ console.log(`${blue('[5/6]')} ${bold('Agents')} — ${dim('no agent packs selected, skipping')}\n`);
513
+ }
514
+
515
+ // 6) Generate .spartan/config.yaml from best matching profile
516
+ const configDir = mode === 'global'
517
+ ? join(homedir(), '.spartan')
518
+ : join(process.cwd(), '.spartan');
519
+ const configPath = join(configDir, 'config.yaml');
520
+
521
+ if (!existsSync(configPath)) {
522
+ const profile = pickProfile(selectedPacks);
523
+ const profileSrc = join(SRC.profiles, `${profile}.yaml`);
524
+
525
+ if (existsSync(profileSrc)) {
526
+ ensureDir(configDir);
527
+ copyFile(profileSrc, configPath);
528
+ console.log(`${blue('[6/6]')} ${bold('Generated .spartan/config.yaml')} from ${cyan(profile)} profile`);
529
+ console.log(` ${dim('Edit this file to customize rules, review stages, and build commands')}\n`);
530
+ }
531
+ } else {
532
+ console.log(`${blue('[6/6]')} ${bold('.spartan/config.yaml')} — ${dim('already exists, kept as-is')}\n`);
512
533
  }
513
534
 
514
535
  // Save pack selection + version
@@ -520,6 +541,24 @@ async function installFull() {
520
541
  return selectedPacks;
521
542
  }
522
543
 
544
+ // ── Profile picker ─────────────────────────────────────────────
545
+ // Maps selected packs to the best matching stack profile.
546
+ function pickProfile(selectedPacks) {
547
+ const packSet = new Set(selectedPacks);
548
+
549
+ // Check for specific stack packs first
550
+ if (packSet.has('backend-micronaut') && packSet.has('frontend-react')) {
551
+ return 'kotlin-micronaut'; // full-stack defaults to backend profile
552
+ }
553
+ if (packSet.has('backend-micronaut')) return 'kotlin-micronaut';
554
+ if (packSet.has('frontend-react')) return 'react-nextjs';
555
+ if (packSet.has('backend-nodejs')) return 'typescript-node';
556
+ if (packSet.has('backend-python')) return 'python-fastapi';
557
+
558
+ // No stack-specific pack → use custom
559
+ return 'custom';
560
+ }
561
+
523
562
  // ── Install for cursor / windsurf / copilot ─────────────────────
524
563
  async function installRulesOnly() {
525
564
  const targets = getTargets();
@@ -403,29 +403,66 @@ npm test && npm run build
403
403
 
404
404
  **This is NOT a self-review.** Spawn a separate review agent to get a fresh perspective. The reviewer finds issues, you fix them, repeat until clean.
405
405
 
406
- ### Step 1: Gather review context
406
+ ### Step 1: Load rules from config
407
407
 
408
- Before spawning the reviewer, collect everything it needs:
408
+ The review uses **configurable rules**. Load them in this order:
409
409
 
410
410
  ```bash
411
- # 1. Get changed files by type
412
- git diff main...HEAD --name-only | grep '\.kt$' # backend files
413
- git diff main...HEAD --name-only | grep '\.tsx\?$' # frontend files
414
- git diff main...HEAD --name-only | grep '\.sql$' # migration files
411
+ # 1. Check for project config
412
+ cat .spartan/config.yaml 2>/dev/null || cat ~/.spartan/config.yaml 2>/dev/null
413
+ ```
415
414
 
416
- # 2. Find spec and plan for this feature
417
- ls .planning/specs/*.md .planning/plans/*.md .planning/designs/*.md 2>/dev/null
415
+ **If `.spartan/config.yaml` exists:**
416
+ - Read the `rules` section → get rule file paths for the current mode
417
+ - Read the `review-stages` section → get which stages to run
418
+ - Read `file-types` section → classify changed files by mode
419
+ - If `extends` is set, load the base profile first, then apply overrides (`rules-add`, `rules-remove`, `rules-override`)
420
+ - If `conditional-rules` is set, match rules to changed files by glob pattern
421
+
422
+ **If no config exists — auto-generate from installed packs:**
423
+
424
+ ```bash
425
+ # Check what packs are installed
426
+ cat .claude/.spartan-packs 2>/dev/null || cat ~/.claude/.spartan-packs 2>/dev/null
427
+ ```
428
+
429
+ If a packs file exists, generate config from the matching profile:
430
+ - Has `backend-micronaut` → use `kotlin-micronaut` profile
431
+ - Has `frontend-react` → use `react-nextjs` profile
432
+ - Has `backend-nodejs` → use `typescript-node` profile
433
+ - Has `backend-python` → use `python-fastapi` profile
434
+ - None of the above → use `custom` profile
435
+
436
+ Look for the profile in the toolkit source:
437
+ ```bash
438
+ REPO_PATH=$(cat ~/.claude/.spartan-repo 2>/dev/null || echo "")
439
+ ls "$REPO_PATH/toolkit/profiles/" 2>/dev/null
440
+ ```
418
441
 
419
- # 3. Find installed rules (pick based on mode)
420
- ls rules/backend-micronaut/ rules/database/ rules/frontend-react/ 2>/dev/null
421
- # Also check ~/.claude/rules/ if project rules/ not found
442
+ Copy the matching profile to `.spartan/config.yaml`. Tell the user:
443
+ > "No config found. Generated `.spartan/config.yaml` from {profile} profile. Edit it to customize."
444
+
445
+ **If no packs file either (bare fallback):**
446
+ - Scan `rules/` directory for all `.md` files
447
+ - Group by subdirectory: `rules/backend-micronaut/` → backend, `rules/frontend-react/` → frontend, `rules/database/` → backend, `rules/core/` → shared
448
+ - If no `rules/` dir, check `.claude/rules/` then `~/.claude/rules/`
449
+ - Use all 7 default review stages
450
+
451
+ ### Step 2: Gather review context
452
+
453
+ ```bash
454
+ # Get changed files by type (use file-types from config if available)
455
+ git diff main...HEAD --name-only
456
+
457
+ # Find spec and plan for this feature
458
+ ls .planning/specs/*.md .planning/plans/*.md .planning/designs/*.md 2>/dev/null
422
459
  ```
423
460
 
424
- ### Step 2: Spawn the review agent
461
+ Classify each changed file into backend/frontend/migration using the `file-types` from config (or defaults: `.kt/.java/.go/.py` = backend, `.tsx/.ts/.vue` = frontend, `.sql` = migration).
425
462
 
426
- Use the `Agent` tool to spawn a reviewer. **The prompt changes based on mode.**
463
+ ### Step 3: Spawn the review agent
427
464
 
428
- Build the prompt from these blocks include only what matches the mode:
465
+ Use the `Agent` tool to spawn a reviewer. **The prompt is built from the config.**
429
466
 
430
467
  ```
431
468
  Agent:
@@ -435,9 +472,9 @@ Agent:
435
472
  You are reviewing code changes for the feature: {feature name}.
436
473
 
437
474
  ## What changed
438
- - Backend files: {list .kt files from git diff, or "none"}
439
- - Frontend files: {list .tsx/.ts files from git diff, or "none"}
440
- - Migration files: {list .sql files from git diff, or "none"}
475
+ - Backend files: {list from git diff, classified by file-types config}
476
+ - Frontend files: {list from git diff}
477
+ - Migration files: {list from git diff}
441
478
  - Design doc: {path if exists, or "none"}
442
479
 
443
480
  ## Spec and plan
@@ -448,62 +485,65 @@ Agent:
448
485
  ## Rules to check against
449
486
  Read these rule files BEFORE reviewing code. They are the source of truth.
450
487
 
451
- {IF backend or full-stack mode, include:}
452
- **Backend rules (read all of these):**
453
- - `rules/backend-micronaut/KOTLIN.md` — null safety, Either error handling, coroutines, no `!!`
454
- - `rules/backend-micronaut/CONTROLLERS.md` thin controllers, @ExecuteOn, @Secured, delegate to Manager
455
- - `rules/backend-micronaut/API_DESIGN.md` — query params only, RPC-style URLs, no path params
456
- - `rules/backend-micronaut/SERVICES_AND_BEANS.md` — Manager returns Either, service layer patterns
457
- - `rules/database/SCHEMA.md` — TEXT not VARCHAR, no FK, soft deletes, UUID PKs, standard columns
458
- - `rules/database/ORM_AND_REPO.md` — Exposed ORM, repository pattern
459
- - `rules/database/TRANSACTIONS.md` transaction(db.primary) {} for multi-table ops
460
-
461
- {IF frontend or full-stack mode, include:}
462
- **Frontend rules (read all of these):**
463
- - `rules/frontend-react/FRONTEND.md` build check before commit, API case conversion, null safety, optimistic updates
464
-
465
- {IF design doc exists, include:}
488
+ {List ALL rule paths from config, grouped by mode. Example:}
489
+
490
+ **Backend rules (from .spartan/config.yaml):**
491
+ {for each rule in config.rules.backend + config.rules.shared:}
492
+ - `{rule path}`
493
+ {end for}
494
+
495
+ **Frontend rules (from .spartan/config.yaml):**
496
+ {for each rule in config.rules.frontend + config.rules.shared:}
497
+ - `{rule path}`
498
+ {end for}
499
+
500
+ **Conditional rules (if any):**
501
+ {for each conditional rule where changed files match applies-to:}
502
+ - `{rule path}` applies to files matching `{glob}`
503
+ {end for}
504
+
505
+ {IF design doc exists:}
466
506
  **Design compliance:**
467
507
  - Read the design doc at {path}. Check that UI matches the approved design.
468
- - Flag any component that looks different from the design spec.
469
508
 
470
- ## Review stages (check all that apply)
509
+ ## Review stages
510
+ {List ONLY the stages that are enabled in config.review-stages.
511
+ For each stage, include its name and description from config.
512
+ If no config, use all 7 defaults below.}
471
513
 
472
514
  **Stage 1 — Correctness & Requirements**
473
515
  - Does the code match the spec? Any missing requirements?
474
516
  - Are all edge cases handled?
475
- - Is error handling using Either (not thrown exceptions)?
517
+ - Error handling follows the project's approach (check the rules)?
476
518
 
477
519
  **Stage 2 — Stack Conventions**
478
- {backend}: Controllers thin? Manager has business logic? Either<ClientException, T>? No `!!`? @ExecuteOn on blocking calls? @Secured on controllers?
479
- {frontend}: Strict TypeScript? No `any`? Hooks rules followed? Server vs client components correct?
520
+ - Code follows the patterns described in the loaded rule files?
521
+ - Stack idioms are correct for this language/framework?
480
522
 
481
523
  **Stage 3 — Test Coverage**
482
- - New endpoints have @MicronautTest integration tests?
524
+ - Tests exist for new code?
483
525
  - Tests are independent (no order dependency)?
484
- - Edge cases tested? Happy path + error paths?
485
- - Frontend: components tested with Testing Library?
526
+ - Edge cases covered? Happy path + error paths?
486
527
 
487
528
  **Stage 4 — Architecture & Clean Code**
488
- - Layered: Controller Manager Service/Repository?
489
- - No business logic in controllers or repositories?
529
+ - Architecture matches what the config says (layered, hexagonal, etc.)?
530
+ - Proper separation between layers?
490
531
  - Functions small and focused? No deep nesting?
491
532
  - No duplication, no dead code?
492
533
 
493
534
  **Stage 5 — Database & API**
494
- - Migration uses TEXT not VARCHAR? No FK constraints?
495
- - Soft delete with deleted_at? Standard columns (id, created_at, updated_at, deleted_at)?
496
- - UUID primary keys? Input validation on public endpoints?
497
- - API URLs follow RPC style?
535
+ - Schema follows the rules? (check loaded database rules)
536
+ - API design follows the rules? (check loaded API rules)
537
+ - Input validation on public endpoints?
498
538
 
499
539
  **Stage 6 — Security**
500
540
  - Auth checks on all endpoints?
501
541
  - Input validated and sanitized?
502
- - No sensitive data logged or exposed in responses?
503
- - No SQL injection, XSS, or command injection risks?
542
+ - No sensitive data logged or exposed?
543
+ - No injection risks?
504
544
 
505
545
  **Stage 7 — Documentation Gaps**
506
- - New pattern used that should be documented? → flag for rules update
546
+ - New pattern that should be documented? → flag for rules update
507
547
  - New convention established? → flag for .memory/patterns/
508
548
  - Recurring issue that should become a rule? → flag it
509
549
 
@@ -512,13 +552,13 @@ Agent:
512
552
  For each issue:
513
553
  - File and line number
514
554
  - What's wrong
515
- - Which rule it breaks (with rule file reference)
555
+ - Which rule it breaks (with rule file path)
516
556
  - Severity: HIGH (must fix) / MEDIUM (should fix) / LOW (nice to have)
517
557
  - Suggested fix
518
558
 
519
559
  End with:
520
560
  - **PASS** or **NEEDS CHANGES** (list all HIGH/MEDIUM issues)
521
- - **Documentation updates needed** (list any rule/pattern updates from Stage 7, or "none")
561
+ - **Documentation updates needed** (list any from Stage 7, or "none")
522
562
  - **What's clean** (always include — praise good code)
523
563
  ```
524
564
 
@@ -1,16 +1,36 @@
1
1
  ---
2
2
  name: spartan:fe-review
3
- description: Thorough PR review for React/Next.js code — App Router conventions, performance, accessibility, TypeScript strictness, and test coverage.
3
+ description: Thorough PR review for frontend code — loads rules from config, defaults to React/Next.js conventions
4
4
  argument-hint: "[optional: PR title or focus area]"
5
5
  ---
6
6
 
7
7
  # Frontend PR Review: {{ args[0] | default: "current branch" }}
8
8
 
9
- Performing a comprehensive review of React/Next.js changes.
10
- Run `git diff main...HEAD` and analyze all modified FE files.
9
+ Performing a thorough review of frontend changes.
10
+
11
+ ## Step 0: Load rules
12
+
13
+ ```bash
14
+ # Check for project config
15
+ cat .spartan/config.yaml 2>/dev/null
16
+
17
+ # Get changed frontend files
18
+ git diff main...HEAD --name-only | grep -E '\.(tsx?|jsx?|vue|svelte|css)$'
19
+ ```
20
+
21
+ **If `.spartan/config.yaml` exists:**
22
+ - Read `rules.frontend` + `rules.shared` — check against these rules
23
+ - Read `review-stages` — only run enabled stages
24
+ - If `conditional-rules` is set, match rules to changed files
25
+
26
+ **If no config:** Use the default React/Next.js checklist below + scan for `rules/frontend-react/` or `~/.claude/rules/frontend-react/`.
27
+
28
+ Read all matched rule files before reviewing code.
11
29
 
12
30
  ---
13
31
 
32
+ Run `git diff main...HEAD` and analyze all modified frontend files.
33
+
14
34
  ## Stage 1: App Router Conventions
15
35
 
16
36
  - [ ] New pages use **Server Components by default**