gsd-pi 2.68.0 → 2.68.1-dev.abc8f2b

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 (258) hide show
  1. package/README.md +66 -70
  2. package/dist/resources/extensions/gsd/auto-model-selection.js +27 -1
  3. package/dist/resources/extensions/gsd/auto.js +8 -2
  4. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
  5. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -5
  6. package/dist/resources/extensions/gsd/guided-flow.js +25 -70
  7. package/dist/resources/extensions/gsd/model-router.js +85 -2
  8. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
  9. package/dist/resources/extensions/gsd/templates/context.md +34 -2
  10. package/dist/web/standalone/.next/BUILD_ID +1 -1
  11. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  12. package/dist/web/standalone/.next/build-manifest.json +3 -3
  13. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  14. package/dist/web/standalone/.next/required-server-files.json +3 -3
  15. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  16. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  26. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  28. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  29. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  30. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  32. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  36. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  37. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  38. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  39. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  40. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  42. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  54. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  74. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  84. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  90. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  106. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  110. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/index.html +1 -1
  120. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  121. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  122. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  123. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  125. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/page.js +2 -2
  127. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  129. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  130. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  131. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/middleware.js +2 -2
  133. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  135. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  136. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  137. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  138. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  139. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  140. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
  141. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  142. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  143. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  144. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  145. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  146. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  147. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  148. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  149. package/dist/web/standalone/server.js +1 -1
  150. package/package.json +1 -1
  151. package/packages/pi-ai/dist/index.d.ts +3 -0
  152. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  153. package/packages/pi-ai/dist/index.js +2 -0
  154. package/packages/pi-ai/dist/index.js.map +1 -1
  155. package/packages/pi-ai/dist/providers/amazon-bedrock.js +2 -2
  156. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  157. package/packages/pi-ai/dist/providers/anthropic-shared.js +2 -2
  158. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  159. package/packages/pi-ai/dist/providers/google-shared.js +2 -2
  160. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  161. package/packages/pi-ai/dist/providers/mistral.js +2 -2
  162. package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
  163. package/packages/pi-ai/dist/providers/openai-completions.js +2 -2
  164. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  165. package/packages/pi-ai/dist/providers/openai-responses-shared.js +2 -2
  166. package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  167. package/packages/pi-ai/dist/providers/provider-capabilities.d.ts +59 -0
  168. package/packages/pi-ai/dist/providers/provider-capabilities.d.ts.map +1 -0
  169. package/packages/pi-ai/dist/providers/provider-capabilities.js +173 -0
  170. package/packages/pi-ai/dist/providers/provider-capabilities.js.map +1 -0
  171. package/packages/pi-ai/dist/providers/provider-capabilities.test.d.ts +2 -0
  172. package/packages/pi-ai/dist/providers/provider-capabilities.test.d.ts.map +1 -0
  173. package/packages/pi-ai/dist/providers/provider-capabilities.test.js +132 -0
  174. package/packages/pi-ai/dist/providers/provider-capabilities.test.js.map +1 -0
  175. package/packages/pi-ai/dist/providers/transform-messages-report.test.d.ts +2 -0
  176. package/packages/pi-ai/dist/providers/transform-messages-report.test.d.ts.map +1 -0
  177. package/packages/pi-ai/dist/providers/transform-messages-report.test.js +172 -0
  178. package/packages/pi-ai/dist/providers/transform-messages-report.test.js.map +1 -0
  179. package/packages/pi-ai/dist/providers/transform-messages.d.ts +34 -1
  180. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  181. package/packages/pi-ai/dist/providers/transform-messages.js +73 -2
  182. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  183. package/packages/pi-ai/src/index.ts +3 -0
  184. package/packages/pi-ai/src/providers/amazon-bedrock.ts +2 -2
  185. package/packages/pi-ai/src/providers/anthropic-shared.ts +2 -2
  186. package/packages/pi-ai/src/providers/google-shared.ts +2 -2
  187. package/packages/pi-ai/src/providers/mistral.ts +2 -2
  188. package/packages/pi-ai/src/providers/openai-completions.ts +2 -2
  189. package/packages/pi-ai/src/providers/openai-responses-shared.ts +2 -2
  190. package/packages/pi-ai/src/providers/provider-capabilities.test.ts +174 -0
  191. package/packages/pi-ai/src/providers/provider-capabilities.ts +215 -0
  192. package/packages/pi-ai/src/providers/transform-messages-report.test.ts +189 -0
  193. package/packages/pi-ai/src/providers/transform-messages.ts +94 -1
  194. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  195. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/extensions/loader.js +10 -1
  199. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -1
  201. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/extensions/runner.js +15 -0
  203. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +41 -0
  205. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  207. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +1 -0
  208. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  210. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.d.ts +27 -0
  212. package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.d.ts.map +1 -0
  213. package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.js +69 -0
  214. package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.js.map +1 -0
  215. package/packages/pi-coding-agent/dist/index.d.ts +2 -2
  216. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  217. package/packages/pi-coding-agent/dist/index.js +3 -1
  218. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  219. package/packages/pi-coding-agent/package.json +1 -1
  220. package/packages/pi-coding-agent/src/core/extensions/index.ts +4 -0
  221. package/packages/pi-coding-agent/src/core/extensions/loader.ts +11 -1
  222. package/packages/pi-coding-agent/src/core/extensions/runner.ts +18 -0
  223. package/packages/pi-coding-agent/src/core/extensions/types.ts +45 -0
  224. package/packages/pi-coding-agent/src/core/tools/index.ts +7 -0
  225. package/packages/pi-coding-agent/src/core/tools/tool-compatibility-registry.ts +83 -0
  226. package/packages/pi-coding-agent/src/index.ts +9 -0
  227. package/pkg/package.json +1 -1
  228. package/src/resources/extensions/gsd/auto-model-selection.ts +36 -4
  229. package/src/resources/extensions/gsd/auto.ts +8 -2
  230. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
  231. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -5
  232. package/src/resources/extensions/gsd/guided-flow.ts +22 -84
  233. package/src/resources/extensions/gsd/model-router.ts +117 -10
  234. package/src/resources/extensions/gsd/preferences-types.ts +3 -1
  235. package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
  236. package/src/resources/extensions/gsd/templates/context.md +34 -2
  237. package/src/resources/extensions/gsd/tests/capability-router.test.ts +31 -7
  238. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -1
  239. package/src/resources/extensions/gsd/tests/model-router.test.ts +2 -2
  240. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +37 -0
  241. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +199 -0
  242. package/src/resources/extensions/gsd/tests/write-gate.test.ts +13 -16
  243. package/dist/resources/extensions/gsd/prompt-validation.js +0 -67
  244. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +0 -424
  245. package/dist/resources/extensions/gsd/templates/context-enhanced.md +0 -138
  246. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
  247. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  248. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  249. package/src/resources/extensions/gsd/prompt-validation.ts +0 -88
  250. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +0 -424
  251. package/src/resources/extensions/gsd/templates/context-enhanced.md +0 -138
  252. package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +0 -223
  253. package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +0 -53
  254. package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +0 -525
  255. package/src/resources/extensions/gsd/tests/preparation.test.ts +0 -1211
  256. package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +0 -669
  257. /package/dist/web/standalone/.next/static/{ka3ShQTakcliYL-EXRRb6 → 3HMOXcBoys84RYd2F8a79}/_buildManifest.js +0 -0
  258. /package/dist/web/standalone/.next/static/{ka3ShQTakcliYL-EXRRb6 → 3HMOXcBoys84RYd2F8a79}/_ssgManifest.js +0 -0
@@ -1,669 +0,0 @@
1
- /**
2
- * Prompt Builder Tests — Comprehensive tests for S02 components.
3
- *
4
- * Tests cover:
5
- * 1. Template validation (context-enhanced.md, discuss-prepared.md)
6
- * 2. Prompt loading and variable substitution
7
- * 3. Enhanced context validation (R109)
8
- * 4. Integration tests for format functions and prompt injection
9
- */
10
-
11
- import test, { describe } from "node:test";
12
- import assert from "node:assert/strict";
13
- import { readFileSync, existsSync } from "node:fs";
14
- import { join } from "node:path";
15
-
16
- // ─── Template Paths ─────────────────────────────────────────────────────────────
17
-
18
- const templatesDir = join(process.cwd(), "src/resources/extensions/gsd/templates");
19
- const promptsDir = join(process.cwd(), "src/resources/extensions/gsd/prompts");
20
-
21
- const contextEnhancedPath = join(templatesDir, "context-enhanced.md");
22
- const contextPath = join(templatesDir, "context.md");
23
- const discussPreparedPath = join(promptsDir, "discuss-prepared.md");
24
-
25
- // ─── Template Tests ─────────────────────────────────────────────────────────────
26
-
27
- describe("Template: context-enhanced.md", () => {
28
- test("file exists", () => {
29
- assert.ok(existsSync(contextEnhancedPath), "context-enhanced.md should exist");
30
- });
31
-
32
- test("contains all original context.md sections", () => {
33
- const contextEnhanced = readFileSync(contextEnhancedPath, "utf-8");
34
- const originalContext = readFileSync(contextPath, "utf-8");
35
-
36
- // Extract section headers from original context.md
37
- const originalSections = originalContext.match(/^## .+$/gm) ?? [];
38
-
39
- // Each original section should be present in context-enhanced.md
40
- for (const section of originalSections) {
41
- assert.ok(
42
- contextEnhanced.includes(section),
43
- `context-enhanced.md should contain original section: ${section}`,
44
- );
45
- }
46
- });
47
-
48
- test("contains new structured sections for prepared discussions", () => {
49
- const contextEnhanced = readFileSync(contextEnhancedPath, "utf-8");
50
-
51
- // New sections required by R108
52
- const newSections = [
53
- "## Codebase Brief",
54
- "## Architectural Decisions",
55
- "## Interface Contracts",
56
- "## Error Handling Strategy",
57
- "## Testing Requirements",
58
- "## Acceptance Criteria",
59
- "## Ecosystem Notes",
60
- ];
61
-
62
- for (const section of newSections) {
63
- assert.ok(
64
- contextEnhanced.includes(section),
65
- `context-enhanced.md should contain new section: ${section}`,
66
- );
67
- }
68
- });
69
-
70
- test("Codebase Brief has sub-sections", () => {
71
- const contextEnhanced = readFileSync(contextEnhancedPath, "utf-8");
72
-
73
- assert.ok(
74
- contextEnhanced.includes("### Technology Stack"),
75
- "Codebase Brief should have Technology Stack sub-section",
76
- );
77
- assert.ok(
78
- contextEnhanced.includes("### Key Modules"),
79
- "Codebase Brief should have Key Modules sub-section",
80
- );
81
- assert.ok(
82
- contextEnhanced.includes("### Patterns in Use"),
83
- "Codebase Brief should have Patterns in Use sub-section",
84
- );
85
- });
86
-
87
- test("Architectural Decisions has structured format guidance", () => {
88
- const contextEnhanced = readFileSync(contextEnhancedPath, "utf-8");
89
-
90
- // Check for decision structure markers
91
- assert.ok(
92
- contextEnhanced.includes("**Decision:**"),
93
- "Architectural Decisions should have Decision marker",
94
- );
95
- assert.ok(
96
- contextEnhanced.includes("**Rationale:**"),
97
- "Architectural Decisions should have Rationale marker",
98
- );
99
- assert.ok(
100
- contextEnhanced.includes("**Evidence:**"),
101
- "Architectural Decisions should have Evidence marker",
102
- );
103
- assert.ok(
104
- contextEnhanced.includes("**Alternatives Considered:**"),
105
- "Architectural Decisions should have Alternatives Considered marker",
106
- );
107
- });
108
- });
109
-
110
- describe("Template: discuss-prepared.md", () => {
111
- test("file exists", () => {
112
- assert.ok(existsSync(discussPreparedPath), "discuss-prepared.md should exist");
113
- });
114
-
115
- test("contains all three brief placeholders", () => {
116
- const discussPrepared = readFileSync(discussPreparedPath, "utf-8");
117
-
118
- assert.ok(
119
- discussPrepared.includes("{{codebaseBrief}}"),
120
- "discuss-prepared.md should contain {{codebaseBrief}} placeholder",
121
- );
122
- assert.ok(
123
- discussPrepared.includes("{{priorContextBrief}}"),
124
- "discuss-prepared.md should contain {{priorContextBrief}} placeholder",
125
- );
126
- assert.ok(
127
- discussPrepared.includes("{{ecosystemBrief}}"),
128
- "discuss-prepared.md should contain {{ecosystemBrief}} placeholder",
129
- );
130
- });
131
-
132
- test("contains 4-layer protocol markers", () => {
133
- const discussPrepared = readFileSync(discussPreparedPath, "utf-8");
134
-
135
- // Check for all four layer headings
136
- assert.ok(
137
- discussPrepared.includes("## Layer 1 — Scope"),
138
- "discuss-prepared.md should contain Layer 1 (Scope)",
139
- );
140
- assert.ok(
141
- discussPrepared.includes("## Layer 2 — Architecture"),
142
- "discuss-prepared.md should contain Layer 2 (Architecture)",
143
- );
144
- assert.ok(
145
- discussPrepared.includes("## Layer 3 — Error States"),
146
- "discuss-prepared.md should contain Layer 3 (Error States)",
147
- );
148
- assert.ok(
149
- discussPrepared.includes("## Layer 4 — Quality Bar"),
150
- "discuss-prepared.md should contain Layer 4 (Quality Bar)",
151
- );
152
- });
153
-
154
- test("contains gate question IDs for all layers", () => {
155
- const discussPrepared = readFileSync(discussPreparedPath, "utf-8");
156
-
157
- assert.ok(
158
- discussPrepared.includes("layer1_scope_gate"),
159
- "discuss-prepared.md should contain layer1_scope_gate question ID",
160
- );
161
- assert.ok(
162
- discussPrepared.includes("layer2_architecture_gate"),
163
- "discuss-prepared.md should contain layer2_architecture_gate question ID",
164
- );
165
- assert.ok(
166
- discussPrepared.includes("layer3_error_gate"),
167
- "discuss-prepared.md should contain layer3_error_gate question ID",
168
- );
169
- assert.ok(
170
- discussPrepared.includes("layer4_quality_gate"),
171
- "discuss-prepared.md should contain layer4_quality_gate question ID",
172
- );
173
- });
174
-
175
- test("contains context-enhanced template guidance", () => {
176
- const discussPrepared = readFileSync(discussPreparedPath, "utf-8");
177
-
178
- assert.ok(
179
- discussPrepared.includes("context-enhanced"),
180
- "discuss-prepared.md should reference context-enhanced template",
181
- );
182
- });
183
- });
184
-
185
- // ─── Prompt Loading Tests ───────────────────────────────────────────────────────
186
-
187
- describe("Prompt Loading", () => {
188
- // Dynamic import to work with the module's warm cache
189
- test("loadPrompt substitutes all variables correctly", async () => {
190
- const { loadPrompt } = await import("../prompt-loader.ts");
191
-
192
- const result = loadPrompt("discuss-prepared", {
193
- preamble: "Test preamble",
194
- codebaseBrief: "Test codebase brief content",
195
- priorContextBrief: "Test prior context brief content",
196
- ecosystemBrief: "Test ecosystem brief content",
197
- milestoneId: "M001",
198
- contextPath: ".gsd/milestones/M001/M001-CONTEXT.md",
199
- roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
200
- inlinedTemplates: "Test templates",
201
- commitInstruction: "Test commit instruction",
202
- multiMilestoneCommitInstruction: "Test multi-milestone commit",
203
- });
204
-
205
- assert.ok(result.includes("Test codebase brief content"), "codebaseBrief should be substituted");
206
- assert.ok(result.includes("Test prior context brief content"), "priorContextBrief should be substituted");
207
- assert.ok(result.includes("Test ecosystem brief content"), "ecosystemBrief should be substituted");
208
- assert.ok(!result.includes("{{codebaseBrief}}"), "placeholder should not remain");
209
- });
210
-
211
- test("loadPrompt throws GSDError for missing variables", async () => {
212
- const { loadPrompt } = await import("../prompt-loader.ts");
213
- const { GSDError, GSD_PARSE_ERROR } = await import("../errors.ts");
214
-
215
- assert.throws(
216
- () => loadPrompt("discuss-prepared", {}), // Missing required variables
217
- (err: unknown) => {
218
- assert.ok(err instanceof GSDError, "should throw GSDError");
219
- assert.equal((err as InstanceType<typeof GSDError>).code, GSD_PARSE_ERROR, "should have GSD_PARSE_ERROR code");
220
- return true;
221
- },
222
- );
223
- });
224
-
225
- test("brief content with {{...}} patterns does not cause false variable errors", async () => {
226
- const { loadPrompt } = await import("../prompt-loader.ts");
227
-
228
- // Content that contains template-like patterns but should not be treated as variables
229
- const briefWithPatterns = `
230
- ## Tech Stack
231
- - Framework: Uses \`{{slot}}\` placeholder syntax in templates
232
- - Pattern: The codebase has \`{{variableName}}\` markers
233
- `;
234
-
235
- // This should NOT throw, because {{slot}} and {{variableName}} are inside
236
- // the brief value, not undeclared placeholders in the template itself.
237
- const result = loadPrompt("discuss-prepared", {
238
- preamble: "Test",
239
- codebaseBrief: briefWithPatterns,
240
- priorContextBrief: "Test brief",
241
- ecosystemBrief: "Test brief",
242
- milestoneId: "M001",
243
- contextPath: ".gsd/milestones/M001/M001-CONTEXT.md",
244
- roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
245
- inlinedTemplates: "Test templates",
246
- commitInstruction: "Test commit instruction",
247
- multiMilestoneCommitInstruction: "Test multi-milestone commit",
248
- });
249
-
250
- assert.ok(result.includes("{{slot}}"), "template-like patterns in content should be preserved");
251
- assert.ok(result.includes("{{variableName}}"), "template-like patterns in content should be preserved");
252
- });
253
- });
254
-
255
- // ─── Validation Tests ───────────────────────────────────────────────────────────
256
-
257
- describe("Enhanced Context Validation", () => {
258
- test("valid enhanced context passes validation", async () => {
259
- const { validateEnhancedContext } = await import("../prompt-validation.ts");
260
-
261
- const validContent = `
262
- # M001: Test Milestone
263
-
264
- ## Why This Milestone
265
-
266
- This is why we need this milestone.
267
-
268
- ## Architectural Decisions
269
-
270
- ### Decision 1
271
-
272
- **Decision:** Use TypeScript
273
- **Rationale:** Type safety
274
-
275
- ## Acceptance Criteria
276
-
277
- - Criterion 1
278
- - Criterion 2
279
- `;
280
-
281
- const result = validateEnhancedContext(validContent);
282
- assert.equal(result.valid, true, "valid content should pass validation");
283
- assert.equal(result.missing.length, 0, "no missing sections");
284
- });
285
-
286
- test("missing scope section fails", async () => {
287
- const { validateEnhancedContext } = await import("../prompt-validation.ts");
288
-
289
- const contentMissingScope = `
290
- # M001: Test Milestone
291
-
292
- ## Architectural Decisions
293
-
294
- ### Decision 1
295
-
296
- **Decision:** Use TypeScript
297
-
298
- ## Acceptance Criteria
299
-
300
- - Criterion 1
301
- `;
302
-
303
- const result = validateEnhancedContext(contentMissingScope);
304
- assert.equal(result.valid, false, "should fail validation");
305
- assert.ok(
306
- result.missing.some((m) => m.includes("Scope") || m.includes("Why This Milestone")),
307
- "should report missing scope section",
308
- );
309
- });
310
-
311
- test("missing architectural decisions section fails", async () => {
312
- const { validateEnhancedContext } = await import("../prompt-validation.ts");
313
-
314
- const contentMissingDecisions = `
315
- # M001: Test Milestone
316
-
317
- ## Why This Milestone
318
-
319
- This is why we need this milestone.
320
-
321
- ## Acceptance Criteria
322
-
323
- - Criterion 1
324
- `;
325
-
326
- const result = validateEnhancedContext(contentMissingDecisions);
327
- assert.equal(result.valid, false, "should fail validation");
328
- assert.ok(
329
- result.missing.includes("Architectural Decisions"),
330
- "should report missing architectural decisions section",
331
- );
332
- });
333
-
334
- test("missing acceptance criteria section fails", async () => {
335
- const { validateEnhancedContext } = await import("../prompt-validation.ts");
336
-
337
- const contentMissingCriteria = `
338
- # M001: Test Milestone
339
-
340
- ## Why This Milestone
341
-
342
- This is why we need this milestone.
343
-
344
- ## Architectural Decisions
345
-
346
- ### Decision 1
347
-
348
- **Decision:** Use TypeScript
349
- `;
350
-
351
- const result = validateEnhancedContext(contentMissingCriteria);
352
- assert.equal(result.valid, false, "should fail validation");
353
- assert.ok(
354
- result.missing.includes("Acceptance Criteria"),
355
- "should report missing acceptance criteria section",
356
- );
357
- });
358
-
359
- test("empty architectural decisions section (no entries) fails", async () => {
360
- const { validateEnhancedContext } = await import("../prompt-validation.ts");
361
-
362
- const contentEmptyDecisions = `
363
- # M001: Test Milestone
364
-
365
- ## Why This Milestone
366
-
367
- This is why we need this milestone.
368
-
369
- ## Architectural Decisions
370
-
371
- No decisions yet.
372
-
373
- ## Acceptance Criteria
374
-
375
- - Criterion 1
376
- `;
377
-
378
- const result = validateEnhancedContext(contentEmptyDecisions);
379
- assert.equal(result.valid, false, "should fail validation");
380
- assert.ok(
381
- result.missing.some((m) => m.includes("decision entry")),
382
- "should report missing decision entry",
383
- );
384
- });
385
-
386
- test("alternative scope headers are accepted", async () => {
387
- const { validateEnhancedContext } = await import("../prompt-validation.ts");
388
-
389
- // Test with ## Scope
390
- const withScope = `
391
- ## Scope
392
-
393
- ### In Scope
394
- - Item 1
395
-
396
- ## Architectural Decisions
397
-
398
- ### Decision 1
399
- **Decision:** Test
400
-
401
- ## Acceptance Criteria
402
-
403
- - Criterion 1
404
- `;
405
- assert.equal(validateEnhancedContext(withScope).valid, true, "## Scope should be accepted");
406
-
407
- // Test with ## Milestone Scope
408
- const withMilestoneScope = `
409
- ## Milestone Scope
410
-
411
- This is the scope.
412
-
413
- ## Architectural Decisions
414
-
415
- ### Decision 1
416
- **Decision:** Test
417
-
418
- ## Acceptance Criteria
419
-
420
- - Criterion 1
421
- `;
422
- assert.equal(
423
- validateEnhancedContext(withMilestoneScope).valid,
424
- true,
425
- "## Milestone Scope should be accepted",
426
- );
427
- });
428
-
429
- test("alternative acceptance criteria headers are accepted", async () => {
430
- const { validateEnhancedContext } = await import("../prompt-validation.ts");
431
-
432
- const withFinalIntegrated = `
433
- ## Why This Milestone
434
-
435
- Test
436
-
437
- ## Architectural Decisions
438
-
439
- ### Decision 1
440
- **Decision:** Test
441
-
442
- ## Final Integrated Acceptance
443
-
444
- - Criterion 1
445
- `;
446
- assert.equal(
447
- validateEnhancedContext(withFinalIntegrated).valid,
448
- true,
449
- "## Final Integrated Acceptance should be accepted",
450
- );
451
- });
452
-
453
- test("inline decision format is accepted", async () => {
454
- const { validateEnhancedContext } = await import("../prompt-validation.ts");
455
-
456
- const withInlineDecision = `
457
- ## Why This Milestone
458
-
459
- Test
460
-
461
- ## Architectural Decisions
462
-
463
- **Decision:** Use React for the frontend
464
-
465
- ## Acceptance Criteria
466
-
467
- - Criterion 1
468
- `;
469
- assert.equal(
470
- validateEnhancedContext(withInlineDecision).valid,
471
- true,
472
- "**Decision marker format should be accepted",
473
- );
474
- });
475
- });
476
-
477
- // ─── Integration Tests ──────────────────────────────────────────────────────────
478
-
479
- describe("Integration: Format Functions", () => {
480
- test("formatCodebaseBrief produces non-empty output", async () => {
481
- const { formatCodebaseBrief } = await import("../preparation.ts");
482
-
483
- const brief = {
484
- techStack: {
485
- primaryLanguage: "TypeScript",
486
- detectedFiles: ["package.json", "tsconfig.json"],
487
- packageManager: "npm",
488
- isMonorepo: false,
489
- hasTests: true,
490
- hasCI: true,
491
- },
492
- moduleStructure: {
493
- topLevelDirs: ["src", "tests"],
494
- srcSubdirs: ["components", "utils"],
495
- totalFilesSampled: 5,
496
- },
497
- patterns: {
498
- asyncStyle: "async/await" as const,
499
- errorHandling: "try/catch" as const,
500
- namingConvention: "camelCase" as const,
501
- evidence: {
502
- asyncStyle: ["src/foo.ts: async/await (5 occurrences)"],
503
- errorHandling: ["src/bar.ts: try/catch (3 occurrences)"],
504
- namingConvention: ["camelCase: 50 occurrences"],
505
- },
506
- fileCounts: {
507
- asyncAwait: 3,
508
- promises: 0,
509
- callbacks: 0,
510
- tryCatch: 2,
511
- errorCallbacks: 0,
512
- resultTypes: 0,
513
- },
514
- },
515
- sampledFiles: ["src/index.ts", "src/utils.ts"],
516
- };
517
-
518
- const formatted = formatCodebaseBrief(brief);
519
- assert.ok(formatted.length > 0, "formatted brief should not be empty");
520
- assert.ok(formatted.includes("TypeScript"), "should include primary language");
521
- assert.ok(formatted.includes("async/await"), "should include async style");
522
- });
523
-
524
- test("formatPriorContextBrief produces non-empty output", async () => {
525
- const { formatPriorContextBrief } = await import("../preparation.ts");
526
-
527
- const brief = {
528
- decisions: {
529
- byScope: new Map([
530
- ["architecture", [{ id: "D001", scope: "architecture", decision: "Use SQLite", choice: "SQLite", rationale: "Simplicity" }]],
531
- ]),
532
- totalCount: 1,
533
- },
534
- requirements: {
535
- active: [{ id: "R001", description: "Test requirement", status: "active" as const }],
536
- validated: [],
537
- deferred: [],
538
- totalCount: 1,
539
- },
540
- knowledge: "Some knowledge entry",
541
- summaries: "M001 completed X and Y",
542
- };
543
-
544
- const formatted = formatPriorContextBrief(brief);
545
- assert.ok(formatted.length > 0, "formatted brief should not be empty");
546
- assert.ok(formatted.includes("Prior Decisions"), "should include decisions section");
547
- assert.ok(formatted.includes("D001"), "should include decision ID");
548
- });
549
-
550
- test("formatEcosystemBrief returns simplified message (research happens during discussion)", async () => {
551
- const { formatEcosystemBrief } = await import("../preparation.ts");
552
-
553
- // formatEcosystemBrief now returns a fixed message regardless of brief content
554
- // because ecosystem research happens during the discussion, not preparation
555
- const briefWithFindings = {
556
- available: true,
557
- queries: ["Next.js best practices 2024"],
558
- findings: [
559
- {
560
- query: "Next.js best practices 2024",
561
- title: "Server Components Guide",
562
- url: "https://example.com/guide",
563
- snippet: "Use Server Components for data fetching",
564
- },
565
- ],
566
- provider: "tavily",
567
- };
568
-
569
- const formatted = formatEcosystemBrief(briefWithFindings);
570
- assert.ok(formatted.length > 0, "formatted brief should not be empty");
571
- assert.ok(formatted.includes("Ecosystem Research"), "should include research heading");
572
- assert.ok(formatted.includes("during the discussion"), "should mention research happens during discussion");
573
- });
574
-
575
- test("formatEcosystemBrief returns same output for any brief state", async () => {
576
- const { formatEcosystemBrief } = await import("../preparation.ts");
577
-
578
- const briefUnavailable = {
579
- available: false,
580
- queries: [],
581
- findings: [],
582
- skippedReason: "No API key configured",
583
- };
584
-
585
- const briefAvailable = {
586
- available: true,
587
- queries: ["test"],
588
- findings: [],
589
- provider: "tavily",
590
- };
591
-
592
- const formatted1 = formatEcosystemBrief(briefUnavailable);
593
- const formatted2 = formatEcosystemBrief(briefAvailable);
594
-
595
- // Both should return the same simplified message
596
- assert.equal(formatted1, formatted2, "should return consistent output regardless of brief state");
597
- assert.ok(formatted1.includes("web search tools"), "should mention web search tools");
598
- });
599
-
600
- test("formatted briefs can be injected into prompt without errors", async () => {
601
- const { loadPrompt } = await import("../prompt-loader.ts");
602
- const { formatCodebaseBrief, formatPriorContextBrief, formatEcosystemBrief } = await import("../preparation.ts");
603
-
604
- // Create realistic briefs
605
- const codebaseBrief = formatCodebaseBrief({
606
- techStack: {
607
- primaryLanguage: "TypeScript",
608
- detectedFiles: ["package.json"],
609
- packageManager: "npm",
610
- isMonorepo: false,
611
- hasTests: true,
612
- hasCI: false,
613
- },
614
- moduleStructure: {
615
- topLevelDirs: ["src"],
616
- srcSubdirs: [],
617
- totalFilesSampled: 1,
618
- },
619
- patterns: {
620
- asyncStyle: "async/await" as const,
621
- errorHandling: "try/catch" as const,
622
- namingConvention: "camelCase" as const,
623
- evidence: { asyncStyle: [], errorHandling: [], namingConvention: [] },
624
- fileCounts: {
625
- asyncAwait: 0,
626
- promises: 0,
627
- callbacks: 0,
628
- tryCatch: 0,
629
- errorCallbacks: 0,
630
- resultTypes: 0,
631
- },
632
- },
633
- sampledFiles: [],
634
- });
635
-
636
- const priorContextBrief = formatPriorContextBrief({
637
- decisions: { byScope: new Map(), totalCount: 0 },
638
- requirements: { active: [], validated: [], deferred: [], totalCount: 0 },
639
- knowledge: "No prior knowledge recorded.",
640
- summaries: "No prior milestone summaries.",
641
- });
642
-
643
- const ecosystemBrief = formatEcosystemBrief({
644
- available: false,
645
- queries: [],
646
- findings: [],
647
- skippedReason: "Preparation disabled",
648
- });
649
-
650
- // Should not throw when injecting formatted briefs
651
- const result = loadPrompt("discuss-prepared", {
652
- preamble: "Test preamble",
653
- codebaseBrief,
654
- priorContextBrief,
655
- ecosystemBrief,
656
- milestoneId: "M001",
657
- contextPath: ".gsd/milestones/M001/M001-CONTEXT.md",
658
- roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
659
- inlinedTemplates: "Test templates",
660
- commitInstruction: "Do not commit",
661
- multiMilestoneCommitInstruction: "Do not commit",
662
- });
663
-
664
- assert.ok(result.includes("TypeScript"), "codebase brief should be present");
665
- assert.ok(result.includes("Prior Decisions"), "prior context brief should be present");
666
- // formatEcosystemBrief now returns a fixed message about research during discussion
667
- assert.ok(result.includes("during the discussion"), "ecosystem brief should be present");
668
- });
669
- });