forgedock 1.0.5 → 1.0.7
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 +7 -1
- package/bin/forgedock.mjs +496 -364
- package/bin/labels.json +152 -0
- package/commands/audit-agents.md +4 -2
- package/commands/autopilot.md +19 -11
- package/commands/cleanup.md +27 -12
- package/commands/deploy-info.md +36 -17
- package/commands/incident-response.md +15 -10
- package/commands/issue.md +8 -6
- package/commands/milestone.md +97 -48
- package/commands/orchestrate.md +109 -65
- package/commands/pipeline-health.md +8 -1
- package/commands/qa-sweep.md +14 -3
- package/commands/review-pr-agents.md +1 -1
- package/commands/review-pr-staging.md +129 -23
- package/commands/review-pr.md +237 -90
- package/commands/rollback.md +26 -7
- package/commands/security-audit.md +27 -25
- package/commands/sync-ecosystem.md +2 -2
- package/commands/work-on/build/architect.md +154 -2
- package/commands/work-on/build/context.md +131 -3
- package/commands/work-on/build/validate.md +32 -13
- package/commands/work-on/decompose.md +2 -0
- package/commands/work-on-monolithic.md +9 -5
- package/commands/work-on.md +67 -23
- package/docs/CONFIG.md +117 -0
- package/package.json +2 -1
- package/scripts/verify-route-registration.sh +36 -15
- package/scripts/verify-sops-chain.sh +18 -0
- package/templates/devdocs/README.md +96 -0
- package/templates/devdocs/agent/using-forgedock.md +245 -0
- package/templates/devdocs/agent/using-github.md +325 -0
- package/templates/devdocs/project/architecture.md +122 -0
- package/templates/devdocs/project/conventions.md +158 -0
- package/templates/devdocs/project/custom-instructions.md +73 -0
- package/templates/devdocs/project/glossary.md +84 -0
- package/templates/devdocs/project/stack.md +80 -0
- package/templates/devdocs/templates/commit-convention.md +147 -0
- package/templates/devdocs/templates/issue.md +141 -0
- package/templates/devdocs/templates/pull-request.md +115 -0
- package/templates/devdocs/templates/review-finding.md +147 -0
- package/bin/github-app-manifest.json +0 -24
package/bin/labels.json
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "priority:P0",
|
|
4
|
+
"color": "B60205",
|
|
5
|
+
"description": "Critical priority — production broken, data loss, security breach. Managed by ForgeDock."
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"name": "priority:P1",
|
|
9
|
+
"color": "D93F0B",
|
|
10
|
+
"description": "High priority — major feature broken, no workaround. Managed by ForgeDock."
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "priority:P2",
|
|
14
|
+
"color": "FBCA04",
|
|
15
|
+
"description": "Medium priority — impaired functionality, workaround exists. Managed by ForgeDock."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "priority:P3",
|
|
19
|
+
"color": "C2E0C6",
|
|
20
|
+
"description": "Low priority — minor issue or polish. Managed by ForgeDock."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "workflow:investigating",
|
|
24
|
+
"color": "1D76DB",
|
|
25
|
+
"description": "Pipeline: investigation phase in progress. Managed by ForgeDock."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "workflow:ready-to-build",
|
|
29
|
+
"color": "0075CA",
|
|
30
|
+
"description": "Pipeline: investigation complete, ready for build. Managed by ForgeDock."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "workflow:building",
|
|
34
|
+
"color": "0052CC",
|
|
35
|
+
"description": "Pipeline: implementation in progress. Managed by ForgeDock."
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "workflow:in-review",
|
|
39
|
+
"color": "5319E7",
|
|
40
|
+
"description": "Pipeline: PR created, under review. Managed by ForgeDock."
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "workflow:merged",
|
|
44
|
+
"color": "0E8A16",
|
|
45
|
+
"description": "Pipeline: PR merged, issue closed. Managed by ForgeDock."
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "workflow:decomposed",
|
|
49
|
+
"color": "BFD4F2",
|
|
50
|
+
"description": "Pipeline: decomposed into sub-issues. Managed by ForgeDock."
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "workflow:invalid",
|
|
54
|
+
"color": "CCCCCC",
|
|
55
|
+
"description": "Pipeline: issue closed as invalid after investigation. Managed by ForgeDock."
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "needs-human",
|
|
59
|
+
"color": "E4E669",
|
|
60
|
+
"description": "Pipeline stalled — requires human intervention. Managed by ForgeDock."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "review-finding",
|
|
64
|
+
"color": "D93F0B",
|
|
65
|
+
"description": "Defect or improvement found during automated PR review. Managed by ForgeDock."
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "needs-validation",
|
|
69
|
+
"color": "FBCA04",
|
|
70
|
+
"description": "Review finding awaiting human validation. Managed by ForgeDock."
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "validated",
|
|
74
|
+
"color": "0E8A16",
|
|
75
|
+
"description": "Review finding confirmed as a real issue. Managed by ForgeDock."
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "false-positive",
|
|
79
|
+
"color": "CCCCCC",
|
|
80
|
+
"description": "Review finding dismissed as a false positive. Managed by ForgeDock."
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "staging-review",
|
|
84
|
+
"color": "1D76DB",
|
|
85
|
+
"description": "Finding from a staging branch review before deploy to main. Managed by ForgeDock."
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "audit-finding",
|
|
89
|
+
"color": "D93F0B",
|
|
90
|
+
"description": "Security or compliance defect found during audit. Managed by ForgeDock."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "orchestration-metrics",
|
|
94
|
+
"color": "5319E7",
|
|
95
|
+
"description": "Running log of persisted audit-agents efficiency summaries. Managed by ForgeDock."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "health-report",
|
|
99
|
+
"color": "1D76DB",
|
|
100
|
+
"description": "Pipeline health report issue. Managed by ForgeDock."
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "bug",
|
|
104
|
+
"color": "D73A4A",
|
|
105
|
+
"description": "Something isn't working. Managed by ForgeDock."
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"name": "enhancement",
|
|
109
|
+
"color": "A2EEEF",
|
|
110
|
+
"description": "New feature or request. Managed by ForgeDock."
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "feature",
|
|
114
|
+
"color": "0075CA",
|
|
115
|
+
"description": "New feature implementation. Managed by ForgeDock."
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "refactor",
|
|
119
|
+
"color": "FEF2C0",
|
|
120
|
+
"description": "Code restructuring without behavior change. Managed by ForgeDock."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "dead-code",
|
|
124
|
+
"color": "E4E669",
|
|
125
|
+
"description": "Unused code to be removed. Managed by ForgeDock."
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "improvement",
|
|
129
|
+
"color": "C5DEF5",
|
|
130
|
+
"description": "Non-bug improvement to existing functionality. Managed by ForgeDock."
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "documentation",
|
|
134
|
+
"color": "0075CA",
|
|
135
|
+
"description": "Documentation addition or update. Managed by ForgeDock."
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"name": "qa",
|
|
139
|
+
"color": "E99695",
|
|
140
|
+
"description": "Quality assurance or testing issue. Managed by ForgeDock."
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"name": "security",
|
|
144
|
+
"color": "B60205",
|
|
145
|
+
"description": "Security vulnerability or hardening. Managed by ForgeDock."
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"name": "performance",
|
|
149
|
+
"color": "F9D0C4",
|
|
150
|
+
"description": "Performance optimization or regression. Managed by ForgeDock."
|
|
151
|
+
}
|
|
152
|
+
]
|
package/commands/audit-agents.md
CHANGED
|
@@ -343,9 +343,11 @@ This step posts a structured `<!-- FORGE:AUDIT-AGENTS -->` summary comment to th
|
|
|
343
343
|
**Step 4E.1 — Locate or create the tracking issue**:
|
|
344
344
|
|
|
345
345
|
```bash
|
|
346
|
-
# Ensure the label exists before using it (gh issue create fails with GraphQL error if label is absent)
|
|
346
|
+
# Ensure the label exists before using it (gh issue create fails with GraphQL error if label is absent).
|
|
347
|
+
# Color and description match the canonical ForgeDock label manifest (bin/labels.json).
|
|
348
|
+
# Run `npx forgedock labels setup` to bootstrap all managed labels at once.
|
|
347
349
|
gh label create "orchestration-metrics" -R {FORGE_REPO} \
|
|
348
|
-
--color "5319E7" --description "Running log of persisted audit-agents efficiency summaries" \
|
|
350
|
+
--color "5319E7" --description "Running log of persisted audit-agents efficiency summaries. Managed by ForgeDock." \
|
|
349
351
|
--force 2>/dev/null || true
|
|
350
352
|
|
|
351
353
|
TRACKING_ISSUE=$(gh issue list -R {FORGE_REPO} \
|
package/commands/autopilot.md
CHANGED
|
@@ -11,6 +11,7 @@ argument-hint: [--fix | --recon-only | --fix --limit 5 | --dry-run]
|
|
|
11
11
|
- `{CREDENTIALS_FILE}` ← `paths.credentials.file` (optional) — path to credentials YAML for analytics APIs
|
|
12
12
|
- `{SERVER_SSH}` ← `services.server_ssh` (optional) — SSH target for production server health checks (e.g., `ubuntu@1.2.3.4`)
|
|
13
13
|
- `{EMEMO_PATH}` ← `services.ememo_path` (optional) — path on production server to open eMemo files
|
|
14
|
+
- `{BILLING_ENABLED}` ← `billing.enabled` (optional, default `false`) — set to `true` to enable Stripe data collection in the Analytics Snapshot agent
|
|
14
15
|
|
|
15
16
|
You are an autonomous improvement engine for this project. Your job is to **find what's wrong, create trackable issues, and optionally fix the highest-impact ones** — all in a single cycle. Every cycle leaves the platform measurably better than before.
|
|
16
17
|
|
|
@@ -51,25 +52,31 @@ DRY_RUN = true if --dry-run present
|
|
|
51
52
|
```bash
|
|
52
53
|
echo "=== Autopilot Cycle: $(date -u +%Y-%m-%dT%H:%M:%SZ) ==="
|
|
53
54
|
|
|
55
|
+
# Portable ISO-8601 date arithmetic using python3 (works on Windows, macOS, Linux).
|
|
56
|
+
# Replaces GNU-only `date -u -d 'N days ago'` which fails on Windows and macOS.
|
|
57
|
+
DATE_3D_AGO=$(python3 -c "from datetime import datetime, timedelta, timezone; print((datetime.now(timezone.utc) - timedelta(days=3)).strftime('%Y-%m-%dT%H:%M:%SZ'))")
|
|
58
|
+
DATE_7D_AGO=$(python3 -c "from datetime import datetime, timedelta, timezone; print((datetime.now(timezone.utc) - timedelta(days=7)).strftime('%Y-%m-%dT%H:%M:%SZ'))")
|
|
59
|
+
DATE_1D_AGO=$(python3 -c "from datetime import datetime, timedelta, timezone; print((datetime.now(timezone.utc) - timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")
|
|
60
|
+
|
|
54
61
|
# Recent closed issues (last 3 days) — what was fixed recently?
|
|
55
62
|
gh issue list --state closed --json number,title,labels,closedAt \
|
|
56
|
-
--jq '[.[] | select(.closedAt > "'$
|
|
63
|
+
--jq '[.[] | select(.closedAt > "'"$DATE_3D_AGO"'")] | length' 2>/dev/null || echo "0"
|
|
57
64
|
|
|
58
65
|
# Open issue count by priority
|
|
59
|
-
gh issue list --state open --label P0 --json number --jq 'length'
|
|
60
|
-
gh issue list --state open --label P1 --json number --jq 'length'
|
|
61
|
-
gh issue list --state open --label P2 --json number --jq 'length'
|
|
66
|
+
gh issue list --state open --label "priority:P0" --json number --jq 'length'
|
|
67
|
+
gh issue list --state open --label "priority:P1" --json number --jq 'length'
|
|
68
|
+
gh issue list --state open --label "priority:P2" --json number --jq 'length'
|
|
62
69
|
|
|
63
70
|
# Stale issues (open, no workflow label, older than 7 days)
|
|
64
71
|
gh issue list --state open --limit 200 --json number,title,labels,createdAt \
|
|
65
72
|
--jq '[.[] | select(
|
|
66
73
|
(.labels | map(.name) | any(startswith("workflow:")) | not) and
|
|
67
|
-
(.createdAt < "'$
|
|
74
|
+
(.createdAt < "'"$DATE_7D_AGO"'")
|
|
68
75
|
)] | length'
|
|
69
76
|
|
|
70
77
|
# Failed CI runs in last 24h
|
|
71
78
|
gh run list --limit 30 --json conclusion,createdAt \
|
|
72
|
-
--jq '[.[] | select(.conclusion == "failure" and .createdAt > "'$
|
|
79
|
+
--jq '[.[] | select(.conclusion == "failure" and .createdAt > "'"$DATE_1D_AGO"'")] | length'
|
|
73
80
|
```
|
|
74
81
|
|
|
75
82
|
Store these as `BASELINE` metrics for the cycle report.
|
|
@@ -77,7 +84,7 @@ Store these as `BASELINE` metrics for the cycle report.
|
|
|
77
84
|
### 0B: Check for open P0s
|
|
78
85
|
|
|
79
86
|
```bash
|
|
80
|
-
gh issue list --state open --label P0 --json number,title --jq '.[] | "#\(.number) \(.title)"'
|
|
87
|
+
gh issue list --state open --label "priority:P0" --json number,title --jq '.[] | "#\(.number) \(.title)"'
|
|
81
88
|
```
|
|
82
89
|
|
|
83
90
|
If any P0 issues exist:
|
|
@@ -140,8 +147,9 @@ Analyze GitHub issue backlog:
|
|
|
140
147
|
Quick analytics pulse — just the key metrics, not a full audit:
|
|
141
148
|
1. Read credentials from {CREDENTIALS_FILE} (set via paths.credentials.file in forge.yaml)
|
|
142
149
|
2. GSC: mcp__gsc__search_analytics for last 7 days — total clicks, impressions, avg position
|
|
143
|
-
3. Stripe: mcp__stripe__retrieve_balance — current balance
|
|
144
|
-
|
|
150
|
+
3. Stripe (only if {BILLING_ENABLED} is true): mcp__stripe__retrieve_balance — current balance.
|
|
151
|
+
Skip this step entirely if {BILLING_ENABLED} is false — do NOT call any Stripe MCP tools.
|
|
152
|
+
4. Return: clicks trend (up/down), revenue (or "N/A — billing.enabled: false" if skipped), notable changes
|
|
145
153
|
```
|
|
146
154
|
|
|
147
155
|
### 1B: Collect results
|
|
@@ -291,7 +299,7 @@ Print a structured report:
|
|
|
291
299
|
|
|
292
300
|
### Analytics Pulse
|
|
293
301
|
- Clicks (7d): {N} ({trend})
|
|
294
|
-
- Revenue: ${N}
|
|
302
|
+
- Revenue: ${N} (or "N/A — billing.enabled: false" if Stripe step was skipped)
|
|
295
303
|
|
|
296
304
|
### Actions Taken
|
|
297
305
|
- Issues created: {count} ({list with numbers})
|
|
@@ -334,7 +342,7 @@ Pick the top `FIX_LIMIT` issues by this priority:
|
|
|
334
342
|
```bash
|
|
335
343
|
# Get candidates
|
|
336
344
|
gh issue list --state open --label "bug" --limit 50 --json number,title,labels,createdAt \
|
|
337
|
-
--jq 'sort_by(.labels | map(select(.name | startswith("P"))) | .[0].name) | .[:{FIX_LIMIT}] | .[] | "#\(.number) \(.title)"'
|
|
345
|
+
--jq 'sort_by(.labels | map(select(.name | startswith("priority:P"))) | .[0].name) | .[:{FIX_LIMIT}] | .[] | "#\(.number) \(.title)"'
|
|
338
346
|
```
|
|
339
347
|
|
|
340
348
|
### 4B: Present fix plan to user
|
package/commands/cleanup.md
CHANGED
|
@@ -25,11 +25,16 @@ GH_FLAG="-R $GH_REPO"
|
|
|
25
25
|
REPO_PATH=$(yq '.paths.root' "$CONFIG_FILE")
|
|
26
26
|
STAGING_BRANCH=$(yq '.branches.staging' "$CONFIG_FILE")
|
|
27
27
|
PROJECT_BOARD_OWNER=$(yq '.project_board.owner // .project.owner' "$CONFIG_FILE")
|
|
28
|
-
PROJECT_NUMBER=$(yq '.project_board.project_number //
|
|
29
|
-
PROJECT_ID=$(yq '.project_board.project_id' "$CONFIG_FILE")
|
|
28
|
+
PROJECT_NUMBER=$(yq '.project_board.project_number // empty' "$CONFIG_FILE" 2>/dev/null || echo "")
|
|
29
|
+
PROJECT_ID=$(yq '.project_board.project_id // empty' "$CONFIG_FILE" 2>/dev/null || echo "")
|
|
30
|
+
# Project board field and option IDs — empty string when project_board section is absent
|
|
31
|
+
STATUS_FIELD_ID=$(yq '.project_board.field_ids.status // ""' "$CONFIG_FILE" 2>/dev/null || echo "")
|
|
32
|
+
WORKFLOW_FIELD_ID=$(yq '.project_board.field_ids.workflow // ""' "$CONFIG_FILE" 2>/dev/null || echo "")
|
|
33
|
+
STATUS_DONE_OPTION_ID=$(yq '.project_board.option_ids.status.done // ""' "$CONFIG_FILE" 2>/dev/null || echo "")
|
|
34
|
+
WORKFLOW_MERGED_OPTION_ID=$(yq '.project_board.option_ids.workflow.merged // ""' "$CONFIG_FILE" 2>/dev/null || echo "")
|
|
30
35
|
```
|
|
31
36
|
|
|
32
|
-
All `{GH_REPO}`, `{GH_FLAG}`, `{REPO_PATH}`, `{STAGING_BRANCH}`, `{PROJECT_BOARD_OWNER}`, `{PROJECT_NUMBER}`, and `{
|
|
37
|
+
All `{GH_REPO}`, `{GH_FLAG}`, `{REPO_PATH}`, `{STAGING_BRANCH}`, `{PROJECT_BOARD_OWNER}`, `{PROJECT_NUMBER}`, `{PROJECT_ID}`, `{STATUS_FIELD_ID}`, `{WORKFLOW_FIELD_ID}`, `{STATUS_DONE_OPTION_ID}`, and `{WORKFLOW_MERGED_OPTION_ID}` references below are populated from `forge.yaml`.
|
|
33
38
|
|
|
34
39
|
---
|
|
35
40
|
|
|
@@ -222,19 +227,29 @@ fi
|
|
|
222
227
|
|
|
223
228
|
## Phase 5: Sync Project Board (if `board` or `all`)
|
|
224
229
|
|
|
225
|
-
|
|
230
|
+
**Skip if `project_board` is not configured** — check resolved vars before proceeding:
|
|
226
231
|
|
|
227
232
|
```bash
|
|
228
|
-
|
|
229
|
-
|
|
233
|
+
if [ -z "$PROJECT_BOARD_OWNER" ] || [ -z "$PROJECT_ID" ] || [ -z "$PROJECT_NUMBER" ]; then
|
|
234
|
+
echo "INFO: project_board not configured in forge.yaml — skipping board sync"
|
|
235
|
+
else
|
|
236
|
+
# Board sync: mark closed issues as Done/Merged on the project board
|
|
230
237
|
|
|
231
|
-
|
|
238
|
+
# List all board items
|
|
239
|
+
ITEMS=$(gh project item-list "$PROJECT_NUMBER" --owner "$PROJECT_BOARD_OWNER" --format json --limit 200)
|
|
232
240
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
gh project item-edit --project-id
|
|
237
|
-
|
|
241
|
+
# For each item where content.state == "CLOSED" but status != "Done" or workflow is not terminal:
|
|
242
|
+
echo "$ITEMS" | jq -r '.items[] | select(.content.state == "CLOSED") | .id' | while read -r ITEM_ID; do
|
|
243
|
+
if [ -n "$STATUS_FIELD_ID" ] && [ -n "$STATUS_DONE_OPTION_ID" ]; then
|
|
244
|
+
gh project item-edit --project-id "$PROJECT_ID" --id "$ITEM_ID" \
|
|
245
|
+
--field-id "$STATUS_FIELD_ID" --single-select-option-id "$STATUS_DONE_OPTION_ID" 2>/dev/null || true # Status=Done
|
|
246
|
+
fi
|
|
247
|
+
if [ -n "$WORKFLOW_FIELD_ID" ] && [ -n "$WORKFLOW_MERGED_OPTION_ID" ]; then
|
|
248
|
+
gh project item-edit --project-id "$PROJECT_ID" --id "$ITEM_ID" \
|
|
249
|
+
--field-id "$WORKFLOW_FIELD_ID" --single-select-option-id "$WORKFLOW_MERGED_OPTION_ID" 2>/dev/null || true # Workflow=Merged
|
|
250
|
+
fi
|
|
251
|
+
done
|
|
252
|
+
fi
|
|
238
253
|
```
|
|
239
254
|
|
|
240
255
|
---
|
package/commands/deploy-info.md
CHANGED
|
@@ -10,6 +10,8 @@ argument-hint: [staging | milestone/{slug} | compare {branch}]
|
|
|
10
10
|
**Config variables used by this command** (set in `forge.yaml`):
|
|
11
11
|
- `{REPO_PATH}` ← `paths.root` — project repository root
|
|
12
12
|
- `{HEALTH_ENDPOINT}` ← `services.health_endpoint` (optional) — URL used in post-deploy health check
|
|
13
|
+
- `{DEPLOY_WORKFLOW}` ← `deploy.workflow` (optional) — GitHub Actions workflow filename to trigger a deploy (e.g., `hotfix-deploy.yml`). When absent or empty, workflow-trigger steps are omitted.
|
|
14
|
+
- `{DEPLOY_SECRETS_BACKEND}` ← `deploy.secrets_backend` (optional) — secrets delivery method (`sops`, `aws-sm`, `vault`, `ci-env`, `none`). Controls whether secret-chain checks run.
|
|
13
15
|
|
|
14
16
|
You are the pipeline's deploy awareness layer. Before the user merges staging → main (triggering CI/CD deployment), this command shows exactly what's going out: which PRs, which issues, what changed, and what risks exist.
|
|
15
17
|
|
|
@@ -153,13 +155,20 @@ done
|
|
|
153
155
|
# Full file diff summary
|
|
154
156
|
git diff --stat origin/$TARGET..origin/$SOURCE
|
|
155
157
|
|
|
158
|
+
# Read layout paths from forge.yaml, fall back to AlterLab defaults
|
|
159
|
+
LAYOUT_API=$(yq '.review.layout.api // "services/api"' $PROJECT_ROOT/forge.yaml 2>/dev/null || echo "services/api")
|
|
160
|
+
LAYOUT_WORKER=$(yq '.review.layout.worker // "services/worker"' $PROJECT_ROOT/forge.yaml 2>/dev/null || echo "services/worker")
|
|
161
|
+
LAYOUT_PAGES=$(yq '.review.layout.pages // "web/src/app"' $PROJECT_ROOT/forge.yaml 2>/dev/null || echo "web/src/app")
|
|
162
|
+
# Derive web root from pages root (strip trailing /src/app or similar suffix if present)
|
|
163
|
+
LAYOUT_WEB=$(echo "$LAYOUT_PAGES" | sed 's|/src/app$||; s|/src$||')
|
|
164
|
+
|
|
156
165
|
# Categorize by service
|
|
157
166
|
echo "=== By Service ==="
|
|
158
167
|
git diff --name-only origin/$TARGET..origin/$SOURCE | sort | while read f; do
|
|
159
168
|
case "$f" in
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
169
|
+
${LAYOUT_API}/*) echo "API: $f" ;;
|
|
170
|
+
${LAYOUT_WORKER}/*) echo "WORKER: $f" ;;
|
|
171
|
+
${LAYOUT_WEB}/*) echo "WEB: $f" ;;
|
|
163
172
|
shared/*) echo "SHARED: $f" ;;
|
|
164
173
|
infra/*) echo "INFRA: $f" ;;
|
|
165
174
|
*) echo "OTHER: $f" ;;
|
|
@@ -170,8 +179,11 @@ done | sort
|
|
|
170
179
|
### Step 2E: Migration check
|
|
171
180
|
|
|
172
181
|
```bash
|
|
182
|
+
# Read migrations path from forge.yaml, fall back to infra/migrations
|
|
183
|
+
LAYOUT_MIGRATIONS=$(yq '.review.layout.migrations // "infra/migrations"' $PROJECT_ROOT/forge.yaml 2>/dev/null || echo "infra/migrations")
|
|
184
|
+
|
|
173
185
|
# Are there new migrations?
|
|
174
|
-
MIGRATIONS=$(git diff --name-only origin/$TARGET..origin/$SOURCE | grep "
|
|
186
|
+
MIGRATIONS=$(git diff --name-only origin/$TARGET..origin/$SOURCE | grep "^${LAYOUT_MIGRATIONS}/" | sort)
|
|
175
187
|
if [ -n "$MIGRATIONS" ]; then
|
|
176
188
|
echo "⚠️ DATABASE MIGRATIONS INCLUDED:"
|
|
177
189
|
echo "$MIGRATIONS"
|
|
@@ -195,7 +207,7 @@ Analyze the deploy payload and flag risks:
|
|
|
195
207
|
|--------|-----------|--------|
|
|
196
208
|
| Database migrations present | MEDIUM | Verify migrations are reversible |
|
|
197
209
|
| `shared/` changes | LOW | Restart-only deploy possible (no rebuild) |
|
|
198
|
-
| `.env.example` changes | HIGH | Verify
|
|
210
|
+
| `.env.example` changes | HIGH | Verify secrets backend has new vars (see `deploy.secrets_backend`) |
|
|
199
211
|
| `docker-compose.prod.yml` changes | HIGH | Review infrastructure changes carefully |
|
|
200
212
|
| `infra/traefik/` changes | HIGH | Routing changes — test before full deploy |
|
|
201
213
|
| 10+ PRs in one deploy | MEDIUM | Consider deploying in smaller batches |
|
|
@@ -205,17 +217,22 @@ Analyze the deploy payload and flag risks:
|
|
|
205
217
|
### Automated Checks
|
|
206
218
|
|
|
207
219
|
```bash
|
|
208
|
-
# Check for new env vars that might not be in
|
|
220
|
+
# Check for new env vars that might not be in the configured secrets backend
|
|
209
221
|
NEW_ENV=$(git diff origin/$TARGET..origin/$SOURCE -- '.env.example' | grep "^+" | grep -v "^+++" | grep -v "^#")
|
|
210
222
|
if [ -n "$NEW_ENV" ]; then
|
|
211
|
-
echo "⚠️ NEW ENVIRONMENT VARIABLES — verify they exist in
|
|
223
|
+
echo "⚠️ NEW ENVIRONMENT VARIABLES — verify they exist in your secrets backend ({deploy.secrets_backend}):"
|
|
212
224
|
echo "$NEW_ENV"
|
|
213
|
-
# Cross-check with
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
225
|
+
# Cross-check with SOPS chain (only when deploy.secrets_backend == "sops")
|
|
226
|
+
# If your project uses a different backend, skip this block and verify manually.
|
|
227
|
+
if [ "{deploy.secrets_backend}" = "sops" ]; then
|
|
228
|
+
for var in $(echo "$NEW_ENV" | grep -oP '^\+\K[A-Z_]+'); do
|
|
229
|
+
if ! grep -q "$var" scripts/decrypt-secrets.sh 2>/dev/null; then
|
|
230
|
+
echo " ❌ $var NOT in decrypt-secrets.sh ENV_MAPPING"
|
|
231
|
+
fi
|
|
232
|
+
done
|
|
233
|
+
else
|
|
234
|
+
echo " ℹ️ SOPS chain check skipped — deploy.secrets_backend is '{deploy.secrets_backend}'. Verify new vars in your configured backend."
|
|
235
|
+
fi
|
|
219
236
|
fi
|
|
220
237
|
```
|
|
221
238
|
|
|
@@ -232,7 +249,7 @@ Generate a checklist based on what's in the deploy:
|
|
|
232
249
|
- [ ] All PRs in this deploy have been reviewed
|
|
233
250
|
- [ ] No open `needs-human` issues blocking deploy
|
|
234
251
|
- [ ] {If migrations} Database backup verified
|
|
235
|
-
- [ ] {If new env vars}
|
|
252
|
+
- [ ] {If new env vars} Secrets backend ({deploy.secrets_backend}) updated with new vars; verify via your configured secrets chain
|
|
236
253
|
- [ ] {If traefik changes} Routing tested locally
|
|
237
254
|
|
|
238
255
|
### Deploy Command
|
|
@@ -240,8 +257,9 @@ Generate a checklist based on what's in the deploy:
|
|
|
240
257
|
# Standard deploy (merge staging → main via GitHub web UI)
|
|
241
258
|
# CI/CD auto-triggers on push to main
|
|
242
259
|
|
|
243
|
-
# Or manual trigger for specific services:
|
|
244
|
-
gh workflow run
|
|
260
|
+
# Or manual trigger for specific services (requires deploy.workflow set in forge.yaml):
|
|
261
|
+
gh workflow run {deploy.workflow} --ref main -f {deploy.workflow_inputs.services}={affected_services} -f {deploy.workflow_inputs.reason}="Deploy: {summary}"
|
|
262
|
+
# If deploy.workflow is not configured, deploy via the GitHub web UI or your CI/CD provider.
|
|
245
263
|
```
|
|
246
264
|
|
|
247
265
|
### Post-Deploy
|
|
@@ -292,5 +310,6 @@ gh workflow run hotfix-deploy.yml --ref main -f services={affected_services} -f
|
|
|
292
310
|
---
|
|
293
311
|
|
|
294
312
|
**Ready to deploy?** Merge staging → main via GitHub web UI, or run:
|
|
295
|
-
`gh workflow run
|
|
313
|
+
`gh workflow run {deploy.workflow} --ref staging -f {deploy.workflow_inputs.services}={services} -f {deploy.workflow_inputs.reason}="Batch deploy"`
|
|
314
|
+
*(requires `deploy.workflow` set in `forge.yaml`; omit this line if not configured)*
|
|
296
315
|
```
|
|
@@ -9,6 +9,7 @@ argument-hint: [issue number | "active" | "postmortem {issue}"]
|
|
|
9
9
|
|
|
10
10
|
**Config variables used by this command** (set in `forge.yaml`):
|
|
11
11
|
- `{REPO_PATH}` ← `paths.root` — project repository root
|
|
12
|
+
- `{DEPLOY_WORKFLOW}` ← `deploy.workflow` (optional) — GitHub Actions workflow filename for hotfix deploys (e.g., `hotfix-deploy.yml`). When absent or empty, workflow-trigger and workflow-monitor steps are omitted.
|
|
12
13
|
|
|
13
14
|
You are the pipeline's incident response coordinator. When production goes down or a critical bug surfaces, this command orchestrates the response: validates the hotfix before deploy, reconstructs the incident timeline, and produces a post-incident analysis.
|
|
14
15
|
|
|
@@ -39,7 +40,7 @@ You are the pipeline's incident response coordinator. When production goes down
|
|
|
39
40
|
gh issue view {NUMBER} --json number,title,body,labels,state,comments,assignees,createdAt
|
|
40
41
|
|
|
41
42
|
# If "active" — find most recent open P0
|
|
42
|
-
gh issue list --state open --label "P0" --limit 5 --json number,title,createdAt,labels \
|
|
43
|
+
gh issue list --state open --label "priority:P0" --limit 5 --json number,title,createdAt,labels \
|
|
43
44
|
--jq 'sort_by(.createdAt) | reverse | .[0]'
|
|
44
45
|
```
|
|
45
46
|
|
|
@@ -55,8 +56,9 @@ Parse the issue to understand:
|
|
|
55
56
|
gh pr list --state merged --base main --json number,title,mergedAt \
|
|
56
57
|
--jq '[.[] | select(.mergedAt > (now - 86400 | todate))] | .[] | "\(.number) | \(.title) | \(.mergedAt)"'
|
|
57
58
|
|
|
58
|
-
# Check recent hotfix deploys
|
|
59
|
-
|
|
59
|
+
# Check recent hotfix deploys (requires deploy.workflow set in forge.yaml)
|
|
60
|
+
# Skip this check if deploy.workflow is not configured.
|
|
61
|
+
gh run list --workflow={deploy.workflow} --limit 5 --json databaseId,status,conclusion,createdAt,displayTitle
|
|
60
62
|
```
|
|
61
63
|
|
|
62
64
|
#### Step 1C: Post incident acknowledgment
|
|
@@ -119,9 +121,10 @@ Your job:
|
|
|
119
121
|
- Does it remove functionality other code depends on?
|
|
120
122
|
- Are there syntax errors?
|
|
121
123
|
- Does it change DB schema without a migration?
|
|
122
|
-
4. Run compile checks:
|
|
123
|
-
- Python: python -m py_compile on changed .py files
|
|
124
|
-
-
|
|
124
|
+
4. Run compile checks (read forge.yaml → verification.commands for tool commands):
|
|
125
|
+
- Python: always run python -m py_compile on changed .py files (no config needed)
|
|
126
|
+
- Python format/lint: run verification.commands.python.format and .lint if configured; log "SKIPPED — not configured in verification.commands" if absent
|
|
127
|
+
- TypeScript: run verification.commands.typescript.typecheck if configured; log "SKIPPED — not configured in verification.commands" if absent
|
|
125
128
|
5. Check if the fix is scoped tightly (minimal changes for the incident)
|
|
126
129
|
|
|
127
130
|
Output:
|
|
@@ -143,10 +146,11 @@ gh issue comment {NUMBER} --body "$(cat <<'EOF'
|
|
|
143
146
|
**Confidence**: {level}
|
|
144
147
|
|
|
145
148
|
{If safe}:
|
|
146
|
-
**Ready for deploy.** Run:
|
|
149
|
+
**Ready for deploy.** Run (requires `deploy.workflow` set in `forge.yaml`):
|
|
147
150
|
```
|
|
148
|
-
gh workflow run
|
|
151
|
+
gh workflow run {deploy.workflow} --ref {FIX_BRANCH} -f {deploy.workflow_inputs.services}={affected_services} -f {deploy.workflow_inputs.reason}="P0: {TITLE}"
|
|
149
152
|
```
|
|
153
|
+
*(If `deploy.workflow` is not configured, merge the fix branch via the GitHub web UI or your CI/CD provider.)*
|
|
150
154
|
|
|
151
155
|
{If not safe}:
|
|
152
156
|
**Concerns found:**
|
|
@@ -164,8 +168,9 @@ EOF
|
|
|
164
168
|
#### Step 3A: Watch the deploy workflow
|
|
165
169
|
|
|
166
170
|
```bash
|
|
167
|
-
# Find the most recent
|
|
168
|
-
|
|
171
|
+
# Find the most recent deploy run (requires deploy.workflow set in forge.yaml)
|
|
172
|
+
# Skip if deploy.workflow is not configured.
|
|
173
|
+
RUN_ID=$(gh run list --workflow={deploy.workflow} --limit 1 --json databaseId --jq '.[0].databaseId')
|
|
169
174
|
|
|
170
175
|
# Check status
|
|
171
176
|
gh run view $RUN_ID --json status,conclusion,jobs
|
package/commands/issue.md
CHANGED
|
@@ -28,7 +28,7 @@ The user's input (`$ARGUMENTS`) can be:
|
|
|
28
28
|
|-----------|---------|
|
|
29
29
|
| Free-text description | "the billing page crashes when credits hit zero" |
|
|
30
30
|
| URL to error/log | "https://sentry.io/..." or a pasted stack trace |
|
|
31
|
-
| Reference to code | "the
|
|
31
|
+
| Reference to code | "the background worker leaks memory in task_processor.py" |
|
|
32
32
|
| Feature request | "add a dark mode toggle to the dashboard settings page" |
|
|
33
33
|
| Multi-repo prefix | "mcp: add list_schemas tool" or "n8n: fix credential refresh" |
|
|
34
34
|
| Audit/investigation | "investigate why deploy times doubled this week" |
|
|
@@ -161,8 +161,8 @@ Format: `{prefix}: {concise description}`
|
|
|
161
161
|
Rules:
|
|
162
162
|
- **Max 80 characters**
|
|
163
163
|
- Use conventional commit prefixes: `fix:`, `feat:`, `refactor:`, `investigate:`, `docs:`
|
|
164
|
-
- Be specific — "fix: billing page crash" is bad, "fix:
|
|
165
|
-
- Include the component/domain if it helps: `fix(
|
|
164
|
+
- Be specific — "fix: billing page crash" is bad, "fix: payment_processor.charge() raises ZeroDivisionError when amount == 0" is good
|
|
165
|
+
- Include the component/domain if it helps: `fix(worker): queue leak in task_processor heartbeat loop`
|
|
166
166
|
- Never use vague words: "improve", "update", "change", "handle" without specifics
|
|
167
167
|
|
|
168
168
|
### 3B: Compose the body
|
|
@@ -258,6 +258,8 @@ Files/areas to examine:
|
|
|
258
258
|
|
|
259
259
|
### 3D: Pipeline Issue Template (machine-callable reference)
|
|
260
260
|
|
|
261
|
+
> **Canonical Standard**: This template is the single source of truth for all automated issue creation in the ForgeDock pipeline. `milestone.md`, `orchestrate.md`, and `work-on/decompose.md` MUST use this template structure when creating issues programmatically. A shared convention is only useful if all create-paths enforce it — divergent inline templates in each command file cause acceptance-criteria drift and coverage gaps. See `work-on/decompose.md` Phase D0 for the investigation-gate pattern that enforces this standard at decomposition time. <!-- Added: forge#293 -->
|
|
262
|
+
|
|
261
263
|
When pipeline agents create issues programmatically (not via user input), use this canonical template. All automated `gh issue create` calls across Forge commands MUST include these mandatory sections. Domain-specific sections are additive — preserve them, but wrap them with this structure.
|
|
262
264
|
|
|
263
265
|
```markdown
|
|
@@ -488,10 +490,10 @@ Create all {N} issues? (yes / adjust #N / cancel)
|
|
|
488
490
|
| Bad Issue | Why It Fails | Good Version |
|
|
489
491
|
|-----------|-------------|-------------|
|
|
490
492
|
| "Fix docker mount" | Which compose file? Which mount? | "fix: `.gemini` volume mount in docker-compose.prod.yml missing rw flag" |
|
|
491
|
-
| "Update billing" | What about billing? What's broken? | "fix:
|
|
492
|
-
| "Investigate performance" | Investigate what? Where? | "investigate: API p95 latency doubled since last deploy — trace hot paths in
|
|
493
|
+
| "Update billing" | What about billing? What's broken? | "fix: payment_processor.charge() raises ZeroDivisionError when amount == 0" |
|
|
494
|
+
| "Investigate performance" | Investigate what? Where? | "investigate: API p95 latency doubled since last deploy — trace hot paths in job processing routers" |
|
|
493
495
|
| No affected files listed | Investigator guesses wrong files | List every file with what needs to change |
|
|
494
|
-
| "Handle edge case" | Which edge case? In what function? | "fix:
|
|
496
|
+
| "Handle edge case" | Which edge case? In what function? | "fix: task_processor.process_job() silently drops jobs when queue.length > MAX_BATCH" |
|
|
495
497
|
| Missing override files | Fix is incomplete, deploy fails | Include docker-compose.prod.yml, .env.example, etc. |
|
|
496
498
|
| P0 for a typo fix | Wastes priority signaling | Use P3 for cosmetic issues |
|
|
497
499
|
|