gsd-pi 2.38.0-dev.96dc7fb → 2.38.0-dev.98b44dc

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 (217) hide show
  1. package/README.md +15 -11
  2. package/dist/app-paths.js +1 -1
  3. package/dist/extension-registry.js +2 -2
  4. package/dist/remote-questions-config.js +2 -2
  5. package/dist/resource-loader.js +34 -1
  6. package/dist/resources/extensions/browser-tools/index.js +3 -1
  7. package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
  8. package/dist/resources/extensions/env-utils.js +29 -0
  9. package/dist/resources/extensions/get-secrets-from-user.js +5 -24
  10. package/dist/resources/extensions/github-sync/cli.js +284 -0
  11. package/dist/resources/extensions/github-sync/index.js +73 -0
  12. package/dist/resources/extensions/github-sync/mapping.js +67 -0
  13. package/dist/resources/extensions/github-sync/sync.js +424 -0
  14. package/dist/resources/extensions/github-sync/templates.js +118 -0
  15. package/dist/resources/extensions/github-sync/types.js +7 -0
  16. package/dist/resources/extensions/gsd/auto/session.js +6 -23
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
  18. package/dist/resources/extensions/gsd/auto-loop.js +636 -594
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +99 -70
  20. package/dist/resources/extensions/gsd/auto-prompts.js +202 -48
  21. package/dist/resources/extensions/gsd/auto-start.js +7 -1
  22. package/dist/resources/extensions/gsd/auto-worktree-sync.js +2 -1
  23. package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
  24. package/dist/resources/extensions/gsd/auto.js +143 -96
  25. package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
  26. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  27. package/dist/resources/extensions/gsd/commands.js +4 -2
  28. package/dist/resources/extensions/gsd/context-budget.js +2 -10
  29. package/dist/resources/extensions/gsd/detection.js +1 -2
  30. package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  31. package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
  32. package/dist/resources/extensions/gsd/doctor.js +20 -1
  33. package/dist/resources/extensions/gsd/exit-command.js +2 -1
  34. package/dist/resources/extensions/gsd/export.js +1 -1
  35. package/dist/resources/extensions/gsd/files.js +48 -9
  36. package/dist/resources/extensions/gsd/forensics.js +1 -1
  37. package/dist/resources/extensions/gsd/git-service.js +30 -12
  38. package/dist/resources/extensions/gsd/gitignore.js +16 -3
  39. package/dist/resources/extensions/gsd/guided-flow.js +149 -38
  40. package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
  41. package/dist/resources/extensions/gsd/health-widget.js +3 -86
  42. package/dist/resources/extensions/gsd/index.js +24 -20
  43. package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
  44. package/dist/resources/extensions/gsd/migrate-external.js +18 -1
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
  46. package/dist/resources/extensions/gsd/paths.js +3 -0
  47. package/dist/resources/extensions/gsd/preferences-models.js +0 -12
  48. package/dist/resources/extensions/gsd/preferences-types.js +1 -1
  49. package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
  50. package/dist/resources/extensions/gsd/preferences.js +22 -11
  51. package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
  52. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  53. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
  55. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
  56. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  57. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  58. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  59. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  60. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  62. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  63. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  64. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  65. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  66. package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
  67. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  68. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  69. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  71. package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
  72. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  73. package/dist/resources/extensions/gsd/repo-identity.js +21 -4
  74. package/dist/resources/extensions/gsd/resource-version.js +2 -1
  75. package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
  76. package/dist/resources/extensions/gsd/state.js +42 -23
  77. package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
  78. package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
  79. package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
  80. package/dist/resources/extensions/mcp-client/index.js +14 -1
  81. package/dist/resources/extensions/remote-questions/status.js +4 -1
  82. package/dist/resources/extensions/remote-questions/store.js +4 -1
  83. package/dist/resources/extensions/search-the-web/provider.js +2 -1
  84. package/dist/resources/extensions/shared/frontmatter.js +1 -1
  85. package/dist/resources/extensions/subagent/isolation.js +2 -1
  86. package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
  87. package/package.json +1 -1
  88. package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
  89. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
  90. package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
  91. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  92. package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
  93. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
  95. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/skills.js +6 -1
  97. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  98. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  99. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  100. package/packages/pi-coding-agent/dist/index.js +1 -1
  101. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  102. package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
  103. package/packages/pi-coding-agent/src/core/skills.ts +9 -1
  104. package/packages/pi-coding-agent/src/index.ts +1 -0
  105. package/src/resources/extensions/browser-tools/index.ts +3 -0
  106. package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
  107. package/src/resources/extensions/env-utils.ts +31 -0
  108. package/src/resources/extensions/get-secrets-from-user.ts +5 -24
  109. package/src/resources/extensions/github-sync/cli.ts +364 -0
  110. package/src/resources/extensions/github-sync/index.ts +93 -0
  111. package/src/resources/extensions/github-sync/mapping.ts +81 -0
  112. package/src/resources/extensions/github-sync/sync.ts +556 -0
  113. package/src/resources/extensions/github-sync/templates.ts +183 -0
  114. package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
  115. package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
  116. package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
  117. package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
  118. package/src/resources/extensions/github-sync/types.ts +47 -0
  119. package/src/resources/extensions/gsd/auto/session.ts +7 -25
  120. package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
  121. package/src/resources/extensions/gsd/auto-loop.ts +526 -545
  122. package/src/resources/extensions/gsd/auto-post-unit.ts +80 -44
  123. package/src/resources/extensions/gsd/auto-prompts.ts +247 -50
  124. package/src/resources/extensions/gsd/auto-start.ts +11 -1
  125. package/src/resources/extensions/gsd/auto-worktree-sync.ts +3 -1
  126. package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
  127. package/src/resources/extensions/gsd/auto.ts +139 -101
  128. package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
  129. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  130. package/src/resources/extensions/gsd/commands.ts +5 -3
  131. package/src/resources/extensions/gsd/context-budget.ts +2 -12
  132. package/src/resources/extensions/gsd/detection.ts +2 -2
  133. package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  134. package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
  135. package/src/resources/extensions/gsd/doctor.ts +22 -1
  136. package/src/resources/extensions/gsd/exit-command.ts +2 -2
  137. package/src/resources/extensions/gsd/export.ts +1 -1
  138. package/src/resources/extensions/gsd/files.ts +51 -11
  139. package/src/resources/extensions/gsd/forensics.ts +1 -1
  140. package/src/resources/extensions/gsd/git-service.ts +44 -10
  141. package/src/resources/extensions/gsd/gitignore.ts +17 -3
  142. package/src/resources/extensions/gsd/guided-flow.ts +177 -44
  143. package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
  144. package/src/resources/extensions/gsd/health-widget.ts +3 -89
  145. package/src/resources/extensions/gsd/index.ts +24 -17
  146. package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
  147. package/src/resources/extensions/gsd/migrate-external.ts +18 -1
  148. package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
  149. package/src/resources/extensions/gsd/paths.ts +4 -0
  150. package/src/resources/extensions/gsd/preferences-models.ts +0 -12
  151. package/src/resources/extensions/gsd/preferences-types.ts +4 -4
  152. package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
  153. package/src/resources/extensions/gsd/preferences.ts +25 -11
  154. package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
  155. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  156. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  157. package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
  158. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
  159. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  160. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  161. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  162. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  163. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  164. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  165. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  166. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  167. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  168. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  169. package/src/resources/extensions/gsd/prompts/queue.md +4 -8
  170. package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  171. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  172. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  173. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  174. package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
  175. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  176. package/src/resources/extensions/gsd/repo-identity.ts +23 -4
  177. package/src/resources/extensions/gsd/resource-version.ts +3 -1
  178. package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
  179. package/src/resources/extensions/gsd/state.ts +39 -21
  180. package/src/resources/extensions/gsd/templates/runtime.md +21 -0
  181. package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
  182. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
  183. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +122 -68
  184. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
  185. package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
  186. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
  187. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
  188. package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
  189. package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
  190. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
  191. package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
  192. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
  193. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
  194. package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
  195. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
  196. package/src/resources/extensions/gsd/types.ts +18 -1
  197. package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
  198. package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
  199. package/src/resources/extensions/mcp-client/index.ts +17 -1
  200. package/src/resources/extensions/remote-questions/status.ts +5 -1
  201. package/src/resources/extensions/remote-questions/store.ts +5 -1
  202. package/src/resources/extensions/search-the-web/provider.ts +2 -1
  203. package/src/resources/extensions/shared/frontmatter.ts +1 -1
  204. package/src/resources/extensions/subagent/isolation.ts +3 -1
  205. package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
  206. package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
  207. package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
  208. package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
  209. package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
  210. package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
  211. package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
  212. package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
  213. package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
  214. package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
  215. package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
  216. package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
  217. package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
@@ -22,7 +22,6 @@ import { writeUnitRuntimeRecord, clearUnitRuntimeRecord } from "./unit-runtime.j
22
22
  import { runGSDDoctor, rebuildState, summarizeDoctorIssues } from "./doctor.js";
23
23
  import { recordHealthSnapshot, checkHealEscalation } from "./doctor-proactive.js";
24
24
  import { syncStateToProjectRoot } from "./auto-worktree-sync.js";
25
- import { resetRewriteCircuitBreaker } from "./auto-dispatch.js";
26
25
  import { isDbAvailable } from "./gsd-db.js";
27
26
  import { consumeSignal } from "./session-status-io.js";
28
27
  import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookState, } from "./post-unit-hooks.js";
@@ -36,7 +35,7 @@ const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
36
35
  *
37
36
  * Returns "dispatched" if a signal caused stop/pause, "continue" to proceed.
38
37
  */
39
- export async function postUnitPreVerification(pctx) {
38
+ export async function postUnitPreVerification(pctx, opts) {
40
39
  const { s, ctx, pi, buildSnapshotOpts, stopAuto, pauseAuto } = pctx;
41
40
  // ── Parallel worker signal check ──
42
41
  const milestoneLock = process.env.GSD_MILESTONE_LOCK;
@@ -55,8 +54,10 @@ export async function postUnitPreVerification(pctx) {
55
54
  }
56
55
  // Invalidate all caches
57
56
  invalidateAllCaches();
58
- // Small delay to let files settle
59
- await new Promise(r => setTimeout(r, 500));
57
+ // Small delay to let files settle (skipped for sidecars where latency matters more)
58
+ if (!opts?.skipSettleDelay) {
59
+ await new Promise(r => setTimeout(r, 100));
60
+ }
60
61
  // Auto-commit
61
62
  if (s.currentUnit) {
62
63
  try {
@@ -71,16 +72,26 @@ export async function postUnitPreVerification(pctx) {
71
72
  const summaryContent = await loadFile(summaryPath);
72
73
  if (summaryContent) {
73
74
  const summary = parseSummary(summaryContent);
75
+ // Look up GitHub issue number for commit linking
76
+ let ghIssueNumber;
77
+ try {
78
+ const { getTaskIssueNumberForCommit } = await import("../github-sync/sync.js");
79
+ ghIssueNumber = getTaskIssueNumberForCommit(s.basePath, mid, sid, tid) ?? undefined;
80
+ }
81
+ catch {
82
+ // GitHub sync not available — skip
83
+ }
74
84
  taskContext = {
75
85
  taskId: `${sid}/${tid}`,
76
86
  taskTitle: summary.title?.replace(/^T\d+:\s*/, "") || tid,
77
87
  oneLiner: summary.oneLiner || undefined,
78
88
  keyFiles: summary.frontmatter.key_files?.filter(f => !f.includes("{{")) || undefined,
89
+ issueNumber: ghIssueNumber,
79
90
  };
80
91
  }
81
92
  }
82
- catch {
83
- // Non-fatal
93
+ catch (e) {
94
+ debugLog("postUnit", { phase: "task-summary-parse", error: String(e) });
84
95
  }
85
96
  }
86
97
  }
@@ -90,57 +101,75 @@ export async function postUnitPreVerification(pctx) {
90
101
  ctx.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
91
102
  }
92
103
  }
93
- catch {
94
- // Non-fatal
104
+ catch (e) {
105
+ debugLog("postUnit", { phase: "auto-commit", error: String(e) });
95
106
  }
96
- // Doctor: fix mechanical bookkeeping
107
+ // GitHub sync (non-blocking, opt-in)
97
108
  try {
98
- const scopeParts = s.currentUnit.id.split("/").slice(0, 2);
99
- const doctorScope = scopeParts.join("/");
100
- const sliceTerminalUnits = new Set(["complete-slice", "run-uat"]);
101
- const effectiveFixLevel = sliceTerminalUnits.has(s.currentUnit.type) ? "all" : "task";
102
- const report = await runGSDDoctor(s.basePath, { fix: true, scope: doctorScope, fixLevel: effectiveFixLevel });
103
- if (report.fixesApplied.length > 0) {
104
- ctx.ui.notify(`Post-hook: applied ${report.fixesApplied.length} fix(es).`, "info");
105
- }
106
- // Proactive health tracking
107
- const summary = summarizeDoctorIssues(report.issues);
108
- recordHealthSnapshot(summary.errors, summary.warnings, report.fixesApplied.length);
109
- // Check if we should escalate to LLM-assisted heal
110
- if (summary.errors > 0) {
111
- const unresolvedErrors = report.issues
112
- .filter(i => i.severity === "error" && !i.fixable)
113
- .map(i => ({ code: i.code, message: i.message, unitId: i.unitId }));
114
- const escalation = checkHealEscalation(summary.errors, unresolvedErrors);
115
- if (escalation.shouldEscalate) {
116
- ctx.ui.notify(`Doctor heal escalation: ${escalation.reason}. Dispatching LLM-assisted heal.`, "warning");
117
- try {
118
- const { formatDoctorIssuesForPrompt, formatDoctorReport } = await import("./doctor.js");
119
- const { dispatchDoctorHeal } = await import("./commands-handlers.js");
120
- const actionable = report.issues.filter(i => i.severity === "error");
121
- const reportText = formatDoctorReport(report, { scope: doctorScope, includeWarnings: true });
122
- const structuredIssues = formatDoctorIssuesForPrompt(actionable);
123
- dispatchDoctorHeal(pi, doctorScope, reportText, structuredIssues);
124
- }
125
- catch {
126
- // Non-fatal
127
- }
128
- }
129
- }
109
+ const { runGitHubSync } = await import("../github-sync/sync.js");
110
+ await runGitHubSync(s.basePath, s.currentUnit.type, s.currentUnit.id);
130
111
  }
131
- catch {
132
- // Non-fatal
112
+ catch (e) {
113
+ debugLog("postUnit", { phase: "github-sync", error: String(e) });
133
114
  }
134
- // Throttled STATE.md rebuild
135
- const now = Date.now();
136
- if (now - s.lastStateRebuildAt >= STATE_REBUILD_MIN_INTERVAL_MS) {
115
+ // Doctor: fix mechanical bookkeeping (skipped for lightweight sidecars)
116
+ if (!opts?.skipDoctor)
137
117
  try {
138
- await rebuildState(s.basePath);
139
- s.lastStateRebuildAt = now;
140
- autoCommitCurrentBranch(s.basePath, "state-rebuild", s.currentUnit.id);
118
+ const scopeParts = s.currentUnit.id.split("/").slice(0, 2);
119
+ const doctorScope = scopeParts.join("/");
120
+ const sliceTerminalUnits = new Set(["complete-slice", "run-uat"]);
121
+ const effectiveFixLevel = sliceTerminalUnits.has(s.currentUnit.type) ? "all" : "task";
122
+ const report = await runGSDDoctor(s.basePath, { fix: true, scope: doctorScope, fixLevel: effectiveFixLevel });
123
+ if (report.fixesApplied.length > 0) {
124
+ ctx.ui.notify(`Post-hook: applied ${report.fixesApplied.length} fix(es).`, "info");
125
+ }
126
+ // Proactive health tracking — filter to current milestone to avoid
127
+ // cross-milestone stale errors inflating the escalation counter
128
+ const currentMilestoneId = s.currentUnit.id.split("/")[0];
129
+ const milestoneIssues = currentMilestoneId
130
+ ? report.issues.filter(i => i.unitId === currentMilestoneId ||
131
+ i.unitId.startsWith(`${currentMilestoneId}/`))
132
+ : report.issues;
133
+ const summary = summarizeDoctorIssues(milestoneIssues);
134
+ recordHealthSnapshot(summary.errors, summary.warnings, report.fixesApplied.length);
135
+ // Check if we should escalate to LLM-assisted heal
136
+ if (summary.errors > 0) {
137
+ const unresolvedErrors = milestoneIssues
138
+ .filter(i => i.severity === "error" && !i.fixable)
139
+ .map(i => ({ code: i.code, message: i.message, unitId: i.unitId }));
140
+ const escalation = checkHealEscalation(summary.errors, unresolvedErrors);
141
+ if (escalation.shouldEscalate) {
142
+ ctx.ui.notify(`Doctor heal escalation: ${escalation.reason}. Dispatching LLM-assisted heal.`, "warning");
143
+ try {
144
+ const { formatDoctorIssuesForPrompt, formatDoctorReport } = await import("./doctor.js");
145
+ const { dispatchDoctorHeal } = await import("./commands-handlers.js");
146
+ const actionable = report.issues.filter(i => i.severity === "error");
147
+ const reportText = formatDoctorReport(report, { scope: doctorScope, includeWarnings: true });
148
+ const structuredIssues = formatDoctorIssuesForPrompt(actionable);
149
+ dispatchDoctorHeal(pi, doctorScope, reportText, structuredIssues);
150
+ return "dispatched";
151
+ }
152
+ catch (e) {
153
+ debugLog("postUnit", { phase: "doctor-heal-dispatch", error: String(e) });
154
+ }
155
+ }
156
+ }
141
157
  }
142
- catch {
143
- // Non-fatal
158
+ catch (e) {
159
+ debugLog("postUnit", { phase: "doctor", error: String(e) });
160
+ }
161
+ // Throttled STATE.md rebuild (skipped for lightweight sidecars)
162
+ if (!opts?.skipStateRebuild) {
163
+ const now = Date.now();
164
+ if (now - s.lastStateRebuildAt >= STATE_REBUILD_MIN_INTERVAL_MS) {
165
+ try {
166
+ await rebuildState(s.basePath);
167
+ s.lastStateRebuildAt = now;
168
+ autoCommitCurrentBranch(s.basePath, "state-rebuild", s.currentUnit.id);
169
+ }
170
+ catch (e) {
171
+ debugLog("postUnit", { phase: "state-rebuild", error: String(e) });
172
+ }
144
173
  }
145
174
  }
146
175
  // Prune dead bg-shell processes
@@ -148,27 +177,27 @@ export async function postUnitPreVerification(pctx) {
148
177
  const { pruneDeadProcesses } = await import("../bg-shell/process-manager.js");
149
178
  pruneDeadProcesses();
150
179
  }
151
- catch {
152
- // Non-fatal
180
+ catch (e) {
181
+ debugLog("postUnit", { phase: "prune-bg-shell", error: String(e) });
153
182
  }
154
- // Sync worktree state back to project root
155
- if (s.originalBasePath && s.originalBasePath !== s.basePath) {
183
+ // Sync worktree state back to project root (skipped for lightweight sidecars)
184
+ if (!opts?.skipWorktreeSync && s.originalBasePath && s.originalBasePath !== s.basePath) {
156
185
  try {
157
186
  syncStateToProjectRoot(s.basePath, s.originalBasePath, s.currentMilestoneId);
158
187
  }
159
- catch {
160
- // Non-fatal
188
+ catch (e) {
189
+ debugLog("postUnit", { phase: "worktree-sync", error: String(e) });
161
190
  }
162
191
  }
163
192
  // Rewrite-docs completion
164
193
  if (s.currentUnit.type === "rewrite-docs") {
165
194
  try {
166
195
  await resolveAllOverrides(s.basePath);
167
- resetRewriteCircuitBreaker();
196
+ s.rewriteAttemptCount = 0;
168
197
  ctx.ui.notify("Override(s) resolved — rewrite-docs completed.", "info");
169
198
  }
170
- catch {
171
- // Non-fatal
199
+ catch (e) {
200
+ debugLog("postUnit", { phase: "rewrite-docs-resolve", error: String(e) });
172
201
  }
173
202
  }
174
203
  // Reactive state cleanup on slice completion
@@ -181,8 +210,8 @@ export async function postUnitPreVerification(pctx) {
181
210
  clearReactiveState(s.basePath, mid, sid);
182
211
  }
183
212
  }
184
- catch {
185
- // Non-fatal
213
+ catch (e) {
214
+ debugLog("postUnit", { phase: "reactive-state-cleanup", error: String(e) });
186
215
  }
187
216
  }
188
217
  // Post-triage: execute actionable resolutions
@@ -224,8 +253,8 @@ export async function postUnitPreVerification(pctx) {
224
253
  invalidateAllCaches();
225
254
  }
226
255
  }
227
- catch {
228
- // Non-fatal
256
+ catch (e) {
257
+ debugLog("postUnit", { phase: "artifact-verify", error: String(e) });
229
258
  }
230
259
  }
231
260
  else {
@@ -238,8 +267,8 @@ export async function postUnitPreVerification(pctx) {
238
267
  });
239
268
  clearUnitRuntimeRecord(s.basePath, s.currentUnit.type, s.currentUnit.id);
240
269
  }
241
- catch {
242
- // Non-fatal
270
+ catch (e) {
271
+ debugLog("postUnit", { phase: "hook-finalize", error: String(e) });
243
272
  }
244
273
  }
245
274
  }
@@ -352,8 +381,8 @@ export async function postUnitPostVerification(pctx) {
352
381
  }
353
382
  }
354
383
  }
355
- catch {
356
- // Triage check failure is non-fatal
384
+ catch (e) {
385
+ debugLog("postUnit", { phase: "triage-check", error: String(e) });
357
386
  }
358
387
  }
359
388
  // ── Quick-task dispatch ──
@@ -387,8 +416,8 @@ export async function postUnitPostVerification(pctx) {
387
416
  ctx.ui.notify(`Executing quick-task: ${capture.id} — "${capture.text}"`, "info");
388
417
  return "continue";
389
418
  }
390
- catch {
391
- // Non-fatal proceed to normal dispatch
419
+ catch (e) {
420
+ debugLog("postUnit", { phase: "quick-task-dispatch", error: String(e) });
392
421
  }
393
422
  }
394
423
  // Step mode → show wizard instead of dispatch