gsd-pi 2.74.0-dev.b741afb → 2.74.0-dev.ffbcc03

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 (403) hide show
  1. package/dist/resources/extensions/gsd/activity-log.js +16 -0
  2. package/dist/resources/extensions/gsd/auto/loop.js +147 -10
  3. package/dist/resources/extensions/gsd/auto/phases.js +113 -3
  4. package/dist/resources/extensions/gsd/auto/session.js +10 -0
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +11 -1
  6. package/dist/resources/extensions/gsd/auto-model-selection.js +51 -5
  7. package/dist/resources/extensions/gsd/auto-post-unit.js +215 -8
  8. package/dist/resources/extensions/gsd/auto-recovery.js +24 -10
  9. package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
  10. package/dist/resources/extensions/gsd/auto-verification.js +100 -2
  11. package/dist/resources/extensions/gsd/auto.js +28 -2
  12. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +10 -1
  13. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +61 -9
  14. package/dist/resources/extensions/gsd/cache.js +16 -5
  15. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  16. package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
  17. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  18. package/dist/resources/extensions/gsd/docs/preferences-reference.md +14 -1
  19. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
  20. package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
  21. package/dist/resources/extensions/gsd/git-service.js +49 -1
  22. package/dist/resources/extensions/gsd/graph-context.js +98 -7
  23. package/dist/resources/extensions/gsd/gsd-db.js +260 -2
  24. package/dist/resources/extensions/gsd/guided-flow.js +24 -1
  25. package/dist/resources/extensions/gsd/init-wizard.js +1 -0
  26. package/dist/resources/extensions/gsd/journal.js +27 -0
  27. package/dist/resources/extensions/gsd/metrics.js +19 -0
  28. package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
  29. package/dist/resources/extensions/gsd/preferences-models.js +20 -3
  30. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  31. package/dist/resources/extensions/gsd/preferences-validation.js +108 -2
  32. package/dist/resources/extensions/gsd/preferences.js +26 -0
  33. package/dist/resources/extensions/gsd/safety/evidence-collector.js +15 -30
  34. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
  35. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  36. package/dist/resources/extensions/gsd/tools/complete-slice.js +5 -0
  37. package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
  38. package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
  39. package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
  40. package/dist/resources/extensions/gsd/uok/audit.js +40 -0
  41. package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
  42. package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
  43. package/dist/resources/extensions/gsd/uok/flags.js +29 -0
  44. package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
  45. package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
  46. package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
  47. package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
  48. package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
  49. package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
  50. package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
  51. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  52. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  53. package/dist/web/standalone/.next/BUILD_ID +1 -1
  54. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  55. package/dist/web/standalone/.next/build-manifest.json +2 -2
  56. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  57. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/index.html +1 -1
  79. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  86. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  87. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  89. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  90. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  91. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  92. package/package.json +1 -1
  93. package/packages/mcp-server/dist/readers/graph.d.ts +1 -1
  94. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -1
  95. package/packages/mcp-server/dist/readers/graph.js +107 -0
  96. package/packages/mcp-server/dist/readers/graph.js.map +1 -1
  97. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  98. package/packages/mcp-server/dist/workflow-tools.js +88 -6
  99. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  100. package/packages/mcp-server/src/readers/graph.test.ts +178 -0
  101. package/packages/mcp-server/src/readers/graph.ts +148 -1
  102. package/packages/mcp-server/src/workflow-tools.ts +95 -10
  103. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  104. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  105. package/packages/pi-ai/dist/index.d.ts +1 -9
  106. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  107. package/packages/pi-ai/dist/index.js +1 -9
  108. package/packages/pi-ai/dist/index.js.map +1 -1
  109. package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
  110. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
  111. package/packages/pi-ai/dist/models/capability-patches.js +36 -0
  112. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
  113. package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
  114. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
  115. package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
  116. package/packages/pi-ai/dist/models/custom.js.map +1 -0
  117. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
  118. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
  119. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
  120. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
  121. package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
  122. package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
  123. package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
  124. package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
  125. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
  126. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
  127. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
  128. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
  129. package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
  130. package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
  131. package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
  132. package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
  133. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
  134. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
  135. package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
  136. package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
  137. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
  138. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
  139. package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
  140. package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
  141. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
  142. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
  143. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
  144. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
  145. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
  146. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
  147. package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
  148. package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
  149. package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
  150. package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
  151. package/packages/pi-ai/dist/models/generated/google.js +464 -0
  152. package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
  153. package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
  154. package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
  155. package/packages/pi-ai/dist/models/generated/groq.js +311 -0
  156. package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
  157. package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
  158. package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
  159. package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
  160. package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
  161. package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
  162. package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
  163. package/packages/pi-ai/dist/models/generated/index.js +51 -0
  164. package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
  165. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
  166. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
  167. package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
  168. package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
  169. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
  170. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
  171. package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
  172. package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
  173. package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
  174. package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
  175. package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
  176. package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
  177. package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
  178. package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
  179. package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
  180. package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
  181. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
  182. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
  184. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
  185. package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
  186. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
  187. package/packages/pi-ai/dist/models/generated/openai.js +702 -0
  188. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
  189. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
  190. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
  191. package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
  192. package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
  193. package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
  194. package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
  195. package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
  196. package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
  197. package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
  198. package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
  199. package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
  200. package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
  201. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
  202. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
  203. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
  204. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
  205. package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
  206. package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
  207. package/packages/pi-ai/dist/models/generated/xai.js +413 -0
  208. package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
  209. package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
  210. package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
  211. package/packages/pi-ai/dist/models/generated/zai.js +239 -0
  212. package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
  213. package/packages/pi-ai/dist/models/index.d.ts +27 -0
  214. package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
  215. package/packages/pi-ai/dist/models/index.js +80 -0
  216. package/packages/pi-ai/dist/models/index.js.map +1 -0
  217. package/packages/pi-ai/dist/models.d.ts +1 -36
  218. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  219. package/packages/pi-ai/dist/models.generated.test.js +1 -2
  220. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  221. package/packages/pi-ai/dist/models.js +3 -112
  222. package/packages/pi-ai/dist/models.js.map +1 -1
  223. package/packages/pi-ai/dist/models.test.js +6 -5
  224. package/packages/pi-ai/dist/models.test.js.map +1 -1
  225. package/packages/pi-ai/scripts/generate-models.ts +74 -40
  226. package/packages/pi-ai/src/index.ts +1 -9
  227. package/packages/pi-ai/src/models/capability-patches.ts +40 -0
  228. package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
  229. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
  230. package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
  231. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  232. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  233. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  234. package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
  235. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  236. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  237. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  238. package/packages/pi-ai/src/models/generated/groq.ts +313 -0
  239. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  240. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  241. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  242. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  243. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  244. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  245. package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
  246. package/packages/pi-ai/src/models/generated/openai.ts +704 -0
  247. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  248. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  249. package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
  250. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  251. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  252. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  253. package/packages/pi-ai/src/models/index.ts +106 -0
  254. package/packages/pi-ai/src/models.generated.test.ts +1 -2
  255. package/packages/pi-ai/src/models.test.ts +6 -5
  256. package/packages/pi-ai/src/models.ts +3 -153
  257. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  258. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  259. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
  260. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +472 -0
  262. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
  264. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
  265. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
  266. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
  267. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  269. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +11 -0
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +23 -9
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +8 -0
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +68 -8
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
  286. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  288. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +232 -18
  289. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  290. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
  291. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
  292. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
  293. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
  294. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +14 -0
  295. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +70 -6
  297. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  298. package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
  299. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +612 -0
  300. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  301. package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
  302. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +19 -0
  303. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +25 -10
  304. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
  305. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +83 -7
  306. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
  307. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +298 -41
  308. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
  309. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +92 -6
  310. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  311. package/packages/pi-coding-agent/tsconfig.json +2 -2
  312. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  313. package/src/resources/extensions/gsd/activity-log.ts +21 -0
  314. package/src/resources/extensions/gsd/auto/loop-deps.ts +4 -0
  315. package/src/resources/extensions/gsd/auto/loop.ts +159 -10
  316. package/src/resources/extensions/gsd/auto/phases.ts +123 -3
  317. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  318. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -6
  319. package/src/resources/extensions/gsd/auto-model-selection.ts +66 -5
  320. package/src/resources/extensions/gsd/auto-post-unit.ts +226 -9
  321. package/src/resources/extensions/gsd/auto-recovery.ts +29 -9
  322. package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
  323. package/src/resources/extensions/gsd/auto-verification.ts +129 -2
  324. package/src/resources/extensions/gsd/auto.ts +34 -2
  325. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -1
  326. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +72 -8
  327. package/src/resources/extensions/gsd/cache.ts +16 -5
  328. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  329. package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
  330. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  331. package/src/resources/extensions/gsd/docs/preferences-reference.md +14 -1
  332. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
  333. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  334. package/src/resources/extensions/gsd/git-service.ts +68 -0
  335. package/src/resources/extensions/gsd/graph-context.ts +139 -12
  336. package/src/resources/extensions/gsd/gsd-db.ts +321 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +33 -1
  338. package/src/resources/extensions/gsd/init-wizard.ts +3 -2
  339. package/src/resources/extensions/gsd/journal.ts +30 -0
  340. package/src/resources/extensions/gsd/metrics.ts +26 -0
  341. package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
  342. package/src/resources/extensions/gsd/preferences-models.ts +20 -3
  343. package/src/resources/extensions/gsd/preferences-types.ts +32 -0
  344. package/src/resources/extensions/gsd/preferences-validation.ts +107 -2
  345. package/src/resources/extensions/gsd/preferences.ts +28 -0
  346. package/src/resources/extensions/gsd/safety/evidence-collector.ts +15 -31
  347. package/src/resources/extensions/gsd/session-lock.ts +14 -2
  348. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
  349. package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  350. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +177 -0
  351. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +7 -3
  352. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
  353. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
  354. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +272 -0
  355. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
  356. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
  357. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  358. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  359. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
  360. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  361. package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
  362. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
  363. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
  364. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  365. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
  366. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
  367. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
  368. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -5
  369. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  370. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
  371. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
  372. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
  373. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
  374. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
  375. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
  376. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  377. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
  378. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  379. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
  380. package/src/resources/extensions/gsd/tools/complete-slice.ts +9 -2
  381. package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
  382. package/src/resources/extensions/gsd/types.ts +14 -1
  383. package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
  384. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  385. package/src/resources/extensions/gsd/uok/audit.ts +51 -0
  386. package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
  387. package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
  388. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  389. package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
  390. package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
  391. package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
  392. package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
  393. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  394. package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
  395. package/src/resources/extensions/gsd/workflow-logger.ts +27 -1
  396. package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
  397. package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
  398. package/packages/pi-ai/dist/models.custom.js.map +0 -1
  399. package/packages/pi-ai/dist/models.generated.js +0 -14343
  400. package/packages/pi-ai/dist/models.generated.js.map +0 -1
  401. package/packages/pi-ai/src/models.generated.ts +0 -14345
  402. /package/dist/web/standalone/.next/static/{XnHY5eXUsTCFmNodWHetD → kn6xzWKYnogsxp2b6RpDD}/_buildManifest.js +0 -0
  403. /package/dist/web/standalone/.next/static/{XnHY5eXUsTCFmNodWHetD → kn6xzWKYnogsxp2b6RpDD}/_ssgManifest.js +0 -0
@@ -4,12 +4,14 @@
4
4
  * and fallback chains.
5
5
  */
6
6
  import { resolveModelWithFallbacksForUnit, resolveDynamicRoutingConfig } from "./preferences.js";
7
- import { classifyUnitComplexity, tierLabel } from "./complexity-classifier.js";
7
+ import { classifyUnitComplexity, extractTaskMetadata, tierLabel } from "./complexity-classifier.js";
8
8
  import { resolveModelForComplexity, escalateTier, getEligibleModels, loadCapabilityOverrides, adjustToolSet } from "./model-router.js";
9
9
  import { getLedger, getProjectTotals } from "./metrics.js";
10
10
  import { unitPhaseLabel } from "./auto-dashboard.js";
11
11
  import { getSessionModelOverride } from "./session-model-override.js";
12
12
  import { logWarning } from "./workflow-logger.js";
13
+ import { resolveUokFlags } from "./uok/flags.js";
14
+ import { applyModelPolicyFilter } from "./uok/model-policy.js";
13
15
  export function resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode = true) {
14
16
  const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
15
17
  if (explicitConfig)
@@ -46,6 +48,7 @@ export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, p
46
48
  isAutoMode = true,
47
49
  /** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
48
50
  sessionModelOverride) {
51
+ const uokFlags = resolveUokFlags(prefs);
49
52
  const effectiveSessionModelOverride = sessionModelOverride === undefined
50
53
  ? getSessionModelOverride(ctx.sessionManager.getSessionId())
51
54
  : (sessionModelOverride ?? undefined);
@@ -67,6 +70,9 @@ sessionModelOverride) {
67
70
  let appliedModel = null;
68
71
  if (modelConfig) {
69
72
  const availableModels = ctx.modelRegistry.getAvailable();
73
+ const modelPolicyTraceId = `model:${ctx.sessionManager.getSessionId()}:${Date.now()}`;
74
+ const modelPolicyTurnId = `${unitType}:${unitId}`;
75
+ let policyAllowedModelKeys = null;
70
76
  // ─── Dynamic Model Routing ─────────────────────────────────────────
71
77
  // Dynamic routing (complexity-based downgrading) only applies in auto-mode.
72
78
  // Interactive/guided-flow dispatches use the user's session model directly,
@@ -75,15 +81,40 @@ sessionModelOverride) {
75
81
  if (!isAutoMode) {
76
82
  routingConfig.enabled = false;
77
83
  }
84
+ // burn-max defaults to quality-first dispatch (no downgrade routing).
85
+ if (prefs?.token_profile === "burn-max") {
86
+ routingConfig.enabled = false;
87
+ }
78
88
  let effectiveModelConfig = modelConfig;
79
89
  let routingTierLabel = "";
90
+ let routingEligibleModels = availableModels;
91
+ const taskMetadataForPolicy = unitType === "execute-task"
92
+ ? extractTaskMetadata(unitId, basePath)
93
+ : undefined;
94
+ if (uokFlags.modelPolicy) {
95
+ const policy = applyModelPolicyFilter(availableModels, {
96
+ basePath,
97
+ traceId: modelPolicyTraceId,
98
+ turnId: modelPolicyTurnId,
99
+ unitType,
100
+ taskMetadata: taskMetadataForPolicy,
101
+ currentProvider: ctx.model?.provider,
102
+ allowCrossProvider: routingConfig.cross_provider !== false,
103
+ requiredTools: pi.getActiveTools(),
104
+ });
105
+ routingEligibleModels = policy.eligible;
106
+ policyAllowedModelKeys = new Set(policy.eligible.map((m) => `${m.provider.toLowerCase()}/${m.id.toLowerCase()}`));
107
+ if (routingEligibleModels.length === 0) {
108
+ throw new Error(`Model policy denied all candidate models for ${unitType}/${unitId}`);
109
+ }
110
+ }
80
111
  // Disable routing for flat-rate providers like GitHub Copilot (#3453).
81
112
  // All models cost the same per request, so downgrading to a cheaper
82
113
  // model provides no cost benefit — it only degrades quality.
83
114
  // Fail-closed: if primary model can't be resolved, fall back to
84
115
  // provider-level signals rather than allowing unwanted downgrades.
85
116
  if (routingConfig.enabled) {
86
- const primaryModel = resolveModelId(modelConfig.primary, availableModels, ctx.model?.provider);
117
+ const primaryModel = resolveModelId(modelConfig.primary, routingEligibleModels, ctx.model?.provider);
87
118
  if (primaryModel) {
88
119
  const primaryFlatRateCtx = buildFlatRateContext(primaryModel.provider, ctx, prefs);
89
120
  if (isFlatRateProvider(primaryModel.provider, primaryFlatRateCtx)) {
@@ -110,8 +141,8 @@ sessionModelOverride) {
110
141
  const isHook = unitType.startsWith("hook/");
111
142
  const shouldClassify = !isHook || routingConfig.hooks !== false;
112
143
  if (shouldClassify) {
113
- let classification = classifyUnitComplexity(unitType, unitId, basePath, budgetPct);
114
- const availableModelIds = availableModels.map(m => m.id);
144
+ let classification = classifyUnitComplexity(unitType, unitId, basePath, budgetPct, taskMetadataForPolicy);
145
+ const availableModelIds = routingEligibleModels.map(m => m.id);
115
146
  // Escalate tier on retry when escalate_on_failure is enabled (default: true)
116
147
  if (retryContext?.isRetry &&
117
148
  retryContext.previousTier &&
@@ -191,13 +222,25 @@ sessionModelOverride) {
191
222
  }
192
223
  }
193
224
  const modelsToTry = [effectiveModelConfig.primary, ...effectiveModelConfig.fallbacks];
225
+ let attemptedPolicyEligible = false;
194
226
  for (const modelId of modelsToTry) {
195
- const model = resolveModelId(modelId, availableModels, ctx.model?.provider);
227
+ const resolutionPool = uokFlags.modelPolicy ? routingEligibleModels : availableModels;
228
+ const model = resolveModelId(modelId, resolutionPool, ctx.model?.provider);
196
229
  if (!model) {
197
230
  if (verbose)
198
231
  ctx.ui.notify(`Model ${modelId} not found, trying fallback.`, "info");
199
232
  continue;
200
233
  }
234
+ if (policyAllowedModelKeys) {
235
+ const key = `${model.provider.toLowerCase()}/${model.id.toLowerCase()}`;
236
+ if (!policyAllowedModelKeys.has(key)) {
237
+ if (verbose) {
238
+ ctx.ui.notify(`Model policy denied ${model.provider}/${model.id}; trying fallback.`, "warning");
239
+ }
240
+ continue;
241
+ }
242
+ attemptedPolicyEligible = true;
243
+ }
201
244
  // Warn if the ID is ambiguous across providers
202
245
  if (!modelId.includes("/")) {
203
246
  const providers = availableModels.filter(m => m.id === modelId).map(m => m.provider);
@@ -255,6 +298,9 @@ sessionModelOverride) {
255
298
  }
256
299
  }
257
300
  }
301
+ if (uokFlags.modelPolicy && policyAllowedModelKeys && !attemptedPolicyEligible) {
302
+ throw new Error(`Model policy denied dispatch for ${unitType}/${unitId} before prompt send`);
303
+ }
258
304
  }
259
305
  else if (autoModeStartModel) {
260
306
  // No model preference for this unit type — re-apply the model captured
@@ -19,7 +19,7 @@ import { invalidateAllCaches } from "./cache.js";
19
19
  import { rebuildState } from "./doctor.js";
20
20
  import { parseUnitId } from "./unit-id.js";
21
21
  import { closeoutUnit } from "./auto-unit-closeout.js";
22
- import { autoCommitCurrentBranch, } from "./worktree.js";
22
+ import { runTurnGitAction, } from "./git-service.js";
23
23
  import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceholder, diagnoseExpectedArtifact, } from "./auto-recovery.js";
24
24
  import { regenerateIfMissing } from "./workflow-projections.js";
25
25
  import { syncStateToProjectRoot } from "./auto-worktree.js";
@@ -42,6 +42,9 @@ import { getSliceTasks } from "./gsd-db.js";
42
42
  import { runPreExecutionChecks } from "./pre-execution-checks.js";
43
43
  import { writePreExecutionEvidence } from "./verification-evidence.js";
44
44
  import { ensureCodebaseMapFresh } from "./codebase-generator.js";
45
+ import { resolveUokFlags } from "./uok/flags.js";
46
+ import { UokGateRunner } from "./uok/gate-runner.js";
47
+ import { writeTurnGitTransaction } from "./uok/gitops.js";
45
48
  /** Maximum verification retry attempts before escalating to blocker placeholder (#2653). */
46
49
  const MAX_VERIFICATION_RETRIES = 3;
47
50
  /** Enqueue a sidecar item (hook, triage, or quick-task) for the main loop to
@@ -71,6 +74,7 @@ import { describeNextUnit, } from "./auto-dashboard.js";
71
74
  import { existsSync, unlinkSync } from "node:fs";
72
75
  import { join } from "node:path";
73
76
  import { _resetHasChangesCache } from "./native-git-bridge.js";
77
+ import { autoCommitCurrentBranch } from "./worktree.js";
74
78
  /**
75
79
  * Detect summary files written directly to disk without the LLM calling
76
80
  * the completion tool. A "rogue" file is one that exists on disk but has
@@ -272,10 +276,154 @@ export async function postUnitPreVerification(pctx, opts) {
272
276
  if (!opts?.skipSettleDelay) {
273
277
  await new Promise(r => setTimeout(r, 100));
274
278
  }
275
- // Auto-commit
279
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
280
+ const uokFlags = resolveUokFlags(prefs);
281
+ // Turn-level git action (commit | snapshot | status-only)
276
282
  if (s.currentUnit) {
277
283
  const unit = s.currentUnit;
278
- await autoCommitUnit(s.basePath, unit.type, unit.id, ctx);
284
+ const turnAction = uokFlags.gitops ? uokFlags.gitopsTurnAction : "commit";
285
+ const traceId = s.currentTraceId ?? `turn:${unit.startedAt}`;
286
+ const turnId = s.currentTurnId ?? `${unit.type}/${unit.id}/${unit.startedAt}`;
287
+ s.lastGitActionFailure = null;
288
+ s.lastGitActionStatus = null;
289
+ try {
290
+ let taskContext;
291
+ if (turnAction === "commit" && s.currentUnit.type === "execute-task") {
292
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
293
+ if (mid && sid && tid) {
294
+ const summaryPath = resolveTaskFile(s.basePath, mid, sid, tid, "SUMMARY");
295
+ if (summaryPath) {
296
+ try {
297
+ const summaryContent = await loadFile(summaryPath);
298
+ if (summaryContent) {
299
+ const summary = parseSummary(summaryContent);
300
+ // Look up GitHub issue number for commit linking
301
+ let ghIssueNumber;
302
+ try {
303
+ const { getTaskIssueNumberForCommit } = await import("../github-sync/sync.js");
304
+ ghIssueNumber = getTaskIssueNumberForCommit(s.basePath, mid, sid, tid) ?? undefined;
305
+ }
306
+ catch (err) {
307
+ // GitHub sync not available — skip
308
+ logWarning("engine", `GitHub issue lookup failed: ${err instanceof Error ? err.message : String(err)}`);
309
+ }
310
+ taskContext = {
311
+ taskId: `${sid}/${tid}`,
312
+ taskTitle: summary.title?.replace(/^T\d+:\s*/, "") || tid,
313
+ oneLiner: summary.oneLiner || undefined,
314
+ keyFiles: summary.frontmatter.key_files?.filter(f => !f.includes("{{")) || undefined,
315
+ issueNumber: ghIssueNumber,
316
+ };
317
+ }
318
+ }
319
+ catch (e) {
320
+ debugLog("postUnit", { phase: "task-summary-parse", error: String(e) });
321
+ }
322
+ }
323
+ }
324
+ }
325
+ // Invalidate the nativeHasChanges cache before auto-commit (#1853).
326
+ // The cache has a 10-second TTL and is keyed by basePath. A stale
327
+ // `false` result causes autoCommit to skip staging entirely, leaving
328
+ // code files only in the working tree where they are destroyed by
329
+ // `git worktree remove --force` during teardown.
330
+ _resetHasChangesCache();
331
+ const skipLifecycleCommit = turnAction === "commit" && LIFECYCLE_ONLY_UNITS.has(s.currentUnit.type);
332
+ if (skipLifecycleCommit) {
333
+ debugLog("postUnit", {
334
+ phase: "git-action-skipped",
335
+ reason: "lifecycle-only-unit",
336
+ unitType: s.currentUnit.type,
337
+ unitId: s.currentUnit.id,
338
+ });
339
+ }
340
+ else {
341
+ const gitResult = runTurnGitAction({
342
+ basePath: s.basePath,
343
+ action: turnAction,
344
+ unitType: s.currentUnit.type,
345
+ unitId: s.currentUnit.id,
346
+ taskContext,
347
+ });
348
+ if (uokFlags.gitops) {
349
+ writeTurnGitTransaction({
350
+ basePath: s.basePath,
351
+ traceId,
352
+ turnId,
353
+ unitType: unit.type,
354
+ unitId: unit.id,
355
+ stage: "publish",
356
+ action: turnAction,
357
+ push: uokFlags.gitopsTurnPush,
358
+ status: gitResult.status,
359
+ error: gitResult.error,
360
+ metadata: {
361
+ dirty: gitResult.dirty,
362
+ commitMessage: gitResult.commitMessage,
363
+ snapshotLabel: gitResult.snapshotLabel,
364
+ },
365
+ });
366
+ }
367
+ if (gitResult.status === "failed") {
368
+ s.lastGitActionFailure = gitResult.error ?? `git ${turnAction} failed`;
369
+ s.lastGitActionStatus = "failed";
370
+ if (uokFlags.gitops && uokFlags.gates) {
371
+ const parsed = parseUnitId(unit.id);
372
+ const gateRunner = new UokGateRunner();
373
+ gateRunner.register({
374
+ id: "closeout-git-action",
375
+ type: "closeout",
376
+ execute: async () => ({
377
+ outcome: "fail",
378
+ failureClass: "git",
379
+ rationale: `turn git action "${turnAction}" failed`,
380
+ findings: gitResult.error ?? "unknown git failure",
381
+ }),
382
+ });
383
+ await gateRunner.run("closeout-git-action", {
384
+ basePath: s.basePath,
385
+ traceId,
386
+ turnId,
387
+ milestoneId: parsed.milestone ?? undefined,
388
+ sliceId: parsed.slice ?? undefined,
389
+ taskId: parsed.task ?? undefined,
390
+ unitType: unit.type,
391
+ unitId: unit.id,
392
+ });
393
+ }
394
+ const failureMsg = `Git ${turnAction} failed: ${(gitResult.error ?? "unknown error").split("\n")[0]}`;
395
+ if (uokFlags.gitops) {
396
+ ctx.ui.notify(failureMsg, "error");
397
+ await pauseAuto(ctx, pi);
398
+ return "dispatched";
399
+ }
400
+ ctx.ui.notify(failureMsg, "warning");
401
+ debugLog("postUnit", {
402
+ phase: "git-action-failed-nonblocking",
403
+ action: turnAction,
404
+ error: gitResult.error ?? "unknown error",
405
+ });
406
+ }
407
+ s.lastGitActionStatus = "ok";
408
+ if (turnAction === "commit" && gitResult.commitMessage) {
409
+ ctx.ui.notify(`Committed: ${gitResult.commitMessage.split("\n")[0]}`, "info");
410
+ }
411
+ else if (turnAction === "snapshot" && gitResult.snapshotLabel) {
412
+ ctx.ui.notify(`Snapshot recorded: ${gitResult.snapshotLabel}`, "info");
413
+ }
414
+ }
415
+ }
416
+ catch (e) {
417
+ const message = e instanceof Error ? e.message : String(e);
418
+ s.lastGitActionFailure = message;
419
+ s.lastGitActionStatus = "failed";
420
+ debugLog("postUnit", { phase: "git-action", error: message, action: turnAction });
421
+ ctx.ui.notify(`Git ${turnAction} failed: ${message.split("\n")[0]}`, uokFlags.gitops ? "error" : "warning");
422
+ if (uokFlags.gitops) {
423
+ await pauseAuto(ctx, pi);
424
+ return "dispatched";
425
+ }
426
+ }
279
427
  // GitHub sync (non-blocking, opt-in)
280
428
  await runSafely("postUnit", "github-sync", async () => {
281
429
  const { runGitHubSync } = await import("../github-sync/sync.js");
@@ -710,11 +858,13 @@ export async function postUnitPostVerification(pctx) {
710
858
  // ── Pre-execution checks (after plan-slice completes) ──
711
859
  if (s.currentUnit &&
712
860
  s.currentUnit.type === "plan-slice") {
861
+ const currentUnit = s.currentUnit;
713
862
  let preExecPauseNeeded = false;
714
863
  await runSafely("postUnitPostVerification", "pre-execution-checks", async () => {
864
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
865
+ const uokFlags = resolveUokFlags(prefs);
715
866
  try {
716
867
  // Check preferences — respect enhanced_verification and enhanced_verification_pre
717
- const prefs = loadEffectiveGSDPreferences()?.preferences;
718
868
  const enhancedEnabled = prefs?.enhanced_verification !== false; // default true
719
869
  const preEnabled = prefs?.enhanced_verification_pre !== false; // default true
720
870
  if (!enhancedEnabled || !preEnabled) {
@@ -726,7 +876,7 @@ export async function postUnitPostVerification(pctx) {
726
876
  return;
727
877
  }
728
878
  // Parse the unit ID to get milestone/slice IDs
729
- const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
879
+ const { milestone: mid, slice: sid } = parseUnitId(currentUnit.id);
730
880
  if (!mid || !sid) {
731
881
  debugLog("postUnitPostVerification", {
732
882
  phase: "pre-execution-checks",
@@ -745,6 +895,7 @@ export async function postUnitPostVerification(pctx) {
745
895
  });
746
896
  return;
747
897
  }
898
+ const strictMode = prefs?.enhanced_verification_strict === true;
748
899
  // Run pre-execution checks
749
900
  const result = await runPreExecutionChecks(tasks, s.basePath);
750
901
  // Log summary to stderr in existing verification output format
@@ -760,10 +911,43 @@ export async function postUnitPostVerification(pctx) {
760
911
  if (slicePath) {
761
912
  writePreExecutionEvidence(result, slicePath, mid, sid);
762
913
  }
763
- // Notify UI
914
+ if (uokFlags.gates) {
915
+ const failedChecks = result.checks
916
+ .filter((check) => !check.passed)
917
+ .map((check) => `[${check.category}] ${check.target}: ${check.message}`);
918
+ const warnEscalated = result.status === "warn" && strictMode;
919
+ const blockingFailure = result.status === "fail" || warnEscalated;
920
+ const gateRunner = new UokGateRunner();
921
+ gateRunner.register({
922
+ id: "pre-execution-checks",
923
+ type: "input",
924
+ execute: async () => ({
925
+ outcome: blockingFailure ? "fail" : "pass",
926
+ failureClass: result.status === "fail" ? "input" : warnEscalated ? "policy" : "none",
927
+ rationale: blockingFailure
928
+ ? `pre-execution checks ${result.status}${warnEscalated ? " (strict)" : ""}`
929
+ : "pre-execution checks passed",
930
+ findings: failedChecks.join("\n"),
931
+ }),
932
+ });
933
+ await gateRunner.run("pre-execution-checks", {
934
+ basePath: s.basePath,
935
+ traceId: `pre-execution:${currentUnit.id}`,
936
+ turnId: currentUnit.id,
937
+ milestoneId: mid,
938
+ sliceId: sid,
939
+ unitType: currentUnit.type,
940
+ unitId: currentUnit.id,
941
+ });
942
+ }
943
+ // Notify UI — surface actionable details (#4259)
764
944
  if (result.status === "fail") {
765
- const blockingCount = result.checks.filter(c => !c.passed && c.blocking).length;
766
- ctx.ui.notify(`Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found`, "error");
945
+ const blockingChecks = result.checks.filter(c => !c.passed && c.blocking);
946
+ const blockingCount = blockingChecks.length;
947
+ const details = blockingChecks.slice(0, 3).map(c => ` \u2022 ${c.message}`).join("\n");
948
+ const suffix = blockingChecks.length > 3 ? `\n \u2022 ...and ${blockingChecks.length - 3} more` : "";
949
+ const evidenceNote = `\nSee ${sid}-PRE-EXEC-VERIFY.json for full details.`;
950
+ ctx.ui.notify(`Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found\n${details}${suffix}${evidenceNote}`, "error");
767
951
  preExecPauseNeeded = true;
768
952
  }
769
953
  else if (result.status === "warn") {
@@ -790,6 +974,29 @@ export async function postUnitPostVerification(pctx) {
790
974
  });
791
975
  logError("engine", `gsd-pre-exec: Pre-execution checks threw an error: ${errorMessage}`);
792
976
  ctx.ui.notify(`Pre-execution checks error: ${errorMessage} — pausing for human review`, "error");
977
+ if (uokFlags.gates && s.currentUnit) {
978
+ const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
979
+ const gateRunner = new UokGateRunner();
980
+ gateRunner.register({
981
+ id: "pre-execution-checks",
982
+ type: "input",
983
+ execute: async () => ({
984
+ outcome: "manual-attention",
985
+ failureClass: "manual-attention",
986
+ rationale: "pre-execution checks threw before completion",
987
+ findings: errorMessage,
988
+ }),
989
+ });
990
+ await gateRunner.run("pre-execution-checks", {
991
+ basePath: s.basePath,
992
+ traceId: `pre-execution:${s.currentUnit.id}`,
993
+ turnId: s.currentUnit.id,
994
+ milestoneId: mid ?? undefined,
995
+ sliceId: sid ?? undefined,
996
+ unitType: s.currentUnit.type,
997
+ unitId: s.currentUnit.id,
998
+ });
999
+ }
793
1000
  preExecPauseNeeded = true;
794
1001
  }
795
1002
  });
@@ -215,20 +215,28 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
215
215
  const absPath = resolveExpectedArtifactPath(unitType, unitId, base);
216
216
  // For unit types with no verifiable artifact (null path), the parent directory
217
217
  // is missing on disk — treat as stale completion state so the key gets evicted (#313).
218
- if (!absPath)
218
+ if (!absPath) {
219
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: resolveExpectedArtifactPath returned null (parent dir missing)`);
219
220
  return false;
220
- if (!existsSync(absPath))
221
+ }
222
+ if (!existsSync(absPath)) {
223
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: existsSync false for ${absPath}`);
221
224
  return false;
225
+ }
222
226
  if (unitType === "validate-milestone") {
223
227
  const validationContent = readFileSync(absPath, "utf-8");
224
- if (!isValidationTerminal(validationContent))
228
+ if (!isValidationTerminal(validationContent)) {
229
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: validation not terminal (len=${validationContent.length}) at ${absPath}`);
225
230
  return false;
231
+ }
226
232
  }
227
233
  if (unitType === "plan-milestone") {
228
234
  try {
229
235
  const roadmap = parseLegacyRoadmap(readFileSync(absPath, "utf-8"));
230
- if (roadmap.slices.length === 0)
236
+ if (roadmap.slices.length === 0) {
237
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: roadmap has zero slices at ${absPath}`);
231
238
  return false;
239
+ }
232
240
  }
233
241
  catch (err) {
234
242
  logWarning("recovery", `plan-milestone roadmap verification failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -245,8 +253,10 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
245
253
  // Accept checkbox-style (- [x] **T01: ...) or heading-style (### T01 -- / ### T01: / ### T01 —)
246
254
  const hasCheckboxTask = /^- \[[xX ]\] \*\*T\d+:/m.test(planContent);
247
255
  const hasHeadingTask = /^#{2,4}\s+T\d+\s*(?:--|—|:)/m.test(planContent);
248
- if (!hasCheckboxTask && !hasHeadingTask)
256
+ if (!hasCheckboxTask && !hasHeadingTask) {
257
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: plan has no task checkbox/heading (len=${planContent.length}) at ${absPath}`);
249
258
  return false;
259
+ }
250
260
  }
251
261
  // execute-task: DB status is authoritative. Fall back to checked-checkbox
252
262
  // detection when the DB is unavailable (unmigrated projects).
@@ -306,11 +316,15 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
306
316
  }
307
317
  if (taskIds && taskIds.length > 0) {
308
318
  const tasksDir = resolveTasksDir(base, mid, sid);
309
- if (tasksDir) {
310
- for (const tid of taskIds) {
311
- const taskPlanFile = join(tasksDir, `${tid}-PLAN.md`);
312
- if (!existsSync(taskPlanFile))
313
- return false;
319
+ if (!tasksDir) {
320
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: resolveTasksDir returned null for ${mid}/${sid}`);
321
+ return false;
322
+ }
323
+ for (const tid of taskIds) {
324
+ const taskPlanFile = join(tasksDir, `${tid}-PLAN.md`);
325
+ if (!existsSync(taskPlanFile)) {
326
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: task plan missing ${taskPlanFile}`);
327
+ return false;
314
328
  }
315
329
  }
316
330
  }
@@ -6,6 +6,7 @@
6
6
  import { snapshotUnitMetrics } from "./metrics.js";
7
7
  import { saveActivityLog } from "./activity-log.js";
8
8
  import { logWarning } from "./workflow-logger.js";
9
+ import { writeTurnGitTransaction } from "./uok/gitops.js";
9
10
  /**
10
11
  * Snapshot metrics, save activity log, and fire-and-forget memory extraction
11
12
  * for a completed unit. Returns the activity log file path (if any).
@@ -28,5 +29,22 @@ export async function closeoutUnit(ctx, basePath, unitType, unitId, startedAt, o
28
29
  logWarning("engine", `operation failed: ${err instanceof Error ? err.message : String(err)}`);
29
30
  }
30
31
  }
32
+ if (opts?.traceId && opts.turnId && opts.gitAction && opts.gitStatus) {
33
+ writeTurnGitTransaction({
34
+ basePath,
35
+ traceId: opts.traceId,
36
+ turnId: opts.turnId,
37
+ unitType,
38
+ unitId,
39
+ stage: "record",
40
+ action: opts.gitAction,
41
+ push: opts.gitPush === true,
42
+ status: opts.gitStatus,
43
+ error: opts.gitError,
44
+ metadata: {
45
+ activityFile,
46
+ },
47
+ });
48
+ }
31
49
  return activityFile ?? undefined;
32
50
  }
@@ -24,6 +24,8 @@ import { writeVerificationJSON } from "./verification-evidence.js";
24
24
  import { logWarning } from "./workflow-logger.js";
25
25
  import { runPostExecutionChecks } from "./post-execution-checks.js";
26
26
  import { join } from "node:path";
27
+ import { resolveUokFlags } from "./uok/flags.js";
28
+ import { UokGateRunner } from "./uok/gate-runner.js";
27
29
  function isInfraVerificationFailure(stderr) {
28
30
  return /\b(ENOENT|ENOTFOUND|ETIMEDOUT|ECONNRESET|EAI_AGAIN|spawn\s+\S+\s+ENOENT|command not found)\b/i.test(stderr);
29
31
  }
@@ -43,6 +45,31 @@ function isInfraVerificationFailure(stderr) {
43
45
  */
44
46
  async function runValidateMilestonePostCheck(vctx, pauseAuto) {
45
47
  const { s, ctx, pi } = vctx;
48
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
49
+ const uokFlags = resolveUokFlags(prefs);
50
+ const persistMilestoneValidationGate = async (outcome, failureClass, rationale, findings = "", milestoneId) => {
51
+ if (!uokFlags.gates || !s.currentUnit)
52
+ return;
53
+ const gateRunner = new UokGateRunner();
54
+ gateRunner.register({
55
+ id: "milestone-validation-post-check",
56
+ type: "verification",
57
+ execute: async () => ({
58
+ outcome,
59
+ failureClass,
60
+ rationale,
61
+ findings,
62
+ }),
63
+ });
64
+ await gateRunner.run("milestone-validation-post-check", {
65
+ basePath: s.basePath,
66
+ traceId: `validation-post-check:${s.currentUnit.id}`,
67
+ turnId: s.currentUnit.id,
68
+ milestoneId,
69
+ unitType: s.currentUnit.type,
70
+ unitId: s.currentUnit.id,
71
+ });
72
+ };
46
73
  if (!s.currentUnit)
47
74
  return "continue";
48
75
  const { milestone: mid } = parseUnitId(s.currentUnit.id);
@@ -55,17 +82,22 @@ async function runValidateMilestonePostCheck(vctx, pauseAuto) {
55
82
  if (!validationContent)
56
83
  return "continue";
57
84
  const verdict = extractVerdict(validationContent);
58
- if (verdict !== "needs-remediation")
85
+ if (verdict !== "needs-remediation") {
86
+ await persistMilestoneValidationGate("pass", "none", `milestone validation verdict is ${verdict}; no remediation loop risk`, "", mid);
59
87
  return "continue";
88
+ }
60
89
  const incompleteSliceCount = await countIncompleteSlices(s.basePath, mid);
61
90
  // If any non-closed slices exist, the agent successfully queued remediation
62
91
  // work — proceed normally. The state machine will execute those slices and
63
92
  // re-validate per the #3596/#3670 fix.
64
- if (incompleteSliceCount > 0)
93
+ if (incompleteSliceCount > 0) {
94
+ await persistMilestoneValidationGate("pass", "none", `remediation slices present (${incompleteSliceCount}); validation can continue`, "", mid);
65
95
  return "continue";
96
+ }
66
97
  ctx.ui.notify(`Milestone ${mid} validation returned verdict=needs-remediation but no remediation slices were added. Pausing for human review.`, "error");
67
98
  process.stderr.write(`validate-milestone: pausing — verdict=needs-remediation with no incomplete slices for ${mid}. ` +
68
99
  `The agent must call gsd_reassess_roadmap to add remediation slices before re-validation.\n`);
100
+ await persistMilestoneValidationGate("manual-attention", "manual-attention", "needs-remediation verdict without queued remediation slices", `No incomplete slices found for ${mid} while verdict=needs-remediation`, mid);
69
101
  await pauseAuto(ctx, pi);
70
102
  return "pause";
71
103
  }
@@ -122,6 +154,7 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
122
154
  try {
123
155
  const effectivePrefs = loadEffectiveGSDPreferences();
124
156
  const prefs = effectivePrefs?.preferences;
157
+ const uokFlags = resolveUokFlags(prefs);
125
158
  // Read task plan verify field
126
159
  const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
127
160
  let taskPlanVerify;
@@ -153,6 +186,35 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
153
186
  process.stderr.write(` [${w.severity}] ${w.name}: ${w.title}\n`);
154
187
  }
155
188
  }
189
+ if (uokFlags.gates) {
190
+ const gateRunner = new UokGateRunner();
191
+ gateRunner.register({
192
+ id: "verification-gate",
193
+ type: "verification",
194
+ execute: async () => ({
195
+ outcome: result.passed ? "pass" : "fail",
196
+ failureClass: result.runtimeErrors?.some((e) => e.blocking)
197
+ ? "execution"
198
+ : "verification",
199
+ rationale: result.passed
200
+ ? "verification checks passed"
201
+ : "verification checks failed",
202
+ findings: result.passed
203
+ ? ""
204
+ : formatFailureContext(result),
205
+ }),
206
+ });
207
+ await gateRunner.run("verification-gate", {
208
+ basePath: s.basePath,
209
+ traceId: `verification:${s.currentUnit.id}`,
210
+ turnId: s.currentUnit.id,
211
+ milestoneId: mid ?? undefined,
212
+ sliceId: sid ?? undefined,
213
+ taskId: tid ?? undefined,
214
+ unitType: s.currentUnit.type,
215
+ unitId: s.currentUnit.id,
216
+ });
217
+ }
156
218
  // Auto-fix retry preferences
157
219
  const autoFixEnabled = prefs?.verification_auto_fix !== false;
158
220
  const maxRetries = typeof prefs?.verification_max_retries === "number"
@@ -253,6 +315,42 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
253
315
  : "⚠";
254
316
  process.stderr.write(`gsd-post-exec: ${checkEmoji} [${check.category}] ${check.target}: ${check.message}\n`);
255
317
  }
318
+ if (uokFlags.gates) {
319
+ const strictMode = prefs?.enhanced_verification_strict === true;
320
+ const warnEscalated = postExecResult.status === "warn" && strictMode;
321
+ const blockingFailure = postExecResult.status === "fail" || warnEscalated;
322
+ const findings = postExecResult.checks
323
+ .filter((check) => !check.passed)
324
+ .map((check) => `[${check.category}] ${check.target}: ${check.message}`)
325
+ .join("\n");
326
+ const gateRunner = new UokGateRunner();
327
+ gateRunner.register({
328
+ id: "post-execution-checks",
329
+ type: "artifact",
330
+ execute: async () => ({
331
+ outcome: blockingFailure ? "fail" : "pass",
332
+ failureClass: postExecResult.status === "fail"
333
+ ? "artifact"
334
+ : warnEscalated
335
+ ? "policy"
336
+ : "none",
337
+ rationale: blockingFailure
338
+ ? `post-execution checks ${postExecResult.status}${warnEscalated ? " (strict)" : ""}`
339
+ : "post-execution checks passed",
340
+ findings,
341
+ }),
342
+ });
343
+ await gateRunner.run("post-execution-checks", {
344
+ basePath: s.basePath,
345
+ traceId: `verification:${s.currentUnit.id}`,
346
+ turnId: s.currentUnit.id,
347
+ milestoneId: mid,
348
+ sliceId: sid,
349
+ taskId: tid,
350
+ unitType: s.currentUnit.type,
351
+ unitId: s.currentUnit.id,
352
+ });
353
+ }
256
354
  // Check for blocking failures
257
355
  if (postExecResult.status === "fail") {
258
356
  postExecBlockingFailure = true;