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,55 @@
1
+ ## TL;DR
2
+
3
+ **What:** Ship workflow lane/writer - lane/writer
4
+ **Why:** Workflow work is complete and ready for review.
5
+ **How:** Generated by GSD GitHub Sync swarm routines from lane evidence.
6
+
7
+ ## What
8
+
9
+ ### Swarm lane
10
+ **Lane:** `lane/writer`
11
+ **Branch:** `lane/single-writer`
12
+ **Owner:** @owner
13
+ **Latest commit:** `abc1234`
14
+
15
+ ### Impact area
16
+ Single-writer UOK metadata.
17
+
18
+ ### Changed contracts
19
+ - [ ] WriterToken
20
+
21
+ ### Transition risks
22
+ - [ ] Writer token lifecycle regression
23
+
24
+ ## Why
25
+
26
+ Workflow work is complete and ready for review.
27
+
28
+ ## How
29
+
30
+ Generated by GSD GitHub Sync swarm routines from lane evidence.
31
+
32
+ ## Linked Issue
33
+
34
+ Closes #123
35
+
36
+ ## Tests Run
37
+
38
+ - npm run typecheck:extensions
39
+
40
+ ## Change Type
41
+
42
+ - [ ] `feat` - New feature or capability
43
+ - [ ] `fix` - Bug fix
44
+ - [x] `refactor` - Code restructuring
45
+ - [ ] `test` - Adding or updating tests
46
+ - [ ] `docs` - Documentation only
47
+ - [ ] `chore` - Build, CI, or tooling changes
48
+
49
+ ## Rollback And Compatibility
50
+
51
+ - Disable writer sequence enrichment
52
+
53
+ ## AI Assistance Disclosure
54
+
55
+ This PR was prepared with AI assistance.
@@ -0,0 +1,60 @@
1
+ ## TL;DR
2
+
3
+ **What:** Ship workflow lane/writer - lane/writer
4
+ **Why:** Workflow work is complete and ready for review.
5
+ **How:** Generated by GSD GitHub Sync swarm routines from lane evidence.
6
+
7
+ ## What
8
+
9
+ ### Swarm lane
10
+ **Lane:** `lane/writer`
11
+ **Branch:** `lane/single-writer`
12
+ **Owner:** @owner
13
+ **Latest commit:** `abc1234`
14
+
15
+ ### Impact area
16
+ Single-writer UOK metadata.
17
+
18
+ ### Changed contracts
19
+ - [ ] WriterToken
20
+
21
+ ### Transition risks
22
+ - [ ] Writer token lifecycle regression
23
+
24
+ ## Blockers
25
+
26
+ - Awaiting state-lane writer-sequence merge
27
+ - Parity report incomplete
28
+
29
+ ## Why
30
+
31
+ Workflow work is complete and ready for review.
32
+
33
+ ## How
34
+
35
+ Generated by GSD GitHub Sync swarm routines from lane evidence.
36
+
37
+ ## Linked Issue
38
+
39
+ Closes #123
40
+
41
+ ## Tests Run
42
+
43
+ - npm run typecheck:extensions
44
+
45
+ ## Change Type
46
+
47
+ - [ ] `feat` - New feature or capability
48
+ - [ ] `fix` - Bug fix
49
+ - [x] `refactor` - Code restructuring
50
+ - [ ] `test` - Adding or updating tests
51
+ - [ ] `docs` - Documentation only
52
+ - [ ] `chore` - Build, CI, or tooling changes
53
+
54
+ ## Rollback And Compatibility
55
+
56
+ - Disable writer sequence enrichment
57
+
58
+ ## AI Assistance Disclosure
59
+
60
+ This PR was prepared with AI assistance.
@@ -233,6 +233,16 @@ describe("getNextPendingStep", () => {
233
233
  const next = getNextPendingStep(graph);
234
234
  assert.equal(next?.id, "b");
235
235
  });
236
+
237
+ it("treats expanded dependencies as satisfied", (t) => {
238
+ const graph = makeGraph([
239
+ makeStep({ id: "iter", status: "expanded" }),
240
+ makeStep({ id: "after", dependsOn: ["iter"] }),
241
+ ]);
242
+
243
+ const next = getNextPendingStep(graph);
244
+ assert.equal(next?.id, "after");
245
+ });
236
246
  });
237
247
 
238
248
  // ─── markStepComplete ────────────────────────────────────────────────────
@@ -30,6 +30,10 @@ import {
30
30
  insertTask,
31
31
  getTask,
32
32
  getSliceTasks,
33
+ deleteMilestone,
34
+ clearEngineHierarchy,
35
+ recordMilestoneCommitAttribution,
36
+ getMilestoneCommitAttributionShas,
33
37
  checkpointDatabase,
34
38
  refreshOpenDatabaseFromDisk,
35
39
  tryCreateMemoriesFts,
@@ -1047,6 +1051,46 @@ describe('gsd-db', () => {
1047
1051
  });
1048
1052
  });
1049
1053
 
1054
+ // ─── milestone_commit_attributions teardown ───────────────────────────────
1055
+
1056
+ describe('milestone commit attribution teardown', () => {
1057
+ test('deleteMilestone removes persisted milestone commit attributions', () => {
1058
+ openDatabase(':memory:');
1059
+ insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
1060
+ recordMilestoneCommitAttribution({
1061
+ commitSha: '0123456789abcdef0123456789abcdef01234567',
1062
+ milestoneId: 'M001',
1063
+ source: 'backfill',
1064
+ confidence: 0.8,
1065
+ files: ['app.js'],
1066
+ createdAt: '2026-05-05T00:00:00.000Z',
1067
+ });
1068
+
1069
+ assert.deepEqual(getMilestoneCommitAttributionShas('M001'), ['0123456789abcdef0123456789abcdef01234567']);
1070
+ deleteMilestone('M001');
1071
+ assert.deepEqual(getMilestoneCommitAttributionShas('M001'), []);
1072
+ closeDatabase();
1073
+ });
1074
+
1075
+ test('clearEngineHierarchy removes persisted milestone commit attributions', () => {
1076
+ openDatabase(':memory:');
1077
+ insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
1078
+ recordMilestoneCommitAttribution({
1079
+ commitSha: 'fedcba9876543210fedcba9876543210fedcba98',
1080
+ milestoneId: 'M001',
1081
+ source: 'backfill',
1082
+ confidence: 0.8,
1083
+ files: ['app.js'],
1084
+ createdAt: '2026-05-05T00:00:00.000Z',
1085
+ });
1086
+
1087
+ assert.deepEqual(getMilestoneCommitAttributionShas('M001'), ['fedcba9876543210fedcba9876543210fedcba98']);
1088
+ clearEngineHierarchy();
1089
+ assert.deepEqual(getMilestoneCommitAttributionShas('M001'), []);
1090
+ closeDatabase();
1091
+ });
1092
+ });
1093
+
1050
1094
  // ─── getDbStatus ───────────────────────────────────────────────────────────
1051
1095
 
1052
1096
  describe('getDbStatus', () => {
@@ -15,7 +15,7 @@ import { tmpdir } from "node:os";
15
15
  import { join } from "node:path";
16
16
  import { randomUUID } from "node:crypto";
17
17
 
18
- import { hasPendingDeepStage } from "../auto-dispatch.ts";
18
+ import { hasPendingDeepStage, shouldRunDeepProjectSetup } from "../auto-dispatch.ts";
19
19
  import type { GSDPreferences } from "../preferences.ts";
20
20
  import { loadEffectiveGSDPreferences } from "../preferences.ts";
21
21
 
@@ -57,6 +57,38 @@ test("hasPendingDeepStage: returns true in deep mode when nothing has been captu
57
57
  }
58
58
  });
59
59
 
60
+ test("shouldRunDeepProjectSetup: complete state wins over pending deep setup", async () => {
61
+ const base = makeBase();
62
+ try {
63
+ assert.equal(hasPendingDeepStage(deepPrefs, base), true);
64
+ assert.equal(
65
+ shouldRunDeepProjectSetup({ phase: "complete" }, deepPrefs, base),
66
+ false,
67
+ "completed projects must not restart deep setup and loop through auto-mode",
68
+ );
69
+ } finally {
70
+ rmSync(base, { recursive: true, force: true });
71
+ }
72
+ });
73
+
74
+ test("shouldRunDeepProjectSetup: only setup phases can trigger pending deep setup", () => {
75
+ const base = makeBase();
76
+ try {
77
+ assert.equal(hasPendingDeepStage(deepPrefs, base), true);
78
+ assert.equal(shouldRunDeepProjectSetup({ phase: "pre-planning" }, deepPrefs, base), true);
79
+ assert.equal(shouldRunDeepProjectSetup({ phase: "needs-discussion" }, deepPrefs, base), true);
80
+ assert.equal(shouldRunDeepProjectSetup({ phase: "planning" }, deepPrefs, base), true);
81
+ assert.equal(shouldRunDeepProjectSetup({ phase: "executing" }, deepPrefs, base), false);
82
+ assert.equal(shouldRunDeepProjectSetup({ phase: "blocked" }, deepPrefs, base), false);
83
+ assert.equal(
84
+ shouldRunDeepProjectSetup({ phase: "pre-planning" }, deepPrefs, base, { hasSurvivorBranch: true }),
85
+ false,
86
+ );
87
+ } finally {
88
+ rmSync(base, { recursive: true, force: true });
89
+ }
90
+ });
91
+
60
92
  test("hasPendingDeepStage: returns true in deep mode when only some gates pass", () => {
61
93
  // workflow-preferences captured but PROJECT.md still missing.
62
94
  const base = makeBase();
@@ -0,0 +1,102 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Golden-fixture equivalence tests pinning PR-body output for buildPrEvidence and formatSwarmLanePRBody.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { readFileSync, writeFileSync } from "node:fs";
7
+ import { fileURLToPath } from "node:url";
8
+ import { dirname, join } from "node:path";
9
+
10
+ import { buildPrEvidence, type PrEvidenceInput } from "../pr-evidence.ts";
11
+ import {
12
+ formatSwarmLanePRBody,
13
+ type SwarmLanePRData,
14
+ } from "../../github-sync/templates.ts";
15
+
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ const FIXTURES_DIR = join(__dirname, "fixtures", "pr-body");
18
+
19
+ const UPDATE = process.env.UPDATE_GOLDENS === "1";
20
+
21
+ function compareGolden(name: string, actual: string): void {
22
+ const path = join(FIXTURES_DIR, name);
23
+ if (UPDATE) {
24
+ writeFileSync(path, actual, "utf8");
25
+ return;
26
+ }
27
+ const expected = readFileSync(path, "utf8");
28
+ assert.equal(actual, expected, `golden mismatch for ${name}`);
29
+ }
30
+
31
+ const SHIP_BASIC: PrEvidenceInput = {
32
+ milestoneId: "M001",
33
+ milestoneTitle: "Authentication",
34
+ changeType: "feat",
35
+ linkedIssue: "Closes #123",
36
+ summaries: ["### S01\nImplemented login flow."],
37
+ roadmapItems: ["- [x] **S01: Login**"],
38
+ metrics: ["**Units executed:** 3"],
39
+ testsRun: ["npm test", "npm run typecheck:extensions"],
40
+ why: "Users need to authenticate before accessing protected resources.",
41
+ how: "Added password hash check and session token issuance.",
42
+ rollbackNotes: ["Revert the merge commit."],
43
+ };
44
+
45
+ const SHIP_EMPTY_OPTIONALS: PrEvidenceInput = {
46
+ milestoneId: "M001",
47
+ milestoneTitle: "Authentication",
48
+ changeType: "feat",
49
+ };
50
+
51
+ const SWARM_WITH_BLOCKERS: SwarmLanePRData = {
52
+ lane: {
53
+ id: "writer",
54
+ branch: "lane/single-writer",
55
+ owner: "@owner",
56
+ latestCommit: "abc1234",
57
+ changedContracts: ["WriterToken"],
58
+ testEvidence: ["npm run typecheck:extensions"],
59
+ blockers: ["Awaiting state-lane writer-sequence merge", "Parity report incomplete"],
60
+ },
61
+ impactArea: "Single-writer UOK metadata.",
62
+ transitionRisks: ["Writer token lifecycle regression"],
63
+ rollbackPlan: ["Disable writer sequence enrichment"],
64
+ linkedIssue: 123,
65
+ };
66
+
67
+ const SWARM_NO_BLOCKERS: SwarmLanePRData = {
68
+ lane: {
69
+ id: "writer",
70
+ branch: "lane/single-writer",
71
+ owner: "@owner",
72
+ latestCommit: "abc1234",
73
+ changedContracts: ["WriterToken"],
74
+ testEvidence: ["npm run typecheck:extensions"],
75
+ },
76
+ impactArea: "Single-writer UOK metadata.",
77
+ transitionRisks: ["Writer token lifecycle regression"],
78
+ rollbackPlan: ["Disable writer sequence enrichment"],
79
+ linkedIssue: 123,
80
+ };
81
+
82
+ test("pr-evidence golden: commands-ship basic", () => {
83
+ compareGolden("commands-ship-basic.md", buildPrEvidence(SHIP_BASIC).body);
84
+ });
85
+
86
+ test("pr-evidence golden: commands-ship empty optionals", () => {
87
+ compareGolden("commands-ship-empty-optionals.md", buildPrEvidence(SHIP_EMPTY_OPTIONALS).body);
88
+ });
89
+
90
+ test("pr-evidence golden: swarm-lane with blockers", () => {
91
+ const body = formatSwarmLanePRBody(SWARM_WITH_BLOCKERS);
92
+ compareGolden("swarm-lane-with-blockers.md", body);
93
+ // Cross-check: top-level ## Blockers heading must appear (regression guard
94
+ // for the silent-drop fixed in this PR).
95
+ assert.ok(body.includes("\n## Blockers\n"), "swarm-lane body must emit a top-level ## Blockers heading");
96
+ });
97
+
98
+ test("pr-evidence golden: swarm-lane no blockers (no Blockers heading)", () => {
99
+ const body = formatSwarmLanePRBody(SWARM_NO_BLOCKERS);
100
+ compareGolden("swarm-lane-no-blockers.md", body);
101
+ assert.ok(!body.includes("## Blockers"), "swarm-lane body without blockers must not emit ## Blockers heading");
102
+ });
@@ -0,0 +1,165 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Hardening tests for buildPrEvidence — HTML-comment stripping, fake commit-trailer removal, and per-item length capping.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+
7
+ import { buildPrEvidence, type PrEvidenceInput } from "../pr-evidence.ts";
8
+
9
+ test("pr-evidence hardening: strips HTML comments from summaries", () => {
10
+ const evidence = buildPrEvidence({
11
+ milestoneId: "M001",
12
+ summaries: ["visible<!-- hidden secret -->tail"],
13
+ });
14
+ assert.ok(!evidence.body.includes("<!--"), "raw <!-- must not appear");
15
+ assert.ok(!evidence.body.includes("hidden secret"), "comment contents must be stripped");
16
+ assert.ok(evidence.body.includes("visibletail"), "non-comment text must remain");
17
+ });
18
+
19
+ test("pr-evidence hardening: removes Co-Authored-By trailer from why", () => {
20
+ const evidence = buildPrEvidence({
21
+ milestoneId: "M001",
22
+ why: "Real reason here.\nCo-Authored-By: Evil <e@evil.com>\nMore reason.",
23
+ });
24
+ assert.ok(!evidence.body.includes("Evil <e@evil.com>"));
25
+ assert.ok(!/Co-Authored-By:/i.test(evidence.body));
26
+ assert.ok(evidence.body.includes("Real reason here."));
27
+ assert.ok(evidence.body.includes("More reason."));
28
+ });
29
+
30
+ test("pr-evidence hardening: removes Signed-off-by trailer from how", () => {
31
+ const evidence = buildPrEvidence({
32
+ milestoneId: "M001",
33
+ how: "Step one.\nSigned-off-by: Forged <f@x.com>\nStep two.",
34
+ });
35
+ assert.ok(!evidence.body.includes("Forged <f@x.com>"));
36
+ assert.ok(!/Signed-off-by:/i.test(evidence.body));
37
+ assert.ok(evidence.body.includes("Step one."));
38
+ assert.ok(evidence.body.includes("Step two."));
39
+ });
40
+
41
+ test("pr-evidence hardening: trailer-name match is case-insensitive", () => {
42
+ const evidence = buildPrEvidence({
43
+ milestoneId: "M001",
44
+ why: "ok\nco-authored-by: lower <l@l.com>\nSIGNED-OFF-BY: upper <u@u.com>\nend",
45
+ });
46
+ assert.ok(!evidence.body.includes("lower <l@l.com>"));
47
+ assert.ok(!evidence.body.includes("upper <u@u.com>"));
48
+ assert.ok(evidence.body.includes("ok"));
49
+ assert.ok(evidence.body.includes("end"));
50
+ });
51
+
52
+ test("pr-evidence hardening: caps oversize summaries item with truncation suffix", () => {
53
+ const big = "A".repeat(5 * 1024); // 5 KB
54
+ const evidence = buildPrEvidence({
55
+ milestoneId: "M001",
56
+ summaries: [big],
57
+ });
58
+ // Find the truncated A-block in the body and assert it is bounded.
59
+ const lines = evidence.body.split("\n");
60
+ const longLine = lines.find((l) => l.startsWith("AAAA"));
61
+ assert.ok(longLine, "expected truncated A-line in body");
62
+ assert.ok(longLine!.endsWith(" … [truncated]"), "must end with truncation suffix");
63
+ assert.ok(
64
+ Buffer.byteLength(longLine!, "utf8") <= 2048,
65
+ `truncated item must be within 2 KB cap, got ${Buffer.byteLength(longLine!, "utf8")}`,
66
+ );
67
+ });
68
+
69
+ test("pr-evidence hardening: HTML comment split across summary items is preserved literally", () => {
70
+ // Documented behavior: each item is sanitized independently. A comment
71
+ // that begins in one item and closes in the next is NOT joined, so the
72
+ // open/close markers remain as literal text. This is intentional — joining
73
+ // items before sanitizing would let an attacker straddle items to inject
74
+ // an aligned comment that hides the second item from rendered view.
75
+ const evidence = buildPrEvidence({
76
+ milestoneId: "M001",
77
+ summaries: ["first item ends <!--", "--> second item begins"],
78
+ });
79
+ // The literal markers survive because each item was sanitized alone.
80
+ assert.ok(evidence.body.includes("<!--"), "open marker preserved as literal");
81
+ assert.ok(evidence.body.includes("-->"), "close marker preserved as literal");
82
+ assert.ok(evidence.body.includes("first item ends"));
83
+ assert.ok(evidence.body.includes("second item begins"));
84
+ });
85
+
86
+ test("pr-evidence hardening: clean input is byte-identical to pre-hardening output", () => {
87
+ // This test is the contract that protects the golden fixtures: the
88
+ // sanitizer must be a true no-op for well-formed input. If this fails,
89
+ // there is a bug in the sanitizer (not in the goldens).
90
+ const cleanInput: PrEvidenceInput = {
91
+ milestoneId: "M001",
92
+ milestoneTitle: "Authentication",
93
+ changeType: "feat",
94
+ linkedIssue: "Closes #123",
95
+ summaries: ["### S01\nImplemented login flow."],
96
+ blockers: ["Awaiting design review"],
97
+ roadmapItems: ["- [x] **S01: Login**"],
98
+ metrics: ["**Units executed:** 3"],
99
+ testsRun: ["npm test", "npm run typecheck:extensions"],
100
+ why: "Users need to authenticate before accessing protected resources.",
101
+ how: "Added password hash check and session token issuance.",
102
+ rollbackNotes: ["Revert the merge commit."],
103
+ };
104
+
105
+ const expected = [
106
+ "## TL;DR",
107
+ "",
108
+ "**What:** Ship milestone M001 - Authentication",
109
+ "**Why:** Users need to authenticate before accessing protected resources.",
110
+ "**How:** Added password hash check and session token issuance.",
111
+ "",
112
+ "## What",
113
+ "",
114
+ "### S01\nImplemented login flow.",
115
+ "",
116
+ "## Blockers",
117
+ "",
118
+ "- Awaiting design review",
119
+ "",
120
+ "## Why",
121
+ "",
122
+ "Users need to authenticate before accessing protected resources.",
123
+ "",
124
+ "## How",
125
+ "",
126
+ "Added password hash check and session token issuance.",
127
+ "",
128
+ "## Linked Issue",
129
+ "",
130
+ "Closes #123",
131
+ "",
132
+ "## Roadmap",
133
+ "",
134
+ "- [x] **S01: Login**",
135
+ "",
136
+ "## Metrics",
137
+ "",
138
+ "- **Units executed:** 3",
139
+ "",
140
+ "## Tests Run",
141
+ "",
142
+ "- npm test",
143
+ "- npm run typecheck:extensions",
144
+ "",
145
+ "## Change Type",
146
+ "",
147
+ "- [x] `feat` - New feature or capability",
148
+ "- [ ] `fix` - Bug fix",
149
+ "- [ ] `refactor` - Code restructuring",
150
+ "- [ ] `test` - Adding or updating tests",
151
+ "- [ ] `docs` - Documentation only",
152
+ "- [ ] `chore` - Build, CI, or tooling changes",
153
+ "",
154
+ "## Rollback And Compatibility",
155
+ "",
156
+ "- Revert the merge commit.",
157
+ "",
158
+ "## AI Assistance Disclosure",
159
+ "",
160
+ "This PR was prepared with AI assistance.",
161
+ ].join("\n");
162
+
163
+ const actual = buildPrEvidence(cleanInput).body;
164
+ assert.equal(actual, expected, "clean input must produce byte-identical output (sanitizer is no-op)");
165
+ });