@sienklogic/plan-build-run 2.9.1 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/package.json +1 -1
  3. package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +42 -0
  4. package/plugins/copilot-pbr/agents/debugger.agent.md +4 -1
  5. package/plugins/copilot-pbr/agents/executor.agent.md +31 -1
  6. package/plugins/copilot-pbr/agents/integration-checker.agent.md +33 -2
  7. package/plugins/copilot-pbr/agents/planner.agent.md +58 -1
  8. package/plugins/copilot-pbr/agents/researcher.agent.md +23 -0
  9. package/plugins/copilot-pbr/agents/synthesizer.agent.md +24 -0
  10. package/plugins/copilot-pbr/agents/verifier.agent.md +35 -1
  11. package/plugins/copilot-pbr/plugin.json +1 -1
  12. package/plugins/copilot-pbr/references/agent-contracts.md +297 -0
  13. package/plugins/copilot-pbr/references/pbr-rules.md +1 -0
  14. package/plugins/copilot-pbr/references/pbr-tools-cli.md +285 -0
  15. package/plugins/copilot-pbr/references/ui-formatting.md +38 -56
  16. package/plugins/copilot-pbr/skills/begin/SKILL.md +30 -7
  17. package/plugins/copilot-pbr/skills/build/SKILL.md +28 -31
  18. package/plugins/copilot-pbr/skills/config/SKILL.md +9 -12
  19. package/plugins/copilot-pbr/skills/continue/SKILL.md +6 -6
  20. package/plugins/copilot-pbr/skills/dashboard/SKILL.md +12 -0
  21. package/plugins/copilot-pbr/skills/debug/SKILL.md +23 -26
  22. package/plugins/copilot-pbr/skills/discuss/SKILL.md +20 -10
  23. package/plugins/copilot-pbr/skills/do/SKILL.md +3 -3
  24. package/plugins/copilot-pbr/skills/explore/SKILL.md +11 -14
  25. package/plugins/copilot-pbr/skills/health/SKILL.md +75 -19
  26. package/plugins/copilot-pbr/skills/help/SKILL.md +6 -6
  27. package/plugins/copilot-pbr/skills/import/SKILL.md +22 -18
  28. package/plugins/copilot-pbr/skills/milestone/SKILL.md +90 -48
  29. package/plugins/copilot-pbr/skills/note/SKILL.md +3 -3
  30. package/plugins/copilot-pbr/skills/pause/SKILL.md +11 -10
  31. package/plugins/copilot-pbr/skills/plan/SKILL.md +22 -9
  32. package/plugins/copilot-pbr/skills/plan/templates/planner-prompt.md.tmpl +1 -1
  33. package/plugins/copilot-pbr/skills/quick/SKILL.md +9 -12
  34. package/plugins/copilot-pbr/skills/resume/SKILL.md +9 -9
  35. package/plugins/copilot-pbr/skills/review/SKILL.md +17 -12
  36. package/plugins/copilot-pbr/skills/scan/SKILL.md +9 -11
  37. package/plugins/copilot-pbr/skills/setup/SKILL.md +54 -8
  38. package/plugins/copilot-pbr/skills/shared/error-reporting.md +2 -1
  39. package/plugins/copilot-pbr/skills/shared/progress-display.md +0 -1
  40. package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +10 -6
  41. package/plugins/copilot-pbr/skills/status/SKILL.md +3 -3
  42. package/plugins/copilot-pbr/skills/statusline/SKILL.md +12 -8
  43. package/plugins/copilot-pbr/skills/todo/SKILL.md +51 -28
  44. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
  45. package/plugins/cursor-pbr/agents/codebase-mapper.md +42 -0
  46. package/plugins/cursor-pbr/agents/debugger.md +4 -1
  47. package/plugins/cursor-pbr/agents/executor.md +31 -1
  48. package/plugins/cursor-pbr/agents/integration-checker.md +33 -2
  49. package/plugins/cursor-pbr/agents/planner.md +58 -1
  50. package/plugins/cursor-pbr/agents/researcher.md +23 -0
  51. package/plugins/cursor-pbr/agents/synthesizer.md +24 -0
  52. package/plugins/cursor-pbr/agents/verifier.md +35 -1
  53. package/plugins/cursor-pbr/references/agent-contracts.md +297 -0
  54. package/plugins/cursor-pbr/references/pbr-rules.md +1 -0
  55. package/plugins/cursor-pbr/references/pbr-tools-cli.md +285 -0
  56. package/plugins/cursor-pbr/references/ui-formatting.md +38 -56
  57. package/plugins/cursor-pbr/skills/begin/SKILL.md +30 -7
  58. package/plugins/cursor-pbr/skills/build/SKILL.md +28 -31
  59. package/plugins/cursor-pbr/skills/config/SKILL.md +9 -10
  60. package/plugins/cursor-pbr/skills/continue/SKILL.md +6 -6
  61. package/plugins/cursor-pbr/skills/dashboard/SKILL.md +12 -0
  62. package/plugins/cursor-pbr/skills/debug/SKILL.md +23 -23
  63. package/plugins/cursor-pbr/skills/discuss/SKILL.md +20 -10
  64. package/plugins/cursor-pbr/skills/do/SKILL.md +3 -3
  65. package/plugins/cursor-pbr/skills/explore/SKILL.md +11 -12
  66. package/plugins/cursor-pbr/skills/health/SKILL.md +75 -19
  67. package/plugins/cursor-pbr/skills/help/SKILL.md +6 -6
  68. package/plugins/cursor-pbr/skills/import/SKILL.md +22 -16
  69. package/plugins/cursor-pbr/skills/milestone/SKILL.md +90 -48
  70. package/plugins/cursor-pbr/skills/note/SKILL.md +3 -3
  71. package/plugins/cursor-pbr/skills/pause/SKILL.md +11 -9
  72. package/plugins/cursor-pbr/skills/plan/SKILL.md +22 -9
  73. package/plugins/cursor-pbr/skills/plan/templates/planner-prompt.md.tmpl +1 -1
  74. package/plugins/cursor-pbr/skills/quick/SKILL.md +9 -12
  75. package/plugins/cursor-pbr/skills/resume/SKILL.md +9 -9
  76. package/plugins/cursor-pbr/skills/review/SKILL.md +17 -12
  77. package/plugins/cursor-pbr/skills/scan/SKILL.md +9 -10
  78. package/plugins/cursor-pbr/skills/setup/SKILL.md +54 -8
  79. package/plugins/cursor-pbr/skills/shared/error-reporting.md +2 -1
  80. package/plugins/cursor-pbr/skills/shared/progress-display.md +0 -1
  81. package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +10 -6
  82. package/plugins/cursor-pbr/skills/status/SKILL.md +3 -3
  83. package/plugins/cursor-pbr/skills/statusline/SKILL.md +12 -8
  84. package/plugins/cursor-pbr/skills/todo/SKILL.md +51 -28
  85. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  86. package/plugins/pbr/agents/codebase-mapper.md +42 -0
  87. package/plugins/pbr/agents/debugger.md +4 -1
  88. package/plugins/pbr/agents/executor.md +31 -1
  89. package/plugins/pbr/agents/integration-checker.md +34 -2
  90. package/plugins/pbr/agents/planner.md +58 -1
  91. package/plugins/pbr/agents/researcher.md +23 -0
  92. package/plugins/pbr/agents/synthesizer.md +24 -0
  93. package/plugins/pbr/agents/verifier.md +36 -1
  94. package/plugins/pbr/references/agent-contracts.md +297 -0
  95. package/plugins/pbr/references/pbr-rules.md +1 -0
  96. package/plugins/pbr/references/pbr-tools-cli.md +285 -0
  97. package/plugins/pbr/references/ui-formatting.md +37 -54
  98. package/plugins/pbr/scripts/check-skill-workflow.js +11 -0
  99. package/plugins/pbr/scripts/check-state-sync.js +58 -0
  100. package/plugins/pbr/scripts/check-subagent-output.js +43 -4
  101. package/plugins/pbr/scripts/validate-task.js +69 -17
  102. package/plugins/pbr/skills/begin/SKILL.md +36 -11
  103. package/plugins/pbr/skills/build/SKILL.md +37 -25
  104. package/plugins/pbr/skills/config/SKILL.md +12 -10
  105. package/plugins/pbr/skills/continue/SKILL.md +11 -9
  106. package/plugins/pbr/skills/dashboard/SKILL.md +12 -0
  107. package/plugins/pbr/skills/debug/SKILL.md +29 -23
  108. package/plugins/pbr/skills/discuss/SKILL.md +20 -10
  109. package/plugins/pbr/skills/do/SKILL.md +3 -3
  110. package/plugins/pbr/skills/explore/SKILL.md +14 -12
  111. package/plugins/pbr/skills/health/SKILL.md +76 -20
  112. package/plugins/pbr/skills/help/SKILL.md +8 -6
  113. package/plugins/pbr/skills/import/SKILL.md +25 -16
  114. package/plugins/pbr/skills/milestone/SKILL.md +88 -45
  115. package/plugins/pbr/skills/note/SKILL.md +3 -3
  116. package/plugins/pbr/skills/pause/SKILL.md +13 -9
  117. package/plugins/pbr/skills/plan/SKILL.md +28 -13
  118. package/plugins/pbr/skills/plan/templates/planner-prompt.md.tmpl +1 -1
  119. package/plugins/pbr/skills/quick/SKILL.md +12 -10
  120. package/plugins/pbr/skills/resume/SKILL.md +11 -9
  121. package/plugins/pbr/skills/review/SKILL.md +35 -24
  122. package/plugins/pbr/skills/scan/SKILL.md +12 -10
  123. package/plugins/pbr/skills/setup/SKILL.md +53 -7
  124. package/plugins/pbr/skills/shared/error-reporting.md +2 -0
  125. package/plugins/pbr/skills/shared/universal-anti-patterns.md +10 -6
  126. package/plugins/pbr/skills/status/SKILL.md +8 -6
  127. package/plugins/pbr/skills/statusline/SKILL.md +12 -8
  128. package/plugins/pbr/skills/todo/SKILL.md +51 -28
@@ -7,9 +7,9 @@ Consistent output formatting for all Plan-Build-Run skills. Every skill that pro
7
7
  Use for major workflow transitions. Always use `PLAN-BUILD-RUN` prefix.
8
8
 
9
9
  ```
10
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
11
- PLAN-BUILD-RUN ► {STAGE NAME}
12
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10
+ ╔══════════════════════════════════════════════════════════════╗
11
+ PLAN-BUILD-RUN ► {STAGE NAME}
12
+ ╚══════════════════════════════════════════════════════════════╝
13
13
  ```
14
14
 
15
15
  **Stage names (uppercase):**
@@ -21,7 +21,7 @@ Use for major workflow transitions. Always use `PLAN-BUILD-RUN` prefix.
21
21
  - `EXECUTING WAVE {N}`
22
22
  - `VERIFYING`
23
23
  - `PHASE {N} COMPLETE ✓`
24
- - `MILESTONE COMPLETE 🎉`
24
+ - `MILESTONE COMPLETE`
25
25
  - `SCANNING CODEBASE`
26
26
  - `DEBUGGING`
27
27
 
@@ -33,9 +33,9 @@ Use for major workflow transitions. Always use `PLAN-BUILD-RUN` prefix.
33
33
 
34
34
  Format:
35
35
  ```
36
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
37
- PLAN-BUILD-RUN ► {SKILL NAME}
38
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
36
+ ╔══════════════════════════════════════════════════════════════╗
37
+ PLAN-BUILD-RUN ► {SKILL NAME}
38
+ ╚══════════════════════════════════════════════════════════════╝
39
39
  ```
40
40
 
41
41
  **Skill names (uppercase):**
@@ -155,7 +155,7 @@ For research agents:
155
155
 
156
156
  ## Checkpoint Boxes
157
157
 
158
- User action required. Use double-line box drawing, 62-character width.
158
+ User action required. Use double-line box drawing, 62-character inner width.
159
159
 
160
160
  ```
161
161
  ╔══════════════════════════════════════════════════════════════╗
@@ -164,9 +164,7 @@ User action required. Use double-line box drawing, 62-character width.
164
164
 
165
165
  {Content}
166
166
 
167
- ──────────────────────────────────────────────────────────────
168
167
  → {ACTION PROMPT}
169
- ──────────────────────────────────────────────────────────────
170
168
  ```
171
169
 
172
170
  **Types:**
@@ -260,25 +258,21 @@ Use plain conversational prompts for these cases instead.
260
258
  Always present at end of major completions (phase complete, milestone complete, project init).
261
259
 
262
260
  ```
263
- ───────────────────────────────────────────────────────────────
264
-
265
- ## ▶ Next Up
261
+ ╔══════════════════════════════════════════════════════════════╗
262
+ ║ ▶ NEXT UP ║
263
+ ╚══════════════════════════════════════════════════════════════╝
266
264
 
267
265
  **{Identifier}: {Name}** — {one-line description}
268
266
 
269
267
  `{copy-paste command}`
270
268
 
271
269
  <sub>`/clear` first → fresh context window</sub>
272
-
273
- ───────────────────────────────────────────────────────────────
270
+ ```
274
271
 
275
272
  **Also available:**
276
273
  - `/pbr:alternative-1` — description
277
274
  - `/pbr:alternative-2` — description
278
275
 
279
- ───────────────────────────────────────────────────────────────
280
- ```
281
-
282
276
  **Shorter routing (for minor completions):**
283
277
  ```
284
278
  What's next?
@@ -333,18 +327,18 @@ Use tables for structured data:
333
327
  ### Phase Complete
334
328
 
335
329
  ```
336
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
337
- PLAN-BUILD-RUN ► PHASE {N} COMPLETE ✓
338
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
330
+ ╔══════════════════════════════════════════════════════════════╗
331
+ PLAN-BUILD-RUN ► PHASE {N} COMPLETE ✓
332
+ ╚══════════════════════════════════════════════════════════════╝
339
333
 
340
334
  **Phase {N}: {Name}**
341
335
 
342
336
  {X} plans executed
343
337
  Goal verified ✓
344
338
 
345
- ───────────────────────────────────────────────────────────────
346
-
347
- ## ▶ Next Up
339
+ ╔══════════════════════════════════════════════════════════════╗
340
+ ║ ▶ NEXT UP ║
341
+ ╚══════════════════════════════════════════════════════════════╝
348
342
 
349
343
  **Phase {N+1}: {Name}** — {Goal from ROADMAP.md}
350
344
 
@@ -352,30 +346,26 @@ Goal verified ✓
352
346
 
353
347
  <sub>/clear first → fresh context window</sub>
354
348
 
355
- ───────────────────────────────────────────────────────────────
356
-
357
349
  **Also available:**
358
350
  - /pbr:plan {N+1} — skip discussion, plan directly
359
351
  - /pbr:review {N} — manual acceptance testing before continuing
360
-
361
- ───────────────────────────────────────────────────────────────
362
352
  ```
363
353
 
364
354
  ### Milestone Complete
365
355
 
366
356
  ```
367
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
368
- PLAN-BUILD-RUN ► MILESTONE COMPLETE 🎉
369
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
357
+ ╔══════════════════════════════════════════════════════════════╗
358
+ PLAN-BUILD-RUN ► MILESTONE COMPLETE
359
+ ╚══════════════════════════════════════════════════════════════╝
370
360
 
371
361
  **{version}**
372
362
 
373
363
  {N} phases completed
374
364
  All phase goals verified ✓
375
365
 
376
- ───────────────────────────────────────────────────────────────
377
-
378
- ## ▶ Next Up
366
+ ╔══════════════════════════════════════════════════════════════╗
367
+ ║ ▶ NEXT UP ║
368
+ ╚══════════════════════════════════════════════════════════════╝
379
369
 
380
370
  **Audit milestone** — verify requirements, cross-phase integration, E2E flows
381
371
 
@@ -383,21 +373,17 @@ All phase goals verified ✓
383
373
 
384
374
  <sub>/clear first → fresh context window</sub>
385
375
 
386
- ───────────────────────────────────────────────────────────────
387
-
388
376
  **Also available:**
389
377
  - /pbr:review — manual acceptance testing
390
378
  - /pbr:milestone complete — archive milestone after audit passes
391
-
392
- ───────────────────────────────────────────────────────────────
393
379
  ```
394
380
 
395
381
  ### Gaps Found
396
382
 
397
383
  ```
398
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
399
- PLAN-BUILD-RUN ► PHASE {N} GAPS FOUND ⚠
400
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
384
+ ╔══════════════════════════════════════════════════════════════╗
385
+ PLAN-BUILD-RUN ► PHASE {N} GAPS FOUND ⚠
386
+ ╚══════════════════════════════════════════════════════════════╝
401
387
 
402
388
  **Phase {N}: {Name}**
403
389
 
@@ -408,9 +394,9 @@ Report: .planning/phases/{phase_dir}/VERIFICATION.md
408
394
 
409
395
  {Extract gap summaries from VERIFICATION.md}
410
396
 
411
- ───────────────────────────────────────────────────────────────
412
-
413
- ## ▶ Next Up
397
+ ╔══════════════════════════════════════════════════════════════╗
398
+ ║ ▶ NEXT UP ║
399
+ ╚══════════════════════════════════════════════════════════════╝
414
400
 
415
401
  **Plan gap closure** — create additional plans to complete the phase
416
402
 
@@ -418,13 +404,9 @@ Report: .planning/phases/{phase_dir}/VERIFICATION.md
418
404
 
419
405
  <sub>/clear first → fresh context window</sub>
420
406
 
421
- ───────────────────────────────────────────────────────────────
422
-
423
407
  **Also available:**
424
408
  - cat .planning/phases/{phase_dir}/VERIFICATION.md — see full report
425
409
  - /pbr:review {N} — manual testing before planning
426
-
427
- ───────────────────────────────────────────────────────────────
428
410
  ```
429
411
 
430
412
  ---
@@ -434,9 +416,9 @@ Report: .planning/phases/{phase_dir}/VERIFICATION.md
434
416
  Use for session lifecycle transitions (pause/resume):
435
417
 
436
418
  ```
437
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
438
- PLAN-BUILD-RUN ► SESSION RESTORED ✓
439
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
419
+ ╔══════════════════════════════════════════════════════════════╗
420
+ PLAN-BUILD-RUN ► SESSION RESTORED ✓
421
+ ╚══════════════════════════════════════════════════════════════╝
440
422
 
441
423
  Position: Phase {N} — {phase name}, Plan {M}
442
424
  Paused: {ISO datetime}
@@ -452,10 +434,11 @@ Other session banners: `SESSION SAVED ✓` (pause), `RESUMING SESSION` (resume s
452
434
  ## Anti-Patterns
453
435
 
454
436
  Do NOT:
455
- - Use varying box/banner widths
456
- - Mix banner styles (`===`, `---`, `***`) with `━━━` banners
437
+ - Use varying box/banner widths — always 62-character inner width
438
+ - Use `━━━` heavy bars or `───` thin dividers for banners/sections — use `╔═╗║╚═╝` boxes
439
+ - Mix banner styles (`===`, `---`, `***`) with double-line boxes
457
440
  - Skip `PLAN-BUILD-RUN ►` prefix in stage banners
458
- - Use random emoji (only `🎉` for milestone complete, `✓` for phase complete)
441
+ - Use random emoji (only for milestone complete, `✓` for phase complete)
459
442
  - Skip the "Next Up" block after major completions
460
443
  - Reference non-Plan-Build-Run commands (always use `/pbr:*` commands)
461
444
  - Use non-Plan-Build-Run branding in banners
@@ -113,6 +113,7 @@ function checkSkillRules(skill, filePath, planningDir) {
113
113
 
114
114
  switch (skill) {
115
115
  case 'quick':
116
+ case 'do':
116
117
  return checkQuickRules(filePath, isInPlanning, planningDir);
117
118
  case 'build':
118
119
  return checkBuildRules(filePath, isInPlanning, planningDir);
@@ -126,6 +127,16 @@ function checkSkillRules(skill, filePath, planningDir) {
126
127
  case 'explore':
127
128
  case 'import':
128
129
  case 'scan':
130
+ case 'note':
131
+ case 'todo':
132
+ case 'health':
133
+ case 'help':
134
+ case 'config':
135
+ case 'continue':
136
+ case 'resume':
137
+ case 'pause':
138
+ case 'status':
139
+ case 'dashboard':
129
140
  return checkReadOnlySkillRules(skill, filePath, isInPlanning);
130
141
  default:
131
142
  return null;
@@ -161,6 +161,10 @@ function updateStatePosition(content, updates) {
161
161
  for (let i = 0; i < lines.length; i++) {
162
162
  const line = lines[i];
163
163
 
164
+ if (updates.phaseLine !== undefined && /^Phase:\s/.test(line)) {
165
+ lines[i] = `Phase: ${updates.phaseLine}`;
166
+ }
167
+
164
168
  if (updates.planLine !== undefined && /^Plan:\s/.test(line)) {
165
169
  lines[i] = `Plan: ${updates.planLine}`;
166
170
  }
@@ -185,6 +189,18 @@ function updateStatePosition(content, updates) {
185
189
  let fm = content.substring(0, fmEnd + 3);
186
190
  const body = content.substring(fmEnd + 3);
187
191
 
192
+ if (updates.fmCurrentPhase !== undefined) {
193
+ fm = fm.replace(/^(current_phase:\s*).*/m, `$1${updates.fmCurrentPhase}`);
194
+ }
195
+ if (updates.fmTotalPhases !== undefined) {
196
+ fm = fm.replace(/^(total_phases:\s*).*/m, `$1${updates.fmTotalPhases}`);
197
+ }
198
+ if (updates.fmPhaseSlug !== undefined) {
199
+ fm = fm.replace(/^(phase_slug:\s*).*/m, `$1"${updates.fmPhaseSlug}"`);
200
+ }
201
+ if (updates.fmPhaseName !== undefined) {
202
+ fm = fm.replace(/^(phase_name:\s*).*/m, `$1"${updates.fmPhaseName}"`);
203
+ }
188
204
  if (updates.fmPlansComplete !== undefined) {
189
205
  fm = fm.replace(/^(plans_complete:\s*).*/m, `$1${updates.fmPlansComplete}`);
190
206
  }
@@ -216,6 +232,9 @@ function updateStatePositionBody(body, updates) {
216
232
  for (let i = 0; i < lines.length; i++) {
217
233
  const line = lines[i];
218
234
 
235
+ if (updates.phaseLine !== undefined && /^Phase:\s/.test(line)) {
236
+ lines[i] = `Phase: ${updates.phaseLine}`;
237
+ }
219
238
  if (updates.planLine !== undefined && /^Plan:\s/.test(line)) {
220
239
  lines[i] = `Plan: ${updates.planLine}`;
221
240
  }
@@ -323,6 +342,17 @@ function checkStateSync(data) {
323
342
  const today = new Date().toISOString().slice(0, 10);
324
343
  const messages = [];
325
344
 
345
+ // Derive phase metadata for potential phase-line sync
346
+ const phaseNumInt = parseInt(phaseNum, 10);
347
+ const phaseSlug = phaseDirName.replace(/^\d+-/, '');
348
+ const phaseName = phaseSlug.replace(/-/g, ' ')
349
+ .replace(/\b\w/g, c => c.toUpperCase());
350
+ let totalPhases = 0;
351
+ try {
352
+ totalPhases = fs.readdirSync(phasesDir, { withFileTypes: true })
353
+ .filter(e => e.isDirectory() && /^\d+-/.test(e.name)).length;
354
+ } catch (_e) { /* leave as 0 */ }
355
+
326
356
  if (isSummary) {
327
357
  const plansComplete = `${artifacts.completeSummaries}/${artifacts.plans}`;
328
358
  const allComplete = artifacts.completeSummaries >= artifacts.plans;
@@ -358,6 +388,20 @@ function checkStateSync(data) {
358
388
  fmLastActivity: today,
359
389
  fmProgressPct: overallPct
360
390
  };
391
+
392
+ // Detect phase mismatch and add phase updates
393
+ const currentPhaseMatch = stateContent.match(/^current_phase:\s*(\d+)/m)
394
+ || stateContent.match(/^Phase:\s*(\d+)\s/m);
395
+ const currentPhase = currentPhaseMatch ? parseInt(currentPhaseMatch[1], 10) : null;
396
+ if (currentPhase !== null && currentPhase !== phaseNumInt) {
397
+ stateUpdates.phaseLine = `${phaseNumInt} of ${totalPhases} (${phaseName})`;
398
+ stateUpdates.fmCurrentPhase = phaseNumInt;
399
+ stateUpdates.fmTotalPhases = totalPhases;
400
+ stateUpdates.fmPhaseSlug = phaseSlug;
401
+ stateUpdates.fmPhaseName = phaseName;
402
+ messages.push(`STATE.md: Phase ${currentPhase} → ${phaseNumInt}`);
403
+ }
404
+
361
405
  const updatedState = updateStatePosition(stateContent, stateUpdates);
362
406
  if (updatedState !== stateContent) {
363
407
  atomicWrite(statePath, updatedState);
@@ -422,6 +466,20 @@ function checkStateSync(data) {
422
466
  fmLastActivity: today,
423
467
  fmProgressPct: overallPct
424
468
  };
469
+
470
+ // Detect phase mismatch and add phase updates
471
+ const currentPhaseMatch = stateContent.match(/^current_phase:\s*(\d+)/m)
472
+ || stateContent.match(/^Phase:\s*(\d+)\s/m);
473
+ const currentPhase = currentPhaseMatch ? parseInt(currentPhaseMatch[1], 10) : null;
474
+ if (currentPhase !== null && currentPhase !== phaseNumInt) {
475
+ stateUpdates.phaseLine = `${phaseNumInt} of ${totalPhases} (${phaseName})`;
476
+ stateUpdates.fmCurrentPhase = phaseNumInt;
477
+ stateUpdates.fmTotalPhases = totalPhases;
478
+ stateUpdates.fmPhaseSlug = phaseSlug;
479
+ stateUpdates.fmPhaseName = phaseName;
480
+ messages.push(`STATE.md: Phase ${currentPhase} → ${phaseNumInt}`);
481
+ }
482
+
425
483
  const updatedState = updateStatePosition(stateContent, stateUpdates);
426
484
  if (updatedState !== stateContent) {
427
485
  atomicWrite(statePath, updatedState);
@@ -21,6 +21,19 @@ const fs = require('fs');
21
21
  const path = require('path');
22
22
  const { logHook } = require('./hook-logger');
23
23
 
24
+ /**
25
+ * Check if a file was modified recently (within thresholdMs).
26
+ * Returns false if file doesn't exist or on error.
27
+ */
28
+ function isRecent(filePath, thresholdMs = 300000) {
29
+ try {
30
+ const stat = fs.statSync(filePath);
31
+ return (Date.now() - stat.mtimeMs) < thresholdMs;
32
+ } catch (_e) {
33
+ return false;
34
+ }
35
+ }
36
+
24
37
  // Agent type → expected output patterns
25
38
  const AGENT_OUTPUTS = {
26
39
  'pbr:executor': {
@@ -46,9 +59,16 @@ const AGENT_OUTPUTS = {
46
59
  const researchDir = path.join(planningDir, 'research');
47
60
  if (!fs.existsSync(researchDir)) return [];
48
61
  try {
49
- return fs.readdirSync(researchDir)
62
+ const allFiles = fs.readdirSync(researchDir)
50
63
  .filter(f => f.endsWith('.md'))
51
64
  .map(f => path.join('research', f));
65
+ if (allFiles.length === 0) return [];
66
+ const recentFiles = allFiles.filter(f => isRecent(path.join(planningDir, f)));
67
+ if (recentFiles.length === 0) {
68
+ // Files exist but none are recent — return them but flag staleness
69
+ allFiles._stale = true;
70
+ }
71
+ return allFiles;
52
72
  } catch (_e) {
53
73
  return [];
54
74
  }
@@ -61,14 +81,27 @@ const AGENT_OUTPUTS = {
61
81
  if (fs.existsSync(researchDir)) {
62
82
  try {
63
83
  const files = fs.readdirSync(researchDir).filter(f => f.endsWith('.md'));
64
- if (files.length > 0) return files.map(f => path.join('research', f));
84
+ if (files.length > 0) {
85
+ const allFiles = files.map(f => path.join('research', f));
86
+ const recentFiles = allFiles.filter(f => isRecent(path.join(planningDir, f)));
87
+ if (recentFiles.length === 0) {
88
+ allFiles._stale = true;
89
+ }
90
+ return allFiles;
91
+ }
65
92
  } catch (_e) { /* best-effort */ }
66
93
  }
67
94
  const contextFile = path.join(planningDir, 'CONTEXT.md');
68
95
  if (fs.existsSync(contextFile)) {
69
96
  try {
70
97
  const stat = fs.statSync(contextFile);
71
- if (stat.size > 0) return ['CONTEXT.md'];
98
+ if (stat.size > 0) {
99
+ const result = ['CONTEXT.md'];
100
+ if (!isRecent(contextFile)) {
101
+ result._stale = true;
102
+ }
103
+ return result;
104
+ }
72
105
  } catch (_e) { /* best-effort */ }
73
106
  }
74
107
  return [];
@@ -255,6 +288,12 @@ function main() {
255
288
  // Skill-specific post-completion validation
256
289
  const skillWarnings = [];
257
290
 
291
+ // Mtime-based recency check for researcher and synthesizer
292
+ if (found._stale && (agentType === 'pbr:researcher' || agentType === 'pbr:synthesizer')) {
293
+ const label = agentType === 'pbr:researcher' ? 'Researcher' : 'Synthesizer';
294
+ skillWarnings.push(`${label} output may be stale — no recent output files detected.`);
295
+ }
296
+
258
297
  // GAP-04: Begin planner must produce core files
259
298
  if (activeSkill === 'begin' && agentType === 'pbr:planner') {
260
299
  const coreFiles = ['REQUIREMENTS.md', 'ROADMAP.md', 'STATE.md'];
@@ -317,5 +356,5 @@ function main() {
317
356
  process.exit(0);
318
357
  }
319
358
 
320
- module.exports = { AGENT_OUTPUTS, findInPhaseDir, findInQuickDir, checkSummaryCommits };
359
+ module.exports = { AGENT_OUTPUTS, findInPhaseDir, findInQuickDir, checkSummaryCommits, isRecent };
321
360
  if (require.main === module || process.argv[1] === __filename) { main(); }
@@ -114,7 +114,8 @@ function checkQuickExecutorGate(data) {
114
114
  return {
115
115
  block: true,
116
116
  reason: 'Cannot spawn executor: .planning/quick/ directory does not exist. ' +
117
- 'You must create the quick task directory and PLAN.md first (Steps 4-6).'
117
+ 'You must create the quick task directory and PLAN.md first (Steps 4-6). ' +
118
+ 'To fix: Re-run /pbr:quick to create the quick task directory and PLAN.md.'
118
119
  };
119
120
  }
120
121
 
@@ -138,13 +139,15 @@ function checkQuickExecutorGate(data) {
138
139
  return {
139
140
  block: true,
140
141
  reason: 'Cannot spawn executor: no PLAN.md found in any .planning/quick/*/ directory. ' +
141
- 'You must create .planning/quick/{NNN}-{slug}/PLAN.md first (Steps 4-6).'
142
+ 'You must create .planning/quick/{NNN}-{slug}/PLAN.md first (Steps 4-6). ' +
143
+ 'To fix: Re-run /pbr:quick to create the quick task directory and PLAN.md.'
142
144
  };
143
145
  }
144
146
  } catch (_e) {
145
147
  return {
146
148
  block: true,
147
- reason: 'Cannot spawn executor: failed to read .planning/quick/ directory.'
149
+ reason: 'Cannot spawn executor: failed to read .planning/quick/ directory. ' +
150
+ 'To fix: Re-run /pbr:quick to create the quick task directory and PLAN.md.'
148
151
  };
149
152
  }
150
153
 
@@ -187,7 +190,7 @@ function checkBuildExecutorGate(data) {
187
190
  if (!fs.existsSync(phasesDir)) {
188
191
  return {
189
192
  block: true,
190
- reason: 'Cannot spawn executor: .planning/phases/ directory does not exist. Run /pbr:plan first.'
193
+ reason: 'Cannot spawn executor: .planning/phases/ directory does not exist. To fix: Run /pbr:plan {N} to create plans first.'
191
194
  };
192
195
  }
193
196
 
@@ -195,7 +198,7 @@ function checkBuildExecutorGate(data) {
195
198
  if (dirs.length === 0) {
196
199
  return {
197
200
  block: true,
198
- reason: `Cannot spawn executor: no phase directory found for phase ${currentPhase}. Run /pbr:plan first.`
201
+ reason: `Cannot spawn executor: no phase directory found for phase ${currentPhase}. To fix: Run /pbr:plan ${currentPhase} to create plans first.`
199
202
  };
200
203
  }
201
204
 
@@ -213,7 +216,7 @@ function checkBuildExecutorGate(data) {
213
216
  if (!hasPlan) {
214
217
  return {
215
218
  block: true,
216
- reason: `Cannot spawn executor: no PLAN.md found in .planning/phases/${dirs[0]}/. Run /pbr:plan first.`
219
+ reason: `Cannot spawn executor: no PLAN.md found in .planning/phases/${dirs[0]}/. To fix: Run /pbr:plan ${currentPhase} to create plans first.`
217
220
  };
218
221
  }
219
222
  } catch (_e) {
@@ -248,7 +251,7 @@ function checkPlanExecutorGate(data) {
248
251
 
249
252
  return {
250
253
  block: true,
251
- reason: 'Plan skill should not spawn executors. Use /pbr:build to execute plans.'
254
+ reason: 'Plan skill should not spawn executors. To fix: Run /pbr:build to execute plans. The plan skill creates plans; the build skill executes them.'
252
255
  };
253
256
  }
254
257
 
@@ -296,7 +299,7 @@ function checkReviewPlannerGate(data) {
296
299
  if (!hasVerification) {
297
300
  return {
298
301
  block: true,
299
- reason: 'Review planner gate: Cannot spawn planner for gap closure without a VERIFICATION.md. Run /pbr:review first to generate verification results.'
302
+ reason: 'Review planner gate: Cannot spawn planner for gap closure without a VERIFICATION.md. To fix: Run /pbr:review {N} to create VERIFICATION.md first.'
300
303
  };
301
304
  }
302
305
  } catch (_e) {
@@ -358,7 +361,7 @@ function checkReviewVerifierGate(data) {
358
361
  if (!hasSummary) {
359
362
  return {
360
363
  block: true,
361
- reason: 'Review verifier gate: Cannot spawn verifier without SUMMARY.md in phase directory. Run /pbr:build first.'
364
+ reason: 'Review verifier gate: Cannot spawn verifier without SUMMARY.md in phase directory. To fix: Run /pbr:build {N} to create SUMMARY.md first.'
362
365
  };
363
366
  }
364
367
  } catch (_e) {
@@ -443,14 +446,22 @@ function checkMilestoneCompleteGate(data) {
443
446
  if (pDirs.length === 0) {
444
447
  return {
445
448
  block: true,
446
- reason: `Milestone complete gate: Phase ${paddedPhase} directory not found. All milestone phases must be verified before completing milestone.`
449
+ reason: `Milestone complete gate: Phase ${paddedPhase} directory not found. All milestone phases must be verified before completing milestone. To fix: Run /pbr:review ${paddedPhase} — phase must have status: passed.`
447
450
  };
448
451
  }
449
- const hasVerification = fs.existsSync(path.join(phasesDir, pDirs[0], 'VERIFICATION.md'));
452
+ const verificationFile = path.join(phasesDir, pDirs[0], 'VERIFICATION.md');
453
+ const hasVerification = fs.existsSync(verificationFile);
450
454
  if (!hasVerification) {
451
455
  return {
452
456
  block: true,
453
- reason: `Milestone complete gate: Phase ${paddedPhase} (${pDirs[0]}) lacks VERIFICATION.md. All milestone phases must be verified before completing milestone.`
457
+ reason: `Milestone complete gate: Phase ${paddedPhase} (${pDirs[0]}) lacks VERIFICATION.md. All milestone phases must be verified before completing milestone. To fix: Run /pbr:review ${paddedPhase} — phase must have status: passed.`
458
+ };
459
+ }
460
+ const verStatus = getVerificationStatus(verificationFile);
461
+ if (verStatus === 'gaps_found') {
462
+ return {
463
+ block: true,
464
+ reason: `Milestone complete gate: Phase ${paddedPhase} VERIFICATION.md has status: gaps_found. Close all gaps before completing milestone. To fix: Run /pbr:review ${paddedPhase} — phase must have status: passed.`
454
465
  };
455
466
  }
456
467
  }
@@ -538,14 +549,14 @@ function checkBuildDependencyGate(data) {
538
549
  if (pDirs.length === 0) {
539
550
  return {
540
551
  block: true,
541
- reason: `Build dependency gate: Dependent phase ${paddedPhase} lacks VERIFICATION.md. Run /pbr:review on dependent phases first.`
552
+ reason: `Build dependency gate: Dependent phase ${paddedPhase} lacks VERIFICATION.md. To fix: Run /pbr:review on the dependency phase first.`
542
553
  };
543
554
  }
544
555
  const hasVerification = fs.existsSync(path.join(phasesDir, pDirs[0], 'VERIFICATION.md'));
545
556
  if (!hasVerification) {
546
557
  return {
547
558
  block: true,
548
- reason: `Build dependency gate: Dependent phase ${paddedPhase} lacks VERIFICATION.md. Run /pbr:review on dependent phases first.`
559
+ reason: `Build dependency gate: Dependent phase ${paddedPhase} lacks VERIFICATION.md. To fix: Run /pbr:review on the dependency phase first.`
549
560
  };
550
561
  }
551
562
  }
@@ -561,6 +572,45 @@ function checkBuildDependencyGate(data) {
561
572
  * spawned, warn if .checkpoint-manifest.json is missing in the phase dir.
562
573
  * Returns a warning string or null.
563
574
  */
575
+ /**
576
+ * Parse VERIFICATION.md frontmatter to extract status field.
577
+ * Returns the status string or 'unknown' if not parseable.
578
+ */
579
+ function getVerificationStatus(filePath) {
580
+ try {
581
+ const content = fs.readFileSync(filePath, 'utf8');
582
+ const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
583
+ if (!fmMatch) return 'unknown';
584
+ const statusMatch = fmMatch[1].match(/^status:\s*(\S+)/m);
585
+ return statusMatch ? statusMatch[1] : 'unknown';
586
+ } catch (_e) {
587
+ return 'unknown';
588
+ }
589
+ }
590
+
591
+ /**
592
+ * Advisory check: when pbr:debugger is spawned and .active-skill is 'debug',
593
+ * warn if .planning/debug/ directory does not exist.
594
+ * Returns a warning string or null.
595
+ */
596
+ function checkDebuggerAdvisory(data) {
597
+ const subagentType = data.tool_input?.subagent_type || '';
598
+ if (subagentType !== 'pbr:debugger') return null;
599
+ // Only advise when spawned from the debug skill
600
+ const activeSkillPath = path.join(process.cwd(), '.planning', '.active-skill');
601
+ try {
602
+ const activeSkill = fs.readFileSync(activeSkillPath, 'utf8').trim();
603
+ if (activeSkill !== 'debug') return null;
604
+ } catch (_e) {
605
+ return null; // No .active-skill file — skip advisory
606
+ }
607
+ const debugDir = path.join(process.cwd(), '.planning', 'debug');
608
+ if (!fs.existsSync(debugDir)) {
609
+ return 'Debugger advisory: .planning/debug/ does not exist. Create it before spawning the debugger so output has a target location.';
610
+ }
611
+ return null;
612
+ }
613
+
564
614
  function checkCheckpointManifest(data) {
565
615
  const toolInput = data.tool_input || {};
566
616
  const subagentType = toolInput.subagent_type || '';
@@ -595,7 +645,7 @@ function checkCheckpointManifest(data) {
595
645
  const phaseDir = path.join(phasesDir, dirs[0]);
596
646
  const manifestFile = path.join(phaseDir, '.checkpoint-manifest.json');
597
647
  if (!fs.existsSync(manifestFile)) {
598
- return 'Build advisory: .checkpoint-manifest.json not found in phase directory. The build skill should write this before spawning executors.';
648
+ return 'Build advisory: .checkpoint-manifest.json not found in phase directory. The build skill should write this before spawning executors. To fix: Run /pbr:health to regenerate checkpoint manifest.';
599
649
  }
600
650
  } catch (_e) {
601
651
  return null;
@@ -624,7 +674,7 @@ function checkActiveSkillIntegrity(data) {
624
674
 
625
675
  const activeSkillFile = path.join(planningDir, '.active-skill');
626
676
  if (!fs.existsSync(activeSkillFile)) {
627
- return 'Active-skill integrity: .planning/.active-skill not found. Skill-specific enforcement is disabled. The invoking skill should write this file.';
677
+ return 'Active-skill integrity: .planning/.active-skill not found. Skill-specific enforcement is disabled. The invoking skill should write this file. To fix: Wait for the current skill to finish, or delete .planning/.active-skill if stale.';
628
678
  }
629
679
 
630
680
  return null;
@@ -727,6 +777,8 @@ function main() {
727
777
  const warnings = checkTask(data);
728
778
  const manifestWarning = checkCheckpointManifest(data);
729
779
  if (manifestWarning) warnings.push(manifestWarning);
780
+ const debuggerWarning = checkDebuggerAdvisory(data);
781
+ if (debuggerWarning) warnings.push(debuggerWarning);
730
782
  const activeSkillWarning = checkActiveSkillIntegrity(data);
731
783
  if (activeSkillWarning) warnings.push(activeSkillWarning);
732
784
 
@@ -747,5 +799,5 @@ function main() {
747
799
  });
748
800
  }
749
801
 
750
- module.exports = { checkTask, checkQuickExecutorGate, checkBuildExecutorGate, checkPlanExecutorGate, checkReviewPlannerGate, checkReviewVerifierGate, checkMilestoneCompleteGate, checkBuildDependencyGate, checkCheckpointManifest, checkActiveSkillIntegrity, KNOWN_AGENTS, MAX_DESCRIPTION_LENGTH };
802
+ module.exports = { checkTask, checkQuickExecutorGate, checkBuildExecutorGate, checkPlanExecutorGate, checkReviewPlannerGate, checkReviewVerifierGate, checkMilestoneCompleteGate, checkBuildDependencyGate, checkCheckpointManifest, checkDebuggerAdvisory, getVerificationStatus, checkActiveSkillIntegrity, KNOWN_AGENTS, MAX_DESCRIPTION_LENGTH };
751
803
  if (require.main === module || process.argv[1] === __filename) { main(); }