@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/VERSION +1 -1
- package/agents/phase-reviewer.md +10 -13
- package/bin/cli.js +47 -8
- package/commands/spartan/build.md +71 -51
- package/commands/spartan/fe-review.md +23 -3
- package/commands/spartan/init-rules.md +298 -0
- package/commands/spartan/lint-rules.md +122 -0
- package/commands/spartan/review.md +78 -53
- package/commands/spartan/scan-rules.md +173 -0
- package/commands/spartan.md +7 -0
- package/package.json +1 -1
- package/packs/core.yaml +3 -0
- package/packs/packs.compiled.json +3 -0
- package/templates/spartan-config.yaml +164 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.7.0
|
package/agents/phase-reviewer.md
CHANGED
|
@@ -81,26 +81,23 @@ Pick the right checks based on file types:
|
|
|
81
81
|
|
|
82
82
|
## How You Work
|
|
83
83
|
|
|
84
|
-
1. **Load
|
|
84
|
+
1. **Load rules from config.** Before looking at any code, find and read the project's rules.
|
|
85
85
|
|
|
86
|
-
**
|
|
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
|
-
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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:
|
|
406
|
+
### Step 1: Load rules from config
|
|
407
407
|
|
|
408
|
-
|
|
408
|
+
The review uses **configurable rules**. Load them in this order:
|
|
409
409
|
|
|
410
410
|
```bash
|
|
411
|
-
# 1.
|
|
412
|
-
|
|
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.
|
|
417
|
-
ls
|
|
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
|
-
#
|
|
420
|
-
ls
|
|
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
|
-
|
|
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
|
-
|
|
443
|
+
### Step 3: Spawn the review agent
|
|
427
444
|
|
|
428
|
-
|
|
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
|
|
439
|
-
- Frontend files: {list
|
|
440
|
-
- Migration files: {list
|
|
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
|
-
{
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
- `
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
{
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
{
|
|
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
|
|
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
|
-
-
|
|
497
|
+
- Error handling follows the project's approach (check the rules)?
|
|
476
498
|
|
|
477
499
|
**Stage 2 — Stack Conventions**
|
|
478
|
-
|
|
479
|
-
|
|
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
|
-
-
|
|
504
|
+
- Tests exist for new code?
|
|
483
505
|
- Tests are independent (no order dependency)?
|
|
484
|
-
- Edge cases
|
|
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
|
-
-
|
|
489
|
-
-
|
|
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
|
-
-
|
|
495
|
-
-
|
|
496
|
-
-
|
|
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
|
|
503
|
-
- No
|
|
522
|
+
- No sensitive data logged or exposed?
|
|
523
|
+
- No injection risks?
|
|
504
524
|
|
|
505
525
|
**Stage 7 — Documentation Gaps**
|
|
506
|
-
- New pattern
|
|
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
|
|
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
|
|
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
|
|
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
|
|
10
|
-
|
|
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**
|