gsd-pi 2.73.1 → 2.74.0-dev.6e23363

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 (471) hide show
  1. package/dist/cli-web-branch.d.ts +4 -3
  2. package/dist/cli-web-branch.js +10 -7
  3. package/dist/cli.js +184 -206
  4. package/dist/headless-query.js +4 -1
  5. package/dist/help-text.js +23 -0
  6. package/dist/logo.d.ts +1 -1
  7. package/dist/logo.js +1 -1
  8. package/dist/onboarding.js +59 -53
  9. package/dist/resource-loader.js +2 -2
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +68 -4
  11. package/dist/resources/extensions/gsd/activity-log.js +16 -0
  12. package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
  13. package/dist/resources/extensions/gsd/auto/loop.js +147 -10
  14. package/dist/resources/extensions/gsd/auto/phases.js +173 -13
  15. package/dist/resources/extensions/gsd/auto/session.js +10 -0
  16. package/dist/resources/extensions/gsd/auto-dispatch.js +22 -4
  17. package/dist/resources/extensions/gsd/auto-model-selection.js +105 -16
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +254 -15
  19. package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
  20. package/dist/resources/extensions/gsd/auto-start.js +23 -6
  21. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
  22. package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
  23. package/dist/resources/extensions/gsd/auto-verification.js +186 -3
  24. package/dist/resources/extensions/gsd/auto.js +65 -12
  25. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +21 -8
  26. package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
  27. package/dist/resources/extensions/gsd/commands/handlers/ops.js +20 -0
  28. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
  29. package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
  30. package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
  31. package/dist/resources/extensions/gsd/commands-do.js +79 -0
  32. package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
  33. package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
  34. package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  36. package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
  37. package/dist/resources/extensions/gsd/commands-ship.js +187 -0
  38. package/dist/resources/extensions/gsd/db-writer.js +3 -5
  39. package/dist/resources/extensions/gsd/docs/preferences-reference.md +15 -2
  40. package/dist/resources/extensions/gsd/git-service.js +49 -1
  41. package/dist/resources/extensions/gsd/graph-context.js +157 -0
  42. package/dist/resources/extensions/gsd/gsd-db.js +581 -2
  43. package/dist/resources/extensions/gsd/guided-flow.js +23 -0
  44. package/dist/resources/extensions/gsd/index.js +15 -2
  45. package/dist/resources/extensions/gsd/init-wizard.js +1 -0
  46. package/dist/resources/extensions/gsd/journal.js +27 -0
  47. package/dist/resources/extensions/gsd/md-importer.js +3 -4
  48. package/dist/resources/extensions/gsd/memory-store.js +19 -51
  49. package/dist/resources/extensions/gsd/metrics.js +19 -0
  50. package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
  52. package/dist/resources/extensions/gsd/notification-widget.js +2 -2
  53. package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
  54. package/dist/resources/extensions/gsd/preferences-models.js +63 -3
  55. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  56. package/dist/resources/extensions/gsd/preferences-validation.js +130 -2
  57. package/dist/resources/extensions/gsd/preferences.js +26 -0
  58. package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
  59. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
  60. package/dist/resources/extensions/gsd/state.js +66 -15
  61. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  62. package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -0
  63. package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
  64. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
  65. package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
  66. package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
  67. package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
  68. package/dist/resources/extensions/gsd/uok/audit.js +40 -0
  69. package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
  70. package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
  71. package/dist/resources/extensions/gsd/uok/flags.js +29 -0
  72. package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
  73. package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
  74. package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
  75. package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
  76. package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
  77. package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
  78. package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
  79. package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
  80. package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
  81. package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
  82. package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
  83. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  84. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  85. package/dist/update-check.d.ts +1 -0
  86. package/dist/update-check.js +13 -5
  87. package/dist/update-cmd.js +4 -3
  88. package/dist/web/standalone/.next/BUILD_ID +1 -1
  89. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  90. package/dist/web/standalone/.next/build-manifest.json +3 -3
  91. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  92. package/dist/web/standalone/.next/required-server-files.json +3 -3
  93. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  94. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  104. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  120. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  132. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  152. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  162. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  168. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  182. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  184. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  186. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  188. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/app/index.html +1 -1
  198. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  199. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  200. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  201. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  202. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  203. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  204. package/dist/web/standalone/.next/server/app/page.js +2 -2
  205. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  207. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  208. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  209. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  210. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  211. package/dist/web/standalone/.next/server/middleware.js +2 -2
  212. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  214. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  215. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  216. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  217. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  218. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  219. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
  220. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  221. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  222. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  223. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  224. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  225. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  226. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  227. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  228. package/dist/web/standalone/server.js +1 -1
  229. package/package.json +3 -3
  230. package/packages/daemon/package.json +2 -2
  231. package/packages/mcp-server/dist/index.d.ts +3 -0
  232. package/packages/mcp-server/dist/index.d.ts.map +1 -1
  233. package/packages/mcp-server/dist/index.js +3 -0
  234. package/packages/mcp-server/dist/index.js.map +1 -1
  235. package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
  236. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
  237. package/packages/mcp-server/dist/readers/graph.js +548 -0
  238. package/packages/mcp-server/dist/readers/graph.js.map +1 -0
  239. package/packages/mcp-server/dist/readers/index.d.ts +2 -0
  240. package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
  241. package/packages/mcp-server/dist/readers/index.js +1 -0
  242. package/packages/mcp-server/dist/readers/index.js.map +1 -1
  243. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  244. package/packages/mcp-server/dist/server.js +65 -0
  245. package/packages/mcp-server/dist/server.js.map +1 -1
  246. package/packages/mcp-server/package.json +2 -2
  247. package/packages/mcp-server/src/index.ts +15 -0
  248. package/packages/mcp-server/src/readers/graph.test.ts +426 -0
  249. package/packages/mcp-server/src/readers/graph.ts +708 -0
  250. package/packages/mcp-server/src/readers/index.ts +12 -0
  251. package/packages/mcp-server/src/server.ts +83 -0
  252. package/packages/mcp-server/tsconfig.json +1 -0
  253. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
  254. package/packages/native/package.json +2 -2
  255. package/packages/native/tsconfig.tsbuildinfo +1 -0
  256. package/packages/pi-agent-core/package.json +1 -1
  257. package/packages/pi-agent-core/tsconfig.json +1 -0
  258. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
  259. package/packages/pi-ai/dist/index.d.ts +1 -0
  260. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  261. package/packages/pi-ai/dist/index.js +1 -0
  262. package/packages/pi-ai/dist/index.js.map +1 -1
  263. package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  264. package/packages/pi-ai/dist/utils/overflow.js +12 -0
  265. package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
  266. package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
  267. package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
  268. package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
  269. package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
  270. package/packages/pi-ai/package.json +1 -1
  271. package/packages/pi-ai/src/index.ts +4 -0
  272. package/packages/pi-ai/src/utils/overflow.ts +14 -1
  273. package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
  274. package/packages/pi-ai/tsconfig.json +1 -0
  275. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
  276. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +433 -8
  277. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  278. package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
  279. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  280. package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
  281. package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
  282. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
  283. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
  284. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
  285. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
  286. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
  287. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
  288. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  290. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  291. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
  292. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  293. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +61 -28
  294. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  295. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +9 -3
  298. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
  300. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
  301. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
  302. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
  303. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  304. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +142 -20
  305. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  306. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  307. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +11 -3
  308. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  309. package/packages/pi-coding-agent/package.json +1 -1
  310. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +521 -8
  311. package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
  312. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
  313. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  314. package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
  315. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +74 -32
  316. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
  317. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
  318. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +166 -25
  319. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +11 -3
  320. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  321. package/packages/pi-coding-agent/tsconfig.json +3 -2
  322. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
  323. package/packages/pi-tui/dist/__tests__/tui.test.js +60 -1
  324. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  325. package/packages/pi-tui/dist/tui.d.ts +8 -0
  326. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  327. package/packages/pi-tui/dist/tui.js +32 -3
  328. package/packages/pi-tui/dist/tui.js.map +1 -1
  329. package/packages/pi-tui/package.json +1 -1
  330. package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
  331. package/packages/pi-tui/src/tui.ts +31 -3
  332. package/packages/pi-tui/tsconfig.json +1 -0
  333. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
  334. package/packages/rpc-client/package.json +1 -1
  335. package/packages/rpc-client/tsconfig.json +1 -0
  336. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
  337. package/pkg/package.json +1 -1
  338. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +107 -5
  339. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +111 -2
  340. package/src/resources/extensions/gsd/activity-log.ts +21 -0
  341. package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
  342. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -0
  343. package/src/resources/extensions/gsd/auto/loop.ts +159 -10
  344. package/src/resources/extensions/gsd/auto/phases.ts +213 -13
  345. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  346. package/src/resources/extensions/gsd/auto-dispatch.ts +26 -10
  347. package/src/resources/extensions/gsd/auto-model-selection.ts +151 -16
  348. package/src/resources/extensions/gsd/auto-post-unit.ts +278 -16
  349. package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
  350. package/src/resources/extensions/gsd/auto-start.ts +30 -6
  351. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
  352. package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
  353. package/src/resources/extensions/gsd/auto-verification.ts +225 -3
  354. package/src/resources/extensions/gsd/auto.ts +72 -16
  355. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -8
  356. package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
  357. package/src/resources/extensions/gsd/commands/handlers/ops.ts +20 -0
  358. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
  359. package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
  360. package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
  361. package/src/resources/extensions/gsd/commands-do.ts +109 -0
  362. package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
  363. package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
  364. package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
  365. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  366. package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
  367. package/src/resources/extensions/gsd/commands-ship.ts +219 -0
  368. package/src/resources/extensions/gsd/db-writer.ts +3 -5
  369. package/src/resources/extensions/gsd/docs/preferences-reference.md +15 -2
  370. package/src/resources/extensions/gsd/git-service.ts +68 -0
  371. package/src/resources/extensions/gsd/graph-context.ts +212 -0
  372. package/src/resources/extensions/gsd/gsd-db.ts +788 -3
  373. package/src/resources/extensions/gsd/guided-flow.ts +32 -0
  374. package/src/resources/extensions/gsd/index.ts +18 -2
  375. package/src/resources/extensions/gsd/init-wizard.ts +3 -2
  376. package/src/resources/extensions/gsd/journal.ts +30 -0
  377. package/src/resources/extensions/gsd/md-importer.ts +3 -5
  378. package/src/resources/extensions/gsd/memory-store.ts +31 -62
  379. package/src/resources/extensions/gsd/metrics.ts +26 -0
  380. package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
  381. package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
  382. package/src/resources/extensions/gsd/notification-widget.ts +2 -2
  383. package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
  384. package/src/resources/extensions/gsd/preferences-models.ts +61 -3
  385. package/src/resources/extensions/gsd/preferences-types.ts +44 -0
  386. package/src/resources/extensions/gsd/preferences-validation.ts +130 -2
  387. package/src/resources/extensions/gsd/preferences.ts +28 -0
  388. package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
  389. package/src/resources/extensions/gsd/session-lock.ts +14 -2
  390. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
  391. package/src/resources/extensions/gsd/state.ts +80 -17
  392. package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  393. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +9 -5
  394. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
  395. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
  396. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
  397. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
  398. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
  399. package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
  400. package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
  401. package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
  402. package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
  403. package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
  404. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
  405. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
  406. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  407. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  408. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
  409. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
  410. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
  411. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
  412. package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
  413. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
  414. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
  415. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
  416. package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
  417. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  418. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  419. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
  420. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
  421. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
  422. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
  423. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
  424. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  425. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
  426. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
  427. package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
  428. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
  429. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
  430. package/src/resources/extensions/gsd/tests/token-profile.test.ts +9 -6
  431. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  432. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
  433. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
  434. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
  435. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
  436. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
  437. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
  438. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  439. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
  440. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  441. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
  442. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
  443. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
  444. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -0
  445. package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
  446. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
  447. package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
  448. package/src/resources/extensions/gsd/types.ts +1 -1
  449. package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
  450. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  451. package/src/resources/extensions/gsd/uok/audit.ts +51 -0
  452. package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
  453. package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
  454. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  455. package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
  456. package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
  457. package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
  458. package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
  459. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  460. package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
  461. package/src/resources/extensions/gsd/workflow-logger.ts +25 -0
  462. package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
  463. package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
  464. package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
  465. package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
  466. package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
  467. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
  468. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  469. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  470. /package/dist/web/standalone/.next/static/{Qr27MOHx0lxRGnJvlhxxu → bc2gRVFTgD7j--BsJE7vP}/_buildManifest.js +0 -0
  471. /package/dist/web/standalone/.next/static/{Qr27MOHx0lxRGnJvlhxxu → bc2gRVFTgD7j--BsJE7vP}/_ssgManifest.js +0 -0
@@ -0,0 +1,82 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+
4
+ // Test the formatting logic used by session-report.
5
+ // The actual handler requires runtime context (metrics module), so we
6
+ // test the core formatting and aggregation patterns.
7
+
8
+ test("session-report: format cost correctly", () => {
9
+ // Simple cost formatting test
10
+ const formatCost = (cost: number): string => {
11
+ if (cost < 0.01) return "<$0.01";
12
+ return `$${cost.toFixed(2)}`;
13
+ };
14
+
15
+ assert.equal(formatCost(0), "<$0.01");
16
+ assert.equal(formatCost(0.005), "<$0.01");
17
+ assert.equal(formatCost(1.5), "$1.50");
18
+ assert.equal(formatCost(10.999), "$11.00");
19
+ });
20
+
21
+ test("session-report: format token count", () => {
22
+ const formatTokenCount = (count: number): string => {
23
+ if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1)}M`;
24
+ if (count >= 1_000) return `${(count / 1_000).toFixed(1)}K`;
25
+ return String(count);
26
+ };
27
+
28
+ assert.equal(formatTokenCount(500), "500");
29
+ assert.equal(formatTokenCount(1500), "1.5K");
30
+ assert.equal(formatTokenCount(1_200_000), "1.2M");
31
+ });
32
+
33
+ test("session-report: aggregate by model", () => {
34
+ interface UnitMetric {
35
+ model: string;
36
+ cost: number;
37
+ }
38
+
39
+ const units: UnitMetric[] = [
40
+ { model: "opus", cost: 1.0 },
41
+ { model: "opus", cost: 0.8 },
42
+ { model: "sonnet", cost: 0.3 },
43
+ { model: "sonnet", cost: 0.5 },
44
+ { model: "sonnet", cost: 0.2 },
45
+ ];
46
+
47
+ const byModel = new Map<string, { count: number; cost: number }>();
48
+ for (const u of units) {
49
+ const existing = byModel.get(u.model) ?? { count: 0, cost: 0 };
50
+ existing.count++;
51
+ existing.cost += u.cost;
52
+ byModel.set(u.model, existing);
53
+ }
54
+
55
+ const opus = byModel.get("opus")!;
56
+ assert.equal(opus.count, 2);
57
+ assert.ok(Math.abs(opus.cost - 1.8) < 0.01);
58
+
59
+ const sonnet = byModel.get("sonnet")!;
60
+ assert.equal(sonnet.count, 3);
61
+ assert.ok(Math.abs(sonnet.cost - 1.0) < 0.01);
62
+ });
63
+
64
+ test("session-report: --json flag detection", () => {
65
+ const args1 = "--json";
66
+ const args2 = "--save --json";
67
+ const args3 = "something else";
68
+
69
+ assert.ok(args1.includes("--json"));
70
+ assert.ok(args2.includes("--json"));
71
+ assert.ok(!args3.includes("--json"));
72
+ });
73
+
74
+ test("session-report: --save flag detection", () => {
75
+ const args1 = "--save";
76
+ const args2 = "--save --json";
77
+ const args3 = "";
78
+
79
+ assert.ok(args1.includes("--save"));
80
+ assert.ok(args2.includes("--save"));
81
+ assert.ok(!args3.includes("--save"));
82
+ });
@@ -0,0 +1,71 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+
4
+ // Test the PR content generation logic used by /gsd ship.
5
+ // Full integration requires gh CLI + git, so we test the text generation.
6
+
7
+ test("ship: generates TL;DR format", () => {
8
+ // Simulate generatePRContent output structure
9
+ const milestoneId = "M001";
10
+ const milestoneTitle = "User authentication system";
11
+
12
+ const title = `feat: ${milestoneTitle}`;
13
+ assert.equal(title, "feat: User authentication system");
14
+ assert.ok(title.length < 80); // PR title should be short
15
+ });
16
+
17
+ test("ship: --dry-run flag detection", () => {
18
+ const args1 = "--dry-run";
19
+ const args2 = "--draft --dry-run";
20
+ const args3 = "--draft";
21
+
22
+ assert.ok(args1.includes("--dry-run"));
23
+ assert.ok(args2.includes("--dry-run"));
24
+ assert.ok(!args3.includes("--dry-run"));
25
+ });
26
+
27
+ test("ship: --base flag parsing", () => {
28
+ const args = "--base develop --draft";
29
+ const baseMatch = args.match(/--base\s+(\S+)/);
30
+ assert.ok(baseMatch);
31
+ assert.equal(baseMatch[1], "develop");
32
+ });
33
+
34
+ test("ship: --base flag absent defaults", () => {
35
+ const args = "--draft";
36
+ const baseMatch = args.match(/--base\s+(\S+)/);
37
+ assert.equal(baseMatch, null);
38
+ });
39
+
40
+ test("ship: --force flag detection", () => {
41
+ const args1 = "--force";
42
+ const args2 = "";
43
+
44
+ assert.ok(args1.includes("--force"));
45
+ assert.ok(!args2.includes("--force"));
46
+ });
47
+
48
+ test("ship: change type checklist format", () => {
49
+ const checklist = [
50
+ "- [x] `feat` — New feature or capability",
51
+ "- [ ] `fix` — Bug fix",
52
+ "- [ ] `refactor` — Code restructuring",
53
+ "- [ ] `test` — Adding or updating tests",
54
+ "- [ ] `docs` — Documentation only",
55
+ "- [ ] `chore` — Build, CI, or tooling changes",
56
+ ];
57
+
58
+ // Verify format matches CONTRIBUTING.md expectations
59
+ for (const line of checklist) {
60
+ assert.match(line, /^- \[[ x]\] `\w+` — .+$/);
61
+ }
62
+ });
63
+
64
+ test("ship: PR body contains required sections", () => {
65
+ const requiredSections = ["## TL;DR", "## Change type"];
66
+ const body = "## TL;DR\n\n**What:** Ship M001\n\n## Change type\n\n- [x] `feat`";
67
+
68
+ for (const section of requiredSections) {
69
+ assert.ok(body.includes(section), `Missing section: ${section}`);
70
+ }
71
+ });
@@ -217,6 +217,20 @@ describe("workflow command handler", () => {
217
217
  );
218
218
  });
219
219
 
220
+ it("preserves quoted workflow run overrides (#4130)", async () => {
221
+ const { parseWorkflowRunArgs } = await import("../commands/handlers/workflow.ts");
222
+ assert.deepStrictEqual(
223
+ parseWorkflowRunArgs('demo-workflow target="multi word target" region=\'us east\''),
224
+ {
225
+ defName: "demo-workflow",
226
+ overrides: {
227
+ target: "multi word target",
228
+ region: "us east",
229
+ },
230
+ },
231
+ );
232
+ });
233
+
220
234
  it("'/gsd workflow run nonexistent' shows error for missing definition", async () => {
221
235
  const { handled, notifications } = await callHandler("workflow run nonexistent-def-12345");
222
236
  assert.ok(handled, "should be handled");
@@ -0,0 +1,142 @@
1
+ /**
2
+ * complete-milestone-false-merge.test.ts — Regression test for #4175.
3
+ *
4
+ * Before the fix, a failed complete-milestone unit could leave a stub
5
+ * SUMMARY blocker placeholder on disk. stopAuto's SUMMARY-presence check
6
+ * then treated the milestone as complete and merged the worktree branch
7
+ * into main — emitting a misleading metadata-only merge warning for a
8
+ * milestone that was never legitimately finished.
9
+ *
10
+ * The fix has three cooperating parts:
11
+ * 1. stopAuto uses DB status (authoritative) instead of SUMMARY presence
12
+ * when the project DB is available.
13
+ * 2. postUnitPreVerification pauses auto-mode for complete-milestone
14
+ * after retries are exhausted instead of writing a blocker placeholder.
15
+ * 3. recoverTimedOutUnit pauses for complete-milestone instead of
16
+ * writing a blocker placeholder.
17
+ *
18
+ * This test guards all three via source inspection so a future refactor
19
+ * cannot silently reintroduce the false-merge path.
20
+ */
21
+
22
+ import test from "node:test";
23
+ import assert from "node:assert/strict";
24
+ import { readFileSync } from "node:fs";
25
+ import { join } from "node:path";
26
+
27
+ const gsdDir = join(import.meta.dirname, "..");
28
+ const autoSrc = readFileSync(join(gsdDir, "auto.ts"), "utf-8");
29
+ const postUnitSrc = readFileSync(join(gsdDir, "auto-post-unit.ts"), "utf-8");
30
+ const timeoutSrc = readFileSync(join(gsdDir, "auto-timeout-recovery.ts"), "utf-8");
31
+
32
+ test("#4175: stopAuto uses DB status as the authoritative milestone-complete signal", () => {
33
+ const step4Idx = autoSrc.indexOf("Step 4: Auto-worktree exit");
34
+ assert.ok(step4Idx !== -1, "Step 4 comment exists in stopAuto");
35
+ const step5Idx = autoSrc.indexOf("Step 5:", step4Idx);
36
+ const step4Block = autoSrc.slice(step4Idx, step5Idx);
37
+
38
+ assert.ok(
39
+ step4Block.includes("isDbAvailable()"),
40
+ "Step 4 should branch on isDbAvailable() so DB is consulted when present",
41
+ );
42
+ assert.ok(
43
+ step4Block.includes("getMilestone(s.currentMilestoneId)"),
44
+ "Step 4 should read authoritative milestone status via getMilestone()",
45
+ );
46
+ assert.ok(
47
+ /status\s*===\s*"complete"/.test(step4Block),
48
+ 'Step 4 should compare the DB row status to "complete"',
49
+ );
50
+ });
51
+
52
+ test("#4175: stopAuto imports getMilestone from gsd-db", () => {
53
+ assert.ok(
54
+ /import\s*\{[^}]*\bgetMilestone\b[^}]*\}\s*from\s*"\.\/gsd-db\.js"/.test(autoSrc),
55
+ "auto.ts should import getMilestone from ./gsd-db.js",
56
+ );
57
+ });
58
+
59
+ test("#4175: stopAuto still falls back to SUMMARY presence when DB is unavailable", () => {
60
+ const step4Idx = autoSrc.indexOf("Step 4: Auto-worktree exit");
61
+ const step5Idx = autoSrc.indexOf("Step 5:", step4Idx);
62
+ const step4Block = autoSrc.slice(step4Idx, step5Idx);
63
+
64
+ assert.ok(
65
+ step4Block.includes("resolveMilestoneFile"),
66
+ "Step 4 should keep SUMMARY-file resolution for DB-unavailable projects",
67
+ );
68
+ assert.ok(
69
+ step4Block.includes("preserveBranch"),
70
+ "Step 4 should still preserve branch for incomplete milestones (fallback path)",
71
+ );
72
+ });
73
+
74
+ test("#4175: postUnitPreVerification pauses complete-milestone after retries exhausted", () => {
75
+ // The pause branch must live inside the retries-exhausted block, above the
76
+ // writeBlockerPlaceholder call — otherwise the stub SUMMARY is still written.
77
+ const retriesExhaustedIdx = postUnitSrc.indexOf(
78
+ "if (attempt > MAX_VERIFICATION_RETRIES)",
79
+ );
80
+ assert.ok(
81
+ retriesExhaustedIdx !== -1,
82
+ "retries-exhausted guard exists in postUnitPreVerification",
83
+ );
84
+
85
+ const blockerCallIdx = postUnitSrc.indexOf("writeBlockerPlaceholder", retriesExhaustedIdx);
86
+ assert.ok(
87
+ blockerCallIdx !== -1,
88
+ "blocker placeholder call still exists for non-milestone units",
89
+ );
90
+
91
+ const exhaustedBlock = postUnitSrc.slice(retriesExhaustedIdx, blockerCallIdx);
92
+
93
+ assert.ok(
94
+ /s\.currentUnit\.type\s*===\s*"complete-milestone"/.test(exhaustedBlock),
95
+ "retries-exhausted block should specifically handle complete-milestone",
96
+ );
97
+ assert.ok(
98
+ /pauseAuto\s*\(\s*ctx\s*,\s*pi\s*\)/.test(exhaustedBlock),
99
+ "complete-milestone path should call pauseAuto instead of falling through",
100
+ );
101
+ // The pause branch must return so execution never reaches writeBlockerPlaceholder.
102
+ assert.ok(
103
+ /return\s+"dispatched"\s*;/.test(exhaustedBlock),
104
+ "complete-milestone pause branch should return before the placeholder call",
105
+ );
106
+ });
107
+
108
+ test("#4175: recoverTimedOutUnit pauses complete-milestone instead of writing a blocker placeholder", () => {
109
+ // The complete-milestone pause branch must sit immediately above the
110
+ // "retries exhausted" writeBlockerPlaceholder call so a failed
111
+ // complete-milestone never produces a stub SUMMARY. Anchor on the
112
+ // comment that precedes that specific placeholder call rather than the
113
+ // function's earlier writeBlockerPlaceholder use sites or its import.
114
+ // Use lastIndexOf so we find the final retries-exhausted block in
115
+ // recoverTimedOutUnit, not an earlier helper with the same comment.
116
+ const exhaustedAnchor = "Retries exhausted — write a blocker placeholder";
117
+ const exhaustedIdx = timeoutSrc.lastIndexOf(exhaustedAnchor);
118
+ assert.ok(
119
+ exhaustedIdx !== -1,
120
+ "retries-exhausted blocker-placeholder path still exists for non-milestone units",
121
+ );
122
+
123
+ const guardIdx = timeoutSrc.lastIndexOf(
124
+ 'unitType === "complete-milestone"',
125
+ exhaustedIdx,
126
+ );
127
+ assert.ok(
128
+ guardIdx !== -1,
129
+ "complete-milestone guard should appear above the retries-exhausted placeholder call",
130
+ );
131
+
132
+ const guardBlock = timeoutSrc.slice(guardIdx, exhaustedIdx);
133
+ assert.ok(
134
+ /return\s+"paused"\s*;/.test(guardBlock),
135
+ "complete-milestone guard should return 'paused' before the placeholder call",
136
+ );
137
+ // The guard itself must not call writeBlockerPlaceholder.
138
+ assert.ok(
139
+ !guardBlock.includes("writeBlockerPlaceholder"),
140
+ "complete-milestone guard must not write a blocker placeholder",
141
+ );
142
+ });
@@ -125,9 +125,9 @@ console.log('\n=== complete-slice: schema v6 migration ===');
125
125
 
126
126
  const adapter = _getAdapter()!;
127
127
 
128
- // Verify schema version is current (v14 after indexes + slice_dependencies)
128
+ // Verify schema version is current (v15 with UOK projection tables)
129
129
  const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
130
- assertEq(versionRow?.['v'], 14, 'schema version should be 14');
130
+ assertEq(versionRow?.['v'], 15, 'schema version should be 15');
131
131
 
132
132
  // Verify slices table has full_summary_md and full_uat_md columns
133
133
  const cols = adapter.prepare("PRAGMA table_info(slices)").all();
@@ -109,9 +109,9 @@ console.log('\n=== complete-task: schema v5 migration ===');
109
109
 
110
110
  const adapter = _getAdapter()!;
111
111
 
112
- // Verify schema version is current (v14 after indexes + slice_dependencies)
112
+ // Verify schema version is current (v15 with UOK projection tables)
113
113
  const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
114
- assertEq(versionRow?.['v'], 14, 'schema version should be 14');
114
+ assertEq(versionRow?.['v'], 15, 'schema version should be 15');
115
115
 
116
116
  // Verify all 4 new tables exist
117
117
  const tables = adapter.prepare(
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Regression test for #4129: tasks.completed_at stays NULL when status is
3
+ * reconciled to 'complete' via the file-existence path in state.ts.
4
+ *
5
+ * Root cause: reconcileSliceTasks called
6
+ * updateTaskStatus(milestoneId, sliceId, t.id, "complete")
7
+ * without a completedAt timestamp, so the column stays NULL.
8
+ *
9
+ * Fix: pass new Date().toISOString() as the 5th argument.
10
+ */
11
+
12
+ import { describe, test } from "node:test";
13
+ import assert from "node:assert/strict";
14
+ import { readFileSync } from "node:fs";
15
+ import { join, dirname } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+
18
+ const __dirname = dirname(fileURLToPath(import.meta.url));
19
+ const stateSource = readFileSync(join(__dirname, "..", "state.ts"), "utf-8");
20
+
21
+ describe("completed-at reconcile (#4129)", () => {
22
+ test("reconcileSliceTasks passes a completedAt timestamp when setting status to complete", () => {
23
+ // Before the fix, state.ts had:
24
+ // updateTaskStatus(milestoneId, sliceId, t.id, "complete")
25
+ // which leaves completed_at NULL in the DB.
26
+ // After the fix, a timestamp must be passed as the 5th argument.
27
+ assert.doesNotMatch(
28
+ stateSource,
29
+ /updateTaskStatus\(\s*milestoneId\s*,\s*sliceId\s*,\s*t\.id\s*,\s*["']complete["']\s*\)/,
30
+ "updateTaskStatus must not be called without a completedAt timestamp when reconciling tasks to 'complete' (#4129)",
31
+ );
32
+ });
33
+
34
+ test("reconcileSliceTasks passes new Date().toISOString() as the completedAt argument", () => {
35
+ // Positive assertion: the fixed call must include a timestamp.
36
+ assert.match(
37
+ stateSource,
38
+ /updateTaskStatus\(\s*milestoneId\s*,\s*sliceId\s*,\s*t\.id\s*,\s*["']complete["']\s*,\s*new Date\(\)\.toISOString\(\)\s*\)/,
39
+ "reconcileSliceTasks must pass new Date().toISOString() as completedAt when setting task status to 'complete' (#4129)",
40
+ );
41
+ });
42
+ });
@@ -351,8 +351,9 @@ skills_used: []
351
351
  const dbState = await deriveStateFromDb(base);
352
352
 
353
353
  assertStatesEqual(dbState, fileState, 'E-blocked');
354
- assert.deepStrictEqual(dbState.phase, 'blocked', 'E-blocked: phase is blocked');
355
- assert.ok(dbState.blockers.length > 0, 'E-blocked: has blockers');
354
+ // With partial-dep fallback, circular deps no longer block — fallback picks first eligible slice
355
+ assert.deepStrictEqual(dbState.phase, 'planning', 'E-blocked: phase is planning (fallback picks a slice)');
356
+ assert.ok(dbState.activeSlice !== null, 'E-blocked: activeSlice is set via fallback');
356
357
 
357
358
  closeDatabase();
358
359
  } finally {
@@ -616,9 +616,10 @@ describe('derive-state-db', async () => {
616
616
  invalidateStateCache();
617
617
  const dbState = await deriveStateFromDb(base);
618
618
 
619
- assert.deepStrictEqual(dbState.phase, 'blocked', 'blocked-db: phase is blocked');
619
+ // With partial-dep fallback, circular deps no longer block — fallback picks first eligible slice
620
+ assert.deepStrictEqual(dbState.phase, 'planning', 'blocked-db: phase is planning (fallback picks a slice)');
620
621
  assert.deepStrictEqual(dbState.phase, fileState.phase, 'blocked-db: phase matches filesystem');
621
- assert.ok(dbState.blockers.length > 0, 'blocked-db: has blockers');
622
+ assert.ok(dbState.activeSlice !== null, 'blocked-db: activeSlice is set via fallback');
622
623
 
623
624
  closeDatabase();
624
625
  } finally {
@@ -307,27 +307,87 @@ describe('derive-state-helpers', () => {
307
307
  }
308
308
  });
309
309
 
310
- // ─── buildCompletenessSet: SUMMARY-on-disk marks complete ───────────
311
- test('buildCompletenessSet: milestone with SUMMARY on disk treated as complete', async () => {
310
+ // ─── buildCompletenessSet: DB status is authoritative ──────────────
311
+ test('buildCompletenessSet: DB status=complete marks milestone complete', async () => {
312
312
  const base = createFixtureBase();
313
313
  try {
314
- // M001 has summary on disk but DB status is still 'active'
315
314
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
316
315
  writeFile(base, 'milestones/M001/M001-SUMMARY.md', '# M001 Summary\n\nDone.');
317
- // M002 is the real active milestone
318
316
  writeFile(base, 'milestones/M002/M002-CONTEXT.md', '# M002\n\nActive.');
319
317
 
320
318
  openDatabase(':memory:');
321
- insertMilestone({ id: 'M001', title: 'First', status: 'active' });
319
+ insertMilestone({ id: 'M001', title: 'First', status: 'complete' });
322
320
  insertMilestone({ id: 'M002', title: 'Second', status: 'active' });
323
321
 
324
322
  invalidateStateCache();
325
323
  const state = await deriveStateFromDb(base);
326
324
 
327
- // M001 should be complete (summary on disk), M002 should be active
328
325
  const m1 = state.registry.find(e => e.id === 'M001');
329
- assert.equal(m1?.status, 'complete', 'summary-disk: M001 marked complete via disk SUMMARY');
330
- assert.equal(state.activeMilestone?.id, 'M002', 'summary-disk: M002 is active');
326
+ assert.equal(m1?.status, 'complete', 'DB status=complete → registry entry complete');
327
+ assert.equal(state.activeMilestone?.id, 'M002', 'M002 is the active milestone');
328
+ } finally {
329
+ closeDatabase();
330
+ cleanup(base);
331
+ }
332
+ });
333
+
334
+ // ─── Regression #4179: orphan SUMMARY must NOT flip DB-active milestone ───
335
+ // A crashed complete-milestone turn (or stale/manual SUMMARY.md) can leave
336
+ // a milestone SUMMARY on disk while the DB row still reads 'active'. The
337
+ // read-side of state derivation must NOT treat the orphan SUMMARY as a
338
+ // completion signal, or the auto-loop advances and merges work that was
339
+ // never actually finished (same failure class as #4175, read-side twin).
340
+ test('buildCompletenessSet (#4179): orphan SUMMARY on disk does not mark DB-active milestone complete', async () => {
341
+ const base = createFixtureBase();
342
+ try {
343
+ writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
344
+ writeFile(base, 'milestones/M001/M001-SUMMARY.md', '# M001 Orphan Summary\n\nLeft over from crashed turn.');
345
+
346
+ openDatabase(':memory:');
347
+ insertMilestone({ id: 'M001', title: 'First', status: 'active' });
348
+ // Slice still in-flight — auto should resume, not merge.
349
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'First', status: 'active', risk: 'low', depends: [] });
350
+ insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Second', status: 'pending', risk: 'low', depends: ['S01'] });
351
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'In-flight', status: 'pending' });
352
+
353
+ invalidateStateCache();
354
+ const state = await deriveStateFromDb(base);
355
+
356
+ const m1 = state.registry.find(e => e.id === 'M001');
357
+ assert.notEqual(m1?.status, 'complete', 'orphan SUMMARY must not mark milestone complete');
358
+ assert.equal(m1?.status, 'active', 'M001 remains active — DB is authoritative');
359
+ assert.equal(state.activeMilestone?.id, 'M001', 'M001 is still the active milestone');
360
+ assert.notEqual(state.phase, 'completing-milestone', 'must not short-circuit into completion');
361
+ } finally {
362
+ closeDatabase();
363
+ cleanup(base);
364
+ }
365
+ });
366
+
367
+ // Regression #4179 (companion): DB-active milestone with all slices done +
368
+ // validation terminal + orphan SUMMARY must still flow through completing-milestone
369
+ // (re-runs complete-milestone), not be reported as already-complete.
370
+ test('buildRegistryAndFindActive (#4179): orphan SUMMARY with validation-terminal falls through to completing-milestone', async () => {
371
+ const base = createFixtureBase();
372
+ try {
373
+ writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
374
+ writeFile(base, 'milestones/M001/slices/S01/S01-PLAN.md', PLAN_CONTENT);
375
+ writeFile(base, 'milestones/M001/slices/S02/S02-PLAN.md', PLAN_CONTENT);
376
+ writeFile(base, 'milestones/M001/M001-VALIDATION.md', '---\nverdict: passed\n---\n# Validation\nAll good.');
377
+ writeFile(base, 'milestones/M001/M001-SUMMARY.md', '# M001 Orphan Summary\n\nLeft over.');
378
+
379
+ openDatabase(':memory:');
380
+ insertMilestone({ id: 'M001', title: 'First', status: 'active' });
381
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'First', status: 'complete', risk: 'low', depends: [] });
382
+ insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Second', status: 'complete', risk: 'low', depends: ['S01'] });
383
+
384
+ invalidateStateCache();
385
+ const state = await deriveStateFromDb(base);
386
+
387
+ const m1 = state.registry.find(e => e.id === 'M001');
388
+ assert.equal(m1?.status, 'active', 'M001 stays active despite orphan SUMMARY + validation-terminal');
389
+ assert.equal(state.activeMilestone?.id, 'M001', 'M001 is still the active milestone');
390
+ assert.equal(state.phase, 'completing-milestone', 'phase flows through completing-milestone (re-run)');
331
391
  } finally {
332
392
  closeDatabase();
333
393
  cleanup(base);
@@ -446,9 +446,9 @@ Continue from step 2.
446
446
 
447
447
  const state2 = await deriveState(base2);
448
448
 
449
- assert.deepStrictEqual(state2.phase, 'blocked', 'blocked-B: phase is blocked');
450
- assert.deepStrictEqual(state2.activeSlice, null, 'blocked-B: activeSlice is null');
451
- assert.ok(state2.blockers.length > 0, 'blocked-B: blockers array is non-empty');
449
+ // With partial-dep fallback, S01 is picked despite unmet dep on S99
450
+ assert.deepStrictEqual(state2.phase, 'planning', 'blocked-B: phase is planning (fallback picks S01)');
451
+ assert.deepStrictEqual(state2.activeSlice?.id, 'S01', 'blocked-B: activeSlice is S01 via fallback');
452
452
  } finally {
453
453
  cleanup(base2);
454
454
  }