@c0x12c/spartan-ai-toolkit 1.6.5 → 1.7.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.
@@ -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.0"
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.0",
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.0
@@ -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,46 @@ 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 (source of truth)
412
+ cat .spartan/config.yaml 2>/dev/null
415
413
 
416
- # 2. Find spec and plan for this feature
417
- ls .planning/specs/*.md .planning/plans/*.md .planning/designs/*.md 2>/dev/null
414
+ # 2. If no config, scan for installed rules
415
+ ls rules/ .claude/rules/ ~/.claude/rules/ 2>/dev/null
416
+ ```
417
+
418
+ **If `.spartan/config.yaml` exists:**
419
+ - Read the `rules` section → get rule file paths for the current mode
420
+ - Read the `review-stages` section → get which stages to run
421
+ - Read `file-types` section → classify changed files by mode
422
+ - If `extends` is set, load the base profile first, then apply overrides (`rules-add`, `rules-remove`, `rules-override`)
423
+ - If `conditional-rules` is set, match rules to changed files by glob pattern
424
+
425
+ **If no config exists (fallback):**
426
+ - Scan `rules/` directory for all `.md` files
427
+ - Group by subdirectory: `rules/backend-micronaut/` → backend, `rules/frontend-react/` → frontend, `rules/database/` → backend, `rules/core/` → shared
428
+ - If no `rules/` dir, check `.claude/rules/` then `~/.claude/rules/`
429
+ - Use all 7 default review stages
430
+
431
+ ### Step 2: Gather review context
432
+
433
+ ```bash
434
+ # Get changed files by type (use file-types from config if available)
435
+ git diff main...HEAD --name-only
418
436
 
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
437
+ # Find spec and plan for this feature
438
+ ls .planning/specs/*.md .planning/plans/*.md .planning/designs/*.md 2>/dev/null
422
439
  ```
423
440
 
424
- ### Step 2: Spawn the review agent
441
+ 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
442
 
426
- Use the `Agent` tool to spawn a reviewer. **The prompt changes based on mode.**
443
+ ### Step 3: Spawn the review agent
427
444
 
428
- Build the prompt from these blocks include only what matches the mode:
445
+ Use the `Agent` tool to spawn a reviewer. **The prompt is built from the config.**
429
446
 
430
447
  ```
431
448
  Agent:
@@ -435,9 +452,9 @@ Agent:
435
452
  You are reviewing code changes for the feature: {feature name}.
436
453
 
437
454
  ## 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"}
455
+ - Backend files: {list from git diff, classified by file-types config}
456
+ - Frontend files: {list from git diff}
457
+ - Migration files: {list from git diff}
441
458
  - Design doc: {path if exists, or "none"}
442
459
 
443
460
  ## Spec and plan
@@ -448,62 +465,65 @@ Agent:
448
465
  ## Rules to check against
449
466
  Read these rule files BEFORE reviewing code. They are the source of truth.
450
467
 
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:}
468
+ {List ALL rule paths from config, grouped by mode. Example:}
469
+
470
+ **Backend rules (from .spartan/config.yaml):**
471
+ {for each rule in config.rules.backend + config.rules.shared:}
472
+ - `{rule path}`
473
+ {end for}
474
+
475
+ **Frontend rules (from .spartan/config.yaml):**
476
+ {for each rule in config.rules.frontend + config.rules.shared:}
477
+ - `{rule path}`
478
+ {end for}
479
+
480
+ **Conditional rules (if any):**
481
+ {for each conditional rule where changed files match applies-to:}
482
+ - `{rule path}` applies to files matching `{glob}`
483
+ {end for}
484
+
485
+ {IF design doc exists:}
466
486
  **Design compliance:**
467
487
  - 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
488
 
470
- ## Review stages (check all that apply)
489
+ ## Review stages
490
+ {List ONLY the stages that are enabled in config.review-stages.
491
+ For each stage, include its name and description from config.
492
+ If no config, use all 7 defaults below.}
471
493
 
472
494
  **Stage 1 — Correctness & Requirements**
473
495
  - Does the code match the spec? Any missing requirements?
474
496
  - Are all edge cases handled?
475
- - Is error handling using Either (not thrown exceptions)?
497
+ - Error handling follows the project's approach (check the rules)?
476
498
 
477
499
  **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?
500
+ - Code follows the patterns described in the loaded rule files?
501
+ - Stack idioms are correct for this language/framework?
480
502
 
481
503
  **Stage 3 — Test Coverage**
482
- - New endpoints have @MicronautTest integration tests?
504
+ - Tests exist for new code?
483
505
  - Tests are independent (no order dependency)?
484
- - Edge cases tested? Happy path + error paths?
485
- - Frontend: components tested with Testing Library?
506
+ - Edge cases covered? Happy path + error paths?
486
507
 
487
508
  **Stage 4 — Architecture & Clean Code**
488
- - Layered: Controller Manager Service/Repository?
489
- - No business logic in controllers or repositories?
509
+ - Architecture matches what the config says (layered, hexagonal, etc.)?
510
+ - Proper separation between layers?
490
511
  - Functions small and focused? No deep nesting?
491
512
  - No duplication, no dead code?
492
513
 
493
514
  **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?
515
+ - Schema follows the rules? (check loaded database rules)
516
+ - API design follows the rules? (check loaded API rules)
517
+ - Input validation on public endpoints?
498
518
 
499
519
  **Stage 6 — Security**
500
520
  - Auth checks on all endpoints?
501
521
  - Input validated and sanitized?
502
- - No sensitive data logged or exposed in responses?
503
- - No SQL injection, XSS, or command injection risks?
522
+ - No sensitive data logged or exposed?
523
+ - No injection risks?
504
524
 
505
525
  **Stage 7 — Documentation Gaps**
506
- - New pattern used that should be documented? → flag for rules update
526
+ - New pattern that should be documented? → flag for rules update
507
527
  - New convention established? → flag for .memory/patterns/
508
528
  - Recurring issue that should become a rule? → flag it
509
529
 
@@ -512,13 +532,13 @@ Agent:
512
532
  For each issue:
513
533
  - File and line number
514
534
  - What's wrong
515
- - Which rule it breaks (with rule file reference)
535
+ - Which rule it breaks (with rule file path)
516
536
  - Severity: HIGH (must fix) / MEDIUM (should fix) / LOW (nice to have)
517
537
  - Suggested fix
518
538
 
519
539
  End with:
520
540
  - **PASS** or **NEEDS CHANGES** (list all HIGH/MEDIUM issues)
521
- - **Documentation updates needed** (list any rule/pattern updates from Stage 7, or "none")
541
+ - **Documentation updates needed** (list any from Stage 7, or "none")
522
542
  - **What's clean** (always include — praise good code)
523
543
  ```
524
544
 
@@ -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**