forgedock 1.0.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/LICENSE +244 -0
- package/README.md +251 -0
- package/bin/forgedock.mjs +232 -0
- package/commands/analytics.md +777 -0
- package/commands/audit-agents.md +410 -0
- package/commands/audit.md +410 -0
- package/commands/autopilot.md +432 -0
- package/commands/cleanup.md +264 -0
- package/commands/deploy-info.md +292 -0
- package/commands/failure-recon.md +375 -0
- package/commands/forge-stats.md +183 -0
- package/commands/geo-audit.md +343 -0
- package/commands/incident-response.md +384 -0
- package/commands/issue.md +506 -0
- package/commands/milestone.md +599 -0
- package/commands/orchestrate.md +1044 -0
- package/commands/pipeline-health.md +2343 -0
- package/commands/qa-sweep.md +237 -0
- package/commands/quality-gate.md +777 -0
- package/commands/review-pr-agents.md +1711 -0
- package/commands/review-pr-staging.md +325 -0
- package/commands/review-pr.md +888 -0
- package/commands/rollback.md +253 -0
- package/commands/security-audit.md +529 -0
- package/commands/sync-ecosystem.md +527 -0
- package/commands/validate.md +131 -0
- package/commands/work-on/build/architect.md +291 -0
- package/commands/work-on/build/context.md +349 -0
- package/commands/work-on/build/implement.md +280 -0
- package/commands/work-on/build/validate.md +292 -0
- package/commands/work-on/build.md +262 -0
- package/commands/work-on/close.md +350 -0
- package/commands/work-on/decompose.md +254 -0
- package/commands/work-on/investigate.md +437 -0
- package/commands/work-on/review.md +245 -0
- package/commands/work-on-monolithic.md +298 -0
- package/commands/work-on.md +1089 -0
- package/docs/CODEX.md +92 -0
- package/docs/WORKFLOW.md +104 -0
- package/package.json +45 -0
- package/scripts/verify-env-vars.sh +201 -0
- package/scripts/verify-host-headers.sh +117 -0
- package/scripts/verify-route-registration.sh +118 -0
- package/scripts/verify-sops-chain.sh +163 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Build subcommand — create worktree, post contract, sequence context/architect/implement/validate
|
|
3
|
+
argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--base PR_BASE]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# work-on/build — Build Phase Orchestrator
|
|
7
|
+
|
|
8
|
+
**Input**: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
**Invoked by**: `work-on.md` state 8 (READY_TO_BUILD).
|
|
11
|
+
**Output**: Create worktree, post contract, sequence build subcommands, return result to router.
|
|
12
|
+
|
|
13
|
+
**Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
|
|
14
|
+
**NEVER use plan mode (EnterPlanMode).**
|
|
15
|
+
|
|
16
|
+
**CRITICAL: You MUST execute ALL phases B0–B6 in order. After each Skill() call returns, you MUST continue to the next phase. Do NOT skip phases B3 (context) or B4 (architect) — they post mandatory `FORGE:CONTEXT` and `FORGE:ARCHITECT` comments that the implement phase reads as its primary input. Skipping them degrades build quality.**
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Inputs
|
|
21
|
+
|
|
22
|
+
Parse from $ARGUMENTS:
|
|
23
|
+
- `{NUMBER}` — issue number (required)
|
|
24
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `RapierCraftStudios/forge`)
|
|
25
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R RapierCraftStudios/forge`)
|
|
26
|
+
- `--base {PR_BASE}` — PR target branch (e.g. `milestone/modular-pipeline-architecture` or `staging`)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Phase B0: Load State from GitHub (MANDATORY)
|
|
31
|
+
|
|
32
|
+
Re-read current state before doing anything:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
|
|
36
|
+
|
|
37
|
+
# Check investigation report
|
|
38
|
+
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
39
|
+
--jq '.[] | select(.body | (contains("FORGE:INVESTIGATOR") or contains("ALTERLAB:INVESTIGATOR"))) | .body'
|
|
40
|
+
|
|
41
|
+
# Check if build already completed
|
|
42
|
+
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
43
|
+
--jq '.[] | select(.body | (contains("FORGE:BUILDER") or contains("ALTERLAB:BUILDER"))) | .body'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Resume check**:
|
|
47
|
+
- If `<!-- FORGE:BUILDER -->` or `<!-- ALTERLAB:BUILDER -->` comment exists → build already complete. Return `BUILD_RESULT: status: ALREADY_DONE` to router.
|
|
48
|
+
- If no `<!-- FORGE:INVESTIGATOR -->` or `<!-- ALTERLAB:INVESTIGATOR -->` comment with `<!-- INVESTIGATION:COMPLETE -->` → EXIT with `BUILD_RESULT: status: BLOCKED`, blocker: "Investigation not complete — run investigate first".
|
|
49
|
+
|
|
50
|
+
Extract from investigation report:
|
|
51
|
+
- Affected files list
|
|
52
|
+
- Root cause
|
|
53
|
+
- Recommendation
|
|
54
|
+
- Task type (Bug Fix / Feature / Refactor / Maintenance / UI/UX / Full-Stack)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Phase B1: Create Worktree & Branch
|
|
59
|
+
|
|
60
|
+
### B1A: Derive branch name
|
|
61
|
+
|
|
62
|
+
From issue title: lowercase, hyphenated, max 40 chars (truncate if needed).
|
|
63
|
+
- Bug / fix issues → prefix `fix/`
|
|
64
|
+
- Feature issues → prefix `feat/`
|
|
65
|
+
- Refactor / maintenance → prefix `fix/` or `refactor/`
|
|
66
|
+
|
|
67
|
+
Append `-{NUMBER}` to ensure uniqueness: e.g. `fix/work-on-build-landing-file-85`.
|
|
68
|
+
|
|
69
|
+
### B1B: Determine source branch
|
|
70
|
+
|
|
71
|
+
- Review-finding issue → parse `**Code branch**: \`{branch}\`` from issue body; branch from `origin/{branch}`
|
|
72
|
+
- **Milestone review-finding hybrid lane** (ONLY when Code branch matches `milestone/*`): This is a high-risk lane. The worktree will carry the full milestone history. The PR target is `staging` (or the base specified). **DANGER: Agents MUST NOT use `git merge` to resolve any conflicts in this lane.** Merge-based conflict resolution will pull the entire milestone commit tree onto staging, contaminating it with unapproved code. Use `git rebase` or `git cherry-pick` only. If conflicts cannot be resolved without a merge, post a comment on the issue, add `needs-human`, and STOP.
|
|
73
|
+
- Feature lane (has milestone) → branch from `origin/{PR_BASE}`
|
|
74
|
+
- Fast lane (no milestone) → branch from `origin/staging`
|
|
75
|
+
|
|
76
|
+
### B1C: Create worktree
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
WORKTREE_PATH="/path/to/repo/.claude/worktrees/{BRANCH_SLUG}"
|
|
80
|
+
git worktree add {WORKTREE_PATH} -b {BRANCH} origin/{SOURCE_BRANCH}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If worktree already exists at that path:
|
|
84
|
+
```bash
|
|
85
|
+
# Reuse existing worktree — verify it's on the correct branch
|
|
86
|
+
git -C {WORKTREE_PATH} branch --show-current
|
|
87
|
+
```
|
|
88
|
+
If wrong branch, remove and recreate:
|
|
89
|
+
```bash
|
|
90
|
+
git worktree remove {WORKTREE_PATH} --force
|
|
91
|
+
git worktree add {WORKTREE_PATH} -b {BRANCH} origin/{SOURCE_BRANCH}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### B1D: Set building label
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
gh issue edit {NUMBER} {GH_FLAG} \
|
|
98
|
+
--add-label "workflow:building" \
|
|
99
|
+
--remove-label "workflow:ready-to-build"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Phase B2: Post Builder Contract
|
|
105
|
+
|
|
106
|
+
Post `<!-- FORGE:CONTRACT -->` comment documenting what will be built and why:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:CONTRACT -->
|
|
110
|
+
## Builder Contract
|
|
111
|
+
|
|
112
|
+
**Task type**: {TASK_TYPE}
|
|
113
|
+
|
|
114
|
+
### Proposed Approach
|
|
115
|
+
|
|
116
|
+
{BRIEF_APPROACH_DESCRIPTION}
|
|
117
|
+
|
|
118
|
+
### Deliverables
|
|
119
|
+
|
|
120
|
+
| File | Change | Why |
|
|
121
|
+
|------|--------|-----|
|
|
122
|
+
{DELIVERABLES_ROWS}
|
|
123
|
+
|
|
124
|
+
### Acceptance Criteria
|
|
125
|
+
|
|
126
|
+
{ACCEPTANCE_CRITERIA_CHECKLIST}
|
|
127
|
+
|
|
128
|
+
### Quality Considerations
|
|
129
|
+
|
|
130
|
+
{AUTH_MODEL_NEW_ENV_VARS_SQL_SAFETY_SECURITY_SURFACE}
|
|
131
|
+
|
|
132
|
+
### Out of Scope
|
|
133
|
+
|
|
134
|
+
{OUT_OF_SCOPE_ITEMS}"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Contract must be grounded in the investigation report. Every deliverable file must appear in the affected files list from the investigator. Adversarially validate the proposed fix against adjacent system layers before posting.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Phase B2.5: Extract FUNCTION_NAMES from Contract
|
|
142
|
+
|
|
143
|
+
After posting the Builder Contract, extract the primary function/class names from the contract's deliverables table. These are passed to the context subcommand for Phase C3 caller/importer discovery.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
FUNCTION_NAMES=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
147
|
+
--jq '.[] | select(.body | contains("FORGE:CONTRACT")) | .body' \
|
|
148
|
+
| awk '/^### Deliverables/{p=1; next} /^### /{p=0} p' \
|
|
149
|
+
| grep -oP '`[A-Za-z_][A-Za-z0-9_]*`' \
|
|
150
|
+
| tr -d '`' \
|
|
151
|
+
| sort -u \
|
|
152
|
+
| tr '\n' ' ' \
|
|
153
|
+
| xargs)
|
|
154
|
+
# Scope is limited to the ### Deliverables section to avoid false matches from FORGE markers,
|
|
155
|
+
# phase labels (B2, C3), and identifiers mentioned in Acceptance Criteria or Quality sections.
|
|
156
|
+
# Fallback: if extraction yields nothing, FUNCTION_NAMES remains empty string
|
|
157
|
+
# context.md Phase C3 skips gracefully when FUNCTION_NAMES is empty (for-loop produces zero iterations)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If `FUNCTION_NAMES` is non-empty, it will be passed via `--functions` to the context subcommand. If empty, the `--functions` flag is omitted — Phase C3 will naturally skip with zero iterations and no error.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Phase B3: Context Gathering (MANDATORY Subcommand)
|
|
165
|
+
|
|
166
|
+
**This phase is NOT optional.** Always invoke it regardless of issue size or complexity. Do NOT invent skip heuristics (e.g. "FAST_PATH") — the context subcommand handles trivial cases gracefully and returns quickly.
|
|
167
|
+
|
|
168
|
+
Invoke the context subcommand to surface historical review findings and bug patterns:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
Skill("work-on:build:context", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} {AFFECTED_FILES} --functions {FUNCTION_NAMES}")
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
If `FUNCTION_NAMES` is empty, omit the `--functions` flag entirely:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
Skill("work-on:build:context", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} {AFFECTED_FILES}")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**After subcommand returns**:
|
|
181
|
+
- Returns structured context briefing (or indicates no relevant history) → continue to B4
|
|
182
|
+
- If subcommand times out or errors → log warning, continue to B4 with empty context (non-blocking)
|
|
183
|
+
# MUST CONTINUE to Phase B4 — context result is intermediate, NOT terminal.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Phase B4: Architecture Planning (MANDATORY Subcommand)
|
|
188
|
+
|
|
189
|
+
**This phase is NOT optional.** Always invoke it regardless of issue size or complexity. Do NOT invent skip heuristics — the architect subcommand handles simple changes gracefully and returns quickly. Even a 1-file fix benefits from cross-path consistency checks.
|
|
190
|
+
|
|
191
|
+
Invoke the architect subcommand to trace all affected code paths and produce an ordered implementation plan:
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
Skill("work-on:build:architect", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} --files {AFFECTED_FILES}")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**After subcommand returns**:
|
|
198
|
+
- Returns ordered implementation plan → continue to B5
|
|
199
|
+
- If subcommand returns BLOCKED → post comment, add `needs-human`, return `BUILD_RESULT: status: BLOCKED`
|
|
200
|
+
# MUST CONTINUE to Phase B5 — architect result is intermediate, NOT terminal.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Phase B5: Implementation (Subcommand)
|
|
205
|
+
|
|
206
|
+
Invoke the implement subcommand to write code, stage, and post the builder comment:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
Skill("work-on:build:implement", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --worktree {WORKTREE_PATH} --branch {BRANCH}")
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**After subcommand returns**:
|
|
213
|
+
- `IMPLEMENT_RESULT: status: COMPLETE` → continue to B6
|
|
214
|
+
- `IMPLEMENT_RESULT: status: ALREADY_DONE` → skip to B6 (validate what's already there)
|
|
215
|
+
- `IMPLEMENT_RESULT: status: INVESTIGATION_COMPLETE` → issues created as deliverables; return `BUILD_RESULT: status: INVESTIGATION_COMPLETE`
|
|
216
|
+
- `IMPLEMENT_RESULT: status: BLOCKED` → post comment with blocker description, add `needs-human`, return `BUILD_RESULT: status: BLOCKED`
|
|
217
|
+
# MUST CONTINUE to Phase B6 — implement result is intermediate, NOT terminal (validation still required).
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Phase B6: Validation (Subcommand)
|
|
222
|
+
|
|
223
|
+
Invoke the validate subcommand to run the quality gate loop, formatting, and deploy checks:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
Skill("work-on:build:validate", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --worktree {WORKTREE_PATH} --files {CHANGED_FILES}")
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Where `{CHANGED_FILES}` is the space-separated list of files changed by the implement subcommand (read from `IMPLEMENT_RESULT` or from the `<!-- FORGE:BUILDER -->` comment).
|
|
230
|
+
|
|
231
|
+
**After subcommand returns**:
|
|
232
|
+
- `VALIDATE_RESULT: gate_passed: true` → build complete, return `BUILD_RESULT: status: COMPLETE`
|
|
233
|
+
- `VALIDATE_RESULT: gate_passed: false` → subcommand has already posted comment and added `needs-human` label; return `BUILD_RESULT: status: BLOCKED`
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Output
|
|
238
|
+
|
|
239
|
+
Output this structured block — the routing loop in `work-on.md` will read this result, re-evaluate state, and continue to the next phase. This subcommand is complete; control returns to the router's loop iteration.
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
BUILD_RESULT:
|
|
243
|
+
status: COMPLETE | ALREADY_DONE | INVESTIGATION_COMPLETE | BLOCKED
|
|
244
|
+
branch: {BRANCH}
|
|
245
|
+
worktree: {WORKTREE_PATH}
|
|
246
|
+
blocker: {description if status=BLOCKED}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Integration Point in work-on.md
|
|
252
|
+
|
|
253
|
+
This module runs at **state 8 (READY_TO_BUILD)** in the routing loop:
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
state 8 → [THIS MODULE] worktree + contract + context + architect + implement + validate
|
|
257
|
+
→ BUILD_RESULT: COMPLETE
|
|
258
|
+
states 7, 6 → work-on:review (push + PR + /review-pr --auto-merge)
|
|
259
|
+
states 5, 4 → work-on:close (trajectory + parent tracker + summary)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The router re-reads GitHub state after this module returns COMPLETE — it will then detect state 6 (IN_REVIEW) or 7 (BUILD_NO_PR) and invoke `work-on:review`.
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Close subcommand — update project board, final issue body, parent tracker, summary report, trajectory log
|
|
3
|
+
argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--pr PR_NUMBER] [--base PR_BASE] [--branch BRANCH] [--worktree WORKTREE_PATH]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# work-on/close — Close & Trajectory Subcommand
|
|
7
|
+
|
|
8
|
+
**Input**: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
**Invoked by**: `work-on.md` Phase 6–7, after `review.md` returns `REVIEW_RESULT: status: COMPLETE`.
|
|
11
|
+
**Output**: Update project board, close issue, update parent tracker, post trajectory log. Return final summary.
|
|
12
|
+
|
|
13
|
+
**Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
|
|
14
|
+
**NEVER use plan mode (EnterPlanMode).**
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Inputs
|
|
19
|
+
|
|
20
|
+
Parse from $ARGUMENTS:
|
|
21
|
+
- `{NUMBER}` — issue number (required)
|
|
22
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `RapierCraftStudios/forge`)
|
|
23
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R RapierCraftStudios/forge`)
|
|
24
|
+
- `--pr {PR_NUMBER}` — merged PR number
|
|
25
|
+
- `--base {PR_BASE}` — branch the PR merged into (e.g. `milestone/modular-pipeline-architecture`)
|
|
26
|
+
- `--branch {BRANCH}` — feature branch name (for worktree cleanup reference)
|
|
27
|
+
- `--worktree {WORKTREE_PATH}` — absolute path to the git worktree to remove (optional — skip cleanup if not provided)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Phase C0: Load State from GitHub (MANDATORY)
|
|
32
|
+
|
|
33
|
+
Re-read current state before doing anything:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Issue full context
|
|
37
|
+
gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
|
|
38
|
+
|
|
39
|
+
# PR state
|
|
40
|
+
gh pr view {PR_NUMBER} {GH_FLAG} --json state,mergedAt,mergeCommit
|
|
41
|
+
|
|
42
|
+
# All agent comments (to reconstruct pipeline results)
|
|
43
|
+
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
44
|
+
--jq '.[] | {body: .body, created_at: .created_at}'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Extract from agent comments:
|
|
48
|
+
- From FORGE:INVESTIGATOR: verdict, confidence, task type
|
|
49
|
+
- From FORGE:BUILDER: branch, commits, files changed
|
|
50
|
+
- From FORGE:TRAJECTORY (if exists): prior trajectory entries
|
|
51
|
+
|
|
52
|
+
**Resume check**:
|
|
53
|
+
- If `<!-- FORGE:TRAJECTORY -->` comment already exists → trajectory already posted, EXIT with `CLOSE_RESULT: status: ALREADY_DONE`
|
|
54
|
+
- If issue is already CLOSED and PR is MERGED → skip to C3 (just post trajectory if missing)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Phase C1: Final Issue Body Update
|
|
59
|
+
|
|
60
|
+
**Multi-phase guard**: Before checking off items, detect whether the issue has multiple phases. Only check off items belonging to the current completed phase — not all remaining items across future phases.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Read current body
|
|
64
|
+
BODY=$(gh issue view {NUMBER} {GH_FLAG} --json body --jq '.body')
|
|
65
|
+
|
|
66
|
+
# Count remaining unchecked items BEFORE any edit
|
|
67
|
+
REMAINING_BEFORE=$(echo "$BODY" | grep -c '^- \[ \]' || true)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**If `REMAINING_BEFORE == 0`** (no unchecked items): skip body edit — all items already checked, proceed to add PR reference only:
|
|
71
|
+
```bash
|
|
72
|
+
UPDATED_BODY="${BODY}"$'\n\n'"**PR**: #{PR_NUMBER} → merged to \`{PR_BASE}\`"
|
|
73
|
+
gh issue edit {NUMBER} {GH_FLAG} --body "{UPDATED_BODY}"
|
|
74
|
+
REMAINING_AFTER=0
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**If `REMAINING_BEFORE > 0`**: check whether ANY `- [ ]` items will still remain after a full check-off — i.e., does the issue have multi-phase structure?
|
|
78
|
+
|
|
79
|
+
Multi-phase issues have checkbox groups separated by phase headings (lines starting with `##` or `###`) where at least one group has unchecked items. Detect this:
|
|
80
|
+
```bash
|
|
81
|
+
# Conservative heuristic: if the issue body contains a phase heading (## or ###)
|
|
82
|
+
# AND unchecked items remain, treat as multi-phase — do NOT check off items from
|
|
83
|
+
# future phases; only add the PR reference and leave unchecked items intact.
|
|
84
|
+
HAS_PHASE_HEADINGS=$(echo "$BODY" | grep -cP '^#{2,3} ' || true)
|
|
85
|
+
|
|
86
|
+
if [ "$HAS_PHASE_HEADINGS" -gt 0 ]; then
|
|
87
|
+
# Multi-phase issue: do NOT check off any [ ] items
|
|
88
|
+
# Only add the PR reference so progress is recorded
|
|
89
|
+
UPDATED_BODY="${BODY}"$'\n\n'"**PR**: #{PR_NUMBER} → merged to \`{PR_BASE}\` (phase complete — remaining phases open)"
|
|
90
|
+
gh issue edit {NUMBER} {GH_FLAG} --body "{UPDATED_BODY}"
|
|
91
|
+
REMAINING_AFTER="$REMAINING_BEFORE"
|
|
92
|
+
else
|
|
93
|
+
# Single-phase issue: check off all remaining [ ] items
|
|
94
|
+
UPDATED_BODY=$(echo "$BODY" | sed 's/^- \[ \]/- [x]/g')
|
|
95
|
+
UPDATED_BODY="${UPDATED_BODY}"$'\n\n'"**PR**: #{PR_NUMBER} → merged to \`{PR_BASE}\`"
|
|
96
|
+
gh issue edit {NUMBER} {GH_FLAG} --body "{UPDATED_BODY}"
|
|
97
|
+
REMAINING_AFTER=0
|
|
98
|
+
fi
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The `REMAINING_AFTER` variable is passed to Phase C2 to decide whether to close.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Phase C1.5: Project Board Update (Status=Done, Workflow=Merged)
|
|
106
|
+
|
|
107
|
+
Update the project board to reflect the merged state. This replaces the old Phase 5E project board update that existed before the modular refactor.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Find the project item ID for this issue
|
|
111
|
+
ISSUE_URL="https://github.com/{GH_REPO}/issues/{NUMBER}"
|
|
112
|
+
ITEM_ID=$(gh project item-list 1 --owner RapierCraft --format json --limit 200 \
|
|
113
|
+
--jq ".items[] | select(.content.url == \"$ISSUE_URL\") | .id" 2>/dev/null | head -1)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If `ITEM_ID` is found:
|
|
117
|
+
```bash
|
|
118
|
+
# Set Status=Done
|
|
119
|
+
gh project item-edit --project-id PVT_kwHOCx3gR84BSK2L --id "$ITEM_ID" \
|
|
120
|
+
--field-id PVTSSF_lAHOCx3gR84BSK2Lzg_yF6E --single-select-option-id 98236657 2>/dev/null || true # Status=Done
|
|
121
|
+
|
|
122
|
+
# Set Workflow=Merged
|
|
123
|
+
gh project item-edit --project-id PVT_kwHOCx3gR84BSK2L --id "$ITEM_ID" \
|
|
124
|
+
--field-id PVTSSF_lAHOCx3gR84BSK2Lzg_yGAA --single-select-option-id b510c537 2>/dev/null || true # Workflow=Merged
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If `ITEM_ID` is empty (issue not on project board) → log and skip:
|
|
128
|
+
```bash
|
|
129
|
+
echo "INFO: Issue #{NUMBER} not found on project board — skipping board update"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Field reference** (project `PVT_kwHOCx3gR84BSK2L`):
|
|
133
|
+
| Field | Field ID | Option | Option ID |
|
|
134
|
+
|-------|----------|--------|-----------|
|
|
135
|
+
| Status | `PVTSSF_lAHOCx3gR84BSK2Lzg_yF6E` | Done | `98236657` |
|
|
136
|
+
| Workflow | `PVTSSF_lAHOCx3gR84BSK2Lzg_yGAA` | Merged | `b510c537` |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Phase C2: Ensure Issue is Closed
|
|
141
|
+
|
|
142
|
+
**Multi-phase guard**: If `REMAINING_AFTER > 0` (set in Phase C1), uncompleted phases remain — do NOT close the issue. Instead, post a phase-complete comment and exit early so the router can pick up the next phase on the next pipeline iteration.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
ISSUE_STATE=$(gh issue view {NUMBER} {GH_FLAG} --json state --jq '.state')
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**If `REMAINING_AFTER > 0`** (multi-phase: uncompleted phases remain):
|
|
149
|
+
```bash
|
|
150
|
+
# Post phase-complete marker — router state 10 (MULTI_PHASE) will re-detect this issue
|
|
151
|
+
gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:PHASE:COMPLETE -->
|
|
152
|
+
Phase complete. PR #{PR_NUMBER} merged to \`{PR_BASE}\`. ${REMAINING_AFTER} phase item(s) remain — leaving issue open for next pipeline iteration."
|
|
153
|
+
|
|
154
|
+
# Update labels to reflect phase complete (not yet fully merged)
|
|
155
|
+
gh issue edit {NUMBER} {GH_FLAG} \
|
|
156
|
+
--remove-label "workflow:in-review,workflow:building,workflow:investigating" 2>/dev/null || true
|
|
157
|
+
|
|
158
|
+
# EXIT — do not close, do not post trajectory, do not run C3–C6
|
|
159
|
+
# Return CLOSE_RESULT: status: PHASE_COMPLETE to caller
|
|
160
|
+
exit 0
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**If `REMAINING_AFTER == 0`** (all phases complete — single-phase or final phase of multi-phase):
|
|
164
|
+
|
|
165
|
+
If state is `OPEN`:
|
|
166
|
+
```bash
|
|
167
|
+
gh issue close {NUMBER} {GH_FLAG} \
|
|
168
|
+
--comment "Closed: PR #{PR_NUMBER} merged to \`{PR_BASE}\`. Closes #{NUMBER}."
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Add merged label:
|
|
172
|
+
```bash
|
|
173
|
+
gh issue edit {NUMBER} {GH_FLAG} \
|
|
174
|
+
--add-label "workflow:merged" \
|
|
175
|
+
--remove-label "workflow:in-review,workflow:building,workflow:investigating" 2>/dev/null || true
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Phase C3: Parent Tracker Update (Sub-Issues Only)
|
|
181
|
+
|
|
182
|
+
**Skip if**: Issue body does NOT contain a parent issue reference (e.g. `Part of #NNN`) or the issue has no parent in its milestone tracker.
|
|
183
|
+
|
|
184
|
+
Detect parent reference:
|
|
185
|
+
```bash
|
|
186
|
+
PARENT_REF=$(gh issue view {NUMBER} {GH_FLAG} --json body --jq '.body' \
|
|
187
|
+
| grep -oP '(?i)(part of|spawned from|sub-issue of|parent issue[:]?|parent[:])\s*#\K\d+' \
|
|
188
|
+
| head -1)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
If no parent reference found → log a warning and skip this phase:
|
|
192
|
+
```bash
|
|
193
|
+
echo "WARNING: No parent reference found in issue body — skipping parent tracker update"
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
If parent found:
|
|
197
|
+
```bash
|
|
198
|
+
# Read parent body
|
|
199
|
+
PARENT_BODY=$(gh issue view {PARENT_REF} {GH_FLAG} --json body --jq '.body')
|
|
200
|
+
|
|
201
|
+
# Check off this sub-issue in parent body (replace "- [ ] #{NUMBER}" with "- [x] #{NUMBER}")
|
|
202
|
+
UPDATED_PARENT=$(echo "$PARENT_BODY" | sed "s/- \[ \] #${NUMBER}/- [x] #${NUMBER}/g")
|
|
203
|
+
gh issue edit {PARENT_REF} {GH_FLAG} --body "$UPDATED_PARENT"
|
|
204
|
+
|
|
205
|
+
# Check if all sub-issues are now closed
|
|
206
|
+
OPEN_SUBS=$(echo "$UPDATED_PARENT" | grep -c '\- \[ \]' || true)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If `OPEN_SUBS == 0` (all sub-issues checked off):
|
|
210
|
+
```bash
|
|
211
|
+
gh issue close {PARENT_REF} {GH_FLAG} \
|
|
212
|
+
--comment "All sub-issues complete. Closing parent tracker. Last completed: #{NUMBER} (PR #{PR_NUMBER})."
|
|
213
|
+
gh issue edit {PARENT_REF} {GH_FLAG} --add-label "workflow:merged"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Phase C4: Summary Report
|
|
219
|
+
|
|
220
|
+
Reconstruct the pipeline summary from GitHub state:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Get investigation verdict from FORGE:INVESTIGATOR comment (or legacy ALTERLAB:INVESTIGATOR)
|
|
224
|
+
VERDICT=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
225
|
+
--jq '.[] | select(.body | (contains("FORGE:INVESTIGATOR") or contains("ALTERLAB:INVESTIGATOR"))) | .body' \
|
|
226
|
+
| grep -oP '(?<=\*\*Verdict\*\*: )\w+' | head -1)
|
|
227
|
+
|
|
228
|
+
CONFIDENCE=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
229
|
+
--jq '.[] | select(.body | (contains("FORGE:INVESTIGATOR") or contains("ALTERLAB:INVESTIGATOR"))) | .body' \
|
|
230
|
+
| grep -oP '(?<=\*\*Confidence\*\*: )\w+' | head -1)
|
|
231
|
+
|
|
232
|
+
# Get files changed from FORGE:BUILDER comment (or legacy ALTERLAB:BUILDER)
|
|
233
|
+
FILES_CHANGED=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
234
|
+
--jq '.[] | select(.body | (contains("FORGE:BUILDER") or contains("ALTERLAB:BUILDER"))) | .body' \
|
|
235
|
+
| grep -oP '(?<=\*\*Files changed\*\*: )\d+' | head -1)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Output to stdout (returned to calling agent):
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
## Done: #{NUMBER} — {TITLE}
|
|
242
|
+
- Investigation: {VERDICT} ({CONFIDENCE})
|
|
243
|
+
- Lane: FEATURE
|
|
244
|
+
- Fix: {BRANCH} → PR #{PR_NUMBER} → merged to `{PR_BASE}`
|
|
245
|
+
- Files changed: {FILES_CHANGED}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Phase C5: Trajectory Log (MANDATORY)
|
|
251
|
+
|
|
252
|
+
Post the `<!-- FORGE:TRAJECTORY -->` comment as the final pipeline record:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:TRAJECTORY -->
|
|
256
|
+
## Pipeline Trajectory — #{NUMBER}
|
|
257
|
+
|
|
258
|
+
| Phase | Result | Notes |
|
|
259
|
+
|-------|--------|-------|
|
|
260
|
+
| Phase 0: Context Load | ✅ Complete | Feature lane → \`{PR_BASE}\` |
|
|
261
|
+
| Phase 1: Investigation | ✅ {VERDICT} ({CONFIDENCE}) | Task type: {TASK_TYPE} |
|
|
262
|
+
| Phase 2: Decomposition | ⏭ Skipped | Single-concern change, no decomposition needed |
|
|
263
|
+
| Phase 3: Build | ✅ Complete | Branch: \`{BRANCH}\` |
|
|
264
|
+
| Phase 3F.5: Validate | ✅ Gate passed | Quality gate: pass |
|
|
265
|
+
| Phase 4–5: Review + PR | ✅ Merged | PR #{PR_NUMBER} → \`{PR_BASE}\` |
|
|
266
|
+
| Phase 6: Parent Tracker | {PARENT_STATUS} | {PARENT_NOTES} |
|
|
267
|
+
| Phase C6: Cleanup | {CLEANUP_STATUS} | Worktree: {WORKTREE_PATH}, Branch: {BRANCH} |
|
|
268
|
+
| Phase 7: Close | ✅ Complete | Issue closed |
|
|
269
|
+
|
|
270
|
+
**Decisions**:
|
|
271
|
+
- Decomposition skipped: {DECOMPOSE_REASON}
|
|
272
|
+
- PR merged to: \`{PR_BASE}\` (feature lane, milestone branch)
|
|
273
|
+
|
|
274
|
+
**Anomalies**: None
|
|
275
|
+
|
|
276
|
+
**Pipeline completed**: {TIMESTAMP}"
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Where:
|
|
280
|
+
- `{PARENT_STATUS}` = `⏭ Skipped` (if no parent) or `✅ Complete` (if parent updated)
|
|
281
|
+
- `{PARENT_NOTES}` = `No parent tracker` or `Checked off in #{PARENT_REF}`
|
|
282
|
+
- `{CLEANUP_STATUS}` = `✅ Removed` (worktree removed + branch deleted) or `⏭ Skipped` (no path provided or path not found)
|
|
283
|
+
- `{TIMESTAMP}` = current date/time in ISO format
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Phase C6: Worktree & Branch Cleanup
|
|
288
|
+
|
|
289
|
+
Remove the git worktree and delete the local feature branch after the PR has merged. This prevents worktree accumulation across pipeline runs.
|
|
290
|
+
|
|
291
|
+
**Skip if**: `{WORKTREE_PATH}` is not provided OR the path does not exist.
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# Remove worktree (--force handles detached or uncommitted state)
|
|
295
|
+
if [ -n "{WORKTREE_PATH}" ] && [ -d "{WORKTREE_PATH}" ]; then
|
|
296
|
+
# Use --git-common-dir to correctly resolve REPO_ROOT for linked worktrees.
|
|
297
|
+
# --show-toplevel returns the worktree path itself (not the main repo root),
|
|
298
|
+
# so xargs dirname would give the worktree's parent dir — not the repo root.
|
|
299
|
+
# --git-common-dir returns the shared .git dir (e.g. /repo/.git), and
|
|
300
|
+
# dirname of that is always the main repo root regardless of worktree depth.
|
|
301
|
+
GIT_COMMON=$(git -C {WORKTREE_PATH} rev-parse --git-common-dir 2>/dev/null)
|
|
302
|
+
REPO_ROOT=$(dirname "$(realpath "$GIT_COMMON" 2>/dev/null || echo "$GIT_COMMON")")
|
|
303
|
+
git -C "$REPO_ROOT" worktree remove {WORKTREE_PATH} --force 2>/dev/null || true
|
|
304
|
+
echo "Worktree removed: {WORKTREE_PATH}"
|
|
305
|
+
|
|
306
|
+
# Delete local feature branch (remote branch already deleted by GitHub on merge)
|
|
307
|
+
if [ -n "{BRANCH}" ]; then
|
|
308
|
+
git -C "$REPO_ROOT" branch -D {BRANCH} 2>/dev/null || true
|
|
309
|
+
echo "Local branch deleted: {BRANCH}"
|
|
310
|
+
fi
|
|
311
|
+
else
|
|
312
|
+
echo "Worktree cleanup skipped: path not provided or does not exist"
|
|
313
|
+
fi
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Set `{CLEANUP_STATUS}` based on outcome:
|
|
317
|
+
- Worktree path provided and existed → `✅ Removed` (worktree removed, branch deleted)
|
|
318
|
+
- Worktree path not provided or path didn't exist → `⏭ Skipped`
|
|
319
|
+
|
|
320
|
+
Update the trajectory log `{CLEANUP_STATUS}` field accordingly (the trajectory was already posted in C5, so this is recorded in the output summary, not by re-editing the comment).
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Output
|
|
325
|
+
|
|
326
|
+
Return structured output to the caller:
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
CLOSE_RESULT:
|
|
330
|
+
status: COMPLETE | ALREADY_DONE | PHASE_COMPLETE
|
|
331
|
+
issue_state: closed | open
|
|
332
|
+
trajectory_url: {url of FORGE:TRAJECTORY comment}
|
|
333
|
+
parent_updated: {true|false}
|
|
334
|
+
parent_closed: {true|false}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Where `PHASE_COMPLETE` means the current phase was closed but uncompleted phases remain — the issue is left OPEN for the router to re-evaluate on the next pipeline iteration (state 10, MULTI_PHASE).
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Integration Point in work-on.md
|
|
342
|
+
|
|
343
|
+
This module runs at **Phases 6–7** — after review.md returns `REVIEW_RESULT: status: COMPLETE`:
|
|
344
|
+
|
|
345
|
+
```
|
|
346
|
+
4–5 → Review (by review.md) — PR created, reviewed, merged, issue closed
|
|
347
|
+
6–7 → [THIS MODULE] Final body update, parent tracker, summary, trajectory
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
This is the terminal phase — after CLOSE_RESULT returns, the pipeline is complete.
|