jdi-cli 0.1.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/AGENTS.md +209 -0
- package/ARCHITECTURE.md +210 -0
- package/COMMANDS.md +241 -0
- package/CREATE-EXAMPLE.md +385 -0
- package/CREATE.md +315 -0
- package/EXTENSION.md +141 -0
- package/LICENSE +21 -0
- package/MEMORY.md +471 -0
- package/PORTABILITY.md +438 -0
- package/README.md +789 -0
- package/bin/git-hooks/post-commit +16 -0
- package/bin/git-hooks/pre-commit +21 -0
- package/bin/jdi-build.ps1 +381 -0
- package/bin/jdi-build.sh +332 -0
- package/bin/jdi-doctor.ps1 +403 -0
- package/bin/jdi-doctor.sh +400 -0
- package/bin/jdi-install-caveman.ps1 +97 -0
- package/bin/jdi-install-caveman.sh +99 -0
- package/bin/jdi-install-playwright.ps1 +319 -0
- package/bin/jdi-install-playwright.sh +284 -0
- package/bin/jdi-install.ps1 +154 -0
- package/bin/jdi-install.sh +132 -0
- package/bin/jdi-uninstall.ps1 +309 -0
- package/bin/jdi-uninstall.sh +264 -0
- package/bin/jdi-update.ps1 +215 -0
- package/bin/jdi-update.sh +209 -0
- package/bin/jdi.js +460 -0
- package/bin/lib/jdi-monitor.ps1 +66 -0
- package/bin/lib/jdi-monitor.sh +74 -0
- package/bin/lib/jdi-truncate.ps1 +96 -0
- package/bin/lib/jdi-truncate.sh +99 -0
- package/bin/lib/ui.js +197 -0
- package/core/agents/jdi-adopter.md +465 -0
- package/core/agents/jdi-architect.md +894 -0
- package/core/agents/jdi-asker.md +153 -0
- package/core/agents/jdi-bootstrap.md +247 -0
- package/core/agents/jdi-planner.md +254 -0
- package/core/agents/jdi-researcher.md +303 -0
- package/core/commands/jdi-adopt.md +155 -0
- package/core/commands/jdi-bootstrap.md +81 -0
- package/core/commands/jdi-create.md +80 -0
- package/core/commands/jdi-discuss.md +80 -0
- package/core/commands/jdi-do.md +200 -0
- package/core/commands/jdi-loop.md +315 -0
- package/core/commands/jdi-new.md +131 -0
- package/core/commands/jdi-plan.md +73 -0
- package/core/commands/jdi-ship.md +146 -0
- package/core/commands/jdi-verify.md +159 -0
- package/core/skills/clean-code/SKILL.md +261 -0
- package/core/skills/dry/SKILL.md +150 -0
- package/core/skills/frontend-rules/SKILL.md +386 -0
- package/core/skills/frontend-validator/SKILL.md +567 -0
- package/core/skills/kiss/SKILL.md +178 -0
- package/core/skills/solid/SKILL.md +281 -0
- package/core/skills/yagni/SKILL.md +207 -0
- package/core/templates/agent.md +72 -0
- package/core/templates/doer-specialist.md +216 -0
- package/core/templates/reviewer-specialist.md +405 -0
- package/core/templates/skill.md +66 -0
- package/package.json +70 -0
- package/runtimes/antigravity/agents.md +74 -0
- package/runtimes/antigravity/skills/clean-code/SKILL.md +252 -0
- package/runtimes/antigravity/skills/dry/SKILL.md +141 -0
- package/runtimes/antigravity/skills/frontend-rules/SKILL.md +376 -0
- package/runtimes/antigravity/skills/frontend-validator/SKILL.md +559 -0
- package/runtimes/antigravity/skills/jdi-adopt/SKILL.md +155 -0
- package/runtimes/antigravity/skills/jdi-adopter/SKILL.md +436 -0
- package/runtimes/antigravity/skills/jdi-architect/SKILL.md +872 -0
- package/runtimes/antigravity/skills/jdi-asker/SKILL.md +125 -0
- package/runtimes/antigravity/skills/jdi-asker/references/context-template.md +34 -0
- package/runtimes/antigravity/skills/jdi-asker/references/decision-format.md +19 -0
- package/runtimes/antigravity/skills/jdi-asker/scripts/find_phase_dir.sh +25 -0
- package/runtimes/antigravity/skills/jdi-bootstrap/SKILL.md +81 -0
- package/runtimes/antigravity/skills/jdi-create/SKILL.md +80 -0
- package/runtimes/antigravity/skills/jdi-discuss/SKILL.md +80 -0
- package/runtimes/antigravity/skills/jdi-discuss/scripts/run_command.sh +62 -0
- package/runtimes/antigravity/skills/jdi-do/SKILL.md +200 -0
- package/runtimes/antigravity/skills/jdi-loop/SKILL.md +315 -0
- package/runtimes/antigravity/skills/jdi-new/SKILL.md +131 -0
- package/runtimes/antigravity/skills/jdi-plan/SKILL.md +73 -0
- package/runtimes/antigravity/skills/jdi-planner/SKILL.md +225 -0
- package/runtimes/antigravity/skills/jdi-researcher/SKILL.md +274 -0
- package/runtimes/antigravity/skills/jdi-ship/SKILL.md +146 -0
- package/runtimes/antigravity/skills/jdi-verify/SKILL.md +159 -0
- package/runtimes/antigravity/skills/kiss/SKILL.md +169 -0
- package/runtimes/antigravity/skills/solid/SKILL.md +272 -0
- package/runtimes/antigravity/skills/yagni/SKILL.md +198 -0
- package/runtimes/claude/CLAUDE.md +91 -0
- package/runtimes/claude/agents/jdi-adopter.md +430 -0
- package/runtimes/claude/agents/jdi-architect.md +864 -0
- package/runtimes/claude/agents/jdi-asker.md +119 -0
- package/runtimes/claude/agents/jdi-bootstrap.md +213 -0
- package/runtimes/claude/agents/jdi-planner.md +221 -0
- package/runtimes/claude/agents/jdi-researcher.md +269 -0
- package/runtimes/claude/commands/jdi-adopt.md +155 -0
- package/runtimes/claude/commands/jdi-bootstrap.md +81 -0
- package/runtimes/claude/commands/jdi-create.md +80 -0
- package/runtimes/claude/commands/jdi-discuss.md +80 -0
- package/runtimes/claude/commands/jdi-do.md +200 -0
- package/runtimes/claude/commands/jdi-loop.md +315 -0
- package/runtimes/claude/commands/jdi-new.md +131 -0
- package/runtimes/claude/commands/jdi-plan.md +73 -0
- package/runtimes/claude/commands/jdi-ship.md +146 -0
- package/runtimes/claude/commands/jdi-verify.md +159 -0
- package/runtimes/claude/settings.example.json +132 -0
- package/runtimes/claude/skills/clean-code/SKILL.md +247 -0
- package/runtimes/claude/skills/dry/SKILL.md +136 -0
- package/runtimes/claude/skills/frontend-rules/SKILL.md +369 -0
- package/runtimes/claude/skills/frontend-validator/SKILL.md +553 -0
- package/runtimes/claude/skills/kiss/SKILL.md +164 -0
- package/runtimes/claude/skills/solid/SKILL.md +267 -0
- package/runtimes/claude/skills/yagni/SKILL.md +193 -0
- package/runtimes/copilot/agents/jdi-adopter.agent.md +430 -0
- package/runtimes/copilot/agents/jdi-architect.agent.md +864 -0
- package/runtimes/copilot/agents/jdi-asker.agent.md +119 -0
- package/runtimes/copilot/agents/jdi-bootstrap.agent.md +213 -0
- package/runtimes/copilot/agents/jdi-planner.agent.md +221 -0
- package/runtimes/copilot/agents/jdi-researcher.agent.md +269 -0
- package/runtimes/copilot/copilot-instructions.md +80 -0
- package/runtimes/copilot/prompts/jdi-adopt.prompt.md +155 -0
- package/runtimes/copilot/prompts/jdi-bootstrap.prompt.md +81 -0
- package/runtimes/copilot/prompts/jdi-create.prompt.md +80 -0
- package/runtimes/copilot/prompts/jdi-discuss.prompt.md +80 -0
- package/runtimes/copilot/prompts/jdi-do.prompt.md +200 -0
- package/runtimes/copilot/prompts/jdi-loop.prompt.md +315 -0
- package/runtimes/copilot/prompts/jdi-new.prompt.md +131 -0
- package/runtimes/copilot/prompts/jdi-plan.prompt.md +73 -0
- package/runtimes/copilot/prompts/jdi-ship.prompt.md +146 -0
- package/runtimes/copilot/prompts/jdi-verify.prompt.md +159 -0
- package/runtimes/opencode/AGENTS.md +87 -0
- package/runtimes/opencode/agents/jdi-adopter.md +434 -0
- package/runtimes/opencode/agents/jdi-architect.md +861 -0
- package/runtimes/opencode/agents/jdi-asker.md +123 -0
- package/runtimes/opencode/agents/jdi-bootstrap.md +217 -0
- package/runtimes/opencode/agents/jdi-planner.md +225 -0
- package/runtimes/opencode/agents/jdi-researcher.md +273 -0
- package/runtimes/opencode/commands/jdi-adopt.md +155 -0
- package/runtimes/opencode/commands/jdi-bootstrap.md +81 -0
- package/runtimes/opencode/commands/jdi-create.md +80 -0
- package/runtimes/opencode/commands/jdi-discuss.md +80 -0
- package/runtimes/opencode/commands/jdi-do.md +200 -0
- package/runtimes/opencode/commands/jdi-loop.md +315 -0
- package/runtimes/opencode/commands/jdi-new.md +131 -0
- package/runtimes/opencode/commands/jdi-plan.md +73 -0
- package/runtimes/opencode/commands/jdi-ship.md +146 -0
- package/runtimes/opencode/commands/jdi-verify.md +159 -0
- package/runtimes/opencode/opencode.example.jsonc +169 -0
- package/runtimes/opencode/skills/clean-code/SKILL.md +247 -0
- package/runtimes/opencode/skills/dry/SKILL.md +136 -0
- package/runtimes/opencode/skills/frontend-rules/SKILL.md +369 -0
- package/runtimes/opencode/skills/frontend-validator/SKILL.md +553 -0
- package/runtimes/opencode/skills/kiss/SKILL.md +164 -0
- package/runtimes/opencode/skills/solid/SKILL.md +267 -0
- package/runtimes/opencode/skills/yagni/SKILL.md +193 -0
- package/templates-jdi-folder/config.json +18 -0
- package/templates-jdi-folder/registry.md +31 -0
- package/templates-jdi-folder/reviewers.md +33 -0
- package/templates-jdi-folder/skills-registry.md +32 -0
- package/templates-jdi-folder/specialists.md +39 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jdi-plan
|
|
3
|
+
description: Generates phase PLAN.md. Decomposes into tasks with files_modified, acceptance, parallelism waves.
|
|
4
|
+
argument_hint: "<phase_number> [--review]"
|
|
5
|
+
runtime_intent:
|
|
6
|
+
invokes_agent: jdi-planner
|
|
7
|
+
runtime_overrides:
|
|
8
|
+
claude:
|
|
9
|
+
allowed-tools: [Read, Write, Bash, Grep, Glob, AskUserQuestion, Agent]
|
|
10
|
+
copilot:
|
|
11
|
+
tools: [read, write, grep, glob]
|
|
12
|
+
opencode:
|
|
13
|
+
agent: jdi-planner
|
|
14
|
+
subtask: true
|
|
15
|
+
model: anthropic/claude-sonnet-4-20250514
|
|
16
|
+
antigravity:
|
|
17
|
+
triggers:
|
|
18
|
+
- "/jdi-plan"
|
|
19
|
+
- "plan phase {N}"
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<objective>
|
|
23
|
+
Generates PLAN.md for the given phase. Decomposes into tasks (max 8), groups into parallelism waves, maps files_modified and acceptance.
|
|
24
|
+
</objective>
|
|
25
|
+
|
|
26
|
+
<arguments>
|
|
27
|
+
- `phase_number` (required): phase number, e.g. `1`, `2`
|
|
28
|
+
- `--review` (optional): show preview and ask for approval before saving
|
|
29
|
+
</arguments>
|
|
30
|
+
|
|
31
|
+
<process>
|
|
32
|
+
|
|
33
|
+
### Step 1: Validation
|
|
34
|
+
```bash
|
|
35
|
+
test -d .jdi/ || { echo "Not a JDI project. Run /jdi-new."; exit 1; }
|
|
36
|
+
test -f .jdi/PROJECT.md || { echo "PROJECT.md missing."; exit 1; }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Verify phase CONTEXT.md exists:
|
|
40
|
+
```bash
|
|
41
|
+
ls .jdi/phases/{NN}*/CONTEXT.md 2>/dev/null || { echo "CONTEXT.md missing. Run /jdi-discuss {N}"; exit 1; }
|
|
42
|
+
|
|
43
|
+
# Context budget warm-up (does not block)
|
|
44
|
+
JDI_LIB="$(dirname "$(command -v jdi 2>/dev/null || echo /usr/local/bin/jdi)")/../lib"
|
|
45
|
+
if [ -f "$JDI_LIB/jdi-monitor.sh" ]; then
|
|
46
|
+
bash "$JDI_LIB/jdi-monitor.sh" .jdi/PROJECT.md .jdi/DECISIONS.md .jdi/phases/{NN}*/CONTEXT.md || true
|
|
47
|
+
fi
|
|
48
|
+
# Windows: pwsh -File "$JDI_LIB/jdi-monitor.ps1" -Paths @(...)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Step 2: Spawn planner
|
|
52
|
+
Invoke `jdi-planner` with phase_number. Wait.
|
|
53
|
+
|
|
54
|
+
### Step 3: Verify
|
|
55
|
+
```bash
|
|
56
|
+
test -f .jdi/phases/{NN}*/PLAN.md || { echo "PLAN.md not created"; exit 1; }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Step 4: Confirm
|
|
60
|
+
Show plan summary + suggest `/jdi-do {N}`.
|
|
61
|
+
|
|
62
|
+
</process>
|
|
63
|
+
|
|
64
|
+
<gates>
|
|
65
|
+
- pre: `.jdi/PROJECT.md` + `.jdi/phases/{NN-slug}/CONTEXT.md` exist
|
|
66
|
+
- post: PLAN.md created + STATE.md updated + commit
|
|
67
|
+
</gates>
|
|
68
|
+
|
|
69
|
+
<errors>
|
|
70
|
+
- CONTEXT.md missing -> suggest `/jdi-discuss {N}`
|
|
71
|
+
- Phase does not exist in ROADMAP -> error
|
|
72
|
+
- Planner cancelled -> exit clean
|
|
73
|
+
</errors>
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jdi-ship
|
|
3
|
+
description: Finalizes phase after verify. Updates ROADMAP.md, marks phase as done, advances pointer to next.
|
|
4
|
+
argument_hint: "<phase_number>"
|
|
5
|
+
runtime_intent:
|
|
6
|
+
invokes_agent: none
|
|
7
|
+
runtime_overrides:
|
|
8
|
+
claude:
|
|
9
|
+
allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion]
|
|
10
|
+
copilot:
|
|
11
|
+
tools: [read, write, edit, grep, glob, terminal]
|
|
12
|
+
opencode:
|
|
13
|
+
subtask: true
|
|
14
|
+
antigravity:
|
|
15
|
+
triggers:
|
|
16
|
+
- "/jdi-ship"
|
|
17
|
+
- "finalize phase {N}"
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<objective>
|
|
21
|
+
Finalizes phase after /jdi-verify approves. Updates ROADMAP.md (phase: done), advances STATE to next phase, final commit.
|
|
22
|
+
</objective>
|
|
23
|
+
|
|
24
|
+
<arguments>
|
|
25
|
+
- `phase_number` (required)
|
|
26
|
+
</arguments>
|
|
27
|
+
|
|
28
|
+
<process>
|
|
29
|
+
|
|
30
|
+
### Step 1: Validation
|
|
31
|
+
```bash
|
|
32
|
+
test -d .jdi/ || { echo "Not a JDI project."; exit 1; }
|
|
33
|
+
|
|
34
|
+
# Verify REVIEW.md exists
|
|
35
|
+
ls .jdi/phases/{NN}*/REVIEW.md 2>/dev/null || {
|
|
36
|
+
echo "REVIEW.md missing. /jdi-verify {N}."
|
|
37
|
+
exit 1
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Read verdict
|
|
41
|
+
VERDICT=$(grep -oE 'Verdict:\*\* (APPROVED|APPROVED_WITH_WARNINGS|BLOCKED)' .jdi/phases/{NN}*/REVIEW.md | awk '{print $2}')
|
|
42
|
+
|
|
43
|
+
if [ "$VERDICT" = "BLOCKED" ]; then
|
|
44
|
+
echo "Phase {N} BLOCKED. Fix before ship."
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Step 2: Confirm with user (only if WITH_WARNINGS)
|
|
50
|
+
|
|
51
|
+
If `VERDICT=APPROVED_WITH_WARNINGS`:
|
|
52
|
+
```
|
|
53
|
+
Phase {N} has uncorrected warnings. Ship anyway?
|
|
54
|
+
- Yes, ship (warnings remain in REVIEW.md)
|
|
55
|
+
- No, fix first
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If "No" -> exit clean.
|
|
59
|
+
|
|
60
|
+
### Step 3: Update ROADMAP.md
|
|
61
|
+
|
|
62
|
+
Edit `.jdi/ROADMAP.md`:
|
|
63
|
+
- Phase {N}: `status: done`
|
|
64
|
+
- Phase {N+1}: `status: ready` (if exists)
|
|
65
|
+
|
|
66
|
+
If no phase {N+1}:
|
|
67
|
+
```
|
|
68
|
+
All phases complete.
|
|
69
|
+
Project delivered.
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Step 4: Update STATE.md
|
|
73
|
+
|
|
74
|
+
```markdown
|
|
75
|
+
current_phase: {N+1 or done}
|
|
76
|
+
phase_status: ready (if {N+1} exists) or complete
|
|
77
|
+
next_step: /jdi-discuss {N+1} or done
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 5: Archive old phases (compaction)
|
|
81
|
+
|
|
82
|
+
Read `archive_after` from `.jdi/config.json` (default 5). If current phase advances to `N+1`, and a phase exists with number `<= (N+1) - archive_after`, move to `.jdi/archive/`.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
ARCHIVE_AFTER=5
|
|
86
|
+
if [ -f .jdi/config.json ]; then
|
|
87
|
+
if command -v jq >/dev/null 2>&1; then
|
|
88
|
+
ARCHIVE_AFTER=$(jq -r '.compaction.archive_after // 5' .jdi/config.json)
|
|
89
|
+
fi
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
NEXT=$((N + 1))
|
|
93
|
+
THRESHOLD=$((NEXT - ARCHIVE_AFTER))
|
|
94
|
+
|
|
95
|
+
if [ "$THRESHOLD" -ge 1 ]; then
|
|
96
|
+
mkdir -p .jdi/archive
|
|
97
|
+
test -f .jdi/archive/index.md || echo "# Archive index" > .jdi/archive/index.md
|
|
98
|
+
|
|
99
|
+
for dir in .jdi/phases/*/; do
|
|
100
|
+
NN=$(basename "$dir" | grep -oE '^[0-9]+' || true)
|
|
101
|
+
[ -z "$NN" ] && continue
|
|
102
|
+
NN_NUM=$((10#$NN)) # force decimal
|
|
103
|
+
if [ "$NN_NUM" -le "$THRESHOLD" ]; then
|
|
104
|
+
VERDICT_OLD=$(grep -oE 'Verdict:\*\* (APPROVED|APPROVED_WITH_WARNINGS|BLOCKED)' "$dir/REVIEW.md" 2>/dev/null | awk '{print $2}' || echo "UNKNOWN")
|
|
105
|
+
mv "$dir" .jdi/archive/
|
|
106
|
+
echo "- $(basename "$dir"): ${VERDICT_OLD} (archived $(date -u +%F))" >> .jdi/archive/index.md
|
|
107
|
+
fi
|
|
108
|
+
done
|
|
109
|
+
fi
|
|
110
|
+
# Windows: equivalent in PowerShell — Move-Item + Add-Content
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Archived phases remain accessible via `.jdi/archive/` but exit the default read-path. Read-depth rule (`ARCHITECTURE.md > Read-depth scaling`) treats archive as `<= current - 2`.
|
|
114
|
+
|
|
115
|
+
### Step 6: Final commit
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
git add .jdi/ROADMAP.md .jdi/STATE.md .jdi/archive/ 2>/dev/null
|
|
119
|
+
git commit -m "feat({NN-slug}): ship phase {N} ({VERDICT})"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Optional tag (if PROJECT.md has `tag_phases: true`):
|
|
123
|
+
```bash
|
|
124
|
+
git tag "phase-{N}-{slug}"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Step 7: Confirm
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
Phase {N} shipped.
|
|
131
|
+
{if more phases:} Next: /jdi-discuss {N+1}
|
|
132
|
+
{if last:} Project delivered. Tag: phase-{N}-{slug}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
</process>
|
|
136
|
+
|
|
137
|
+
<gates>
|
|
138
|
+
- pre: REVIEW.md exists + verdict != BLOCKED
|
|
139
|
+
- post: ROADMAP.md + STATE.md updated + old phases archived (if applicable) + commit (+ optional tag)
|
|
140
|
+
</gates>
|
|
141
|
+
|
|
142
|
+
<errors>
|
|
143
|
+
- REVIEW missing -> /jdi-verify
|
|
144
|
+
- Verdict BLOCKED -> abort
|
|
145
|
+
- Already shipped -> abort with warning
|
|
146
|
+
</errors>
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jdi-verify
|
|
3
|
+
description: Runs phase quality gates via reviewer specialist. Build, tests, coverage, lint, security checks. Verdict APPROVED / APPROVED_WITH_WARNINGS / BLOCKED.
|
|
4
|
+
argument_hint: "<phase_number>"
|
|
5
|
+
runtime_intent:
|
|
6
|
+
invokes_agent: dynamic
|
|
7
|
+
runtime_overrides:
|
|
8
|
+
claude:
|
|
9
|
+
allowed-tools: [Read, Bash, Grep, Glob, Agent]
|
|
10
|
+
copilot:
|
|
11
|
+
tools: [read, grep, glob, terminal]
|
|
12
|
+
opencode:
|
|
13
|
+
subtask: true
|
|
14
|
+
model: anthropic/claude-sonnet-4-20250514
|
|
15
|
+
antigravity:
|
|
16
|
+
triggers:
|
|
17
|
+
- "/jdi-verify"
|
|
18
|
+
- "verify phase {N}"
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<objective>
|
|
22
|
+
Verifies the phase was delivered correctly. Runs gates defined in the project's reviewer specialist. Verdict blocks or releases the ship.
|
|
23
|
+
</objective>
|
|
24
|
+
|
|
25
|
+
<arguments>
|
|
26
|
+
- `phase_number` (required)
|
|
27
|
+
</arguments>
|
|
28
|
+
|
|
29
|
+
<process>
|
|
30
|
+
|
|
31
|
+
### Step 1: Validation
|
|
32
|
+
```bash
|
|
33
|
+
test -d .jdi/ || { echo "Not a JDI project."; exit 1; }
|
|
34
|
+
|
|
35
|
+
# Verify reviewer exists
|
|
36
|
+
ls .jdi/agents/jdi-reviewer-*.md 2>/dev/null | head -1 || {
|
|
37
|
+
echo "Reviewer missing. /jdi-bootstrap."
|
|
38
|
+
exit 1
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Verify phase was executed
|
|
42
|
+
ls .jdi/phases/{NN}*/SUMMARY.md 2>/dev/null || {
|
|
43
|
+
echo "Phase {N} not executed. /jdi-do {N}."
|
|
44
|
+
exit 1
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Context budget warm-up (does not block)
|
|
48
|
+
JDI_LIB="$(dirname "$(command -v jdi 2>/dev/null || echo /usr/local/bin/jdi)")/../lib"
|
|
49
|
+
if [ -f "$JDI_LIB/jdi-monitor.sh" ]; then
|
|
50
|
+
bash "$JDI_LIB/jdi-monitor.sh" .jdi/PROJECT.md .jdi/DECISIONS.md .jdi/phases/{NN}*/PLAN.md .jdi/phases/{NN}*/SUMMARY.md || true
|
|
51
|
+
fi
|
|
52
|
+
# Windows: pwsh -File "$JDI_LIB/jdi-monitor.ps1" -Paths @(...)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Step 2: Resolve reviewer specialist(s)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
REVIEWERS=$(grep -oE 'jdi-reviewer-[a-z0-9-]+' .jdi/reviewers.md | sort -u)
|
|
59
|
+
REVIEWER_COUNT=$(echo "$REVIEWERS" | wc -l)
|
|
60
|
+
echo "Reviewers registered: $REVIEWER_COUNT"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Single-stack** (`REVIEWER_COUNT == 1`): one reviewer, normal flow.
|
|
64
|
+
**Multi-stack** (`REVIEWER_COUNT > 1`): chain reviewers in registry order. Each writes its own REVIEW segment; aggregate verdict = worst-case (1 BLOCK = overall BLOCK).
|
|
65
|
+
|
|
66
|
+
### Step 3: Spawn reviewer(s)
|
|
67
|
+
|
|
68
|
+
**Single-stack:**
|
|
69
|
+
```
|
|
70
|
+
Agent(
|
|
71
|
+
subagent_type="${REVIEWERS}",
|
|
72
|
+
description="Verify phase {N}",
|
|
73
|
+
prompt="phase={N}, mode=verify"
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Multi-stack:** spawn each reviewer in sequence (NOT parallel — build/test commands may conflict on ports, locks, output dirs):
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
for REVIEWER in $REVIEWERS:
|
|
81
|
+
Agent(
|
|
82
|
+
subagent_type="$REVIEWER",
|
|
83
|
+
description="Verify phase {N} ({REVIEWER})",
|
|
84
|
+
prompt="phase={N}, mode=verify, reviewer_segment=${REVIEWER}"
|
|
85
|
+
)
|
|
86
|
+
# Each reviewer appends to .jdi/phases/{NN-slug}/REVIEW.md under section
|
|
87
|
+
# "## Reviewer: {REVIEWER}" with its own gate results and verdict
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Each reviewer scopes its gates to its `file_glob` (from frontmatter `scope.file_glob`). Coverage threshold enforced only on files matching the glob.
|
|
91
|
+
|
|
92
|
+
Reviewers are read-only. Wait for completion before next.
|
|
93
|
+
|
|
94
|
+
### Step 4: Read aggregate verdict
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
test -f .jdi/phases/{NN}*/REVIEW.md || { echo "REVIEW.md not created"; exit 1; }
|
|
98
|
+
|
|
99
|
+
# Collect all per-reviewer verdicts
|
|
100
|
+
VERDICTS=$(grep -oE 'Verdict:\*\* (APPROVED|APPROVED_WITH_WARNINGS|BLOCKED)' .jdi/phases/{NN}*/REVIEW.md | awk '{print $2}')
|
|
101
|
+
|
|
102
|
+
# Worst-case wins: BLOCK > WARNINGS > APPROVED
|
|
103
|
+
if echo "$VERDICTS" | grep -q BLOCKED; then
|
|
104
|
+
VERDICT=BLOCKED
|
|
105
|
+
elif echo "$VERDICTS" | grep -q APPROVED_WITH_WARNINGS; then
|
|
106
|
+
VERDICT=APPROVED_WITH_WARNINGS
|
|
107
|
+
else
|
|
108
|
+
VERDICT=APPROVED
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# For single-stack, this collapses to the single reviewer's verdict — backward compatible.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Step 5: Update STATE
|
|
115
|
+
|
|
116
|
+
```markdown
|
|
117
|
+
current_phase: {N}
|
|
118
|
+
phase_status: {verified|blocked}
|
|
119
|
+
phase_verdict: {APPROVED|APPROVED_WITH_WARNINGS|BLOCKED}
|
|
120
|
+
next_step: {if APPROVED or WITH_WARNINGS: /jdi-ship {N}; if BLOCKED: fix and /jdi-do {N} again}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
git add .jdi/phases/{NN-slug}/REVIEW.md .jdi/STATE.md
|
|
125
|
+
git commit -m "docs({NN-slug}): verify phase ({VERDICT})"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Step 6: Confirm
|
|
129
|
+
|
|
130
|
+
**APPROVED:**
|
|
131
|
+
```
|
|
132
|
+
Phase {N}: APPROVED. Next: /jdi-ship {N}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**APPROVED_WITH_WARNINGS:**
|
|
136
|
+
```
|
|
137
|
+
Phase {N}: APPROVED_WITH_WARNINGS ({count} warnings).
|
|
138
|
+
REVIEW.md: .jdi/phases/{NN-slug}/REVIEW.md
|
|
139
|
+
Next: /jdi-ship {N} (or fix first)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**BLOCKED:**
|
|
143
|
+
```
|
|
144
|
+
Phase {N}: BLOCKED ({count} blockers). REVIEW.md: .jdi/phases/{NN-slug}/REVIEW.md
|
|
145
|
+
Fix → /jdi-do {N} → /jdi-verify {N}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
</process>
|
|
149
|
+
|
|
150
|
+
<gates>
|
|
151
|
+
- pre: SUMMARY.md exists + reviewer registered in .jdi/reviewers.md
|
|
152
|
+
- post: REVIEW.md created + STATE updated
|
|
153
|
+
</gates>
|
|
154
|
+
|
|
155
|
+
<errors>
|
|
156
|
+
- Reviewer missing -> /jdi-bootstrap
|
|
157
|
+
- SUMMARY missing -> /jdi-do
|
|
158
|
+
- Reviewer fails -> show error, keep state, suggest retry
|
|
159
|
+
</errors>
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: clean-code
|
|
3
|
+
description: Clean Code. Human-readable code, optimized for reading (read 10x more than written). Names reveal intent, small functions, no redundant comments, explicit error handling, no magic numbers. Applies in any language.
|
|
4
|
+
type: skill
|
|
5
|
+
applies_to: |
|
|
6
|
+
Loaded by doer when writing code (any code change).
|
|
7
|
+
Loaded by reviewer at gate 5 to detect code smells.
|
|
8
|
+
loaded_by:
|
|
9
|
+
- jdi-doer-{slug}
|
|
10
|
+
- jdi-reviewer-{slug}
|
|
11
|
+
runtime_overrides:
|
|
12
|
+
antigravity:
|
|
13
|
+
triggers:
|
|
14
|
+
- "Clean Code"
|
|
15
|
+
- "clean code"
|
|
16
|
+
- "code smells"
|
|
17
|
+
- "code readability"
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Skill: Clean Code
|
|
21
|
+
|
|
22
|
+
> Code is read 10x more than written. Optimize for reading.
|
|
23
|
+
|
|
24
|
+
Not about pretty style. About **making reader understand in 1 pass**, without mentally simulating execution.
|
|
25
|
+
|
|
26
|
+
## Rules
|
|
27
|
+
|
|
28
|
+
### 1. Names reveal intent
|
|
29
|
+
|
|
30
|
+
- **Variable**: what it **is**, not how it's stored (`elapsedSeconds` > `t` > `time`)
|
|
31
|
+
- **Function**: what it **does**, verb + object (`calculateTax(order)`, not `tax(order)`)
|
|
32
|
+
- **Boolean**: yes/no question (`isActive`, `hasPermission`, `canSubmit`)
|
|
33
|
+
- **Class/module**: noun (`OrderRepository`, `EmailValidator`)
|
|
34
|
+
- **Interface**: role/capability (`Repository`, `Cacheable`) — no `I`/`Abstract` prefix if language doesn't require
|
|
35
|
+
|
|
36
|
+
### Anti-names
|
|
37
|
+
|
|
38
|
+
| Wrong | Right |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `data`, `info`, `value`, `temp`, `result` | something descriptive of the context |
|
|
41
|
+
| `processData()` | `parseUserPayload()`, `applyDiscount()`, etc |
|
|
42
|
+
| `Manager`, `Helper`, `Util` | name of the real responsibility |
|
|
43
|
+
| `flag`, `status` | `isComplete`, `paymentStatus` |
|
|
44
|
+
| `obj`, `item`, `thing` | actual type |
|
|
45
|
+
| Abbreviations: `usr`, `ctx`, `mgr`, `cfg` | `user`, `context` (exception: well-established domain convention) |
|
|
46
|
+
| Variables with `_2`, `_new`, `_old` | refactor until 1 remains |
|
|
47
|
+
|
|
48
|
+
### 2. Small functions
|
|
49
|
+
|
|
50
|
+
- **Size**: ideally < 20 lines. If over 50, almost certainly doing too much.
|
|
51
|
+
- **1 abstraction level**: inside function, all operations at same level. Mixing "open connection" + "calculate tax" = no.
|
|
52
|
+
- **3-4 params max**: more than that signals either missing object or too much responsibility.
|
|
53
|
+
- **1 logical exit**: early return is OK; multiple returns mid-complex-logic is bad.
|
|
54
|
+
|
|
55
|
+
### 3. Functions do **one** thing
|
|
56
|
+
|
|
57
|
+
If you describe function as "does X **and** Y", split into two. Function name must be precise.
|
|
58
|
+
|
|
59
|
+
Exception: orchestrators (controllers, command handlers) coordinate — OK to describe as "validates, saves, notifies" if each step is a call to another function.
|
|
60
|
+
|
|
61
|
+
### 4. Comments
|
|
62
|
+
|
|
63
|
+
**Default: DON'T write**.
|
|
64
|
+
|
|
65
|
+
Well-named code doesn't need to explain **what** it does. If you feel like writing a comment, first attempt: rename function/variable.
|
|
66
|
+
|
|
67
|
+
### Comments OK when:
|
|
68
|
+
|
|
69
|
+
- **Why** non-obvious: workaround for specific bug, surprising design decision, external constraint
|
|
70
|
+
- **Critical invariant**: "this array MUST be sorted for binary search to work"
|
|
71
|
+
- **TODO/FIXME marker** with ticket link: `// TODO(#1234): handle UTF-16 surrogate`
|
|
72
|
+
- **Pitfall warning**: "// don't call this in a loop, O(n^2)"
|
|
73
|
+
- **Public API doc**: contract for caller (params, returns, exceptions)
|
|
74
|
+
|
|
75
|
+
### Comments bad when:
|
|
76
|
+
|
|
77
|
+
- Explain **what** (code already says)
|
|
78
|
+
- Repeat the function name in English
|
|
79
|
+
- Comment goes stale relative to code
|
|
80
|
+
- "// removed on XX/YY" left in the tree
|
|
81
|
+
- "// hack" without explanation
|
|
82
|
+
- "// not sure why this works" — investigate, don't guess
|
|
83
|
+
|
|
84
|
+
### 5. Explicit error handling
|
|
85
|
+
|
|
86
|
+
- **Never silence exception**: `try { ... } catch {}` is **latent bug**
|
|
87
|
+
- **Explicit handling**: structured log + rethrow OR return Result/Either
|
|
88
|
+
- **Errors are part of the contract**: document what can fail
|
|
89
|
+
- **Boundary**: handle error at the boundary (controller, top-level handler), not at every internal call
|
|
90
|
+
- **Validation**: at the entry (boundary), not scattered
|
|
91
|
+
|
|
92
|
+
### 6. No magic numbers/strings
|
|
93
|
+
|
|
94
|
+
- Number or string with meaning becomes a **named constant**
|
|
95
|
+
- `if (status === 3)` becomes `if (status === OrderStatus.Shipped)`
|
|
96
|
+
- `setTimeout(fn, 86400000)` becomes `setTimeout(fn, MS_PER_DAY)`
|
|
97
|
+
- Exception: 0, 1, -1, universally clear cases
|
|
98
|
+
|
|
99
|
+
### 7. Command-Query Separation (CQS)
|
|
100
|
+
|
|
101
|
+
- **Query**: returns info, does **not** mutate state
|
|
102
|
+
- **Command**: mutates state, does **not** return (or returns void/minimal ack)
|
|
103
|
+
|
|
104
|
+
`function getUser(id)` that **also** updates last_access violates CQS — caller doesn't expect side-effect. Split.
|
|
105
|
+
|
|
106
|
+
### 8. Boy Scout Rule
|
|
107
|
+
|
|
108
|
+
> Leave the campground cleaner than you found it.
|
|
109
|
+
|
|
110
|
+
Touched a file? Small cleanness improvement is OK in the same commit:
|
|
111
|
+
- Rename obscure variable
|
|
112
|
+
- Split giant function you already had to read
|
|
113
|
+
- Remove stale comment
|
|
114
|
+
- Delete dead code
|
|
115
|
+
|
|
116
|
+
No heavy unrelated refactor — atomic commit still rules.
|
|
117
|
+
|
|
118
|
+
### 9. Formatting
|
|
119
|
+
|
|
120
|
+
- **Auto-format**: linter/formatter on the project (prettier, dotnet format, ruff format, gofmt) — no human decisions
|
|
121
|
+
- **Member order**: consistent convention (publics before privates, or group by feature)
|
|
122
|
+
- **Blank line**: separates logical blocks. Function all glued together is hard to scan.
|
|
123
|
+
- **Consistent indentation**: respect project convention
|
|
124
|
+
|
|
125
|
+
### 10. Symmetry and consistency
|
|
126
|
+
|
|
127
|
+
- Functions at same "level" have similar signature
|
|
128
|
+
- `getUserById, getUserByEmail` — consistent param order
|
|
129
|
+
- Exceptions "as is" vs "throws" vs Result — pick **one** style in the project
|
|
130
|
+
- `null` vs `undefined` vs `Option` — pick **one**
|
|
131
|
+
- Consistent naming convention (camelCase, PascalCase, snake_case) following the language
|
|
132
|
+
|
|
133
|
+
## Classic code smells
|
|
134
|
+
|
|
135
|
+
| Smell | Symptom |
|
|
136
|
+
|---|---|
|
|
137
|
+
| **Long function** | > 50 lines |
|
|
138
|
+
| **Long parameter list** | > 4 params |
|
|
139
|
+
| **God class** | 1 class does everything |
|
|
140
|
+
| **Feature envy** | method uses more data from **another** class than its own |
|
|
141
|
+
| **Data clump** | same 3-4 params bundled in multiple places -> object |
|
|
142
|
+
| **Primitive obsession** | everything is string/int, no value objects |
|
|
143
|
+
| **Scattered switch statements** | OCP violated |
|
|
144
|
+
| **Shotgun surgery** | simple change touches N files |
|
|
145
|
+
| **Divergent change** | 1 class changes for 5 different reasons (SRP) |
|
|
146
|
+
| **Dead code** | function/parameter/var never used |
|
|
147
|
+
| **Speculative generality** | flexibility without caller (YAGNI) |
|
|
148
|
+
| **Comments compensating bad code** | refactor code, delete comment |
|
|
149
|
+
| **Magic numbers** | 86400, 1024 with no name |
|
|
150
|
+
| **Silenced exceptions** | `catch {}`, `catch (Exception _) { }` |
|
|
151
|
+
| **Long if/else chains** | use polymorphism/strategy |
|
|
152
|
+
| **Inconsistent naming** | `getUser` here, `fetchAccount` there, `loadOrder` over there |
|
|
153
|
+
| **Boolean parameter** | `fn(true)` at caller — nobody knows what `true` means |
|
|
154
|
+
|
|
155
|
+
## Procedure
|
|
156
|
+
|
|
157
|
+
### Doer
|
|
158
|
+
|
|
159
|
+
After writing:
|
|
160
|
+
1. **Name review**: does each variable/function have a name that stands without a comment? Rename if not.
|
|
161
|
+
2. **Size**: any function > 30 lines? Split.
|
|
162
|
+
3. **Magic**: any number/string without obvious meaning? Constant.
|
|
163
|
+
4. **Redundant comments**: any comment that just repeats the code? Delete.
|
|
164
|
+
5. **Error handling**: any silent `catch {}`? Log or rethrow.
|
|
165
|
+
|
|
166
|
+
### Reviewer (gate 5)
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Long functions
|
|
170
|
+
awk '/^(function|def|public |private |protected |async )/ { start=NR; name=$0 }
|
|
171
|
+
/^}$|^\s{0,2}}\s*$/ { if (NR-start > 50) print FILENAME":"start": function with "(NR-start)" lines: "name }' src/**/*.{ts,cs,py,go,java}
|
|
172
|
+
|
|
173
|
+
# Magic numbers (typical suspects)
|
|
174
|
+
grep -RnE '\b(86400|3600|1024|65535|1000000)\b' src/
|
|
175
|
+
|
|
176
|
+
# Silent catch
|
|
177
|
+
grep -RnE 'catch\s*(\([^)]*\))?\s*\{\s*\}' src/
|
|
178
|
+
grep -RnE 'except.*:\s*pass\s*$' src/
|
|
179
|
+
grep -RnE 'catch.*:.*ignore' src/
|
|
180
|
+
|
|
181
|
+
# TODO without ticket
|
|
182
|
+
grep -RnE 'TODO(?!.*#\d+)|FIXME(?!.*#\d+)' src/
|
|
183
|
+
|
|
184
|
+
# Suspect boolean params
|
|
185
|
+
grep -RnE 'function \w+\([^)]*: bool|: boolean' src/
|
|
186
|
+
|
|
187
|
+
# Generic name
|
|
188
|
+
grep -RnE '\b(data|info|value|temp|tmp|result|obj|item|thing)\b\s*[:=]' src/ | head -20
|
|
189
|
+
|
|
190
|
+
# Dead code (linter catches — confirm)
|
|
191
|
+
|
|
192
|
+
# Obvious comments
|
|
193
|
+
grep -RnE '^\s*//\s*(get|set|return|increment|decrement|loop|iterate)\b' src/
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Relevant match -> WARN or BLOCK depending on severity.
|
|
197
|
+
|
|
198
|
+
## Inputs
|
|
199
|
+
|
|
200
|
+
- Diff/content of the file
|
|
201
|
+
- Project convention (linter config, naming convention from PROJECT.md)
|
|
202
|
+
|
|
203
|
+
## Outputs
|
|
204
|
+
|
|
205
|
+
Does NOT produce a file. Modifies judgement.
|
|
206
|
+
|
|
207
|
+
## Examples
|
|
208
|
+
|
|
209
|
+
### Example 1: bad names
|
|
210
|
+
|
|
211
|
+
Wrong:
|
|
212
|
+
```python
|
|
213
|
+
def calc(d, t):
|
|
214
|
+
r = d * t * 0.18
|
|
215
|
+
return r
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Right:
|
|
219
|
+
```python
|
|
220
|
+
VAT_RATE = 0.18
|
|
221
|
+
|
|
222
|
+
def calculate_vat(amount: Decimal, qty: int) -> Decimal:
|
|
223
|
+
return amount * qty * VAT_RATE
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Example 2: giant function
|
|
227
|
+
|
|
228
|
+
Wrong: 1 function of 120 lines validating, saving, sending email, logging.
|
|
229
|
+
|
|
230
|
+
Right: 4 functions of 20 lines each + 1 orchestrator of 15 lines that coordinates.
|
|
231
|
+
|
|
232
|
+
### Example 3: silenced exception
|
|
233
|
+
|
|
234
|
+
Wrong:
|
|
235
|
+
```typescript
|
|
236
|
+
try {
|
|
237
|
+
await sendNotification(user)
|
|
238
|
+
} catch {}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Latent bug — notification failure disappears.
|
|
242
|
+
|
|
243
|
+
Right:
|
|
244
|
+
```typescript
|
|
245
|
+
try {
|
|
246
|
+
await sendNotification(user)
|
|
247
|
+
} catch (err) {
|
|
248
|
+
logger.error("notification failed", { userId: user.id, err })
|
|
249
|
+
// intentional: notification is best-effort, doesn't block flow
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Comment here justifies the "why" of the no-rethrow.
|
|
254
|
+
|
|
255
|
+
### Example 4: boolean param
|
|
256
|
+
|
|
257
|
+
Wrong: `createUser("alice", "alice@x.com", true, false)`
|
|
258
|
+
|
|
259
|
+
Right: `createUser({ name: "alice", email: "alice@x.com", admin: true, sendWelcome: false })`
|
|
260
|
+
|
|
261
|
+
Caller becomes self-documented.
|