gsd-pi 2.74.0-dev.6e23363 → 2.74.0-dev.703eabc

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 (271) hide show
  1. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -3
  2. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +10 -1
  3. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +45 -4
  4. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  5. package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
  6. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
  7. package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
  8. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  9. package/dist/web/standalone/.next/BUILD_ID +1 -1
  10. package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
  11. package/dist/web/standalone/.next/build-manifest.json +2 -2
  12. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  13. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  30. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  31. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  32. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  33. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  34. package/dist/web/standalone/.next/server/app/index.html +1 -1
  35. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
  42. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  43. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  44. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  45. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  46. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  47. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  48. package/package.json +1 -1
  49. package/packages/mcp-server/dist/readers/graph.d.ts +1 -1
  50. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -1
  51. package/packages/mcp-server/dist/readers/graph.js +107 -0
  52. package/packages/mcp-server/dist/readers/graph.js.map +1 -1
  53. package/packages/mcp-server/src/readers/graph.test.ts +178 -0
  54. package/packages/mcp-server/src/readers/graph.ts +148 -1
  55. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  56. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  57. package/packages/pi-ai/dist/index.d.ts +1 -9
  58. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  59. package/packages/pi-ai/dist/index.js +1 -9
  60. package/packages/pi-ai/dist/index.js.map +1 -1
  61. package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
  62. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
  63. package/packages/pi-ai/dist/models/capability-patches.js +36 -0
  64. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
  65. package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
  66. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
  67. package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
  68. package/packages/pi-ai/dist/models/custom.js.map +1 -0
  69. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
  70. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
  71. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
  72. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
  73. package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
  74. package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
  75. package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
  76. package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
  77. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
  78. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
  79. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
  80. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
  81. package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
  82. package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
  83. package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
  84. package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
  85. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
  86. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
  87. package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
  88. package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
  89. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
  90. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
  91. package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
  92. package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
  93. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
  94. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
  95. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
  96. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
  97. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
  98. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
  99. package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
  100. package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
  101. package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
  102. package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
  103. package/packages/pi-ai/dist/models/generated/google.js +464 -0
  104. package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
  105. package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
  106. package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
  107. package/packages/pi-ai/dist/models/generated/groq.js +311 -0
  108. package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
  109. package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
  110. package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
  111. package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
  112. package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
  113. package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
  114. package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
  115. package/packages/pi-ai/dist/models/generated/index.js +51 -0
  116. package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
  117. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
  118. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
  119. package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
  120. package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
  121. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
  122. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
  123. package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
  124. package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
  125. package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
  126. package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
  127. package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
  128. package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
  129. package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
  130. package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
  131. package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
  132. package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
  133. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
  134. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
  135. package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
  136. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
  137. package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
  138. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
  139. package/packages/pi-ai/dist/models/generated/openai.js +702 -0
  140. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
  141. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
  142. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
  143. package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
  144. package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
  145. package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
  146. package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
  147. package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
  148. package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
  149. package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
  150. package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
  151. package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
  152. package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
  153. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
  154. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
  155. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
  156. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
  157. package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
  158. package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
  159. package/packages/pi-ai/dist/models/generated/xai.js +413 -0
  160. package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
  161. package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
  162. package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
  163. package/packages/pi-ai/dist/models/generated/zai.js +239 -0
  164. package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
  165. package/packages/pi-ai/dist/models/index.d.ts +27 -0
  166. package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
  167. package/packages/pi-ai/dist/models/index.js +80 -0
  168. package/packages/pi-ai/dist/models/index.js.map +1 -0
  169. package/packages/pi-ai/dist/models.d.ts +1 -36
  170. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  171. package/packages/pi-ai/dist/models.generated.test.js +1 -2
  172. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  173. package/packages/pi-ai/dist/models.js +3 -112
  174. package/packages/pi-ai/dist/models.js.map +1 -1
  175. package/packages/pi-ai/dist/models.test.js +6 -5
  176. package/packages/pi-ai/dist/models.test.js.map +1 -1
  177. package/packages/pi-ai/scripts/generate-models.ts +74 -40
  178. package/packages/pi-ai/src/index.ts +1 -9
  179. package/packages/pi-ai/src/models/capability-patches.ts +40 -0
  180. package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
  181. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
  182. package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
  183. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  184. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  185. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  186. package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
  187. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  188. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  189. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  190. package/packages/pi-ai/src/models/generated/groq.ts +313 -0
  191. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  192. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  193. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  194. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  195. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  196. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  197. package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
  198. package/packages/pi-ai/src/models/generated/openai.ts +704 -0
  199. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  200. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  201. package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
  202. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  203. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  204. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  205. package/packages/pi-ai/src/models/index.ts +106 -0
  206. package/packages/pi-ai/src/models.generated.test.ts +1 -2
  207. package/packages/pi-ai/src/models.test.ts +6 -5
  208. package/packages/pi-ai/src/models.ts +3 -153
  209. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  210. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  211. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
  212. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  213. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +359 -7
  214. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +11 -0
  216. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  217. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  218. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  219. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +23 -9
  220. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  221. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
  222. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
  223. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
  225. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +51 -8
  227. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  229. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
  230. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  231. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +192 -22
  233. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
  235. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
  236. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
  237. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
  238. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +13 -0
  239. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  240. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +53 -6
  241. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  242. package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
  243. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +453 -7
  244. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +19 -0
  245. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +25 -10
  246. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
  247. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +66 -7
  248. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
  249. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +253 -45
  250. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
  251. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +73 -6
  252. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  253. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -3
  254. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -1
  255. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +56 -3
  256. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  257. package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
  258. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
  259. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  260. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
  261. package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
  262. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
  263. package/src/resources/extensions/gsd/types.ts +13 -0
  264. package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
  265. package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
  266. package/packages/pi-ai/dist/models.custom.js.map +0 -1
  267. package/packages/pi-ai/dist/models.generated.js +0 -14343
  268. package/packages/pi-ai/dist/models.generated.js.map +0 -1
  269. package/packages/pi-ai/src/models.generated.ts +0 -14345
  270. /package/dist/web/standalone/.next/static/{bc2gRVFTgD7j--BsJE7vP → 3U-oZ5FT59BM7sm2GInic}/_buildManifest.js +0 -0
  271. /package/dist/web/standalone/.next/static/{bc2gRVFTgD7j--BsJE7vP → 3U-oZ5FT59BM7sm2GInic}/_ssgManifest.js +0 -0
@@ -98,6 +98,49 @@ function makeProjectWithArtifacts(projectDir: string): void {
98
98
  ].join('\n'));
99
99
  }
100
100
 
101
+ // ---------------------------------------------------------------------------
102
+ // LEARNINGS.md fixture helpers
103
+ // ---------------------------------------------------------------------------
104
+
105
+ function writeLearningsFixture(projectDir: string, milestoneId: string, content: string): void {
106
+ writeFixture(projectDir, `.gsd/milestones/${milestoneId}/${milestoneId}-LEARNINGS.md`, content);
107
+ }
108
+
109
+ const SAMPLE_LEARNINGS = `---
110
+ phase: "M001"
111
+ phase_name: "User Auth"
112
+ project: "my-project"
113
+ generated: "2026-04-15T10:00:00Z"
114
+ counts:
115
+ decisions: 2
116
+ lessons: 1
117
+ patterns: 1
118
+ surprises: 1
119
+ missing_artifacts: []
120
+ ---
121
+
122
+ # Learnings: User Auth
123
+
124
+ ## Decisions
125
+ - Use JWT for stateless auth across services.
126
+ Source: M001-PLAN.md/Architecture
127
+
128
+ - Store refresh tokens in HTTP-only cookies only.
129
+ Source: M001-PLAN.md/Security
130
+
131
+ ## Lessons
132
+ - Integration tests need a real DB — mocks missed migration bugs.
133
+ Source: M001-SUMMARY.md/Testing
134
+
135
+ ## Patterns
136
+ - Repository pattern abstracts DB access and simplifies testing.
137
+ Source: M001-PLAN.md/Design
138
+
139
+ ## Surprises
140
+ - Token expiry edge case caused silent auth failures in prod.
141
+ Source: M001-SUMMARY.md/Issues
142
+ `;
143
+
101
144
  // ---------------------------------------------------------------------------
102
145
  // buildGraph tests
103
146
  // ---------------------------------------------------------------------------
@@ -162,6 +205,141 @@ describe('buildGraph', () => {
162
205
  });
163
206
  });
164
207
 
208
+ // ---------------------------------------------------------------------------
209
+ // buildGraph — LEARNINGS.md parsing tests
210
+ // ---------------------------------------------------------------------------
211
+
212
+ describe('buildGraph — LEARNINGS.md parsing', () => {
213
+ let projectDir: string;
214
+
215
+ beforeEach(() => {
216
+ projectDir = tmpProject();
217
+ // Create minimal milestone directory so parseMilestoneFiles finds it
218
+ mkdirSync(join(projectDir, '.gsd', 'milestones', 'M001'), { recursive: true });
219
+ writeLearningsFixture(projectDir, 'M001', SAMPLE_LEARNINGS);
220
+ });
221
+
222
+ afterEach(() => rmSync(projectDir, { recursive: true, force: true }));
223
+
224
+ it('extracts decision nodes from ## Decisions section', async () => {
225
+ const graph = await buildGraph(projectDir);
226
+ const decisions = graph.nodes.filter((n) => n.type === 'decision' || (n.type === 'rule' && n.id.startsWith('decision:')));
227
+ // Decisions should be extracted with a 'decision' type (or similar existing type)
228
+ const decisionNodes = graph.nodes.filter((n) => n.id.includes('decision:M001'));
229
+ assert.ok(decisionNodes.length >= 2, `Expected >= 2 decision nodes, got ${decisionNodes.length}`);
230
+ });
231
+
232
+ it('extracts lesson nodes from ## Lessons section', async () => {
233
+ const graph = await buildGraph(projectDir);
234
+ const lessonNodes = graph.nodes.filter((n) => n.id.includes('lesson:M001'));
235
+ assert.ok(lessonNodes.length >= 1, `Expected >= 1 lesson node, got ${lessonNodes.length}`);
236
+ assert.ok(lessonNodes.every((n) => n.type === 'lesson'), 'All lesson nodes must have type "lesson"');
237
+ });
238
+
239
+ it('extracts pattern nodes from ## Patterns section', async () => {
240
+ const graph = await buildGraph(projectDir);
241
+ const patternNodes = graph.nodes.filter((n) => n.id.includes('pattern:M001'));
242
+ assert.ok(patternNodes.length >= 1, `Expected >= 1 pattern node, got ${patternNodes.length}`);
243
+ assert.ok(patternNodes.every((n) => n.type === 'pattern'), 'All pattern nodes must have type "pattern"');
244
+ });
245
+
246
+ it('maps surprises to lesson nodes', async () => {
247
+ const graph = await buildGraph(projectDir);
248
+ // Surprises should be mapped to lesson type since no "surprise" NodeType exists
249
+ const surpriseNodes = graph.nodes.filter((n) => n.id.includes('surprise:M001'));
250
+ assert.ok(surpriseNodes.length >= 1, `Expected >= 1 surprise node, got ${surpriseNodes.length}`);
251
+ assert.ok(surpriseNodes.every((n) => n.type === 'lesson'), 'Surprises must be mapped to type "lesson"');
252
+ });
253
+
254
+ it('node labels contain the learning text', async () => {
255
+ const graph = await buildGraph(projectDir);
256
+ const hasJwtDecision = graph.nodes.some((n) =>
257
+ n.label.toLowerCase().includes('jwt') || n.description?.toLowerCase().includes('jwt'),
258
+ );
259
+ assert.ok(hasJwtDecision, 'Expected a node describing the JWT decision');
260
+ });
261
+
262
+ it('node description includes source attribution', async () => {
263
+ const graph = await buildGraph(projectDir);
264
+ const learningNodes = graph.nodes.filter((n) =>
265
+ n.id.includes(':M001:') || n.id.match(/:(decision|lesson|pattern|surprise):M001/),
266
+ );
267
+ const withSource = learningNodes.filter((n) => n.description?.includes('Source:') || n.description?.includes('M001-PLAN'));
268
+ assert.ok(withSource.length > 0, 'Expected at least one node with source attribution in description');
269
+ });
270
+
271
+ it('adds relates_to edge from learning node to milestone node', async () => {
272
+ const graph = await buildGraph(projectDir);
273
+ const edgesToMilestone = graph.edges.filter(
274
+ (e) => e.to === 'milestone:M001' || e.from === 'milestone:M001',
275
+ );
276
+ // At least one learning node should relate to the milestone
277
+ const learningEdges = graph.edges.filter(
278
+ (e) => (e.from.includes('M001') && (e.type === 'relates_to' || e.type === 'contains')) ||
279
+ (e.to.includes('M001') && e.type === 'relates_to'),
280
+ );
281
+ assert.ok(learningEdges.length > 0 || edgesToMilestone.length > 0,
282
+ 'Expected edges connecting learning nodes to milestone');
283
+ });
284
+
285
+ it('skips LEARNINGS.md gracefully when file is malformed', async () => {
286
+ const badProject = tmpProject();
287
+ mkdirSync(join(badProject, '.gsd', 'milestones', 'M002'), { recursive: true });
288
+ writeLearningsFixture(badProject, 'M002', '\0\0\0 not valid yaml or markdown \0\0\0');
289
+ // Must not throw
290
+ const graph = await buildGraph(badProject);
291
+ assert.ok(graph.nodes.length >= 0);
292
+ assert.equal(typeof graph.builtAt, 'string');
293
+ rmSync(badProject, { recursive: true, force: true });
294
+ });
295
+
296
+ it('produces no learning nodes when all sections are empty', async () => {
297
+ const emptyProject = tmpProject();
298
+ mkdirSync(join(emptyProject, '.gsd', 'milestones', 'M003'), { recursive: true });
299
+ writeLearningsFixture(emptyProject, 'M003', `---
300
+ phase: "M003"
301
+ phase_name: "Empty"
302
+ project: "test"
303
+ generated: "2026-04-15T10:00:00Z"
304
+ counts:
305
+ decisions: 0
306
+ lessons: 0
307
+ patterns: 0
308
+ surprises: 0
309
+ missing_artifacts: []
310
+ ---
311
+
312
+ # Learnings: Empty
313
+
314
+ ## Decisions
315
+
316
+ ## Lessons
317
+
318
+ ## Patterns
319
+
320
+ ## Surprises
321
+ `);
322
+ const graph = await buildGraph(emptyProject);
323
+ const learningNodes = graph.nodes.filter((n) =>
324
+ n.id.includes('decision:M003') ||
325
+ n.id.includes('lesson:M003') ||
326
+ n.id.includes('pattern:M003') ||
327
+ n.id.includes('surprise:M003'),
328
+ );
329
+ assert.equal(learningNodes.length, 0, 'Empty sections should produce no nodes');
330
+ rmSync(emptyProject, { recursive: true, force: true });
331
+ });
332
+
333
+ it('does not crash when LEARNINGS.md is missing entirely', async () => {
334
+ const noLearningsProject = tmpProject();
335
+ mkdirSync(join(noLearningsProject, '.gsd', 'milestones', 'M004'), { recursive: true });
336
+ // No LEARNINGS.md file written
337
+ const graph = await buildGraph(noLearningsProject);
338
+ assert.ok(graph.nodes.length >= 0);
339
+ rmSync(noLearningsProject, { recursive: true, force: true });
340
+ });
341
+ });
342
+
165
343
  // ---------------------------------------------------------------------------
166
344
  // writeGraph tests
167
345
  // ---------------------------------------------------------------------------
@@ -27,7 +27,8 @@ export type NodeType =
27
27
  | 'rule'
28
28
  | 'pattern'
29
29
  | 'lesson'
30
- | 'concept';
30
+ | 'concept'
31
+ | 'decision';
31
32
 
32
33
  export type EdgeType =
33
34
  | 'contains'
@@ -386,6 +387,151 @@ function parseTasksFromPlan(
386
387
  }
387
388
  }
388
389
 
390
+ // ---------------------------------------------------------------------------
391
+ // LEARNINGS.md parser
392
+ // ---------------------------------------------------------------------------
393
+
394
+ /**
395
+ * Parse all *-LEARNINGS.md files found in milestone directories.
396
+ * Extracts Decisions, Lessons, Patterns, and Surprises as typed graph nodes.
397
+ * Surprises are mapped to the 'lesson' NodeType (no distinct type exists).
398
+ * Parse errors per file are caught — the file is skipped, never rethrows.
399
+ */
400
+ function parseLearningsFiles(gsdRoot: string, nodes: GraphNode[], edges: GraphEdge[]): void {
401
+ const milestoneIds = findMilestoneIds(gsdRoot);
402
+
403
+ for (const milestoneId of milestoneIds) {
404
+ try {
405
+ parseSingleLearningsFile(gsdRoot, milestoneId, nodes, edges);
406
+ } catch {
407
+ // Skip this milestone's LEARNINGS.md on any error
408
+ }
409
+ }
410
+ }
411
+
412
+ function parseSingleLearningsFile(
413
+ gsdRoot: string,
414
+ milestoneId: string,
415
+ nodes: GraphNode[],
416
+ edges: GraphEdge[],
417
+ ): void {
418
+ const mDir = resolveMilestoneDir(gsdRoot, milestoneId);
419
+ if (!mDir) return;
420
+
421
+ const learningsPath = join(mDir, `${milestoneId}-LEARNINGS.md`);
422
+ if (!existsSync(learningsPath)) return;
423
+
424
+ let content: string;
425
+ try {
426
+ content = readFileSync(learningsPath, 'utf-8');
427
+ } catch {
428
+ return;
429
+ }
430
+
431
+ // Strip YAML frontmatter if present
432
+ const withoutFrontmatter = content.replace(/^---[\s\S]*?---\n?/, '');
433
+
434
+ const milestoneNodeId = `milestone:${milestoneId}`;
435
+ const sourceFile = `milestones/${milestoneId}/${milestoneId}-LEARNINGS.md`;
436
+
437
+ // Parse each section: [sectionName, nodeType, idPrefix]
438
+ const sections: Array<[string, NodeType, string]> = [
439
+ ['Decisions', 'decision', 'decision'],
440
+ ['Lessons', 'lesson', 'lesson'],
441
+ ['Patterns', 'pattern', 'pattern'],
442
+ ['Surprises', 'lesson', 'surprise'],
443
+ ];
444
+
445
+ for (const [sectionName, nodeType, idPrefix] of sections) {
446
+ const sectionMatch = withoutFrontmatter.match(
447
+ new RegExp(`##\\s+${sectionName}\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$)`, 'i'),
448
+ );
449
+ if (!sectionMatch) continue;
450
+
451
+ const sectionContent = sectionMatch[1];
452
+ parseLearningsSection(
453
+ sectionContent,
454
+ milestoneId,
455
+ idPrefix,
456
+ nodeType,
457
+ milestoneNodeId,
458
+ sourceFile,
459
+ nodes,
460
+ edges,
461
+ );
462
+ }
463
+ }
464
+
465
+ function parseLearningsSection(
466
+ sectionContent: string,
467
+ milestoneId: string,
468
+ idPrefix: string,
469
+ nodeType: NodeType,
470
+ milestoneNodeId: string,
471
+ sourceFile: string,
472
+ nodes: GraphNode[],
473
+ edges: GraphEdge[],
474
+ ): void {
475
+ // Each item is a bullet line starting with "- " followed by optional
476
+ // indented "Source: ..." line.
477
+ // We collect bullet items and their associated source attribution.
478
+ const lines = sectionContent.split('\n');
479
+ let itemIndex = 0;
480
+ let currentText: string | null = null;
481
+ let currentSource: string | null = null;
482
+
483
+ const flushItem = (): void => {
484
+ if (!currentText) return;
485
+ itemIndex += 1;
486
+ const nodeId = `${idPrefix}:${milestoneId}:${itemIndex}`;
487
+ const description = currentSource ? `${currentSource}` : undefined;
488
+
489
+ nodes.push({
490
+ id: nodeId,
491
+ label: currentText,
492
+ type: nodeType,
493
+ description,
494
+ confidence: 'EXTRACTED',
495
+ sourceFile,
496
+ });
497
+
498
+ // Edge: milestone relates_to this learning node
499
+ edges.push({
500
+ from: milestoneNodeId,
501
+ to: nodeId,
502
+ type: 'relates_to',
503
+ confidence: 'EXTRACTED',
504
+ });
505
+
506
+ currentText = null;
507
+ currentSource = null;
508
+ };
509
+
510
+ for (const line of lines) {
511
+ const bulletMatch = line.match(/^[-*]\s+(.+)/);
512
+ if (bulletMatch) {
513
+ flushItem();
514
+ currentText = bulletMatch[1].trim();
515
+ continue;
516
+ }
517
+
518
+ // Indented source attribution: " Source: ..."
519
+ const sourceMatch = line.match(/^\s+Source:\s+(.+)/i);
520
+ if (sourceMatch && currentText !== null) {
521
+ currentSource = `Source: ${sourceMatch[1].trim()}`;
522
+ continue;
523
+ }
524
+
525
+ // Continuation of current item text (indented non-source line)
526
+ const continuationMatch = line.match(/^\s{2,}(.+)/);
527
+ if (continuationMatch && currentText !== null && currentSource === null) {
528
+ currentText += ' ' + continuationMatch[1].trim();
529
+ }
530
+ }
531
+
532
+ flushItem();
533
+ }
534
+
389
535
  // ---------------------------------------------------------------------------
390
536
  // buildGraph
391
537
  // ---------------------------------------------------------------------------
@@ -407,6 +553,7 @@ export async function buildGraph(projectDir: string): Promise<KnowledgeGraph> {
407
553
  parseStateFile,
408
554
  parseKnowledgeFile,
409
555
  parseMilestoneFiles,
556
+ parseLearningsFiles,
410
557
  ];
411
558
 
412
559
  for (const parser of parsers) {