jdi-cli 0.1.2 → 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.
@@ -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>