chief-clancy 0.8.22 → 0.9.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.
Files changed (94) hide show
  1. package/bin/clancy.js +153 -0
  2. package/package.json +8 -88
  3. package/README.md +0 -292
  4. package/dist/bundle/clancy-afk.js +0 -6
  5. package/dist/bundle/clancy-once.js +0 -239
  6. package/dist/installer/file-ops/file-ops.d.ts +0 -32
  7. package/dist/installer/file-ops/file-ops.d.ts.map +0 -1
  8. package/dist/installer/file-ops/file-ops.js +0 -58
  9. package/dist/installer/file-ops/file-ops.js.map +0 -1
  10. package/dist/installer/hook-installer/hook-installer.d.ts +0 -31
  11. package/dist/installer/hook-installer/hook-installer.d.ts.map +0 -1
  12. package/dist/installer/hook-installer/hook-installer.js +0 -137
  13. package/dist/installer/hook-installer/hook-installer.js.map +0 -1
  14. package/dist/installer/install.d.ts +0 -3
  15. package/dist/installer/install.d.ts.map +0 -1
  16. package/dist/installer/install.js +0 -270
  17. package/dist/installer/install.js.map +0 -1
  18. package/dist/installer/manifest/manifest.d.ts +0 -41
  19. package/dist/installer/manifest/manifest.d.ts.map +0 -1
  20. package/dist/installer/manifest/manifest.js +0 -97
  21. package/dist/installer/manifest/manifest.js.map +0 -1
  22. package/dist/installer/prompts/prompts.d.ts +0 -33
  23. package/dist/installer/prompts/prompts.d.ts.map +0 -1
  24. package/dist/installer/prompts/prompts.js +0 -55
  25. package/dist/installer/prompts/prompts.js.map +0 -1
  26. package/dist/installer/role-filter/role-filter.d.ts +0 -15
  27. package/dist/installer/role-filter/role-filter.d.ts.map +0 -1
  28. package/dist/installer/role-filter/role-filter.js +0 -48
  29. package/dist/installer/role-filter/role-filter.js.map +0 -1
  30. package/dist/installer/ui/ui.d.ts +0 -9
  31. package/dist/installer/ui/ui.d.ts.map +0 -1
  32. package/dist/installer/ui/ui.js +0 -94
  33. package/dist/installer/ui/ui.js.map +0 -1
  34. package/dist/scripts/shared/env-parser/env-parser.d.ts +0 -30
  35. package/dist/scripts/shared/env-parser/env-parser.d.ts.map +0 -1
  36. package/dist/scripts/shared/env-parser/env-parser.js +0 -64
  37. package/dist/scripts/shared/env-parser/env-parser.js.map +0 -1
  38. package/dist/utils/ansi/ansi.d.ts +0 -55
  39. package/dist/utils/ansi/ansi.d.ts.map +0 -1
  40. package/dist/utils/ansi/ansi.js +0 -55
  41. package/dist/utils/ansi/ansi.js.map +0 -1
  42. package/hooks/clancy-branch-guard.js +0 -128
  43. package/hooks/clancy-check-update.js +0 -114
  44. package/hooks/clancy-context-monitor.js +0 -189
  45. package/hooks/clancy-credential-guard.js +0 -120
  46. package/hooks/clancy-drift-detector.js +0 -96
  47. package/hooks/clancy-notification.js +0 -105
  48. package/hooks/clancy-post-compact.js +0 -53
  49. package/hooks/clancy-statusline.js +0 -82
  50. package/hooks/package.json +0 -3
  51. package/registry/boards.json +0 -44
  52. package/src/agents/arch-agent.md +0 -72
  53. package/src/agents/concerns-agent.md +0 -89
  54. package/src/agents/design-agent.md +0 -130
  55. package/src/agents/devils-advocate.md +0 -53
  56. package/src/agents/quality-agent.md +0 -161
  57. package/src/agents/tech-agent.md +0 -92
  58. package/src/agents/verification-gate.md +0 -128
  59. package/src/roles/implementer/commands/dry-run.md +0 -14
  60. package/src/roles/implementer/commands/once.md +0 -17
  61. package/src/roles/implementer/commands/run.md +0 -11
  62. package/src/roles/implementer/workflows/once.md +0 -146
  63. package/src/roles/implementer/workflows/run.md +0 -127
  64. package/src/roles/planner/commands/approve-plan.md +0 -10
  65. package/src/roles/planner/commands/plan.md +0 -20
  66. package/src/roles/planner/workflows/approve-plan.md +0 -535
  67. package/src/roles/planner/workflows/plan.md +0 -536
  68. package/src/roles/reviewer/commands/logs.md +0 -7
  69. package/src/roles/reviewer/commands/review.md +0 -9
  70. package/src/roles/reviewer/commands/status.md +0 -9
  71. package/src/roles/reviewer/workflows/logs.md +0 -104
  72. package/src/roles/reviewer/workflows/review.md +0 -186
  73. package/src/roles/reviewer/workflows/status.md +0 -134
  74. package/src/roles/setup/commands/doctor.md +0 -7
  75. package/src/roles/setup/commands/help.md +0 -80
  76. package/src/roles/setup/commands/init.md +0 -7
  77. package/src/roles/setup/commands/map-codebase.md +0 -16
  78. package/src/roles/setup/commands/settings.md +0 -7
  79. package/src/roles/setup/commands/uninstall.md +0 -5
  80. package/src/roles/setup/commands/update-docs.md +0 -9
  81. package/src/roles/setup/commands/update.md +0 -12
  82. package/src/roles/setup/workflows/doctor.md +0 -124
  83. package/src/roles/setup/workflows/init.md +0 -1073
  84. package/src/roles/setup/workflows/map-codebase.md +0 -125
  85. package/src/roles/setup/workflows/scaffold.md +0 -845
  86. package/src/roles/setup/workflows/settings.md +0 -944
  87. package/src/roles/setup/workflows/uninstall.md +0 -161
  88. package/src/roles/setup/workflows/update-docs.md +0 -92
  89. package/src/roles/setup/workflows/update.md +0 -277
  90. package/src/roles/strategist/commands/approve-brief.md +0 -21
  91. package/src/roles/strategist/commands/brief.md +0 -27
  92. package/src/roles/strategist/workflows/approve-brief.md +0 -834
  93. package/src/roles/strategist/workflows/brief.md +0 -890
  94. package/src/templates/CLAUDE.md +0 -87
@@ -1,10 +0,0 @@
1
- # /clancy:approve-plan
2
-
3
- Promote an approved Clancy plan to the ticket description. Accepts an optional ticket key argument (e.g. `/clancy:approve-plan PROJ-123`). When no key is provided, auto-selects the oldest planned-but-unapproved ticket.
4
-
5
- Optional flags:
6
- - **Skip confirmation:** `--afk` — auto-confirm without prompting (for automation)
7
-
8
- @.claude/clancy/workflows/approve-plan.md
9
-
10
- Follow the approve-plan workflow above. Fetch the plan comment, confirm with the user, append it to the ticket description, and transition the ticket to the implementation queue.
@@ -1,20 +0,0 @@
1
- # /clancy:plan
2
-
3
- Fetch backlog tickets from the board, explore the codebase, and generate structured implementation plans. Plans are posted as comments on the ticket for human review.
4
-
5
- Accepts optional arguments:
6
- - **Batch mode:** `/clancy:plan 3` — plan up to 3 tickets from the queue
7
- - **Specific ticket:** `/clancy:plan PROJ-123`, `/clancy:plan #42`, `/clancy:plan ENG-42` — plan a single ticket by key
8
- - **Fresh start:** `--fresh` — discard any existing plan and start over
9
- - **Skip confirmations:** `--afk` — auto-confirm all prompts (for automation)
10
-
11
- Examples:
12
- - `/clancy:plan` — plan 1 ticket from queue
13
- - `/clancy:plan 3` — plan 3 tickets from queue
14
- - `/clancy:plan PROJ-123` — plan a specific Jira/Linear ticket
15
- - `/clancy:plan #42` — plan a specific GitHub issue
16
- - `/clancy:plan --fresh PROJ-123` — discard existing plan and start over
17
-
18
- @.claude/clancy/workflows/plan.md
19
-
20
- Follow the plan workflow above. For each ticket: run the feasibility scan, explore the codebase, generate the plan, and post it as a comment. Do not implement anything — planning only.
@@ -1,535 +0,0 @@
1
- # Clancy Approve Plan Workflow
2
-
3
- ## Overview
4
-
5
- Promote an approved Clancy plan from a ticket comment to the ticket description. The plan is appended below the existing description, never replacing it. After promotion, the ticket is transitioned to the implementation queue.
6
-
7
- ---
8
-
9
- ## Step 1 — Preflight checks
10
-
11
- 1. Check `.clancy/` exists and `.clancy/.env` is present. If not:
12
- ```
13
- .clancy/ not found. Run /clancy:init to set up Clancy first.
14
- ```
15
- Stop.
16
-
17
- 2. Source `.clancy/.env` and check board credentials are present.
18
-
19
- ---
20
-
21
- ## Step 2 — Parse argument / Resolve ticket
22
-
23
- ### If no argument provided:
24
-
25
- 1. Scan `.clancy/progress.txt` for entries matching `| PLAN |` or `| REVISED |` that have no subsequent `| APPROVE_PLAN |` for the same key.
26
- 2. Sort by timestamp ascending (oldest first).
27
- 3. If 0 found:
28
- ```
29
- No planned tickets awaiting approval. Run /clancy:plan first.
30
- ```
31
- Stop.
32
- 4. If 1+ found, auto-select the oldest. Show:
33
- ```
34
- Auto-selected [{KEY}] {Title} (planned {date}). Promote this plan? [Y/n]
35
- ```
36
- To resolve the title, fetch the ticket from the board:
37
- - **GitHub:** `GET /repos/$GITHUB_REPO/issues/$ISSUE_NUMBER` → use `.title`
38
- - **Jira:** `GET $JIRA_BASE_URL/rest/api/3/issue/$KEY?fields=summary` → use `.fields.summary`
39
- - **Linear:** `issues(filter: { identifier: { eq: "$KEY" } }) { nodes { title } }` → use `nodes[0].title`
40
- If fetching fails, show the key without a title: `Auto-selected [{KEY}] (planned {date}). Promote? [Y/n]`
41
- 5. If user declines:
42
- ```
43
- Cancelled.
44
- ```
45
- Stop.
46
- 6. Note that the user has already confirmed — set a flag to skip the Step 4 confirmation.
47
-
48
- ### If argument provided:
49
-
50
- Validate the key format per board (case-insensitive):
51
- - **GitHub:** `#\d+` or bare number
52
- - **Jira:** `[A-Za-z][A-Za-z0-9]+-\d+` (e.g. `PROJ-123` or `proj-123`)
53
- - **Linear:** `[A-Za-z]{1,10}-\d+` (e.g. `ENG-42` or `eng-42`)
54
-
55
- If invalid format:
56
- ```
57
- Invalid ticket key: {input}. Expected format: {board-specific example}.
58
- ```
59
- Stop.
60
-
61
- Proceed with that key.
62
-
63
- ---
64
-
65
- ## Step 3 — Fetch the plan comment
66
-
67
- Detect board from `.clancy/.env` and fetch comments for the specified ticket.
68
-
69
- ### Jira
70
-
71
- ```bash
72
- RESPONSE=$(curl -s \
73
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
74
- -H "Accept: application/json" \
75
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY/comment")
76
- ```
77
-
78
- Search for the most recent comment containing an ADF heading node with text `Clancy Implementation Plan`. **Capture the comment `id`** for later editing in Step 5b.
79
-
80
- ### GitHub
81
-
82
- First, determine the issue number from the ticket key (strip the `#` prefix if present):
83
-
84
- ```bash
85
- RESPONSE=$(curl -s \
86
- -H "Authorization: Bearer $GITHUB_TOKEN" \
87
- -H "Accept: application/vnd.github+json" \
88
- -H "X-GitHub-Api-Version: 2022-11-28" \
89
- "https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER/comments?per_page=100")
90
- ```
91
-
92
- Search for the most recent comment body containing `## Clancy Implementation Plan`. **Capture the comment `id`** for later editing in Step 5b.
93
-
94
- ### Linear
95
-
96
- Use the filter-based query (preferred over `issueSearch`):
97
-
98
- ```graphql
99
- query {
100
- issues(filter: { identifier: { eq: "$KEY" } }) {
101
- nodes {
102
- id identifier title description
103
- comments {
104
- nodes { id body createdAt user { id } }
105
- }
106
- }
107
- }
108
- }
109
- ```
110
-
111
- If the filter-based query returns no results, fall back to `issueSearch`:
112
-
113
- ```graphql
114
- query {
115
- issueSearch(query: "$IDENTIFIER", first: 5) {
116
- nodes {
117
- id identifier title description
118
- comments { nodes { id body createdAt user { id } } }
119
- }
120
- }
121
- }
122
- ```
123
-
124
- **Important:** `issueSearch` is a fuzzy text search. After fetching results, verify the returned issue's `identifier` field exactly matches the provided key (case-insensitive). If no exact match is found in the results, report: `Issue {KEY} not found. Check the identifier and try again.`
125
-
126
- Search the comments for the most recent one containing `## Clancy Implementation Plan`. **Capture the comment `id`** and the existing comment `body` for later editing in Step 5b. Also capture the issue's internal `id` (UUID) for transitions in Step 6.
127
-
128
- If no plan comment is found:
129
- ```
130
- No Clancy plan found for {KEY}. Run /clancy:plan first.
131
- ```
132
- Stop.
133
-
134
- ---
135
-
136
- ## Step 3b — Check for existing plan in description
137
-
138
- Before confirming, check if the ticket description already contains `## Clancy Implementation Plan`.
139
-
140
- If it does:
141
- ```
142
- This ticket's description already contains a Clancy plan.
143
- Continuing will add a duplicate.
144
-
145
- [1] Continue anyway
146
- [2] Cancel
147
- ```
148
-
149
- If the user picks [2], stop: `Cancelled. No changes made.`
150
-
151
- ---
152
-
153
- ## Step 4 — Confirm
154
-
155
- **If the user already confirmed via auto-select in Step 2, SKIP this step entirely** (avoid double-confirmation).
156
-
157
- **AFK mode:** If running in AFK mode (`--afk` flag or `CLANCY_MODE=afk`), skip the confirmation prompt and auto-confirm. Display the summary for logging purposes but proceed without waiting for input.
158
-
159
- Display a summary and ask for confirmation:
160
-
161
- ```
162
- Clancy — Approve Plan
163
-
164
- [{KEY}] {Title}
165
- Size: {S/M/L} | {N} affected files
166
- Planned: {date from plan}
167
-
168
- Promote this plan to the ticket description? [Y/n]
169
- ```
170
-
171
- If the user declines (interactive only), stop:
172
- ```
173
- Cancelled. No changes made.
174
- ```
175
-
176
- ---
177
-
178
- ## Step 5 — Update ticket description
179
-
180
- Append the plan below the existing description with a separator. Never overwrite the original description.
181
-
182
- The updated description follows this format:
183
- ```
184
- {existing description}
185
-
186
- ---
187
-
188
- {full plan content}
189
- ```
190
-
191
- ### Jira — PUT issue
192
-
193
- Fetch the current description first:
194
- ```bash
195
- CURRENT=$(curl -s \
196
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
197
- -H "Accept: application/json" \
198
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY?fields=description")
199
- ```
200
-
201
- Merge the existing ADF description with a `rule` node (horizontal rule) and the plan content as new ADF nodes. Then update:
202
-
203
- ```bash
204
- curl -s \
205
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
206
- -X PUT \
207
- -H "Content-Type: application/json" \
208
- -H "Accept: application/json" \
209
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY" \
210
- -d '{"fields": {"description": <merged ADF>}}'
211
- ```
212
-
213
- If ADF construction fails for the plan content, wrap the plan in a `codeBlock` node as fallback.
214
-
215
- ### GitHub — PATCH issue
216
-
217
- Fetch the current body:
218
- ```bash
219
- CURRENT=$(curl -s \
220
- -H "Authorization: Bearer $GITHUB_TOKEN" \
221
- -H "Accept: application/vnd.github+json" \
222
- -H "X-GitHub-Api-Version: 2022-11-28" \
223
- "https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER")
224
- ```
225
-
226
- Append the plan:
227
- ```bash
228
- curl -s \
229
- -H "Authorization: Bearer $GITHUB_TOKEN" \
230
- -H "Accept: application/vnd.github+json" \
231
- -H "X-GitHub-Api-Version: 2022-11-28" \
232
- -X PATCH \
233
- "https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER" \
234
- -d '{"body": "<existing body>\n\n---\n\n<plan>"}'
235
- ```
236
-
237
- ### Linear — issueUpdate mutation
238
-
239
- Fetch the current description:
240
- ```graphql
241
- query { issue(id: "$ISSUE_ID") { description } }
242
- ```
243
-
244
- Update with appended plan:
245
- ```graphql
246
- mutation {
247
- issueUpdate(
248
- id: "$ISSUE_ID"
249
- input: { description: "<existing>\n\n---\n\n<plan>" }
250
- ) { success }
251
- }
252
- ```
253
-
254
- ---
255
-
256
- ## Step 5b — Edit plan comment (approval note)
257
-
258
- After updating the description, edit the original plan comment to prepend an approval note. This is **best-effort** — warn on failure, continue.
259
-
260
- ### GitHub
261
-
262
- ```bash
263
- curl -s \
264
- -H "Authorization: Bearer $GITHUB_TOKEN" \
265
- -H "Accept: application/vnd.github+json" \
266
- -H "X-GitHub-Api-Version: 2022-11-28" \
267
- -H "Content-Type: application/json" \
268
- -X PATCH \
269
- "https://api.github.com/repos/$GITHUB_REPO/issues/comments/$COMMENT_ID" \
270
- -d '{"body": "> **Plan approved and promoted to description** -- {YYYY-MM-DD}\n\n{existing_comment_body}"}'
271
- ```
272
-
273
- ### Jira
274
-
275
- ```bash
276
- curl -s \
277
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
278
- -X PUT \
279
- -H "Content-Type: application/json" \
280
- -H "Accept: application/json" \
281
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY/comment/$COMMENT_ID" \
282
- -d '{
283
- "body": {
284
- "version": 1,
285
- "type": "doc",
286
- "content": [
287
- {"type": "paragraph", "content": [
288
- {"type": "text", "text": "Plan approved and promoted to description -- {YYYY-MM-DD}.",
289
- "marks": [{"type": "strong"}]}
290
- ]},
291
- <...existing ADF content nodes...>
292
- ]
293
- }
294
- }'
295
- ```
296
-
297
- ### Linear
298
-
299
- ```graphql
300
- mutation {
301
- commentUpdate(
302
- id: "$COMMENT_ID"
303
- input: {
304
- body: "> **Plan approved and promoted to description** -- {YYYY-MM-DD}\n\n{existing_comment_body}"
305
- }
306
- ) { success }
307
- }
308
- ```
309
-
310
- On failure for any platform:
311
- ```
312
- Could not update plan comment. The plan is still promoted to the description.
313
- ```
314
-
315
- ---
316
-
317
- ## Step 6 — Post-approval label transition
318
-
319
- Transition the ticket from the planning queue to the implementation queue via pipeline labels. This is **best-effort** — warn on failure, continue.
320
-
321
- **Crash safety:** Add the new label BEFORE removing the old one. A ticket briefly has two labels (harmless) rather than zero labels (ticket lost).
322
-
323
- **This label transition is mandatory — always apply and remove.** Use `CLANCY_LABEL_BUILD` from `.clancy/.env` if set, otherwise `clancy:build`. Use `CLANCY_LABEL_PLAN` from `.clancy/.env` if set, otherwise fall back to `CLANCY_PLAN_LABEL`, otherwise `clancy:plan`. Ensure the build label exists on the board (create if missing), add it to the ticket, then remove the plan label.
324
-
325
- ### GitHub
326
-
327
- 1. **Add build label** (ensure it exists first):
328
- ```bash
329
- # Ensure label exists (ignore 422 = already exists)
330
- curl -s \
331
- -H "Authorization: Bearer $GITHUB_TOKEN" \
332
- -H "Accept: application/vnd.github+json" \
333
- -H "X-GitHub-Api-Version: 2022-11-28" \
334
- -H "Content-Type: application/json" \
335
- -X POST \
336
- "https://api.github.com/repos/$GITHUB_REPO/labels" \
337
- -d '{"name": "$CLANCY_LABEL_BUILD", "color": "0075ca"}'
338
-
339
- # Add to issue
340
- curl -s \
341
- -H "Authorization: Bearer $GITHUB_TOKEN" \
342
- -H "Accept: application/vnd.github+json" \
343
- -H "X-GitHub-Api-Version: 2022-11-28" \
344
- -H "Content-Type: application/json" \
345
- -X POST \
346
- "https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER/labels" \
347
- -d '{"labels": ["$CLANCY_LABEL_BUILD"]}'
348
- ```
349
-
350
- 2. **Remove plan label:**
351
- ```bash
352
- curl -s \
353
- -H "Authorization: Bearer $GITHUB_TOKEN" \
354
- -H "Accept: application/vnd.github+json" \
355
- -H "X-GitHub-Api-Version: 2022-11-28" \
356
- -X DELETE \
357
- "https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER/labels/$(echo $CLANCY_LABEL_PLAN | jq -Rr @uri)"
358
- ```
359
- Ignore 404 (label not on issue).
360
-
361
- ### Jira
362
-
363
- 1. **Add build label** (Jira auto-creates labels):
364
- ```bash
365
- # Fetch current labels
366
- CURRENT_LABELS=$(curl -s \
367
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
368
- -H "Accept: application/json" \
369
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY?fields=labels" | jq -r '.fields.labels')
370
-
371
- # Add build label
372
- UPDATED_LABELS=$(echo "$CURRENT_LABELS" | jq --arg build "$CLANCY_LABEL_BUILD" '. + [$build] | unique')
373
-
374
- curl -s \
375
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
376
- -X PUT \
377
- -H "Content-Type: application/json" \
378
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY" \
379
- -d "{\"fields\": {\"labels\": $UPDATED_LABELS}}"
380
- ```
381
-
382
- 2. **Remove plan label:**
383
- ```bash
384
- # Re-fetch labels (may have changed), remove plan label
385
- CURRENT_LABELS=$(curl -s \
386
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
387
- -H "Accept: application/json" \
388
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY?fields=labels" | jq -r '.fields.labels')
389
-
390
- UPDATED_LABELS=$(echo "$CURRENT_LABELS" | jq --arg plan "$CLANCY_LABEL_PLAN" '[.[] | select(. != $plan)]')
391
-
392
- curl -s \
393
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
394
- -X PUT \
395
- -H "Content-Type: application/json" \
396
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY" \
397
- -d "{\"fields\": {\"labels\": $UPDATED_LABELS}}"
398
- ```
399
-
400
- 3. **Status transition** (only if `CLANCY_STATUS_PLANNED` is set — skip if unset):
401
- ```bash
402
- # Fetch transitions
403
- curl -s \
404
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
405
- -H "Accept: application/json" \
406
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY/transitions"
407
-
408
- # Find matching transition and execute
409
- curl -s \
410
- -u "$JIRA_USER:$JIRA_API_TOKEN" \
411
- -X POST \
412
- -H "Content-Type: application/json" \
413
- "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY/transitions" \
414
- -d '{"transition": {"id": "$TRANSITION_ID"}}'
415
- ```
416
-
417
- On failure:
418
- ```
419
- Could not transition ticket. Move it manually to your implementation queue.
420
- ```
421
-
422
- ### Linear
423
-
424
- 1. **Add build label** (ensure it exists, then add):
425
- ```graphql
426
- # Ensure label exists — check team labels, workspace labels, create if missing
427
- mutation {
428
- issueLabelCreate(input: {
429
- teamId: "$LINEAR_TEAM_ID"
430
- name: "$CLANCY_LABEL_BUILD"
431
- color: "#0075ca"
432
- }) { success issueLabel { id } }
433
- }
434
-
435
- # Fetch current label IDs on the issue, add build label ID
436
- mutation {
437
- issueUpdate(
438
- id: "$ISSUE_UUID"
439
- input: { labelIds: [...currentLabelIds, buildLabelId] }
440
- ) { success }
441
- }
442
- ```
443
-
444
- 2. **Remove plan label:**
445
- ```graphql
446
- # Fetch current label IDs, filter out plan label ID
447
- mutation {
448
- issueUpdate(
449
- id: "$ISSUE_UUID"
450
- input: { labelIds: [currentLabelIds without planLabelId] }
451
- ) { success }
452
- }
453
- ```
454
-
455
- 3. **State transition** (always):
456
- ```graphql
457
- # Resolve "unstarted" state
458
- query {
459
- workflowStates(filter: {
460
- team: { id: { eq: "$LINEAR_TEAM_ID" } }
461
- type: { eq: "unstarted" }
462
- }) { nodes { id name } }
463
- }
464
-
465
- # Transition
466
- mutation {
467
- issueUpdate(
468
- id: "$ISSUE_UUID"
469
- input: { stateId: "$UNSTARTED_STATE_ID" }
470
- ) { success }
471
- }
472
- ```
473
- If no `unstarted` state found: warn, skip transition.
474
-
475
- On failure:
476
- ```
477
- Could not transition ticket. Move it manually to your implementation queue.
478
- ```
479
-
480
- ---
481
-
482
- ## Step 7 — Confirm and log
483
-
484
- On success, display a board-specific message:
485
-
486
- **GitHub:**
487
- ```
488
- Plan promoted. Label swapped: {CLANCY_LABEL_PLAN} → {CLANCY_LABEL_BUILD}. Ready for /clancy:once.
489
-
490
- "Book 'em, Lou." — The ticket is ready for /clancy:once.
491
- ```
492
-
493
- **Jira (with transition):**
494
- ```
495
- Plan promoted. Ticket transitioned to {CLANCY_STATUS_PLANNED}.
496
-
497
- "Book 'em, Lou." -- The ticket is ready for /clancy:once.
498
- ```
499
-
500
- **Jira (no transition configured):**
501
- ```
502
- Plan promoted. Move [{KEY}] to your implementation queue for /clancy:once.
503
-
504
- "Book 'em, Lou." -- The ticket is ready for /clancy:once.
505
- ```
506
-
507
- **Linear:**
508
- ```
509
- Plan promoted. Moved to unstarted. Ready for /clancy:once.
510
-
511
- "Book 'em, Lou." -- The ticket is ready for /clancy:once.
512
- ```
513
-
514
- Append to `.clancy/progress.txt`:
515
- ```
516
- YYYY-MM-DD HH:MM | {KEY} | APPROVE_PLAN | —
517
- ```
518
-
519
- On failure:
520
- ```
521
- Failed to update description for [{KEY}]. Check your board permissions.
522
- ```
523
-
524
- ---
525
-
526
- ## Notes
527
-
528
- - This command only appends -- it never overwrites the existing ticket description
529
- - If the ticket has multiple plan comments, the most recent one is used
530
- - The plan content is taken verbatim from the comment -- no regeneration
531
- - Step 3b checks for existing plans in the description to prevent accidental duplication
532
- - The ticket key is case-insensitive -- accept `PROJ-123`, `proj-123`, or `#123` (GitHub)
533
- - Step 5b edits the plan comment with an approval note -- this is best-effort and does not block the workflow
534
- - Step 6 transitions the ticket to the implementation queue -- this is best-effort and board-specific
535
- - The `## Clancy Implementation Plan` marker in comments is used by both `/clancy:plan` (to detect existing plans) and `/clancy:approve-plan` (to find the plan to promote)