gsd-pi 2.74.0-dev.2b524c3 → 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 (484) hide show
  1. package/dist/cli.js +85 -0
  2. package/dist/headless-query.js +4 -1
  3. package/dist/help-text.js +23 -0
  4. package/dist/resources/extensions/gsd/activity-log.js +16 -0
  5. package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
  6. package/dist/resources/extensions/gsd/auto/loop.js +147 -10
  7. package/dist/resources/extensions/gsd/auto/phases.js +158 -4
  8. package/dist/resources/extensions/gsd/auto/session.js +10 -0
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +11 -1
  10. package/dist/resources/extensions/gsd/auto-model-selection.js +51 -5
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +220 -17
  12. package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
  13. package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
  14. package/dist/resources/extensions/gsd/auto-verification.js +100 -2
  15. package/dist/resources/extensions/gsd/auto.js +36 -4
  16. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +30 -8
  17. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +45 -4
  18. package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
  19. package/dist/resources/extensions/gsd/commands/handlers/ops.js +25 -0
  20. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
  21. package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
  22. package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
  23. package/dist/resources/extensions/gsd/commands-do.js +79 -0
  24. package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
  25. package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
  26. package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
  27. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  28. package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
  29. package/dist/resources/extensions/gsd/commands-ship.js +187 -0
  30. package/dist/resources/extensions/gsd/db-writer.js +3 -5
  31. package/dist/resources/extensions/gsd/docs/preferences-reference.md +14 -1
  32. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
  33. package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
  34. package/dist/resources/extensions/gsd/git-service.js +49 -1
  35. package/dist/resources/extensions/gsd/graph-context.js +157 -0
  36. package/dist/resources/extensions/gsd/gsd-db.js +581 -2
  37. package/dist/resources/extensions/gsd/guided-flow.js +23 -0
  38. package/dist/resources/extensions/gsd/index.js +15 -2
  39. package/dist/resources/extensions/gsd/init-wizard.js +1 -0
  40. package/dist/resources/extensions/gsd/journal.js +27 -0
  41. package/dist/resources/extensions/gsd/md-importer.js +3 -4
  42. package/dist/resources/extensions/gsd/memory-store.js +19 -51
  43. package/dist/resources/extensions/gsd/metrics.js +19 -0
  44. package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
  46. package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
  47. package/dist/resources/extensions/gsd/preferences-models.js +20 -3
  48. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  49. package/dist/resources/extensions/gsd/preferences-validation.js +108 -2
  50. package/dist/resources/extensions/gsd/preferences.js +26 -0
  51. package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
  52. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
  53. package/dist/resources/extensions/gsd/state.js +5 -1
  54. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  55. package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -0
  56. package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
  57. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
  58. package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
  59. package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
  60. package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
  61. package/dist/resources/extensions/gsd/uok/audit.js +40 -0
  62. package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
  63. package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
  64. package/dist/resources/extensions/gsd/uok/flags.js +29 -0
  65. package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
  66. package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
  67. package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
  68. package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
  69. package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
  70. package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
  71. package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
  72. package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
  73. package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
  74. package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
  75. package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
  76. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  77. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  78. package/dist/web/standalone/.next/BUILD_ID +1 -1
  79. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  80. package/dist/web/standalone/.next/build-manifest.json +2 -2
  81. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  82. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/index.html +1 -1
  104. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  111. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  112. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  114. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  115. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  116. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  117. package/package.json +3 -2
  118. package/packages/daemon/package.json +2 -2
  119. package/packages/mcp-server/dist/index.d.ts +3 -0
  120. package/packages/mcp-server/dist/index.d.ts.map +1 -1
  121. package/packages/mcp-server/dist/index.js +3 -0
  122. package/packages/mcp-server/dist/index.js.map +1 -1
  123. package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
  124. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
  125. package/packages/mcp-server/dist/readers/graph.js +655 -0
  126. package/packages/mcp-server/dist/readers/graph.js.map +1 -0
  127. package/packages/mcp-server/dist/readers/index.d.ts +2 -0
  128. package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
  129. package/packages/mcp-server/dist/readers/index.js +1 -0
  130. package/packages/mcp-server/dist/readers/index.js.map +1 -1
  131. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  132. package/packages/mcp-server/dist/server.js +65 -0
  133. package/packages/mcp-server/dist/server.js.map +1 -1
  134. package/packages/mcp-server/package.json +2 -2
  135. package/packages/mcp-server/src/index.ts +15 -0
  136. package/packages/mcp-server/src/readers/graph.test.ts +604 -0
  137. package/packages/mcp-server/src/readers/graph.ts +855 -0
  138. package/packages/mcp-server/src/readers/index.ts +12 -0
  139. package/packages/mcp-server/src/server.ts +83 -0
  140. package/packages/mcp-server/tsconfig.json +1 -0
  141. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
  142. package/packages/native/package.json +2 -2
  143. package/packages/native/tsconfig.tsbuildinfo +1 -0
  144. package/packages/pi-agent-core/package.json +1 -1
  145. package/packages/pi-agent-core/tsconfig.json +1 -0
  146. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
  147. package/packages/pi-ai/dist/index.d.ts +1 -9
  148. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  149. package/packages/pi-ai/dist/index.js +1 -9
  150. package/packages/pi-ai/dist/index.js.map +1 -1
  151. package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
  152. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
  153. package/packages/pi-ai/dist/models/capability-patches.js +36 -0
  154. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
  155. package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
  156. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
  157. package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
  158. package/packages/pi-ai/dist/models/custom.js.map +1 -0
  159. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
  160. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
  161. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
  162. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
  163. package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
  164. package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
  165. package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
  166. package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
  167. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
  168. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
  169. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
  170. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
  171. package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
  172. package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
  173. package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
  174. package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
  175. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
  176. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
  177. package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
  178. package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
  179. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
  180. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
  181. package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
  182. package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
  183. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
  184. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
  185. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
  186. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
  187. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
  188. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
  189. package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
  190. package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
  191. package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
  192. package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/models/generated/google.js +464 -0
  194. package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
  195. package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
  196. package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
  197. package/packages/pi-ai/dist/models/generated/groq.js +311 -0
  198. package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
  199. package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
  200. package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
  201. package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
  202. package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
  203. package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
  204. package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
  205. package/packages/pi-ai/dist/models/generated/index.js +51 -0
  206. package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
  207. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
  208. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
  209. package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
  210. package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
  211. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
  212. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
  213. package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
  214. package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
  215. package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
  216. package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
  217. package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
  218. package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
  219. package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
  220. package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
  221. package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
  222. package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
  223. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
  224. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
  225. package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
  226. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
  227. package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
  228. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
  229. package/packages/pi-ai/dist/models/generated/openai.js +702 -0
  230. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
  231. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
  232. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
  233. package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
  234. package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
  235. package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
  236. package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
  237. package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
  238. package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
  239. package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
  240. package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
  241. package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
  242. package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
  243. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
  244. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
  245. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
  246. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
  247. package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
  248. package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
  249. package/packages/pi-ai/dist/models/generated/xai.js +413 -0
  250. package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
  251. package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
  252. package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
  253. package/packages/pi-ai/dist/models/generated/zai.js +239 -0
  254. package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
  255. package/packages/pi-ai/dist/models/index.d.ts +27 -0
  256. package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
  257. package/packages/pi-ai/dist/models/index.js +80 -0
  258. package/packages/pi-ai/dist/models/index.js.map +1 -0
  259. package/packages/pi-ai/dist/models.d.ts +1 -36
  260. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  261. package/packages/pi-ai/dist/models.generated.test.js +1 -2
  262. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  263. package/packages/pi-ai/dist/models.js +3 -112
  264. package/packages/pi-ai/dist/models.js.map +1 -1
  265. package/packages/pi-ai/dist/models.test.js +6 -5
  266. package/packages/pi-ai/dist/models.test.js.map +1 -1
  267. package/packages/pi-ai/package.json +1 -1
  268. package/packages/pi-ai/scripts/generate-models.ts +74 -40
  269. package/packages/pi-ai/src/index.ts +1 -9
  270. package/packages/pi-ai/src/models/capability-patches.ts +40 -0
  271. package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
  272. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
  273. package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
  274. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  275. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  276. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  277. package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
  278. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  279. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  280. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  281. package/packages/pi-ai/src/models/generated/groq.ts +313 -0
  282. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  283. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  284. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  285. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  286. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  287. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  288. package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
  289. package/packages/pi-ai/src/models/generated/openai.ts +704 -0
  290. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  291. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  292. package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
  293. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  294. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  295. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  296. package/packages/pi-ai/src/models/index.ts +106 -0
  297. package/packages/pi-ai/src/models.generated.test.ts +1 -2
  298. package/packages/pi-ai/src/models.test.ts +6 -5
  299. package/packages/pi-ai/src/models.ts +3 -153
  300. package/packages/pi-ai/tsconfig.json +1 -0
  301. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
  302. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
  304. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  305. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +472 -0
  306. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  307. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
  308. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
  310. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  313. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +11 -0
  315. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  317. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  318. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +23 -9
  319. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  320. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
  321. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
  322. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
  323. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +51 -8
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  330. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +232 -18
  332. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
  334. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
  335. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
  336. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
  337. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +13 -0
  338. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  339. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +53 -6
  340. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  341. package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
  342. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +612 -0
  343. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  344. package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
  345. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +19 -0
  346. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +25 -10
  347. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
  348. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +66 -7
  349. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
  350. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +298 -41
  351. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
  352. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +73 -6
  353. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  354. package/packages/pi-coding-agent/tsconfig.json +3 -2
  355. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
  356. package/packages/pi-tui/package.json +1 -1
  357. package/packages/pi-tui/tsconfig.json +1 -0
  358. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
  359. package/packages/rpc-client/package.json +1 -1
  360. package/packages/rpc-client/tsconfig.json +1 -0
  361. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
  362. package/src/resources/extensions/gsd/activity-log.ts +21 -0
  363. package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
  364. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -0
  365. package/src/resources/extensions/gsd/auto/loop.ts +159 -10
  366. package/src/resources/extensions/gsd/auto/phases.ts +191 -4
  367. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  368. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -6
  369. package/src/resources/extensions/gsd/auto-model-selection.ts +66 -5
  370. package/src/resources/extensions/gsd/auto-post-unit.ts +238 -18
  371. package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
  372. package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
  373. package/src/resources/extensions/gsd/auto-verification.ts +129 -2
  374. package/src/resources/extensions/gsd/auto.ts +41 -2
  375. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +38 -8
  376. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +56 -3
  377. package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
  378. package/src/resources/extensions/gsd/commands/handlers/ops.ts +25 -0
  379. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
  380. package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
  381. package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
  382. package/src/resources/extensions/gsd/commands-do.ts +109 -0
  383. package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
  384. package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
  385. package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
  386. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  387. package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
  388. package/src/resources/extensions/gsd/commands-ship.ts +219 -0
  389. package/src/resources/extensions/gsd/db-writer.ts +3 -5
  390. package/src/resources/extensions/gsd/docs/preferences-reference.md +14 -1
  391. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
  392. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  393. package/src/resources/extensions/gsd/git-service.ts +68 -0
  394. package/src/resources/extensions/gsd/graph-context.ts +212 -0
  395. package/src/resources/extensions/gsd/gsd-db.ts +788 -3
  396. package/src/resources/extensions/gsd/guided-flow.ts +32 -0
  397. package/src/resources/extensions/gsd/index.ts +18 -2
  398. package/src/resources/extensions/gsd/init-wizard.ts +3 -2
  399. package/src/resources/extensions/gsd/journal.ts +30 -0
  400. package/src/resources/extensions/gsd/md-importer.ts +3 -5
  401. package/src/resources/extensions/gsd/memory-store.ts +31 -62
  402. package/src/resources/extensions/gsd/metrics.ts +26 -0
  403. package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
  404. package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
  405. package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
  406. package/src/resources/extensions/gsd/preferences-models.ts +20 -3
  407. package/src/resources/extensions/gsd/preferences-types.ts +32 -0
  408. package/src/resources/extensions/gsd/preferences-validation.ts +107 -2
  409. package/src/resources/extensions/gsd/preferences.ts +28 -0
  410. package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
  411. package/src/resources/extensions/gsd/session-lock.ts +14 -2
  412. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
  413. package/src/resources/extensions/gsd/state.ts +9 -2
  414. package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  415. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +7 -3
  416. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
  417. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
  418. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
  419. package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
  420. package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
  421. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
  422. package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
  423. package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
  424. package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
  425. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
  426. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  427. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  428. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
  429. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
  430. package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
  431. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  432. package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
  433. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
  434. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
  435. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
  436. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
  437. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  438. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
  439. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
  440. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
  441. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
  442. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -5
  443. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  444. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
  445. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
  446. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
  447. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
  448. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
  449. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
  450. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  451. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
  452. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  453. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
  454. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
  455. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -0
  456. package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
  457. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
  458. package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
  459. package/src/resources/extensions/gsd/types.ts +14 -1
  460. package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
  461. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  462. package/src/resources/extensions/gsd/uok/audit.ts +51 -0
  463. package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
  464. package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
  465. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  466. package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
  467. package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
  468. package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
  469. package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
  470. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  471. package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
  472. package/src/resources/extensions/gsd/workflow-logger.ts +27 -1
  473. package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
  474. package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
  475. package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
  476. package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
  477. package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
  478. package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
  479. package/packages/pi-ai/dist/models.custom.js.map +0 -1
  480. package/packages/pi-ai/dist/models.generated.js +0 -14343
  481. package/packages/pi-ai/dist/models.generated.js.map +0 -1
  482. package/packages/pi-ai/src/models.generated.ts +0 -14345
  483. /package/dist/web/standalone/.next/static/{YzIEI9sxJy4t5xgClF08g → 3U-oZ5FT59BM7sm2GInic}/_buildManifest.js +0 -0
  484. /package/dist/web/standalone/.next/static/{YzIEI9sxJy4t5xgClF08g → 3U-oZ5FT59BM7sm2GInic}/_ssgManifest.js +0 -0
@@ -217,6 +217,20 @@ describe("workflow command handler", () => {
217
217
  );
218
218
  });
219
219
 
220
+ it("preserves quoted workflow run overrides (#4130)", async () => {
221
+ const { parseWorkflowRunArgs } = await import("../commands/handlers/workflow.ts");
222
+ assert.deepStrictEqual(
223
+ parseWorkflowRunArgs('demo-workflow target="multi word target" region=\'us east\''),
224
+ {
225
+ defName: "demo-workflow",
226
+ overrides: {
227
+ target: "multi word target",
228
+ region: "us east",
229
+ },
230
+ },
231
+ );
232
+ });
233
+
220
234
  it("'/gsd workflow run nonexistent' shows error for missing definition", async () => {
221
235
  const { handled, notifications } = await callHandler("workflow run nonexistent-def-12345");
222
236
  assert.ok(handled, "should be handled");
@@ -125,9 +125,9 @@ console.log('\n=== complete-slice: schema v6 migration ===');
125
125
 
126
126
  const adapter = _getAdapter()!;
127
127
 
128
- // Verify schema version is current (v14 after indexes + slice_dependencies)
128
+ // Verify schema version is current (v15 with UOK projection tables)
129
129
  const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
130
- assertEq(versionRow?.['v'], 14, 'schema version should be 14');
130
+ assertEq(versionRow?.['v'], 15, 'schema version should be 15');
131
131
 
132
132
  // Verify slices table has full_summary_md and full_uat_md columns
133
133
  const cols = adapter.prepare("PRAGMA table_info(slices)").all();
@@ -109,9 +109,9 @@ console.log('\n=== complete-task: schema v5 migration ===');
109
109
 
110
110
  const adapter = _getAdapter()!;
111
111
 
112
- // Verify schema version is current (v14 after indexes + slice_dependencies)
112
+ // Verify schema version is current (v15 with UOK projection tables)
113
113
  const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
114
- assertEq(versionRow?.['v'], 14, 'schema version should be 14');
114
+ assertEq(versionRow?.['v'], 15, 'schema version should be 15');
115
115
 
116
116
  // Verify all 4 new tables exist
117
117
  const tables = adapter.prepare(
@@ -0,0 +1,154 @@
1
+ // Structural contracts for GSD extension bootstrap isolation.
2
+ //
3
+ // The /gsd command must survive failures in the full extension bootstrap
4
+ // (register-extension.ts). This guards against the regression where a
5
+ // Windows-specific import failure in register-shortcuts.ts silently
6
+ // prevented /gsd from being registered at all (#4168, #4172).
7
+
8
+ import { describe, test } from "node:test";
9
+ import assert from "node:assert/strict";
10
+ import { readFileSync } from "node:fs";
11
+ import { join, dirname } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const indexSrc = readFileSync(join(__dirname, "../index.ts"), "utf-8");
16
+ const registerExtSrc = readFileSync(
17
+ join(__dirname, "../bootstrap/register-extension.ts"),
18
+ "utf-8",
19
+ );
20
+
21
+ // ─── index.ts: core /gsd command must be registered before full bootstrap ─────
22
+
23
+ describe("index.ts bootstrap isolation", () => {
24
+ test("imports registerGSDCommand from commands/index.js separately", () => {
25
+ assert.ok(
26
+ indexSrc.includes('./commands/index.js"') || indexSrc.includes("./commands/index.js'"),
27
+ "index.ts must import registerGSDCommand from ./commands/index.js",
28
+ );
29
+ });
30
+
31
+ test("calls registerGSDCommand before importing register-extension.js", () => {
32
+ const gsdCommandCallPos = indexSrc.indexOf("registerGSDCommand(pi)");
33
+ const bootstrapImportPos = indexSrc.indexOf(
34
+ './bootstrap/register-extension.js"',
35
+ );
36
+
37
+ assert.ok(gsdCommandCallPos >= 0, "must call registerGSDCommand(pi)");
38
+ assert.ok(bootstrapImportPos >= 0, "must import register-extension.js");
39
+ assert.ok(
40
+ gsdCommandCallPos < bootstrapImportPos,
41
+ "registerGSDCommand(pi) must be called BEFORE importing register-extension.js",
42
+ );
43
+ });
44
+
45
+ test("wraps register-extension.js import in try-catch", () => {
46
+ // The dynamic import of register-extension.js must be inside a try block
47
+ const tryPos = indexSrc.indexOf("try {");
48
+ const bootstrapImportPos = indexSrc.indexOf(
49
+ './bootstrap/register-extension.js"',
50
+ );
51
+ const catchPos = indexSrc.indexOf("catch (err)");
52
+
53
+ assert.ok(tryPos >= 0, "must have try block");
54
+ assert.ok(catchPos >= 0, "must have catch block");
55
+ assert.ok(
56
+ tryPos < bootstrapImportPos && bootstrapImportPos < catchPos,
57
+ "register-extension.js import must be wrapped in try-catch",
58
+ );
59
+ });
60
+
61
+ test("logs warning on bootstrap failure via workflow-logger", () => {
62
+ assert.ok(
63
+ indexSrc.includes("logWarning"),
64
+ "must use logWarning when bootstrap fails",
65
+ );
66
+ assert.ok(
67
+ indexSrc.includes("Extension setup partially failed"),
68
+ "warning message must indicate partial failure with /gsd still available",
69
+ );
70
+ });
71
+ });
72
+
73
+ // ─── register-extension.ts: no double-registration + defensive wrapping ───────
74
+
75
+ describe("register-extension.ts defensive registration", () => {
76
+ test("does NOT import or call registerGSDCommand (avoids double-registration)", () => {
77
+ // registerGSDCommand is now called by index.ts, not register-extension.ts
78
+ assert.ok(
79
+ !registerExtSrc.includes("import { registerGSDCommand }"),
80
+ "register-extension.ts must NOT import registerGSDCommand",
81
+ );
82
+
83
+ // Check the function body of registerGsdExtension doesn't call it
84
+ const funcBodyStart = registerExtSrc.indexOf(
85
+ "export function registerGsdExtension",
86
+ );
87
+ const funcBody = registerExtSrc.slice(funcBodyStart);
88
+ assert.ok(
89
+ !funcBody.includes("registerGSDCommand(pi)"),
90
+ "registerGsdExtension must NOT call registerGSDCommand(pi)",
91
+ );
92
+ });
93
+
94
+ test("still registers worktree, exit, and kill commands", () => {
95
+ const funcBodyStart = registerExtSrc.indexOf(
96
+ "export function registerGsdExtension",
97
+ );
98
+ const funcBody = registerExtSrc.slice(funcBodyStart);
99
+
100
+ assert.ok(
101
+ funcBody.includes("registerWorktreeCommand(pi)"),
102
+ "must register worktree command",
103
+ );
104
+ assert.ok(
105
+ funcBody.includes("registerExitCommand(pi)"),
106
+ "must register exit command",
107
+ );
108
+ assert.ok(
109
+ funcBody.includes('"kill"'),
110
+ "must register kill command",
111
+ );
112
+ });
113
+
114
+ test("wraps non-critical registrations in individual try-catch blocks", () => {
115
+ const funcBodyStart = registerExtSrc.indexOf(
116
+ "export function registerGsdExtension",
117
+ );
118
+ const funcBody = registerExtSrc.slice(funcBodyStart);
119
+
120
+ // Each non-critical registration should be wrapped with error handling
121
+ const registrationNames = [
122
+ "dynamic-tools",
123
+ "db-tools",
124
+ "journal-tools",
125
+ "query-tools",
126
+ "shortcuts",
127
+ "hooks",
128
+ ];
129
+
130
+ for (const name of registrationNames) {
131
+ assert.ok(
132
+ funcBody.includes(`"${name}"`),
133
+ `non-critical registration "${name}" must be present`,
134
+ );
135
+ }
136
+
137
+ // Must have try-catch inside the registration loop
138
+ assert.ok(
139
+ funcBody.includes("try {") && funcBody.includes("catch (err)"),
140
+ "must have try-catch for non-critical registrations",
141
+ );
142
+ });
143
+
144
+ test("logs warning when a non-critical registration fails", () => {
145
+ assert.ok(
146
+ registerExtSrc.includes("Failed to register"),
147
+ "must log descriptive warning for individual registration failures",
148
+ );
149
+ assert.ok(
150
+ registerExtSrc.includes("logWarning"),
151
+ "must use logWarning from workflow-logger",
152
+ );
153
+ });
154
+ });
@@ -26,6 +26,14 @@ import { MAX_FINALIZE_TIMEOUTS } from "../auto/types.ts";
26
26
 
27
27
  const { assertTrue, assertEq, report } = createTestContext();
28
28
 
29
+ function getRunFinalizeBody(phasesSource: string): string {
30
+ const fnIdx = phasesSource.indexOf("export async function runFinalize(");
31
+ assertTrue(fnIdx > 0, "runFinalize function should exist in phases.ts");
32
+
33
+ const nextExportIdx = phasesSource.indexOf("\nexport ", fnIdx + 1);
34
+ return phasesSource.slice(fnIdx, nextExportIdx > fnIdx ? nextExportIdx : undefined);
35
+ }
36
+
29
37
  // ═══ Test: withTimeout resolves when inner promise resolves promptly ══════════
30
38
 
31
39
  {
@@ -145,11 +153,7 @@ const { assertTrue, assertEq, report } = createTestContext();
145
153
  "utf-8",
146
154
  );
147
155
 
148
- // Find the runFinalize function body
149
- const fnIdx = phasesSource.indexOf("export async function runFinalize(");
150
- assertTrue(fnIdx > 0, "runFinalize function should exist in phases.ts");
151
-
152
- const fnBody = phasesSource.slice(fnIdx, fnIdx + 8000);
156
+ const fnBody = getRunFinalizeBody(phasesSource);
153
157
 
154
158
  // postUnitPreVerification must be wrapped in withTimeout
155
159
  const preTimeoutIdx = fnBody.indexOf("withTimeout(");
@@ -207,8 +211,7 @@ const { assertTrue, assertEq, report } = createTestContext();
207
211
  "utf-8",
208
212
  );
209
213
 
210
- const fnIdx = phasesSource.indexOf("export async function runFinalize(");
211
- const fnBody = phasesSource.slice(fnIdx, fnIdx + 8000);
214
+ const fnBody = getRunFinalizeBody(phasesSource);
212
215
 
213
216
  // Both timeout handlers should increment consecutiveFinalizeTimeouts
214
217
  const incrementCount = (fnBody.match(/consecutiveFinalizeTimeouts\+\+/g) || []).length;
@@ -0,0 +1,337 @@
1
+ /**
2
+ * graph-context.test.ts — Unit tests for inlineGraphSubgraph().
3
+ *
4
+ * Covers:
5
+ * Group 1: Null-return paths (empty term, zero nodes, missing graph.json)
6
+ * Group 2: Correct output formatting (nodes, edges, stale annotation)
7
+ * Group 3: Node formatting (description, confidence, no-description)
8
+ *
9
+ * Testing strategy:
10
+ * @gsd-build/mcp-server is dynamically imported inside inlineGraphSubgraph().
11
+ * Because node:test (v22) does not support mock.module() without the
12
+ * --experimental-test-module-mocks flag (not enabled in test:unit), we
13
+ * exercise the real graphQuery/graphStatus functions by controlling the
14
+ * on-disk graph.json that those functions read. This is a clean, deterministic
15
+ * approach that avoids all module-level mocking.
16
+ *
17
+ * Fixture layout per test:
18
+ * <tmpDir>/.gsd/graphs/graph.json
19
+ *
20
+ * builtAt controls staleness: old timestamp → stale, recent → fresh.
21
+ */
22
+
23
+ import { describe, it } from "node:test";
24
+ import assert from "node:assert/strict";
25
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
26
+ import { join } from "node:path";
27
+ import { tmpdir } from "node:os";
28
+
29
+ import { inlineGraphSubgraph } from "../graph-context.ts";
30
+
31
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
32
+
33
+ interface TestNode {
34
+ id: string;
35
+ label: string;
36
+ type: string;
37
+ confidence: string;
38
+ description?: string;
39
+ sourceFile?: string;
40
+ }
41
+
42
+ interface TestEdge {
43
+ from: string;
44
+ to: string;
45
+ type: string;
46
+ confidence: string;
47
+ }
48
+
49
+ interface GraphFixture {
50
+ nodes: TestNode[];
51
+ edges: TestEdge[];
52
+ /** ISO timestamp for graph.builtAt. Controls staleness. Default: recent (not stale). */
53
+ builtAt?: string;
54
+ }
55
+
56
+ /** Returns an ISO timestamp that is stale (> 24h ago). */
57
+ function staleTimestamp(hoursAgo = 26): string {
58
+ return new Date(Date.now() - hoursAgo * 60 * 60 * 1000).toISOString();
59
+ }
60
+
61
+ /** Returns an ISO timestamp that is fresh (< 24h ago). */
62
+ function freshTimestamp(): string {
63
+ return new Date(Date.now() - 30 * 60 * 1000).toISOString(); // 30 minutes ago
64
+ }
65
+
66
+ /**
67
+ * Creates a temp project directory with a .gsd/graphs/graph.json file.
68
+ * Returns the projectDir path. Caller is responsible for cleanup.
69
+ */
70
+ function makeProjectDir(fixture: GraphFixture): string {
71
+ const projectDir = mkdtempSync(join(tmpdir(), "graph-ctx-test-"));
72
+ const gsdDir = join(projectDir, ".gsd");
73
+ const graphsDir = join(gsdDir, "graphs");
74
+ mkdirSync(graphsDir, { recursive: true });
75
+
76
+ const graph = {
77
+ nodes: fixture.nodes,
78
+ edges: fixture.edges,
79
+ builtAt: fixture.builtAt ?? freshTimestamp(),
80
+ };
81
+
82
+ writeFileSync(join(graphsDir, "graph.json"), JSON.stringify(graph), "utf-8");
83
+ return projectDir;
84
+ }
85
+
86
+ /** Removes a temp directory, suppressing errors on Windows. */
87
+ function cleanup(dir: string): void {
88
+ try { rmSync(dir, { recursive: true, force: true }); } catch { /* ignore */ }
89
+ }
90
+
91
+ /** Minimal node factory. */
92
+ function makeNode(overrides: Partial<TestNode> & { id: string; label: string }): TestNode {
93
+ return {
94
+ type: "CLASS",
95
+ confidence: "INFERRED",
96
+ ...overrides,
97
+ };
98
+ }
99
+
100
+ /** Minimal edge factory. */
101
+ function makeEdge(overrides: Partial<TestEdge> & { from: string; to: string }): TestEdge {
102
+ return {
103
+ type: "CALLS",
104
+ confidence: "INFERRED",
105
+ ...overrides,
106
+ };
107
+ }
108
+
109
+ // ─── Group 1: Null returns ────────────────────────────────────────────────────
110
+
111
+ describe("inlineGraphSubgraph — null returns", () => {
112
+ it("returns null immediately for empty string term", async () => {
113
+ // No graph.json needed — exits before any file I/O
114
+ const result = await inlineGraphSubgraph("/tmp/nonexistent", "", { budget: 3000 });
115
+ assert.strictEqual(result, null);
116
+ });
117
+
118
+ it("returns null for whitespace-only term", async () => {
119
+ const result = await inlineGraphSubgraph("/tmp/nonexistent", " ", { budget: 3000 });
120
+ assert.strictEqual(result, null);
121
+ });
122
+
123
+ it("returns null when graphQuery returns zero nodes (no matching term in graph)", async () => {
124
+ const projectDir = makeProjectDir({
125
+ nodes: [makeNode({ id: "n1", label: "AuthService" })],
126
+ edges: [],
127
+ });
128
+ try {
129
+ // "zzznomatch999" is intentionally absent from the fixture
130
+ const result = await inlineGraphSubgraph(projectDir, "zzznomatch999", { budget: 3000 });
131
+ assert.strictEqual(result, null);
132
+ } finally {
133
+ cleanup(projectDir);
134
+ }
135
+ });
136
+
137
+ it("returns null (no throw) when graph.json is missing", async () => {
138
+ // A project dir with no .gsd directory at all — graphQuery returns zero nodes
139
+ const projectDir = mkdtempSync(join(tmpdir(), "graph-ctx-nofile-"));
140
+ try {
141
+ const result = await inlineGraphSubgraph(projectDir, "auth", { budget: 3000 });
142
+ assert.strictEqual(result, null);
143
+ } finally {
144
+ cleanup(projectDir);
145
+ }
146
+ });
147
+ });
148
+
149
+ // ─── Group 2: Correct output formatting ──────────────────────────────────────
150
+
151
+ describe("inlineGraphSubgraph — correct output", () => {
152
+ it("returns block with section header and node labels when term matches", async () => {
153
+ const projectDir = makeProjectDir({
154
+ nodes: [
155
+ makeNode({ id: "n1", label: "UserService" }),
156
+ makeNode({ id: "n2", label: "UserRepository" }),
157
+ ],
158
+ edges: [],
159
+ });
160
+ try {
161
+ const result = await inlineGraphSubgraph(projectDir, "User", { budget: 3000 });
162
+ assert.ok(result !== null, "result should not be null");
163
+ assert.ok(result!.includes("### Knowledge Graph Context"), "should include section header");
164
+ assert.ok(result!.includes("UserService"), "should include first node label");
165
+ assert.ok(result!.includes("UserRepository"), "should include second node label");
166
+ assert.ok(result!.includes("Nodes (2)"), "should show node count");
167
+ } finally {
168
+ cleanup(projectDir);
169
+ }
170
+ });
171
+
172
+ it("does not include Relations section when edges array is empty", async () => {
173
+ const projectDir = makeProjectDir({
174
+ nodes: [makeNode({ id: "n1", label: "AuthController" })],
175
+ edges: [],
176
+ });
177
+ try {
178
+ const result = await inlineGraphSubgraph(projectDir, "Auth", { budget: 3000 });
179
+ assert.ok(result !== null, "result should not be null");
180
+ assert.ok(!result!.includes("Relations"), "should not include Relations section for zero edges");
181
+ assert.ok(!result!.includes("⚠"), "should not include stale warning for fresh graph");
182
+ } finally {
183
+ cleanup(projectDir);
184
+ }
185
+ });
186
+
187
+ it("includes Relations section when edges are present", async () => {
188
+ const projectDir = makeProjectDir({
189
+ nodes: [
190
+ makeNode({ id: "n1", label: "AuthService" }),
191
+ makeNode({ id: "n2", label: "UserRepo" }),
192
+ ],
193
+ edges: [makeEdge({ from: "n1", to: "n2", type: "CALLS" })],
194
+ });
195
+ try {
196
+ const result = await inlineGraphSubgraph(projectDir, "Auth", { budget: 3000 });
197
+ assert.ok(result !== null, "result should not be null");
198
+ assert.ok(result!.includes("Relations (1)"), "should show edge count");
199
+ assert.ok(result!.includes("→[CALLS]→"), "should include edge type in arrow notation");
200
+ } finally {
201
+ cleanup(projectDir);
202
+ }
203
+ });
204
+
205
+ it("includes stale annotation when graph was built more than 24h ago", async () => {
206
+ const projectDir = makeProjectDir({
207
+ nodes: [makeNode({ id: "n1", label: "AuthService" })],
208
+ edges: [],
209
+ builtAt: staleTimestamp(26), // 26 hours ago → stale
210
+ });
211
+ try {
212
+ const result = await inlineGraphSubgraph(projectDir, "Auth", { budget: 3000 });
213
+ assert.ok(result !== null, "result should not be null");
214
+ assert.ok(result!.includes("⚠ Graph last built"), "should include stale annotation");
215
+ assert.ok(result!.includes("h ago"), "should include hours-ago text");
216
+ } finally {
217
+ cleanup(projectDir);
218
+ }
219
+ });
220
+
221
+ it("does not include stale annotation for a fresh graph", async () => {
222
+ const projectDir = makeProjectDir({
223
+ nodes: [makeNode({ id: "n1", label: "AuthService" })],
224
+ edges: [],
225
+ builtAt: freshTimestamp(), // 30 minutes ago → not stale
226
+ });
227
+ try {
228
+ const result = await inlineGraphSubgraph(projectDir, "Auth", { budget: 3000 });
229
+ assert.ok(result !== null, "result should not be null");
230
+ assert.ok(!result!.includes("⚠"), "should not include stale annotation for fresh graph");
231
+ } finally {
232
+ cleanup(projectDir);
233
+ }
234
+ });
235
+
236
+ it("returns valid block even when graph.json has corrupted builtAt (graphStatus throws internally)", async () => {
237
+ // Write a graph.json with an invalid builtAt — graphStatus will catch and return {exists: false}
238
+ // inlineGraphSubgraph should still return the node block without stale annotation
239
+ const projectDir = mkdtempSync(join(tmpdir(), "graph-ctx-corrupt-"));
240
+ const gsdDir = join(projectDir, ".gsd");
241
+ const graphsDir = join(gsdDir, "graphs");
242
+ mkdirSync(graphsDir, { recursive: true });
243
+
244
+ const graph = {
245
+ nodes: [{ id: "n1", label: "AuthController", type: "CLASS", confidence: "INFERRED" }],
246
+ edges: [],
247
+ builtAt: "NOT-A-DATE", // invalid ISO — will cause Date.now() - NaN to produce NaN
248
+ };
249
+ writeFileSync(join(graphsDir, "graph.json"), JSON.stringify(graph), "utf-8");
250
+
251
+ try {
252
+ const result = await inlineGraphSubgraph(projectDir, "Auth", { budget: 3000 });
253
+ // graphQuery reads the file and finds the node; graphStatus may return {exists: true, stale: false/true}
254
+ // Either way, function must not throw and must return a string with node content
255
+ assert.ok(result !== null, "result should not be null");
256
+ assert.ok(result!.includes("AuthController"), "should include node label");
257
+ } finally {
258
+ cleanup(projectDir);
259
+ }
260
+ });
261
+
262
+ it("passes the budget option to graphQuery (enforces node count limit)", async () => {
263
+ // Each node uses ~20 tokens. With budget=20, only ~1 node should be returned.
264
+ // Build a graph with many nodes all matching the same term.
265
+ const nodes: TestNode[] = Array.from({ length: 10 }, (_, i) =>
266
+ makeNode({ id: `n${i}`, label: `AuthModule${i}` })
267
+ );
268
+ const projectDir = makeProjectDir({ nodes, edges: [] });
269
+ try {
270
+ const resultSmall = await inlineGraphSubgraph(projectDir, "Auth", { budget: 20 });
271
+ const resultLarge = await inlineGraphSubgraph(projectDir, "Auth", { budget: 10000 });
272
+
273
+ // Both should return something (at least 1 node matches)
274
+ assert.ok(resultSmall !== null, "small-budget result should not be null");
275
+ assert.ok(resultLarge !== null, "large-budget result should not be null");
276
+
277
+ // With a very small budget (20 tokens ≈ 1 node), fewer nodes should appear
278
+ const smallNodeCount = (resultSmall!.match(/- \*\*/g) || []).length;
279
+ const largeNodeCount = (resultLarge!.match(/- \*\*/g) || []).length;
280
+ assert.ok(
281
+ smallNodeCount <= largeNodeCount,
282
+ `small-budget should return <= nodes than large-budget (got ${smallNodeCount} vs ${largeNodeCount})`,
283
+ );
284
+ } finally {
285
+ cleanup(projectDir);
286
+ }
287
+ });
288
+ });
289
+
290
+ // ─── Group 3: Node formatting ─────────────────────────────────────────────────
291
+
292
+ describe("inlineGraphSubgraph — node formatting", () => {
293
+ it("includes description after em-dash when node has description", async () => {
294
+ const projectDir = makeProjectDir({
295
+ nodes: [makeNode({ id: "n1", label: "JwtValidator", description: "JWT validation" })],
296
+ edges: [],
297
+ });
298
+ try {
299
+ const result = await inlineGraphSubgraph(projectDir, "Jwt", { budget: 3000 });
300
+ assert.ok(result !== null, "result should not be null");
301
+ assert.ok(result!.includes("— JWT validation"), "should include description after em-dash");
302
+ } finally {
303
+ cleanup(projectDir);
304
+ }
305
+ });
306
+
307
+ it("omits em-dash suffix when node has no description", async () => {
308
+ const projectDir = makeProjectDir({
309
+ nodes: [makeNode({ id: "n1", label: "TokenStore" })], // no description
310
+ edges: [],
311
+ });
312
+ try {
313
+ const result = await inlineGraphSubgraph(projectDir, "Token", { budget: 3000 });
314
+ assert.ok(result !== null, "result should not be null");
315
+ const lines = result!.split("\n");
316
+ const nodeLine = lines.find((l) => l.includes("TokenStore"));
317
+ assert.ok(nodeLine !== undefined, "node line should be present");
318
+ assert.ok(!nodeLine.includes("—"), "node line should not include em-dash when no description");
319
+ } finally {
320
+ cleanup(projectDir);
321
+ }
322
+ });
323
+
324
+ it("includes confidence tier in the node output line", async () => {
325
+ const projectDir = makeProjectDir({
326
+ nodes: [makeNode({ id: "n1", label: "AuthService", confidence: "EXTRACTED" })],
327
+ edges: [],
328
+ });
329
+ try {
330
+ const result = await inlineGraphSubgraph(projectDir, "Auth", { budget: 3000 });
331
+ assert.ok(result !== null, "result should not be null");
332
+ assert.ok(result!.includes("EXTRACTED"), "should include the confidence tier in node line");
333
+ } finally {
334
+ cleanup(projectDir);
335
+ }
336
+ });
337
+ });
@@ -80,7 +80,7 @@ describe('gsd-db', () => {
80
80
  // Check schema_version table
81
81
  const adapter = _getAdapter()!;
82
82
  const version = adapter.prepare('SELECT MAX(version) as version FROM schema_version').get();
83
- assert.deepStrictEqual(version?.['version'], 14, 'schema version should be 14');
83
+ assert.deepStrictEqual(version?.['version'], 15, 'schema version should be 15');
84
84
 
85
85
  // Check tables exist by querying them
86
86
  const dRows = adapter.prepare('SELECT count(*) as cnt FROM decisions').get();
@@ -198,7 +198,7 @@ test("session_start bootstraps the health widget alongside notifications", async
198
198
  },
199
199
  } as any;
200
200
 
201
- registerHooks(pi);
201
+ registerHooks(pi, []);
202
202
  const sessionStart = handlers.get("session_start");
203
203
  assert.ok(sessionStart, "session_start handler is registered");
204
204