@ikunin/sprintpilot 1.0.2 → 1.0.4
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/_Sprintpilot/Sprintpilot.md +17 -1
- package/_Sprintpilot/manifest.yaml +1 -1
- package/_Sprintpilot/modules/autopilot/config.yaml +18 -0
- package/_Sprintpilot/scripts/scan.js +457 -0
- package/_Sprintpilot/skills/sprint-autopilot-on/workflow.md +206 -38
- package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/architecture-mapper.md +22 -15
- package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/concerns-hunter.md +47 -24
- package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/integration-mapper.md +21 -21
- package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/quality-assessor.md +34 -22
- package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/stack-analyzer.md +41 -43
- package/_Sprintpilot/skills/sprintpilot-codebase-map/workflow.md +1 -1
- package/lib/commands/install.js +247 -3
- package/lib/prompts.js +22 -0
- package/lib/substitute.js +1 -1
- package/package.json +4 -1
|
@@ -8,6 +8,24 @@ You do NOT hardcode the workflow sequence. After each completed skill, read its
|
|
|
8
8
|
|
|
9
9
|
**Git integration** is additive. If `_Sprintpilot/manifest.yaml` doesn't exist or `git.enabled: false`, all git operations are silently skipped and this workflow behaves identically to the stock autopilot.
|
|
10
10
|
|
|
11
|
+
### Shell portability (IMPORTANT)
|
|
12
|
+
|
|
13
|
+
Sprintpilot runs under any LLM CLI (Claude Code, Gemini CLI, Cursor, etc.) on any OS. The shell that executes commands may be **bash, zsh, PowerShell, or cmd** depending on platform and CLI. Shell-specific idioms will fail silently when the wrong shell is used.
|
|
14
|
+
|
|
15
|
+
**When you encounter bash-style idioms below, translate them to your shell.** The table applies to **external commands** (like `git`); cmdlets have slightly different conventions.
|
|
16
|
+
|
|
17
|
+
| Bash idiom | PowerShell equivalent | Meaning |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `A && B` | `A; if ($LASTEXITCODE -eq 0) { B }` (or separate commands, guarding B manually) | Run B only if A succeeded |
|
|
20
|
+
| `A \|\| true` | `A; $LASTEXITCODE = 0` (or `try { A } catch {}` for cmdlets) | Run A, ignore failures |
|
|
21
|
+
| `2>/dev/null` | `2>$null` | Suppress stderr |
|
|
22
|
+
| `rm -rf <dir>` | `Remove-Item -Recurse -Force <dir>` | Recursive delete |
|
|
23
|
+
| `if [ -f X ]; then ... fi` | `if (Test-Path -PathType Leaf X) { ... }` | File-exists check (regular file, not dir) |
|
|
24
|
+
|
|
25
|
+
**Safer:** when in doubt, use the cross-platform Node helpers under `_Sprintpilot/scripts/`. For ad-hoc file ops, invoke Node inline: `node -e "require('fs').rmSync('<path>', {recursive: true, force: true})"`.
|
|
26
|
+
|
|
27
|
+
If a step below uses `&&` to chain "run B only on A's success", and you cannot express that in one line, **run the commands separately and STOP if any step fails** — do not proceed past a failed step.
|
|
28
|
+
|
|
11
29
|
---
|
|
12
30
|
|
|
13
31
|
## AUTOPILOT RULES — READ BEFORE PROCEEDING
|
|
@@ -120,6 +138,7 @@ All BMAD skills are fully automatable (auto-continue past menus, derive decision
|
|
|
120
138
|
| `bmad-create-ux-design` | Automatable if PRD exists; BLOCKER if no PRD |
|
|
121
139
|
| `bmad-party-mode` | Skip — inherently interactive |
|
|
122
140
|
| `bmad-brainstorming` | Skip — inherently interactive |
|
|
141
|
+
| `bmad-retrospective` | Under autopilot, handled per `autopilot.retrospective_mode`: `auto` (default — inline artifact, no external skill call), `stop` (pause so user runs `/bmad-retrospective` interactively, then resumes autopilot), or `skip` (not recommended). The external skill is NOT invoked from autopilot because it enters a multi-persona discussion loop under some CLIs. |
|
|
123
142
|
|
|
124
143
|
---
|
|
125
144
|
|
|
@@ -155,13 +174,15 @@ Resolve:
|
|
|
155
174
|
</action>
|
|
156
175
|
<action>Read `{project-root}/_Sprintpilot/modules/autopilot/config.yaml` (if present) and set:
|
|
157
176
|
- `{{session_story_limit}}` from `autopilot.session_story_limit` (default: 3). A value of 0 disables the limit (run until sprint complete).
|
|
158
|
-
|
|
177
|
+
- `{{retrospective_mode}}` from `autopilot.retrospective_mode` (default: `auto`). Valid values: `auto` | `stop` | `skip`. Any unknown value falls back to `auto`.
|
|
178
|
+
If the file or either key is missing, fall back to the defaults above.
|
|
159
179
|
</action>
|
|
160
180
|
</check>
|
|
161
181
|
|
|
162
182
|
<check if="manifest does NOT exist">
|
|
163
183
|
<action>Set `{{git_enabled}}` = false</action>
|
|
164
184
|
<action>Set `{{session_story_limit}}` = 3</action>
|
|
185
|
+
<action>Set `{{retrospective_mode}}` = `auto`</action>
|
|
165
186
|
<action>Log: "No _Sprintpilot/manifest.yaml found — running stock autopilot (no git)"</action>
|
|
166
187
|
</check>
|
|
167
188
|
|
|
@@ -170,7 +191,9 @@ Resolve:
|
|
|
170
191
|
<check if="not a git repo">
|
|
171
192
|
<action>HALT: "No git repository found. Initialize one first:
|
|
172
193
|
```
|
|
173
|
-
git init
|
|
194
|
+
git init
|
|
195
|
+
git add -A
|
|
196
|
+
git commit -m 'initial commit'
|
|
174
197
|
git remote add origin <your-repo-url>
|
|
175
198
|
```
|
|
176
199
|
Then run /sprint-autopilot-on again."</action>
|
|
@@ -201,15 +224,20 @@ Resolve:
|
|
|
201
224
|
- COMMITTED: log "Recoverable work found for <name> — will push via git -C"
|
|
202
225
|
Push the branch: `git -C .worktrees/<name> push -u origin <branch> 2>&1`
|
|
203
226
|
If `{{create_pr}}` is true AND platform != git_only: create PR via `node {{project_root}}/_Sprintpilot/scripts/create-pr.js ...`
|
|
204
|
-
If `{{create_pr}}` is false OR platform is git_only: merge directly
|
|
227
|
+
If `{{create_pr}}` is false OR platform is git_only: merge directly. Run each as a separate command; **STOP and log the failure if any step fails — do not proceed past a failed step**:
|
|
228
|
+
1. `git checkout -B {{base_branch}} origin/{{base_branch}}`
|
|
229
|
+
2. `git merge <branch> --no-edit`
|
|
230
|
+
3. `git push origin {{base_branch}}`
|
|
205
231
|
Then remove worktree.
|
|
206
232
|
- STALE: `git worktree remove .worktrees/<name> --force` + prune
|
|
207
233
|
- DIRTY: warn user, ask how to proceed (stash/commit/discard)
|
|
208
|
-
- ORPHAN: `
|
|
234
|
+
- ORPHAN: remove the directory cross-platform with `node -e "require('fs').rmSync('.worktrees/<name>', {recursive: true, force: true})"`, then `git worktree prune`
|
|
209
235
|
</action>
|
|
210
236
|
|
|
211
237
|
<action>**Branch reconciliation** — detect pushed-but-unmerged story branches.
|
|
212
|
-
Run
|
|
238
|
+
Run as separate commands — **if `git fetch origin` fails (network/auth), STOP branch reconciliation and log a warning; do not operate on stale local refs**:
|
|
239
|
+
1. `git fetch origin`
|
|
240
|
+
2. `git branch -r --list "origin/{{branch_prefix}}*"`
|
|
213
241
|
For each remote branch:
|
|
214
242
|
- Extract story-key from branch name (strip "origin/{{branch_prefix}}" prefix)
|
|
215
243
|
- Look up story status in `{status_file}`
|
|
@@ -226,16 +254,16 @@ Resolve:
|
|
|
226
254
|
- If merge fails: log warning, continue (branch is preserved on remote)
|
|
227
255
|
- If merge succeeds:
|
|
228
256
|
- Re-read `{status_file}` from HEAD (may now include story artifacts after merge)
|
|
229
|
-
- Update `{git_status_file}` via sync-status.
|
|
230
|
-
**IMPORTANT:** sync-status.
|
|
257
|
+
- Update `{git_status_file}` via sync-status.js: set `--merge-status "recovered"` for this story.
|
|
258
|
+
**IMPORTANT:** sync-status.js does full block replacement. If the story already has an entry in `{git_status_file}`, re-read its existing fields and pass ALL of them alongside `--merge-status`. If no entry exists yet, pass at minimum `--branch` and `--push-status "pushed"`.
|
|
231
259
|
- If `{{platform}}` is NOT git_only (github, gitlab, bitbucket, gitea) AND `{{create_pr}}` is true:
|
|
232
260
|
- Check if PR/MR already exists for this branch (platform-specific check via create-pr.sh or CLI)
|
|
233
261
|
- If no PR: create one via `node {{project_root}}/_Sprintpilot/scripts/create-pr.js --platform {{platform}} ...`
|
|
234
262
|
- Log: "PR created/found for <story-key>"
|
|
235
|
-
- Update `{git_status_file}` via sync-status.
|
|
263
|
+
- Update `{git_status_file}` via sync-status.js: set `--merge-status "pr_pending"` for this story (same full-field requirement as above)
|
|
236
264
|
- If status IS "done" AND branch still exists AND `{{cleanup_on_merge}}` is true:
|
|
237
265
|
- Log: "Stale remote branch: <branch> — story already done, cleaning up"
|
|
238
|
-
- Delete remote branch: `git push origin --delete <branch
|
|
266
|
+
- Delete remote branch (ignore failure — the branch may already be gone): `git push origin --delete <branch>`
|
|
239
267
|
</action>
|
|
240
268
|
|
|
241
269
|
<action>Set `{{git_enabled}}` = true, `{{platform}}` = detected value</action>
|
|
@@ -290,6 +318,34 @@ Resolve:
|
|
|
290
318
|
- Advance to next non-done story
|
|
291
319
|
- Update `{state_file}` with reconciled values
|
|
292
320
|
</action>
|
|
321
|
+
|
|
322
|
+
<!-- Resume from a `retrospective_mode: stop` pause.
|
|
323
|
+
The user was told to run /bmad-retrospective interactively. If they
|
|
324
|
+
did, the epic is now `done` in {status_file} (or a retrospective
|
|
325
|
+
artifact exists). Otherwise, re-issue the instructions and halt. -->
|
|
326
|
+
<check if="{state_file}.paused_at is epic-complete-awaiting-retrospective">
|
|
327
|
+
<action>Set `{{paused_epic_id}}` from `{state_file}.paused_epic_id`</action>
|
|
328
|
+
<action>Check whether epic `{{paused_epic_id}}` is now `done` in `{status_file}` OR an artifact exists at `{implementation_artifacts}/retrospectives/epic-{{paused_epic_id}}-*.md`</action>
|
|
329
|
+
<check if="epic is done OR retrospective artifact exists">
|
|
330
|
+
<action>Clear `paused_at`, `paused_epic_id`, and `next_action` from `{state_file}`</action>
|
|
331
|
+
<action>Log: "Epic {{paused_epic_id}} retrospective detected — resuming autopilot"</action>
|
|
332
|
+
</check>
|
|
333
|
+
<check if="epic is NOT done AND no retrospective artifact">
|
|
334
|
+
<action>Report:
|
|
335
|
+
```
|
|
336
|
+
Autopilot still paused — epic {{paused_epic_id}} retrospective not yet done.
|
|
337
|
+
|
|
338
|
+
Run `/bmad-retrospective` interactively for epic {{paused_epic_id}},
|
|
339
|
+
then re-run `/sprint-autopilot-on` to continue.
|
|
340
|
+
|
|
341
|
+
(To bypass, edit _Sprintpilot/modules/autopilot/config.yaml and set
|
|
342
|
+
retrospective_mode to `auto` or `skip`.)
|
|
343
|
+
```
|
|
344
|
+
</action>
|
|
345
|
+
<action>STOP</action>
|
|
346
|
+
</check>
|
|
347
|
+
</check>
|
|
348
|
+
|
|
293
349
|
<goto step="2">Jump to execution loop with reconciled state</goto>
|
|
294
350
|
</check>
|
|
295
351
|
|
|
@@ -344,6 +400,7 @@ Resolve:
|
|
|
344
400
|
Git integration: {{git_enabled}}
|
|
345
401
|
Platform: {{platform}}
|
|
346
402
|
Session limit: {{session_story_limit}} stories, then checkpoint + new session
|
|
403
|
+
Retrospective mode: {{retrospective_mode}}
|
|
347
404
|
|
|
348
405
|
Beginning autonomous execution. I will only stop for true blockers or session checkpoints.
|
|
349
406
|
```
|
|
@@ -486,8 +543,8 @@ Resolve:
|
|
|
486
543
|
</action>
|
|
487
544
|
|
|
488
545
|
<action>**Init submodules** if needed.
|
|
489
|
-
|
|
490
|
-
If
|
|
546
|
+
First check for `.gitmodules` (use your file-exists tool, or `node -e "process.exit(require('fs').existsSync('.gitmodules')?0:1)"`). If not present, skip this step.
|
|
547
|
+
If present, run `git submodule update --init --recursive` (give it ~30 seconds). If the command fails or hangs, warn "Submodule init failed (may need auth). Continuing without." and proceed.
|
|
491
548
|
</action>
|
|
492
549
|
|
|
493
550
|
<action>Set `{{in_worktree}}` = true</action>
|
|
@@ -561,8 +618,12 @@ pr_base: {{pr_base}}
|
|
|
561
618
|
<goto step="7">Mark story done</goto>
|
|
562
619
|
</check>
|
|
563
620
|
|
|
564
|
-
<check if="{{completed_skill}}
|
|
565
|
-
<action>Log: "Epic retrospective
|
|
621
|
+
<check if="{{completed_skill}} is retrospective-auto">
|
|
622
|
+
<action>Log: "Epic retrospective generated inline by autopilot — sprint-status.yaml updated"</action>
|
|
623
|
+
</check>
|
|
624
|
+
|
|
625
|
+
<check if="{{completed_skill}} is retrospective-skip">
|
|
626
|
+
<action>Log: "Epic retrospective skipped per config — sprint-status.yaml updated inline"</action>
|
|
566
627
|
</check>
|
|
567
628
|
|
|
568
629
|
<check if="{{completed_skill}} was bmad-create-epics-and-stories">
|
|
@@ -595,17 +656,18 @@ pr_base: {{pr_base}}
|
|
|
595
656
|
<!-- GIT: Commit planning artifacts to main after planning skills -->
|
|
596
657
|
<check if="{{git_enabled}} AND {{completed_skill}} is a planning skill (bmad-create-prd, bmad-create-architecture, bmad-create-ux-design, bmad-create-epics-and-stories, bmad-sprint-planning, bmad-check-implementation-readiness, bmad-create-story)">
|
|
597
658
|
<action>**Commit planning artifacts to main** — keep track of all planning decisions in git.
|
|
598
|
-
Stage all changed artifacts:
|
|
659
|
+
Stage all changed artifacts (ignore errors — any of these paths may not yet exist):
|
|
599
660
|
```
|
|
600
|
-
git add _bmad-output/planning-artifacts/ _bmad-output/implementation-artifacts/ _bmad-output/stories/
|
|
661
|
+
git add _bmad-output/planning-artifacts/ _bmad-output/implementation-artifacts/ _bmad-output/stories/
|
|
601
662
|
```
|
|
602
|
-
|
|
663
|
+
Check if there's anything staged; if yes, commit:
|
|
603
664
|
```
|
|
604
|
-
git diff --cached --quiet
|
|
665
|
+
git diff --cached --quiet
|
|
605
666
|
```
|
|
606
|
-
|
|
667
|
+
If that exits non-zero (there are staged changes), run: `git commit -m "docs: {{completed_skill}} artifacts"`
|
|
668
|
+
Then push (log a warning if push fails; do not halt autopilot):
|
|
607
669
|
```
|
|
608
|
-
git push origin {{base_branch}}
|
|
670
|
+
git push origin {{base_branch}}
|
|
609
671
|
```
|
|
610
672
|
</action>
|
|
611
673
|
</check>
|
|
@@ -775,12 +837,12 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
775
837
|
Log warning but do NOT halt. The branch is pushed and preserved.
|
|
776
838
|
Boot reconciliation (INITIALIZATION branch reconciliation) will retry on next session.
|
|
777
839
|
|
|
778
|
-
Note: `{{merge_status}}` is persisted by the full sync-status.
|
|
840
|
+
Note: `{{merge_status}}` is persisted by the full sync-status.js call later in this step (via `--merge-status`). Do NOT call sync-status.js separately here — it does full block replacement and would destroy other fields.
|
|
779
841
|
</action>
|
|
780
842
|
<check if="{{cleanup_on_merge}} is true">
|
|
781
|
-
<action>**Cleanup worktree** for merged story — branch was merged locally, worktree is no longer needed:
|
|
843
|
+
<action>**Cleanup worktree** for merged story — branch was merged locally, worktree is no longer needed. Ignore failures from the remove (the worktree may already be gone):
|
|
782
844
|
```
|
|
783
|
-
git worktree remove .worktrees/{{current_story}} --force
|
|
845
|
+
git worktree remove .worktrees/{{current_story}} --force
|
|
784
846
|
git worktree prune
|
|
785
847
|
```
|
|
786
848
|
</action>
|
|
@@ -804,17 +866,21 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
804
866
|
This writes to `git-status.yaml` (addon-owned). Sprint-status.yaml is BMAD-owned — updated by BMAD skills only.
|
|
805
867
|
</action>
|
|
806
868
|
|
|
807
|
-
<action>**Stage and commit artifacts** — explicitly include git-status.yaml and decision-log.yaml:
|
|
869
|
+
<action>**Stage and commit artifacts** — explicitly include git-status.yaml and decision-log.yaml. Ignore errors from the `git add` (any listed path may not yet exist):
|
|
808
870
|
```
|
|
809
|
-
git add _bmad-output/implementation-artifacts/sprint-status.yaml _bmad-output/implementation-artifacts/git-status.yaml _bmad-output/implementation-artifacts/autopilot-state.yaml _bmad-output/implementation-artifacts/decision-log.yaml _bmad-output/stories/ _bmad-output/planning-artifacts/
|
|
810
|
-
|
|
811
|
-
git
|
|
871
|
+
git add _bmad-output/implementation-artifacts/sprint-status.yaml _bmad-output/implementation-artifacts/git-status.yaml _bmad-output/implementation-artifacts/autopilot-state.yaml _bmad-output/implementation-artifacts/decision-log.yaml _bmad-output/stories/ _bmad-output/planning-artifacts/
|
|
872
|
+
```
|
|
873
|
+
Check if anything is staged: `git diff --cached --quiet`. If that exits non-zero, commit:
|
|
874
|
+
`git commit -m "docs: story {{current_story}} done — {{test_count}} tests{{#if pr_url}}, PR: {{pr_url}}{{/if}}"`
|
|
875
|
+
Then push (log a warning if push fails; do not halt autopilot):
|
|
876
|
+
```
|
|
877
|
+
git push origin {{base_branch}}
|
|
812
878
|
```
|
|
813
879
|
This ensures sprint-status.yaml, git-status.yaml, story files, and any updated artifacts are on main even when story code is on a PR branch.
|
|
814
880
|
</action>
|
|
815
881
|
</check>
|
|
816
882
|
|
|
817
|
-
<!-- Story git status was already written by sync-status.
|
|
883
|
+
<!-- Story git status was already written by sync-status.js above (when git_enabled AND in_worktree).
|
|
818
884
|
sprint-status.yaml is BMAD-owned — updated by bmad-dev-story / bmad-code-review directly. -->
|
|
819
885
|
<check if="NOT {{git_enabled}}">
|
|
820
886
|
<action>Log: "Story {{current_story}} complete — BMAD dev-story updates sprint-status.yaml directly"</action>
|
|
@@ -828,10 +894,111 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
828
894
|
|
|
829
895
|
<action>Check if ALL stories in this epic are `done`</action>
|
|
830
896
|
<check if="epic complete">
|
|
831
|
-
<action>
|
|
832
|
-
<action>
|
|
833
|
-
|
|
834
|
-
|
|
897
|
+
<action>Resolve `{{epic_id}}` (e.g. "1") and `{{epic_title}}` from `{status_file}` for the current epic</action>
|
|
898
|
+
<action>Create task "[epic {{epic_id}}] retrospective" → `in_progress`</action>
|
|
899
|
+
|
|
900
|
+
<!-- Retrospective handling is driven by `autopilot.retrospective_mode`
|
|
901
|
+
in modules/autopilot/config.yaml. See the SKILL AUTOMATABLE REFERENCE
|
|
902
|
+
table for rationale. The external `bmad-retrospective` skill is
|
|
903
|
+
NEVER invoked from autopilot — it enters a multi-persona discussion
|
|
904
|
+
loop under some CLIs. -->
|
|
905
|
+
|
|
906
|
+
<check if="{{retrospective_mode}} is auto">
|
|
907
|
+
<!-- Deterministic single-pass retrospective. No persona simulation,
|
|
908
|
+
no rounds, no external skill call. All inputs are on-disk. -->
|
|
909
|
+
<action>Collect from `{status_file}` for epic `{{epic_id}}`:
|
|
910
|
+
- list of done stories with { story-key, title, test_pass_count, patch_count }
|
|
911
|
+
- epic title, start/end dates if present
|
|
912
|
+
</action>
|
|
913
|
+
<action>Collect decision-log entries for epic `{{epic_id}}` from `{decision_log_file}` (match on `story` prefix `{{epic_id}}-` or `phase: autopilot:*` entries tagged to this epic)</action>
|
|
914
|
+
<action>Identify open risks / carry-over notes from sprint-status (any story with `notes` or `risks` fields, any `workaround` decisions in the log for this epic)</action>
|
|
915
|
+
<action>Ensure directory `{implementation_artifacts}/retrospectives/` exists</action>
|
|
916
|
+
<action>Write `{implementation_artifacts}/retrospectives/epic-{{epic_id}}-retrospective.md` using this template:
|
|
917
|
+
```markdown
|
|
918
|
+
# Epic {{epic_id}} — {{epic_title}} — Retrospective
|
|
919
|
+
|
|
920
|
+
**Completed:** {current_date}
|
|
921
|
+
**Stories done:** {{n_done}}/{{n_total}}
|
|
922
|
+
|
|
923
|
+
## Stories
|
|
924
|
+
{{#each stories}}
|
|
925
|
+
- **{{story-key}}** — {{title}}
|
|
926
|
+
- Tests: {{test_pass_count}}
|
|
927
|
+
- Patches applied: {{patch_count}}
|
|
928
|
+
{{/each}}
|
|
929
|
+
|
|
930
|
+
## Key decisions
|
|
931
|
+
{{#each decisions}}
|
|
932
|
+
- [{{impact}}] {{category}}: {{decision}} — {{rationale}}
|
|
933
|
+
{{/each}}
|
|
934
|
+
|
|
935
|
+
## Risks carried forward
|
|
936
|
+
{{#each open_risks}}
|
|
937
|
+
- {{risk}}
|
|
938
|
+
{{/each}}
|
|
939
|
+
|
|
940
|
+
## Notes
|
|
941
|
+
Generated inline by Sprintpilot autopilot per `autopilot.retrospective_mode: auto`.
|
|
942
|
+
```
|
|
943
|
+
</action>
|
|
944
|
+
<action>Update `{status_file}`:
|
|
945
|
+
- `epics.{{epic_id}}.status` = `done`
|
|
946
|
+
- `epics.{{epic_id}}.retrospective_path` = the retrospective file path (relative to project root)
|
|
947
|
+
- `epics.{{epic_id}}.completed_at` = {current_date}
|
|
948
|
+
</action>
|
|
949
|
+
<action>Append decision-log entry:
|
|
950
|
+
`{ category: workaround, decision: "retrospective generated inline", rationale: "autopilot.retrospective_mode=auto — avoids external skill's multi-persona loop", impact: low, phase: autopilot:retrospective, story: "epic-{{epic_id}}" }`
|
|
951
|
+
</action>
|
|
952
|
+
<action>Mark retrospective task → `completed`</action>
|
|
953
|
+
<action>Set `{{completed_skill}}` = `retrospective-auto`</action>
|
|
954
|
+
</check>
|
|
955
|
+
|
|
956
|
+
<check if="{{retrospective_mode}} is stop">
|
|
957
|
+
<!-- Pause autopilot so user can run /bmad-retrospective interactively.
|
|
958
|
+
On the next /sprint-autopilot-on the resume logic in step 1 will
|
|
959
|
+
detect the cleared state and move to the next epic. -->
|
|
960
|
+
<action>Update `{state_file}`:
|
|
961
|
+
- `paused_at` = `epic-complete-awaiting-retrospective`
|
|
962
|
+
- `paused_epic_id` = `{{epic_id}}`
|
|
963
|
+
- `next_action` = "run /bmad-retrospective interactively for epic {{epic_id}}, then re-run /sprint-autopilot-on"
|
|
964
|
+
</action>
|
|
965
|
+
<action>Append decision-log entry:
|
|
966
|
+
`{ category: workaround, decision: "paused for interactive retrospective", rationale: "autopilot.retrospective_mode=stop", impact: low, phase: autopilot:retrospective, story: "epic-{{epic_id}}" }`
|
|
967
|
+
</action>
|
|
968
|
+
<action>Mark retrospective task → `completed` (handed off to user)</action>
|
|
969
|
+
<action>Report:
|
|
970
|
+
```
|
|
971
|
+
Autopilot paused — epic {{epic_id}} complete, retrospective handed off.
|
|
972
|
+
|
|
973
|
+
Per `autopilot.retrospective_mode: stop` in
|
|
974
|
+
_Sprintpilot/modules/autopilot/config.yaml, autopilot does not run the
|
|
975
|
+
retrospective automatically.
|
|
976
|
+
|
|
977
|
+
To continue:
|
|
978
|
+
1. Run `/bmad-retrospective` interactively for epic {{epic_id}}
|
|
979
|
+
2. When done, run `/sprint-autopilot-on` to resume with the next epic
|
|
980
|
+
|
|
981
|
+
State saved to: {state_file}
|
|
982
|
+
```
|
|
983
|
+
</action>
|
|
984
|
+
<action>STOP</action>
|
|
985
|
+
</check>
|
|
986
|
+
|
|
987
|
+
<check if="{{retrospective_mode}} is skip">
|
|
988
|
+
<!-- User opted out of retrospective. Record and move on. -->
|
|
989
|
+
<action>Update `{status_file}`:
|
|
990
|
+
- `epics.{{epic_id}}.status` = `done`
|
|
991
|
+
- `epics.{{epic_id}}.retrospective_path` = null
|
|
992
|
+
- `epics.{{epic_id}}.retrospective_skipped` = true
|
|
993
|
+
- `epics.{{epic_id}}.completed_at` = {current_date}
|
|
994
|
+
</action>
|
|
995
|
+
<action>Append decision-log entry:
|
|
996
|
+
`{ category: workaround, decision: "retrospective skipped", rationale: "autopilot.retrospective_mode=skip (NOT RECOMMENDED)", impact: medium, phase: autopilot:retrospective, story: "epic-{{epic_id}}" }`
|
|
997
|
+
</action>
|
|
998
|
+
<action>Mark retrospective task → `completed` (skipped)</action>
|
|
999
|
+
<action>Set `{{completed_skill}}` = `retrospective-skip`</action>
|
|
1000
|
+
<action>Log: "Epic {{epic_id}} retrospective skipped per config — continuing with next epic"</action>
|
|
1001
|
+
</check>
|
|
835
1002
|
|
|
836
1003
|
<!-- GIT: Epic completion — suggest merge, cleanup worktrees -->
|
|
837
1004
|
<check if="{{git_enabled}}">
|
|
@@ -917,7 +1084,7 @@ pr_base: {{pr_base}}
|
|
|
917
1084
|
`git merge <branch-ref> --no-edit`
|
|
918
1085
|
`git push origin {{base_branch}}`
|
|
919
1086
|
- If merge succeeds: update merge_status in `{git_status_file}`.
|
|
920
|
-
**IMPORTANT:** sync-status.
|
|
1087
|
+
**IMPORTANT:** sync-status.js does full block replacement — you MUST re-read the story's existing fields from `{git_status_file}` (branch, commit, patch_commits, push_status, pr_url, lint_result, worktree, platform, base_branch, worktree_cleaned) and pass ALL of them along with `--merge-status "merged"`. Omitting fields destroys them.
|
|
921
1088
|
- If merge fails: `git merge --abort`, update merge_status to "failed" in `{git_status_file}` (same full-field requirement), log warning, continue
|
|
922
1089
|
Log: "Pre-checkpoint merge: N stories verified on {{base_branch}}"
|
|
923
1090
|
</action>
|
|
@@ -999,13 +1166,14 @@ If the skill is not available or fails, generate a minimal README.md:
|
|
|
999
1166
|
|
|
1000
1167
|
<!-- GIT: Commit documentation and final artifacts to main -->
|
|
1001
1168
|
<check if="{{git_enabled}}">
|
|
1002
|
-
<action>**Commit final artifacts and documentation to main
|
|
1169
|
+
<action>**Commit final artifacts and documentation to main**. Run each step; if an early step fails, STOP and log — don't proceed past a failed step. `git add` may fail for missing optional paths (`docs/`, `README.md`); ignore those path-specific errors. Failure of the final push should log a warning but not halt autopilot:
|
|
1003
1170
|
```
|
|
1004
1171
|
git checkout -B {{base_branch}} origin/{{base_branch}}
|
|
1005
|
-
git add _bmad-output/ README.md docs/
|
|
1006
|
-
git diff --cached --quiet || git commit -m "docs: project documentation and final artifacts"
|
|
1007
|
-
git push origin {{base_branch}} 2>/dev/null || true
|
|
1172
|
+
git add _bmad-output/ README.md docs/
|
|
1008
1173
|
```
|
|
1174
|
+
Check if anything is staged: `git diff --cached --quiet`. If that exits non-zero, commit:
|
|
1175
|
+
`git commit -m "docs: project documentation and final artifacts"`
|
|
1176
|
+
Then: `git push origin {{base_branch}}`
|
|
1009
1177
|
</action>
|
|
1010
1178
|
</check>
|
|
1011
1179
|
|
|
@@ -1035,8 +1203,8 @@ If the skill is not available or fails, generate a minimal README.md:
|
|
|
1035
1203
|
<check if="{{git_enabled}}">
|
|
1036
1204
|
<action>**Cleanup all remaining worktrees**:
|
|
1037
1205
|
Run: `git worktree list --porcelain`
|
|
1038
|
-
For each worktree that is NOT the main worktree:
|
|
1039
|
-
`git worktree remove <path> --force
|
|
1206
|
+
For each worktree that is NOT the main worktree, run the following — log and continue on failure; some worktrees may already be gone:
|
|
1207
|
+
`git worktree remove <path> --force`
|
|
1040
1208
|
Then: `git worktree prune`
|
|
1041
1209
|
</action>
|
|
1042
1210
|
</check>
|
|
@@ -19,28 +19,35 @@ Scan the project at `{{project_root}}` and write your findings to `{{output_file
|
|
|
19
19
|
- `*.key`, `*.pem`, `*.p12` (private keys)
|
|
20
20
|
- `credentials.json`, `service-account.json`
|
|
21
21
|
|
|
22
|
-
## Exploration
|
|
22
|
+
## Exploration
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
# Top-level structure
|
|
26
|
-
ls -la
|
|
27
|
-
find . -maxdepth 2 -type d -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/vendor/*' | head -50
|
|
24
|
+
Use your native file tools (Read, Glob, Grep). The lists below describe what data to collect; pick the appropriate tool for your CLI.
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
### Top-level structure
|
|
27
|
+
Glob the root for directories and files (exclude `node_modules`, `.git`, `vendor`, `target`, `dist`, `build`). Look 1-2 levels deep to understand the layout.
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
### Entry points
|
|
30
|
+
Read whichever of these exist: `index.ts`, `index.js`, `main.py`, `main.go`, `cmd/main.go`, `src/main.rs`, `lib/main.rb`, `app.py`, `manage.py`, `main.c`, `main.cpp`, `src/main.c`, `src/main.cpp`. 30 lines is usually enough to identify the entry path.
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
### Route definitions
|
|
33
|
+
Use Grep to find route declarations across `*.ts`, `*.js`, `*.py`, `*.java`, `*.go`, `*.xml`, C/C++ headers. Pattern set:
|
|
34
|
+
```
|
|
35
|
+
router\.|app\.(get|post|put|delete|patch)|@app\.route|@Controller|@RequestMapping|CROW_ROUTE|CPPREST_|Pistache::
|
|
36
|
+
```
|
|
37
|
+
Limit to ~30 matches.
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
### Module exports / barrel files
|
|
40
|
+
Use Glob for: `**/index.ts`, `**/index.js`, `**/__init__.py`, `**/mod.rs`. Cap at ~20 hits.
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
### Import patterns (what depends on what)
|
|
43
|
+
Use Grep to find import/require/include lines across `*.ts`, `*.js`, `*.py`, `*.sh`, C/C++ sources:
|
|
43
44
|
```
|
|
45
|
+
^import|^from|require\(|source |^\.|^#include
|
|
46
|
+
```
|
|
47
|
+
Scan the top ~100 matches and note frequent dependencies. (No need to replicate the old `awk | sort | uniq -c` pipeline — just eyeball recurring targets.)
|
|
48
|
+
|
|
49
|
+
### Configuration loading
|
|
50
|
+
Use Grep (files-with-matches mode) for `config|CONFIG|Settings|settings` across config-bearing file types. Limit to ~10 files.
|
|
44
51
|
|
|
45
52
|
Read entry point files, follow the import chain 2-3 levels deep to understand request flow.
|
|
46
53
|
|
|
@@ -20,42 +20,65 @@ Scan the project at `{{project_root}}` and write your findings to `{{output_file
|
|
|
20
20
|
- `credentials.json`, `service-account.json`
|
|
21
21
|
- Files in `.git/` directory
|
|
22
22
|
|
|
23
|
-
## Exploration
|
|
23
|
+
## Exploration
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
# TODOs, FIXMEs, HACKs
|
|
27
|
-
grep -rn 'TODO\|FIXME\|HACK\|XXX\|WORKAROUND\|TEMP\|DEPRECATED' --include='*.ts' --include='*.js' --include='*.py' --include='*.go' --include='*.java' --include='*.rs' --include='*.rb' --include='*.cs' --include='*.sql' --include='*.sps' --include='*.spb' --include='*.xml' --include='*.sh' --include='*.c' --include='*.h' --include='*.cpp' --include='*.hpp' --include='*.cc' --include='*.cxx' --include='*.hxx' | head -50
|
|
25
|
+
Use Grep for pattern searches and `scan.js` for aggregations. All Grep calls below should filter to code file types (e.g., `*.ts`, `*.js`, `*.py`, `*.java`, `*.go`, `*.rs`, `*.rb`, `*.cs`, `*.sql`, `*.sps`, `*.spb`, `*.xml`, `*.sh`, `*.c`, `*.h`, `*.cpp`, `*.hpp`, `*.cc`, `*.cxx`, `*.hxx`) and cap each result set (~20-50).
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
### TODOs, FIXMEs, HACKs
|
|
28
|
+
Grep for: `TODO|FIXME|HACK|XXX|WORKAROUND|TEMP|DEPRECATED`. Limit ~50.
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
### Security: hardcoded secrets
|
|
31
|
+
Grep (case-insensitive) for: `password\s*=\s*["']|api_key\s*=\s*["']|secret\s*=\s*["']|token\s*=\s*["']`. Exclude matches under `node_modules/`, `test*`, `spec*`, `*mock*`, `*fixture*`, `.env.example`. Limit ~20.
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
### Security: dangerous runtime sinks
|
|
34
|
+
Grep for these high-risk call sites (code-exec and XSS patterns). The tokens below are split to avoid security-hook false positives on this documentation file — when building your regex, join them with `|` and concatenate the split tokens exactly as indicated.
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
grep -rn 'strcpy(\|strcat(\|sprintf(\|gets(\|scanf(.*%s[^0-9]\|system(\|popen(' --include='*.c' --include='*.h' --include='*.cpp' --include='*.hpp' --include='*.cc' --include='*.cxx' --include='*.hxx' | head -20
|
|
36
|
+
Literal regex tokens (already properly escaped):
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
- `eval\(`
|
|
39
|
+
- `exec\(`
|
|
40
|
+
- `innerHTML\s*=`
|
|
41
|
+
- `__import__`
|
|
42
|
+
- `yaml\.load\(`
|
|
43
|
+
- `EXECUTE IMMEDIATE`
|
|
44
|
+
- `DBMS_SQL`
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
grep -rn '^\s*//.*function\|^\s*//.*class\|^\s*//.*const\|^\s*#.*def\|^\s*#.*class\|^\s*--.*PROCEDURE\|^\s*--.*FUNCTION\|^\s*--.*PACKAGE\|^\s*//.*struct\|^\s*//.*typedef\|^\s*/\*.*struct\|^\s*/\*.*typedef' --include='*.ts' --include='*.js' --include='*.py' --include='*.sql' --include='*.sps' --include='*.spb' --include='*.sh' --include='*.c' --include='*.h' --include='*.cpp' --include='*.hpp' --include='*.cc' --include='*.cxx' --include='*.hxx' | head -20
|
|
46
|
+
Split tokens — concatenate the two halves verbatim, then escape the resulting literal dot:
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
- `dangerously` + `SetInnerHTML` → final regex literal `dangerouslySetInnerHTML`
|
|
49
|
+
- `pick` + `le.load` → final regex literal `pickle\.load` (note the escaped dot)
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
find . -type f \( -name '*.ts' -o -name '*.js' -o -name '*.py' -o -name '*.java' -o -name '*.sql' -o -name '*.sps' -o -name '*.spb' -o -name '*.xml' -o -name '*.sh' -o -name '*.c' -o -name '*.h' -o -name '*.cpp' -o -name '*.hpp' -o -name '*.cc' -o -name '*.cxx' -o -name '*.hxx' \) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | sort -rn | head -10
|
|
51
|
+
Run the search case-sensitively across the code-file types listed above. Limit ~20.
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
### SQL injection risk
|
|
54
|
+
Grep across `*.ts`, `*.js`, `*.py`, `*.java`, `*.xml` for: `query.*\$\{|query.*%s|query.*format|execute.*f"|query.*\+`. Limit ~20.
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
### C/C++ unsafe string / memory functions
|
|
57
|
+
Grep across C/C++ files only for: `strcpy\(|strcat\(|sprintf\(|gets\(|scanf\(.*%s[^0-9]|system\(|popen\(`. Limit ~20.
|
|
58
|
+
|
|
59
|
+
### Dead code: unused-import candidates
|
|
60
|
+
Grep for `^import.*from` across `*.ts`, `*.js`, `*.py` and eyeball the top imports. A full frequency rollup is not required — cite notable duplicates.
|
|
61
|
+
|
|
62
|
+
### Commented-out code blocks
|
|
63
|
+
Grep for:
|
|
64
|
+
```
|
|
65
|
+
^\s*//.*(function|class|const|struct|typedef)|^\s*#.*(def|class)|^\s*--.*(PROCEDURE|FUNCTION|PACKAGE)|^\s*/\*.*(struct|typedef)
|
|
58
66
|
```
|
|
67
|
+
Limit ~20.
|
|
68
|
+
|
|
69
|
+
### Complexity: deeply nested code
|
|
70
|
+
Grep for lines starting with 16+ spaces: `^\s{16,}`. Limit ~10 (sample).
|
|
71
|
+
|
|
72
|
+
### Large files (complexity hotspots)
|
|
73
|
+
```
|
|
74
|
+
node "{{project_root}}/_Sprintpilot/scripts/scan.js" largest --include "*.ts,*.js,*.py,*.java,*.cs,*.go,*.rs,*.rb,*.sql,*.sps,*.spb,*.xml,*.sh,*.c,*.h,*.cpp,*.hpp,*.cc,*.cxx,*.hxx" --root "{{project_root}}" --limit 10
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Deprecated package warnings
|
|
78
|
+
Read `package.json` if present and check for `deprecated|legacy|old` (case-insensitive).
|
|
79
|
+
|
|
80
|
+
### Error handling: bare catches
|
|
81
|
+
Grep for: `catch\s*\(|except:|except Exception|rescue$|EXCEPTION\s*$|WHEN OTHERS|catch\s*\(\.\.\.\)`. Limit ~20.
|
|
59
82
|
|
|
60
83
|
## Downstream Consumers
|
|
61
84
|
|
|
@@ -21,36 +21,36 @@ Scan the project at `{{project_root}}` and write your findings to `{{output_file
|
|
|
21
21
|
|
|
22
22
|
**DO read**: `.env.example`, `.env.sample`, `.env.template` (safe — contain variable names only)
|
|
23
23
|
|
|
24
|
-
## Exploration
|
|
24
|
+
## Exploration
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
# Environment variables referenced in code
|
|
28
|
-
grep -rn 'process\.env\.\|os\.environ\|os\.getenv\|ENV\[\|\${\|export \|getenv(' --include='*.ts' --include='*.js' --include='*.py' --include='*.rb' --include='*.go' --include='*.sh' --include='*.c' --include='*.h' --include='*.cpp' --include='*.hpp' --include='*.cc' --include='*.cxx' --include='*.hxx' | sed 's/.*\(process\.env\.[A-Z_]*\|os\.environ\[['"'"'"]\?\([A-Z_]*\)\|os\.getenv(\([A-Z_]*\)\|ENV\[\([A-Z_]*\)\|getenv("\?\([A-Z_]*\)\).*/\1/' | sort -u | head -30
|
|
26
|
+
Use Grep and Read. Below are the patterns to search for — file-type filters match the original language coverage (`*.ts`, `*.js`, `*.py`, `*.rb`, `*.go`, `*.rs`, `*.java`, `*.sh`, `*.c`, `*.h`, `*.cpp`, `*.hpp`, `*.cc`, `*.cxx`, `*.hxx`, `*.sql`, `*.sps`, `*.spb`, `*.xml`). Cap each result set (~15-30 matches).
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
### Environment variables referenced in code
|
|
29
|
+
Grep for: `process\.env\.|os\.environ|os\.getenv|ENV\[|\$\{|export |getenv\(`. Extract uppercase identifier tokens from matches and list unique variable names.
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
### .env.example (safe to read — template only)
|
|
32
|
+
Read whichever exist: `.env.example`, `.env.sample`, `.env.template`.
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
### HTTP client usage
|
|
35
|
+
Grep for: `fetch\(|axios\.|requests\.|http\.Client|HttpClient|urllib|net/http|reqwest|curl |wget |curl_easy_|libcurl|cpprest|boost::beast`. Limit ~20.
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
### Database connections
|
|
38
|
+
Grep (files-with-matches) for: `createConnection|createPool|mongoose\.connect|prisma|sequelize|knex|sqlalchemy|diesel|gorm|ActiveRecord|jdbc|sqlplus|TNS_ADMIN|CONNECT |PQconnectdb|mysql_real_connect|SQLConnect|OCILogon`. Limit ~10 files.
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
### Message queue / event usage
|
|
41
|
+
Grep (case-insensitive) for: `kafka|rabbitmq|amqp|sqs|sns|pubsub|redis.*pub|redis.*sub|bull|BullMQ|celery|sidekiq|AQ$|DBMS_AQ|librdkafka|cppkafka|zmq_`. Limit ~15.
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
### Cloud SDK usage
|
|
44
|
+
Grep (files-with-matches) for: `aws-sdk|@aws-sdk|boto3|google-cloud|@google-cloud|azure|@azure|aws/core|Aws::|google::cloud`. Limit ~10.
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
### OAuth / Auth providers
|
|
47
|
+
Grep (case-insensitive) across `*.ts`, `*.js`, `*.py`, `*.xml` for: `oauth|passport|auth0|firebase.*auth|cognito|supabase.*auth|clerk|next-auth|lucia`. Limit ~15.
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
### Third-party SaaS SDKs
|
|
50
|
+
Grep (files-with-matches, case-insensitive) for: `stripe|sendgrid|twilio|sentry|datadog|segment|amplitude|mixpanel|intercom|slack`. Limit ~10.
|
|
51
|
+
|
|
52
|
+
### Docker-compose services
|
|
53
|
+
Read `docker-compose*.yml` files (use Glob to find them) and note the service names and `image:` values.
|
|
54
54
|
|
|
55
55
|
## Downstream Consumers
|
|
56
56
|
|