gsd-pi 2.44.0-dev.d25d507 → 2.45.0-dev.1afbdaa

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 (407) hide show
  1. package/dist/help-text.js +1 -1
  2. package/dist/loader.js +34 -0
  3. package/dist/resources/extensions/gsd/activity-log.js +7 -0
  4. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  5. package/dist/resources/extensions/gsd/auto/phases.js +63 -77
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  7. package/dist/resources/extensions/gsd/auto/session.js +0 -11
  8. package/dist/resources/extensions/gsd/auto-artifact-paths.js +112 -0
  9. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -96
  10. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  11. package/dist/resources/extensions/gsd/auto-start.js +23 -5
  12. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  13. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  14. package/dist/resources/extensions/gsd/auto-worktree.js +14 -10
  15. package/dist/resources/extensions/gsd/auto.js +42 -60
  16. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +170 -11
  17. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -0
  18. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  19. package/dist/resources/extensions/gsd/commands/context.js +0 -4
  20. package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
  21. package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
  22. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +1 -1
  23. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  24. package/dist/resources/extensions/gsd/crash-recovery.js +2 -4
  25. package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -44
  26. package/dist/resources/extensions/gsd/db-writer.js +40 -22
  27. package/dist/resources/extensions/gsd/doctor-checks.js +167 -2
  28. package/dist/resources/extensions/gsd/doctor.js +13 -3
  29. package/dist/resources/extensions/gsd/git-service.js +8 -3
  30. package/dist/resources/extensions/gsd/gsd-db.js +28 -4
  31. package/dist/resources/extensions/gsd/guided-flow.js +1 -2
  32. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  33. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  34. package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -18
  35. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  36. package/dist/resources/extensions/gsd/preferences.js +8 -4
  37. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
  38. package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  39. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  40. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -15
  41. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  42. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  43. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  44. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -3
  47. package/dist/resources/extensions/gsd/prompts/queue.md +2 -2
  48. package/dist/resources/extensions/gsd/prompts/quick-task.md +2 -0
  49. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  50. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  51. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  52. package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -3
  53. package/dist/resources/extensions/gsd/prompts/rethink.md +83 -0
  54. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  56. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  57. package/dist/resources/extensions/gsd/repo-identity.js +45 -7
  58. package/dist/resources/extensions/gsd/rethink.js +115 -0
  59. package/dist/resources/extensions/gsd/session-lock.js +1 -3
  60. package/dist/resources/extensions/gsd/state.js +48 -3
  61. package/dist/resources/extensions/gsd/sync-lock.js +89 -0
  62. package/dist/resources/extensions/gsd/tools/complete-milestone.js +61 -11
  63. package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -11
  64. package/dist/resources/extensions/gsd/tools/complete-task.js +50 -2
  65. package/dist/resources/extensions/gsd/tools/plan-milestone.js +37 -1
  66. package/dist/resources/extensions/gsd/tools/plan-slice.js +31 -1
  67. package/dist/resources/extensions/gsd/tools/plan-task.js +28 -1
  68. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +32 -2
  69. package/dist/resources/extensions/gsd/tools/reopen-slice.js +86 -0
  70. package/dist/resources/extensions/gsd/tools/reopen-task.js +90 -0
  71. package/dist/resources/extensions/gsd/tools/replan-slice.js +34 -2
  72. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  73. package/dist/resources/extensions/gsd/unit-ownership.js +85 -0
  74. package/dist/resources/extensions/gsd/workflow-events.js +102 -0
  75. package/dist/resources/extensions/gsd/workflow-logger.js +193 -0
  76. package/dist/resources/extensions/gsd/workflow-manifest.js +244 -0
  77. package/dist/resources/extensions/gsd/workflow-migration.js +280 -0
  78. package/dist/resources/extensions/gsd/workflow-projections.js +373 -0
  79. package/dist/resources/extensions/gsd/workflow-reconcile.js +411 -0
  80. package/dist/resources/extensions/gsd/worktree-manager.js +34 -3
  81. package/dist/resources/extensions/gsd/worktree-resolver.js +43 -0
  82. package/dist/resources/extensions/gsd/write-intercept.js +84 -0
  83. package/dist/resources/extensions/mcp-client/index.js +14 -0
  84. package/dist/resources/extensions/voice/index.js +11 -16
  85. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  88. package/dist/web/standalone/.next/build-manifest.json +3 -3
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  91. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  93. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found/page.js +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  110. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/index.html +1 -1
  151. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  152. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  153. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  154. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  156. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  157. package/dist/web/standalone/.next/server/app/page.js +1 -1
  158. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  160. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  163. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  164. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  165. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
  166. package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
  167. package/dist/web/standalone/.next/static/chunks/app/{page-b9367c5ae13b99c6.js → page-6654a8cca61a3d1c.js} +1 -1
  168. package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
  169. package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
  170. package/package.json +2 -1
  171. package/packages/native/dist/stream-process/index.js +2 -2
  172. package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
  173. package/packages/native/src/stream-process/index.ts +2 -2
  174. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  175. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  177. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  178. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  180. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  182. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  185. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  187. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  189. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  191. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  192. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  193. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  194. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  195. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  196. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  197. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +13 -1
  199. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  201. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  203. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  205. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  207. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/main.js +17 -0
  210. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  215. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  217. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  219. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  220. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  221. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  222. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  225. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  226. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  227. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  229. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  231. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  233. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  235. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  236. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  237. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  238. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  239. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  240. package/packages/pi-coding-agent/package.json +1 -1
  241. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  242. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  243. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  244. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  245. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  246. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  247. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  248. package/packages/pi-coding-agent/src/core/model-registry.ts +51 -4
  249. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  250. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  251. package/packages/pi-coding-agent/src/main.ts +19 -0
  252. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  253. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  254. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  255. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  256. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  257. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  258. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  259. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  260. package/pkg/package.json +1 -1
  261. package/src/resources/extensions/gsd/activity-log.ts +1 -0
  262. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  263. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -19
  264. package/src/resources/extensions/gsd/auto/phases.ts +69 -91
  265. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  266. package/src/resources/extensions/gsd/auto/session.ts +0 -18
  267. package/src/resources/extensions/gsd/auto-artifact-paths.ts +131 -0
  268. package/src/resources/extensions/gsd/auto-dashboard.ts +0 -1
  269. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -106
  270. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  271. package/src/resources/extensions/gsd/auto-start.ts +26 -5
  272. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  273. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  274. package/src/resources/extensions/gsd/auto-worktree.ts +17 -11
  275. package/src/resources/extensions/gsd/auto.ts +44 -86
  276. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +162 -11
  277. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  278. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  279. package/src/resources/extensions/gsd/commands/context.ts +0 -5
  280. package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
  281. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  282. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +1 -1
  283. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  284. package/src/resources/extensions/gsd/crash-recovery.ts +1 -5
  285. package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -50
  286. package/src/resources/extensions/gsd/db-writer.ts +41 -27
  287. package/src/resources/extensions/gsd/doctor-checks.ts +180 -2
  288. package/src/resources/extensions/gsd/doctor-types.ts +7 -1
  289. package/src/resources/extensions/gsd/doctor.ts +13 -4
  290. package/src/resources/extensions/gsd/git-service.ts +6 -2
  291. package/src/resources/extensions/gsd/gsd-db.ts +32 -4
  292. package/src/resources/extensions/gsd/guided-flow.ts +1 -2
  293. package/src/resources/extensions/gsd/journal.ts +6 -1
  294. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  295. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  296. package/src/resources/extensions/gsd/parallel-orchestrator.ts +5 -21
  297. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  298. package/src/resources/extensions/gsd/preferences.ts +7 -3
  299. package/src/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
  300. package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  301. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  302. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -15
  303. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  304. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  305. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  306. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  307. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  308. package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -3
  309. package/src/resources/extensions/gsd/prompts/queue.md +2 -2
  310. package/src/resources/extensions/gsd/prompts/quick-task.md +2 -0
  311. package/src/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  312. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  313. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  314. package/src/resources/extensions/gsd/prompts/research-slice.md +3 -3
  315. package/src/resources/extensions/gsd/prompts/rethink.md +83 -0
  316. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  317. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  318. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  319. package/src/resources/extensions/gsd/repo-identity.ts +46 -7
  320. package/src/resources/extensions/gsd/rethink.ts +154 -0
  321. package/src/resources/extensions/gsd/session-lock.ts +0 -4
  322. package/src/resources/extensions/gsd/state.ts +49 -1
  323. package/src/resources/extensions/gsd/sync-lock.ts +94 -0
  324. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +5 -13
  325. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +6 -10
  326. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  327. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +96 -0
  328. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +264 -228
  329. package/src/resources/extensions/gsd/tests/complete-task.test.ts +317 -250
  330. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  331. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +2 -8
  332. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -3
  333. package/src/resources/extensions/gsd/tests/db-writer.test.ts +79 -0
  334. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
  335. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +60 -0
  336. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  337. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  338. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +1 -1
  339. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  340. package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
  341. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +15 -24
  342. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  343. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  344. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  345. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  346. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  347. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +8 -9
  348. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +42 -3
  349. package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -1
  350. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +0 -7
  351. package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +7 -8
  352. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +20 -24
  353. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +0 -2
  354. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +9 -6
  355. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
  356. package/src/resources/extensions/gsd/tests/preferences.test.ts +7 -9
  357. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +174 -0
  358. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -21
  359. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
  360. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
  361. package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
  362. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +1 -4
  363. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  364. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +2 -3
  365. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
  366. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +122 -0
  367. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  368. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +2 -1
  369. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +175 -0
  370. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
  371. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  372. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +186 -0
  373. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +171 -0
  374. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  375. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
  376. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
  377. package/src/resources/extensions/gsd/tools/complete-milestone.ts +74 -11
  378. package/src/resources/extensions/gsd/tools/complete-slice.ts +68 -11
  379. package/src/resources/extensions/gsd/tools/complete-task.ts +63 -1
  380. package/src/resources/extensions/gsd/tools/plan-milestone.ts +45 -0
  381. package/src/resources/extensions/gsd/tools/plan-slice.ts +40 -0
  382. package/src/resources/extensions/gsd/tools/plan-task.ts +37 -1
  383. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +39 -1
  384. package/src/resources/extensions/gsd/tools/reopen-slice.ts +125 -0
  385. package/src/resources/extensions/gsd/tools/reopen-task.ts +129 -0
  386. package/src/resources/extensions/gsd/tools/replan-slice.ts +41 -1
  387. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  388. package/src/resources/extensions/gsd/types.ts +8 -0
  389. package/src/resources/extensions/gsd/unit-ownership.ts +104 -0
  390. package/src/resources/extensions/gsd/workflow-events.ts +154 -0
  391. package/src/resources/extensions/gsd/workflow-logger.ts +243 -0
  392. package/src/resources/extensions/gsd/workflow-manifest.ts +334 -0
  393. package/src/resources/extensions/gsd/workflow-migration.ts +345 -0
  394. package/src/resources/extensions/gsd/workflow-projections.ts +425 -0
  395. package/src/resources/extensions/gsd/workflow-reconcile.ts +503 -0
  396. package/src/resources/extensions/gsd/worktree-manager.ts +41 -5
  397. package/src/resources/extensions/gsd/worktree-resolver.ts +44 -0
  398. package/src/resources/extensions/gsd/write-intercept.ts +90 -0
  399. package/src/resources/extensions/mcp-client/index.ts +20 -0
  400. package/src/resources/extensions/voice/index.ts +11 -21
  401. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  402. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  403. package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
  404. package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
  405. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
  406. /package/dist/web/standalone/.next/static/{tokoGmfkYfWf1_Yl_Gz7i → j-BskPs0nxxPeYY-bSrab}/_buildManifest.js +0 -0
  407. /package/dist/web/standalone/.next/static/{tokoGmfkYfWf1_Yl_Gz7i → j-BskPs0nxxPeYY-bSrab}/_ssgManifest.js +0 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Timestamp formatting for message display.
3
+ *
4
+ * Formats:
5
+ * - "time-date-iso": 10:34 2025-03-24 (default)
6
+ * - "date-time-iso": 2025-03-24 10:34
7
+ * - "time-date-us": 10:34 AM 03/24/2025
8
+ * - "date-time-us": 03/24/2025 10:34 AM
9
+ */
10
+
11
+ export type TimestampFormat = "date-time-iso" | "date-time-us";
12
+
13
+ function pad2(n: number): string {
14
+ return n.toString().padStart(2, "0");
15
+ }
16
+
17
+ function isoDate(d: Date): string {
18
+ return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
19
+ }
20
+
21
+ function isoTime(d: Date): string {
22
+ return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
23
+ }
24
+
25
+ function usDate(d: Date): string {
26
+ return `${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}-${d.getFullYear()}`;
27
+ }
28
+
29
+ function usTime(d: Date): string {
30
+ const hours = d.getHours();
31
+ const period = hours >= 12 ? "PM" : "AM";
32
+ const h = hours % 12 || 12;
33
+ return `${h}:${pad2(d.getMinutes())} ${period}`;
34
+ }
35
+
36
+ /**
37
+ * Format a timestamp for message display using the specified format.
38
+ */
39
+ export function formatTimestamp(timestamp: number, format: TimestampFormat = "date-time-iso"): string {
40
+ const d = new Date(timestamp);
41
+
42
+ switch (format) {
43
+ case "date-time-iso":
44
+ return `${isoDate(d)} ${isoTime(d)}`;
45
+ case "date-time-us":
46
+ return `${usDate(d)} ${usTime(d)}`;
47
+ }
48
+ }
@@ -895,7 +895,9 @@ export class ToolExecutionComponent extends Container {
895
895
  // Server-side Anthropic web search
896
896
  text = theme.fg("toolTitle", theme.bold("web search"));
897
897
 
898
- if (this.result) {
898
+ if (process.env.PI_OFFLINE === "1") {
899
+ text += "\n\n" + theme.fg("muted", "\u{1F50C} Offline \u{2014} web search unavailable");
900
+ } else if (this.result) {
899
901
  const output = this.getTextOutput().trim();
900
902
  if (output) {
901
903
  const lines = output.split("\n");
@@ -1,15 +1,21 @@
1
- import { Container, Markdown, type MarkdownTheme, Spacer } from "@gsd/pi-tui";
1
+ import { Container, Markdown, type MarkdownTheme, Spacer, Text } from "@gsd/pi-tui";
2
2
  import { getMarkdownTheme, theme } from "../theme/theme.js";
3
+ import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
3
4
 
4
5
  const OSC133_ZONE_START = "\x1b]133;A\x07";
5
6
  const OSC133_ZONE_END = "\x1b]133;B\x07";
6
7
 
7
8
  /**
8
- * Component that renders a user message
9
+ * Component that renders a user message with a right-aligned timestamp.
9
10
  */
10
11
  export class UserMessageComponent extends Container {
11
- constructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme()) {
12
+ private timestamp: number | undefined;
13
+ private timestampFormat: TimestampFormat;
14
+
15
+ constructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), timestamp?: number, timestampFormat: TimestampFormat = "date-time-iso") {
12
16
  super();
17
+ this.timestamp = timestamp;
18
+ this.timestampFormat = timestampFormat;
13
19
  this.addChild(new Spacer(1));
14
20
  this.addChild(
15
21
  new Markdown(text, 1, 1, markdownTheme, {
@@ -25,6 +31,15 @@ export class UserMessageComponent extends Container {
25
31
  return lines;
26
32
  }
27
33
 
34
+ // Insert right-aligned timestamp above the message content
35
+ if (this.timestamp) {
36
+ const timeStr = formatTimestamp(this.timestamp, this.timestampFormat);
37
+ const label = theme.fg("dim", timeStr);
38
+ const padding = Math.max(0, width - timeStr.length - 1);
39
+ const timestampLine = " ".repeat(padding) + label;
40
+ lines.splice(0, 0, timestampLine);
41
+ }
42
+
28
43
  lines[0] = OSC133_ZONE_START + lines[0];
29
44
  lines[lines.length - 1] = lines[lines.length - 1] + OSC133_ZONE_END;
30
45
  return lines;
@@ -100,6 +100,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
100
100
  undefined,
101
101
  host.hideThinkingBlock,
102
102
  host.getMarkdownThemeWithSettings(),
103
+ host.settingsManager.getTimestampFormat(),
103
104
  );
104
105
  host.streamingMessage = event.message;
105
106
  host.chatContainer.addChild(host.streamingComponent);
@@ -144,13 +145,21 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
144
145
  } else if (content.type === "webSearchResult") {
145
146
  const component = host.pendingTools.get(content.toolUseId);
146
147
  if (component) {
147
- const searchContent = content.content;
148
- const isError = searchContent && typeof searchContent === "object" && "type" in (searchContent as any) && (searchContent as any).type === "web_search_tool_result_error";
149
- component.updateResult({
150
- content: [{ type: "text", text: host.formatWebSearchResult(searchContent) }],
151
- isError: !!isError,
152
- });
153
- host.pendingTools.delete(content.toolUseId);
148
+ if (process.env.PI_OFFLINE === "1") {
149
+ component.updateResult({
150
+ content: [{ type: "text", text: "Web search disabled (offline mode)" }],
151
+ isError: false,
152
+ });
153
+ host.pendingTools.delete(content.toolUseId);
154
+ } else {
155
+ const searchContent = content.content;
156
+ const isError = searchContent && typeof searchContent === "object" && "type" in (searchContent as any) && (searchContent as any).type === "web_search_tool_result_error";
157
+ component.updateResult({
158
+ content: [{ type: "text", text: host.formatWebSearchResult(searchContent) }],
159
+ isError: !!isError,
160
+ });
161
+ host.pendingTools.delete(content.toolUseId);
162
+ }
154
163
  }
155
164
  }
156
165
  }
@@ -2099,11 +2099,13 @@ export class InteractiveMode {
2099
2099
  const userComponent = new UserMessageComponent(
2100
2100
  skillBlock.userMessage,
2101
2101
  this.getMarkdownThemeWithSettings(),
2102
+ message.timestamp,
2103
+ this.settingsManager.getTimestampFormat(),
2102
2104
  );
2103
2105
  this.chatContainer.addChild(userComponent);
2104
2106
  }
2105
2107
  } else {
2106
- const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings());
2108
+ const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), message.timestamp, this.settingsManager.getTimestampFormat());
2107
2109
  this.chatContainer.addChild(userComponent);
2108
2110
  }
2109
2111
  if (options?.populateHistory) {
@@ -2117,6 +2119,7 @@ export class InteractiveMode {
2117
2119
  message,
2118
2120
  this.hideThinkingBlock,
2119
2121
  this.getMarkdownThemeWithSettings(),
2122
+ this.settingsManager.getTimestampFormat(),
2120
2123
  );
2121
2124
  this.chatContainer.addChild(assistantComponent);
2122
2125
  break;
@@ -2795,6 +2798,7 @@ export class InteractiveMode {
2795
2798
  respectGitignoreInPicker: this.settingsManager.getRespectGitignoreInPicker(),
2796
2799
  quietStartup: this.settingsManager.getQuietStartup(),
2797
2800
  clearOnShrink: this.settingsManager.getClearOnShrink(),
2801
+ timestampFormat: this.settingsManager.getTimestampFormat(),
2798
2802
  },
2799
2803
  {
2800
2804
  onAutoCompactChange: (enabled) => {
@@ -2898,6 +2902,9 @@ export class InteractiveMode {
2898
2902
  this.settingsManager.setRespectGitignoreInPicker(enabled);
2899
2903
  this.autocompleteProvider?.setRespectGitignore(enabled);
2900
2904
  },
2905
+ onTimestampFormatChange: (format) => {
2906
+ this.settingsManager.setTimestampFormat(format);
2907
+ },
2901
2908
  onCancel: () => {
2902
2909
  done();
2903
2910
  this.ui.requestRender();
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glittercowboy/gsd",
3
- "version": "2.44.0",
3
+ "version": "2.45.0",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -153,6 +153,7 @@ export function pruneActivityLogs(activityDir: string, retentionDays: number): v
153
153
  const cutoff = Date.now() - retentionDays * 86_400_000;
154
154
  for (const entry of entries) {
155
155
  if (entry.seq === maxSeq) continue; // always preserve highest-seq
156
+ if (retentionDays === 0) { try { unlinkSync(entry.filePath); } catch { /* skip */ } continue; }
156
157
  try {
157
158
  const mtime = statSync(entry.filePath).mtimeMs;
158
159
  if (Math.floor(mtime) <= cutoff) unlinkSync(entry.filePath);
@@ -18,6 +18,9 @@ export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
18
18
  "EDQUOT", // disk quota exceeded
19
19
  "EMFILE", // too many open files (process)
20
20
  "ENFILE", // too many open files (system)
21
+ "ECONNREFUSED", // connection refused (offline / local server down)
22
+ "ENOTFOUND", // DNS lookup failed (offline / no network)
23
+ "ENETUNREACH", // network unreachable (offline / no route)
21
24
  ]);
22
25
 
23
26
  /**
@@ -80,7 +80,6 @@ export interface LoopDeps {
80
80
  basePath: string,
81
81
  unitType: string,
82
82
  unitId: string,
83
- completedUnits: number,
84
83
  sessionFile?: string,
85
84
  ) => void;
86
85
  handleLostSessionLock: (
@@ -179,29 +178,11 @@ export interface LoopDeps {
179
178
  startedAt: number,
180
179
  opts?: CloseoutOptions & Record<string, unknown>,
181
180
  ) => Promise<void>;
182
- verifyExpectedArtifact: (
183
- unitType: string,
184
- unitId: string,
185
- basePath: string,
186
- ) => boolean;
187
- clearUnitRuntimeRecord: (
188
- basePath: string,
189
- unitType: string,
190
- unitId: string,
191
- ) => void;
192
- writeUnitRuntimeRecord: (
193
- basePath: string,
194
- unitType: string,
195
- unitId: string,
196
- startedAt: number,
197
- record: Record<string, unknown>,
198
- ) => void;
199
181
  recordOutcome: (unitType: string, tier: string, success: boolean) => void;
200
182
  writeLock: (
201
183
  lockBase: string,
202
184
  unitType: string,
203
185
  unitId: string,
204
- completedCount: number,
205
186
  sessionFile?: string,
206
187
  ) => void;
207
188
  captureAvailableSkills: () => void;
@@ -24,10 +24,15 @@ import {
24
24
  import { detectStuck } from "./detect-stuck.js";
25
25
  import { runUnit } from "./run-unit.js";
26
26
  import { debugLog } from "../debug-logger.js";
27
- import { gsdRoot } from "../paths.js";
28
- import { atomicWriteSync } from "../atomic-write.js";
29
27
  import { PROJECT_FILES } from "../detection.js";
28
+ import { MergeConflictError } from "../git-service.js";
30
29
  import { join } from "node:path";
30
+ import { existsSync, cpSync } from "node:fs";
31
+ import { logWarning, logError } from "../workflow-logger.js";
32
+ import { gsdRoot } from "../paths.js";
33
+ import { atomicWriteSync } from "../atomic-write.js";
34
+ import { verifyExpectedArtifact } from "../auto-recovery.js";
35
+ import { writeUnitRuntimeRecord } from "../unit-runtime.js";
31
36
 
32
37
  // ─── generateMilestoneReport ──────────────────────────────────────────────────
33
38
 
@@ -162,8 +167,8 @@ export async function runPreDispatch(
162
167
  debugLog("autoLoop", { phase: "exit", reason: "health-gate-failed" });
163
168
  return { action: "break", reason: "health-gate-failed" };
164
169
  }
165
- } catch {
166
- // Non-fatal
170
+ } catch (e) {
171
+ logWarning("engine", "Pre-dispatch health gate threw unexpectedly", { error: String(e) });
167
172
  }
168
173
 
169
174
  // Sync project root artifacts into worktree
@@ -233,26 +238,24 @@ export async function runPreDispatch(
233
238
  loopState.stuckRecoveryAttempts = 0;
234
239
 
235
240
  // Worktree lifecycle on milestone transition — merge current, enter next
236
- deps.resolver.mergeAndExit(s.currentMilestoneId!, ctx.ui);
237
-
238
- // Opt-in: create draft PR on milestone completion
239
- if (prefs?.git?.auto_pr) {
240
- try {
241
- const { createDraftPR } = await import("../git-service.js");
242
- const prUrl = createDraftPR(
243
- s.basePath,
244
- s.currentMilestoneId!,
245
- `[GSD] ${s.currentMilestoneId} complete`,
246
- `Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
241
+ try {
242
+ deps.resolver.mergeAndExit(s.currentMilestoneId!, ctx.ui);
243
+ } catch (mergeErr) {
244
+ if (mergeErr instanceof MergeConflictError) {
245
+ // Real code conflicts — stop the loop instead of retrying forever (#2330)
246
+ ctx.ui.notify(
247
+ `Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
248
+ "error",
247
249
  );
248
- if (prUrl) {
249
- ctx.ui.notify(`Draft PR created: ${prUrl}`, "info");
250
- }
251
- } catch {
252
- // Non-fatal — PR creation is best-effort
250
+ await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
251
+ return { action: "break", reason: "merge-conflict" };
253
252
  }
253
+ // Non-conflict merge errors — log and continue
254
+ logWarning("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
254
255
  }
255
256
 
257
+ // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
258
+
256
259
  deps.invalidateAllCaches();
257
260
 
258
261
  state = await deps.deriveState(s.basePath);
@@ -276,14 +279,20 @@ export async function runPreDispatch(
276
279
  .map((m: { id: string }) => m.id);
277
280
  deps.pruneQueueOrder(s.basePath, pendingIds);
278
281
 
279
- // Reset completed-units tracking for the new milestone — stale entries
280
- // from the previous milestone cause the dispatch loop to skip units
281
- // that haven't actually been completed in the new milestone's context.
282
- s.completedUnits = [];
282
+ // Archive the old completed-units.json instead of wiping it (#2313).
283
283
  try {
284
284
  const completedKeysPath = join(gsdRoot(s.basePath), "completed-units.json");
285
+ if (existsSync(completedKeysPath) && s.currentMilestoneId) {
286
+ const archivePath = join(
287
+ gsdRoot(s.basePath),
288
+ `completed-units-${s.currentMilestoneId}.json`,
289
+ );
290
+ cpSync(completedKeysPath, archivePath);
291
+ }
285
292
  atomicWriteSync(completedKeysPath, JSON.stringify([], null, 2));
286
- } catch { /* non-fatal */ }
293
+ } catch (e) {
294
+ logWarning("engine", "Failed to archive completed-units on milestone transition", { error: String(e) });
295
+ }
287
296
 
288
297
  // Rebuild STATE.md immediately so it reflects the new active milestone.
289
298
  // This bypasses the 30-second throttle in the normal rebuild path —
@@ -291,8 +300,8 @@ export async function runPreDispatch(
291
300
  // immediate write.
292
301
  try {
293
302
  await deps.rebuildState(s.basePath);
294
- } catch {
295
- // Non-fatal — STATE.md will be rebuilt on the next regular cycle
303
+ } catch (e) {
304
+ logWarning("engine", "STATE.md rebuild failed after milestone transition", { error: String(e) });
296
305
  }
297
306
  }
298
307
 
@@ -322,25 +331,20 @@ export async function runPreDispatch(
322
331
  if (incomplete.length === 0 && state.registry.length > 0) {
323
332
  // All milestones complete — merge milestone branch before stopping
324
333
  if (s.currentMilestoneId) {
325
- deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
326
-
327
- // Opt-in: create draft PR on milestone completion
328
- if (prefs?.git?.auto_pr) {
329
- try {
330
- const { createDraftPR } = await import("../git-service.js");
331
- const prUrl = createDraftPR(
332
- s.basePath,
333
- s.currentMilestoneId,
334
- `[GSD] ${s.currentMilestoneId} complete`,
335
- `Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
334
+ try {
335
+ deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
336
+ } catch (mergeErr) {
337
+ if (mergeErr instanceof MergeConflictError) {
338
+ ctx.ui.notify(
339
+ `Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
340
+ "error",
336
341
  );
337
- if (prUrl) {
338
- ctx.ui.notify(`Draft PR created: ${prUrl}`, "info");
339
- }
340
- } catch {
341
- // Non-fatal — PR creation is best-effort
342
+ await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
343
+ return { action: "break", reason: "merge-conflict" };
342
344
  }
343
345
  }
346
+
347
+ // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
344
348
  }
345
349
  deps.sendDesktopNotification(
346
350
  "GSD",
@@ -422,25 +426,20 @@ export async function runPreDispatch(
422
426
  if (state.phase === "complete") {
423
427
  // Milestone merge on complete (before closeout so branch state is clean)
424
428
  if (s.currentMilestoneId) {
425
- deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
426
-
427
- // Opt-in: create draft PR on milestone completion
428
- if (prefs?.git?.auto_pr) {
429
- try {
430
- const { createDraftPR } = await import("../git-service.js");
431
- const prUrl = createDraftPR(
432
- s.basePath,
433
- s.currentMilestoneId,
434
- `[GSD] ${s.currentMilestoneId} complete`,
435
- `Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
429
+ try {
430
+ deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
431
+ } catch (mergeErr) {
432
+ if (mergeErr instanceof MergeConflictError) {
433
+ ctx.ui.notify(
434
+ `Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
435
+ "error",
436
436
  );
437
- if (prUrl) {
438
- ctx.ui.notify(`Draft PR created: ${prUrl}`, "info");
439
- }
440
- } catch {
441
- // Non-fatal — PR creation is best-effort
437
+ await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
438
+ return { action: "break", reason: "merge-conflict" };
442
439
  }
443
440
  }
441
+
442
+ // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
444
443
  }
445
444
  deps.sendDesktopNotification(
446
445
  "GSD",
@@ -539,7 +538,7 @@ export async function runDispatch(
539
538
  if (loopState.stuckRecoveryAttempts === 0) {
540
539
  // Level 1: try verifying the artifact, then cache invalidation + retry
541
540
  loopState.stuckRecoveryAttempts++;
542
- const artifactExists = deps.verifyExpectedArtifact(
541
+ const artifactExists = verifyExpectedArtifact(
543
542
  unitType,
544
543
  unitId,
545
544
  s.basePath,
@@ -848,7 +847,7 @@ export async function runUnitPhase(
848
847
  const unitStartSeq = ic.nextSeq();
849
848
  deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
850
849
  deps.captureAvailableSkills();
851
- deps.writeUnitRuntimeRecord(
850
+ writeUnitRuntimeRecord(
852
851
  s.basePath,
853
852
  unitType,
854
853
  unitId,
@@ -860,6 +859,7 @@ export async function runUnitPhase(
860
859
  lastProgressAt: s.currentUnit.startedAt,
861
860
  progressCount: 0,
862
861
  lastProgressKind: "dispatch",
862
+ recoveryAttempts: 0, // Reset so re-dispatched units get full recovery budget (#2322)
863
863
  },
864
864
  );
865
865
 
@@ -921,8 +921,8 @@ export async function runUnitPhase(
921
921
  (decisionsContent?.length ?? 0) +
922
922
  (requirementsContent?.length ?? 0) +
923
923
  (projectContent?.length ?? 0);
924
- } catch {
925
- // Non-fatal
924
+ } catch (e) {
925
+ logWarning("engine", "Baseline char count measurement failed", { error: String(e) });
926
926
  }
927
927
  }
928
928
 
@@ -932,9 +932,7 @@ export async function runUnitPhase(
932
932
  } catch (reorderErr) {
933
933
  const msg =
934
934
  reorderErr instanceof Error ? reorderErr.message : String(reorderErr);
935
- process.stderr.write(
936
- `[gsd] prompt reorder failed (non-fatal): ${msg}\n`,
937
- );
935
+ logWarning("engine", "Prompt reorder failed", { error: msg });
938
936
  }
939
937
 
940
938
  // Select and apply model (with tier escalation on retry — normal units only)
@@ -1001,7 +999,6 @@ export async function runUnitPhase(
1001
999
  deps.lockBase(),
1002
1000
  unitType,
1003
1001
  unitId,
1004
- s.completedUnits.length,
1005
1002
  );
1006
1003
 
1007
1004
  debugLog("autoLoop", {
@@ -1032,14 +1029,12 @@ export async function runUnitPhase(
1032
1029
  deps.lockBase(),
1033
1030
  unitType,
1034
1031
  unitId,
1035
- s.completedUnits.length,
1036
1032
  sessionFile,
1037
1033
  );
1038
1034
  deps.writeLock(
1039
1035
  deps.lockBase(),
1040
1036
  unitType,
1041
1037
  unitId,
1042
- s.completedUnits.length,
1043
1038
  sessionFile,
1044
1039
  );
1045
1040
 
@@ -1103,8 +1098,8 @@ export async function runUnitPhase(
1103
1098
  `${unitType} ${unitId} completed with 0 tool calls — hallucinated summary, will retry`,
1104
1099
  "warning",
1105
1100
  );
1106
- // Do NOT add to completedUnits fall through to next iteration
1107
- // where dispatch will re-derive and re-dispatch this task.
1101
+ // Fall through to next iteration where dispatch will re-derive
1102
+ // and re-dispatch this task.
1108
1103
  return { action: "next", data: { unitStartedAt: s.currentUnit.startedAt } };
1109
1104
  }
1110
1105
  }
@@ -1121,25 +1116,8 @@ export async function runUnitPhase(
1121
1116
  const skipArtifactVerification = unitType.startsWith("hook/") || unitType === "custom-step";
1122
1117
  const artifactVerified =
1123
1118
  skipArtifactVerification ||
1124
- deps.verifyExpectedArtifact(unitType, unitId, s.basePath);
1119
+ verifyExpectedArtifact(unitType, unitId, s.basePath);
1125
1120
  if (artifactVerified) {
1126
- s.completedUnits.push({
1127
- type: unitType,
1128
- id: unitId,
1129
- startedAt: s.currentUnit.startedAt,
1130
- finishedAt: Date.now(),
1131
- });
1132
- if (s.completedUnits.length > 200) {
1133
- s.completedUnits = s.completedUnits.slice(-200);
1134
- }
1135
- // Flush completed-units to disk so the record survives crashes
1136
- try {
1137
- const completedKeysPath = join(gsdRoot(s.basePath), "completed-units.json");
1138
- const keys = s.completedUnits.map((u) => `${u.type}/${u.id}`);
1139
- atomicWriteSync(completedKeysPath, JSON.stringify(keys, null, 2));
1140
- } catch { /* non-fatal: disk flush failure */ }
1141
-
1142
- deps.clearUnitRuntimeRecord(s.basePath, unitType, unitId);
1143
1121
  s.unitDispatchCount.delete(`${unitType}/${unitId}`);
1144
1122
  s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
1145
1123
  }
@@ -1184,8 +1162,8 @@ export async function runFinalize(
1184
1162
  // Sidecar items use lightweight pre-verification opts
1185
1163
  const preVerificationOpts: PreVerificationOpts | undefined = sidecarItem
1186
1164
  ? sidecarItem.kind === "hook"
1187
- ? { skipSettleDelay: true, skipDoctor: true, skipStateRebuild: true, skipWorktreeSync: true }
1188
- : { skipSettleDelay: true, skipStateRebuild: true }
1165
+ ? { skipSettleDelay: true, skipWorktreeSync: true }
1166
+ : { skipSettleDelay: true }
1189
1167
  : undefined;
1190
1168
  const preResult = await deps.postUnitPreVerification(postUnitCtx, preVerificationOpts);
1191
1169
  if (preResult === "dispatched") {
@@ -11,6 +11,7 @@ import { NEW_SESSION_TIMEOUT_MS } from "./session.js";
11
11
  import type { UnitResult } from "./types.js";
12
12
  import { _setCurrentResolve, _setSessionSwitchInFlight } from "./resolve.js";
13
13
  import { debugLog } from "../debug-logger.js";
14
+ import { logWarning, logError } from "../workflow-logger.js";
14
15
 
15
16
  /**
16
17
  * Execute a single unit: create a new session, send the prompt, and await
@@ -85,7 +86,9 @@ export async function runUnit(
85
86
  if (process.cwd() !== s.basePath) {
86
87
  process.chdir(s.basePath);
87
88
  }
88
- } catch { /* non-fatal — chdir may fail if dir was removed */ }
89
+ } catch (e) {
90
+ logWarning("engine", "Failed to chdir to basePath before dispatch", { basePath: s.basePath, error: String(e) });
91
+ }
89
92
 
90
93
  // ── Send the prompt ──
91
94
  debugLog("runUnit", { phase: "send-message", unitType, unitId });
@@ -115,8 +118,8 @@ export async function runUnit(
115
118
  if (typeof cmdCtxAny?.clearQueue === "function") {
116
119
  (cmdCtxAny.clearQueue as () => unknown)();
117
120
  }
118
- } catch {
119
- // Non-fatal clearQueue may not be available in all contexts
121
+ } catch (e) {
122
+ logWarning("engine", "clearQueue failed after unit completion", { error: String(e) });
120
123
  }
121
124
 
122
125
  return result;
@@ -23,13 +23,6 @@ import type { BudgetAlertLevel } from "../auto-budget.js";
23
23
 
24
24
  // ─── Exported Types ──────────────────────────────────────────────────────────
25
25
 
26
- export interface CompletedUnit {
27
- type: string;
28
- id: string;
29
- startedAt: number;
30
- finishedAt: number;
31
- }
32
-
33
26
  export interface CurrentUnit {
34
27
  type: string;
35
28
  id: string;
@@ -106,7 +99,6 @@ export class AutoSession {
106
99
  // ── Current unit ─────────────────────────────────────────────────────────
107
100
  currentUnit: CurrentUnit | null = null;
108
101
  currentUnitRouting: UnitRouting | null = null;
109
- completedUnits: CompletedUnit[] = [];
110
102
  currentMilestoneId: string | null = null;
111
103
 
112
104
  // ── Model state ──────────────────────────────────────────────────────────
@@ -160,14 +152,6 @@ export class AutoSession {
160
152
  return this.originalBasePath || this.basePath;
161
153
  }
162
154
 
163
- completeCurrentUnit(): CompletedUnit | null {
164
- if (!this.currentUnit) return null;
165
- const done: CompletedUnit = { ...this.currentUnit, finishedAt: Date.now() };
166
- this.completedUnits.push(done);
167
- this.currentUnit = null;
168
- return done;
169
- }
170
-
171
155
  reset(): void {
172
156
  this.clearTimers();
173
157
 
@@ -193,7 +177,6 @@ export class AutoSession {
193
177
  // Unit
194
178
  this.currentUnit = null;
195
179
  this.currentUnitRouting = null;
196
- this.completedUnits = [];
197
180
  this.currentMilestoneId = null;
198
181
 
199
182
  // Model
@@ -234,7 +217,6 @@ export class AutoSession {
234
217
  activeRunDir: this.activeRunDir,
235
218
  currentMilestoneId: this.currentMilestoneId,
236
219
  currentUnit: this.currentUnit,
237
- completedUnits: this.completedUnits.length,
238
220
  unitDispatchCount: Object.fromEntries(this.unitDispatchCount),
239
221
  };
240
222
  }