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

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 (303) 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-extract-learnings.js +17 -12
  19. package/dist/resources/extensions/gsd/custom-workflow-engine.js +22 -2
  20. package/dist/resources/extensions/gsd/db-base-schema.js +14 -0
  21. package/dist/resources/extensions/gsd/db-migration-steps.js +16 -0
  22. package/dist/resources/extensions/gsd/detection.js +106 -0
  23. package/dist/resources/extensions/gsd/graph.js +9 -3
  24. package/dist/resources/extensions/gsd/gsd-db.js +102 -2
  25. package/dist/resources/extensions/gsd/guided-flow.js +2 -2
  26. package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
  27. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  28. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  29. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  30. package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
  31. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  32. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  33. package/dist/web/standalone/.next/BUILD_ID +1 -1
  34. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  35. package/dist/web/standalone/.next/build-manifest.json +3 -3
  36. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  37. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/index.html +1 -1
  56. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  63. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  64. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  67. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  68. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  69. package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
  70. package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
  71. package/package.json +10 -6
  72. package/packages/contracts/package.json +1 -1
  73. package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
  74. package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
  75. package/packages/pi-ai/dist/models/fake-model.js +27 -0
  76. package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
  77. package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
  78. package/packages/pi-ai/dist/models/index.js +8 -0
  79. package/packages/pi-ai/dist/models/index.js.map +1 -1
  80. package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
  81. package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
  82. package/packages/pi-ai/dist/providers/fake.js +319 -0
  83. package/packages/pi-ai/dist/providers/fake.js.map +1 -0
  84. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  85. package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
  86. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  87. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  88. package/packages/pi-ai/src/models/index.ts +9 -0
  89. package/packages/pi-ai/src/providers/fake.ts +376 -0
  90. package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
  91. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  92. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +74 -0
  93. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  95. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/extensions/runner.js +14 -1
  97. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  98. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +97 -0
  99. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  100. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  101. package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
  102. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  103. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +4 -0
  104. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  105. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  106. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  108. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  109. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  110. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
  116. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
  118. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
  119. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
  120. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
  121. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
  122. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
  132. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  133. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +16 -0
  134. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  135. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -17
  136. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  138. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +60 -1
  139. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +40 -1
  141. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
  143. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  145. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  148. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +23 -0
  150. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
  153. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
  155. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
  156. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
  157. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
  158. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  159. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
  161. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  162. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  163. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  164. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
  165. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  167. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  168. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  169. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
  170. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
  171. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
  172. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
  173. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
  174. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
  175. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
  176. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
  177. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +87 -0
  178. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +108 -0
  179. package/packages/pi-coding-agent/src/core/extensions/runner.ts +16 -1
  180. package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
  181. package/packages/pi-coding-agent/src/core/settings-manager.ts +12 -0
  182. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  183. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  184. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
  185. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
  186. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
  187. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  188. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
  189. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  190. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
  191. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +118 -17
  192. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +43 -1
  193. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -1
  194. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
  195. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
  196. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +25 -0
  197. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  198. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
  199. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
  200. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
  201. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  202. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
  203. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  204. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  205. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  206. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  207. package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
  208. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  209. package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
  210. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  211. package/packages/pi-tui/dist/index.d.ts +1 -0
  212. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  213. package/packages/pi-tui/dist/index.js +2 -0
  214. package/packages/pi-tui/dist/index.js.map +1 -1
  215. package/packages/pi-tui/dist/style.d.ts +41 -0
  216. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  217. package/packages/pi-tui/dist/style.js +158 -0
  218. package/packages/pi-tui/dist/style.js.map +1 -0
  219. package/packages/pi-tui/dist/tui.d.ts +0 -1
  220. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  221. package/packages/pi-tui/dist/tui.js +3 -8
  222. package/packages/pi-tui/dist/tui.js.map +1 -1
  223. package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
  224. package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
  225. package/packages/pi-tui/src/index.ts +9 -0
  226. package/packages/pi-tui/src/style.ts +225 -0
  227. package/packages/pi-tui/src/tui.ts +3 -8
  228. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  229. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  230. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  231. package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
  232. package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  233. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  234. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  235. package/pkg/dist/modes/interactive/theme/theme.js +18 -1
  236. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  237. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  238. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  239. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  240. package/src/resources/GSD-WORKFLOW.md +2 -2
  241. package/src/resources/extensions/github-sync/templates.ts +38 -8
  242. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  243. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  244. package/src/resources/extensions/gsd/auto/loop.ts +17 -10
  245. package/src/resources/extensions/gsd/auto/phases.ts +42 -28
  246. package/src/resources/extensions/gsd/auto/run-unit.ts +24 -14
  247. package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
  248. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
  249. package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
  250. package/src/resources/extensions/gsd/auto-prompts.ts +116 -1
  251. package/src/resources/extensions/gsd/auto-recovery.ts +153 -7
  252. package/src/resources/extensions/gsd/auto-start.ts +7 -6
  253. package/src/resources/extensions/gsd/auto.ts +12 -1
  254. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -1
  255. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -1
  256. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
  257. package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
  258. package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
  259. package/src/resources/extensions/gsd/custom-workflow-engine.ts +24 -1
  260. package/src/resources/extensions/gsd/db-base-schema.ts +15 -0
  261. package/src/resources/extensions/gsd/db-migration-steps.ts +17 -0
  262. package/src/resources/extensions/gsd/detection.ts +128 -0
  263. package/src/resources/extensions/gsd/graph.ts +12 -5
  264. package/src/resources/extensions/gsd/gsd-db.ts +119 -1
  265. package/src/resources/extensions/gsd/guided-flow.ts +2 -2
  266. package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
  267. package/src/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  268. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  269. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  270. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
  271. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
  272. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +84 -5
  273. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +170 -1
  274. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
  275. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
  276. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +112 -6
  277. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
  278. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  279. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
  280. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  281. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  282. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  283. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  284. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  285. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
  286. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
  287. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  288. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  289. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  290. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  291. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  292. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +46 -2
  293. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  294. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  295. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
  296. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  297. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  298. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
  299. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  300. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  301. package/packages/contracts/tsconfig.tsbuildinfo +0 -1
  302. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → mPZbi5BH9dwokaPZlrYuQ}/_buildManifest.js +0 -0
  303. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → mPZbi5BH9dwokaPZlrYuQ}/_ssgManifest.js +0 -0
@@ -0,0 +1,428 @@
1
+ // gsd-2 (GSD2) + db migration `:memory:` integration tests
2
+ //
3
+ // Covers the gap left by the FakeAdapter unit tests for the gsd-db split
4
+ // (PR #5308): those assert SQL strings, not that DDL actually executes.
5
+ // These tests open a real node:sqlite `:memory:` database, run the schema
6
+ // helpers, and verify the resulting schema via PRAGMA introspection.
7
+
8
+ import { describe, test } from "node:test";
9
+ import assert from "node:assert/strict";
10
+ import { createRequire } from "node:module";
11
+
12
+ import { createDbAdapter, type DbAdapter } from "../db-adapter.ts";
13
+ import { createBaseSchemaObjects } from "../db-base-schema.ts";
14
+ import { columnExists } from "../db-schema-metadata.ts";
15
+ import {
16
+ applyMigrationV2Artifacts,
17
+ applyMigrationV3Memories,
18
+ applyMigrationV4DecisionMadeBy,
19
+ applyMigrationV5HierarchyTables,
20
+ applyMigrationV6SliceSummaries,
21
+ applyMigrationV7Dependencies,
22
+ applyMigrationV8PlanningFields,
23
+ applyMigrationV9Ordering,
24
+ applyMigrationV10ReplanTrigger,
25
+ applyMigrationV11TaskPlanning,
26
+ applyMigrationV12QualityGates,
27
+ applyMigrationV13HotPathIndexes,
28
+ applyMigrationV22QualityGateRepair,
29
+ } from "../db-migration-steps.ts";
30
+
31
+ const _require = createRequire(import.meta.url);
32
+
33
+ interface ColumnInfo {
34
+ name: string;
35
+ type: string;
36
+ notnull: number;
37
+ dflt_value: unknown;
38
+ pk: number;
39
+ }
40
+
41
+ function openMemoryAdapter(): { adapter: DbAdapter; close: () => void } {
42
+ const sqlite = _require("node:sqlite") as { DatabaseSync: new (path: string) => unknown };
43
+ const raw = new sqlite.DatabaseSync(":memory:");
44
+ const adapter = createDbAdapter(raw);
45
+ return {
46
+ adapter,
47
+ close: () => adapter.close(),
48
+ };
49
+ }
50
+
51
+ function tableInfo(db: DbAdapter, table: string): ColumnInfo[] {
52
+ return db.prepare(`PRAGMA table_info(${table})`).all() as unknown as ColumnInfo[];
53
+ }
54
+
55
+ function columnNames(db: DbAdapter, table: string): string[] {
56
+ return tableInfo(db, table).map((c) => c.name);
57
+ }
58
+
59
+ function tableExists(db: DbAdapter, table: string): boolean {
60
+ return !!db
61
+ .prepare("SELECT 1 as present FROM sqlite_master WHERE type='table' AND name=?")
62
+ .get(table);
63
+ }
64
+
65
+ function indexExists(db: DbAdapter, name: string): boolean {
66
+ return !!db
67
+ .prepare("SELECT 1 as present FROM sqlite_master WHERE type='index' AND name=?")
68
+ .get(name);
69
+ }
70
+
71
+ function viewExists(db: DbAdapter, name: string): boolean {
72
+ return !!db
73
+ .prepare("SELECT 1 as present FROM sqlite_master WHERE type='view' AND name=?")
74
+ .get(name);
75
+ }
76
+
77
+ describe("db base schema bring-up against :memory: sqlite", () => {
78
+ test("createBaseSchemaObjects executes all DDL without throwing", () => {
79
+ const { adapter, close } = openMemoryAdapter();
80
+ try {
81
+ assert.doesNotThrow(() => {
82
+ createBaseSchemaObjects(adapter, {
83
+ tryCreateMemoriesFts: () => true,
84
+ ensureVerificationEvidenceDedupIndex: () => {},
85
+ });
86
+ });
87
+ } finally {
88
+ close();
89
+ }
90
+ });
91
+
92
+ test("base schema produces all expected tables, indexes, and views", () => {
93
+ const { adapter, close } = openMemoryAdapter();
94
+ try {
95
+ createBaseSchemaObjects(adapter, {
96
+ tryCreateMemoriesFts: () => true,
97
+ ensureVerificationEvidenceDedupIndex: () => {},
98
+ });
99
+
100
+ const expectedTables = [
101
+ "schema_version",
102
+ "decisions",
103
+ "requirements",
104
+ "artifacts",
105
+ "memories",
106
+ "memory_processed_units",
107
+ "memory_sources",
108
+ "memory_embeddings",
109
+ "memory_relations",
110
+ "milestones",
111
+ "slices",
112
+ "tasks",
113
+ "verification_evidence",
114
+ "replan_history",
115
+ "assessments",
116
+ "quality_gates",
117
+ "slice_dependencies",
118
+ "gate_runs",
119
+ "turn_git_transactions",
120
+ "audit_events",
121
+ "audit_turn_index",
122
+ ];
123
+ for (const t of expectedTables) {
124
+ assert.ok(tableExists(adapter, t), `expected table ${t} to exist`);
125
+ }
126
+
127
+ const expectedIndexes = [
128
+ "idx_memories_active",
129
+ "idx_replan_history_milestone",
130
+ "idx_tasks_active",
131
+ "idx_slices_active",
132
+ "idx_milestones_status",
133
+ "idx_quality_gates_pending",
134
+ "idx_verification_evidence_task",
135
+ "idx_slice_deps_target",
136
+ "idx_gate_runs_turn",
137
+ "idx_gate_runs_lookup",
138
+ "idx_turn_git_tx_turn",
139
+ "idx_audit_events_trace",
140
+ "idx_audit_events_turn",
141
+ ];
142
+ for (const i of expectedIndexes) {
143
+ assert.ok(indexExists(adapter, i), `expected index ${i}`);
144
+ }
145
+
146
+ for (const v of ["active_decisions", "active_requirements", "active_memories"]) {
147
+ assert.ok(viewExists(adapter, v), `expected view ${v}`);
148
+ }
149
+ } finally {
150
+ close();
151
+ }
152
+ });
153
+
154
+ test("base schema decisions table has the documented column shape", () => {
155
+ const { adapter, close } = openMemoryAdapter();
156
+ try {
157
+ createBaseSchemaObjects(adapter, {
158
+ tryCreateMemoriesFts: () => true,
159
+ ensureVerificationEvidenceDedupIndex: () => {},
160
+ });
161
+
162
+ const cols = tableInfo(adapter, "decisions");
163
+ const byName = new Map(cols.map((c) => [c.name, c]));
164
+
165
+ const seq = byName.get("seq");
166
+ assert.ok(seq, "decisions.seq column missing");
167
+ assert.equal(seq!.type, "INTEGER");
168
+ assert.equal(seq!.pk, 1, "seq should be primary key");
169
+
170
+ const id = byName.get("id");
171
+ assert.ok(id);
172
+ assert.equal(id!.type, "TEXT");
173
+ assert.equal(id!.notnull, 1);
174
+
175
+ const madeBy = byName.get("made_by");
176
+ assert.ok(madeBy, "decisions.made_by missing (V4 migration column)");
177
+ assert.equal(madeBy!.notnull, 1);
178
+
179
+ const source = byName.get("source");
180
+ assert.ok(source, "decisions.source missing (V16 migration column)");
181
+ assert.equal(source!.notnull, 1);
182
+ } finally {
183
+ close();
184
+ }
185
+ });
186
+
187
+ test("base schema tasks table promotes composite primary key correctly", () => {
188
+ const { adapter, close } = openMemoryAdapter();
189
+ try {
190
+ createBaseSchemaObjects(adapter, {
191
+ tryCreateMemoriesFts: () => true,
192
+ ensureVerificationEvidenceDedupIndex: () => {},
193
+ });
194
+
195
+ const cols = tableInfo(adapter, "tasks");
196
+ const pkCols = cols.filter((c) => c.pk > 0).sort((a, b) => a.pk - b.pk).map((c) => c.name);
197
+ assert.deepEqual(pkCols, ["milestone_id", "slice_id", "id"]);
198
+ } finally {
199
+ close();
200
+ }
201
+ });
202
+ });
203
+
204
+ describe("db migration steps end-to-end against :memory: sqlite", () => {
205
+ // Drive a fresh DB from V1 baseline up to V13 so each high-risk migration
206
+ // sees a realistic schema (not the FakeAdapter no-op surface).
207
+ function runUpToV13(adapter: DbAdapter): void {
208
+ adapter.exec(`
209
+ CREATE TABLE schema_version (
210
+ version INTEGER NOT NULL,
211
+ applied_at TEXT NOT NULL
212
+ )
213
+ `);
214
+ adapter.exec(`
215
+ CREATE TABLE decisions (
216
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
217
+ id TEXT NOT NULL UNIQUE,
218
+ when_context TEXT NOT NULL DEFAULT '',
219
+ scope TEXT NOT NULL DEFAULT '',
220
+ decision TEXT NOT NULL DEFAULT '',
221
+ choice TEXT NOT NULL DEFAULT '',
222
+ rationale TEXT NOT NULL DEFAULT '',
223
+ revisable TEXT NOT NULL DEFAULT '',
224
+ superseded_by TEXT DEFAULT NULL
225
+ )
226
+ `);
227
+ adapter.exec(`
228
+ CREATE TABLE requirements (
229
+ id TEXT PRIMARY KEY,
230
+ class TEXT NOT NULL DEFAULT '',
231
+ status TEXT NOT NULL DEFAULT '',
232
+ description TEXT NOT NULL DEFAULT '',
233
+ why TEXT NOT NULL DEFAULT '',
234
+ source TEXT NOT NULL DEFAULT '',
235
+ primary_owner TEXT NOT NULL DEFAULT '',
236
+ supporting_slices TEXT NOT NULL DEFAULT '',
237
+ validation TEXT NOT NULL DEFAULT '',
238
+ notes TEXT NOT NULL DEFAULT '',
239
+ full_content TEXT NOT NULL DEFAULT '',
240
+ superseded_by TEXT DEFAULT NULL
241
+ )
242
+ `);
243
+ adapter.exec("CREATE VIEW active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL");
244
+ adapter.exec("CREATE VIEW active_requirements AS SELECT * FROM requirements WHERE superseded_by IS NULL");
245
+
246
+ applyMigrationV2Artifacts(adapter);
247
+ applyMigrationV3Memories(adapter);
248
+ applyMigrationV4DecisionMadeBy(adapter);
249
+ applyMigrationV5HierarchyTables(adapter);
250
+ applyMigrationV6SliceSummaries(adapter);
251
+ applyMigrationV7Dependencies(adapter);
252
+ applyMigrationV8PlanningFields(adapter);
253
+ applyMigrationV9Ordering(adapter);
254
+ applyMigrationV10ReplanTrigger(adapter);
255
+ applyMigrationV11TaskPlanning(adapter);
256
+ applyMigrationV12QualityGates(adapter);
257
+ applyMigrationV13HotPathIndexes(adapter, () => {});
258
+ }
259
+
260
+ test("V8 PlanningFields adds every promised ALTER column without throwing", () => {
261
+ const { adapter, close } = openMemoryAdapter();
262
+ try {
263
+ runUpToV13(adapter);
264
+
265
+ assert.ok(columnExists(adapter, "milestones", "vision"));
266
+ assert.ok(columnExists(adapter, "milestones", "verification_uat"));
267
+ assert.ok(columnExists(adapter, "milestones", "definition_of_done"));
268
+ assert.ok(columnExists(adapter, "milestones", "boundary_map_markdown"));
269
+
270
+ assert.ok(columnExists(adapter, "slices", "goal"));
271
+ assert.ok(columnExists(adapter, "slices", "proof_level"));
272
+ assert.ok(columnExists(adapter, "slices", "observability_impact"));
273
+
274
+ assert.ok(columnExists(adapter, "tasks", "estimate"));
275
+ assert.ok(columnExists(adapter, "tasks", "files"));
276
+ assert.ok(columnExists(adapter, "tasks", "expected_output"));
277
+
278
+ assert.ok(tableExists(adapter, "replan_history"));
279
+ assert.ok(tableExists(adapter, "assessments"));
280
+ } finally {
281
+ close();
282
+ }
283
+ });
284
+
285
+ test("V13 HotPathIndexes succeeds when prior migrations have run (ordering)", () => {
286
+ const { adapter, close } = openMemoryAdapter();
287
+ try {
288
+ runUpToV13(adapter);
289
+
290
+ for (const i of [
291
+ "idx_tasks_active",
292
+ "idx_slices_active",
293
+ "idx_milestones_status",
294
+ "idx_quality_gates_pending",
295
+ "idx_verification_evidence_task",
296
+ ]) {
297
+ assert.ok(indexExists(adapter, i), `expected index ${i} after V13`);
298
+ }
299
+ } finally {
300
+ close();
301
+ }
302
+ });
303
+
304
+ test("V13 HotPathIndexes throws if quality_gates table does not yet exist (ordering guard)", () => {
305
+ const { adapter, close } = openMemoryAdapter();
306
+ try {
307
+ adapter.exec("CREATE TABLE schema_version (version INTEGER NOT NULL, applied_at TEXT NOT NULL)");
308
+ assert.throws(
309
+ () => applyMigrationV13HotPathIndexes(adapter, () => {}),
310
+ /no such table/i,
311
+ );
312
+ } finally {
313
+ close();
314
+ }
315
+ });
316
+
317
+ test("V22 QualityGateRepair rebuilds quality_gates with task_id NOT NULL and preserves indexes", () => {
318
+ const { adapter, close } = openMemoryAdapter();
319
+ try {
320
+ runUpToV13(adapter);
321
+
322
+ adapter.exec("DROP INDEX IF EXISTS idx_quality_gates_pending");
323
+ adapter.exec("DROP TABLE quality_gates");
324
+ adapter.exec(`
325
+ CREATE TABLE quality_gates (
326
+ milestone_id TEXT NOT NULL,
327
+ slice_id TEXT NOT NULL,
328
+ gate_id TEXT NOT NULL,
329
+ task_id TEXT DEFAULT '',
330
+ status TEXT NOT NULL DEFAULT 'pending',
331
+ verdict TEXT NOT NULL DEFAULT '',
332
+ rationale TEXT NOT NULL DEFAULT '',
333
+ findings TEXT NOT NULL DEFAULT '',
334
+ evaluated_at TEXT DEFAULT NULL,
335
+ PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
336
+ FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
337
+ )
338
+ `);
339
+
340
+ const before = tableInfo(adapter, "quality_gates").find((c) => c.name === "task_id");
341
+ assert.ok(before);
342
+ assert.equal(before!.notnull, 0, "pre-repair fixture should have nullable task_id");
343
+
344
+ let copyCalled = 0;
345
+ applyMigrationV22QualityGateRepair(adapter, {
346
+ copyQualityGateRowsToRepairedTable: () => {
347
+ copyCalled += 1;
348
+ },
349
+ });
350
+
351
+ assert.equal(copyCalled, 1, "repair branch should invoke the row-copy hook exactly once");
352
+
353
+ const after = tableInfo(adapter, "quality_gates").find((c) => c.name === "task_id");
354
+ assert.ok(after);
355
+ assert.equal(after!.notnull, 1, "post-repair task_id must be NOT NULL");
356
+
357
+ assert.ok(columnExists(adapter, "quality_gates", "scope"));
358
+ assert.ok(columnExists(adapter, "assessments", "scope"));
359
+
360
+ assert.ok(indexExists(adapter, "idx_quality_gates_pending"));
361
+
362
+ assert.equal(tableExists(adapter, "quality_gates_new"), false);
363
+
364
+ assert.deepEqual(columnNames(adapter, "quality_gates"), [
365
+ "milestone_id",
366
+ "slice_id",
367
+ "gate_id",
368
+ "scope",
369
+ "task_id",
370
+ "status",
371
+ "verdict",
372
+ "rationale",
373
+ "findings",
374
+ "evaluated_at",
375
+ ]);
376
+ } finally {
377
+ close();
378
+ }
379
+ });
380
+
381
+ test("V22 is a no-op on already-repaired quality_gates", () => {
382
+ const { adapter, close } = openMemoryAdapter();
383
+ try {
384
+ runUpToV13(adapter);
385
+
386
+ let copyCalled = 0;
387
+ applyMigrationV22QualityGateRepair(adapter, {
388
+ copyQualityGateRowsToRepairedTable: () => {
389
+ copyCalled += 1;
390
+ },
391
+ });
392
+
393
+ assert.equal(copyCalled, 0, "no-op when task_id is already NOT NULL");
394
+ assert.ok(columnExists(adapter, "quality_gates", "scope"));
395
+ } finally {
396
+ close();
397
+ }
398
+ });
399
+ });
400
+
401
+ describe("db provider happy path against :memory: sqlite", () => {
402
+ test("createDbAdapter wraps node:sqlite and supports exec/prepare/close", () => {
403
+ const sqlite = _require("node:sqlite") as { DatabaseSync: new (path: string) => unknown };
404
+ const raw = new sqlite.DatabaseSync(":memory:");
405
+ const adapter = createDbAdapter(raw);
406
+
407
+ assert.doesNotThrow(() => adapter.exec("CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)"));
408
+
409
+ const insert = adapter.prepare("INSERT INTO t (id, v) VALUES (?, ?)");
410
+ insert.run(1, "alpha");
411
+ insert.run(2, "beta");
412
+
413
+ const selectOne = adapter.prepare("SELECT v FROM t WHERE id = ?");
414
+ const row = selectOne.get(1);
415
+ assert.deepEqual(row, { v: "alpha" });
416
+
417
+ const selectAll = adapter.prepare("SELECT id, v FROM t ORDER BY id");
418
+ const rows = selectAll.all();
419
+ assert.equal(rows.length, 2);
420
+ assert.equal(rows[0]["v"], "alpha");
421
+ assert.equal(rows[1]["v"], "beta");
422
+
423
+ const selectAgain = adapter.prepare("SELECT v FROM t WHERE id = ?");
424
+ assert.deepEqual(selectAgain.get(2), { v: "beta" });
425
+
426
+ assert.doesNotThrow(() => adapter.close());
427
+ });
428
+ });
@@ -106,10 +106,10 @@ describe("db-schema-metadata", () => {
106
106
  test("records schema version rows with timestamps", () => {
107
107
  const db = new FakeAdapter();
108
108
 
109
- recordSchemaVersion(db, 25);
109
+ recordSchemaVersion(db, 26);
110
110
 
111
111
  assert.equal(db.runCalls.length, 1);
112
- assert.equal((db.runCalls[0][0] as Record<string, unknown>)[":version"], 25);
112
+ assert.equal((db.runCalls[0][0] as Record<string, unknown>)[":version"], 26);
113
113
  assert.equal(typeof (db.runCalls[0][0] as Record<string, unknown>)[":applied_at"], "string");
114
114
  });
115
115
  });
@@ -11,12 +11,14 @@
11
11
  import test from "node:test";
12
12
  import assert from "node:assert/strict";
13
13
  import { mkdirSync, writeFileSync, rmSync, existsSync } from "node:fs";
14
+ import { execFileSync } from "node:child_process";
14
15
  import { join } from "node:path";
15
16
  import { tmpdir } from "node:os";
16
17
  import {
17
18
  detectProjectState,
18
19
  detectV1Planning,
19
20
  detectProjectSignals,
21
+ classifyProject,
20
22
  scanProjectFiles,
21
23
  } from "../detection.ts";
22
24
 
@@ -37,6 +39,18 @@ function cleanup(dir: string): void {
37
39
  }
38
40
  }
39
41
 
42
+ function git(dir: string, args: string[]): void {
43
+ execFileSync("git", args, { cwd: dir, stdio: "ignore" });
44
+ }
45
+
46
+ function makeGitRepo(prefix: string): string {
47
+ const dir = makeTempDir(prefix);
48
+ git(dir, ["init"]);
49
+ git(dir, ["config", "user.email", "test@example.com"]);
50
+ git(dir, ["config", "user.name", "Test User"]);
51
+ return dir;
52
+ }
53
+
40
54
  // ─── detectProjectState ─────────────────────────────────────────────────────────
41
55
 
42
56
  test("detectProjectState: empty directory returns state=none", (t) => {
@@ -49,6 +63,132 @@ test("detectProjectState: empty directory returns state=none", (t) => {
49
63
  assert.equal(result.v2, undefined);
50
64
  });
51
65
 
66
+ test("classifyProject: no git repo is invalid", (t) => {
67
+ const dir = makeTempDir("classify-invalid");
68
+ t.after(() => cleanup(dir));
69
+
70
+ const classification = classifyProject(dir);
71
+ assert.equal(classification.kind, "invalid-repo");
72
+ });
73
+
74
+ test("classifyProject: empty git repo is greenfield", (t) => {
75
+ const dir = makeGitRepo("classify-greenfield");
76
+ t.after(() => cleanup(dir));
77
+
78
+ const classification = classifyProject(dir);
79
+ assert.equal(classification.kind, "greenfield");
80
+ });
81
+
82
+ test("classifyProject: nested empty git repo does not inherit ancestor markers", (t) => {
83
+ const parent = makeGitRepo("classify-parent-marker");
84
+ t.after(() => cleanup(parent));
85
+
86
+ writeFileSync(join(parent, "package.json"), JSON.stringify({ name: "parent" }), "utf-8");
87
+ git(parent, ["add", "package.json"]);
88
+ git(parent, ["commit", "-m", "add parent marker"]);
89
+ const child = join(parent, "nested");
90
+ mkdirSync(child, { recursive: true });
91
+ git(child, ["init"]);
92
+ git(child, ["config", "user.email", "test@example.com"]);
93
+ git(child, ["config", "user.name", "Test User"]);
94
+
95
+ const classification = classifyProject(child);
96
+ assert.equal(classification.kind, "greenfield");
97
+ });
98
+
99
+ test("classifyProject: tracked static HTML is existing untyped content", (t) => {
100
+ const dir = makeGitRepo("classify-index");
101
+ t.after(() => cleanup(dir));
102
+
103
+ writeFileSync(join(dir, "index.html"), "<main></main>\n", "utf-8");
104
+ git(dir, ["add", "index.html"]);
105
+ git(dir, ["commit", "-m", "add static page"]);
106
+
107
+ const classification = classifyProject(dir);
108
+ assert.equal(classification.kind, "untyped-existing");
109
+ assert.deepEqual(classification.contentFiles, ["index.html"]);
110
+ });
111
+
112
+ test("classifyProject: README-only repo is existing untyped content", (t) => {
113
+ const dir = makeGitRepo("classify-readme");
114
+ t.after(() => cleanup(dir));
115
+
116
+ writeFileSync(join(dir, "README.md"), "# docs\n", "utf-8");
117
+ git(dir, ["add", "README.md"]);
118
+ git(dir, ["commit", "-m", "add docs"]);
119
+
120
+ const classification = classifyProject(dir);
121
+ assert.equal(classification.kind, "untyped-existing");
122
+ });
123
+
124
+ test("classifyProject: src-only content is untyped existing, not typed marker", (t) => {
125
+ const dir = makeGitRepo("classify-src-only");
126
+ t.after(() => cleanup(dir));
127
+
128
+ mkdirSync(join(dir, "src"), { recursive: true });
129
+ writeFileSync(join(dir, "src", "index.txt"), "content\n", "utf-8");
130
+ git(dir, ["add", "src/index.txt"]);
131
+ git(dir, ["commit", "-m", "add source content"]);
132
+
133
+ const classification = classifyProject(dir);
134
+ assert.equal(classification.kind, "untyped-existing");
135
+ assert.deepEqual(classification.contentFiles, ["src/index.txt"]);
136
+ });
137
+
138
+ test("classifyProject: nested untracked files count as project content", (t) => {
139
+ const dir = makeGitRepo("classify-untracked-nested");
140
+ t.after(() => cleanup(dir));
141
+
142
+ mkdirSync(join(dir, "docs"), { recursive: true });
143
+ writeFileSync(join(dir, "docs", "index.html"), "<main></main>\n", "utf-8");
144
+
145
+ const classification = classifyProject(dir);
146
+ assert.equal(classification.kind, "untyped-existing");
147
+ assert.deepEqual(classification.untrackedFiles, ["docs/index.html"]);
148
+ });
149
+
150
+ test("classifyProject: known markers produce typed existing project", (t) => {
151
+ const dir = makeGitRepo("classify-typed");
152
+ t.after(() => cleanup(dir));
153
+
154
+ writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "typed" }), "utf-8");
155
+ git(dir, ["add", "package.json"]);
156
+ git(dir, ["commit", "-m", "add package"]);
157
+
158
+ const classification = classifyProject(dir);
159
+ assert.equal(classification.kind, "typed-existing");
160
+ assert.ok(classification.markers.includes("package.json"));
161
+ });
162
+
163
+ test("classifyProject: ignored build/cache-only files do not count as content", (t) => {
164
+ const dir = makeGitRepo("classify-ignored");
165
+ t.after(() => cleanup(dir));
166
+
167
+ writeFileSync(join(dir, ".gitignore"), "dist/\n.cache/\n", "utf-8");
168
+ git(dir, ["add", ".gitignore"]);
169
+ git(dir, ["commit", "-m", "ignore generated files"]);
170
+ mkdirSync(join(dir, "dist"), { recursive: true });
171
+ writeFileSync(join(dir, "dist", "bundle.js"), "generated\n", "utf-8");
172
+ mkdirSync(join(dir, ".cache"), { recursive: true });
173
+ writeFileSync(join(dir, ".cache", "x"), "cache\n", "utf-8");
174
+
175
+ const classification = classifyProject(dir);
176
+ assert.equal(classification.kind, "greenfield");
177
+ });
178
+
179
+ test("classifyProject: generated framework/cache dirs do not count as content", (t) => {
180
+ const dir = makeGitRepo("classify-generated-dirs");
181
+ t.after(() => cleanup(dir));
182
+
183
+ mkdirSync(join(dir, ".next", "server"), { recursive: true });
184
+ writeFileSync(join(dir, ".next", "server", "page.js"), "generated\n", "utf-8");
185
+ mkdirSync(join(dir, ".venv", "lib"), { recursive: true });
186
+ writeFileSync(join(dir, ".venv", "lib", "site.py"), "generated\n", "utf-8");
187
+
188
+ const classification = classifyProject(dir);
189
+ assert.equal(classification.kind, "greenfield");
190
+ });
191
+
52
192
  test("detectProjectState: directory with .gsd/milestones/M001 returns v2-gsd", (t) => {
53
193
  const dir = makeTempDir("v2-gsd");
54
194
  t.after(() => cleanup(dir));
@@ -0,0 +1,52 @@
1
+ ## TL;DR
2
+
3
+ **What:** Ship milestone M001 - Authentication
4
+ **Why:** Users need to authenticate before accessing protected resources.
5
+ **How:** Added password hash check and session token issuance.
6
+
7
+ ## What
8
+
9
+ ### S01
10
+ Implemented login flow.
11
+
12
+ ## Why
13
+
14
+ Users need to authenticate before accessing protected resources.
15
+
16
+ ## How
17
+
18
+ Added password hash check and session token issuance.
19
+
20
+ ## Linked Issue
21
+
22
+ Closes #123
23
+
24
+ ## Roadmap
25
+
26
+ - [x] **S01: Login**
27
+
28
+ ## Metrics
29
+
30
+ - **Units executed:** 3
31
+
32
+ ## Tests Run
33
+
34
+ - npm test
35
+ - npm run typecheck:extensions
36
+
37
+ ## Change Type
38
+
39
+ - [x] `feat` - New feature or capability
40
+ - [ ] `fix` - Bug fix
41
+ - [ ] `refactor` - Code restructuring
42
+ - [ ] `test` - Adding or updating tests
43
+ - [ ] `docs` - Documentation only
44
+ - [ ] `chore` - Build, CI, or tooling changes
45
+
46
+ ## Rollback And Compatibility
47
+
48
+ - Revert the merge commit.
49
+
50
+ ## AI Assistance Disclosure
51
+
52
+ This PR was prepared with AI assistance.
@@ -0,0 +1,42 @@
1
+ ## TL;DR
2
+
3
+ **What:** Ship milestone M001 - Authentication
4
+ **Why:** Milestone work is complete and ready for review.
5
+ **How:** Generated from GSD evidence and local workflow artifacts.
6
+
7
+ ## What
8
+
9
+ Milestone M001 completed.
10
+
11
+ ## Why
12
+
13
+ Milestone work is complete and ready for review.
14
+
15
+ ## How
16
+
17
+ Generated from GSD evidence and local workflow artifacts.
18
+
19
+ ## Linked Issue
20
+
21
+ Not specified. Add an issue link before marking this PR ready if CONTRIBUTING.md requires one.
22
+
23
+ ## Tests Run
24
+
25
+ - Not specified. Add exact verification commands before requesting review.
26
+
27
+ ## Change Type
28
+
29
+ - [x] `feat` - New feature or capability
30
+ - [ ] `fix` - Bug fix
31
+ - [ ] `refactor` - Code restructuring
32
+ - [ ] `test` - Adding or updating tests
33
+ - [ ] `docs` - Documentation only
34
+ - [ ] `chore` - Build, CI, or tooling changes
35
+
36
+ ## Rollback And Compatibility
37
+
38
+ - No behavior-changing rollback notes recorded.
39
+
40
+ ## AI Assistance Disclosure
41
+
42
+ This PR was prepared with AI assistance.