@ikunin/sprintpilot 1.0.1 → 1.0.3
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 +2 -2
- package/_Sprintpilot/lib/runtime/args.js +0 -2
- package/_Sprintpilot/lib/runtime/git.js +0 -2
- package/_Sprintpilot/lib/runtime/http.js +12 -5
- package/_Sprintpilot/lib/runtime/log.js +0 -2
- package/_Sprintpilot/lib/runtime/secrets.js +14 -16
- package/_Sprintpilot/lib/runtime/spawn.js +21 -8
- package/_Sprintpilot/lib/runtime/text.js +0 -2
- package/_Sprintpilot/lib/runtime/yaml-lite.js +9 -5
- package/_Sprintpilot/manifest.yaml +1 -1
- package/_Sprintpilot/scripts/create-pr.js +76 -38
- package/_Sprintpilot/scripts/detect-platform.js +35 -10
- package/_Sprintpilot/scripts/health-check.js +17 -8
- package/_Sprintpilot/scripts/lint-changed.js +35 -16
- package/_Sprintpilot/scripts/lock.js +22 -6
- package/_Sprintpilot/scripts/sanitize-branch.js +4 -2
- package/_Sprintpilot/scripts/scan.js +457 -0
- package/_Sprintpilot/scripts/stage-and-commit.js +15 -7
- package/_Sprintpilot/scripts/sync-status.js +16 -6
- package/_Sprintpilot/skills/sprint-autopilot-on/workflow.md +62 -31
- 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/bin/sprintpilot.js +11 -4
- package/lib/commands/check-update.js +0 -2
- package/lib/commands/install.js +139 -49
- package/lib/commands/uninstall.js +21 -11
- package/lib/core/bmad-config.js +0 -2
- package/lib/core/file-ops.js +6 -6
- package/lib/core/gitignore.js +0 -2
- package/lib/core/markers.js +5 -3
- package/lib/core/tool-registry.js +19 -21
- package/lib/core/update-check.js +0 -2
- package/lib/core/v1-detect.js +0 -2
- package/lib/prompts.js +0 -2
- package/lib/substitute.js +1 -5
- package/package.json +1 -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
|
|
@@ -170,7 +188,9 @@ Resolve:
|
|
|
170
188
|
<check if="not a git repo">
|
|
171
189
|
<action>HALT: "No git repository found. Initialize one first:
|
|
172
190
|
```
|
|
173
|
-
git init
|
|
191
|
+
git init
|
|
192
|
+
git add -A
|
|
193
|
+
git commit -m 'initial commit'
|
|
174
194
|
git remote add origin <your-repo-url>
|
|
175
195
|
```
|
|
176
196
|
Then run /sprint-autopilot-on again."</action>
|
|
@@ -201,15 +221,20 @@ Resolve:
|
|
|
201
221
|
- COMMITTED: log "Recoverable work found for <name> — will push via git -C"
|
|
202
222
|
Push the branch: `git -C .worktrees/<name> push -u origin <branch> 2>&1`
|
|
203
223
|
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
|
|
224
|
+
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**:
|
|
225
|
+
1. `git checkout -B {{base_branch}} origin/{{base_branch}}`
|
|
226
|
+
2. `git merge <branch> --no-edit`
|
|
227
|
+
3. `git push origin {{base_branch}}`
|
|
205
228
|
Then remove worktree.
|
|
206
229
|
- STALE: `git worktree remove .worktrees/<name> --force` + prune
|
|
207
230
|
- DIRTY: warn user, ask how to proceed (stash/commit/discard)
|
|
208
|
-
- ORPHAN: `
|
|
231
|
+
- ORPHAN: remove the directory cross-platform with `node -e "require('fs').rmSync('.worktrees/<name>', {recursive: true, force: true})"`, then `git worktree prune`
|
|
209
232
|
</action>
|
|
210
233
|
|
|
211
234
|
<action>**Branch reconciliation** — detect pushed-but-unmerged story branches.
|
|
212
|
-
Run
|
|
235
|
+
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**:
|
|
236
|
+
1. `git fetch origin`
|
|
237
|
+
2. `git branch -r --list "origin/{{branch_prefix}}*"`
|
|
213
238
|
For each remote branch:
|
|
214
239
|
- Extract story-key from branch name (strip "origin/{{branch_prefix}}" prefix)
|
|
215
240
|
- Look up story status in `{status_file}`
|
|
@@ -226,16 +251,16 @@ Resolve:
|
|
|
226
251
|
- If merge fails: log warning, continue (branch is preserved on remote)
|
|
227
252
|
- If merge succeeds:
|
|
228
253
|
- 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.
|
|
254
|
+
- Update `{git_status_file}` via sync-status.js: set `--merge-status "recovered"` for this story.
|
|
255
|
+
**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
256
|
- If `{{platform}}` is NOT git_only (github, gitlab, bitbucket, gitea) AND `{{create_pr}}` is true:
|
|
232
257
|
- Check if PR/MR already exists for this branch (platform-specific check via create-pr.sh or CLI)
|
|
233
258
|
- If no PR: create one via `node {{project_root}}/_Sprintpilot/scripts/create-pr.js --platform {{platform}} ...`
|
|
234
259
|
- Log: "PR created/found for <story-key>"
|
|
235
|
-
- Update `{git_status_file}` via sync-status.
|
|
260
|
+
- Update `{git_status_file}` via sync-status.js: set `--merge-status "pr_pending"` for this story (same full-field requirement as above)
|
|
236
261
|
- If status IS "done" AND branch still exists AND `{{cleanup_on_merge}}` is true:
|
|
237
262
|
- Log: "Stale remote branch: <branch> — story already done, cleaning up"
|
|
238
|
-
- Delete remote branch: `git push origin --delete <branch
|
|
263
|
+
- Delete remote branch (ignore failure — the branch may already be gone): `git push origin --delete <branch>`
|
|
239
264
|
</action>
|
|
240
265
|
|
|
241
266
|
<action>Set `{{git_enabled}}` = true, `{{platform}}` = detected value</action>
|
|
@@ -486,8 +511,8 @@ Resolve:
|
|
|
486
511
|
</action>
|
|
487
512
|
|
|
488
513
|
<action>**Init submodules** if needed.
|
|
489
|
-
|
|
490
|
-
If
|
|
514
|
+
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.
|
|
515
|
+
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
516
|
</action>
|
|
492
517
|
|
|
493
518
|
<action>Set `{{in_worktree}}` = true</action>
|
|
@@ -595,17 +620,18 @@ pr_base: {{pr_base}}
|
|
|
595
620
|
<!-- GIT: Commit planning artifacts to main after planning skills -->
|
|
596
621
|
<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
622
|
<action>**Commit planning artifacts to main** — keep track of all planning decisions in git.
|
|
598
|
-
Stage all changed artifacts:
|
|
623
|
+
Stage all changed artifacts (ignore errors — any of these paths may not yet exist):
|
|
599
624
|
```
|
|
600
|
-
git add _bmad-output/planning-artifacts/ _bmad-output/implementation-artifacts/ _bmad-output/stories/
|
|
625
|
+
git add _bmad-output/planning-artifacts/ _bmad-output/implementation-artifacts/ _bmad-output/stories/
|
|
601
626
|
```
|
|
602
|
-
|
|
627
|
+
Check if there's anything staged; if yes, commit:
|
|
603
628
|
```
|
|
604
|
-
git diff --cached --quiet
|
|
629
|
+
git diff --cached --quiet
|
|
605
630
|
```
|
|
606
|
-
|
|
631
|
+
If that exits non-zero (there are staged changes), run: `git commit -m "docs: {{completed_skill}} artifacts"`
|
|
632
|
+
Then push (log a warning if push fails; do not halt autopilot):
|
|
607
633
|
```
|
|
608
|
-
git push origin {{base_branch}}
|
|
634
|
+
git push origin {{base_branch}}
|
|
609
635
|
```
|
|
610
636
|
</action>
|
|
611
637
|
</check>
|
|
@@ -775,12 +801,12 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
775
801
|
Log warning but do NOT halt. The branch is pushed and preserved.
|
|
776
802
|
Boot reconciliation (INITIALIZATION branch reconciliation) will retry on next session.
|
|
777
803
|
|
|
778
|
-
Note: `{{merge_status}}` is persisted by the full sync-status.
|
|
804
|
+
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
805
|
</action>
|
|
780
806
|
<check if="{{cleanup_on_merge}} is true">
|
|
781
|
-
<action>**Cleanup worktree** for merged story — branch was merged locally, worktree is no longer needed:
|
|
807
|
+
<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
808
|
```
|
|
783
|
-
git worktree remove .worktrees/{{current_story}} --force
|
|
809
|
+
git worktree remove .worktrees/{{current_story}} --force
|
|
784
810
|
git worktree prune
|
|
785
811
|
```
|
|
786
812
|
</action>
|
|
@@ -804,17 +830,21 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
804
830
|
This writes to `git-status.yaml` (addon-owned). Sprint-status.yaml is BMAD-owned — updated by BMAD skills only.
|
|
805
831
|
</action>
|
|
806
832
|
|
|
807
|
-
<action>**Stage and commit artifacts** — explicitly include git-status.yaml and decision-log.yaml:
|
|
833
|
+
<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):
|
|
834
|
+
```
|
|
835
|
+
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/
|
|
836
|
+
```
|
|
837
|
+
Check if anything is staged: `git diff --cached --quiet`. If that exits non-zero, commit:
|
|
838
|
+
`git commit -m "docs: story {{current_story}} done — {{test_count}} tests{{#if pr_url}}, PR: {{pr_url}}{{/if}}"`
|
|
839
|
+
Then push (log a warning if push fails; do not halt autopilot):
|
|
808
840
|
```
|
|
809
|
-
git
|
|
810
|
-
git diff --cached --quiet || git commit -m "docs: story {{current_story}} done — {{test_count}} tests{{#if pr_url}}, PR: {{pr_url}}{{/if}}"
|
|
811
|
-
git push origin {{base_branch}} 2>/dev/null || true
|
|
841
|
+
git push origin {{base_branch}}
|
|
812
842
|
```
|
|
813
843
|
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
844
|
</action>
|
|
815
845
|
</check>
|
|
816
846
|
|
|
817
|
-
<!-- Story git status was already written by sync-status.
|
|
847
|
+
<!-- Story git status was already written by sync-status.js above (when git_enabled AND in_worktree).
|
|
818
848
|
sprint-status.yaml is BMAD-owned — updated by bmad-dev-story / bmad-code-review directly. -->
|
|
819
849
|
<check if="NOT {{git_enabled}}">
|
|
820
850
|
<action>Log: "Story {{current_story}} complete — BMAD dev-story updates sprint-status.yaml directly"</action>
|
|
@@ -917,7 +947,7 @@ pr_base: {{pr_base}}
|
|
|
917
947
|
`git merge <branch-ref> --no-edit`
|
|
918
948
|
`git push origin {{base_branch}}`
|
|
919
949
|
- If merge succeeds: update merge_status in `{git_status_file}`.
|
|
920
|
-
**IMPORTANT:** sync-status.
|
|
950
|
+
**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
951
|
- If merge fails: `git merge --abort`, update merge_status to "failed" in `{git_status_file}` (same full-field requirement), log warning, continue
|
|
922
952
|
Log: "Pre-checkpoint merge: N stories verified on {{base_branch}}"
|
|
923
953
|
</action>
|
|
@@ -999,13 +1029,14 @@ If the skill is not available or fails, generate a minimal README.md:
|
|
|
999
1029
|
|
|
1000
1030
|
<!-- GIT: Commit documentation and final artifacts to main -->
|
|
1001
1031
|
<check if="{{git_enabled}}">
|
|
1002
|
-
<action>**Commit final artifacts and documentation to main
|
|
1032
|
+
<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
1033
|
```
|
|
1004
1034
|
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
|
|
1035
|
+
git add _bmad-output/ README.md docs/
|
|
1008
1036
|
```
|
|
1037
|
+
Check if anything is staged: `git diff --cached --quiet`. If that exits non-zero, commit:
|
|
1038
|
+
`git commit -m "docs: project documentation and final artifacts"`
|
|
1039
|
+
Then: `git push origin {{base_branch}}`
|
|
1009
1040
|
</action>
|
|
1010
1041
|
</check>
|
|
1011
1042
|
|
|
@@ -1035,8 +1066,8 @@ If the skill is not available or fails, generate a minimal README.md:
|
|
|
1035
1066
|
<check if="{{git_enabled}}">
|
|
1036
1067
|
<action>**Cleanup all remaining worktrees**:
|
|
1037
1068
|
Run: `git worktree list --porcelain`
|
|
1038
|
-
For each worktree that is NOT the main worktree:
|
|
1039
|
-
`git worktree remove <path> --force
|
|
1069
|
+
For each worktree that is NOT the main worktree, run the following — log and continue on failure; some worktrees may already be gone:
|
|
1070
|
+
`git worktree remove <path> --force`
|
|
1040
1071
|
Then: `git worktree prune`
|
|
1041
1072
|
</action>
|
|
1042
1073
|
</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
|
|
|
@@ -19,35 +19,47 @@ 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
|
-
# Test framework detection
|
|
26
|
-
cat jest.config* vitest.config* pytest.ini setup.cfg pyproject.toml .rspec Cargo.toml 2>/dev/null | grep -i 'test\|jest\|pytest\|mocha\|vitest\|rspec'
|
|
24
|
+
Use your native file tools (Read, Glob, Grep) plus the `scan.js` helper for aggregations.
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
echo "Source files:" && find . -type f \( -name '*.ts' -o -name '*.js' -o -name '*.py' -o -name '*.go' -o -name '*.rs' -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/*' -not -path '*/test*' -not -name '*.test.*' -not -name '*.spec.*' | wc -l
|
|
26
|
+
### Test framework detection
|
|
27
|
+
Read if present: `jest.config*`, `vitest.config*`, `pytest.ini`, `setup.cfg`, `pyproject.toml`, `.rspec`, `Cargo.toml`. Grep each for `test|jest|pytest|mocha|vitest|rspec` (case-insensitive).
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
### Test file count
|
|
30
|
+
```
|
|
31
|
+
node "{{project_root}}/_Sprintpilot/scripts/scan.js" files --include "*.test.*,*.spec.*,test_*,*_test.*" --root "{{project_root}}" --count
|
|
32
|
+
```
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
### Source file count
|
|
35
|
+
```
|
|
36
|
+
node "{{project_root}}/_Sprintpilot/scripts/scan.js" files --include "*.ts,*.js,*.py,*.go,*.rs,*.java,*.sql,*.sps,*.spb,*.xml,*.sh,*.c,*.h,*.cpp,*.hpp,*.cc,*.cxx,*.hxx" --exclude "**/test/**,**/tests/**,**/__tests__/**,**/spec/**,*.test.*,*.spec.*,*_test.*,test_*" --root "{{project_root}}" --count
|
|
37
|
+
```
|
|
38
|
+
(The `scan.js` helper automatically also excludes `node_modules`, `.git`, `vendor`, `dist`, `build`, etc.)
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
### Test types present
|
|
41
|
+
Use Glob for `**/e2e/**`, `**/integration/**`, `**/unit/**`, `*.e2e.*`, `*.integration.*`. First ~10 hits are enough.
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
### CI/CD configuration
|
|
44
|
+
Read if present: `.github/workflows/*.yml` (use Glob to list them first), `.gitlab-ci.yml`, `Jenkinsfile`, `azure-pipelines.yml`, `.circleci/config.yml`, `.travis.yml`. 80 lines each is usually enough.
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
### Linting & formatting config
|
|
47
|
+
Use Glob to list: `.eslintrc*`, `.prettierrc*`, `.editorconfig`, `.rubocop.yml`, `.flake8`, `pyproject.toml`, `rustfmt.toml`, `.golangci.yml`, `biome.json`, `.sqlfluff*`.
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
### Code metrics (total LOC)
|
|
50
|
+
```
|
|
51
|
+
node "{{project_root}}/_Sprintpilot/scripts/scan.js" loc --include "*.ts,*.js,*.py,*.go,*.rs,*.java,*.sql,*.sps,*.spb,*.xml,*.sh,*.c,*.h,*.cpp,*.hpp,*.cc,*.cxx,*.hxx" --root "{{project_root}}"
|
|
50
52
|
```
|
|
53
|
+
Output is tab-separated `<total-lines>\t<file-count>`.
|
|
54
|
+
|
|
55
|
+
### Largest files (complexity hotspots)
|
|
56
|
+
```
|
|
57
|
+
node "{{project_root}}/_Sprintpilot/scripts/scan.js" largest --include "*.ts,*.js,*.py,*.sql,*.sps,*.spb,*.sh,*.c,*.h,*.cpp,*.hpp,*.cc,*.cxx,*.hxx" --root "{{project_root}}" --limit 10
|
|
58
|
+
```
|
|
59
|
+
Output: `<lines>\t<path>`, descending.
|
|
60
|
+
|
|
61
|
+
### Coverage
|
|
62
|
+
Read `.nycrc`, `.istanbul.yml`, `jest.config*`, `vitest.config*` if present and grep for `cover`. Use Glob to check for `coverage/`, `htmlcov/`, `.coverage` directories/files.
|
|
51
63
|
|
|
52
64
|
## Downstream Consumers
|
|
53
65
|
|
|
@@ -69,8 +81,8 @@ Write to `{{output_file}}`:
|
|
|
69
81
|
| Metric | Value | Evidence |
|
|
70
82
|
|--------|-------|----------|
|
|
71
83
|
| Test framework | Jest 29.7 | jest.config.ts:1 |
|
|
72
|
-
| Test files | 45 |
|
|
73
|
-
| Source files | 120 |
|
|
84
|
+
| Test files | 45 | scan.js files --include ... --count |
|
|
85
|
+
| Source files | 120 | scan.js files --include ... --count |
|
|
74
86
|
| Test:Source ratio | 1:2.7 | Calculated |
|
|
75
87
|
| Test types present | unit, integration | directory structure |
|
|
76
88
|
| Test types missing | e2e, snapshot | No e2e/ directory found |
|
|
@@ -20,50 +20,48 @@ Scan the project at `{{project_root}}` and write your findings to `{{output_file
|
|
|
20
20
|
- `credentials.json`, `service-account.json`
|
|
21
21
|
- `*.secret`, `*password*`, `*token*` (in filenames)
|
|
22
22
|
|
|
23
|
-
## Exploration
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
# C / C++ manifests
|
|
44
|
-
ls -la *.c *.h *.cpp *.hpp *.cc *.cxx *.hxx 2>/dev/null | head -10
|
|
45
|
-
find . -type f \( -name '*.c' -o -name '*.h' -o -name '*.cpp' -o -name '*.hpp' -o -name '*.cc' -o -name '*.cxx' -o -name '*.hxx' \) -not -path '*/.git/*' 2>/dev/null | wc -l
|
|
46
|
-
cat CMakeLists.txt configure.ac conanfile.txt vcpkg.json 2>/dev/null | head -20
|
|
47
|
-
|
|
48
|
-
# Lockfiles (versions)
|
|
49
|
-
head -100 package-lock.json 2>/dev/null || head -100 yarn.lock 2>/dev/null || head -100 pnpm-lock.yaml 2>/dev/null
|
|
50
|
-
|
|
51
|
-
# Runtime versions
|
|
52
|
-
cat .nvmrc .node-version .python-version .ruby-version .tool-versions 2>/dev/null
|
|
53
|
-
cat rust-toolchain.toml 2>/dev/null
|
|
54
|
-
|
|
55
|
-
# File type distribution
|
|
56
|
-
find . -type f -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/vendor/*' -not -path '*/target/*' | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -20
|
|
57
|
-
|
|
58
|
-
# Build tools
|
|
59
|
-
ls -la webpack.config* vite.config* rollup.config* tsconfig* babel.config* .babelrc Makefile CMakeLists.txt build.gradle* pom.xml *.sln *.xml 2>/dev/null
|
|
60
|
-
|
|
61
|
-
# Infrastructure
|
|
62
|
-
ls -la Dockerfile* docker-compose* .dockerignore 2>/dev/null
|
|
63
|
-
ls -la terraform/ cdk.json serverless.yml k8s/ kubernetes/ helm/ 2>/dev/null
|
|
23
|
+
## Exploration
|
|
24
|
+
|
|
25
|
+
Gather data using your native file tools (Read, Glob, Grep). The commands below are illustrative — use the equivalent tool from your CLI. Skip files that don't exist; do not fail the task on missing manifests.
|
|
26
|
+
|
|
27
|
+
### Package manifests
|
|
28
|
+
Read each of these if present (top 100 lines is enough for most):
|
|
29
|
+
`package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `Gemfile`, `pom.xml`, `build.gradle`, any `*.csproj`.
|
|
30
|
+
|
|
31
|
+
### Database / PL/SQL manifests
|
|
32
|
+
Read `tnsnames.ora`, `sqlnet.ora` if present.
|
|
33
|
+
Count SQL / PL-SQL files:
|
|
34
|
+
```
|
|
35
|
+
node "{{project_root}}/_Sprintpilot/scripts/scan.js" files --include "*.sql,*.sps,*.spb" --root "{{project_root}}" --count
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### C / C++ manifests
|
|
39
|
+
Read `CMakeLists.txt`, `configure.ac`, `conanfile.txt`, `vcpkg.json` if present.
|
|
40
|
+
Count C/C++ files:
|
|
41
|
+
```
|
|
42
|
+
node "{{project_root}}/_Sprintpilot/scripts/scan.js" files --include "*.c,*.h,*.cpp,*.hpp,*.cc,*.cxx,*.hxx" --root "{{project_root}}" --count
|
|
64
43
|
```
|
|
65
44
|
|
|
66
|
-
|
|
45
|
+
### Lockfiles (versions)
|
|
46
|
+
Read the first ~100 lines of whichever is present: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.
|
|
47
|
+
|
|
48
|
+
### Runtime versions
|
|
49
|
+
Read if present: `.nvmrc`, `.node-version`, `.python-version`, `.ruby-version`, `.tool-versions`, `rust-toolchain.toml`.
|
|
50
|
+
|
|
51
|
+
### File type distribution
|
|
52
|
+
```
|
|
53
|
+
node "{{project_root}}/_Sprintpilot/scripts/scan.js" extensions --root "{{project_root}}" --limit 20
|
|
54
|
+
```
|
|
55
|
+
Output is tab-separated `<count>\t<extension>`, descending.
|
|
56
|
+
|
|
57
|
+
### Build tools
|
|
58
|
+
Use Glob to list if present: `webpack.config*`, `vite.config*`, `rollup.config*`, `tsconfig*`, `babel.config*`, `.babelrc`, `Makefile`, `CMakeLists.txt`, `build.gradle*`, `pom.xml`, `*.sln`.
|
|
59
|
+
|
|
60
|
+
### Infrastructure
|
|
61
|
+
Use Glob to list if present: `Dockerfile*`, `docker-compose*`, `.dockerignore`.
|
|
62
|
+
Check for directories: `terraform/`, `k8s/`, `kubernetes/`, `helm/`. Read `cdk.json`, `serverless.yml` if present.
|
|
63
|
+
|
|
64
|
+
Use Glob and Grep to find patterns not covered above.
|
|
67
65
|
|
|
68
66
|
## Downstream Consumers
|
|
69
67
|
|
|
@@ -87,7 +85,7 @@ Write to `{{output_file}}`:
|
|
|
87
85
|
| TypeScript | 142 | 65% | Application code |
|
|
88
86
|
| ... | ... | ... | ... |
|
|
89
87
|
|
|
90
|
-
Evidence: `
|
|
88
|
+
Evidence: `scan.js extensions` output showing file distribution
|
|
91
89
|
|
|
92
90
|
## Frameworks & Core Libraries
|
|
93
91
|
| Name | Version | Purpose | Evidence |
|
|
@@ -18,7 +18,7 @@ Complementary, not a replacement. `bmad-document-project` generates comprehensiv
|
|
|
18
18
|
|
|
19
19
|
## Step 1 — Prepare
|
|
20
20
|
|
|
21
|
-
<action>Create output directory
|
|
21
|
+
<action>Create output directory `{output_folder}/codebase-analysis` (use your native file-create tool; it will create parent directories as needed). The first `Write` tool call targeting a file inside this directory will auto-create it, so no explicit mkdir is required in practice.</action>
|
|
22
22
|
<action>Determine project root absolute path: `{{project_root}}`</action>
|
|
23
23
|
|
|
24
24
|
---
|