jdi-cli 0.1.1 → 0.1.3
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/README.md +6 -0
- package/core/agents/jdi-architect.md +19 -0
- package/core/agents/jdi-researcher.md +2 -1
- package/core/commands/jdi-add-phase.md +171 -0
- package/core/commands/jdi-remove-phase.md +228 -0
- package/core/skills/clean-architecture/SKILL.md +134 -0
- package/core/skills/ddd/SKILL.md +140 -0
- package/core/skills/hexagonal/SKILL.md +127 -0
- package/core/skills/onion/SKILL.md +133 -0
- package/core/skills/the-method/SKILL.md +139 -0
- package/core/skills/vertical-slice/SKILL.md +127 -0
- package/package.json +1 -1
- package/runtimes/antigravity/agents.md +4 -0
- package/runtimes/antigravity/skills/clean-architecture/SKILL.md +125 -0
- package/runtimes/antigravity/skills/ddd/SKILL.md +131 -0
- package/runtimes/antigravity/skills/hexagonal/SKILL.md +118 -0
- package/runtimes/antigravity/skills/jdi-add-phase/SKILL.md +171 -0
- package/runtimes/antigravity/skills/jdi-architect/SKILL.md +19 -0
- package/runtimes/antigravity/skills/jdi-remove-phase/SKILL.md +228 -0
- package/runtimes/antigravity/skills/jdi-researcher/SKILL.md +2 -1
- package/runtimes/antigravity/skills/onion/SKILL.md +124 -0
- package/runtimes/antigravity/skills/the-method/SKILL.md +130 -0
- package/runtimes/antigravity/skills/vertical-slice/SKILL.md +118 -0
- package/runtimes/claude/CLAUDE.md +4 -0
- package/runtimes/claude/agents/jdi-architect.md +19 -0
- package/runtimes/claude/agents/jdi-researcher.md +2 -1
- package/runtimes/claude/commands/jdi-add-phase.md +171 -0
- package/runtimes/claude/commands/jdi-remove-phase.md +228 -0
- package/runtimes/claude/skills/clean-architecture/SKILL.md +120 -0
- package/runtimes/claude/skills/ddd/SKILL.md +125 -0
- package/runtimes/claude/skills/hexagonal/SKILL.md +112 -0
- package/runtimes/claude/skills/onion/SKILL.md +119 -0
- package/runtimes/claude/skills/the-method/SKILL.md +124 -0
- package/runtimes/claude/skills/vertical-slice/SKILL.md +113 -0
- package/runtimes/copilot/agents/jdi-architect.agent.md +19 -0
- package/runtimes/copilot/agents/jdi-researcher.agent.md +2 -1
- package/runtimes/copilot/copilot-instructions.md +4 -0
- package/runtimes/copilot/prompts/jdi-add-phase.prompt.md +171 -0
- package/runtimes/copilot/prompts/jdi-remove-phase.prompt.md +228 -0
- package/runtimes/opencode/AGENTS.md +4 -0
- package/runtimes/opencode/agents/jdi-architect.md +19 -0
- package/runtimes/opencode/agents/jdi-researcher.md +2 -1
- package/runtimes/opencode/commands/jdi-add-phase.md +171 -0
- package/runtimes/opencode/commands/jdi-remove-phase.md +228 -0
- package/runtimes/opencode/skills/clean-architecture/SKILL.md +120 -0
- package/runtimes/opencode/skills/ddd/SKILL.md +125 -0
- package/runtimes/opencode/skills/hexagonal/SKILL.md +112 -0
- package/runtimes/opencode/skills/onion/SKILL.md +119 -0
- package/runtimes/opencode/skills/the-method/SKILL.md +124 -0
- package/runtimes/opencode/skills/vertical-slice/SKILL.md +113 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jdi-remove-phase
|
|
3
|
+
description: Removes a phase from ROADMAP.md. Refuses to remove done phases or the current phase. Archives any existing phase artifacts. Atomic commit.
|
|
4
|
+
argument_hint: "<phase_number> [--force]"
|
|
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-remove-phase"
|
|
17
|
+
- "remove phase"
|
|
18
|
+
- "delete phase"
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<objective>
|
|
22
|
+
Removes a phase from `.jdi/ROADMAP.md`. Refuses to remove the current phase or any phase already shipped. If the phase has artifacts under `.jdi/phases/<NN-slug>/`, moves them to `.jdi/archive/removed-<NN-slug>/` instead of deleting (preserves history).
|
|
23
|
+
</objective>
|
|
24
|
+
|
|
25
|
+
<arguments>
|
|
26
|
+
- `phase_number` (required) — number of the phase to remove (as listed in ROADMAP.md).
|
|
27
|
+
- `--force` (optional) — required when removing a phase that has any artifacts in `.jdi/phases/`. Without `--force`, the command refuses and explains.
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
- `/jdi-remove-phase 4`
|
|
31
|
+
- `/jdi-remove-phase 5 --force`
|
|
32
|
+
</arguments>
|
|
33
|
+
|
|
34
|
+
<process>
|
|
35
|
+
|
|
36
|
+
### Step 1: Validation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
test -d .jdi/ || { echo "Not a JDI project."; exit 1; }
|
|
40
|
+
test -f .jdi/ROADMAP.md || { echo "ROADMAP.md missing."; exit 1; }
|
|
41
|
+
test -f .jdi/STATE.md || { echo "STATE.md missing."; exit 1; }
|
|
42
|
+
|
|
43
|
+
# Argument required
|
|
44
|
+
[ -n "$1" ] || { echo "Phase number required. Usage: /jdi-remove-phase <N> [--force]"; exit 1; }
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Parse `phase_number` (positional). Parse `--force` flag.
|
|
48
|
+
|
|
49
|
+
### Step 2: Read state
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
CURRENT=$(grep -oE 'current_phase:\s*[0-9]+' .jdi/STATE.md | grep -oE '[0-9]+')
|
|
53
|
+
TOTAL=$(grep -oE 'total_phases:\s*[0-9]+' .jdi/ROADMAP.md | grep -oE '[0-9]+')
|
|
54
|
+
PHASE_NUMBER=$1
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
PowerShell:
|
|
58
|
+
```powershell
|
|
59
|
+
$current = (Select-String -Path .jdi/STATE.md -Pattern 'current_phase:\s*([0-9]+)').Matches[0].Groups[1].Value -as [int]
|
|
60
|
+
$total = (Select-String -Path .jdi/ROADMAP.md -Pattern 'total_phases:\s*([0-9]+)').Matches[0].Groups[1].Value -as [int]
|
|
61
|
+
$phaseNumber = [int]$args[0]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Step 3: Hard refuses (no override)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Must be in range
|
|
68
|
+
if [ "$PHASE_NUMBER" -lt 1 ] || [ "$PHASE_NUMBER" -gt "$TOTAL" ]; then
|
|
69
|
+
echo "Phase $PHASE_NUMBER does not exist. Valid: 1..$TOTAL"
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Cannot remove past phases (preserves history)
|
|
74
|
+
if [ "$PHASE_NUMBER" -lt "$CURRENT" ]; then
|
|
75
|
+
echo "Cannot remove phase $PHASE_NUMBER — already past. current_phase is $CURRENT. Past phases are immutable history."
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Cannot remove the current phase
|
|
80
|
+
if [ "$PHASE_NUMBER" -eq "$CURRENT" ]; then
|
|
81
|
+
echo "Cannot remove the current phase ($CURRENT). Ship or abandon it first, then advance current_phase."
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Read the phase's `Status:` from ROADMAP:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
STATUS=$(awk "/### Phase $PHASE_NUMBER:/,/^### Phase /" .jdi/ROADMAP.md | grep -oE 'Status:\*\* (pending|ready|done|partial|blocked|in-progress)' | head -1 | awk '{print $2}')
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
If `STATUS == done`: refuse hard.
|
|
93
|
+
```
|
|
94
|
+
Phase $PHASE_NUMBER is `done`. Cannot remove. Shipped phases are immutable history.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Step 4: Detect artifacts
|
|
98
|
+
|
|
99
|
+
Find the phase folder under `.jdi/phases/`:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
NN=$(printf '%02d' "$PHASE_NUMBER")
|
|
103
|
+
PHASE_DIR=$(ls -d .jdi/phases/${NN}-*/ 2>/dev/null | head -1 || true)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
PowerShell:
|
|
107
|
+
```powershell
|
|
108
|
+
$nn = '{0:D2}' -f $phaseNumber
|
|
109
|
+
$phaseDir = Get-ChildItem .jdi/phases/ -Directory -Filter "$nn-*" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If `PHASE_DIR` exists AND `--force` NOT passed: refuse.
|
|
113
|
+
```
|
|
114
|
+
Phase $PHASE_NUMBER has artifacts in $PHASE_DIR (CONTEXT/PLAN/SUMMARY/REVIEW).
|
|
115
|
+
Re-run with --force to archive these artifacts to .jdi/archive/removed-<NN-slug>/ and proceed.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Step 5: Confirm with user (irreversible-ish action)
|
|
119
|
+
|
|
120
|
+
AskUserQuestion (always run, even with --force):
|
|
121
|
+
|
|
122
|
+
> "Remove phase $PHASE_NUMBER: '$PHASE_NAME'?
|
|
123
|
+
>
|
|
124
|
+
> Status: $STATUS
|
|
125
|
+
> Artifacts: ${PHASE_DIR:-none}
|
|
126
|
+
> Action: ROADMAP section removed, total_phases decremented, artifacts (if any) moved to .jdi/archive/removed-<NN-slug>/."
|
|
127
|
+
>
|
|
128
|
+
> Options:
|
|
129
|
+
> - [Yes, remove]
|
|
130
|
+
> - [Cancel]
|
|
131
|
+
|
|
132
|
+
If "Cancel" -> exit clean.
|
|
133
|
+
|
|
134
|
+
### Step 6: Archive artifacts (if any)
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
if [ -n "$PHASE_DIR" ]; then
|
|
138
|
+
mkdir -p .jdi/archive
|
|
139
|
+
test -f .jdi/archive/index.md || echo "# Archive index" > .jdi/archive/index.md
|
|
140
|
+
|
|
141
|
+
BASENAME=$(basename "$PHASE_DIR")
|
|
142
|
+
TARGET=".jdi/archive/removed-$BASENAME"
|
|
143
|
+
mv "$PHASE_DIR" "$TARGET"
|
|
144
|
+
echo "- removed-$BASENAME (removed $(date -u +%F) via /jdi-remove-phase)" >> .jdi/archive/index.md
|
|
145
|
+
fi
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
PowerShell:
|
|
149
|
+
```powershell
|
|
150
|
+
if ($phaseDir) {
|
|
151
|
+
if (-not (Test-Path .jdi/archive)) { New-Item -ItemType Directory .jdi/archive | Out-Null }
|
|
152
|
+
if (-not (Test-Path .jdi/archive/index.md)) { Set-Content .jdi/archive/index.md "# Archive index" }
|
|
153
|
+
$basename = $phaseDir.Name
|
|
154
|
+
$target = ".jdi/archive/removed-$basename"
|
|
155
|
+
Move-Item $phaseDir.FullName $target
|
|
156
|
+
Add-Content .jdi/archive/index.md "- removed-$basename (removed $(Get-Date -Format 'yyyy-MM-dd') via /jdi-remove-phase)"
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Step 7: Edit ROADMAP.md
|
|
161
|
+
|
|
162
|
+
Remove the entire `### Phase $PHASE_NUMBER: ...` block (header + bullets) up to (but not including) the next `### Phase ` line or end of file.
|
|
163
|
+
|
|
164
|
+
Decrement `total_phases`:
|
|
165
|
+
```
|
|
166
|
+
total_phases: {TOTAL - 1}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Do NOT renumber** subsequent phases. Phases after the removed one keep their original numbers. This preserves all references in commit history, `DECISIONS.md`, and archived phase folders. The roadmap simply has a gap (e.g., 1, 2, 3, 5, 6 — 4 was removed).
|
|
170
|
+
|
|
171
|
+
### Step 8: Audit trail in DECISIONS.md
|
|
172
|
+
|
|
173
|
+
Append:
|
|
174
|
+
```markdown
|
|
175
|
+
D-{N+1} ({date}): Phase $PHASE_NUMBER removed via /jdi-remove-phase. Artifacts: ${PHASE_DIR:+archived to .jdi/archive/removed-<NN-slug>/}{none if empty}.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Step 9: Commit
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
git add .jdi/ROADMAP.md .jdi/DECISIONS.md .jdi/archive/ 2>/dev/null
|
|
182
|
+
git commit -m "chore(jdi): remove phase {PHASE_NUMBER}"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Step 10: Confirm
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
Phase {PHASE_NUMBER} removed.
|
|
189
|
+
{if artifacts:} Artifacts archived: .jdi/archive/removed-{NN-slug}/
|
|
190
|
+
total_phases: {TOTAL - 1}
|
|
191
|
+
|
|
192
|
+
Note: phase numbers are not renumbered — references in commits, DECISIONS, and archive remain valid.
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
</process>
|
|
196
|
+
|
|
197
|
+
<gates>
|
|
198
|
+
- pre: `.jdi/ROADMAP.md` + `.jdi/STATE.md` exist
|
|
199
|
+
- pre: `phase_number` is in range `1..total_phases`
|
|
200
|
+
- pre: `phase_number > current_phase`
|
|
201
|
+
- pre: phase status != `done`
|
|
202
|
+
- pre: `--force` provided when phase has artifacts
|
|
203
|
+
- post: ROADMAP.md section removed + total_phases decremented + artifacts archived (if any) + DECISIONS.md appended + atomic commit
|
|
204
|
+
</gates>
|
|
205
|
+
|
|
206
|
+
<errors>
|
|
207
|
+
- `.jdi/` missing -> "Run /jdi-new first"
|
|
208
|
+
- `phase_number` missing -> usage hint
|
|
209
|
+
- `phase_number` out of range -> "Valid: 1..{total}"
|
|
210
|
+
- `phase_number < current_phase` -> refuse (past = history)
|
|
211
|
+
- `phase_number == current_phase` -> refuse (ship or abandon first)
|
|
212
|
+
- phase status `done` -> refuse (shipped = history)
|
|
213
|
+
- artifacts exist + no `--force` -> refuse + suggest `--force`
|
|
214
|
+
- user cancels at AskUserQuestion -> exit clean
|
|
215
|
+
</errors>
|
|
216
|
+
|
|
217
|
+
<runtime_notes>
|
|
218
|
+
|
|
219
|
+
**Claude Code:**
|
|
220
|
+
- Confirms via AskUserQuestion.
|
|
221
|
+
|
|
222
|
+
**Copilot:**
|
|
223
|
+
- AskUserQuestion not always available — require explicit `--yes` flag as fallback.
|
|
224
|
+
|
|
225
|
+
**OpenCode/Antigravity:**
|
|
226
|
+
- Same interactive confirm as Claude. Fallback to `--yes` when prompts unsupported.
|
|
227
|
+
|
|
228
|
+
</runtime_notes>
|
|
@@ -12,6 +12,10 @@ Este projeto usa **JDI (Just Do It)** como workflow de desenvolvimento. JDI eh u
|
|
|
12
12
|
/jdi-do <N> -> executa via doer specialist
|
|
13
13
|
/jdi-verify <N> -> gates via reviewer specialist
|
|
14
14
|
/jdi-ship <N> -> finaliza phase
|
|
15
|
+
|
|
16
|
+
# Roadmap mutation (qualquer hora)
|
|
17
|
+
/jdi-add-phase "<name>" [--goal "<t>"] [--at <pos>] -> adiciona phase
|
|
18
|
+
/jdi-remove-phase <N> [--force] -> remove future/pending phase
|
|
15
19
|
```
|
|
16
20
|
|
|
17
21
|
`/jdi-create [desc]` cria agents/skills genericos no `core/` (so dentro do repo JDI).
|
|
@@ -378,13 +378,29 @@ Write to `.jdi/agents/jdi-reviewer-{slug}.md`.
|
|
|
378
378
|
|
|
379
379
|
After writing doer/reviewer, inject `<skills_to_load>` block after `</role>` via Edit.
|
|
380
380
|
|
|
381
|
+
**Code-design skill (mandatory) — resolve from `PROJECT.md.Code Design` (LOCKED value) using this mapping:**
|
|
382
|
+
|
|
383
|
+
| Code Design (PROJECT.md) | Skill to load |
|
|
384
|
+
|---|---|
|
|
385
|
+
| The Method | `the-method` |
|
|
386
|
+
| DDD | `ddd` |
|
|
387
|
+
| Clean Architecture | `clean-architecture` |
|
|
388
|
+
| Hexagonal | `hexagonal` |
|
|
389
|
+
| Onion | `onion` |
|
|
390
|
+
| Vertical Slice | `vertical-slice` |
|
|
391
|
+
|
|
392
|
+
The resolved code-design skill is loaded by **both doer and reviewer**. Exactly one code-design skill is loaded. Never load two code-design skills simultaneously — the project uses exactly one design. If the mapping cannot resolve, abort with an error and ask the user to fix `PROJECT.md.Code Design`.
|
|
393
|
+
|
|
381
394
|
**Doer — always:**
|
|
382
395
|
```markdown
|
|
383
396
|
<skills_to_load>
|
|
384
397
|
- solid — before creating classes/modules/interfaces. Detects god class, large switches, deep inheritance, dep on concretes.
|
|
398
|
+
- {CODE_DESIGN_SKILL} — INVIOLABLE structural rules for the project's locked code design. Apply on every file created.
|
|
385
399
|
</skills_to_load>
|
|
386
400
|
```
|
|
387
401
|
|
|
402
|
+
Replace `{CODE_DESIGN_SKILL}` with the resolved entry from the mapping above (e.g. `the-method`, `ddd`, `clean-architecture`, `hexagonal`, `onion`, `vertical-slice`).
|
|
403
|
+
|
|
388
404
|
If `has_frontend=true`, append:
|
|
389
405
|
```markdown
|
|
390
406
|
- frontend-rules — when task touches .tsx/.vue/.svelte/.razor/.cshtml/.html/.twig/.erb/.blade.php. WCAG 2.2 AA + UX.
|
|
@@ -397,9 +413,12 @@ If `has_frontend=true`, append:
|
|
|
397
413
|
- kiss — gate 5: over-engineering — interface with 1 impl, factory for new(), pass-through, deep inheritance.
|
|
398
414
|
- yagni — gate 5: speculative code — optional params never passed, TODO without ticket, generic with 1 type.
|
|
399
415
|
- clean-code — bad names, long functions, magic numbers, silent catch, boolean params, redundant comments.
|
|
416
|
+
- {CODE_DESIGN_SKILL} — gate 5: enforce INVIOLABLE structural rules for the project's locked code design. BLOCKED on violations defined by the skill.
|
|
400
417
|
</skills_to_load>
|
|
401
418
|
```
|
|
402
419
|
|
|
420
|
+
Replace `{CODE_DESIGN_SKILL}` with the same resolved entry — both doer and reviewer load the SAME code-design skill.
|
|
421
|
+
|
|
403
422
|
If `has_frontend=true`, append:
|
|
404
423
|
```markdown
|
|
405
424
|
- frontend-rules — gate 5 frontend: <input> without label, button without aria-label, localStorage with token, outline removed.
|
|
@@ -60,10 +60,11 @@ Options:
|
|
|
60
60
|
- Vertical Slice
|
|
61
61
|
- Clean Architecture
|
|
62
62
|
- Hexagonal (Ports & Adapters)
|
|
63
|
+
- Onion Architecture
|
|
63
64
|
- The Method (Juval Löwy)
|
|
64
65
|
- "Don't know, suggest" (-> recommend based on type + stack)
|
|
65
66
|
|
|
66
|
-
Locked for the life of the project (global rule).
|
|
67
|
+
Locked for the life of the project (global rule). Mutually exclusive — the project uses exactly ONE code design. The choice is enforced by a JDI skill loaded into doer + reviewer (one of: `ddd`, `vertical-slice`, `clean-architecture`, `hexagonal`, `onion`, `the-method`).
|
|
67
68
|
|
|
68
69
|
**Q4 — MVP scope**
|
|
69
70
|
"Which minimum features for the MVP? (comma-separated)"
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jdi-add-phase
|
|
3
|
+
description: Adds a new phase to ROADMAP.md. Append at end (default) or insert at a specific position. Bumps total_phases. Atomic commit.
|
|
4
|
+
argument_hint: "\"<phase name>\" [--goal \"<goal>\"] [--at <position>]"
|
|
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-add-phase"
|
|
17
|
+
- "add new phase"
|
|
18
|
+
- "create phase"
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<objective>
|
|
22
|
+
Adds a new phase to the project's roadmap. Edits `.jdi/ROADMAP.md`. Does not start the phase — only registers it. The user advances via `/jdi-discuss <N>` when ready.
|
|
23
|
+
</objective>
|
|
24
|
+
|
|
25
|
+
<arguments>
|
|
26
|
+
- `name` (required) — short phase name. Quote if it contains spaces.
|
|
27
|
+
- `--goal "<text>"` (optional) — 1-line description of what the phase delivers. If missing, AskUserQuestion will prompt.
|
|
28
|
+
- `--at <position>` (optional) — insert at this position instead of appending. Existing phases at and after `<position>` shift down by 1 (renumbered in ROADMAP only — slugs stay the same in any existing `.jdi/phases/` folders). Default: append.
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
- `/jdi-add-phase "User authentication" --goal "Login + signup + JWT"`
|
|
32
|
+
- `/jdi-add-phase "Performance pass" --at 3`
|
|
33
|
+
- `/jdi-add-phase "Hotfix N+1 query"`
|
|
34
|
+
</arguments>
|
|
35
|
+
|
|
36
|
+
<process>
|
|
37
|
+
|
|
38
|
+
### Step 1: Validation
|
|
39
|
+
```bash
|
|
40
|
+
test -d .jdi/ || { echo "Not a JDI project. /jdi-new first."; exit 1; }
|
|
41
|
+
test -f .jdi/ROADMAP.md || { echo "ROADMAP.md missing."; exit 1; }
|
|
42
|
+
test -f .jdi/STATE.md || { echo "STATE.md missing."; exit 1; }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If `<name>` argument missing: AskUserQuestion "Phase name?" (free text). Required.
|
|
46
|
+
|
|
47
|
+
If `--goal` flag missing: AskUserQuestion "Phase goal (1 line)?" (free text). Required.
|
|
48
|
+
|
|
49
|
+
### Step 2: Compute phase number + slug
|
|
50
|
+
|
|
51
|
+
Read `total_phases` from `.jdi/ROADMAP.md`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
TOTAL=$(grep -oE 'total_phases:\s*[0-9]+' .jdi/ROADMAP.md | grep -oE '[0-9]+')
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
PowerShell:
|
|
58
|
+
```powershell
|
|
59
|
+
$total = (Select-String -Path .jdi/ROADMAP.md -Pattern 'total_phases:\s*([0-9]+)').Matches[0].Groups[1].Value -as [int]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If `--at <pos>` provided, validate `1 <= pos <= total + 1`. Otherwise `pos = total + 1` (append).
|
|
63
|
+
|
|
64
|
+
If `pos <= current_phase` (read from STATE.md), abort with error: "Cannot insert before current phase {current}. Use --at {current+1} or higher."
|
|
65
|
+
|
|
66
|
+
Generate `slug` from `name`:
|
|
67
|
+
- Lowercase
|
|
68
|
+
- Replace accents (à → a, é → e, ç → c, ñ → n)
|
|
69
|
+
- Non-alphanumeric → `-`
|
|
70
|
+
- Collapse repeated `-`, strip leading/trailing `-`
|
|
71
|
+
- Truncate to 40 chars
|
|
72
|
+
|
|
73
|
+
Phase identifier prefix is the 2-digit position (`NN`): `01`, `02`, ..., zero-padded.
|
|
74
|
+
|
|
75
|
+
### Step 3: Renumber prefix on shift (only if --at)
|
|
76
|
+
|
|
77
|
+
If `--at <pos>` shifts existing phases:
|
|
78
|
+
|
|
79
|
+
Edit `.jdi/ROADMAP.md` — for every existing `### Phase K:` where `K >= pos`, change to `### Phase K+1:` and bump its `**Slug:**` prefix from `KK-...` to `(K+1)(K+1)-...`.
|
|
80
|
+
|
|
81
|
+
**WARNING (printed):**
|
|
82
|
+
> "Renumbering ROADMAP phases. Any existing `.jdi/phases/<NN-slug>/` folders are NOT renamed — they keep their original slugs and become "history". New work in renumbered phases creates new folders. Commits referencing old `phase {K}` remain valid as history."
|
|
83
|
+
|
|
84
|
+
This is intentional. Do not rename `.jdi/phases/` folders — would break commit history and cross-references in DECISIONS.md.
|
|
85
|
+
|
|
86
|
+
If `--at` not provided (append), skip Step 3.
|
|
87
|
+
|
|
88
|
+
### Step 4: Append phase section to ROADMAP.md
|
|
89
|
+
|
|
90
|
+
If appending (`pos == total + 1`), append at the bottom of `## Phases`:
|
|
91
|
+
|
|
92
|
+
```markdown
|
|
93
|
+
|
|
94
|
+
### Phase {pos}: {name}
|
|
95
|
+
- **Slug:** {NN}-{slug}
|
|
96
|
+
- **Status:** pending
|
|
97
|
+
- **Goal:** {goal}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If inserting (`pos <= total`), insert the new section BEFORE the section that previously had number `pos` (now renumbered to `pos+1`).
|
|
101
|
+
|
|
102
|
+
### Step 5: Bump total_phases
|
|
103
|
+
|
|
104
|
+
Edit `.jdi/ROADMAP.md`:
|
|
105
|
+
```
|
|
106
|
+
total_phases: {TOTAL + 1}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Step 6: Audit trail in DECISIONS.md (optional, only if user passes --reason)
|
|
110
|
+
|
|
111
|
+
Not required. If user wants to record why this phase was added mid-project, they pass `--reason "<text>"`. When present, append to `.jdi/DECISIONS.md`:
|
|
112
|
+
|
|
113
|
+
```markdown
|
|
114
|
+
D-{N+1} ({date}, phase {pos}): Phase added mid-project. Reason: {reason}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
(N = current max D-X.)
|
|
118
|
+
|
|
119
|
+
### Step 7: Commit
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
git add .jdi/ROADMAP.md .jdi/DECISIONS.md 2>/dev/null
|
|
123
|
+
git commit -m "chore(jdi): add phase {pos} {NN-slug}"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
PowerShell:
|
|
127
|
+
```powershell
|
|
128
|
+
git add .jdi/ROADMAP.md .jdi/DECISIONS.md 2>$null
|
|
129
|
+
git commit -m "chore(jdi): add phase $pos $NN-$slug"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Step 8: Confirm
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
Phase {pos}: {name} added.
|
|
136
|
+
Slug: {NN}-{slug}
|
|
137
|
+
Goal: {goal}
|
|
138
|
+
Status: pending
|
|
139
|
+
total_phases: {TOTAL + 1}
|
|
140
|
+
|
|
141
|
+
Next: /jdi-discuss {pos} (when ready to start this phase)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
</process>
|
|
145
|
+
|
|
146
|
+
<gates>
|
|
147
|
+
- pre: `.jdi/ROADMAP.md` + `.jdi/STATE.md` exist
|
|
148
|
+
- pre: `--at <pos>` (if used) is greater than `current_phase` in STATE.md
|
|
149
|
+
- post: ROADMAP.md has new phase section + bumped total_phases + atomic commit
|
|
150
|
+
</gates>
|
|
151
|
+
|
|
152
|
+
<errors>
|
|
153
|
+
- `.jdi/` missing -> "Run /jdi-new first"
|
|
154
|
+
- `--at <pos>` <= current_phase -> "Cannot insert before current phase. Use --at {current+1} or higher."
|
|
155
|
+
- `--at <pos>` < 1 or > total+1 -> "Position out of range. Valid: 1..{total+1}"
|
|
156
|
+
- Phase name empty -> AskUserQuestion to fill
|
|
157
|
+
- Goal empty -> AskUserQuestion to fill
|
|
158
|
+
</errors>
|
|
159
|
+
|
|
160
|
+
<runtime_notes>
|
|
161
|
+
|
|
162
|
+
**Claude Code:**
|
|
163
|
+
- AskUserQuestion handles missing args interactively.
|
|
164
|
+
|
|
165
|
+
**Copilot:**
|
|
166
|
+
- AskUserQuestion not always available — read missing args from prompt body or fail with clear error.
|
|
167
|
+
|
|
168
|
+
**OpenCode/Antigravity:**
|
|
169
|
+
- Same interactive flow as Claude when supported. Otherwise fail with clear error message asking the user to re-invoke with all args.
|
|
170
|
+
|
|
171
|
+
</runtime_notes>
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jdi-remove-phase
|
|
3
|
+
description: Removes a phase from ROADMAP.md. Refuses to remove done phases or the current phase. Archives any existing phase artifacts. Atomic commit.
|
|
4
|
+
argument_hint: "<phase_number> [--force]"
|
|
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-remove-phase"
|
|
17
|
+
- "remove phase"
|
|
18
|
+
- "delete phase"
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<objective>
|
|
22
|
+
Removes a phase from `.jdi/ROADMAP.md`. Refuses to remove the current phase or any phase already shipped. If the phase has artifacts under `.jdi/phases/<NN-slug>/`, moves them to `.jdi/archive/removed-<NN-slug>/` instead of deleting (preserves history).
|
|
23
|
+
</objective>
|
|
24
|
+
|
|
25
|
+
<arguments>
|
|
26
|
+
- `phase_number` (required) — number of the phase to remove (as listed in ROADMAP.md).
|
|
27
|
+
- `--force` (optional) — required when removing a phase that has any artifacts in `.jdi/phases/`. Without `--force`, the command refuses and explains.
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
- `/jdi-remove-phase 4`
|
|
31
|
+
- `/jdi-remove-phase 5 --force`
|
|
32
|
+
</arguments>
|
|
33
|
+
|
|
34
|
+
<process>
|
|
35
|
+
|
|
36
|
+
### Step 1: Validation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
test -d .jdi/ || { echo "Not a JDI project."; exit 1; }
|
|
40
|
+
test -f .jdi/ROADMAP.md || { echo "ROADMAP.md missing."; exit 1; }
|
|
41
|
+
test -f .jdi/STATE.md || { echo "STATE.md missing."; exit 1; }
|
|
42
|
+
|
|
43
|
+
# Argument required
|
|
44
|
+
[ -n "$1" ] || { echo "Phase number required. Usage: /jdi-remove-phase <N> [--force]"; exit 1; }
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Parse `phase_number` (positional). Parse `--force` flag.
|
|
48
|
+
|
|
49
|
+
### Step 2: Read state
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
CURRENT=$(grep -oE 'current_phase:\s*[0-9]+' .jdi/STATE.md | grep -oE '[0-9]+')
|
|
53
|
+
TOTAL=$(grep -oE 'total_phases:\s*[0-9]+' .jdi/ROADMAP.md | grep -oE '[0-9]+')
|
|
54
|
+
PHASE_NUMBER=$1
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
PowerShell:
|
|
58
|
+
```powershell
|
|
59
|
+
$current = (Select-String -Path .jdi/STATE.md -Pattern 'current_phase:\s*([0-9]+)').Matches[0].Groups[1].Value -as [int]
|
|
60
|
+
$total = (Select-String -Path .jdi/ROADMAP.md -Pattern 'total_phases:\s*([0-9]+)').Matches[0].Groups[1].Value -as [int]
|
|
61
|
+
$phaseNumber = [int]$args[0]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Step 3: Hard refuses (no override)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Must be in range
|
|
68
|
+
if [ "$PHASE_NUMBER" -lt 1 ] || [ "$PHASE_NUMBER" -gt "$TOTAL" ]; then
|
|
69
|
+
echo "Phase $PHASE_NUMBER does not exist. Valid: 1..$TOTAL"
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Cannot remove past phases (preserves history)
|
|
74
|
+
if [ "$PHASE_NUMBER" -lt "$CURRENT" ]; then
|
|
75
|
+
echo "Cannot remove phase $PHASE_NUMBER — already past. current_phase is $CURRENT. Past phases are immutable history."
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Cannot remove the current phase
|
|
80
|
+
if [ "$PHASE_NUMBER" -eq "$CURRENT" ]; then
|
|
81
|
+
echo "Cannot remove the current phase ($CURRENT). Ship or abandon it first, then advance current_phase."
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Read the phase's `Status:` from ROADMAP:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
STATUS=$(awk "/### Phase $PHASE_NUMBER:/,/^### Phase /" .jdi/ROADMAP.md | grep -oE 'Status:\*\* (pending|ready|done|partial|blocked|in-progress)' | head -1 | awk '{print $2}')
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
If `STATUS == done`: refuse hard.
|
|
93
|
+
```
|
|
94
|
+
Phase $PHASE_NUMBER is `done`. Cannot remove. Shipped phases are immutable history.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Step 4: Detect artifacts
|
|
98
|
+
|
|
99
|
+
Find the phase folder under `.jdi/phases/`:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
NN=$(printf '%02d' "$PHASE_NUMBER")
|
|
103
|
+
PHASE_DIR=$(ls -d .jdi/phases/${NN}-*/ 2>/dev/null | head -1 || true)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
PowerShell:
|
|
107
|
+
```powershell
|
|
108
|
+
$nn = '{0:D2}' -f $phaseNumber
|
|
109
|
+
$phaseDir = Get-ChildItem .jdi/phases/ -Directory -Filter "$nn-*" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If `PHASE_DIR` exists AND `--force` NOT passed: refuse.
|
|
113
|
+
```
|
|
114
|
+
Phase $PHASE_NUMBER has artifacts in $PHASE_DIR (CONTEXT/PLAN/SUMMARY/REVIEW).
|
|
115
|
+
Re-run with --force to archive these artifacts to .jdi/archive/removed-<NN-slug>/ and proceed.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Step 5: Confirm with user (irreversible-ish action)
|
|
119
|
+
|
|
120
|
+
AskUserQuestion (always run, even with --force):
|
|
121
|
+
|
|
122
|
+
> "Remove phase $PHASE_NUMBER: '$PHASE_NAME'?
|
|
123
|
+
>
|
|
124
|
+
> Status: $STATUS
|
|
125
|
+
> Artifacts: ${PHASE_DIR:-none}
|
|
126
|
+
> Action: ROADMAP section removed, total_phases decremented, artifacts (if any) moved to .jdi/archive/removed-<NN-slug>/."
|
|
127
|
+
>
|
|
128
|
+
> Options:
|
|
129
|
+
> - [Yes, remove]
|
|
130
|
+
> - [Cancel]
|
|
131
|
+
|
|
132
|
+
If "Cancel" -> exit clean.
|
|
133
|
+
|
|
134
|
+
### Step 6: Archive artifacts (if any)
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
if [ -n "$PHASE_DIR" ]; then
|
|
138
|
+
mkdir -p .jdi/archive
|
|
139
|
+
test -f .jdi/archive/index.md || echo "# Archive index" > .jdi/archive/index.md
|
|
140
|
+
|
|
141
|
+
BASENAME=$(basename "$PHASE_DIR")
|
|
142
|
+
TARGET=".jdi/archive/removed-$BASENAME"
|
|
143
|
+
mv "$PHASE_DIR" "$TARGET"
|
|
144
|
+
echo "- removed-$BASENAME (removed $(date -u +%F) via /jdi-remove-phase)" >> .jdi/archive/index.md
|
|
145
|
+
fi
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
PowerShell:
|
|
149
|
+
```powershell
|
|
150
|
+
if ($phaseDir) {
|
|
151
|
+
if (-not (Test-Path .jdi/archive)) { New-Item -ItemType Directory .jdi/archive | Out-Null }
|
|
152
|
+
if (-not (Test-Path .jdi/archive/index.md)) { Set-Content .jdi/archive/index.md "# Archive index" }
|
|
153
|
+
$basename = $phaseDir.Name
|
|
154
|
+
$target = ".jdi/archive/removed-$basename"
|
|
155
|
+
Move-Item $phaseDir.FullName $target
|
|
156
|
+
Add-Content .jdi/archive/index.md "- removed-$basename (removed $(Get-Date -Format 'yyyy-MM-dd') via /jdi-remove-phase)"
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Step 7: Edit ROADMAP.md
|
|
161
|
+
|
|
162
|
+
Remove the entire `### Phase $PHASE_NUMBER: ...` block (header + bullets) up to (but not including) the next `### Phase ` line or end of file.
|
|
163
|
+
|
|
164
|
+
Decrement `total_phases`:
|
|
165
|
+
```
|
|
166
|
+
total_phases: {TOTAL - 1}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Do NOT renumber** subsequent phases. Phases after the removed one keep their original numbers. This preserves all references in commit history, `DECISIONS.md`, and archived phase folders. The roadmap simply has a gap (e.g., 1, 2, 3, 5, 6 — 4 was removed).
|
|
170
|
+
|
|
171
|
+
### Step 8: Audit trail in DECISIONS.md
|
|
172
|
+
|
|
173
|
+
Append:
|
|
174
|
+
```markdown
|
|
175
|
+
D-{N+1} ({date}): Phase $PHASE_NUMBER removed via /jdi-remove-phase. Artifacts: ${PHASE_DIR:+archived to .jdi/archive/removed-<NN-slug>/}{none if empty}.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Step 9: Commit
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
git add .jdi/ROADMAP.md .jdi/DECISIONS.md .jdi/archive/ 2>/dev/null
|
|
182
|
+
git commit -m "chore(jdi): remove phase {PHASE_NUMBER}"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Step 10: Confirm
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
Phase {PHASE_NUMBER} removed.
|
|
189
|
+
{if artifacts:} Artifacts archived: .jdi/archive/removed-{NN-slug}/
|
|
190
|
+
total_phases: {TOTAL - 1}
|
|
191
|
+
|
|
192
|
+
Note: phase numbers are not renumbered — references in commits, DECISIONS, and archive remain valid.
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
</process>
|
|
196
|
+
|
|
197
|
+
<gates>
|
|
198
|
+
- pre: `.jdi/ROADMAP.md` + `.jdi/STATE.md` exist
|
|
199
|
+
- pre: `phase_number` is in range `1..total_phases`
|
|
200
|
+
- pre: `phase_number > current_phase`
|
|
201
|
+
- pre: phase status != `done`
|
|
202
|
+
- pre: `--force` provided when phase has artifacts
|
|
203
|
+
- post: ROADMAP.md section removed + total_phases decremented + artifacts archived (if any) + DECISIONS.md appended + atomic commit
|
|
204
|
+
</gates>
|
|
205
|
+
|
|
206
|
+
<errors>
|
|
207
|
+
- `.jdi/` missing -> "Run /jdi-new first"
|
|
208
|
+
- `phase_number` missing -> usage hint
|
|
209
|
+
- `phase_number` out of range -> "Valid: 1..{total}"
|
|
210
|
+
- `phase_number < current_phase` -> refuse (past = history)
|
|
211
|
+
- `phase_number == current_phase` -> refuse (ship or abandon first)
|
|
212
|
+
- phase status `done` -> refuse (shipped = history)
|
|
213
|
+
- artifacts exist + no `--force` -> refuse + suggest `--force`
|
|
214
|
+
- user cancels at AskUserQuestion -> exit clean
|
|
215
|
+
</errors>
|
|
216
|
+
|
|
217
|
+
<runtime_notes>
|
|
218
|
+
|
|
219
|
+
**Claude Code:**
|
|
220
|
+
- Confirms via AskUserQuestion.
|
|
221
|
+
|
|
222
|
+
**Copilot:**
|
|
223
|
+
- AskUserQuestion not always available — require explicit `--yes` flag as fallback.
|
|
224
|
+
|
|
225
|
+
**OpenCode/Antigravity:**
|
|
226
|
+
- Same interactive confirm as Claude. Fallback to `--yes` when prompts unsupported.
|
|
227
|
+
|
|
228
|
+
</runtime_notes>
|