gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.f2447468f

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 (335) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/GSD-WORKFLOW.md +2 -2
  3. package/dist/resources/extensions/github-sync/templates.js +39 -8
  4. package/dist/resources/extensions/gsd/auto/loop.js +16 -9
  5. package/dist/resources/extensions/gsd/auto/phases.js +37 -30
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +19 -15
  7. package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
  8. package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
  9. package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
  10. package/dist/resources/extensions/gsd/auto-prompts.js +111 -1
  11. package/dist/resources/extensions/gsd/auto-recovery.js +154 -8
  12. package/dist/resources/extensions/gsd/auto-start.js +2 -3
  13. package/dist/resources/extensions/gsd/auto.js +9 -1
  14. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +15 -1
  15. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -1
  16. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
  17. package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
  18. package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
  19. package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
  20. package/dist/resources/extensions/gsd/custom-workflow-engine.js +22 -2
  21. package/dist/resources/extensions/gsd/db-base-schema.js +14 -0
  22. package/dist/resources/extensions/gsd/db-migration-steps.js +16 -0
  23. package/dist/resources/extensions/gsd/detection.js +106 -0
  24. package/dist/resources/extensions/gsd/graph.js +9 -3
  25. package/dist/resources/extensions/gsd/gsd-db.js +102 -2
  26. package/dist/resources/extensions/gsd/guided-flow.js +46 -9
  27. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  28. package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
  29. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  30. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  31. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  32. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  33. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  34. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  35. package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
  36. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  37. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  38. package/dist/web/standalone/.next/BUILD_ID +1 -1
  39. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  40. package/dist/web/standalone/.next/build-manifest.json +3 -3
  41. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  42. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  44. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/index.html +1 -1
  61. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  68. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  69. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  72. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  73. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  74. package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
  75. package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
  76. package/package.json +10 -6
  77. package/packages/contracts/package.json +1 -1
  78. package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
  79. package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
  80. package/packages/pi-ai/dist/models/fake-model.js +27 -0
  81. package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
  82. package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
  83. package/packages/pi-ai/dist/models/index.js +8 -0
  84. package/packages/pi-ai/dist/models/index.js.map +1 -1
  85. package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
  86. package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
  87. package/packages/pi-ai/dist/providers/fake.js +319 -0
  88. package/packages/pi-ai/dist/providers/fake.js.map +1 -0
  89. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  90. package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
  91. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  92. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  93. package/packages/pi-ai/src/models/index.ts +9 -0
  94. package/packages/pi-ai/src/providers/fake.ts +376 -0
  95. package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
  96. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  97. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +74 -0
  98. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  100. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  101. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  102. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  103. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  104. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  105. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  106. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  107. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  108. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  109. package/packages/pi-coding-agent/dist/core/extensions/runner.js +14 -1
  110. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  111. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +97 -0
  112. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  113. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  114. package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
  115. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  116. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +4 -0
  117. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  118. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  119. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  120. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  122. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
  132. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
  133. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
  134. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
  135. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  138. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
  139. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
  141. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
  143. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
  145. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +16 -0
  147. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -17
  149. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  151. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +60 -1
  152. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  153. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +40 -1
  154. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
  156. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  158. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  159. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  161. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +23 -0
  163. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  164. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
  166. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  167. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
  168. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
  169. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
  170. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
  171. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  172. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  173. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
  174. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  176. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  181. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
  183. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
  184. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
  185. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
  186. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
  187. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
  188. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
  189. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
  190. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  191. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  192. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  193. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  194. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  195. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  196. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  197. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +87 -0
  198. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  199. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  200. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +108 -0
  201. package/packages/pi-coding-agent/src/core/extensions/runner.ts +16 -1
  202. package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
  203. package/packages/pi-coding-agent/src/core/settings-manager.ts +12 -0
  204. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  205. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  206. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
  207. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
  208. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
  209. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  210. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
  211. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  212. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
  213. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +118 -17
  214. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +43 -1
  215. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -1
  216. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
  217. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
  218. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +25 -0
  219. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  220. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
  221. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
  222. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
  223. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  224. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
  225. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  226. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  227. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  228. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  229. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  230. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  231. package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
  232. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  233. package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
  234. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  235. package/packages/pi-tui/dist/index.d.ts +1 -0
  236. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  237. package/packages/pi-tui/dist/index.js +2 -0
  238. package/packages/pi-tui/dist/index.js.map +1 -1
  239. package/packages/pi-tui/dist/style.d.ts +41 -0
  240. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  241. package/packages/pi-tui/dist/style.js +158 -0
  242. package/packages/pi-tui/dist/style.js.map +1 -0
  243. package/packages/pi-tui/dist/tui.d.ts +0 -1
  244. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  245. package/packages/pi-tui/dist/tui.js +3 -8
  246. package/packages/pi-tui/dist/tui.js.map +1 -1
  247. package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
  248. package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
  249. package/packages/pi-tui/src/index.ts +9 -0
  250. package/packages/pi-tui/src/style.ts +225 -0
  251. package/packages/pi-tui/src/tui.ts +3 -8
  252. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  253. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  254. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  255. package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
  256. package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  257. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  258. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  259. package/pkg/dist/modes/interactive/theme/theme.js +18 -1
  260. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  261. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  262. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  263. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  264. package/src/resources/GSD-WORKFLOW.md +2 -2
  265. package/src/resources/extensions/github-sync/templates.ts +38 -8
  266. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  267. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  268. package/src/resources/extensions/gsd/auto/loop.ts +17 -10
  269. package/src/resources/extensions/gsd/auto/phases.ts +42 -28
  270. package/src/resources/extensions/gsd/auto/run-unit.ts +24 -14
  271. package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
  272. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
  273. package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
  274. package/src/resources/extensions/gsd/auto-prompts.ts +116 -1
  275. package/src/resources/extensions/gsd/auto-recovery.ts +153 -7
  276. package/src/resources/extensions/gsd/auto-start.ts +7 -6
  277. package/src/resources/extensions/gsd/auto.ts +12 -1
  278. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -1
  279. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -1
  280. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
  281. package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
  282. package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
  283. package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
  284. package/src/resources/extensions/gsd/custom-workflow-engine.ts +24 -1
  285. package/src/resources/extensions/gsd/db-base-schema.ts +15 -0
  286. package/src/resources/extensions/gsd/db-migration-steps.ts +17 -0
  287. package/src/resources/extensions/gsd/detection.ts +128 -0
  288. package/src/resources/extensions/gsd/graph.ts +12 -5
  289. package/src/resources/extensions/gsd/gsd-db.ts +119 -1
  290. package/src/resources/extensions/gsd/guided-flow.ts +46 -9
  291. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  292. package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
  293. package/src/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  294. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  295. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  296. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  297. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
  298. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
  299. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +84 -5
  300. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +170 -1
  301. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
  302. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
  303. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +112 -6
  304. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
  305. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  306. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
  307. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  308. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  309. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  310. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  311. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  312. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
  313. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
  314. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  315. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  316. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  317. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  318. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  319. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  320. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  321. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
  322. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +46 -2
  323. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  324. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  325. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
  326. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  327. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  328. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
  329. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  330. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  331. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  332. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  333. package/packages/contracts/tsconfig.tsbuildinfo +0 -1
  334. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → _67VlKGhH0VvTM6yfRGKl}/_buildManifest.js +0 -0
  335. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → _67VlKGhH0VvTM6yfRGKl}/_ssgManifest.js +0 -0
@@ -118,6 +118,22 @@ export function resolveExpectedArtifactPathForScope(
118
118
  return resolveExpectedArtifactPath(unitType, unitId, scope.workspace.projectRoot);
119
119
  }
120
120
 
121
+ async function runQuickTaskChoice(ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
122
+ if (!ctx.hasUI) {
123
+ ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
124
+ return;
125
+ }
126
+
127
+ const task = (await ctx.ui.input("Quick task", "Describe the small task to run with /gsd quick"))?.trim();
128
+ if (!task) {
129
+ ctx.ui.notify("Quick task cancelled.", "info");
130
+ return;
131
+ }
132
+
133
+ const { handleQuick } = await import("./quick.js");
134
+ await handleQuick(task, ctx, pi);
135
+ }
136
+
121
137
  /**
122
138
  * Scope-based overload of isGhostMilestone.
123
139
  * Binds basePath and milestoneId from the scope, ensuring path resolution
@@ -2064,8 +2080,8 @@ export async function showSmartEntry(
2064
2080
  // standard wizard below.
2065
2081
  {
2066
2082
  const prefs = loadEffectiveGSDPreferences(basePath)?.preferences;
2067
- const { hasPendingDeepStage } = await import("./auto-dispatch.js");
2068
- if (hasPendingDeepStage(prefs, basePath)) {
2083
+ const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
2084
+ if (shouldRunDeepProjectSetup(state, prefs, basePath)) {
2069
2085
  await startDeepProjectSetupForeground(ctx, pi, basePath, stepMode);
2070
2086
  return;
2071
2087
  }
@@ -2134,17 +2150,24 @@ export async function showSmartEntry(
2134
2150
  title: "GSD — Get Shit Done",
2135
2151
  summary: ["No active milestone."],
2136
2152
  actions: [
2153
+ {
2154
+ id: "quick_task",
2155
+ label: "Quick task",
2156
+ description: "For small bounded work, run /gsd quick <task> or /gsd do <task>.",
2157
+ recommended: true,
2158
+ },
2137
2159
  {
2138
2160
  id: "new_milestone",
2139
2161
  label: "Create next milestone",
2140
- description: "Define what to build next.",
2141
- recommended: true,
2162
+ description: "Define a larger body of work with planning artifacts.",
2142
2163
  },
2143
2164
  ],
2144
2165
  notYetMessage: "Run /gsd when ready.",
2145
2166
  });
2146
2167
 
2147
- if (choice === "new_milestone") {
2168
+ if (choice === "quick_task") {
2169
+ await runQuickTaskChoice(ctx, pi);
2170
+ } else if (choice === "new_milestone") {
2148
2171
  setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
2149
2172
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
2150
2173
  `New milestone ${nextId}.`,
@@ -2181,11 +2204,16 @@ export async function showSmartEntry(
2181
2204
  title: `GSD — ${milestoneId}: ${milestoneTitle}`,
2182
2205
  summary: ["All milestones complete."],
2183
2206
  actions: [
2207
+ {
2208
+ id: "quick_task",
2209
+ label: "Quick task",
2210
+ description: "Do a small bounded task without opening a milestone.",
2211
+ recommended: true,
2212
+ },
2184
2213
  {
2185
2214
  id: "new_milestone",
2186
2215
  label: "Start new milestone",
2187
2216
  description: "Define and plan the next milestone.",
2188
- recommended: true,
2189
2217
  },
2190
2218
  {
2191
2219
  id: "status",
@@ -2196,7 +2224,9 @@ export async function showSmartEntry(
2196
2224
  notYetMessage: "Run /gsd when ready.",
2197
2225
  });
2198
2226
 
2199
- if (choice === "new_milestone") {
2227
+ if (choice === "quick_task") {
2228
+ await runQuickTaskChoice(ctx, pi);
2229
+ } else if (choice === "new_milestone") {
2200
2230
  const milestoneIds = findMilestoneIds(basePath);
2201
2231
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
2202
2232
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
@@ -2300,13 +2330,18 @@ export async function showSmartEntry(
2300
2330
  const hasContext = !!(contextFile && await loadFile(contextFile));
2301
2331
 
2302
2332
  const actions = [
2333
+ {
2334
+ id: "quick_task",
2335
+ label: "Quick task instead",
2336
+ description: "Use this when the work is small and should not become a milestone.",
2337
+ recommended: true,
2338
+ },
2303
2339
  {
2304
2340
  id: "plan",
2305
2341
  label: "Create roadmap",
2306
2342
  description: hasContext
2307
2343
  ? "Context captured. Decompose into slices with a boundary map."
2308
2344
  : "Decompose the milestone into slices with a boundary map.",
2309
- recommended: true,
2310
2345
  },
2311
2346
  ...(!hasContext ? [{
2312
2347
  id: "discuss",
@@ -2332,7 +2367,9 @@ export async function showSmartEntry(
2332
2367
  notYetMessage: "Run /gsd when ready.",
2333
2368
  });
2334
2369
 
2335
- if (choice === "plan") {
2370
+ if (choice === "quick_task") {
2371
+ await runQuickTaskChoice(ctx, pi);
2372
+ } else if (choice === "plan") {
2336
2373
  setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
2337
2374
  await dispatchWorkflow(
2338
2375
  pi,
@@ -0,0 +1,35 @@
1
+ import { isAbsolute, relative, resolve } from "node:path";
2
+ import { normalizePlannedFileReference } from "./files.js";
3
+
4
+ export interface PlanningPathScopeField {
5
+ field: string;
6
+ values: string[];
7
+ }
8
+
9
+ function isInsideBase(basePath: string, candidate: string): boolean {
10
+ const base = resolve(basePath);
11
+ const abs = resolve(candidate);
12
+ const rel = relative(base, abs);
13
+ return rel === "" || (!!rel && !rel.startsWith("..") && !isAbsolute(rel));
14
+ }
15
+
16
+ /**
17
+ * Planning IO fields are execution contracts. Absolute paths are only safe when
18
+ * they stay inside the active working directory; in worktree mode, an absolute
19
+ * path to the original checkout makes executors edit the wrong tree.
20
+ */
21
+ export function validatePlanningPathScope(
22
+ basePath: string,
23
+ fields: PlanningPathScopeField[],
24
+ ): string | null {
25
+ for (const { field, values } of fields) {
26
+ for (const raw of values) {
27
+ const candidate = normalizePlannedFileReference(raw);
28
+ if (!isAbsolute(candidate)) continue;
29
+ if (isInsideBase(basePath, candidate)) continue;
30
+ return `${field} contains absolute path outside working directory: ${candidate}. Use a path relative to ${basePath}.`;
31
+ }
32
+ }
33
+
34
+ return null;
35
+ }
@@ -11,6 +11,7 @@ export interface PrEvidenceInput {
11
11
  changeType?: PrChangeType;
12
12
  linkedIssue?: string;
13
13
  summaries?: string[];
14
+ blockers?: string[];
14
15
  roadmapItems?: string[];
15
16
  metrics?: string[];
16
17
  testsRun?: string[];
@@ -34,8 +35,54 @@ const CHANGE_TYPE_LABELS: Record<PrChangeType, string> = {
34
35
  chore: "Build, CI, or tooling changes",
35
36
  };
36
37
 
38
+ // Per-item cap for user-supplied content. 2 KB gives slice titles plus
39
+ // descriptions room while still bounding malicious DoS-via-PR-body input.
40
+ const USER_CONTENT_CAP_BYTES = 2048;
41
+ const TRUNCATION_SUFFIX = " … [truncated]";
42
+
43
+ // Strips HTML comments, fake commit trailers (Co-Authored-By, Signed-off-by —
44
+ // case-insensitive on the trailer name), and caps total length. Designed to
45
+ // be a no-op for well-formed input; golden fixtures must remain byte-stable.
46
+ // Trailer lines are removed (not rejected) so that a single bad line in an
47
+ // otherwise legitimate description does not block the entire PR.
48
+ function sanitizeUserContent(s: string): string {
49
+ if (!s) return s;
50
+ // Strip HTML comments greedily across newlines.
51
+ let out = s.replace(/<!--[\s\S]*?-->/g, "");
52
+ // Drop lines that look like commit trailers we do not want forged.
53
+ out = out
54
+ .split("\n")
55
+ .filter((line) => !/^\s*(co-authored-by|signed-off-by)\s*:/i.test(line))
56
+ .join("\n");
57
+ if (Buffer.byteLength(out, "utf8") > USER_CONTENT_CAP_BYTES) {
58
+ const budget = USER_CONTENT_CAP_BYTES - Buffer.byteLength(TRUNCATION_SUFFIX, "utf8");
59
+ // Truncate by code units to stay safely under the byte budget for ASCII;
60
+ // for multibyte content we conservatively walk back until under budget.
61
+ let sliced = out.slice(0, Math.max(0, budget));
62
+ while (Buffer.byteLength(sliced, "utf8") > budget && sliced.length > 0) {
63
+ sliced = sliced.slice(0, -1);
64
+ }
65
+ out = sliced + TRUNCATION_SUFFIX;
66
+ }
67
+ return out;
68
+ }
69
+
70
+ // Strips HTML comments and fake trailers without applying the length cap.
71
+ // Used for short fields like linkedIssue where truncation would be confusing.
72
+ function sanitizeIssueRef(s: string): string {
73
+ if (!s) return s;
74
+ let out = s.replace(/<!--[\s\S]*?-->/g, "");
75
+ out = out
76
+ .split("\n")
77
+ .filter((line) => !/^\s*(co-authored-by|signed-off-by)\s*:/i.test(line))
78
+ .join("\n");
79
+ return out;
80
+ }
81
+
37
82
  function normalizeList(values: readonly string[] | undefined): string[] {
38
- return (values ?? []).map((value) => value.trim()).filter(Boolean);
83
+ return (values ?? [])
84
+ .map((value) => sanitizeUserContent(value).trim())
85
+ .filter(Boolean);
39
86
  }
40
87
 
41
88
  function changeTypeChecklist(selected: PrChangeType): string[] {
@@ -56,13 +103,17 @@ export function buildPrEvidence(input: PrEvidenceInput): PrEvidence {
56
103
  const subjectTitle = input.milestoneTitle?.trim() || subjectId;
57
104
  const changeType = input.changeType ?? "feat";
58
105
  const summaries = normalizeList(input.summaries);
106
+ const blockers = normalizeList(input.blockers);
59
107
  const roadmapItems = normalizeList(input.roadmapItems);
60
108
  const metrics = normalizeList(input.metrics);
61
109
  const testsRun = normalizeList(input.testsRun);
62
110
  const rollbackNotes = normalizeList(input.rollbackNotes);
63
- const linkedIssue = input.linkedIssue?.trim() || "Not specified. Add an issue link before marking this PR ready if CONTRIBUTING.md requires one.";
64
- const why = input.why?.trim() || `${capitalize(subjectKind)} work is complete and ready for review.`;
65
- const how = input.how?.trim() || "Generated from GSD evidence and local workflow artifacts.";
111
+ // linkedIssue is sanitized but not length-capped: legitimate issue refs
112
+ // are short by nature, and truncating "Closes #123" would be unhelpful.
113
+ const linkedIssueRaw = input.linkedIssue ? sanitizeIssueRef(input.linkedIssue).trim() : "";
114
+ const linkedIssue = linkedIssueRaw || "Not specified. Add an issue link before marking this PR ready if CONTRIBUTING.md requires one.";
115
+ const why = (input.why ? sanitizeUserContent(input.why).trim() : "") || `${capitalize(subjectKind)} work is complete and ready for review.`;
116
+ const how = (input.how ? sanitizeUserContent(input.how).trim() : "") || "Generated from GSD evidence and local workflow artifacts.";
66
117
  const title = `${changeType}: ${subjectTitle}`;
67
118
 
68
119
  const sections: string[] = [
@@ -75,6 +126,13 @@ export function buildPrEvidence(input: PrEvidenceInput): PrEvidence {
75
126
  "## What",
76
127
  "",
77
128
  summaries.length > 0 ? summaries.join("\n\n") : `${capitalize(subjectKind)} ${subjectId} completed.`,
129
+ ];
130
+
131
+ if (blockers.length > 0) {
132
+ sections.push("", "## Blockers", "", blockers.map((blocker) => `- ${blocker}`).join("\n"));
133
+ }
134
+
135
+ sections.push(
78
136
  "",
79
137
  "## Why",
80
138
  "",
@@ -87,7 +145,7 @@ export function buildPrEvidence(input: PrEvidenceInput): PrEvidence {
87
145
  "## Linked Issue",
88
146
  "",
89
147
  linkedIssue,
90
- ];
148
+ );
91
149
 
92
150
  if (roadmapItems.length > 0) {
93
151
  sections.push("", "## Roadmap", "", roadmapItems.join("\n"));
@@ -16,15 +16,14 @@ Start with what the excerpts give you. Read full files when the section heads si
16
16
 
17
17
  **On-demand Read ordering:** Complete all slice SUMMARY Reads you need for cross-slice synthesis, the Decision Re-evaluation table, and LEARNINGS **before** calling `gsd_complete_milestone` (step 12). Once that tool runs, the milestone is marked complete in the DB, so it must be the final persistent milestone-closeout write.
18
18
 
19
- ### Delegate Review Work
19
+ ### Closeout Review Mode
20
20
 
21
- Use `subagent` for review work needing fresh context, before drafting LEARNINGS:
21
+ The inlined context includes a validation status block.
22
22
 
23
- - Cross-slice integrations or new public APIs -> **reviewer** with milestone diff and roadmap.
24
- - Auth, network, parsing, file IO, shell exec, or crypto -> **security** audit.
25
- - Significant tests added or changed -> **tester** coverage check against success criteria.
23
+ - If it says a passing validation artifact is present, treat that artifact as authoritative for success criteria, requirement coverage, verification classes, and cross-slice integration. Do not delegate fresh reviewer/security/tester audits unless the validation artifact is internally inconsistent with the inlined summaries.
24
+ - If validation is missing, stale, non-pass, or internally inconsistent, use `subagent` for review work needing fresh context before drafting LEARNINGS: cross-slice integrations or new public APIs -> **reviewer**; auth, network, parsing, file IO, shell exec, or crypto -> **security**; significant tests added or changed -> **tester**.
26
25
 
27
- Subagents report only; they do not write user source. Fold findings into Decision Re-evaluation and LEARNINGS before completion.
26
+ Subagents report only; they do not write user source. Fold any findings into Decision Re-evaluation and LEARNINGS before completion.
28
27
 
29
28
  {{inlinedContext}}
30
29
 
@@ -33,8 +32,8 @@ Subagents report only; they do not write user source. Fold findings into Decisio
33
32
  1. Use the **Milestone Summary** output template from the inlined context above
34
33
  2. {{skillActivation}}
35
34
  3. **Verify code changes exist.** Compare milestone work against the integration branch (`main`, `master`, or recorded branch), using merge-base as older revision and `HEAD` as newer. If the diff lists non-`.gsd/` files, pass. If `HEAD` equals the integration branch/merge-base, treat it as a self-diff retry: inspect milestone-scoped commit evidence (`GSD-Unit: {{milestoneId}}` or production `GSD-Task: Sxx/Tyy` trailers touching `.gsd/milestones/{{milestoneId}}/`) and verify those commits touched non-`.gsd/` files. Record **verification failure** only when neither source shows implementation files.
36
- 4. Verify every **success criterion** from `{{roadmapPath}}` with evidence from summaries, tests, or observable behavior. Record unmet criteria as **verification failure**.
37
- 5. Verify **definition of done**: all slices `[x]`, summaries exist, and integrations work. Record unmet items as **verification failure**.
35
+ 4. Verify every **success criterion** from `{{roadmapPath}}`. If passing validation is present, summarize the validation evidence instead of re-auditing it; otherwise verify with evidence from summaries, tests, or observable behavior. Record unmet criteria as **verification failure**.
36
+ 5. Verify **definition of done**: all slices `[x]`, summaries exist, and integrations work. If passing validation is present, trust its integration/verification verdict unless inconsistent with current artifacts. Record unmet items as **verification failure**.
38
37
  6. If the roadmap includes a **Horizontal Checklist**, verify each item and note unchecked items in the summary.
39
38
  7. Fill the **Decision Re-evaluation** table: compare each key `.gsd/DECISIONS.md` decision from this milestone with what shipped, and flag decisions to revisit.
40
39
  8. Validate **requirement status transitions**. For each changed requirement, confirm evidence supports the new status. Requirements may move between Active, Validated, Deferred, Blocked, or Out of Scope only with proof.
@@ -48,7 +48,7 @@ Narrate decomposition reasoning in complete sentences: grouping, risk order, ver
48
48
  Then:
49
49
  1. Use the **Roadmap** output template from the inlined context above
50
50
  2. {{skillActivation}}
51
- 3. Create only as many demoable vertical slices as the work genuinely needs.
51
+ 3. Create only as many demoable vertical slices as the work genuinely needs. Use 1-10 slices, sized to the work; tiny/single-file/static work should usually be one slice.
52
52
  4. Order by risk, high-risk first.
53
53
  5. Call `gsd_plan_milestone` to persist milestone fields, slice rows, and **Horizontal Checklist** through the DB-backed path. Fill checklist concerns considered during planning: requirements, decisions, shutdown, revenue, auth, shared resources, reconnection. Omit for trivial milestones. Do **not** write `{{outputPath}}`, `ROADMAP.md`, or other planning artifacts manually; the tool owns rendering and persistence.
54
54
  6. If planning produced structural decisions (slice ordering, technology choices, scope exclusions), call `gsd_decision_save` for each; the tool assigns IDs and regenerates `.gsd/DECISIONS.md`.
@@ -78,6 +78,8 @@ Apply these when decomposing and ordering slices:
78
78
  - Ship features, not proofs; use clearly marked realistic stubs only when necessary.
79
79
  - **Dependency format is comma-separated, never range syntax.** Write `depends:[S01,S02,S03]`, not `depends:[S01-S03]`.
80
80
  - Roadmap ambition must match the milestone; right-size decomposition.
81
+ - Missing ecosystem markers are not a reason to over-plan. If Project Classification says `untyped-existing`, treat the listed content files as the project surface and use generic file-level workflow guidance.
82
+ - For `untyped-existing` projects with 1-2 content files, prefer exactly one slice unless the request clearly spans multiple independent user-visible capabilities. For 3-5 content files, prefer 1-2 slices.
81
83
 
82
84
  ## Progressive Planning (ADR-011)
83
85
 
@@ -39,7 +39,7 @@ If slice research is inlined, trust it. Explore enough code to confirm paths, bo
39
39
  5. Define slice verification before tasks. Non-trivial slices need real tests or executable assertions; boundary contracts need contract-exercising checks. Tests must not read .gitignore/gitignored paths such as `.gsd/`, `.planning/`, or `.audits/`.
40
40
  6. Include Threat Surface (Q3), Requirement Impact (Q4), proof level, observability, integration closure, Failure Modes (Q5), Load Profile (Q6), and Negative Tests (Q7) only where applicable.
41
41
  7. Right-size tasks. Simple slices can be one task; split only when context, ownership, or verification boundaries justify it.
42
- 8. Each task needs a concrete title, Why / Files / Do / Verify / Done when, plus task-plan description, steps, must-haves, verification, inputs, and expected output. Inputs and Expected Output must include concrete backtick-wrapped paths; each task needs at least one output path.
42
+ 8. Each task needs a concrete title, Why / Files / Do / Verify / Done when, plus task-plan description, steps, must-haves, verification, inputs, and expected output. Inputs and Expected Output must include concrete backtick-wrapped paths; each task needs at least one output path. Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands.
43
43
  9. Persist with `gsd_plan_slice` using goal, successCriteria, optional proofLevel/integrationClosure/observabilityImpact, and tasks. `gsd_plan_slice` handles task persistence transactionally and renders `{{outputPath}}` plus task plans; do not call `gsd_plan_task`. The DB-backed tool is the canonical write path. Do **not** rely on direct `PLAN.md` writes as the source of truth.
44
44
  10. Self-audit before finishing: goal/demo closure, requirement coverage, locked decisions, concrete paths, dependency order, wiring, scope size, proof truthfulness, feature completeness, and quality gates. Quality gates: non-trivial slices/tasks include specific Q3-Q7 coverage where applicable.
45
45
  11. If planning creates structural decisions, append them to `.gsd/DECISIONS.md`.
@@ -50,6 +50,15 @@ export interface FileEditEvidence {
50
50
 
51
51
  export type EvidenceEntry = BashEvidence | FileWriteEvidence | FileEditEvidence;
52
52
 
53
+ const EXECUTION_TOOL_NAMES = new Set([
54
+ "bash",
55
+ "Bash",
56
+ "gsd_exec",
57
+ "gsd_exec_search",
58
+ "mcp__gsd-workflow__gsd_exec",
59
+ "mcp__gsd-workflow__gsd_exec_search",
60
+ ]);
61
+
53
62
  // ─── Module State ───────────────────────────────────────────────────────────
54
63
 
55
64
  let unitEvidence: EvidenceEntry[] = [];
@@ -188,11 +197,11 @@ export function clearEvidenceFromDisk(
188
197
  * Exit codes and output are filled in by recordToolResult after execution.
189
198
  */
190
199
  export function recordToolCall(toolCallId: string, toolName: string, input: Record<string, unknown>): void {
191
- if (toolName === "bash" || toolName === "Bash") {
200
+ if (EXECUTION_TOOL_NAMES.has(toolName)) {
192
201
  unitEvidence.push({
193
202
  kind: "bash",
194
203
  toolCallId,
195
- command: String(input.command ?? ""),
204
+ command: String(input.command ?? input.cmd ?? input.query ?? ""),
196
205
  exitCode: -1,
197
206
  outputSnippet: "",
198
207
  timestamp: Date.now(),
@@ -1,7 +1,7 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
 
4
- import { _buildAbortedPauseContext } from "../bootstrap/agent-end-recovery.js";
4
+ import { _buildAbortedPauseContext, isUserInitiatedAbortMessage } from "../bootstrap/agent-end-recovery.js";
5
5
  import { _buildCancelledUnitStopReason } from "../auto/phases.js";
6
6
 
7
7
  test("aborted agent_end maps errorMessage into structured aborted pause context", () => {
@@ -30,3 +30,9 @@ test("cancelled non-session failures are labeled as unit aborts (not session-cre
30
30
  assert.equal(cancelled.stopReason, "Unit aborted: tool invocation cancelled");
31
31
  assert.equal(cancelled.loopReason, "unit-aborted");
32
32
  });
33
+
34
+ test("provider user-abort errors are recognized as cancellations, not provider outages", () => {
35
+ assert.equal(isUserInitiatedAbortMessage("Claude Code process aborted by user"), true);
36
+ assert.equal(isUserInitiatedAbortMessage("Request aborted by user"), true);
37
+ assert.equal(isUserInitiatedAbortMessage("HTTP 503 Service Unavailable"), false);
38
+ });
@@ -23,6 +23,8 @@ import {
23
23
  _refreshLastCommitForTests,
24
24
  _getLastCommitForTests,
25
25
  _getLastCommitFetchedAtForTests,
26
+ formatRuntimeHealthSignal,
27
+ shouldRenderRoadmapProgress,
26
28
  } from "../auto-dashboard.ts";
27
29
  import {
28
30
  openDatabase,
@@ -193,6 +195,37 @@ test("formatWidgetTokens formats millions with M", () => {
193
195
  assert.equal(formatWidgetTokens(25_000_000), "25M");
194
196
  });
195
197
 
198
+ test("formatRuntimeHealthSignal surfaces idle recovery instead of generic progress", () => {
199
+ const signal = formatRuntimeHealthSignal({
200
+ version: 1,
201
+ unitType: "research-milestone",
202
+ unitId: "M001",
203
+ startedAt: 1_000,
204
+ updatedAt: 600_000,
205
+ phase: "recovered",
206
+ wrapupWarningSent: false,
207
+ continueHereFired: false,
208
+ timeoutAt: null,
209
+ lastProgressAt: 1_000,
210
+ progressCount: 1,
211
+ lastProgressKind: "idle-recovery-retry",
212
+ recoveryAttempts: 1,
213
+ lastRecoveryReason: "idle",
214
+ }, 600_000);
215
+
216
+ assert.deepEqual(signal, {
217
+ level: "yellow",
218
+ summary: "Recovering",
219
+ detail: "retry 1 after idle stall",
220
+ });
221
+ });
222
+
223
+ test("shouldRenderRoadmapProgress hides pre-roadmap zero-slice progress", () => {
224
+ assert.equal(shouldRenderRoadmapProgress(null), false);
225
+ assert.equal(shouldRenderRoadmapProgress({ done: 0, total: 0, activeSliceTasks: null } as any), false);
226
+ assert.equal(shouldRenderRoadmapProgress({ done: 0, total: 1, activeSliceTasks: null } as any), true);
227
+ });
228
+
196
229
  // ─── estimateTimeRemaining ──────────────────────────────────────────────
197
230
 
198
231
  test("estimateTimeRemaining returns null when no ledger data", () => {
@@ -879,7 +879,11 @@ test("autoLoop passes structured session-lock failure details to the handler", a
879
879
  );
880
880
  });
881
881
 
882
- test("autoLoop keeps queued sidecar work when the session lock is lost", async () => {
882
+ // Regression for #5308: the iteration prelude must dequeue sidecar items
883
+ // (popping the queue and emitting the `sidecar-dequeue` journal event) BEFORE
884
+ // validateSessionLock + break-on-invalid. Inverting that order silently drops
885
+ // queued sidecar work on lock-loss. Covers first-iteration and mid-session.
886
+ test("autoLoop dequeues sidecar item before session-lock break (first iteration, #5308)", async () => {
883
887
  _resetPendingResolve();
884
888
 
885
889
  const ctx = makeMockCtx();
@@ -911,12 +915,87 @@ test("autoLoop keeps queued sidecar work when the session lock is lost", async (
911
915
 
912
916
  await autoLoop(ctx, pi, s, deps);
913
917
 
914
- assert.equal(s.sidecarQueue.length, 1, "lost session lock must not consume queued sidecar work");
915
- assert.equal(s.sidecarQueue[0]?.unitId, "M001/S01/T01/review");
916
- assert.ok(!journalEvents.includes("sidecar-dequeue"), "sidecar dequeue must happen only after lock validation");
918
+ assert.equal(
919
+ s.sidecarQueue.length,
920
+ 0,
921
+ "sidecar item must be popped on lock-loss iteration (pre-#5308 ordering)",
922
+ );
923
+ assert.ok(
924
+ journalEvents.includes("sidecar-dequeue"),
925
+ "sidecar-dequeue journal event must be emitted before session-lock break",
926
+ );
927
+ assert.ok(
928
+ deps.callLog.includes("handleLostSessionLock"),
929
+ "session lock handler must still fire after sidecar dequeue",
930
+ );
917
931
  assert.ok(!deps.callLog.includes("deriveState"), "lock loss should stop before deriving state");
918
932
  });
919
933
 
934
+ test("autoLoop dequeues sidecar item before session-lock break (mid-session, #5308)", async () => {
935
+ _resetPendingResolve();
936
+
937
+ const ctx = makeMockCtx();
938
+ ctx.ui.setStatus = () => {};
939
+ const pi = makeMockPi();
940
+ const s = makeLoopSession();
941
+
942
+ const journalEvents: string[] = [];
943
+ let lockCheckCount = 0;
944
+ const deps = makeMockDeps({
945
+ // First iteration: lock valid; second iteration: lock invalidates.
946
+ validateSessionLock: () => {
947
+ lockCheckCount += 1;
948
+ if (lockCheckCount === 1) {
949
+ return { valid: true } as SessionLockStatus;
950
+ }
951
+ return {
952
+ valid: false,
953
+ failureReason: "compromised",
954
+ expectedPid: process.pid,
955
+ } as SessionLockStatus;
956
+ },
957
+ handleLostSessionLock: () => {
958
+ deps.callLog.push("handleLostSessionLock");
959
+ },
960
+ emitJournalEvent: (entry) => {
961
+ journalEvents.push(entry.eventType);
962
+ },
963
+ // Enqueue a sidecar item at the end of iteration 1, so iteration 2 begins
964
+ // with a non-empty queue and an invalid lock.
965
+ postUnitPostVerification: async () => {
966
+ deps.callLog.push("postUnitPostVerification");
967
+ s.sidecarQueue.push({
968
+ kind: "hook" as const,
969
+ unitType: "hook/review",
970
+ unitId: "M001/S01/T01/review",
971
+ prompt: "review the code",
972
+ });
973
+ return "continue" as const;
974
+ },
975
+ });
976
+
977
+ const loopPromise = autoLoop(ctx, pi, s, deps);
978
+ // Allow the loop to reach runUnit's await on iteration 1.
979
+ await new Promise((r) => setTimeout(r, 50));
980
+ resolveAgentEnd(makeEvent());
981
+ await loopPromise;
982
+
983
+ assert.ok(lockCheckCount >= 2, "lock validator must run on iteration 2");
984
+ assert.equal(
985
+ s.sidecarQueue.length,
986
+ 0,
987
+ "queued sidecar item must be popped on the lock-loss iteration",
988
+ );
989
+ assert.ok(
990
+ journalEvents.includes("sidecar-dequeue"),
991
+ "sidecar-dequeue journal event must be emitted before session-lock break",
992
+ );
993
+ assert.ok(
994
+ deps.callLog.includes("handleLostSessionLock"),
995
+ "lock-loss handler must still fire on iteration 2",
996
+ );
997
+ });
998
+
920
999
  test("autoLoop exits on terminal blocked state", async (t) => {
921
1000
  _resetPendingResolve();
922
1001
 
@@ -2477,7 +2556,7 @@ test("autoLoop warns but proceeds for greenfield project (no project files) (#18
2477
2556
  "should not stop with health check failure for greenfield project",
2478
2557
  );
2479
2558
  const greenfieldWarning = notifications.find(
2480
- (n) => n.includes("no recognized project files") && n.includes("greenfield"),
2559
+ (n) => n.includes("no project content yet") && n.includes("greenfield"),
2481
2560
  );
2482
2561
  assert.ok(
2483
2562
  greenfieldWarning,