forgedock 1.0.1 → 1.0.2
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 +19 -2
- package/bin/forgedock.mjs +286 -10
- package/commands/analytics.md +129 -52
- package/commands/audit-agents.md +29 -5
- package/commands/audit.md +55 -17
- package/commands/autopilot.md +11 -6
- package/commands/cleanup.md +44 -24
- package/commands/deploy-info.md +7 -3
- package/commands/forge-stats.md +13 -4
- package/commands/forgedock-init.md +534 -0
- package/commands/geo-audit.md +114 -26
- package/commands/incident-response.md +4 -1
- package/commands/issue.md +26 -25
- package/commands/milestone.md +80 -59
- package/commands/orchestrate.md +38 -21
- package/commands/pipeline-health.md +26 -15
- package/commands/qa-sweep.md +68 -5
- package/commands/quality-gate.md +18 -0
- package/commands/review-pr-agents.md +58 -90
- package/commands/review-pr.md +58 -16
- package/commands/rollback.md +8 -5
- package/commands/security-audit.md +68 -12
- package/commands/sync-ecosystem.md +196 -156
- package/commands/work-on/build/architect.md +2 -2
- package/commands/work-on/build/context.md +2 -2
- package/commands/work-on/build/implement.md +3 -3
- package/commands/work-on/build/validate.md +3 -3
- package/commands/work-on/build.md +6 -6
- package/commands/work-on/close.md +59 -30
- package/commands/work-on/decompose.md +6 -6
- package/commands/work-on/investigate.md +16 -20
- package/commands/work-on/review.md +4 -4
- package/commands/work-on-monolithic.md +15 -16
- package/commands/work-on.md +45 -33
- package/docs/CODEX.md +1 -1
- package/docs/CONFIG.md +398 -0
- package/docs/WORKFLOW.md +115 -72
- package/package.json +1 -1
- package/scripts/verify-host-headers.sh +14 -9
- package/scripts/verify-route-registration.sh +10 -10
- package/commands/failure-recon.md +0 -375
|
@@ -19,8 +19,8 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--worktree P
|
|
|
19
19
|
|
|
20
20
|
Parse from $ARGUMENTS:
|
|
21
21
|
- `{NUMBER}` — issue number (required)
|
|
22
|
-
- `--repo {GH_REPO}` — GitHub repo (e.g. `
|
|
23
|
-
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R
|
|
22
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `{owner}/{repo}` — resolved from `forge.yaml → project`)
|
|
23
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R {owner}/{repo}`)
|
|
24
24
|
- `--worktree {WORKTREE_PATH}` — absolute path to the git worktree (set by caller)
|
|
25
25
|
- `--branch {BRANCH}` — feature branch name (e.g. `feat/my-feature`)
|
|
26
26
|
|
|
@@ -145,7 +145,7 @@ if [ -n "$NEW_ENV_VARS" ]; then
|
|
|
145
145
|
fi
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
-
**If any MISSING line is printed**: add the var to the missing location before proceeding to Phase I4. If
|
|
148
|
+
**If any MISSING line is printed**: add the var to the missing location before proceeding to Phase I4. If a file listed above doesn't exist in this repo (e.g. `ENV_VARS.md` or `env_validation.py` may not be present in all projects), skip that check silently.
|
|
149
149
|
|
|
150
150
|
### Check 2 — Deploy/infra restart risk
|
|
151
151
|
|
|
@@ -19,8 +19,8 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--worktree P
|
|
|
19
19
|
|
|
20
20
|
Parse from $ARGUMENTS:
|
|
21
21
|
- `{NUMBER}` — issue number (required)
|
|
22
|
-
- `--repo {GH_REPO}` — GitHub repo (e.g. `
|
|
23
|
-
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R
|
|
22
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `{owner}/{repo}` — resolved from `forge.yaml → project`)
|
|
23
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R {owner}/{repo}`)
|
|
24
24
|
- `--worktree {WORKTREE_PATH}` — absolute path to the git worktree
|
|
25
25
|
- `--files {CHANGED_FILES}` — space-separated list of changed files (from implement result)
|
|
26
26
|
|
|
@@ -99,7 +99,7 @@ python -m py_compile {PYTHON_FILES}
|
|
|
99
99
|
```
|
|
100
100
|
Failures in `py_compile` are BLOCKING — fix before continuing.
|
|
101
101
|
|
|
102
|
-
**TypeScript (
|
|
102
|
+
**TypeScript (tsc)**:
|
|
103
103
|
```bash
|
|
104
104
|
cd {WORKTREE_PATH}
|
|
105
105
|
prettier --write {TS_FILES}
|
|
@@ -21,8 +21,8 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--base PR_BA
|
|
|
21
21
|
|
|
22
22
|
Parse from $ARGUMENTS:
|
|
23
23
|
- `{NUMBER}` — issue number (required)
|
|
24
|
-
- `--repo {GH_REPO}` — GitHub repo (e.g. `
|
|
25
|
-
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R
|
|
24
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `{owner}/{repo}` — resolved from `forge.yaml → project`)
|
|
25
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R {owner}/{repo}`)
|
|
26
26
|
- `--base {PR_BASE}` — PR target branch (e.g. `milestone/modular-pipeline-architecture` or `staging`)
|
|
27
27
|
|
|
28
28
|
---
|
|
@@ -36,16 +36,16 @@ gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
|
|
|
36
36
|
|
|
37
37
|
# Check investigation report
|
|
38
38
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
39
|
-
--jq '.[] | select(.body |
|
|
39
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body'
|
|
40
40
|
|
|
41
41
|
# Check if build already completed
|
|
42
42
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
43
|
-
--jq '.[] | select(.body |
|
|
43
|
+
--jq '.[] | select(.body | contains("FORGE:BUILDER")) | .body'
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
**Resume check**:
|
|
47
|
-
- If `<!-- FORGE:BUILDER -->`
|
|
48
|
-
- If no `<!-- FORGE:INVESTIGATOR -->`
|
|
47
|
+
- If `<!-- FORGE:BUILDER -->` comment exists → build already complete. Return `BUILD_RESULT: status: ALREADY_DONE` to router.
|
|
48
|
+
- If no `<!-- FORGE:INVESTIGATOR -->` comment with `<!-- INVESTIGATION:COMPLETE -->` → EXIT with `BUILD_RESULT: status: BLOCKED`, blocker: "Investigation not complete — run investigate first".
|
|
49
49
|
|
|
50
50
|
Extract from investigation report:
|
|
51
51
|
- Affected files list
|
|
@@ -19,8 +19,8 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--pr PR_NUMB
|
|
|
19
19
|
|
|
20
20
|
Parse from $ARGUMENTS:
|
|
21
21
|
- `{NUMBER}` — issue number (required)
|
|
22
|
-
- `--repo {GH_REPO}` — GitHub repo (e.g. `
|
|
23
|
-
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R
|
|
22
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `{owner}/{repo}` — resolved from `forge.yaml → project`)
|
|
23
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R {owner}/{repo}`)
|
|
24
24
|
- `--pr {PR_NUMBER}` — merged PR number
|
|
25
25
|
- `--base {PR_BASE}` — branch the PR merged into (e.g. `milestone/modular-pipeline-architecture`)
|
|
26
26
|
- `--branch {BRANCH}` — feature branch name (for worktree cleanup reference)
|
|
@@ -106,34 +106,63 @@ The `REMAINING_AFTER` variable is passed to Phase C2 to decide whether to close.
|
|
|
106
106
|
|
|
107
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
108
|
|
|
109
|
-
|
|
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
|
-
```
|
|
109
|
+
**Read project board config from `forge.yaml`**. If the `project_board` section is absent or commented out, skip this phase entirely:
|
|
115
110
|
|
|
116
|
-
If `ITEM_ID` is found:
|
|
117
111
|
```bash
|
|
118
|
-
#
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
112
|
+
# Read project board config from forge.yaml
|
|
113
|
+
PROJECT_BOARD_OWNER=$(yq '.project_board.owner // ""' forge.yaml 2>/dev/null || echo "")
|
|
114
|
+
PROJECT_ID=$(yq '.project_board.project_id // ""' forge.yaml 2>/dev/null || echo "")
|
|
115
|
+
PROJECT_NUMBER=$(yq '.project_board.project_number // ""' forge.yaml 2>/dev/null || echo "")
|
|
116
|
+
STATUS_FIELD_ID=$(yq '.project_board.field_ids.status // ""' forge.yaml 2>/dev/null || echo "")
|
|
117
|
+
WORKFLOW_FIELD_ID=$(yq '.project_board.field_ids.workflow // ""' forge.yaml 2>/dev/null || echo "")
|
|
118
|
+
STATUS_DONE_OPTION_ID=$(yq '.project_board.option_ids.status.done // ""' forge.yaml 2>/dev/null || echo "")
|
|
119
|
+
WORKFLOW_MERGED_OPTION_ID=$(yq '.project_board.option_ids.workflow.merged // ""' forge.yaml 2>/dev/null || echo "")
|
|
120
|
+
|
|
121
|
+
if [ -z "$PROJECT_BOARD_OWNER" ] || [ -z "$PROJECT_ID" ] || [ -z "$STATUS_FIELD_ID" ]; then
|
|
122
|
+
echo "INFO: project_board not configured in forge.yaml — skipping board update"
|
|
123
|
+
# → STOP: do not proceed to ITEM_ID fetch or board update — continue to Phase C2
|
|
124
|
+
else
|
|
125
|
+
# Project board is configured — find the item and update it
|
|
126
|
+
|
|
127
|
+
# Find the project item ID for this issue
|
|
128
|
+
ISSUE_URL="https://github.com/{GH_REPO}/issues/{NUMBER}"
|
|
129
|
+
ITEM_ID=$(gh project item-list "$PROJECT_NUMBER" --owner "$PROJECT_BOARD_OWNER" --format json --limit 200 \
|
|
130
|
+
--jq ".items[] | select(.content.url == \"$ISSUE_URL\") | .id" 2>/dev/null | head -1)
|
|
131
|
+
|
|
132
|
+
if [ -n "$ITEM_ID" ]; then
|
|
133
|
+
# Set Status=Done
|
|
134
|
+
if [ -n "$STATUS_FIELD_ID" ] && [ -n "$STATUS_DONE_OPTION_ID" ]; then
|
|
135
|
+
gh project item-edit --project-id "$PROJECT_ID" --id "$ITEM_ID" \
|
|
136
|
+
--field-id "$STATUS_FIELD_ID" --single-select-option-id "$STATUS_DONE_OPTION_ID" 2>/dev/null || true
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# Set Workflow=Merged
|
|
140
|
+
if [ -n "$WORKFLOW_FIELD_ID" ] && [ -n "$WORKFLOW_MERGED_OPTION_ID" ]; then
|
|
141
|
+
gh project item-edit --project-id "$PROJECT_ID" --id "$ITEM_ID" \
|
|
142
|
+
--field-id "$WORKFLOW_FIELD_ID" --single-select-option-id "$WORKFLOW_MERGED_OPTION_ID" 2>/dev/null || true
|
|
143
|
+
fi
|
|
144
|
+
else
|
|
145
|
+
echo "INFO: Issue #{NUMBER} not found on project board — skipping board update"
|
|
146
|
+
fi
|
|
147
|
+
fi
|
|
125
148
|
```
|
|
126
149
|
|
|
127
|
-
|
|
128
|
-
```
|
|
129
|
-
|
|
150
|
+
**Project board field IDs are read from `forge.yaml → project_board`**. To configure:
|
|
151
|
+
```yaml
|
|
152
|
+
project_board:
|
|
153
|
+
owner: "{your-github-org}"
|
|
154
|
+
project_number: 1
|
|
155
|
+
project_id: "PVT_kwHO..."
|
|
156
|
+
field_ids:
|
|
157
|
+
status: "PVTSSF_..."
|
|
158
|
+
workflow: "PVTSSF_..."
|
|
159
|
+
option_ids:
|
|
160
|
+
status:
|
|
161
|
+
done: "..."
|
|
162
|
+
workflow:
|
|
163
|
+
merged: "..."
|
|
130
164
|
```
|
|
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` |
|
|
165
|
+
To find your project IDs: `gh project list --owner {owner}` and `gh project field-list {number} --owner {owner}`.
|
|
137
166
|
|
|
138
167
|
---
|
|
139
168
|
|
|
@@ -220,18 +249,18 @@ gh issue edit {PARENT_REF} {GH_FLAG} --add-label "workflow:merged"
|
|
|
220
249
|
Reconstruct the pipeline summary from GitHub state:
|
|
221
250
|
|
|
222
251
|
```bash
|
|
223
|
-
# Get investigation verdict from FORGE:INVESTIGATOR comment
|
|
252
|
+
# Get investigation verdict from FORGE:INVESTIGATOR comment
|
|
224
253
|
VERDICT=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
225
|
-
--jq '.[] | select(.body |
|
|
254
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body' \
|
|
226
255
|
| grep -oP '(?<=\*\*Verdict\*\*: )\w+' | head -1)
|
|
227
256
|
|
|
228
257
|
CONFIDENCE=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
229
|
-
--jq '.[] | select(.body |
|
|
258
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body' \
|
|
230
259
|
| grep -oP '(?<=\*\*Confidence\*\*: )\w+' | head -1)
|
|
231
260
|
|
|
232
|
-
# Get files changed from FORGE:BUILDER comment
|
|
261
|
+
# Get files changed from FORGE:BUILDER comment
|
|
233
262
|
FILES_CHANGED=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
234
|
-
--jq '.[] | select(.body |
|
|
263
|
+
--jq '.[] | select(.body | contains("FORGE:BUILDER")) | .body' \
|
|
235
264
|
| grep -oP '(?<=\*\*Files changed\*\*: )\d+' | head -1)
|
|
236
265
|
```
|
|
237
266
|
|
|
@@ -19,8 +19,8 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG]
|
|
|
19
19
|
|
|
20
20
|
Parse from $ARGUMENTS:
|
|
21
21
|
- `{NUMBER}` — issue number (required)
|
|
22
|
-
- `--repo {GH_REPO}` — GitHub repo (e.g. `
|
|
23
|
-
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R
|
|
22
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `{owner}/{repo}` — resolved from `forge.yaml → project`)
|
|
23
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R {owner}/{repo}`)
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
@@ -33,11 +33,11 @@ gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
|
|
|
33
33
|
|
|
34
34
|
# Read investigation report (required — contains decomposition plan)
|
|
35
35
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
36
|
-
--jq '.[] | select(.body |
|
|
36
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body'
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
**Validation**:
|
|
40
|
-
- If FORGE:INVESTIGATOR
|
|
40
|
+
- If FORGE:INVESTIGATOR comment is absent → EXIT with `DECOMPOSE_RESULT: status: BLOCKED`, blocker: "No investigation report found — run investigate first"
|
|
41
41
|
- If investigation report has no Decomposition Assessment section, OR the assessment does not list any sub-issues → EXIT with `DECOMPOSE_RESULT: status: BLOCKED`, blocker: "Investigation report has no decomposition plan — re-run investigate with explicit decomposition scope"
|
|
42
42
|
|
|
43
43
|
Extract from investigation report:
|
|
@@ -56,10 +56,10 @@ MILESTONE_TITLE=$(gh issue view {NUMBER} {GH_FLAG} --json milestone --jq '.miles
|
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
58
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
59
|
-
--jq '.[] | select(.body |
|
|
59
|
+
--jq '.[] | select(.body | contains("FORGE:DECOMPOSED")) | .body'
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
- If `<!-- FORGE:DECOMPOSED -->`
|
|
62
|
+
- If `<!-- FORGE:DECOMPOSED -->` comment exists → decomposition already complete. EXIT with `DECOMPOSE_RESULT: status: ALREADY_DONE`.
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Investigate a GitHub issue — validate it's real, determine root cause, post findings
|
|
3
|
-
argument-hint: [issue number] [--repo
|
|
3
|
+
argument-hint: [issue number] [--repo {owner}/{repo}] [--gh-flag "-R {owner}/{repo}"]
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /work-on:investigate — Issue Investigation Subcommand
|
|
@@ -18,10 +18,10 @@ Standalone investigation phase for the work-on pipeline. Validates whether an is
|
|
|
18
18
|
|
|
19
19
|
Parse from $ARGUMENTS:
|
|
20
20
|
- `{NUMBER}` — issue number (required)
|
|
21
|
-
- `--repo {GH_REPO}` — GitHub repo (
|
|
22
|
-
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R
|
|
21
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `{owner}/{repo}` — resolved from `forge.yaml → project`)
|
|
22
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R {owner}/{repo}`)
|
|
23
23
|
|
|
24
|
-
If called from `work-on`, these are passed through. If invoked standalone,
|
|
24
|
+
If called from `work-on`, these are passed through. If invoked standalone, `--repo` and `--gh-flag` are resolved from `forge.yaml → project`.
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
@@ -33,8 +33,8 @@ gh api repos/{GH_REPO}/issues/{NUMBER}/comments --jq '.[] | {id: .id, body: .bod
|
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
**Resume logic**:
|
|
36
|
-
- If `<!-- FORGE:INVESTIGATOR -->`
|
|
37
|
-
- If `<!-- FORGE:INVESTIGATOR -->`
|
|
36
|
+
- If `<!-- FORGE:INVESTIGATOR -->` comment exists AND `<!-- INVESTIGATION:COMPLETE -->` is present in the SAME comment → investigation already complete, EXIT (return existing verdict to caller)
|
|
37
|
+
- If `<!-- FORGE:INVESTIGATOR -->` comment exists BUT `<!-- INVESTIGATION:COMPLETE -->` is ABSENT → investigation was interrupted, delete the partial comment and restart:
|
|
38
38
|
```bash
|
|
39
39
|
gh api repos/{GH_REPO}/issues/comments/{COMMENT_ID} -X DELETE
|
|
40
40
|
```
|
|
@@ -54,20 +54,16 @@ gh issue edit {NUMBER} {GH_FLAG} --remove-label "workflow:ready-to-build,workflo
|
|
|
54
54
|
|
|
55
55
|
### Resolve target repo and branch
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
- Key files: `commands/work-on.md`, `commands/review-pr.md`, `commands/quality-gate.md`, `commands/orchestrate.md`, `install.sh`, `CLAUDE.md`
|
|
57
|
+
The target repo is `{GH_REPO}` (resolved from `forge.yaml → project`). The working directory is `{REPO_PATH}` (resolved from `forge.yaml → paths.root`).
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
**Domain-to-files mapping**: The repo's domain structure depends on the project. Before investigating, read the issue body and labels to identify the affected domain. Then look at the repo's directory structure under `{REPO_PATH}` to locate relevant files. Common entry points:
|
|
60
|
+
- Command/prompt files: `commands/`, `.claude/commands/`
|
|
61
|
+
- Backend services: any `services/`, `routers/`, `core/` directories
|
|
62
|
+
- Frontend: any `web/`, `frontend/`, `src/` directories
|
|
63
|
+
- Infrastructure: `.github/workflows/`, `docker-compose*.yml`, `infra/`
|
|
64
|
+
- Config: `forge.yaml`, `.env.example`, any `config/` directory
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|--------|-----------|
|
|
64
|
-
| BILLING | `routers/billing.py`, `core/pricing.py`, `services/credit_service.py` |
|
|
65
|
-
| SCRAPING | `unified_consumer.py`, `queues.py`, `domain_playbooks.json` |
|
|
66
|
-
| AUTH | `core/auth.py`, `routers/auth.py`, `dependencies.py` |
|
|
67
|
-
| DATABASE | `infra/migrations/`, `models/`, `db/` |
|
|
68
|
-
| FRONTEND | `web/src/app/`, `web/src/components/`, `web/src/lib/` |
|
|
69
|
-
| CORTEX | `cortex_client.py`, `routers/cortex.py` |
|
|
70
|
-
| INFRA | `.github/workflows/`, `docker-compose.yml`, `infra/traefik/` |
|
|
66
|
+
If the issue specifies a **Code branch** (`**Code branch**: \`{branch}\``), check out that branch — the affected files may not be on the default branch.
|
|
71
67
|
|
|
72
68
|
### Investigation steps
|
|
73
69
|
|
|
@@ -154,7 +150,7 @@ fi
|
|
|
154
150
|
|
|
155
151
|
```bash
|
|
156
152
|
INVESTIGATION_BODY=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
157
|
-
--jq '.[] | select(.body |
|
|
153
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body' | head -1)
|
|
158
154
|
```
|
|
159
155
|
|
|
160
156
|
### Step 3: Generate filename and metadata
|
|
@@ -166,7 +162,7 @@ MILESTONE=$(gh issue view {NUMBER} {GH_FLAG} --json milestone --jq '.milestone.t
|
|
|
166
162
|
# Generate slug from title: lowercase, replace non-alphanumeric with hyphens, collapse, truncate
|
|
167
163
|
SLUG=$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-40)
|
|
168
164
|
|
|
169
|
-
# Derive repo short name from GH_REPO (e.g., "
|
|
165
|
+
# Derive repo short name from GH_REPO (e.g., "acme-org/acme-platform" → "acme-platform")
|
|
170
166
|
REPO_SHORT=$(echo "{GH_REPO}" | sed 's|.*/||')
|
|
171
167
|
|
|
172
168
|
GIST_FILENAME="${REPO_SHORT}_${NUMBER}_${SLUG}.md"
|
|
@@ -19,8 +19,8 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--worktree P
|
|
|
19
19
|
|
|
20
20
|
Parse from $ARGUMENTS:
|
|
21
21
|
- `{NUMBER}` — issue number (required)
|
|
22
|
-
- `--repo {GH_REPO}` — GitHub repo (e.g. `
|
|
23
|
-
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R
|
|
22
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `{owner}/{repo}` — resolved from `forge.yaml → project`)
|
|
23
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R {owner}/{repo}`)
|
|
24
24
|
- `--worktree {WORKTREE_PATH}` — absolute path to the git worktree
|
|
25
25
|
- `--branch {BRANCH}` — feature branch name (e.g. `feat/my-feature`)
|
|
26
26
|
- `--base {PR_BASE}` — PR target branch (e.g. `milestone/modular-pipeline-architecture` or `staging`)
|
|
@@ -36,7 +36,7 @@ gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
|
|
|
36
36
|
|
|
37
37
|
# Get builder comment (for branch + commit info)
|
|
38
38
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
39
|
-
--jq '.[] | select(.body |
|
|
39
|
+
--jq '.[] | select(.body | contains("FORGE:BUILDER")) | .body'
|
|
40
40
|
|
|
41
41
|
# Check if PR already exists for this branch
|
|
42
42
|
gh pr list {GH_FLAG} --head {BRANCH} --json number,state,url 2>/dev/null
|
|
@@ -45,7 +45,7 @@ gh pr list {GH_FLAG} --head {BRANCH} --json number,state,url 2>/dev/null
|
|
|
45
45
|
**Resume check**:
|
|
46
46
|
- If PR already exists AND is OPEN → skip to Phase R3 (invoke /review-pr)
|
|
47
47
|
- If PR already exists AND is MERGED → return `REVIEW_RESULT: status: ALREADY_MERGED`
|
|
48
|
-
- If no `<!-- FORGE:BUILDER -->`
|
|
48
|
+
- If no `<!-- FORGE:BUILDER -->` comment exists → EXIT with `REVIEW_RESULT: status: BLOCKED`, blocker: "FORGE:BUILDER comment not found — implement phase may not have completed"
|
|
49
49
|
|
|
50
50
|
---
|
|
51
51
|
|
|
@@ -29,24 +29,23 @@ Orchestrator for the full issue lifecycle: investigate → build → review →
|
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## Project Configuration
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|-------|-------------|
|
|
36
|
-
| `123` / `#123` | AlterLab (default): `RapierCraftStudios/AlterLab` |
|
|
37
|
-
| `mcp:5` | MCP Server: `RapierCraftStudios/alterlab-mcp-server` |
|
|
38
|
-
| `n8n:12` | n8n Node: `RapierCraftStudios/n8n-nodes-alterlab` |
|
|
34
|
+
Read `forge.yaml` from the repository root. If missing, tell the user to run `npx forgedock init` and stop.
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
Resolve the following variables from `forge.yaml` before running any pipeline phase:
|
|
41
37
|
|
|
42
|
-
| Variable |
|
|
43
|
-
|
|
44
|
-
| `GH_REPO` | `
|
|
45
|
-
| `REPO_PATH` |
|
|
46
|
-
| `STAGING_BRANCH` | `staging` |
|
|
47
|
-
| `
|
|
38
|
+
| Variable | Source in forge.yaml | Description |
|
|
39
|
+
|----------|----------------------|-------------|
|
|
40
|
+
| `GH_REPO` | `project.owner` + `project.repo` | Full GitHub repo identifier (`owner/repo`) |
|
|
41
|
+
| `REPO_PATH` | `paths.root` | Absolute path to the local repository |
|
|
42
|
+
| `STAGING_BRANCH` | `branches.staging` | Branch for fast-lane PRs (no milestone) |
|
|
43
|
+
| `WORKTREE_BASE` | `paths.worktree_base` | Directory where git worktrees are created |
|
|
44
|
+
| `GH_FLAG` | _(empty for default repo; `-R owner/repo` for satellites)_ | Extra flag for `gh` CLI satellite repo calls |
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
**Multi-repo routing** (optional): If `forge.yaml` contains a `repos.satellites` list, build the prefix routing table from it. Each satellite entry has `prefix`, `repo`, `staging_branch`, and `local_path`. Issues without a prefix route to the default `GH_REPO`. Satellite repos have no staging — their fast-lane PRs go to their configured `staging_branch` (typically `main`).
|
|
47
|
+
|
|
48
|
+
If no `repos.satellites` section exists, only the primary repo is available — all issues route to `GH_REPO`.
|
|
50
49
|
|
|
51
50
|
---
|
|
52
51
|
|
|
@@ -189,7 +188,7 @@ Branch slug from title (lowercase, hyphenated, max 40 chars). Prefix: `fix/` (bu
|
|
|
189
188
|
cd {REPO_PATH}
|
|
190
189
|
git fetch origin
|
|
191
190
|
BRANCH="fix/{slug}-{NUMBER}"
|
|
192
|
-
git worktree add
|
|
191
|
+
git worktree add {WORKTREE_BASE}/{BRANCH} -b {BRANCH} origin/{PR_BASE}
|
|
193
192
|
```
|
|
194
193
|
|
|
195
194
|
### 3F: Implement
|
|
@@ -204,7 +203,7 @@ Fix HIGH/MEDIUM findings. Max 2 iterations. Skip for 1-file config/docs edits.
|
|
|
204
203
|
|
|
205
204
|
### 3G: Format and verify
|
|
206
205
|
- Python: `black` + `isort` + `py_compile`
|
|
207
|
-
- TypeScript (
|
|
206
|
+
- TypeScript (primary repo): `prettier --write` + `tsc --noEmit` (BLOCKING if fails)
|
|
208
207
|
- TypeScript (satellite): `npm run build` + `prettier --write`
|
|
209
208
|
|
|
210
209
|
### 3H: Frontend proxy wiring check (MANDATORY)
|
package/commands/work-on.md
CHANGED
|
@@ -62,15 +62,31 @@ Orchestrator for the full issue lifecycle: investigate → decompose (if needed)
|
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
65
|
-
##
|
|
65
|
+
## Project Configuration
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|-------|-------------|---------|----------------|
|
|
69
|
-
| `123` / `#123` | AlterLab (default) | `RapierCraft/AlterLab` | `staging` |
|
|
70
|
-
| `mcp:5` | MCP Server | `RapierCraft/alterlab-mcp-server` | `main` |
|
|
71
|
-
| `n8n:12` | n8n Node | `RapierCraft/n8n-nodes-alterlab` | `main` |
|
|
67
|
+
Read `forge.yaml` from the repository root before processing any issue.
|
|
72
68
|
|
|
73
|
-
|
|
69
|
+
If `forge.yaml` is missing: stop and tell the user to run `npx forgedock init` to generate it.
|
|
70
|
+
|
|
71
|
+
**Resolve these values from `forge.yaml`**:
|
|
72
|
+
|
|
73
|
+
| Variable | Source field | Notes |
|
|
74
|
+
|----------|-------------|-------|
|
|
75
|
+
| `GH_REPO` | `project.owner` + `/` + `project.repo` | e.g. `acme-org/acme-platform` |
|
|
76
|
+
| `GH_FLAG` | `-R {GH_REPO}` | Passed to all `gh` commands |
|
|
77
|
+
| `REPO_PATH` | `paths.root` | Absolute path to repo root |
|
|
78
|
+
| `WORKTREE_BASE` | `paths.worktree_base` | Base dir for git worktrees |
|
|
79
|
+
| `STAGING_BRANCH` | `branches.staging` | Fast-lane PR target |
|
|
80
|
+
| `PROJECT_BOARD_OWNER` | `project_board.owner` (or `project.owner` as fallback) | For `gh project` commands |
|
|
81
|
+
| `PROJECT_BOARD_NUMBER` | `project_board.project_number` (or `1` as fallback) | Project number in `gh project` commands |
|
|
82
|
+
|
|
83
|
+
**Multi-repo routing** (when `forge.yaml → repos` section is present):
|
|
84
|
+
|
|
85
|
+
Parse issue input for a prefix (`<prefix>:<number>`). Look up `<prefix>` in `forge.yaml → repos.satellites[]`. Use that satellite's `repo` and `staging_branch` as `GH_REPO` and `STAGING_BRANCH`. If no prefix is given, use the default (`project.owner/project.repo`).
|
|
86
|
+
|
|
87
|
+
If `forge.yaml → repos` is absent, only the default repo is available — prefixed issue numbers are invalid.
|
|
88
|
+
|
|
89
|
+
Satellite repos (those without a `staging` branch) receive fast-lane PRs directly to `main`.
|
|
74
90
|
|
|
75
91
|
---
|
|
76
92
|
|
|
@@ -100,12 +116,12 @@ Add issue to project, set Status=In Progress, Lane, Component, Priority, Workflo
|
|
|
100
116
|
|
|
101
117
|
## Phase 1: Investigation
|
|
102
118
|
|
|
103
|
-
**Skip if**: `<!-- FORGE:INVESTIGATOR -->`
|
|
119
|
+
**Skip if**: `<!-- FORGE:INVESTIGATOR -->` exists with `<!-- INVESTIGATION:COMPLETE -->` in the SAME comment.
|
|
104
120
|
|
|
105
121
|
**Partial investigation**: If investigator comment exists BUT `<!-- INVESTIGATION:COMPLETE -->` is ABSENT → investigation was interrupted. Delete the partial comment and restart:
|
|
106
122
|
```bash
|
|
107
123
|
COMMENT_ID=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
108
|
-
--jq '.[] | select(.body |
|
|
124
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .id')
|
|
109
125
|
gh api repos/{GH_REPO}/issues/comments/$COMMENT_ID -X DELETE
|
|
110
126
|
```
|
|
111
127
|
|
|
@@ -171,20 +187,14 @@ Mission: Validate whether the issue is real. Assume description is wrong until p
|
|
|
171
187
|
|
|
172
188
|
**Resolve target repo and branch**:
|
|
173
189
|
|
|
174
|
-
|
|
175
|
-
|
|
190
|
+
Read `forge.yaml → review.tech_stack` and `forge.yaml → review.key_paths` (if present) to identify which files are most relevant for the affected domain. If the `review` section is absent, use the issue labels, title keywords, and the affected files listed in the issue body to determine the domain. Start with the files the issue explicitly names, then expand to callers and related modules.
|
|
191
|
+
|
|
192
|
+
**Workflow pipeline issues** (repo is a ForgeDock installation):
|
|
193
|
+
- Key files: `commands/work-on.md`, `commands/review-pr.md`, `commands/quality-gate.md`, `commands/orchestrate.md`, `forge.yaml`, `bin/forgedock.mjs`
|
|
176
194
|
|
|
177
|
-
|
|
195
|
+
**Application issues** (all other repos):
|
|
178
196
|
|
|
179
|
-
|
|
180
|
-
|--------|-----------|
|
|
181
|
-
| BILLING | `routers/billing.py`, `core/pricing.py`, `services/credit_service.py` |
|
|
182
|
-
| SCRAPING | `unified_consumer.py`, `queues.py`, `domain_playbooks.json` |
|
|
183
|
-
| AUTH | `core/auth.py`, `routers/auth.py`, `dependencies.py` |
|
|
184
|
-
| DATABASE | `infra/migrations/`, `models/`, `db/` |
|
|
185
|
-
| FRONTEND | `web/src/app/`, `web/src/components/`, `web/src/lib/` |
|
|
186
|
-
| CORTEX | `cortex_client.py`, `routers/cortex.py` |
|
|
187
|
-
| INFRA | `.github/workflows/`, `docker-compose.yml`, `infra/traefik/` |
|
|
197
|
+
Use `forge.yaml → review.tech_stack` and the issue domain labels to identify entry points. If `forge.yaml → review.key_paths` lists domain-to-file mappings, use that table directly. Otherwise, infer key files from the issue body's Affected Files section.
|
|
188
198
|
|
|
189
199
|
**INFRA domain known footguns** (read before writing any `.github/workflows/*.yml` changes):
|
|
190
200
|
- **appleboy/ssh-action Go template preprocessing**: Any `{{` in a `script:` block is interpreted as a Go template directive **before the script reaches SSH**. This means `docker ps --format '{{.Names}}'` and `docker inspect --format '{{index .RepoTags 0}}'` will crash the action with exit 1. Both function calls (`{{index .X Y}}`) AND field accessors (`{{.Names}}`, `{{.Status}}`) fail on the action's empty data context. Shell error handlers (`|| fallback`, `set -e`, `2>/dev/null`) are bypassed because the failure is client-side. Always use `docker inspect IMAGE | jq -r '.[0].RepoTags[0]'` and `docker ps --format json | jq -r '.Names'` patterns in `appleboy/ssh-action` scripts. (Ref: forge#226 — 6-day silent deploy failure masked by `continue-on-error: true`)
|
|
@@ -194,11 +204,10 @@ For AlterLab issues (repo = `RapierCraft/AlterLab`):
|
|
|
194
204
|
2. Read domain files — start with key files for the affected domain
|
|
195
205
|
2.5. **Existing system search (conditional)**: If the issue describes a gap in a functional capability — content not being distributed, notifications not sending, jobs not running, data not being synced — MUST search for an existing automated system before proposing a new one. The issue body may name a specific tool or path (e.g., `reddit-bot/`, `marketing/`) — do NOT anchor on that path alone. Expand the search to all service layers:
|
|
196
206
|
```bash
|
|
197
|
-
#
|
|
198
|
-
grep -rn "{capability_keyword}"
|
|
199
|
-
grep -rn "{capability_keyword}" services/ --include="*.py" -l | head -20
|
|
207
|
+
# Check all service layers for the capability (adapt paths to your project structure)
|
|
208
|
+
grep -rn "{capability_keyword}" {REPO_PATH}/services/ --include="*.py" -l | head -20
|
|
200
209
|
# Look for scheduled jobs, automated runners, existing integrations
|
|
201
|
-
grep -rn "scheduler\|celery\|cron\|nightly\|periodic" services/ --include="*.py" -l | head -10
|
|
210
|
+
grep -rn "scheduler\|celery\|cron\|nightly\|periodic" {REPO_PATH}/services/ --include="*.py" -l | head -10
|
|
202
211
|
```
|
|
203
212
|
If an existing system is found that already handles the capability: the fix MUST route through the existing system (fix its config, env var, or gate) — NOT create a new parallel tool. Document the existing system in the investigation report and make it the centerpiece of the recommendation. This check is especially critical when the issue references a standalone tool directory (`reddit-bot/`, `scripts/`, `tools/`) — those directories often duplicate functionality that a service already owns. (Ref: forge#279 — investigator anchored on `reddit-bot/` from issue body, never checked `services/herald/app/scheduler/`, built parallel PRAW integration alongside Herald's existing automated crosspost scheduler)
|
|
204
213
|
3. Verify claims — does the code actually have the problem described?
|
|
@@ -308,13 +317,13 @@ gh issue close {NUMBER} {GH_FLAG} --comment "Closing as invalid: {reason from in
|
|
|
308
317
|
```bash
|
|
309
318
|
gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
|
|
310
319
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
311
|
-
--jq '.[] | select(.body |
|
|
320
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body'
|
|
312
321
|
```
|
|
313
322
|
|
|
314
323
|
**MANDATORY — Owner override detection**: After reading the investigation comment, read ALL comments on the issue to check for owner override signals:
|
|
315
324
|
```bash
|
|
316
325
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
317
|
-
--jq '.[] | select(.body |
|
|
326
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR") | not) | {author: .user.login, body: .body}'
|
|
318
327
|
```
|
|
319
328
|
|
|
320
329
|
Scan non-agent comments for override signals — phrases like "do not", "do NOT", "instead", "revert", "remove this", "override", "actually", or explicit disagreement with the investigation's recommendation. If an override comment is found from a repo owner or admin (not a bot):
|
|
@@ -402,7 +411,7 @@ gh issue edit {NUMBER} {GH_FLAG} \
|
|
|
402
411
|
|
|
403
412
|
<!-- FORGE:PHASE_COMPLETE — Entering Phase 3 (Build). See Universal Phase Dispatcher: sub-phases 3A–3M execute in sequence. No sub-phase completion is terminal. -->
|
|
404
413
|
|
|
405
|
-
**Skip if**: `<!-- FORGE:BUILDER -->`
|
|
414
|
+
**Skip if**: `<!-- FORGE:BUILDER -->` exists.
|
|
406
415
|
|
|
407
416
|
**CRITICAL: You MUST execute ALL sub-phases 3A–3M in order. Do NOT skip phases 3C.5 (context) or 3C.6 (architect) — they post mandatory `FORGE:CONTEXT` and `FORGE:ARCHITECT` comments that Phase 3F reads as its primary input. Skipping them degrades build quality and causes review findings. After each sub-phase, continue to the next — no sub-phase is terminal.**
|
|
408
417
|
|
|
@@ -412,11 +421,11 @@ gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
|
|
|
412
421
|
|
|
413
422
|
# Read investigation report
|
|
414
423
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
415
|
-
--jq '.[] | select(.body |
|
|
424
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body'
|
|
416
425
|
|
|
417
426
|
# Check if build already completed
|
|
418
427
|
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
419
|
-
--jq '.[] | select(.body |
|
|
428
|
+
--jq '.[] | select(.body | contains("FORGE:BUILDER")) | .body'
|
|
420
429
|
```
|
|
421
430
|
|
|
422
431
|
If no investigation comment with `<!-- INVESTIGATION:COMPLETE -->` → STOP (investigation not complete).
|
|
@@ -745,7 +754,7 @@ black {PYTHON_FILES} && isort {PYTHON_FILES} && python -m py_compile {PYTHON_FIL
|
|
|
745
754
|
```
|
|
746
755
|
`py_compile` failures are BLOCKING.
|
|
747
756
|
|
|
748
|
-
**TypeScript (
|
|
757
|
+
**TypeScript (primary repo — has tsconfig.json)**:
|
|
749
758
|
```bash
|
|
750
759
|
cd {WORKTREE_PATH}
|
|
751
760
|
prettier --write {TS_FILES} && tsc --noEmit
|
|
@@ -984,13 +993,16 @@ If multi-phase (`HAS_PHASE_HEADINGS > 0` AND `REMAINING_BEFORE > 0`): do NOT che
|
|
|
984
993
|
If single-phase or final phase: check off all `[ ]` items, add PR reference.
|
|
985
994
|
|
|
986
995
|
### 6B: Project board update (Status=Done, Workflow=Merged)
|
|
996
|
+
|
|
997
|
+
Resolve `PROJECT_BOARD_OWNER` and `PROJECT_BOARD_NUMBER` from `forge.yaml → project_board` (fields: `owner`, `project_number`). Fall back to `forge.yaml → project.owner` and project number `1` if `project_board` section is absent.
|
|
998
|
+
|
|
987
999
|
```bash
|
|
988
1000
|
ISSUE_URL="https://github.com/{GH_REPO}/issues/{NUMBER}"
|
|
989
|
-
ITEM_ID=$(gh project item-list
|
|
1001
|
+
ITEM_ID=$(gh project item-list {PROJECT_BOARD_NUMBER} --owner {PROJECT_BOARD_OWNER} --format json --limit 200 \
|
|
990
1002
|
--jq ".items[] | select(.content.url == \"$ISSUE_URL\") | .id" 2>/dev/null | head -1)
|
|
991
1003
|
```
|
|
992
1004
|
|
|
993
|
-
If found: set Status=Done, Workflow=Merged using project field IDs.
|
|
1005
|
+
If found: set Status=Done, Workflow=Merged using project field IDs from `forge.yaml → project_board.field_ids`.
|
|
994
1006
|
|
|
995
1007
|
### 6C: Ensure issue is closed
|
|
996
1008
|
|
package/docs/CODEX.md
CHANGED
|
@@ -69,7 +69,7 @@ When a repo-local adapter exists under `.agents/skills/`, it becomes authoritati
|
|
|
69
69
|
- different default GitHub repo resolution
|
|
70
70
|
- Codex-native worktree roots
|
|
71
71
|
- Forge-specific review heuristics
|
|
72
|
-
- best-effort handling of project-board steps that
|
|
72
|
+
- best-effort handling of project-board steps that may be project-specific upstream
|
|
73
73
|
|
|
74
74
|
## Trust and Global Config
|
|
75
75
|
|