forgedock 1.0.16 → 1.0.17
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 +21 -3
- package/bin/forgedock.mjs +1992 -540
- package/bin/github-app-manifest.json.license +2 -0
- package/bin/hooks/session-start.mjs +4 -5
- package/bin/registry.mjs +20 -0
- package/bin/tui.mjs +172 -96
- package/commands/adopt.md +433 -0
- package/commands/analytics.md +2 -0
- package/commands/audit-agents.md +2 -0
- package/commands/audit.md +2 -0
- package/commands/changelog.md +354 -0
- package/commands/cleanup.md +2 -0
- package/commands/compat-audit.md +330 -0
- package/commands/deploy-info.md +6 -5
- package/commands/diagnose.md +483 -0
- package/commands/explain.md +349 -0
- package/commands/forge-stats.md +2 -0
- package/commands/forgedock-init.md +2 -0
- package/commands/geo-audit.md +2 -0
- package/commands/incident-response.md +2 -0
- package/commands/issue.md +2 -0
- package/commands/milestone.md +2 -0
- package/commands/optimize.md +411 -0
- package/commands/orchestrate.md +118 -0
- package/commands/pipeline-health.md +60 -1
- package/commands/qa-sweep.md +2 -0
- package/commands/quality-gate.md +37 -0
- package/commands/replay.md +263 -0
- package/commands/resume.md +264 -0
- package/commands/review-pr-agents.md +5 -1
- package/commands/review-pr-staging.md +2 -0
- package/commands/review-pr.md +85 -3
- package/commands/rollback.md +2 -0
- package/commands/scope.md +280 -0
- package/commands/security-audit.md +2 -0
- package/commands/status.md +262 -0
- package/commands/sync-ecosystem.md +2 -0
- package/commands/validate.md +2 -0
- package/commands/work-on/build/architect.md +128 -18
- package/commands/work-on/build/context.md +130 -17
- package/commands/work-on/build/implement.md +2 -0
- package/commands/work-on/build/validate.md +2 -0
- package/commands/work-on/build.md +32 -7
- package/commands/work-on/close.md +85 -0
- package/commands/work-on/decompose.md +2 -0
- package/commands/work-on/investigate.md +30 -3
- package/commands/work-on/review.md +13 -1
- package/commands/work-on-monolithic.md +2 -0
- package/commands/work-on.md +624 -36
- package/docs/BRAND.md +51 -0
- package/docs/CONFIG.md +94 -0
- package/docs/articles/per-repo-adaptive-scripts-token-savings.md +174 -0
- package/docs/claude-breakpoints.json +47 -0
- package/docs/site/getting-started.md +21 -0
- package/package.json +3 -3
- package/scripts/classify-lane.sh +145 -0
- package/scripts/transition-label.sh +161 -0
- package/scripts/validate-pr-target.sh +30 -0
- package/templates/devdocs/README.md +72 -0
- package/templates/devdocs/agent/using-forgedock.md +3 -0
- package/templates/devdocs/agent/using-github.md +3 -0
- package/templates/devdocs/index.yaml +162 -0
- package/templates/devdocs/project/architecture.md +3 -0
- package/templates/devdocs/project/conventions.md +3 -0
- package/templates/devdocs/project/custom-instructions.md +3 -0
- package/templates/devdocs/project/glossary.md +3 -0
- package/templates/devdocs/project/stack.md +3 -0
- package/templates/devdocs/templates/commit-convention.md +3 -0
- package/templates/devdocs/templates/issue.md +3 -0
- package/templates/devdocs/templates/pull-request.md +3 -0
- package/templates/devdocs/templates/review-finding.md +3 -0
package/commands/review-pr.md
CHANGED
|
@@ -3,6 +3,8 @@ description: Context-aware PR review — analyzes what the PR touches, spawns do
|
|
|
3
3
|
argument-hint: [PR number, URL, "open", or "staging" for feature→main review]
|
|
4
4
|
allowed-tools: Task, Bash, Read, Grep, Glob, WebFetch, Skill
|
|
5
5
|
---
|
|
6
|
+
<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
|
|
7
|
+
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
|
6
8
|
|
|
7
9
|
# PR Review — Orchestrator
|
|
8
10
|
|
|
@@ -124,6 +126,9 @@ while [ "$MERGE_HEALTH" = "UNKNOWN" ] && [ "$MERGE_RETRY" -lt 3 ]; do
|
|
|
124
126
|
done
|
|
125
127
|
# MERGE_HEALTH: MERGEABLE | CONFLICTING | UNKNOWN (still async after retries)
|
|
126
128
|
# MERGE_HEALTH_STATE: CLEAN | DIRTY | BLOCKED | UNSTABLE | UNKNOWN
|
|
129
|
+
|
|
130
|
+
# Resolve repo name early — used in Phases 5, 6, 8B, 9A (clean-review skip path bypasses Phase 6A) <!-- Added: forge#820 -->
|
|
131
|
+
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
|
|
127
132
|
```
|
|
128
133
|
|
|
129
134
|
### 1B: Classify
|
|
@@ -731,7 +736,6 @@ If synthesis needed, launch a `general-purpose` Task (model: resolved per policy
|
|
|
731
736
|
### 6A: Extract Findings
|
|
732
737
|
|
|
733
738
|
```bash
|
|
734
|
-
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
|
|
735
739
|
HAS_SYNTHESIS=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" --jq '.[].body' | grep -c 'REVIEW-FINDINGS-SYNTHESIZED-START' || echo 0)
|
|
736
740
|
|
|
737
741
|
if [ "$HAS_SYNTHESIS" -gt 0 ]; then
|
|
@@ -786,8 +790,8 @@ fi
|
|
|
786
790
|
|
|
787
791
|
if [ -n "$MILESTONE_BRANCH" ]; then
|
|
788
792
|
BRANCH_SLUG=$(echo "$MILESTONE_BRANCH" | sed 's|^milestone/||')
|
|
789
|
-
MILESTONE_NUMBER=$(gh api repos/${REPO}/milestones
|
|
790
|
-
[ -z "$MILESTONE_NUMBER" ] && MILESTONE_NUMBER=$(gh api repos/${REPO}/milestones
|
|
793
|
+
MILESTONE_NUMBER=$(gh api repos/${REPO}/milestones 2>/dev/null | jq --arg slug "$BRANCH_SLUG" '.[] | select((.title | ascii_downcase | gsub("[^a-z0-9]+"; "-")) == $slug) | .number' 2>/dev/null | head -1)
|
|
794
|
+
[ -z "$MILESTONE_NUMBER" ] && MILESTONE_NUMBER=$(gh api repos/${REPO}/milestones 2>/dev/null | jq --arg slug "$BRANCH_SLUG" '.[] | select((.title | ascii_downcase | gsub("[^a-z0-9]+"; "-")) | test($slug)) | .number' 2>/dev/null | head -1)
|
|
791
795
|
[ -n "$MILESTONE_NUMBER" ] && MILESTONE_FLAG="--milestone $(gh api repos/${REPO}/milestones/${MILESTONE_NUMBER} --jq '.title')"
|
|
792
796
|
fi
|
|
793
797
|
```
|
|
@@ -1060,12 +1064,89 @@ fi
|
|
|
1060
1064
|
|
|
1061
1065
|
**Important**: Phase 8 ONLY merges the PR. It does NOT close the issue, update labels, or clean up worktrees. When invoked via `/work-on`, those responsibilities belong to `work-on/close.md` — which runs after the router detects state 4 (MERGE_COMPLETE: PR merged + issue open). Doing them here would cause the router to hit TERMINAL_MERGED (state 1) and skip the close phase entirely.
|
|
1062
1066
|
|
|
1067
|
+
### 8B: Post-Merge Review Finding Demilestoning (Milestone PRs Only)
|
|
1068
|
+
|
|
1069
|
+
**Skip if**: `IS_MILESTONE_TO_STAGING` is false or `MERGE_STATE != "MERGED"`. Runs only when a milestone→staging PR was just successfully merged.
|
|
1070
|
+
|
|
1071
|
+
**Purpose**: Review-finding issues created during a milestone PR review (Phase 6C) inherit the milestone. Once the milestone PR merges, those findings should flow through the fast lane independently — not remain stranded on a closed milestone. This step clears their milestone assignment automatically.
|
|
1072
|
+
|
|
1073
|
+
```bash
|
|
1074
|
+
if [ "${IS_MILESTONE_TO_STAGING:-false}" = "true" ] && [ "${MERGE_STATE:-}" = "MERGED" ]; then
|
|
1075
|
+
echo "Phase 8B: Clearing milestone from open review-finding issues referencing PR #${PR_NUMBER}..."
|
|
1076
|
+
|
|
1077
|
+
# Find open review-finding issues whose body references this PR number
|
|
1078
|
+
# The title template in Phase 6C always includes: "review finding — PR #${PR_NUMBER}"
|
|
1079
|
+
FINDINGS_TO_DEMILESTONE=$(gh issue list -R "${REPO}" \
|
|
1080
|
+
--state open \
|
|
1081
|
+
--label "review-finding" \
|
|
1082
|
+
--limit 200 \
|
|
1083
|
+
--json number,title,milestone \
|
|
1084
|
+
--jq ".[] | select(.milestone != null) | select(.title | test(\"PR #${PR_NUMBER}\")) | .number" \
|
|
1085
|
+
2>/dev/null || echo "")
|
|
1086
|
+
|
|
1087
|
+
if [ -z "$FINDINGS_TO_DEMILESTONE" ]; then
|
|
1088
|
+
echo "Phase 8B: No open review-finding issues with milestones found referencing PR #${PR_NUMBER}."
|
|
1089
|
+
else
|
|
1090
|
+
MOVED_COUNT=0
|
|
1091
|
+
echo "$FINDINGS_TO_DEMILESTONE" | while IFS= read -r FINDING_NUM; do
|
|
1092
|
+
[ -z "$FINDING_NUM" ] && continue
|
|
1093
|
+
FINDING_TITLE=$(gh issue view "$FINDING_NUM" -R "${REPO}" --json title --jq '.title' 2>/dev/null || echo "#${FINDING_NUM}")
|
|
1094
|
+
gh issue edit "$FINDING_NUM" -R "${REPO}" --milestone "" 2>/dev/null && \
|
|
1095
|
+
echo " Moved to fast lane: #${FINDING_NUM} — ${FINDING_TITLE}" || \
|
|
1096
|
+
echo " WARNING: Failed to clear milestone for #${FINDING_NUM}"
|
|
1097
|
+
MOVED_COUNT=$((MOVED_COUNT + 1))
|
|
1098
|
+
done
|
|
1099
|
+
echo "Phase 8B: Review finding demilestoning complete."
|
|
1100
|
+
fi
|
|
1101
|
+
fi
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
<!-- Added: forge#815 -->
|
|
1105
|
+
|
|
1063
1106
|
---
|
|
1064
1107
|
|
|
1065
1108
|
## Phase 9: Integrity Check & Summary (LAST)
|
|
1066
1109
|
|
|
1067
1110
|
**Run AFTER Phase 6 (issues created), Phase 7 (verdict posted), Phase 8 (merge if applicable).**
|
|
1068
1111
|
|
|
1112
|
+
### 9A: Post-Merge Review Finding Demilestoning Fallback (Milestone PRs Only)
|
|
1113
|
+
|
|
1114
|
+
**Skip if**: `IS_MILESTONE_TO_STAGING` is false. Runs when `AUTO_MERGE=false` but the PR was merged manually — Phase 8B did not run in this case, so Phase 9 handles cleanup.
|
|
1115
|
+
|
|
1116
|
+
**Detection**: Check if the PR is now MERGED. If so and `IS_MILESTONE_TO_STAGING=true`, run the same demilestoning logic as Phase 8B.
|
|
1117
|
+
|
|
1118
|
+
```bash
|
|
1119
|
+
if [ "${IS_MILESTONE_TO_STAGING:-false}" = "true" ]; then
|
|
1120
|
+
PR_MERGE_STATE=$(gh pr view $ARGUMENTS --json state --jq '.state' 2>/dev/null || echo "")
|
|
1121
|
+
if [ "$PR_MERGE_STATE" = "MERGED" ]; then
|
|
1122
|
+
echo "Phase 9A: Checking for open review-finding issues to demilestone (fallback — manual merge path)..."
|
|
1123
|
+
|
|
1124
|
+
FINDINGS_TO_DEMILESTONE=$(gh issue list -R "${REPO}" \
|
|
1125
|
+
--state open \
|
|
1126
|
+
--label "review-finding" \
|
|
1127
|
+
--limit 200 \
|
|
1128
|
+
--json number,title,milestone \
|
|
1129
|
+
--jq ".[] | select(.milestone != null) | select(.title | test(\"PR #${PR_NUMBER}\")) | .number" \
|
|
1130
|
+
2>/dev/null || echo "")
|
|
1131
|
+
|
|
1132
|
+
if [ -z "$FINDINGS_TO_DEMILESTONE" ]; then
|
|
1133
|
+
echo "Phase 9A: No open review-finding issues with milestones found referencing PR #${PR_NUMBER} (already cleared or none created)."
|
|
1134
|
+
else
|
|
1135
|
+
echo "$FINDINGS_TO_DEMILESTONE" | while IFS= read -r FINDING_NUM; do
|
|
1136
|
+
[ -z "$FINDING_NUM" ] && continue
|
|
1137
|
+
FINDING_TITLE=$(gh issue view "$FINDING_NUM" -R "${REPO}" --json title --jq '.title' 2>/dev/null || echo "#${FINDING_NUM}")
|
|
1138
|
+
gh issue edit "$FINDING_NUM" -R "${REPO}" --milestone "" 2>/dev/null && \
|
|
1139
|
+
echo " Moved to fast lane: #${FINDING_NUM} — ${FINDING_TITLE}" || \
|
|
1140
|
+
echo " WARNING: Failed to clear milestone for #${FINDING_NUM}"
|
|
1141
|
+
done
|
|
1142
|
+
echo "Phase 9A: Fallback demilestoning complete."
|
|
1143
|
+
fi
|
|
1144
|
+
fi
|
|
1145
|
+
fi
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
<!-- Added: forge#815 -->
|
|
1149
|
+
|
|
1069
1150
|
```bash
|
|
1070
1151
|
CURRENT_SHA=$(gh pr view $ARGUMENTS --json headRefOid --jq '.headRefOid')
|
|
1071
1152
|
REVIEW_IS_STALE="false"
|
|
@@ -1118,4 +1199,5 @@ Review complete for PR #X. Verdict: [VERDICT].
|
|
|
1118
1199
|
- Integration checks: [pass/N broken paths found]
|
|
1119
1200
|
- Issues created: [M]
|
|
1120
1201
|
{IF AUTO_MERGE: "PR merged and issue closed." / "Merge FAILED — see issue."}
|
|
1202
|
+
{IF IS_MILESTONE_TO_STAGING: "Review findings demilestoned: [N] issues moved to fast lane." / ""}
|
|
1121
1203
|
```
|
package/commands/rollback.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
description: Create a revert PR to roll back a shipped feature or fix that caused a production incident
|
|
3
3
|
argument-hint: [PR number to revert, or "last" for most recent deploy]
|
|
4
4
|
---
|
|
5
|
+
<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
|
|
6
|
+
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
|
5
7
|
|
|
6
8
|
# /rollback — Automated Revert PR Creation
|
|
7
9
|
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Estimate issue complexity before running /work-on — affected files, blast radius, risk flags, and decomposition recommendation
|
|
3
|
+
argument-hint: <issue number> [--repo {owner}/{repo}]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /scope — Pre-Flight Complexity Estimator
|
|
7
|
+
|
|
8
|
+
**Input**: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
You are a read-only pre-flight analyst. Given a GitHub issue number, you estimate how complex it is BEFORE the user commits to running `/work-on`. You surface affected files, blast radius, dependency risks, estimated pipeline phases, and a decomposition recommendation.
|
|
11
|
+
|
|
12
|
+
**This command is strictly READ-ONLY.** No labels are written, no comments are posted, no worktrees are created.
|
|
13
|
+
|
|
14
|
+
**Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
|
|
15
|
+
**NEVER use plan mode (EnterPlanMode).**
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Config Preamble
|
|
20
|
+
|
|
21
|
+
Read `forge.yaml` before running any phase:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
CONFIG_FILE="${FORGE_CONFIG:-forge.yaml}"
|
|
25
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
26
|
+
GH_OWNER=$(yq '.project.owner' "$CONFIG_FILE")
|
|
27
|
+
GH_REPO_NAME=$(yq '.project.repo' "$CONFIG_FILE")
|
|
28
|
+
GH_REPO="${GH_OWNER}/${GH_REPO_NAME}"
|
|
29
|
+
GH_FLAG="-R $GH_REPO"
|
|
30
|
+
REPO_PATH=$(yq '.paths.root' "$CONFIG_FILE")
|
|
31
|
+
else
|
|
32
|
+
echo "WARNING: forge.yaml not found."
|
|
33
|
+
echo "Run: npx forgedock init"
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Parse `$ARGUMENTS`:
|
|
39
|
+
- `{NUMBER}` — issue number (required)
|
|
40
|
+
- `--repo {owner}/{repo}` — override GH_REPO (optional; useful for satellite repos)
|
|
41
|
+
|
|
42
|
+
If `--repo` is provided: set `GH_REPO` and `GH_FLAG` to the override value.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Phase 1: Load Issue
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
gh issue view {NUMBER} {GH_FLAG} \
|
|
50
|
+
--json number,title,body,labels,milestone,state
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If the issue is CLOSED: print `Issue #{NUMBER} is already closed — scope analysis may not be actionable.` and continue anyway (the user may be scoping a re-open or reference).
|
|
54
|
+
|
|
55
|
+
Extract:
|
|
56
|
+
- `TITLE` — issue title (strip conventional commit prefix: `fix:`, `feat:`, `refactor:`, `chore:`)
|
|
57
|
+
- `BODY` — full body text
|
|
58
|
+
- `LABELS` — label names (used for domain detection)
|
|
59
|
+
- `MILESTONE` — milestone title if set (indicates feature lane)
|
|
60
|
+
- `TASK_TYPE` — infer from title prefix: `fix:` → Bug Fix, `feat:` → Feature, `refactor:` → Refactor, `chore:` → Maintenance, other → Unknown
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Phase 2: Extract Keywords
|
|
65
|
+
|
|
66
|
+
From `TITLE` and `BODY`, extract:
|
|
67
|
+
1. **Explicit file references** — anything matching `*.py`, `*.ts`, `*.tsx`, `*.md`, `*.yml`, `*.yaml`, `*.json`, `*.sh`, `docker-compose*`, `Dockerfile*` — collect as `EXPLICIT_FILES`
|
|
68
|
+
2. **Domain terms** — nouns and compound terms (e.g. function names, service names, component names, CLI command names) — collect as `DOMAIN_TERMS`
|
|
69
|
+
3. **Affected section files** — lines under `## Affected Files` section in the body (if present)
|
|
70
|
+
|
|
71
|
+
Merge `EXPLICIT_FILES` + `AFFECTED_SECTION_FILES` into `TARGET_FILES` (deduplicated).
|
|
72
|
+
|
|
73
|
+
Limit `DOMAIN_TERMS` to the 10 most specific (skip generic words: "fix", "bug", "issue", "add", "the", "and", "for", "with", "use", "get", "set").
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Phase 3: Affected-File Discovery
|
|
78
|
+
|
|
79
|
+
Search `REPO_PATH` for each keyword to find candidate files:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# For each file explicitly named in the issue
|
|
83
|
+
for file in {TARGET_FILES}; do
|
|
84
|
+
find "$REPO_PATH" -name "$file" -not -path "*/.git/*" -not -path "*/node_modules/*" 2>/dev/null
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
# For each domain term: grep for references
|
|
88
|
+
for term in {DOMAIN_TERMS}; do
|
|
89
|
+
grep -rl "$term" "$REPO_PATH" \
|
|
90
|
+
--include="*.py" --include="*.ts" --include="*.tsx" \
|
|
91
|
+
--include="*.md" --include="*.yml" --include="*.yaml" \
|
|
92
|
+
--include="*.json" --include="*.sh" \
|
|
93
|
+
--exclude-dir=".git" --exclude-dir="node_modules" \
|
|
94
|
+
--exclude-dir=".claude" 2>/dev/null | head -5
|
|
95
|
+
done
|
|
96
|
+
|
|
97
|
+
# Git log — files recently changed alongside the named files
|
|
98
|
+
if [ -n "{TARGET_FILES}" ]; then
|
|
99
|
+
for file in {TARGET_FILES}; do
|
|
100
|
+
git -C "$REPO_PATH" log --oneline -20 -- "$file" \
|
|
101
|
+
--name-only --format="" 2>/dev/null | grep -v "^$" | sort -u | head -10
|
|
102
|
+
done
|
|
103
|
+
fi
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Collect all results into `CANDIDATE_FILES` (deduplicated, sorted, absolute paths stripped to relative).
|
|
107
|
+
|
|
108
|
+
**Relevance filter**: Keep only files where the keyword match is in the file's primary logic — not in test fixtures, lock files, or generated output. Exclude: `*.lock`, `package-lock.json`, `yarn.lock`, `*.min.js`, `dist/`, `build/`, `.next/`, `__pycache__/`.
|
|
109
|
+
|
|
110
|
+
Final list: `AFFECTED_FILES` — at most 25 files.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Phase 4: Blast Radius
|
|
115
|
+
|
|
116
|
+
From `AFFECTED_FILES`, compute:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Count unique top-level directories
|
|
120
|
+
DIRS=$(echo "{AFFECTED_FILES}" | xargs -I{} dirname {} | sort -u)
|
|
121
|
+
DIR_COUNT=$(echo "$DIRS" | grep -c .)
|
|
122
|
+
|
|
123
|
+
# Count unique service groups (second-level directories under known roots)
|
|
124
|
+
# Adapt to project structure — common roots: services/, apps/, packages/, web/, commands/
|
|
125
|
+
SERVICE_GROUPS=$(echo "{AFFECTED_FILES}" | sed 's|/[^/]*$||' | sort -u)
|
|
126
|
+
SERVICE_COUNT=$(echo "$SERVICE_GROUPS" | grep -c .)
|
|
127
|
+
|
|
128
|
+
# Classify affected modules
|
|
129
|
+
MODULES=""
|
|
130
|
+
echo "{AFFECTED_FILES}" | grep -q "^commands/" && MODULES="$MODULES pipeline-commands"
|
|
131
|
+
echo "{AFFECTED_FILES}" | grep -q "^bin/" && MODULES="$MODULES installer"
|
|
132
|
+
echo "{AFFECTED_FILES}" | grep -q "^\.github/" && MODULES="$MODULES CI/CD"
|
|
133
|
+
echo "{AFFECTED_FILES}" | grep -q "^docs/" && MODULES="$MODULES docs"
|
|
134
|
+
echo "{AFFECTED_FILES}" | grep -q "services/" && MODULES="$MODULES backend-services"
|
|
135
|
+
echo "{AFFECTED_FILES}" | grep -q "web/" && MODULES="$MODULES frontend"
|
|
136
|
+
echo "{AFFECTED_FILES}" | grep -q "infra/\|docker-compose" && MODULES="$MODULES infrastructure"
|
|
137
|
+
echo "{AFFECTED_FILES}" | grep -q "migrations/" && MODULES="$MODULES database"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Phase 5: Risk Flag Detection
|
|
143
|
+
|
|
144
|
+
Scan `AFFECTED_FILES` and the issue body for high-risk signals:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
RISK_FLAGS=""
|
|
148
|
+
|
|
149
|
+
# Auth risk
|
|
150
|
+
(echo "{AFFECTED_FILES}" | grep -qiE "auth|login|session|token|jwt|oauth|permission|role" || \
|
|
151
|
+
echo "$BODY" | grep -qiE "auth|login|session|token|jwt|oauth|permission|role") && \
|
|
152
|
+
RISK_FLAGS="$RISK_FLAGS AUTH"
|
|
153
|
+
|
|
154
|
+
# Billing risk
|
|
155
|
+
(echo "{AFFECTED_FILES}" | grep -qiE "billing|payment|stripe|subscription|credit|invoice" || \
|
|
156
|
+
echo "$BODY" | grep -qiE "billing|payment|stripe|subscription|credit|invoice") && \
|
|
157
|
+
RISK_FLAGS="$RISK_FLAGS BILLING"
|
|
158
|
+
|
|
159
|
+
# Database migration risk
|
|
160
|
+
(echo "{AFFECTED_FILES}" | grep -qiE "migration|alembic|schema|model" || \
|
|
161
|
+
echo "$BODY" | grep -qiE "migration|schema change|db migration|database") && \
|
|
162
|
+
RISK_FLAGS="$RISK_FLAGS DB-MIGRATION"
|
|
163
|
+
|
|
164
|
+
# API schema / contract risk
|
|
165
|
+
(echo "{AFFECTED_FILES}" | grep -qiE "openapi|schema|serializer|types\.ts|api\.ts|client\.py" || \
|
|
166
|
+
echo "$BODY" | grep -qiE "api.contract|breaking.change|response.shape|openapi") && \
|
|
167
|
+
RISK_FLAGS="$RISK_FLAGS API-CONTRACT"
|
|
168
|
+
|
|
169
|
+
# CI/CD risk
|
|
170
|
+
(echo "{AFFECTED_FILES}" | grep -qiE "\.github/workflows|Dockerfile|docker-compose|deploy|infra/" || \
|
|
171
|
+
echo "$BODY" | grep -qiE "deploy|CI|CD|workflow|dockerfile|container") && \
|
|
172
|
+
RISK_FLAGS="$RISK_FLAGS CI-CD"
|
|
173
|
+
|
|
174
|
+
# Pipeline-phase risk (for ForgeDock itself)
|
|
175
|
+
echo "{AFFECTED_FILES}" | grep -qE "^commands/(work-on|review-pr|quality-gate|orchestrate)" && \
|
|
176
|
+
RISK_FLAGS="$RISK_FLAGS PIPELINE-CORE"
|
|
177
|
+
|
|
178
|
+
# New env vars
|
|
179
|
+
echo "$BODY" | grep -qiE "env var|environment variable|\.env|getenv|process\.env" && \
|
|
180
|
+
RISK_FLAGS="$RISK_FLAGS ENV-VARS"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Phase 6: Complexity Scoring
|
|
186
|
+
|
|
187
|
+
Compute a complexity score from the signals collected:
|
|
188
|
+
|
|
189
|
+
| Signal | Points |
|
|
190
|
+
|--------|--------|
|
|
191
|
+
| Each affected file | +1 |
|
|
192
|
+
| Each unique directory | +2 |
|
|
193
|
+
| AUTH risk flag | +5 |
|
|
194
|
+
| BILLING risk flag | +5 |
|
|
195
|
+
| DB-MIGRATION risk flag | +4 |
|
|
196
|
+
| API-CONTRACT risk flag | +3 |
|
|
197
|
+
| CI-CD risk flag | +3 |
|
|
198
|
+
| PIPELINE-CORE risk flag | +4 |
|
|
199
|
+
| ENV-VARS risk flag | +2 |
|
|
200
|
+
| Milestone set (feature lane) | +3 |
|
|
201
|
+
| 2+ task type signals in body | +3 |
|
|
202
|
+
|
|
203
|
+
**Score bands**:
|
|
204
|
+
| Score | Band | Typical pipeline time |
|
|
205
|
+
|-------|------|-----------------------|
|
|
206
|
+
| 0–10 | TRIVIAL | 5–15 min (1-file fix, 1–2 pipeline phases) |
|
|
207
|
+
| 11–20 | SIMPLE | 20–40 min (2–5 files, all phases) |
|
|
208
|
+
| 21–35 | MODERATE | 45–90 min (5–10 files, possible review findings) |
|
|
209
|
+
| 36–55 | COMPLEX | 90–150 min (10+ files, multiple domains) |
|
|
210
|
+
| 56+ | DECOMPOSE | 2h+ (multiple task types, 3+ service groups) |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Phase 7: Decomposition Recommendation
|
|
215
|
+
|
|
216
|
+
Apply the same signals `/work-on` uses to trigger decomposition. Recommend **decompose: YES** if 2+ of these signals match (at least 1 Strong):
|
|
217
|
+
|
|
218
|
+
**Strong signals**:
|
|
219
|
+
- [ ] 2+ distinct task types (Bug Fix + Feature, Refactor + Feature, etc.)
|
|
220
|
+
- [ ] 3+ service groups affected
|
|
221
|
+
- [ ] 6+ files across 3+ directories
|
|
222
|
+
|
|
223
|
+
**Supporting signals**:
|
|
224
|
+
- [ ] Phased requirements ("first do X, then Y, then Z")
|
|
225
|
+
- [ ] Score band is DECOMPOSE (56+)
|
|
226
|
+
- [ ] Both frontend and backend affected
|
|
227
|
+
- [ ] DB migration + API contract change in same issue
|
|
228
|
+
|
|
229
|
+
If decompose: YES — suggest 2–4 sub-issue titles based on the natural fault lines visible in the affected-file analysis.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Phase 8: Output Scope Report
|
|
234
|
+
|
|
235
|
+
Print a structured scope report. Do NOT post it as a GitHub comment — print to stdout only.
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
╔══════════════════════════════════════════════════════════════╗
|
|
239
|
+
║ /scope — Issue #{NUMBER}: {TITLE}
|
|
240
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
241
|
+
║ Task type : {TASK_TYPE}
|
|
242
|
+
║ Lane : {Fast lane (no milestone) | Feature lane — milestone: {MILESTONE}}
|
|
243
|
+
║ Complexity: {SCORE} → {BAND}
|
|
244
|
+
║ Est. time : {TYPICAL_PIPELINE_TIME}
|
|
245
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
246
|
+
║ AFFECTED FILES ({COUNT})
|
|
247
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
248
|
+
{list each file — one per line, relative to REPO_PATH}
|
|
249
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
250
|
+
║ BLAST RADIUS
|
|
251
|
+
║ Directories : {DIR_COUNT}
|
|
252
|
+
║ Modules : {MODULES}
|
|
253
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
254
|
+
║ RISK FLAGS
|
|
255
|
+
{if no flags: " None detected"}
|
|
256
|
+
{for each flag: " ⚠ {FLAG} — {brief note on what to watch for}"}
|
|
257
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
258
|
+
║ DECOMPOSITION
|
|
259
|
+
║ Recommendation: {decompose: YES | decompose: NO}
|
|
260
|
+
{if YES:
|
|
261
|
+
"║ Signals met: {list matched signals}
|
|
262
|
+
║ Suggested sub-issues:
|
|
263
|
+
║ 1. {sub-issue title}
|
|
264
|
+
║ 2. {sub-issue title}
|
|
265
|
+
║ → Run /work-on {NUMBER} — it will auto-decompose based on investigation."
|
|
266
|
+
}
|
|
267
|
+
{if NO:
|
|
268
|
+
"║ → Safe to run /work-on {NUMBER} directly."
|
|
269
|
+
}
|
|
270
|
+
╚══════════════════════════════════════════════════════════════╝
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Risk flag annotations:
|
|
274
|
+
- AUTH — review auth middleware, permission checks, and session handling carefully
|
|
275
|
+
- BILLING — get explicit sign-off before merging; test with real payment fixtures
|
|
276
|
+
- DB-MIGRATION — verify migration is reversible and tested on a copy of prod data
|
|
277
|
+
- API-CONTRACT — grep all consumers of the changed endpoint before shipping
|
|
278
|
+
- CI-CD — test workflow changes in a fork or staging environment first
|
|
279
|
+
- PIPELINE-CORE — changes to work-on/review-pr/quality-gate affect the entire AI dev loop; review-pr will run extra scrutiny
|
|
280
|
+
- ENV-VARS — ensure new vars are added to .env.example and all required config locations
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
description: Periodic security posture audit — runs a scripted 4-phase checklist against repo files (not diffs), creates GitHub issues for confirmed findings
|
|
3
3
|
argument-hint: [--repo <prefix>] [--phase 1|2|3|4|all] [--dry-run]
|
|
4
4
|
---
|
|
5
|
+
<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
|
|
6
|
+
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
|
5
7
|
|
|
6
8
|
# /security-audit — Periodic Security Posture Audit
|
|
7
9
|
|