devflow-kit 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/agents/code.md +330 -0
- package/{src/assets → dist}/agents/design.md +1 -1
- package/{src/assets → dist}/agents/diagnose.md +1 -2
- package/dist/agents/git.md +29 -56
- package/{src/assets → dist}/agents/knowledge.md +4 -3
- package/{src/assets → dist}/agents/research.md +2 -2
- package/{src/assets → dist}/agents/review.md +8 -7
- package/{src/assets → dist}/agents/scrutinize.md +1 -1
- package/dist/agents/skim.md +148 -0
- package/{src/assets → dist}/agents/triage.md +1 -1
- package/dist/cli/commands/init.js +62 -0
- package/dist/cli/commands/learning.js +38 -3
- package/dist/cli/commands/uninstall.js +42 -1
- package/dist/commands/bug-analysis.md +30 -8
- package/dist/commands/code-review.md +141 -60
- package/dist/commands/debug.md +14 -12
- package/dist/commands/dynamic-build.md +37 -38
- package/dist/commands/dynamic-plan.md +30 -18
- package/dist/commands/dynamic-profile.md +27 -13
- package/dist/commands/dynamic-tickets.md +28 -14
- package/dist/commands/explore.md +15 -13
- package/dist/commands/implement.md +33 -28
- package/dist/commands/plan.md +37 -24
- package/dist/commands/release.md +69 -4
- package/dist/commands/research.md +33 -11
- package/dist/commands/resolve.md +35 -32
- package/dist/commands/self-review.md +36 -23
- package/dist/core/agent-models.js +43 -0
- package/dist/core/assets.js +55 -10
- package/dist/core/claude-md-audit.js +190 -0
- package/dist/core/feature-switch.js +20 -1
- package/dist/core/flags.js +28 -0
- package/dist/core/fs-atomic.js +8 -3
- package/dist/core/learning-variants.js +213 -0
- package/dist/core/manifest.js +62 -0
- package/dist/core/mds-variants.js +38 -1
- package/dist/core/plugins.js +71 -9
- package/{src/assets → dist/learning-off}/agents/code.md +6 -10
- package/dist/learning-off/agents/design.md +119 -0
- package/dist/learning-off/agents/diagnose.md +210 -0
- package/dist/learning-off/agents/knowledge.md +90 -0
- package/dist/learning-off/agents/research.md +149 -0
- package/dist/learning-off/agents/review.md +228 -0
- package/dist/learning-off/agents/scrutinize.md +117 -0
- package/{src/assets → dist/learning-off}/agents/skim.md +1 -8
- package/dist/learning-off/agents/triage.md +163 -0
- package/dist/learning-off/commands/bug-analysis.md +420 -0
- package/dist/learning-off/commands/code-review.md +525 -0
- package/dist/learning-off/commands/debug.md +294 -0
- package/dist/learning-off/commands/dynamic-build.md +1255 -0
- package/dist/learning-off/commands/dynamic-plan.md +424 -0
- package/dist/learning-off/commands/dynamic-profile.md +214 -0
- package/dist/learning-off/commands/dynamic-tickets.md +632 -0
- package/dist/learning-off/commands/explore.md +210 -0
- package/dist/learning-off/commands/implement.md +808 -0
- package/dist/learning-off/commands/plan.md +664 -0
- package/dist/learning-off/commands/release.md +310 -0
- package/dist/learning-off/commands/research.md +222 -0
- package/dist/learning-off/commands/resolve.md +837 -0
- package/dist/learning-off/commands/self-review.md +266 -0
- package/dist/skills/git/references/tracker/_contract.md +33 -0
- package/dist/skills/git/references/tracker/github/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/github/gather-release-evidence.md +4 -0
- package/dist/skills/git/references/tracker/github/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/github/setup-task.md +12 -0
- package/dist/skills/git/references/tracker/jira/associate-release.md +1 -1
- package/dist/skills/git/references/tracker/jira/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +4 -0
- package/dist/skills/git/references/tracker/jira/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/jira/setup-task.md +14 -2
- package/dist/skills/git/references/tracker/linear/associate-release.md +1 -1
- package/dist/skills/git/references/tracker/linear/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +4 -0
- package/dist/skills/git/references/tracker/linear/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/linear/setup-task.md +14 -2
- package/dist/targets/claude-code/installer.js +72 -36
- package/dist/targets/claude-code/language-stamp.js +185 -0
- package/dist/targets/claude-code/learning-install.js +489 -0
- package/package.json +1 -1
- package/src/assets/agents/code.mds +339 -0
- package/src/assets/agents/design.mds +149 -0
- package/src/assets/agents/diagnose.mds +225 -0
- package/src/assets/agents/evaluate.md +1 -3
- package/src/assets/agents/git.mds +29 -56
- package/src/assets/agents/knowledge.mds +125 -0
- package/src/assets/agents/research.mds +176 -0
- package/src/assets/agents/review.mds +286 -0
- package/src/assets/agents/scrutinize.mds +132 -0
- package/src/assets/agents/skim.mds +161 -0
- package/src/assets/agents/triage.mds +194 -0
- package/src/assets/agents/validate.md +8 -6
- package/src/assets/commands/_partials/_compliance.mds +5 -4
- package/src/assets/commands/_partials/_decisions.mds +31 -0
- package/src/assets/commands/_partials/_engine.mds +9 -1
- package/src/assets/commands/_partials/_knowledge.mds +25 -12
- package/src/assets/commands/_partials/_preamble.mds +33 -9
- package/src/assets/commands/_partials/_publication.mds +5 -4
- package/src/assets/commands/_partials/_settings.mds +13 -5
- package/src/assets/commands/_partials/_wave.mds +8 -0
- package/src/assets/commands/bug-analysis.mds +24 -2
- package/src/assets/commands/code-review.mds +147 -44
- package/src/assets/commands/debug.mds +17 -1
- package/src/assets/commands/dynamic-build.mds +33 -2
- package/src/assets/commands/dynamic-plan.mds +36 -6
- package/src/assets/commands/dynamic-profile.mds +9 -1
- package/src/assets/commands/dynamic-tickets.mds +16 -2
- package/src/assets/commands/explore.mds +27 -1
- package/src/assets/commands/implement.mds +41 -8
- package/src/assets/commands/plan.mds +47 -8
- package/src/assets/commands/{release.md → release.mds} +27 -24
- package/src/assets/commands/research.mds +28 -4
- package/src/assets/commands/resolve.mds +43 -2
- package/src/assets/commands/self-review.mds +30 -5
- package/src/assets/mds/tracker/_contract.mds +72 -0
- package/src/assets/mds/tracker/_github.mds +13 -2
- package/src/assets/mds/tracker/_jira.mds +17 -5
- package/src/assets/mds/tracker/_linear.mds +17 -5
- package/src/assets/mds/tracker/_mcp.mds +2 -2
- package/src/assets/mds/tracker/_steps.mds +97 -0
- package/src/assets/rules/context-economy.md +10 -0
- package/src/assets/rules/go.md +1 -0
- package/src/assets/rules/java.md +1 -0
- package/src/assets/rules/python.md +1 -0
- package/src/assets/rules/rust.md +1 -0
- package/src/assets/rules/typescript.md +1 -0
- package/src/assets/scripts/claude-md-audit.cjs +611 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +1 -2
- package/src/assets/scripts/hooks/json-helper.cjs +13 -5
- package/src/assets/scripts/hooks/json-parse +34 -10
- package/src/assets/scripts/hooks/session-start-context +315 -7
- package/src/assets/skills/apply-decisions/SKILL.md +1 -1
- package/src/assets/skills/apply-feature-knowledge/SKILL.md +5 -5
- package/src/assets/skills/feature-knowledge/SKILL.md +43 -12
- package/src/assets/skills/quality-gates/SKILL.md +1 -1
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Proactive bug finding with static and semantic analysis — hunts real bugs in changed code before merge
|
|
3
|
+
---
|
|
4
|
+
# Bug Analysis Command
|
|
5
|
+
|
|
6
|
+
Run a proactive bug analysis on the current branch by combining static analysis tools with parallel semantic analyzers, then synthesizing results into an actionable bug report. Supports incremental analysis, timestamped report directories, and `/resolve` compatibility.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
/bug-analysis (analyze current branch — incremental if prior analysis exists)
|
|
12
|
+
/bug-analysis --full (force full analysis, ignore incremental state)
|
|
13
|
+
/bug-analysis --no-static (skip static analysis track, semantic-only)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Phases
|
|
17
|
+
|
|
18
|
+
### Phase 1: Pre-flight
|
|
19
|
+
|
|
20
|
+
**Produces:** BRANCH_INFO, PR_DESCRIPTION, EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL
|
|
21
|
+
|
|
22
|
+
**Resolve the evidence policy once per run**, from the repository root, before any step reads the values:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
node "$HOME/.devflow/scripts/resolve-evidence-policy.cjs" 2>/dev/null; echo "exit=$?"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `EVIDENCE_POLICY=<required|standard> SOURCE=<file|worktree|default|invalid|error> REF=<branch|none>[ WARN=<remote-unavailable|invalid-file|raised-by-compliance|pr-changes-policy>[,…]] ISSUE_REQUIRED=<true|false> APPLY_CONVENTIONS=<true|false> REQUIRE_NON_AUTHOR_APPROVAL=<true|false>` — these fields, in this order, nothing else, where `<branch>` is a branch name such as `main`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `EVIDENCE_POLICY=required SOURCE=error REF=none ISSUE_REQUIRED=true APPLY_CONVENTIONS=true REQUIRE_NON_AUTHOR_APPROVAL=true` instead.
|
|
29
|
+
|
|
30
|
+
Set `EVIDENCE_POLICY`, `ISSUE_REQUIRED`, `APPLY_CONVENTIONS` and `REQUIRE_NON_AUTHOR_APPROVAL` from the accepted line. Pass agents only the three mechanism inputs, never `EVIDENCE_POLICY`. Report `Evidence policy: {EVIDENCE_POLICY} (source: {SOURCE})`, plus any `WARN` tokens as advisory, once in the final report.
|
|
31
|
+
|
|
32
|
+
**Docs root (D-DOCS-ROOT).** Every `.devflow/docs/` path this command reads or writes lives at the checkout's toplevel, never under the directory the session started in. Resolve `{worktree}` from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — by running
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git -C "{start}" rev-parse --show-toplevel
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
and using its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. Every docs path below is written `{worktree}/.devflow/docs/…`; a repo-relative docs path handed to an agent always travels with a `WORKTREE_PATH` naming the checkout it is relative to.
|
|
39
|
+
|
|
40
|
+
Render the test-plan block from `/implement`'s evidence file, and from nothing else:
|
|
41
|
+
1. `branch_slug` is `git branch --show-current` with every `/` replaced by `-`.
|
|
42
|
+
2. Only when `branch_slug` matches `^[A-Za-z0-9._-]{1,200}$` and the file exists, run (the path double-quoted):
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{worktree}/.devflow/docs/evidence-{branch_slug}.md"; echo "exit=$?"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
3. On `exit=0`, `PR_TEST_PLAN_BLOCK` is its stdout byte for byte without that `exit=` line; in every other case it is `(none)`. Nothing here waits on it: the Git agent pastes it only behind its own check, and only into a PR it creates.
|
|
49
|
+
|
|
50
|
+
Spawn Git agent:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
Agent(subagent_type="Git", run_in_background=false):
|
|
54
|
+
"OPERATION: ensure-pr-ready
|
|
55
|
+
PR_TEST_PLAN_BLOCK: {PR_TEST_PLAN_BLOCK verbatim, or (none)}
|
|
56
|
+
APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
|
|
57
|
+
Validate branch, commit if needed, push, create PR if needed.
|
|
58
|
+
Return: branch, base_branch, branch-slug, PR#"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Extract from response:** `branch`, `base_branch`, `branch_slug`, `pr_number`.
|
|
62
|
+
|
|
63
|
+
**Fetch PR body** (after extracting `pr_number`):
|
|
64
|
+
```bash
|
|
65
|
+
PR_DESCRIPTION=$(gh pr view {pr_number} --json body --jq '.body' 2>/dev/null || echo "(none)")
|
|
66
|
+
```
|
|
67
|
+
If `pr_number` is absent or the command fails, set `PR_DESCRIPTION` to `(none)`.
|
|
68
|
+
|
|
69
|
+
### Phase 2: Static Analysis
|
|
70
|
+
|
|
71
|
+
**Requires:** BRANCH_INFO
|
|
72
|
+
|
|
73
|
+
#### Step 2a: Incremental Detection & Timestamp Setup
|
|
74
|
+
|
|
75
|
+
**Produces:** DIFF_RANGE, ANALYSIS_DIR
|
|
76
|
+
**Requires:** BRANCH_INFO
|
|
77
|
+
|
|
78
|
+
1. Check `{worktree}/.devflow/docs/bug-analysis/{branch-slug}/.last-analysis-head`:
|
|
79
|
+
- **If exists AND `--full` NOT set:**
|
|
80
|
+
- Read the SHA from the file
|
|
81
|
+
- Verify reachable: `git cat-file -t {sha}` — if exit code non-zero (rebase invalidated SHA), fall through to full
|
|
82
|
+
- If SHA == current HEAD → "No new commits since last analysis. Use --full for a full re-analysis." Stop.
|
|
83
|
+
- Set `DIFF_RANGE` to `{sha}...HEAD`
|
|
84
|
+
- **If not exists, unreachable SHA, or `--full`:**
|
|
85
|
+
- Set `DIFF_RANGE` to `{base_branch}...HEAD`
|
|
86
|
+
2. Generate timestamp: `YYYY-MM-DD_HHMM`. If directory already exists (same-minute collision), append seconds (`YYYY-MM-DD_HHMMSS`).
|
|
87
|
+
3. Create timestamped analysis directory: `mkdir -p "{worktree}/.devflow/docs/bug-analysis/{branch-slug}/{timestamp}/"`
|
|
88
|
+
4. Set `ANALYSIS_DIR` to that path.
|
|
89
|
+
|
|
90
|
+
#### Step 2b: Check Changed Files
|
|
91
|
+
|
|
92
|
+
**Requires:** DIFF_RANGE
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
CHANGED_FILES=$(git diff --name-only {DIFF_RANGE})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Store result as `CHANGED_FILES` — used throughout Steps 2d and Phase 4 to avoid repeated git invocations and ensure consistency.
|
|
99
|
+
|
|
100
|
+
If output is empty → "No changes to analyze." Stop.
|
|
101
|
+
|
|
102
|
+
#### Step 2c: Tool Availability Check
|
|
103
|
+
|
|
104
|
+
**Produces:** STATIC_TOOL_STATUS
|
|
105
|
+
|
|
106
|
+
Skip if `--no-static` flag provided.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
SEMGREP_AVAILABLE=$(which semgrep 2>/dev/null && echo "yes" || echo "no")
|
|
110
|
+
SNYK_AVAILABLE=$(which snyk 2>/dev/null && echo "yes" || echo "no")
|
|
111
|
+
CODEQL_AVAILABLE=$(which codeql 2>/dev/null && echo "yes" || echo "no")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If all are `no`: warn user "No static analysis tools found. Proceeding with semantic analysis only. To enable static analysis, install semgrep (`pip install semgrep`) or snyk (`npm install -g snyk`)." Set `STATIC_FINDINGS` to `(none)`.
|
|
115
|
+
|
|
116
|
+
If some are available: note which tools will run.
|
|
117
|
+
|
|
118
|
+
#### Step 2d: Tiered Static Analysis
|
|
119
|
+
|
|
120
|
+
**Produces:** STATIC_FINDINGS
|
|
121
|
+
**Requires:** STATIC_TOOL_STATUS, DIFF_RANGE, ANALYSIS_DIR
|
|
122
|
+
|
|
123
|
+
Skip if `--no-static` flag provided or all tools unavailable.
|
|
124
|
+
|
|
125
|
+
Run available tools on the changed files (from `CHANGED_FILES` computed in Step 2b).
|
|
126
|
+
|
|
127
|
+
**Semgrep and Snyk run in parallel** — launch both in the background, then wait for both before proceeding to CodeQL. CodeQL is conditional and sequential (it needs Semgrep/Snyk results to decide whether to run).
|
|
128
|
+
|
|
129
|
+
**Semgrep** (if available):
|
|
130
|
+
```bash
|
|
131
|
+
# tr '\n' '\0' + xargs -0 is portable across GNU and BSD xargs (macOS ships BSD xargs, which lacks -d)
|
|
132
|
+
echo "$CHANGED_FILES" | tr '\n' '\0' | xargs -0 timeout 300 semgrep scan --config auto --sarif --quiet 2>/dev/null
|
|
133
|
+
```
|
|
134
|
+
Parse SARIF output → extract findings.
|
|
135
|
+
|
|
136
|
+
**Snyk Code** (if available):
|
|
137
|
+
```bash
|
|
138
|
+
# Run a single project-level scan; filter SARIF results programmatically to CHANGED_FILES before LLM processing.
|
|
139
|
+
# Per-file invocation via xargs would invoke snyk O(n) times and --file is for dependency scanning, not source code.
|
|
140
|
+
SNYK_SARIF=$(timeout 300 snyk code test --sarif 2>/dev/null)
|
|
141
|
+
# Programmatic filter: keep only results whose file path appears in CHANGED_FILES.
|
|
142
|
+
# This is defense-in-depth — filtering at the data layer before the LLM agent sees any output.
|
|
143
|
+
SNYK_FILTERED=$(echo "$SNYK_SARIF" | jq --argjson files "$(echo "$CHANGED_FILES" | jq -R . | jq -s .)" \
|
|
144
|
+
'.runs[].results |= map(select(.locations[].physicalLocation.artifactLocation.uri as $uri | $files | index($uri) != null))' \
|
|
145
|
+
2>/dev/null || echo "$SNYK_SARIF")
|
|
146
|
+
```
|
|
147
|
+
Parse `SNYK_FILTERED` SARIF → extract findings. If `jq` is unavailable, fall back to the raw `SNYK_SARIF` and note the limitation.
|
|
148
|
+
|
|
149
|
+
**CodeQL** (if available AND (`--full` OR Semgrep/Snyk found HIGH/CRITICAL findings)):
|
|
150
|
+
```bash
|
|
151
|
+
# Use a unique temp directory per run to prevent symlink attacks and concurrent-process clobbering
|
|
152
|
+
CODEQL_TMP=$(mktemp -d)
|
|
153
|
+
# Register cleanup trap immediately after mktemp — ensures rm -rf runs on EXIT, SIGTERM, and SIGINT
|
|
154
|
+
# even if the session is interrupted before reaching the explicit rm -rf below
|
|
155
|
+
trap 'rm -rf "${CODEQL_TMP}"' EXIT INT TERM
|
|
156
|
+
timeout 600 codeql database create "${CODEQL_TMP}/db" --language={detected-language} --source-root=. 2>/dev/null && \
|
|
157
|
+
timeout 600 codeql database analyze "${CODEQL_TMP}/db" --format=sarif-latest --output="${CODEQL_TMP}/results.sarif" 2>/dev/null
|
|
158
|
+
# Capture exit status before cleanup so cleanup doesn't mask failures
|
|
159
|
+
CODEQL_EXIT=$?
|
|
160
|
+
# Parse SARIF output BEFORE cleanup — rm -rf destroys results.sarif
|
|
161
|
+
CODEQL_SARIF=$(cat "${CODEQL_TMP}/results.sarif" 2>/dev/null || echo "")
|
|
162
|
+
# Explicit cleanup (trap also covers this path; explicit rm is belt-and-suspenders)
|
|
163
|
+
rm -rf "${CODEQL_TMP}"
|
|
164
|
+
trap - EXIT INT TERM
|
|
165
|
+
```
|
|
166
|
+
Parse `CODEQL_SARIF` → extract findings. If database creation fails, `CODEQL_EXIT` is non-zero — skip CodeQL findings and note it. The `trap` guarantees cleanup on SIGTERM/SIGINT/EXIT so orphaned temp directories do not accumulate across interrupted sessions.
|
|
167
|
+
|
|
168
|
+
**Normalize** all findings to unified table, cap at top 50 by severity. Truncate each Description entry to 200 characters maximum to bound the serialized size of `STATIC_FINDINGS`:
|
|
169
|
+
|
|
170
|
+
| Tool | File:Line | CWE | Severity | Title | Description |
|
|
171
|
+
|------|-----------|-----|----------|-------|-------------|
|
|
172
|
+
| {tool} | {file}:{line} | {CWE or —} | {CRITICAL/HIGH/MEDIUM/LOW} | {title} | {description truncated to 200 chars} |
|
|
173
|
+
|
|
174
|
+
Write ALL raw findings to `{ANALYSIS_DIR}/static-findings.md`. Set `STATIC_FINDINGS` to the top-50 table.
|
|
175
|
+
|
|
176
|
+
If no tool produced findings: set `STATIC_FINDINGS` to `(none)`.
|
|
177
|
+
|
|
178
|
+
### Phase 3: Context Loading
|
|
179
|
+
|
|
180
|
+
**Produces:** FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, PLAN_CONTEXT, ACCEPTANCE_RULES
|
|
181
|
+
|
|
182
|
+
#### Feature Knowledge
|
|
183
|
+
|
|
184
|
+
### Load Feature Knowledge
|
|
185
|
+
|
|
186
|
+
Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
git -C "{start}" rev-parse --show-toplevel
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
|
|
193
|
+
|
|
194
|
+
**Step 1 — Read the index cache:**
|
|
195
|
+
|
|
196
|
+
Attempt to read `{worktree}/.devflow/features/index.md`. Each line follows the format:
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
- **{slug}** — {areas} — {Use-when description}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
If `index.md` exists and contains at least one entry line, use it for relevance matching.
|
|
203
|
+
|
|
204
|
+
**Step 2 — Fallback: glob frontmatter (if `index.md` is absent or empty):**
|
|
205
|
+
|
|
206
|
+
Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read only its YAML frontmatter block (between the opening and closing `---` delimiters). The frontmatter fields `name`, `description`, and `directories` are the authoritative relevance surface — `index.md` is only a cache.
|
|
207
|
+
|
|
208
|
+
**Step 3 — Pick relevant KBs:**
|
|
209
|
+
|
|
210
|
+
Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
|
|
211
|
+
|
|
212
|
+
**Step 4 — Read each selected KB's Rules:**
|
|
213
|
+
|
|
214
|
+
For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
|
|
215
|
+
|
|
216
|
+
1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
|
|
217
|
+
2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
|
|
218
|
+
3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
|
|
219
|
+
|
|
220
|
+
When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
|
|
221
|
+
|
|
222
|
+
**Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
|
|
223
|
+
|
|
224
|
+
Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
--- Feature knowledge: {slug} ---
|
|
228
|
+
KB: .devflow/features/{slug}/KNOWLEDGE.md
|
|
229
|
+
Rules:
|
|
230
|
+
- **KB-AP-2** {bullet text, verbatim}
|
|
231
|
+
- **KB-INV-1** {bullet text, verbatim}
|
|
232
|
+
Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
|
|
236
|
+
|
|
237
|
+
**One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
|
|
238
|
+
|
|
239
|
+
#### Plan Artifact
|
|
240
|
+
|
|
241
|
+
1. List `{worktree}/.devflow/docs/design/*.md` — sort descending by filename (timestamps are naturally sortable), scan the 10 most recent
|
|
242
|
+
2. Read the most recent file if it exists
|
|
243
|
+
3. Extract `## Acceptance Criteria` section → parse into table: `| ID | Criterion | Type | Testable Condition |`
|
|
244
|
+
4. Set `PLAN_CONTEXT` to plan summary; `ACCEPTANCE_RULES` to the table
|
|
245
|
+
5. If no plan files exist or section not found: `PLAN_CONTEXT=(none)`, `ACCEPTANCE_RULES=(none)`
|
|
246
|
+
|
|
247
|
+
### Phase 4: File Analysis
|
|
248
|
+
|
|
249
|
+
**Produces:** ACTIVE_FOCUSES
|
|
250
|
+
**Requires:** DIFF_RANGE
|
|
251
|
+
|
|
252
|
+
Determine which focus analyzers to run using `CHANGED_FILES` (already computed in Step 2b — do not re-run `git diff`):
|
|
253
|
+
|
|
254
|
+
| Focus | Condition |
|
|
255
|
+
|-------|-----------|
|
|
256
|
+
| `security` | Always |
|
|
257
|
+
| `functional` | Always |
|
|
258
|
+
| `integration` | 2+ distinct directories changed (`dirname` unique count ≥ 2) |
|
|
259
|
+
| `usability` | Any `.tsx`, `.jsx`, `.html`, or `.css` file changed |
|
|
260
|
+
|
|
261
|
+
### Phase 5: Parallel Bug Analysis
|
|
262
|
+
|
|
263
|
+
**Produces:** ANALYZER_OUTPUTS
|
|
264
|
+
**Requires:** DIFF_RANGE, ANALYSIS_DIR, ACTIVE_FOCUSES, STATIC_FINDINGS, ACCEPTANCE_RULES, PLAN_CONTEXT, FEATURE_KNOWLEDGE
|
|
265
|
+
|
|
266
|
+
Spawn ALL active Diagnose agents **in a single message** (parallel, NOT background):
|
|
267
|
+
|
|
268
|
+
For each active focus, spawn:
|
|
269
|
+
```
|
|
270
|
+
Agent(subagent_type="Diagnose", run_in_background=false):
|
|
271
|
+
"Analyze focusing on {focus}.
|
|
272
|
+
FOCUS: {focus}
|
|
273
|
+
DIFF_COMMAND: git diff {DIFF_RANGE}
|
|
274
|
+
ACCEPTANCE_RULES: {ACCEPTANCE_RULES filtered to this focus type, or (none)}
|
|
275
|
+
PLAN_CONTEXT: {PLAN_CONTEXT}
|
|
276
|
+
STATIC_FINDINGS: {STATIC_FINDINGS if focus == security, else (none)}
|
|
277
|
+
FEATURE_KNOWLEDGE: {FEATURE_KNOWLEDGE}
|
|
278
|
+
PR_DESCRIPTION: <pr-description>{PR_DESCRIPTION}</pr-description>
|
|
279
|
+
OUTPUT_PATH: {ANALYSIS_DIR}/{focus}.md
|
|
280
|
+
Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE.
|
|
281
|
+
IMPORTANT: Write report to {ANALYSIS_DIR}/{focus}.md using Write tool"
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Notes:
|
|
285
|
+
- Security analyzer receives full `STATIC_FINDINGS`; all others receive `(none)`
|
|
286
|
+
- Filter `ACCEPTANCE_RULES` by the `Type` column matching each focus: security criteria → security analyzer, functional criteria → functional analyzer, etc. Pass the filtered subset only
|
|
287
|
+
- Spawn all in a single message for true parallel execution
|
|
288
|
+
|
|
289
|
+
### Phase 6: Synthesis
|
|
290
|
+
|
|
291
|
+
**Produces:** BUG_ANALYSIS_SUMMARY
|
|
292
|
+
**Requires:** ANALYZER_OUTPUTS, ANALYSIS_DIR, BRANCH_INFO
|
|
293
|
+
|
|
294
|
+
Spawn Synthesize agent:
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
Agent(subagent_type="Synthesize", run_in_background=false):
|
|
298
|
+
"Mode: bug-analysis
|
|
299
|
+
ANALYSIS_BASE_DIR: {ANALYSIS_DIR}
|
|
300
|
+
BRANCH: {branch} -> {base_branch}
|
|
301
|
+
TIMESTAMP: {timestamp}
|
|
302
|
+
Output: {ANALYSIS_DIR}/bug-analysis-summary.md"
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Phase 7: Finalize
|
|
306
|
+
|
|
307
|
+
**Requires:** BRANCH_INFO, ANALYSIS_DIR
|
|
308
|
+
|
|
309
|
+
1. Write current HEAD SHA to `{worktree}/.devflow/docs/bug-analysis/{branch-slug}/.last-analysis-head`
|
|
310
|
+
2. Report to user:
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
## Bug Analysis Complete
|
|
314
|
+
|
|
315
|
+
**Branch**: {branch} -> {base_branch}
|
|
316
|
+
**Analysis**: {ANALYSIS_DIR}
|
|
317
|
+
|
|
318
|
+
### Risk Assessment: {risk_level}
|
|
319
|
+
|
|
320
|
+
{brief_reasoning}
|
|
321
|
+
|
|
322
|
+
### Bug Counts
|
|
323
|
+
| Category | CRITICAL | HIGH | MEDIUM | LOW | Total |
|
|
324
|
+
|----------|----------|------|--------|-----|-------|
|
|
325
|
+
| Security | {n} | {n} | {n} | {n} | {n} |
|
|
326
|
+
| Functional | {n} | {n} | {n} | {n} | {n} |
|
|
327
|
+
| Integration | {n} | {n} | {n} | {n} | {n} |
|
|
328
|
+
| Usability | {n} | {n} | {n} | {n} | {n} |
|
|
329
|
+
|
|
330
|
+
### Top Findings
|
|
331
|
+
{List top 3-5 bugs by severity and confidence}
|
|
332
|
+
|
|
333
|
+
### Artifacts
|
|
334
|
+
- Bug report: {ANALYSIS_DIR}/bug-analysis-summary.md
|
|
335
|
+
- Per-focus reports: {ANALYSIS_DIR}/{security|functional|integration|usability}.md
|
|
336
|
+
- Static findings: {ANALYSIS_DIR}/static-findings.md (if static analysis ran)
|
|
337
|
+
|
|
338
|
+
{if any CRITICAL or HIGH bugs found:}
|
|
339
|
+
Run `/resolve` to process and fix these findings.
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Architecture
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
/bug-analysis (orchestrator — spawns agents only)
|
|
346
|
+
│
|
|
347
|
+
├─ Phase 1: Pre-flight
|
|
348
|
+
│ └─ Git agent (ensure-pr-ready)
|
|
349
|
+
│
|
|
350
|
+
├─ Phase 2: Static Analysis
|
|
351
|
+
│ ├─ Step 2a: Incremental detection + timestamp setup
|
|
352
|
+
│ ├─ Step 2b: Check changed files (stop if none)
|
|
353
|
+
│ ├─ Step 2c: Tool availability check
|
|
354
|
+
│ └─ Step 2d: Tiered static analysis (semgrep → snyk → codeql)
|
|
355
|
+
│ Write static-findings.md
|
|
356
|
+
│
|
|
357
|
+
├─ Phase 3: Context Loading
|
|
358
|
+
│ ├─ Feature knowledge load → FEATURE_KNOWLEDGE
|
|
359
|
+
│ └─ {worktree}/.devflow/docs/design/*.md → PLAN_CONTEXT + ACCEPTANCE_RULES
|
|
360
|
+
│
|
|
361
|
+
├─ Phase 4: File Analysis
|
|
362
|
+
│ └─ Detect active focuses (security + functional always; integration + usability conditional)
|
|
363
|
+
│
|
|
364
|
+
├─ Phase 5: Bug Analysis (PARALLEL)
|
|
365
|
+
│ ├─ Diagnose agent: security (+ STATIC_FINDINGS)
|
|
366
|
+
│ ├─ Diagnose agent: functional
|
|
367
|
+
│ ├─ Diagnose agent: integration (conditional)
|
|
368
|
+
│ └─ Diagnose agent: usability (conditional)
|
|
369
|
+
│
|
|
370
|
+
├─ Phase 6: Synthesis
|
|
371
|
+
│ └─ Synthesize agent (mode: bug-analysis)
|
|
372
|
+
│
|
|
373
|
+
└─ Phase 7: Finalize
|
|
374
|
+
├─ Write .last-analysis-head
|
|
375
|
+
└─ Display results + suggest /resolve if blocking bugs found
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Edge Cases
|
|
379
|
+
|
|
380
|
+
| Case | Handling |
|
|
381
|
+
|------|----------|
|
|
382
|
+
| No new commits since last analysis | Stop: "No new commits since last analysis. Use --full for a full re-analysis." |
|
|
383
|
+
| Rebase invalidates `.last-analysis-head` SHA | `git cat-file -t` check fails → fallback to full diff |
|
|
384
|
+
| Zero changed files in DIFF_RANGE | Stop: "No changes to analyze." |
|
|
385
|
+
| Same-minute analysis collision | `mkdir` with seconds suffix (`YYYY-MM-DD_HHMMSS`) |
|
|
386
|
+
| All static tools unavailable | Warn, proceed with semantic-only analysis |
|
|
387
|
+
| `--no-static` flag | Skip Phase 2c and 2d entirely; `STATIC_FINDINGS=(none)` |
|
|
388
|
+
| `--full` flag | Bypass incremental detection (Step 2a), run full diff from base |
|
|
389
|
+
| CodeQL database creation fails | Skip CodeQL, note in output, continue with other tools |
|
|
390
|
+
| Static tool produces no findings | `STATIC_FINDINGS=(none)` — normal, proceed with semantic analysis |
|
|
391
|
+
| No plan artifact found | `PLAN_CONTEXT=(none)`, `ACCEPTANCE_RULES=(none)` — proceed without acceptance criteria |
|
|
392
|
+
| `integration` focus skipped | Not spawned when only 1 directory changed |
|
|
393
|
+
| `usability` focus skipped | Not spawned when no UI files changed |
|
|
394
|
+
|
|
395
|
+
## Resolve Compatibility
|
|
396
|
+
|
|
397
|
+
Run `/resolve` after `/bug-analysis` to fix identified bugs. `/resolve` automatically detects and uses bug analysis reports when no code review report exists.
|
|
398
|
+
|
|
399
|
+
## Principles
|
|
400
|
+
|
|
401
|
+
1. **Orchestration only** — Command spawns agents, doesn't do analysis work itself
|
|
402
|
+
2. **Parallel, not background** — Analyzers spawn in one message with `run_in_background=false`
|
|
403
|
+
3. **Static + semantic** — Two complementary tracks, each validates the other
|
|
404
|
+
4. **Incremental by default** — Only analyze new changes unless `--full` specified
|
|
405
|
+
5. **Verify before reporting** — Diagnose agents self-verify every finding
|
|
406
|
+
6. **Honest reporting** — Display risk level and counts directly from synthesis
|
|
407
|
+
|
|
408
|
+
## Phase Completion Checklist
|
|
409
|
+
|
|
410
|
+
Before reporting results, verify every phase was executed:
|
|
411
|
+
|
|
412
|
+
- [ ] Phase 1: Pre-flight → BRANCH_INFO captured, PR_DESCRIPTION fetched (or `(none)`)
|
|
413
|
+
- [ ] Phase 2: Static Analysis → STATIC_FINDINGS captured (or `(none)` if skipped/no tools/no findings); ANALYSIS_DIR created; CHANGED_FILES populated
|
|
414
|
+
- [ ] Phase 3: Context Loading → FEATURE_KNOWLEDGE loaded (or `(none)`), PLAN_CONTEXT and ACCEPTANCE_RULES captured (or `(none)`)
|
|
415
|
+
- [ ] Phase 4: File Analysis → ACTIVE_FOCUSES determined (security + functional always present)
|
|
416
|
+
- [ ] Phase 5: Parallel Bug Analysis → ANALYZER_OUTPUTS captured per active focus; all reports written to ANALYSIS_DIR
|
|
417
|
+
- [ ] Phase 6: Synthesis → BUG_ANALYSIS_SUMMARY written to `{ANALYSIS_DIR}/bug-analysis-summary.md`
|
|
418
|
+
- [ ] Phase 7: Finalize → `.last-analysis-head` updated; results displayed to user
|
|
419
|
+
|
|
420
|
+
If any phase is unchecked, execute it before proceeding.
|