@ikunin/sprintpilot 2.2.31 → 2.3.1

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.
Files changed (47) hide show
  1. package/README.md +228 -415
  2. package/_Sprintpilot/Sprintpilot.md +76 -8
  3. package/_Sprintpilot/bin/autopilot.js +734 -68
  4. package/_Sprintpilot/lib/orchestrator/action-ledger.js +208 -0
  5. package/_Sprintpilot/lib/orchestrator/adapt.js +93 -15
  6. package/_Sprintpilot/lib/orchestrator/profile-rules.js +7 -16
  7. package/_Sprintpilot/lib/orchestrator/sprint-plan.js +488 -0
  8. package/_Sprintpilot/lib/orchestrator/state-store.js +9 -5
  9. package/_Sprintpilot/lib/orchestrator/user-command-applier.js +78 -0
  10. package/_Sprintpilot/lib/orchestrator/user-commands.js +114 -0
  11. package/_Sprintpilot/lib/orchestrator/verify.js +10 -17
  12. package/_Sprintpilot/manifest.yaml +4 -3
  13. package/_Sprintpilot/modules/autopilot/profiles/_base.yaml +18 -4
  14. package/_Sprintpilot/modules/git/config.yaml +15 -9
  15. package/_Sprintpilot/modules/ma/config.yaml +29 -27
  16. package/_Sprintpilot/scripts/dispatch-layer.js +12 -15
  17. package/_Sprintpilot/scripts/infer-dependencies.js +706 -254
  18. package/_Sprintpilot/scripts/log-timing.js +6 -10
  19. package/_Sprintpilot/scripts/merge-shards.js +21 -23
  20. package/_Sprintpilot/scripts/post-green-gates.js +3 -1
  21. package/_Sprintpilot/scripts/resolve-dag.js +452 -280
  22. package/_Sprintpilot/scripts/sprint-plan.js +1068 -0
  23. package/_Sprintpilot/scripts/state-shard.js +13 -5
  24. package/_Sprintpilot/scripts/summarize-timings.js +2 -3
  25. package/_Sprintpilot/skills/sprint-autopilot-on/SKILL.md +30 -2
  26. package/_Sprintpilot/skills/sprint-autopilot-on/workflow.orchestrator.md +36 -10
  27. package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/architecture-mapper.md +10 -8
  28. package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/concerns-hunter.md +11 -9
  29. package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/integration-mapper.md +11 -9
  30. package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/quality-assessor.md +10 -8
  31. package/_Sprintpilot/skills/sprintpilot-codebase-map/agents/stack-analyzer.md +11 -9
  32. package/_Sprintpilot/skills/sprintpilot-codebase-map/workflow.md +1 -1
  33. package/_Sprintpilot/skills/sprintpilot-dependency-graph/SKILL.md +63 -0
  34. package/_Sprintpilot/skills/sprintpilot-dependency-graph/workflow.md +227 -0
  35. package/_Sprintpilot/skills/sprintpilot-plan-sprint/SKILL.md +67 -0
  36. package/_Sprintpilot/skills/sprintpilot-plan-sprint/workflow.md +435 -0
  37. package/_Sprintpilot/skills/sprintpilot-sprint-progress/SKILL.md +53 -0
  38. package/_Sprintpilot/skills/sprintpilot-sprint-progress/workflow.md +169 -0
  39. package/lib/commands/install.js +186 -12
  40. package/package.json +1 -1
  41. package/_Sprintpilot/skills/sprintpilot-code-review/SKILL.md +0 -6
  42. package/_Sprintpilot/skills/sprintpilot-code-review/agents/acceptance-auditor.md +0 -51
  43. package/_Sprintpilot/skills/sprintpilot-code-review/agents/blind-hunter.md +0 -39
  44. package/_Sprintpilot/skills/sprintpilot-code-review/agents/edge-case-hunter.md +0 -46
  45. package/_Sprintpilot/skills/sprintpilot-code-review/workflow.md +0 -111
  46. package/_Sprintpilot/skills/sprintpilot-party-mode/SKILL.md +0 -6
  47. package/_Sprintpilot/skills/sprintpilot-party-mode/workflow.md +0 -138
@@ -0,0 +1,169 @@
1
+ # Sprintpilot — Sprint Progress Check
2
+
3
+ ## Purpose
4
+
5
+ Produce a concise health check of the current sprint's autopilot
6
+ execution. Reads the structured progress snapshot, recent halts /
7
+ verify failures, and step-level events; layers brief judgment on top
8
+ to highlight what (if anything) needs attention.
9
+
10
+ ## Outputs
11
+
12
+ - A ≤15-line human-readable summary printed to chat.
13
+ - A single recommended next action (or "nothing to do — autopilot is
14
+ healthy / idle").
15
+
16
+ No file writes. No state mutations.
17
+
18
+ ## Conventions
19
+
20
+ - `<root>` = project root (where `_bmad-output/` lives).
21
+ - All shell-outs use `node` (no global install assumed).
22
+ - On any error (no plan, missing ledger, etc.), degrade gracefully —
23
+ print what you DO know and skip the parts you don't. The user gets
24
+ a partial answer rather than a halt.
25
+
26
+ ---
27
+
28
+ ## Step 1 — Collect the Structured Snapshot
29
+
30
+ <action>Run the progress CLI in JSON mode:
31
+ ```
32
+ node _Sprintpilot/bin/autopilot.js progress --project-root <root> --json
33
+ ```
34
+ Parse the response. Key fields:
35
+ - `plan_present` — false → project running in sprint-status order; the
36
+ rest of the analysis is naturally lighter.
37
+ - `plan_id`
38
+ - `current_story` / `current_step`
39
+ - `sprint_progress` — `{ total, done, pending, skipped, excluded, source }`
40
+ - `recent_events` — last 3 `story_step_*` ledger entries.
41
+
42
+ Don't fail if the command exits non-zero (e.g., missing project root).
43
+ Capture stderr and treat as "unknown progress" — proceed with Step 2
44
+ which still produces useful output.</action>
45
+
46
+ ---
47
+
48
+ ## Step 2 — Pull Recent Halt / Verify Context
49
+
50
+ <action>Read the tail of the ledger to identify any unresolved
51
+ halts, verify rejections, or repeated step-failure loops. Inline node
52
+ is the lightest path:
53
+
54
+ ```
55
+ node -e "
56
+ const l = require('./_Sprintpilot/lib/orchestrator/action-ledger.js');
57
+ const entries = l.read({projectRoot: process.cwd()}, {limit: 40});
58
+ const interesting = entries.filter(e =>
59
+ e.kind === 'halt' ||
60
+ e.kind === 'verify_rejected' ||
61
+ e.kind === 'plan_exhausted' ||
62
+ e.kind === 'plan_reorder_rejected' ||
63
+ e.kind === 'auto_derive_emitted' ||
64
+ e.kind === 'plan_migrated'
65
+ );
66
+ process.stdout.write(JSON.stringify(interesting));
67
+ "
68
+ ```
69
+
70
+ Look for:
71
+ - **`halt` with reason in {`autopilot_lock_held`, `worktree_orphans_detected`,
72
+ `plan_exhausted`, `user_pause`, `user_replan_sprint`, `user_abort_sprint`}**
73
+ — autopilot is stopped and needs user attention.
74
+ - **`verify_rejected` with `consecutive >= 3`** — autopilot is stuck in
75
+ a retry loop; the LLM may need to re-read the failing artifact.
76
+ - **`plan_reorder_rejected`** — a recent reorder violated the DAG;
77
+ the user has unresolved input pending.
78
+ - **Repeated `story_step_started` for the same story+phase without
79
+ matching `story_step_completed`** — phase entered but never finished;
80
+ could indicate a wedged session.
81
+
82
+ Don't fail if the ledger is empty (greenfield project, never run).
83
+ Just note "no execution history yet" and proceed.</action>
84
+
85
+ ---
86
+
87
+ ## Step 3 — Synthesize the Report
88
+
89
+ <action>Render a single brief block to chat following this template
90
+ (omit any line that doesn't apply):
91
+
92
+ ```
93
+ Sprint progress
94
+ Plan: <plan_id> — <done>/<total> done (<pending> pending,
95
+ <skipped> skipped, <excluded> excluded)
96
+ Bar: [===== ] <pct>%
97
+ Tracker: <linked>/<total> stories linked to <provider> (<project_key>) ← only when issue_tracker set
98
+ Current: <story_key> [<issue_id>] (step: <phase>) OR "idle"
99
+ ↑ issue_id bracket only when set on this story
100
+ Recent: <kind> <story> [<issue_id>] / <phase> (<elapsed>s ago)
101
+ <kind> <story> [<issue_id>] / <phase> (<elapsed>s ago)
102
+
103
+ Health: <one of: HEALTHY | STALLED | NEEDS-INPUT | EXHAUSTED | NO-PLAN>
104
+ Reason: <one short sentence>
105
+ Suggest: <one concrete next action OR "continue running">
106
+ ```
107
+
108
+ The `autopilot progress --json` response carries the lookup data:
109
+ - `current_issue_id` — the issue_id of the currently-running story (or null).
110
+ - `issue_tracking` — `{provider, project_key, base_url, total, linked, coverage}`
111
+ when an issue_tracker is configured; null otherwise (omit the Tracker
112
+ line entirely when null — don't surface zeros as noise).
113
+ - Each `recent_events[]` entry carries an `issue_id` field (or null).
114
+
115
+ Always include the `[<issue_id>]` bracket when the field is non-null;
116
+ omit it when null. Don't write "[no issue]" or similar — silence
117
+ communicates "not tracked" cleanly.
118
+
119
+ **Health classification:**
120
+
121
+ | Signal | Health | Suggest |
122
+ |---|---|---|
123
+ | `plan_present=false` AND no halts in last 40 | NO-PLAN | "Continue in sprint-status order, or run /sprintpilot-plan-sprint to enable dependency-aware ordering." |
124
+ | Most-recent halt is `plan_exhausted` | EXHAUSTED | "Run /sprintpilot-plan-sprint to add more stories, or `autopilot start --no-auto-plan` to continue in sprint-status order." |
125
+ | Most-recent halt is `user_pause` | NEEDS-INPUT | "Resume with `autopilot start`." |
126
+ | Most-recent halt is `user_replan_sprint` | NEEDS-INPUT | "Next `autopilot start` will invoke /sprintpilot-plan-sprint." |
127
+ | `verify_rejected` with `consecutive >= 3` in last 5 entries | STALLED | "Inspect the failing artifact named in `verify_result.issues`; consider `user_input { kind: 'force_continue' }` only if you've manually resolved the issue." |
128
+ | `plan_reorder_rejected` more recent than any subsequent reorder_queue | NEEDS-INPUT | "Reorder violations exist; revise the order to respect the DAG before sending another reorder_queue." |
129
+ | No halts, current_story present, current_step is a valid phase | HEALTHY | "Continue running; nothing requires attention." |
130
+ | No halts, no current_story, sprint_progress.pending > 0 | HEALTHY | "Run `autopilot start` to pick up the next pending story." |
131
+ | No halts, no current_story, sprint_progress.pending == 0 | HEALTHY | "Sprint complete; consider running the bmad-retrospective skill if not already done." |
132
+
133
+ Default to HEALTHY when classification is ambiguous — don't manufacture
134
+ alarm.</action>
135
+
136
+ <action>If the user invoked the skill with a story name argument
137
+ (e.g., `/sprintpilot-sprint-progress 1-3-add-auth`), also call:
138
+ ```
139
+ node _Sprintpilot/bin/autopilot.js progress --project-root <root> --story <story-key> --json
140
+ ```
141
+ And append a one-block "Story detail" section showing that story's
142
+ plan entry. When `issue_id` is non-null, prominently display it on its
143
+ own line (it's the primary cross-reference back to the user's issue
144
+ tracker):
145
+
146
+ ```
147
+ Story: <story_key>
148
+ Issue: <issue_id> ← omit line when null
149
+ Epic: <epic>
150
+ Plan status: <plan_status>
151
+ BMad status: <bmad_status>
152
+ Priority: <priority>
153
+ Current step: <current_step> ← omit when not running
154
+ Completed: <completed_at> ← omit when not done
155
+ ```
156
+
157
+ Do not repeat the full sprint summary in this mode — just the focused
158
+ story block.</action>
159
+
160
+ ---
161
+
162
+ ## Failure modes
163
+
164
+ | Symptom | Recovery |
165
+ |---|---|
166
+ | `autopilot progress` exits non-zero (missing project root, etc.) | Capture stderr; print "Progress CLI unavailable: <stderr first line>"; still attempt Step 2. |
167
+ | Ledger file missing | Print "No execution history yet — sprint hasn't started"; skip Step 2 analysis; suggest `autopilot start`. |
168
+ | Plan file corrupt | Print "sprint-plan.yaml unreadable (run `node _Sprintpilot/scripts/sprint-plan.js read --project-root .` to inspect)"; do NOT auto-archive — that's user's call. |
169
+ | Recent ledger has 0 entries | Note "Ledger is empty — autopilot hasn't run yet or was reset"; skip halt analysis. |
@@ -748,7 +748,15 @@ async function evictV1Installation(projectRoot, { dryRun, migrateV1, yes }) {
748
748
  // Regex-based so we don't add a YAML parser dep for two scalar fields.
749
749
  // Unrecognized / unreadable files fall back to bundled defaults.
750
750
  async function readExistingAutopilotConfig(projectRoot, v1Snapshot) {
751
- const out = { sessionStoryLimit: null, retrospectiveMode: null };
751
+ const out = {
752
+ sessionStoryLimit: null,
753
+ retrospectiveMode: null,
754
+ // v2.3.0 additions. null means "not set in user config" → use the bundled
755
+ // default. autoInferDependencies is read only to surface a deprecation
756
+ // notice on upgrade — we never write it back.
757
+ autoPlanOnStart: null,
758
+ autoInferDependencies: null,
759
+ };
752
760
  let raw = null;
753
761
 
754
762
  // Precedence order:
@@ -809,6 +817,22 @@ async function readExistingAutopilotConfig(projectRoot, v1Snapshot) {
809
817
  if (modeMatch && RETROSPECTIVE_MODES.includes(modeMatch[1])) {
810
818
  out.retrospectiveMode = modeMatch[1];
811
819
  }
820
+ // v2.3.0 — `auto_plan_on_start: true|false`. Bool; bundled default is false.
821
+ const planMatch = raw.match(
822
+ new RegExp(`^[ \\t]*auto_plan_on_start:[ \\t]*(true|false)${commentTail}`, 'm'),
823
+ );
824
+ if (planMatch) {
825
+ out.autoPlanOnStart = planMatch[1] === 'true';
826
+ }
827
+ // Legacy `auto_infer_dependencies: true|false` — read so the installer can
828
+ // surface a deprecation notice when the user is upgrading from v2.2.x with
829
+ // the flag set to true (it's now a no-op). Never written back.
830
+ const inferMatch = raw.match(
831
+ new RegExp(`^[ \\t]*auto_infer_dependencies:[ \\t]*(true|false)${commentTail}`, 'm'),
832
+ );
833
+ if (inferMatch) {
834
+ out.autoInferDependencies = inferMatch[1] === 'true';
835
+ }
812
836
  return out;
813
837
  }
814
838
 
@@ -859,7 +883,10 @@ function applyScalar(source, key, value) {
859
883
  return `${trimmed} ${key}: ${value}\n`;
860
884
  }
861
885
 
862
- async function patchAutopilotConfig(projectRoot, { sessionStoryLimit, retrospectiveMode }) {
886
+ async function patchAutopilotConfig(
887
+ projectRoot,
888
+ { sessionStoryLimit, retrospectiveMode, autoPlanOnStart },
889
+ ) {
863
890
  const file = path.join(
864
891
  projectRoot,
865
892
  PROJECT_ADDON_DIR_NAME,
@@ -871,6 +898,12 @@ async function patchAutopilotConfig(projectRoot, { sessionStoryLimit, retrospect
871
898
  const original = await fs.readFile(file, 'utf8');
872
899
  let updated = applyScalar(original, 'session_story_limit', sessionStoryLimit);
873
900
  updated = applyScalar(updated, 'retrospective_mode', retrospectiveMode);
901
+ // v2.3.0 — auto_plan_on_start is a boolean. applyScalar handles literal
902
+ // values (true/false) the same way as numbers; we just need to pass the
903
+ // unquoted lowercase string for booleans.
904
+ if (autoPlanOnStart !== undefined && autoPlanOnStart !== null) {
905
+ updated = applyScalar(updated, 'auto_plan_on_start', autoPlanOnStart ? 'true' : 'false');
906
+ }
874
907
  if (updated !== original) {
875
908
  await writeAtomic(file, updated);
876
909
  }
@@ -915,6 +948,46 @@ async function readExistingComplexityProfile(projectRoot, v1Snapshot) {
915
948
  return m[1];
916
949
  }
917
950
 
951
+ // v2.3.0 — post-install hygiene check. Cross-reference the project's
952
+ // _Sprintpilot/manifest.yaml `installed_skills` against what actually
953
+ // landed under `_Sprintpilot/skills/<name>/SKILL.md`. Catches the
954
+ // classic "added skill to manifest but forgot to ship the files" bug
955
+ // at install time rather than at first invocation.
956
+ //
957
+ // Returns { missing: string[] } — empty array means everything is
958
+ // wired correctly. The caller chooses how to surface mismatches
959
+ // (warning vs fail). We never fail the install on a mismatch; it's
960
+ // hygiene, not correctness — the skill just won't appear under the
961
+ // host tool's /-command if it's missing on disk.
962
+ async function verifySkillManifest(projectRoot) {
963
+ const manifestPath = path.join(projectRoot, PROJECT_ADDON_DIR_NAME, 'manifest.yaml');
964
+ if (!(await fs.pathExists(manifestPath))) {
965
+ return { missing: [] };
966
+ }
967
+ let raw;
968
+ try {
969
+ raw = await fs.readFile(manifestPath, 'utf8');
970
+ } catch {
971
+ return { missing: [] };
972
+ }
973
+ // Parse the YAML list under `installed_skills:` via regex — bullet
974
+ // lines starting with `-` at consistent indent. Cheap; no YAML dep.
975
+ const skillNames = [];
976
+ const installedMatch = raw.match(/^[ \t]*installed_skills:\s*\n((?:[ \t]+- [^\n]+\n?)+)/m);
977
+ if (installedMatch) {
978
+ for (const line of installedMatch[1].split(/\n/)) {
979
+ const m = line.match(/^[ \t]+-\s+([A-Za-z0-9._-]+)/);
980
+ if (m) skillNames.push(m[1]);
981
+ }
982
+ }
983
+ const missing = [];
984
+ for (const name of skillNames) {
985
+ const skillFile = path.join(projectRoot, PROJECT_ADDON_DIR_NAME, 'skills', name, 'SKILL.md');
986
+ if (!(await fs.pathExists(skillFile))) missing.push(name);
987
+ }
988
+ return { missing };
989
+ }
990
+
918
991
  async function patchComplexityProfile(projectRoot, profile) {
919
992
  const file = path.join(
920
993
  projectRoot,
@@ -1008,25 +1081,39 @@ async function resolveAutopilotSettings({ projectRoot, yes, dryRun, v1Snapshot }
1008
1081
  const existing = await readExistingAutopilotConfig(projectRoot, v1Snapshot);
1009
1082
  const defaultLimit = existing.sessionStoryLimit ?? DEFAULT_SESSION_STORY_LIMIT;
1010
1083
  const defaultMode = existing.retrospectiveMode ?? DEFAULT_RETROSPECTIVE_MODE;
1084
+ // v2.3.0 — opt-in default false; preserve existing user choice on upgrade.
1085
+ const defaultAutoPlan = existing.autoPlanOnStart ?? false;
1011
1086
 
1012
1087
  if (yes) {
1013
- if (existing.sessionStoryLimit != null || existing.retrospectiveMode != null) {
1088
+ if (
1089
+ existing.sessionStoryLimit != null ||
1090
+ existing.retrospectiveMode != null ||
1091
+ existing.autoPlanOnStart != null
1092
+ ) {
1014
1093
  console.log(
1015
1094
  pc.dim(
1016
- `Preserving autopilot config: session_story_limit=${defaultLimit}, retrospective_mode=${defaultMode}`,
1095
+ `Preserving autopilot config: session_story_limit=${defaultLimit}, retrospective_mode=${defaultMode}, auto_plan_on_start=${defaultAutoPlan}`,
1017
1096
  ),
1018
1097
  );
1019
1098
  }
1020
- return { sessionStoryLimit: defaultLimit, retrospectiveMode: defaultMode };
1099
+ return {
1100
+ sessionStoryLimit: defaultLimit,
1101
+ retrospectiveMode: defaultMode,
1102
+ autoPlanOnStart: defaultAutoPlan,
1103
+ };
1021
1104
  }
1022
1105
 
1023
1106
  if (dryRun) {
1024
1107
  console.log(
1025
1108
  pc.dim(
1026
- `[DRY RUN] Would prompt for autopilot config (current: session_story_limit=${defaultLimit}, retrospective_mode=${defaultMode})`,
1109
+ `[DRY RUN] Would prompt for autopilot config (current: session_story_limit=${defaultLimit}, retrospective_mode=${defaultMode}, auto_plan_on_start=${defaultAutoPlan})`,
1027
1110
  ),
1028
1111
  );
1029
- return { sessionStoryLimit: defaultLimit, retrospectiveMode: defaultMode };
1112
+ return {
1113
+ sessionStoryLimit: defaultLimit,
1114
+ retrospectiveMode: defaultMode,
1115
+ autoPlanOnStart: defaultAutoPlan,
1116
+ };
1030
1117
  }
1031
1118
 
1032
1119
  const limitRaw = await prompts.text({
@@ -1065,7 +1152,17 @@ async function resolveAutopilotSettings({ projectRoot, yes, dryRun, v1Snapshot }
1065
1152
  initialValue: defaultMode,
1066
1153
  });
1067
1154
 
1068
- return { sessionStoryLimit, retrospectiveMode };
1155
+ // v2.3.0 single yes/no prompt for the new plan workflow. Default false:
1156
+ // `autopilot start` runs in sprint-status order until the user explicitly
1157
+ // invokes /sprintpilot-plan-sprint, which is always available regardless.
1158
+ // Set this true to auto-trigger the planning skill on greenfield projects.
1159
+ const autoPlanOnStart = await prompts.confirm({
1160
+ message:
1161
+ 'Auto-build a sprint plan on first `autopilot start`? (v2.3.0; runs /sprintpilot-plan-sprint to infer dependencies. You can always invoke the skill manually regardless of this setting.)',
1162
+ initialValue: defaultAutoPlan,
1163
+ });
1164
+
1165
+ return { sessionStoryLimit, retrospectiveMode, autoPlanOnStart };
1069
1166
  }
1070
1167
 
1071
1168
  async function runInteractiveToolPicker(detected) {
@@ -1194,7 +1291,7 @@ async function runInstall(options = {}) {
1194
1291
  // runtime copy — they're NOT threaded through `renderString`, because
1195
1292
  // workflow.md's `{{session_story_limit}}` / `{{retrospective_mode}}`
1196
1293
  // variable references would collide with single-brace token matching.
1197
- const { sessionStoryLimit, retrospectiveMode } = await resolveAutopilotSettings({
1294
+ const { sessionStoryLimit, retrospectiveMode, autoPlanOnStart } = await resolveAutopilotSettings({
1198
1295
  projectRoot,
1199
1296
  yes,
1200
1297
  dryRun,
@@ -1439,7 +1536,11 @@ async function runInstall(options = {}) {
1439
1536
  // wrote the bundled default config) AND after the v1 snapshot
1440
1537
  // reapply (which might have restored an older config.yaml without
1441
1538
  // `retrospective_mode`). The user's prompted values always win.
1442
- await patchAutopilotConfig(projectRoot, { sessionStoryLimit, retrospectiveMode });
1539
+ await patchAutopilotConfig(projectRoot, {
1540
+ sessionStoryLimit,
1541
+ retrospectiveMode,
1542
+ autoPlanOnStart,
1543
+ });
1443
1544
 
1444
1545
  // 6c. Persist the complexity_profile. Separate from patchAutopilotConfig
1445
1546
  // so the existing upgrade test coverage (readExistingAutopilotConfig /
@@ -1501,6 +1602,56 @@ async function runInstall(options = {}) {
1501
1602
  console.log(
1502
1603
  `Total skills installed: ${totalInstalled} (${skillCount} skills x ${selectedTools.length} tools)`,
1503
1604
  );
1605
+
1606
+ // v2.3.0 — post-install hygiene: warn if any skill in manifest.yaml
1607
+ // doesn't have a SKILL.md on disk. Non-blocking; surfaces packaging
1608
+ // bugs without failing the install.
1609
+ try {
1610
+ const verify = await verifySkillManifest(projectRoot);
1611
+ if (verify.missing.length > 0) {
1612
+ console.log('');
1613
+ console.log(
1614
+ pc.yellow(` WARN: manifest references skills missing from disk: ${verify.missing.join(', ')}`),
1615
+ );
1616
+ console.log(pc.yellow(' These won\'t appear under your host tool\'s / menu until the SKILL.md files are present.'));
1617
+ }
1618
+ } catch {
1619
+ // Self-check failure is non-fatal — never block install on hygiene.
1620
+ }
1621
+
1622
+ // v2.3.0 upgrade notes — surfaced only when the relevant signals are
1623
+ // actually present. Greenfield installs see nothing; upgraders from
1624
+ // v2.2.x see migration + deprecation notices.
1625
+ const v23Notes = [];
1626
+ const legacyDepsPath = path.join(projectRoot, '_Sprintpilot', 'sprints', 'dependencies.yaml');
1627
+ if (await fs.pathExists(legacyDepsPath)) {
1628
+ v23Notes.push(
1629
+ 'Legacy file detected: _Sprintpilot/sprints/dependencies.yaml',
1630
+ ' Auto-migrated to sprint-plan.yaml on the first `autopilot start`.',
1631
+ ' Run now: node _Sprintpilot/scripts/infer-dependencies.js migrate',
1632
+ );
1633
+ }
1634
+ // Re-read so we can show the deprecation notice without threading state
1635
+ // through every helper. Cheap (one regex scan); only happens once per install.
1636
+ try {
1637
+ const existingForNotes = await readExistingAutopilotConfig(projectRoot, v1ConfigSnapshot);
1638
+ if (existingForNotes.autoInferDependencies === true) {
1639
+ if (v23Notes.length > 0) v23Notes.push('');
1640
+ v23Notes.push(
1641
+ 'Deprecated: autopilot.auto_infer_dependencies = true in your config.',
1642
+ ' This flag is a no-op in v2.3.0 — superseded by auto_plan_on_start (default false).',
1643
+ ' Safe to remove from config.yaml; the new /sprintpilot-plan-sprint workflow',
1644
+ ' handles inference manually or on opt-in auto-trigger.',
1645
+ );
1646
+ }
1647
+ } catch {
1648
+ // Config re-read failure is non-fatal — skip the deprecation notice.
1649
+ }
1650
+ if (v23Notes.length > 0) {
1651
+ console.log('');
1652
+ console.log(pc.cyan('v2.3.0 upgrade notes:'));
1653
+ for (const line of v23Notes) console.log(' ' + line);
1654
+ }
1504
1655
  console.log('');
1505
1656
  console.log('Skills:');
1506
1657
  for (const skill of allSkills) console.log(` - ${skill}`);
@@ -1513,6 +1664,13 @@ async function runInstall(options = {}) {
1513
1664
  console.log(' /sprint-autopilot-off Disengage and show status');
1514
1665
  console.log(' /bmad-help Orientation and next-step guidance (from BMad Method)');
1515
1666
  console.log('');
1667
+ console.log('First steps for a new sprint:');
1668
+ console.log(' 1. BMad sprint planning: /bmad-sprint-planning');
1669
+ console.log(' 2. (optional) Sprint plan: /sprintpilot-plan-sprint');
1670
+ console.log(' 3. (optional) Inspect DAG: /sprintpilot-dependency-graph mermaid');
1671
+ console.log(' 4. Start autopilot: /sprint-autopilot-on');
1672
+ console.log(' 5. Check live progress: /sprintpilot-sprint-progress');
1673
+ console.log('');
1516
1674
  console.log('Configuration (edit these files to customize behavior):');
1517
1675
  console.log('');
1518
1676
  console.log(' _Sprintpilot/modules/git/config.yaml');
@@ -1542,15 +1700,30 @@ async function runInstall(options = {}) {
1542
1700
  console.log(
1543
1701
  ` ${apKey('autopilot.retrospective_mode')}${apVal(retrospectiveMode)} Epic-end retrospective: auto (inline) | stop (pause) | skip (not recommended)`,
1544
1702
  );
1703
+ console.log(
1704
+ ` ${apKey('autopilot.auto_plan_on_start')}${apVal(String(autoPlanOnStart))} Auto-build sprint plan on first start (v2.3.0; default off)`,
1705
+ );
1706
+ console.log('');
1707
+ console.log('Sprint planning + progress (v2.3.0):');
1708
+ console.log(' /sprintpilot-plan-sprint Build dependency-aware sprint plan');
1709
+ console.log(' /sprintpilot-sprint-progress Concise health-check of autopilot execution');
1710
+ console.log(' /sprintpilot-dependency-graph Render DAG (mermaid / graphviz / text / layers / json)');
1711
+ console.log('');
1712
+ console.log('CLI utilities:');
1713
+ console.log(' autopilot progress Live status (--json / --story <key>)');
1714
+ console.log(' autopilot start --no-auto-plan Skip auto-planning for one session');
1545
1715
  console.log('');
1546
1716
  console.log('Multi-agent skills — run parallel subagents for faster analysis:');
1547
- console.log(' /sprintpilot-code-review Parallel 3-layer adversarial review');
1548
1717
  console.log(' /sprintpilot-codebase-map 5-stream brownfield codebase analysis');
1549
1718
  console.log(' /sprintpilot-assess Tech debt and dependency audit');
1550
1719
  console.log(' /sprintpilot-reverse-architect Extract architecture from existing code');
1551
1720
  console.log(' /sprintpilot-migrate Legacy migration planning');
1552
1721
  console.log(' /sprintpilot-research Parallel web research');
1553
- console.log(' /sprintpilot-party-mode Multi-persona agent discussions');
1722
+ console.log('');
1723
+ console.log('Documentation:');
1724
+ console.log(' Sprint planning walkthrough: docs/USAGE.md');
1725
+ console.log(' Configuration reference: docs/CONFIGURATION.md');
1726
+ console.log(' Architecture deep-dive: docs/ARCHITECTURE.md');
1554
1727
 
1555
1728
  const latestVersion = await latestVersionPromise;
1556
1729
  if (latestVersion && addonVersion && compareVersions(addonVersion, latestVersion) === 'behind') {
@@ -1586,5 +1759,6 @@ module.exports = {
1586
1759
  KEY_RENAMES,
1587
1760
  snapshotUserOwnedFiles,
1588
1761
  applyUserOwnedFiles,
1762
+ verifySkillManifest,
1589
1763
  },
1590
1764
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikunin/sprintpilot",
3
- "version": "2.2.31",
3
+ "version": "2.3.1",
4
4
  "description": "Sprintpilot — autopilot and multi-agent addon for BMad Method v6: git workflow, parallel agents, autonomous story execution",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1,6 +0,0 @@
1
- ---
2
- name: sprintpilot-code-review
3
- description: 'Parallel 3-layer code review via subagents. Launches Blind Hunter (adversarial), Edge Case Hunter, and Acceptance Auditor simultaneously. Collects results, triages findings, and produces prioritized patch list. Use instead of stock bmad-code-review for deeper, faster reviews.'
4
- ---
5
-
6
- Follow the instructions in ./workflow.md.
@@ -1,51 +0,0 @@
1
- # Acceptance Auditor — Code Review Agent
2
-
3
- You are a QA auditor verifying that the implementation satisfies the story's acceptance criteria. You have the diff, the story file, and project access.
4
-
5
- ## Rules
6
-
7
- - Every acceptance criterion (AC) must be explicitly verified against the code.
8
- - If an AC is NOT covered by the implementation, flag it as MISSING.
9
- - If an AC is partially covered, flag what's missing.
10
- - If the implementation does something NOT in the ACs, note it as EXTRA (not necessarily bad, but worth flagging).
11
- - Cap your response at 2000 tokens.
12
-
13
- ## What to Check
14
-
15
- For each acceptance criterion in the story:
16
- 1. **Implemented?** — Is there code that addresses this criterion?
17
- 2. **Tested?** — Is there a test that verifies this criterion?
18
- 3. **Correct?** — Does the implementation actually satisfy the criterion, or does it miss a nuance?
19
-
20
- Also check:
21
- 4. **Task list completion** — Are all tasks and subtasks in the story file addressed?
22
- 5. **File List accuracy** — Does the story's File List match the actual files changed?
23
- 6. **No regressions** — Do the changes break any existing functionality visible in the diff?
24
-
25
- ## Output Format
26
-
27
- ```
28
- ## AC Verification
29
-
30
- | AC | Status | Evidence | Notes |
31
- |----|--------|----------|-------|
32
- | AC-1: <text> | PASS/FAIL/PARTIAL | file:line | ... |
33
- | AC-2: <text> | PASS/FAIL/PARTIAL | file:line | ... |
34
-
35
- ## Issues Found
36
-
37
- 1. [SEVERITY] AC-N not satisfied — file:line
38
- What's missing: ...
39
- Suggested fix: ...
40
-
41
- 2. ...
42
-
43
- ## Extra (not in ACs)
44
- - <description of extra behavior>
45
- ```
46
-
47
- If all ACs pass, say "All acceptance criteria verified" with the evidence table.
48
-
49
- ## Story and Diff
50
-
51
- The story file content and diff follow below. Review them now.
@@ -1,39 +0,0 @@
1
- # Blind Hunter — Adversarial Code Review Agent
2
-
3
- You are a ruthless code reviewer. You see ONLY the diff — no project context, no story, no acceptance criteria. Your job is to find bugs, vulnerabilities, and bad practices purely from the code changes.
4
-
5
- ## Rules
6
-
7
- - You have NO project context. Do not ask for it. Review only what you see.
8
- - Be specific: cite exact file paths and line numbers.
9
- - Focus on things that will break in production, not style preferences.
10
- - Cap your response at 2000 tokens. Be concise.
11
-
12
- ## What to Look For
13
-
14
- 1. **Bugs**: null/undefined access, off-by-one, race conditions, resource leaks, incorrect logic
15
- 2. **Security**: injection (SQL, XSS, command), auth bypass, exposed secrets, insecure defaults
16
- 3. **Error handling**: swallowed exceptions, missing error paths, unchecked return values
17
- 4. **Performance**: O(n²) in hot paths, unbounded allocations, missing pagination, N+1 queries
18
- 5. **Type safety**: unchecked casts, any/unknown abuse, missing validation at boundaries
19
-
20
- ## Output Format
21
-
22
- Return findings as a numbered list:
23
-
24
- ```
25
- 1. [SEVERITY] file:line — Title
26
- Description of the issue.
27
- Suggested fix: ...
28
-
29
- 2. [SEVERITY] file:line — Title
30
- ...
31
- ```
32
-
33
- Severity: CRITICAL, HIGH, MEDIUM, LOW
34
-
35
- If the diff looks clean, say "No issues found" — do not manufacture findings.
36
-
37
- ## Diff to Review
38
-
39
- The diff follows below. Review it now.
@@ -1,46 +0,0 @@
1
- # Edge Case Hunter — Code Review Agent
2
-
3
- You are a methodical edge case analyst. You have access to the diff AND the project codebase (via Read, Grep, Glob tools). Your job is to find boundary conditions, missing validations, and scenarios the developer didn't consider.
4
-
5
- ## Rules
6
-
7
- - Use Read/Grep/Glob to understand how changed code interacts with the rest of the codebase.
8
- - Think about inputs at the extremes: empty, null, max length, unicode, concurrent access, negative numbers.
9
- - Focus on cases that the tests probably DON'T cover.
10
- - Cap your response at 2000 tokens. Be concise.
11
-
12
- ## What to Look For
13
-
14
- 1. **Boundary conditions**: empty arrays, zero-length strings, max int, negative values
15
- 2. **Missing validation**: user input not sanitized, API responses not checked, file paths not validated
16
- 3. **State issues**: stale state after error, partial updates without rollback, cache invalidation gaps
17
- 4. **Concurrency**: shared mutable state, missing locks, TOCTOU races
18
- 5. **Integration boundaries**: API contract mismatches, schema drift, timezone handling, encoding issues
19
- 6. **Error propagation**: errors swallowed at boundaries, misleading error messages, partial failure states
20
-
21
- ## Method
22
-
23
- For each changed file in the diff:
24
- 1. Read the full file (not just the diff) to understand context
25
- 2. Grep for callers of changed functions to assess blast radius
26
- 3. Think: "What input would make this fail?"
27
- 4. Think: "What happens if the thing this calls fails?"
28
-
29
- ## Output Format
30
-
31
- ```
32
- 1. [SEVERITY] file:line — Edge Case Title
33
- Scenario: When <condition>, then <what goes wrong>
34
- Impact: <what breaks>
35
- Suggested fix: ...
36
-
37
- 2. ...
38
- ```
39
-
40
- Severity: CRITICAL, HIGH, MEDIUM, LOW
41
-
42
- If no edge cases found, say "No edge cases identified" — do not manufacture findings.
43
-
44
- ## Diff to Review
45
-
46
- The diff follows below. Review it now, then explore the codebase as needed.