gsd-pi 2.73.1-dev.d987996 → 2.74.0-dev.14c45ac

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 (365) hide show
  1. package/dist/cli-web-branch.d.ts +4 -3
  2. package/dist/cli-web-branch.js +10 -7
  3. package/dist/cli.js +184 -206
  4. package/dist/headless-query.js +4 -1
  5. package/dist/help-text.js +23 -0
  6. package/dist/logo.d.ts +1 -1
  7. package/dist/logo.js +1 -1
  8. package/dist/onboarding.js +59 -53
  9. package/dist/resource-loader.js +2 -2
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +68 -4
  11. package/dist/resources/extensions/gsd/activity-log.js +16 -0
  12. package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
  13. package/dist/resources/extensions/gsd/auto/loop.js +147 -10
  14. package/dist/resources/extensions/gsd/auto/phases.js +173 -13
  15. package/dist/resources/extensions/gsd/auto/session.js +10 -0
  16. package/dist/resources/extensions/gsd/auto-dispatch.js +22 -4
  17. package/dist/resources/extensions/gsd/auto-model-selection.js +105 -16
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +254 -15
  19. package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
  20. package/dist/resources/extensions/gsd/auto-start.js +23 -6
  21. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
  22. package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
  23. package/dist/resources/extensions/gsd/auto-verification.js +186 -3
  24. package/dist/resources/extensions/gsd/auto.js +65 -12
  25. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +21 -8
  26. package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
  27. package/dist/resources/extensions/gsd/commands/handlers/ops.js +25 -0
  28. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
  29. package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
  30. package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
  31. package/dist/resources/extensions/gsd/commands-do.js +79 -0
  32. package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
  33. package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
  34. package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
  35. package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
  36. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  37. package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
  38. package/dist/resources/extensions/gsd/commands-ship.js +187 -0
  39. package/dist/resources/extensions/gsd/db-writer.js +3 -5
  40. package/dist/resources/extensions/gsd/docs/preferences-reference.md +15 -2
  41. package/dist/resources/extensions/gsd/git-service.js +49 -1
  42. package/dist/resources/extensions/gsd/graph-context.js +157 -0
  43. package/dist/resources/extensions/gsd/gsd-db.js +581 -2
  44. package/dist/resources/extensions/gsd/guided-flow.js +23 -0
  45. package/dist/resources/extensions/gsd/index.js +15 -2
  46. package/dist/resources/extensions/gsd/init-wizard.js +1 -0
  47. package/dist/resources/extensions/gsd/journal.js +27 -0
  48. package/dist/resources/extensions/gsd/md-importer.js +3 -4
  49. package/dist/resources/extensions/gsd/memory-store.js +19 -51
  50. package/dist/resources/extensions/gsd/metrics.js +19 -0
  51. package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
  52. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
  53. package/dist/resources/extensions/gsd/notification-widget.js +2 -2
  54. package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
  55. package/dist/resources/extensions/gsd/preferences-models.js +63 -3
  56. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  57. package/dist/resources/extensions/gsd/preferences-validation.js +130 -2
  58. package/dist/resources/extensions/gsd/preferences.js +26 -0
  59. package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
  60. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
  61. package/dist/resources/extensions/gsd/state.js +66 -15
  62. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  63. package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -0
  64. package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
  65. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
  66. package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
  67. package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
  68. package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
  69. package/dist/resources/extensions/gsd/uok/audit.js +40 -0
  70. package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
  71. package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
  72. package/dist/resources/extensions/gsd/uok/flags.js +29 -0
  73. package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
  74. package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
  75. package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
  76. package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
  77. package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
  78. package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
  79. package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
  80. package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
  81. package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
  82. package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
  83. package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
  84. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  86. package/dist/update-check.d.ts +1 -0
  87. package/dist/update-check.js +13 -5
  88. package/dist/update-cmd.js +4 -3
  89. package/dist/web/standalone/.next/BUILD_ID +1 -1
  90. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  91. package/dist/web/standalone/.next/build-manifest.json +2 -2
  92. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  93. package/dist/web/standalone/.next/required-server-files.json +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.html +1 -1
  111. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  118. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  120. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  121. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  122. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  123. package/dist/web/standalone/server.js +1 -1
  124. package/package.json +3 -3
  125. package/packages/daemon/package.json +2 -2
  126. package/packages/mcp-server/dist/index.d.ts +3 -0
  127. package/packages/mcp-server/dist/index.d.ts.map +1 -1
  128. package/packages/mcp-server/dist/index.js +3 -0
  129. package/packages/mcp-server/dist/index.js.map +1 -1
  130. package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
  131. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
  132. package/packages/mcp-server/dist/readers/graph.js +655 -0
  133. package/packages/mcp-server/dist/readers/graph.js.map +1 -0
  134. package/packages/mcp-server/dist/readers/index.d.ts +2 -0
  135. package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
  136. package/packages/mcp-server/dist/readers/index.js +1 -0
  137. package/packages/mcp-server/dist/readers/index.js.map +1 -1
  138. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  139. package/packages/mcp-server/dist/server.js +65 -0
  140. package/packages/mcp-server/dist/server.js.map +1 -1
  141. package/packages/mcp-server/package.json +2 -2
  142. package/packages/mcp-server/src/index.ts +15 -0
  143. package/packages/mcp-server/src/readers/graph.test.ts +604 -0
  144. package/packages/mcp-server/src/readers/graph.ts +855 -0
  145. package/packages/mcp-server/src/readers/index.ts +12 -0
  146. package/packages/mcp-server/src/server.ts +83 -0
  147. package/packages/mcp-server/tsconfig.json +1 -0
  148. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
  149. package/packages/native/package.json +2 -2
  150. package/packages/native/tsconfig.tsbuildinfo +1 -0
  151. package/packages/pi-agent-core/package.json +1 -1
  152. package/packages/pi-agent-core/tsconfig.json +1 -0
  153. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
  154. package/packages/pi-ai/dist/index.d.ts +1 -0
  155. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  156. package/packages/pi-ai/dist/index.js +1 -0
  157. package/packages/pi-ai/dist/index.js.map +1 -1
  158. package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  159. package/packages/pi-ai/dist/utils/overflow.js +12 -0
  160. package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
  161. package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
  162. package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
  163. package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
  164. package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
  165. package/packages/pi-ai/package.json +1 -1
  166. package/packages/pi-ai/src/index.ts +4 -0
  167. package/packages/pi-ai/src/utils/overflow.ts +14 -1
  168. package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
  169. package/packages/pi-ai/tsconfig.json +1 -0
  170. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
  171. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +511 -8
  172. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
  174. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
  177. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
  178. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
  180. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
  181. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
  182. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
  183. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  185. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
  187. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  188. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +61 -28
  189. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  190. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -1
  191. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +9 -3
  193. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
  195. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
  196. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
  197. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
  198. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  199. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +165 -20
  200. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  201. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +11 -3
  203. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  204. package/packages/pi-coding-agent/package.json +1 -1
  205. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +620 -8
  206. package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
  207. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
  208. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  209. package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
  210. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +74 -32
  211. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
  212. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
  213. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +189 -25
  214. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +11 -3
  215. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  216. package/packages/pi-coding-agent/tsconfig.json +3 -2
  217. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
  218. package/packages/pi-tui/dist/__tests__/tui.test.js +60 -1
  219. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  220. package/packages/pi-tui/dist/tui.d.ts +8 -0
  221. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  222. package/packages/pi-tui/dist/tui.js +32 -3
  223. package/packages/pi-tui/dist/tui.js.map +1 -1
  224. package/packages/pi-tui/package.json +1 -1
  225. package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
  226. package/packages/pi-tui/src/tui.ts +31 -3
  227. package/packages/pi-tui/tsconfig.json +1 -0
  228. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
  229. package/packages/rpc-client/package.json +1 -1
  230. package/packages/rpc-client/tsconfig.json +1 -0
  231. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
  232. package/pkg/package.json +1 -1
  233. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +107 -5
  234. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +111 -2
  235. package/src/resources/extensions/gsd/activity-log.ts +21 -0
  236. package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
  237. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -0
  238. package/src/resources/extensions/gsd/auto/loop.ts +159 -10
  239. package/src/resources/extensions/gsd/auto/phases.ts +213 -13
  240. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  241. package/src/resources/extensions/gsd/auto-dispatch.ts +26 -10
  242. package/src/resources/extensions/gsd/auto-model-selection.ts +151 -16
  243. package/src/resources/extensions/gsd/auto-post-unit.ts +278 -16
  244. package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
  245. package/src/resources/extensions/gsd/auto-start.ts +30 -6
  246. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
  247. package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
  248. package/src/resources/extensions/gsd/auto-verification.ts +225 -3
  249. package/src/resources/extensions/gsd/auto.ts +72 -16
  250. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -8
  251. package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
  252. package/src/resources/extensions/gsd/commands/handlers/ops.ts +25 -0
  253. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
  254. package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
  255. package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
  256. package/src/resources/extensions/gsd/commands-do.ts +109 -0
  257. package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
  258. package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
  259. package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
  260. package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
  261. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  262. package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
  263. package/src/resources/extensions/gsd/commands-ship.ts +219 -0
  264. package/src/resources/extensions/gsd/db-writer.ts +3 -5
  265. package/src/resources/extensions/gsd/docs/preferences-reference.md +15 -2
  266. package/src/resources/extensions/gsd/git-service.ts +68 -0
  267. package/src/resources/extensions/gsd/graph-context.ts +212 -0
  268. package/src/resources/extensions/gsd/gsd-db.ts +788 -3
  269. package/src/resources/extensions/gsd/guided-flow.ts +32 -0
  270. package/src/resources/extensions/gsd/index.ts +18 -2
  271. package/src/resources/extensions/gsd/init-wizard.ts +3 -2
  272. package/src/resources/extensions/gsd/journal.ts +30 -0
  273. package/src/resources/extensions/gsd/md-importer.ts +3 -5
  274. package/src/resources/extensions/gsd/memory-store.ts +31 -62
  275. package/src/resources/extensions/gsd/metrics.ts +26 -0
  276. package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
  277. package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
  278. package/src/resources/extensions/gsd/notification-widget.ts +2 -2
  279. package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
  280. package/src/resources/extensions/gsd/preferences-models.ts +61 -3
  281. package/src/resources/extensions/gsd/preferences-types.ts +44 -0
  282. package/src/resources/extensions/gsd/preferences-validation.ts +130 -2
  283. package/src/resources/extensions/gsd/preferences.ts +28 -0
  284. package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
  285. package/src/resources/extensions/gsd/session-lock.ts +14 -2
  286. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
  287. package/src/resources/extensions/gsd/state.ts +80 -17
  288. package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  289. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +9 -5
  290. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
  291. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
  292. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
  293. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
  294. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
  295. package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
  296. package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
  297. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
  298. package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
  299. package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
  300. package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
  301. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
  302. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
  303. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  304. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  305. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
  306. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
  307. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
  308. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
  309. package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
  310. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
  311. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
  312. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
  313. package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
  314. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  315. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  316. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
  317. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
  318. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
  319. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
  320. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
  321. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  322. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
  323. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
  324. package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
  325. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
  326. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
  327. package/src/resources/extensions/gsd/tests/token-profile.test.ts +9 -6
  328. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  329. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
  330. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
  331. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
  332. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
  333. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
  334. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
  335. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  336. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
  337. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  338. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
  339. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
  340. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
  341. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -0
  342. package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
  343. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
  344. package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
  345. package/src/resources/extensions/gsd/types.ts +1 -1
  346. package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
  347. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  348. package/src/resources/extensions/gsd/uok/audit.ts +51 -0
  349. package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
  350. package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
  351. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  352. package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
  353. package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
  354. package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
  355. package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
  356. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  357. package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
  358. package/src/resources/extensions/gsd/workflow-logger.ts +25 -0
  359. package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
  360. package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
  361. package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
  362. package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
  363. package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
  364. /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → ZMKM0OI0CrTgzKWbgfPOg}/_buildManifest.js +0 -0
  365. /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → ZMKM0OI0CrTgzKWbgfPOg}/_ssgManifest.js +0 -0
@@ -23,6 +23,9 @@ import { invalidateStateCache } from "../state.js";
23
23
  import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
24
24
  import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
25
25
  import { logWarning } from "../workflow-logger.js";
26
+ import { UokGateRunner } from "../uok/gate-runner.js";
27
+ import { loadEffectiveGSDPreferences } from "../preferences.js";
28
+ import { resolveUokFlags } from "../uok/flags.js";
26
29
 
27
30
  export interface ValidateMilestoneParams {
28
31
  milestoneId: string;
@@ -43,6 +46,12 @@ export interface ValidateMilestoneResult {
43
46
  validationPath: string;
44
47
  }
45
48
 
49
+ export interface ValidateMilestoneOptions {
50
+ uokGatesEnabled?: boolean;
51
+ traceId?: string;
52
+ turnId?: string;
53
+ }
54
+
46
55
  function renderValidationMarkdown(params: ValidateMilestoneParams): string {
47
56
  let md = `---
48
57
  verdict: ${params.verdict}
@@ -81,6 +90,7 @@ ${params.verdictRationale}
81
90
  export async function handleValidateMilestone(
82
91
  params: ValidateMilestoneParams,
83
92
  basePath: string,
93
+ opts?: ValidateMilestoneOptions,
84
94
  ): Promise<ValidateMilestoneResult | { error: string }> {
85
95
  if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
86
96
  return { error: "milestoneId is required and must be a non-empty string" };
@@ -108,6 +118,8 @@ export async function handleValidateMilestone(
108
118
  // rendering can regenerate. The inverse (file exists, no DB row) is
109
119
  // harder to detect and recover from (#2725).
110
120
  const validatedAt = new Date().toISOString();
121
+ const slices = getMilestoneSlices(params.milestoneId);
122
+ const gateSliceId = slices.length > 0 ? slices[0].id : "_milestone";
111
123
 
112
124
  transaction(() => {
113
125
  insertAssessment({
@@ -123,11 +135,9 @@ export async function handleValidateMilestone(
123
135
  // #2945 Bug 4: persist quality_gates records alongside the assessment.
124
136
  // Previously only the assessment was written, leaving M002+ milestones
125
137
  // with zero quality_gate records despite passing validation.
126
- const slices = getMilestoneSlices(params.milestoneId);
127
- const sliceId = slices.length > 0 ? slices[0].id : "_milestone";
128
138
  insertMilestoneValidationGates(
129
139
  params.milestoneId,
130
- sliceId,
140
+ gateSliceId,
131
141
  params.verdict,
132
142
  validatedAt,
133
143
  );
@@ -147,6 +157,41 @@ export async function handleValidateMilestone(
147
157
  clearPathCache();
148
158
  clearParseCache();
149
159
 
160
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
161
+ const gatesEnabled = opts?.uokGatesEnabled ?? resolveUokFlags(prefs).gates;
162
+ if (gatesEnabled) {
163
+ try {
164
+ const gateRunner = new UokGateRunner();
165
+ const nonPassVerdict = params.verdict !== "pass";
166
+ gateRunner.register({
167
+ id: "milestone-validation-gates",
168
+ type: "verification",
169
+ execute: async () => ({
170
+ outcome: nonPassVerdict ? "manual-attention" : "pass",
171
+ failureClass: nonPassVerdict ? "manual-attention" : "none",
172
+ rationale: `milestone validation verdict: ${params.verdict}`,
173
+ findings: nonPassVerdict
174
+ ? [params.verdictRationale, params.remediationPlan ?? ""].filter(Boolean).join("\n")
175
+ : "",
176
+ }),
177
+ });
178
+ await gateRunner.run("milestone-validation-gates", {
179
+ basePath,
180
+ traceId: opts?.traceId ?? `validate-milestone:${params.milestoneId}`,
181
+ turnId: opts?.turnId ?? `${params.milestoneId}:validate`,
182
+ milestoneId: params.milestoneId,
183
+ sliceId: gateSliceId,
184
+ unitType: "validate-milestone",
185
+ unitId: params.milestoneId,
186
+ });
187
+ } catch (err) {
188
+ logWarning(
189
+ "tool",
190
+ `validate_milestone — failed to persist UOK gate result: ${(err as Error).message}`,
191
+ );
192
+ }
193
+ }
194
+
150
195
  return {
151
196
  milestoneId: params.milestoneId,
152
197
  verdict: params.verdict,
@@ -5,7 +5,7 @@ import {
5
5
  getMilestone,
6
6
  getSliceStatusSummary,
7
7
  getSliceTaskCounts,
8
- _getAdapter,
8
+ readTransaction,
9
9
  saveGateResult,
10
10
  } from "../gsd-db.js";
11
11
  import { GATE_REGISTRY } from "../gate-registry.js";
@@ -616,12 +616,9 @@ export async function executeMilestoneStatus(
616
616
  };
617
617
  }
618
618
 
619
- const adapter = _getAdapter()!;
620
- adapter.exec("BEGIN");
621
- try {
619
+ return readTransaction(() => {
622
620
  const milestone = getMilestone(params.milestoneId);
623
621
  if (!milestone) {
624
- adapter.exec("COMMIT");
625
622
  return {
626
623
  content: [{ type: "text", text: `Milestone ${params.milestoneId} not found in database.` }],
627
624
  details: { operation: "milestone_status", milestoneId: params.milestoneId, found: false },
@@ -635,8 +632,6 @@ export async function executeMilestoneStatus(
635
632
  taskCounts: getSliceTaskCounts(params.milestoneId, s.id),
636
633
  }));
637
634
 
638
- adapter.exec("COMMIT");
639
-
640
635
  const result = {
641
636
  milestoneId: milestone.id,
642
637
  title: milestone.title,
@@ -651,10 +646,7 @@ export async function executeMilestoneStatus(
651
646
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
652
647
  details: { operation: "milestone_status", milestoneId: milestone.id, sliceCount: slices.length },
653
648
  };
654
- } catch (txErr) {
655
- try { adapter.exec("ROLLBACK"); } catch { /* swallow */ }
656
- throw txErr;
657
- }
649
+ });
658
650
  } catch (err) {
659
651
  const msg = err instanceof Error ? err.message : String(err);
660
652
  logWarning("tool", `gsd_milestone_status tool failed: ${msg}`);
@@ -111,14 +111,9 @@ export function executeReplan(
111
111
  // Also write replan_triggered_at column for DB-backed detection
112
112
  try {
113
113
  const req = createRequire(import.meta.url);
114
- const { isDbAvailable, _getAdapter } = req("./gsd-db.js");
114
+ const { isDbAvailable, setSliceReplanTriggeredAt } = req("./gsd-db.js");
115
115
  if (isDbAvailable()) {
116
- const adapter = _getAdapter();
117
- if (adapter) {
118
- adapter.prepare(
119
- "UPDATE slices SET replan_triggered_at = :ts WHERE milestone_id = :mid AND id = :sid",
120
- ).run({ ":ts": ts, ":mid": mid, ":sid": sid });
121
- }
116
+ setSliceReplanTriggeredAt(mid, sid, ts);
122
117
  }
123
118
  } catch {
124
119
  // DB write is best-effort — disk file is the primary trigger for fallback path
@@ -306,7 +306,7 @@ export interface HookDispatchResult {
306
306
 
307
307
  export type BudgetEnforcementMode = "warn" | "pause" | "halt";
308
308
 
309
- export type TokenProfile = "budget" | "balanced" | "quality";
309
+ export type TokenProfile = "budget" | "balanced" | "quality" | "burn-max";
310
310
 
311
311
  export type InlineLevel = "full" | "standard" | "minimal";
312
312
 
@@ -46,8 +46,8 @@ let loadAttempted = false;
46
46
 
47
47
  function suppressSqliteWarning(): void {
48
48
  const origEmit = process.emit;
49
- // @ts-expect-error overriding process.emit for warning filter
50
- process.emit = function (event: string, ...args: unknown[]): boolean {
49
+ // Override via loose cast: Node's overloaded emit signature is not directly assignable.
50
+ (process as any).emit = function (event: string, ...args: unknown[]): boolean {
51
51
  if (
52
52
  event === "warning" &&
53
53
  args[0] &&
@@ -0,0 +1,9 @@
1
+ const AUDIT_ENV_KEY = "GSD_UOK_AUDIT_UNIFIED";
2
+
3
+ export function setUnifiedAuditEnabled(enabled: boolean): void {
4
+ process.env[AUDIT_ENV_KEY] = enabled ? "1" : "0";
5
+ }
6
+
7
+ export function isUnifiedAuditEnabled(): boolean {
8
+ return process.env[AUDIT_ENV_KEY] === "1";
9
+ }
@@ -0,0 +1,51 @@
1
+ import { appendFileSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+
5
+ import { gsdRoot } from "../paths.js";
6
+ import { isDbAvailable, insertAuditEvent } from "../gsd-db.js";
7
+ import type { AuditEventEnvelope } from "./contracts.js";
8
+
9
+ function auditLogPath(basePath: string): string {
10
+ return join(gsdRoot(basePath), "audit", "events.jsonl");
11
+ }
12
+
13
+ function ensureAuditDir(basePath: string): void {
14
+ mkdirSync(join(gsdRoot(basePath), "audit"), { recursive: true });
15
+ }
16
+
17
+ export function buildAuditEnvelope(args: {
18
+ traceId: string;
19
+ turnId?: string;
20
+ causedBy?: string;
21
+ category: AuditEventEnvelope["category"];
22
+ type: string;
23
+ payload?: Record<string, unknown>;
24
+ }): AuditEventEnvelope {
25
+ return {
26
+ eventId: randomUUID(),
27
+ traceId: args.traceId,
28
+ turnId: args.turnId,
29
+ causedBy: args.causedBy,
30
+ category: args.category,
31
+ type: args.type,
32
+ ts: new Date().toISOString(),
33
+ payload: args.payload ?? {},
34
+ };
35
+ }
36
+
37
+ export function emitUokAuditEvent(basePath: string, event: AuditEventEnvelope): void {
38
+ try {
39
+ ensureAuditDir(basePath);
40
+ appendFileSync(auditLogPath(basePath), `${JSON.stringify(event)}\n`, "utf-8");
41
+ } catch {
42
+ // Best-effort: audit writes must never break orchestration.
43
+ }
44
+
45
+ if (!isDbAvailable()) return;
46
+ try {
47
+ insertAuditEvent(event);
48
+ } catch {
49
+ // Projection failures are non-fatal while legacy readers are still active.
50
+ }
51
+ }
@@ -0,0 +1,135 @@
1
+ export type FailureClass =
2
+ | "none"
3
+ | "policy"
4
+ | "input"
5
+ | "execution"
6
+ | "artifact"
7
+ | "verification"
8
+ | "closeout"
9
+ | "git"
10
+ | "timeout"
11
+ | "manual-attention"
12
+ | "unknown";
13
+
14
+ export type GateOutcome = "pass" | "fail" | "retry" | "manual-attention";
15
+
16
+ export interface GateResult {
17
+ gateId: string;
18
+ gateType: string;
19
+ outcome: GateOutcome;
20
+ failureClass: FailureClass;
21
+ rationale?: string;
22
+ findings?: string;
23
+ attempt: number;
24
+ maxAttempts: number;
25
+ retryable: boolean;
26
+ evaluatedAt: string;
27
+ }
28
+
29
+ export type TurnPhase =
30
+ | "pre-dispatch"
31
+ | "dispatch"
32
+ | "unit"
33
+ | "finalize"
34
+ | "guard"
35
+ | "custom-engine";
36
+
37
+ export type TurnStatus =
38
+ | "completed"
39
+ | "failed"
40
+ | "paused"
41
+ | "stopped"
42
+ | "skipped"
43
+ | "retry";
44
+
45
+ export interface TurnContract {
46
+ traceId: string;
47
+ turnId: string;
48
+ iteration: number;
49
+ basePath: string;
50
+ unitType?: string;
51
+ unitId?: string;
52
+ sidecarKind?: string;
53
+ startedAt: string;
54
+ metadata?: Record<string, unknown>;
55
+ }
56
+
57
+ export interface TurnCloseoutRecord {
58
+ traceId: string;
59
+ turnId: string;
60
+ unitType?: string;
61
+ unitId?: string;
62
+ status: TurnStatus;
63
+ failureClass: FailureClass;
64
+ gitAction: "commit" | "snapshot" | "status-only";
65
+ gitPushed: boolean;
66
+ activityFile?: string;
67
+ finishedAt: string;
68
+ }
69
+
70
+ export interface TurnResult {
71
+ traceId: string;
72
+ turnId: string;
73
+ iteration: number;
74
+ unitType?: string;
75
+ unitId?: string;
76
+ status: TurnStatus;
77
+ failureClass: FailureClass;
78
+ phaseResults: Array<{
79
+ phase: TurnPhase;
80
+ action: string;
81
+ ts: string;
82
+ data?: Record<string, unknown>;
83
+ }>;
84
+ gateResults?: GateResult[];
85
+ closeout?: TurnCloseoutRecord;
86
+ error?: string;
87
+ startedAt: string;
88
+ finishedAt: string;
89
+ }
90
+
91
+ export interface AuditEventEnvelope {
92
+ eventId: string;
93
+ traceId: string;
94
+ turnId?: string;
95
+ causedBy?: string;
96
+ category:
97
+ | "orchestration"
98
+ | "gate"
99
+ | "model-policy"
100
+ | "gitops"
101
+ | "verification"
102
+ | "metrics"
103
+ | "plan"
104
+ | "execution";
105
+ type: string;
106
+ ts: string;
107
+ payload: Record<string, unknown>;
108
+ }
109
+
110
+ export type UokNodeKind =
111
+ | "unit"
112
+ | "hook"
113
+ | "subagent"
114
+ | "team-worker"
115
+ | "verification"
116
+ | "reprocess";
117
+
118
+ export interface UokGraphNode {
119
+ id: string;
120
+ kind: UokNodeKind;
121
+ dependsOn: string[];
122
+ writes?: string[];
123
+ reads?: string[];
124
+ metadata?: Record<string, unknown>;
125
+ }
126
+
127
+ export interface UokTurnObserver {
128
+ onTurnStart(contract: TurnContract): void;
129
+ onPhaseResult(
130
+ phase: TurnPhase,
131
+ action: string,
132
+ data?: Record<string, unknown>,
133
+ ): void;
134
+ onTurnResult(result: TurnResult): void;
135
+ }
@@ -0,0 +1,241 @@
1
+ import type { UokGraphNode } from "./contracts.js";
2
+ import type { DerivedTaskNode } from "../types.js";
3
+ import type { SidecarItem } from "../auto/session.js";
4
+
5
+ export interface ExecutionGraphRunOptions {
6
+ parallel?: boolean;
7
+ maxWorkers?: number;
8
+ }
9
+
10
+ export interface ExecutionGraphResult {
11
+ order: string[];
12
+ conflicts: Array<{ nodeA: string; nodeB: string; file: string }>;
13
+ }
14
+
15
+ export type ExecutionNodeHandler = (node: UokGraphNode) => Promise<void>;
16
+
17
+ export interface ConflictFreeBatchInput {
18
+ orderedIds: string[];
19
+ maxParallel: number;
20
+ hasConflict: (leftId: string, rightId: string) => boolean;
21
+ }
22
+
23
+ export interface ReactiveDispatchSelectionInput {
24
+ graph: Array<Pick<DerivedTaskNode, "id" | "dependsOn" | "outputFiles">>;
25
+ readyIds: string[];
26
+ maxParallel: number;
27
+ inFlightOutputs?: Set<string>;
28
+ }
29
+
30
+ export interface ReactiveDispatchSelectionResult {
31
+ selected: string[];
32
+ conflicts: Array<{ nodeA: string; nodeB: string; file: string }>;
33
+ }
34
+
35
+ export function selectConflictFreeBatch({
36
+ orderedIds,
37
+ maxParallel,
38
+ hasConflict,
39
+ }: ConflictFreeBatchInput): string[] {
40
+ if (maxParallel <= 0 || orderedIds.length === 0) return [];
41
+ const selected: string[] = [];
42
+ for (const candidate of orderedIds) {
43
+ if (selected.length >= maxParallel) break;
44
+ const conflictsExisting = selected.some((existing) => hasConflict(candidate, existing));
45
+ if (conflictsExisting) continue;
46
+ selected.push(candidate);
47
+ }
48
+ return selected;
49
+ }
50
+
51
+ function buildReactiveNodes(
52
+ graph: Array<Pick<DerivedTaskNode, "id" | "dependsOn" | "outputFiles">>,
53
+ ): UokGraphNode[] {
54
+ return graph.map((node) => ({
55
+ id: node.id,
56
+ kind: "unit",
57
+ dependsOn: [...node.dependsOn],
58
+ writes: [...node.outputFiles],
59
+ }));
60
+ }
61
+
62
+ export function selectReactiveDispatchBatch(
63
+ input: ReactiveDispatchSelectionInput,
64
+ ): ReactiveDispatchSelectionResult {
65
+ const nodeMap = new Map(buildReactiveNodes(input.graph).map((n) => [n.id, n]));
66
+ const readyNodes = input.readyIds
67
+ .map((id) => nodeMap.get(id))
68
+ .filter((node): node is UokGraphNode => !!node);
69
+ const conflicts = detectFileConflicts(readyNodes);
70
+ if (readyNodes.length === 0 || input.maxParallel <= 0) {
71
+ return { selected: [], conflicts };
72
+ }
73
+
74
+ const claimed = new Set(input.inFlightOutputs ?? []);
75
+ const selected: string[] = [];
76
+ const selectedSet = new Set<string>();
77
+ const readySet = new Set(input.readyIds);
78
+
79
+ for (const id of input.readyIds) {
80
+ if (selected.length >= input.maxParallel) break;
81
+ const node = nodeMap.get(id);
82
+ if (!node) continue;
83
+
84
+ const hasUnmetReadyDependency = node.dependsOn.some(
85
+ (dep) => readySet.has(dep) && !selectedSet.has(dep),
86
+ );
87
+ if (hasUnmetReadyDependency) continue;
88
+
89
+ const writes = node.writes ?? [];
90
+ const conflictsWithClaimed = writes.some((file) => claimed.has(file));
91
+ if (conflictsWithClaimed) continue;
92
+
93
+ selected.push(node.id);
94
+ selectedSet.add(node.id);
95
+ for (const file of writes) claimed.add(file);
96
+ }
97
+
98
+ return { selected, conflicts };
99
+ }
100
+
101
+ function sidecarToNodeKind(kind: SidecarItem["kind"]): UokGraphNode["kind"] {
102
+ if (kind === "hook") return "hook";
103
+ if (kind === "triage") return "verification";
104
+ return "team-worker";
105
+ }
106
+
107
+ export function buildSidecarQueueNodes(queue: SidecarItem[]): UokGraphNode[] {
108
+ return queue.map((item, index) => ({
109
+ id: `sidecar-${String(index).padStart(4, "0")}:${item.kind}:${item.unitType}:${item.unitId}`,
110
+ kind: sidecarToNodeKind(item.kind),
111
+ dependsOn: index > 0 ? [`sidecar-${String(index - 1).padStart(4, "0")}:${queue[index - 1].kind}:${queue[index - 1].unitType}:${queue[index - 1].unitId}`] : [],
112
+ metadata: { index },
113
+ }));
114
+ }
115
+
116
+ export async function scheduleSidecarQueue(queue: SidecarItem[]): Promise<SidecarItem[]> {
117
+ if (queue.length <= 1) return [...queue];
118
+ const nodes = buildSidecarQueueNodes(queue);
119
+ const scheduler = new ExecutionGraphScheduler();
120
+ const orderedIndexes: number[] = [];
121
+ const seenKinds = new Set<UokGraphNode["kind"]>(nodes.map((n) => n.kind));
122
+
123
+ for (const kind of seenKinds) {
124
+ scheduler.registerHandler(kind, async (node) => {
125
+ const idx = Number(node.metadata?.index);
126
+ if (Number.isInteger(idx) && idx >= 0) orderedIndexes.push(idx);
127
+ });
128
+ }
129
+
130
+ await scheduler.run(nodes, { parallel: false });
131
+ return orderedIndexes.map((idx) => queue[idx]).filter((item): item is SidecarItem => !!item);
132
+ }
133
+
134
+ export class ExecutionGraphScheduler {
135
+ private readonly handlers = new Map<string, ExecutionNodeHandler>();
136
+
137
+ registerHandler(kind: UokGraphNode["kind"], handler: ExecutionNodeHandler): void {
138
+ this.handlers.set(kind, handler);
139
+ }
140
+
141
+ async run(nodes: UokGraphNode[], options?: ExecutionGraphRunOptions): Promise<ExecutionGraphResult> {
142
+ const sorted = topologicalSort(nodes);
143
+ const conflicts = detectFileConflicts(nodes);
144
+
145
+ // Default deterministic serial execution remains the reference path.
146
+ if (!options?.parallel) {
147
+ for (const node of sorted) {
148
+ const handler = this.handlers.get(node.kind);
149
+ if (handler) await handler(node);
150
+ }
151
+ return { order: sorted.map((n) => n.id), conflicts };
152
+ }
153
+
154
+ // Parallel mode only for nodes whose dependencies are already satisfied.
155
+ const maxWorkers = Math.max(1, Math.min(8, options.maxWorkers ?? 2));
156
+ const remaining = new Map(nodes.map((n) => [n.id, n]));
157
+ const done = new Set<string>();
158
+ const order: string[] = [];
159
+
160
+ while (remaining.size > 0) {
161
+ const ready = Array.from(remaining.values()).filter((node) =>
162
+ node.dependsOn.every((dep) => done.has(dep)),
163
+ );
164
+ ready.sort((a, b) => a.id.localeCompare(b.id));
165
+ if (ready.length === 0) {
166
+ throw new Error("Execution graph deadlock detected: no ready nodes and graph not complete");
167
+ }
168
+
169
+ const batch = ready.slice(0, maxWorkers);
170
+ await Promise.all(
171
+ batch.map(async (node) => {
172
+ const handler = this.handlers.get(node.kind);
173
+ if (handler) await handler(node);
174
+ done.add(node.id);
175
+ order.push(node.id);
176
+ remaining.delete(node.id);
177
+ }),
178
+ );
179
+ }
180
+
181
+ return { order, conflicts };
182
+ }
183
+ }
184
+
185
+ function topologicalSort(nodes: UokGraphNode[]): UokGraphNode[] {
186
+ const nodeMap = new Map(nodes.map((n) => [n.id, n]));
187
+ const inDegree = new Map(nodes.map((n) => [n.id, 0]));
188
+
189
+ for (const node of nodes) {
190
+ for (const dep of node.dependsOn) {
191
+ if (nodeMap.has(dep)) {
192
+ inDegree.set(node.id, (inDegree.get(node.id) ?? 0) + 1);
193
+ }
194
+ }
195
+ }
196
+
197
+ const queue = nodes
198
+ .filter((n) => (inDegree.get(n.id) ?? 0) === 0)
199
+ .sort((a, b) => a.id.localeCompare(b.id));
200
+ const ordered: UokGraphNode[] = [];
201
+
202
+ while (queue.length > 0) {
203
+ const current = queue.shift()!;
204
+ ordered.push(current);
205
+
206
+ for (const next of nodes) {
207
+ if (!next.dependsOn.includes(current.id)) continue;
208
+ const deg = (inDegree.get(next.id) ?? 0) - 1;
209
+ inDegree.set(next.id, deg);
210
+ if (deg === 0) {
211
+ queue.push(next);
212
+ queue.sort((a, b) => a.id.localeCompare(b.id));
213
+ }
214
+ }
215
+ }
216
+
217
+ if (ordered.length !== nodes.length) {
218
+ throw new Error("Execution graph has cyclic dependencies");
219
+ }
220
+
221
+ return ordered;
222
+ }
223
+
224
+ function detectFileConflicts(nodes: UokGraphNode[]): Array<{ nodeA: string; nodeB: string; file: string }> {
225
+ const conflicts: Array<{ nodeA: string; nodeB: string; file: string }> = [];
226
+ for (let i = 0; i < nodes.length; i++) {
227
+ const a = nodes[i];
228
+ const writesA = new Set(a.writes ?? []);
229
+ if (writesA.size === 0) continue;
230
+
231
+ for (let j = i + 1; j < nodes.length; j++) {
232
+ const b = nodes[j];
233
+ for (const file of b.writes ?? []) {
234
+ if (writesA.has(file)) {
235
+ conflicts.push({ nodeA: a.id, nodeB: b.id, file });
236
+ }
237
+ }
238
+ }
239
+ }
240
+ return conflicts;
241
+ }
@@ -0,0 +1,45 @@
1
+ import type { GSDPreferences } from "../preferences.js";
2
+ import { loadEffectiveGSDPreferences } from "../preferences.js";
3
+
4
+ export interface UokFlags {
5
+ enabled: boolean;
6
+ legacyFallback: boolean;
7
+ gates: boolean;
8
+ modelPolicy: boolean;
9
+ executionGraph: boolean;
10
+ gitops: boolean;
11
+ gitopsTurnAction: "commit" | "snapshot" | "status-only";
12
+ gitopsTurnPush: boolean;
13
+ auditUnified: boolean;
14
+ planV2: boolean;
15
+ }
16
+
17
+ function envForcesLegacyFallback(): boolean {
18
+ const raw = process.env.GSD_UOK_FORCE_LEGACY ?? process.env.GSD_UOK_LEGACY_FALLBACK;
19
+ if (!raw) return false;
20
+ const normalized = raw.trim().toLowerCase();
21
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
22
+ }
23
+
24
+ export function resolveUokFlags(prefs: GSDPreferences | undefined): UokFlags {
25
+ const uok = prefs?.uok;
26
+ const legacyFallback = uok?.legacy_fallback?.enabled === true || envForcesLegacyFallback();
27
+ const enabledByPreference = uok?.enabled ?? true;
28
+ return {
29
+ enabled: enabledByPreference && !legacyFallback,
30
+ legacyFallback,
31
+ gates: uok?.gates?.enabled === true,
32
+ modelPolicy: uok?.model_policy?.enabled === true,
33
+ executionGraph: uok?.execution_graph?.enabled === true,
34
+ gitops: uok?.gitops?.enabled === true,
35
+ gitopsTurnAction: uok?.gitops?.turn_action ?? "status-only",
36
+ gitopsTurnPush: uok?.gitops?.turn_push === true,
37
+ auditUnified: uok?.audit_unified?.enabled === true,
38
+ planV2: uok?.plan_v2?.enabled === true,
39
+ };
40
+ }
41
+
42
+ export function loadUokFlags(): UokFlags {
43
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
44
+ return resolveUokFlags(prefs);
45
+ }