gsd-pi 2.74.0-dev.2b524c3 → 2.74.0-dev.6e23363

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 (275) hide show
  1. package/dist/cli.js +85 -0
  2. package/dist/headless-query.js +4 -1
  3. package/dist/help-text.js +23 -0
  4. package/dist/resources/extensions/gsd/activity-log.js +16 -0
  5. package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
  6. package/dist/resources/extensions/gsd/auto/loop.js +147 -10
  7. package/dist/resources/extensions/gsd/auto/phases.js +158 -4
  8. package/dist/resources/extensions/gsd/auto/session.js +10 -0
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +11 -1
  10. package/dist/resources/extensions/gsd/auto-model-selection.js +51 -5
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +213 -14
  12. package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
  13. package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
  14. package/dist/resources/extensions/gsd/auto-verification.js +100 -2
  15. package/dist/resources/extensions/gsd/auto.js +36 -4
  16. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +21 -8
  17. package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
  18. package/dist/resources/extensions/gsd/commands/handlers/ops.js +20 -0
  19. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
  20. package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
  21. package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
  22. package/dist/resources/extensions/gsd/commands-do.js +79 -0
  23. package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
  24. package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
  25. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  26. package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
  27. package/dist/resources/extensions/gsd/commands-ship.js +187 -0
  28. package/dist/resources/extensions/gsd/db-writer.js +3 -5
  29. package/dist/resources/extensions/gsd/docs/preferences-reference.md +14 -1
  30. package/dist/resources/extensions/gsd/git-service.js +49 -1
  31. package/dist/resources/extensions/gsd/graph-context.js +157 -0
  32. package/dist/resources/extensions/gsd/gsd-db.js +581 -2
  33. package/dist/resources/extensions/gsd/guided-flow.js +23 -0
  34. package/dist/resources/extensions/gsd/index.js +15 -2
  35. package/dist/resources/extensions/gsd/init-wizard.js +1 -0
  36. package/dist/resources/extensions/gsd/journal.js +27 -0
  37. package/dist/resources/extensions/gsd/md-importer.js +3 -4
  38. package/dist/resources/extensions/gsd/memory-store.js +19 -51
  39. package/dist/resources/extensions/gsd/metrics.js +19 -0
  40. package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
  41. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
  42. package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
  43. package/dist/resources/extensions/gsd/preferences-models.js +20 -3
  44. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  45. package/dist/resources/extensions/gsd/preferences-validation.js +108 -2
  46. package/dist/resources/extensions/gsd/preferences.js +26 -0
  47. package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
  48. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
  49. package/dist/resources/extensions/gsd/state.js +5 -1
  50. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  51. package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -0
  52. package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
  53. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
  54. package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
  55. package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
  56. package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
  57. package/dist/resources/extensions/gsd/uok/audit.js +40 -0
  58. package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
  59. package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
  60. package/dist/resources/extensions/gsd/uok/flags.js +29 -0
  61. package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
  62. package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
  63. package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
  64. package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
  65. package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
  66. package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
  67. package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
  68. package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
  69. package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
  70. package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
  71. package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
  72. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  73. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  74. package/dist/web/standalone/.next/BUILD_ID +1 -1
  75. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  76. package/dist/web/standalone/.next/build-manifest.json +2 -2
  77. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  78. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.html +1 -1
  95. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  102. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  104. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  105. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  106. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  107. package/package.json +3 -2
  108. package/packages/daemon/package.json +2 -2
  109. package/packages/mcp-server/dist/index.d.ts +3 -0
  110. package/packages/mcp-server/dist/index.d.ts.map +1 -1
  111. package/packages/mcp-server/dist/index.js +3 -0
  112. package/packages/mcp-server/dist/index.js.map +1 -1
  113. package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
  114. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
  115. package/packages/mcp-server/dist/readers/graph.js +548 -0
  116. package/packages/mcp-server/dist/readers/graph.js.map +1 -0
  117. package/packages/mcp-server/dist/readers/index.d.ts +2 -0
  118. package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
  119. package/packages/mcp-server/dist/readers/index.js +1 -0
  120. package/packages/mcp-server/dist/readers/index.js.map +1 -1
  121. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  122. package/packages/mcp-server/dist/server.js +65 -0
  123. package/packages/mcp-server/dist/server.js.map +1 -1
  124. package/packages/mcp-server/package.json +2 -2
  125. package/packages/mcp-server/src/index.ts +15 -0
  126. package/packages/mcp-server/src/readers/graph.test.ts +426 -0
  127. package/packages/mcp-server/src/readers/graph.ts +708 -0
  128. package/packages/mcp-server/src/readers/index.ts +12 -0
  129. package/packages/mcp-server/src/server.ts +83 -0
  130. package/packages/mcp-server/tsconfig.json +1 -0
  131. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
  132. package/packages/native/package.json +2 -2
  133. package/packages/native/tsconfig.tsbuildinfo +1 -0
  134. package/packages/pi-agent-core/package.json +1 -1
  135. package/packages/pi-agent-core/tsconfig.json +1 -0
  136. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
  137. package/packages/pi-ai/package.json +1 -1
  138. package/packages/pi-ai/tsconfig.json +1 -0
  139. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
  140. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +120 -0
  141. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
  143. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
  144. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
  145. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
  146. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  148. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  150. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +48 -4
  151. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  152. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +166 -0
  153. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  154. package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
  155. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +53 -4
  156. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  157. package/packages/pi-coding-agent/tsconfig.json +3 -2
  158. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
  159. package/packages/pi-tui/package.json +1 -1
  160. package/packages/pi-tui/tsconfig.json +1 -0
  161. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
  162. package/packages/rpc-client/package.json +1 -1
  163. package/packages/rpc-client/tsconfig.json +1 -0
  164. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
  165. package/src/resources/extensions/gsd/activity-log.ts +21 -0
  166. package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
  167. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -0
  168. package/src/resources/extensions/gsd/auto/loop.ts +159 -10
  169. package/src/resources/extensions/gsd/auto/phases.ts +191 -4
  170. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  171. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -6
  172. package/src/resources/extensions/gsd/auto-model-selection.ts +66 -5
  173. package/src/resources/extensions/gsd/auto-post-unit.ts +231 -15
  174. package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
  175. package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
  176. package/src/resources/extensions/gsd/auto-verification.ts +129 -2
  177. package/src/resources/extensions/gsd/auto.ts +41 -2
  178. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -8
  179. package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
  180. package/src/resources/extensions/gsd/commands/handlers/ops.ts +20 -0
  181. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
  182. package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
  183. package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
  184. package/src/resources/extensions/gsd/commands-do.ts +109 -0
  185. package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
  186. package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
  187. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  188. package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
  189. package/src/resources/extensions/gsd/commands-ship.ts +219 -0
  190. package/src/resources/extensions/gsd/db-writer.ts +3 -5
  191. package/src/resources/extensions/gsd/docs/preferences-reference.md +14 -1
  192. package/src/resources/extensions/gsd/git-service.ts +68 -0
  193. package/src/resources/extensions/gsd/graph-context.ts +212 -0
  194. package/src/resources/extensions/gsd/gsd-db.ts +788 -3
  195. package/src/resources/extensions/gsd/guided-flow.ts +32 -0
  196. package/src/resources/extensions/gsd/index.ts +18 -2
  197. package/src/resources/extensions/gsd/init-wizard.ts +3 -2
  198. package/src/resources/extensions/gsd/journal.ts +30 -0
  199. package/src/resources/extensions/gsd/md-importer.ts +3 -5
  200. package/src/resources/extensions/gsd/memory-store.ts +31 -62
  201. package/src/resources/extensions/gsd/metrics.ts +26 -0
  202. package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
  203. package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
  204. package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
  205. package/src/resources/extensions/gsd/preferences-models.ts +20 -3
  206. package/src/resources/extensions/gsd/preferences-types.ts +32 -0
  207. package/src/resources/extensions/gsd/preferences-validation.ts +107 -2
  208. package/src/resources/extensions/gsd/preferences.ts +28 -0
  209. package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
  210. package/src/resources/extensions/gsd/session-lock.ts +14 -2
  211. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
  212. package/src/resources/extensions/gsd/state.ts +9 -2
  213. package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  214. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +7 -3
  215. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
  216. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
  217. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
  218. package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
  219. package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
  220. package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
  221. package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
  222. package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
  223. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
  224. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  225. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  226. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
  227. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
  228. package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
  229. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  230. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
  231. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
  232. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
  233. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
  234. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  235. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
  236. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
  237. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
  238. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -5
  239. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  240. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
  241. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
  242. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
  243. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
  244. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
  245. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
  246. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  247. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
  248. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  249. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
  250. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
  251. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -0
  252. package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
  253. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
  254. package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
  255. package/src/resources/extensions/gsd/types.ts +1 -1
  256. package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
  257. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  258. package/src/resources/extensions/gsd/uok/audit.ts +51 -0
  259. package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
  260. package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
  261. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  262. package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
  263. package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
  264. package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
  265. package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
  266. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  267. package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
  268. package/src/resources/extensions/gsd/workflow-logger.ts +25 -0
  269. package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
  270. package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
  271. package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
  272. package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
  273. package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
  274. /package/dist/web/standalone/.next/static/{YzIEI9sxJy4t5xgClF08g → bc2gRVFTgD7j--BsJE7vP}/_buildManifest.js +0 -0
  275. /package/dist/web/standalone/.next/static/{YzIEI9sxJy4t5xgClF08g → bc2gRVFTgD7j--BsJE7vP}/_ssgManifest.js +0 -0
@@ -0,0 +1,162 @@
1
+ import type {
2
+ TurnCloseoutRecord,
3
+ TurnContract,
4
+ TurnResult,
5
+ UokTurnObserver,
6
+ } from "./contracts.js";
7
+ import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js";
8
+ import { writeTurnCloseoutGitRecord, writeTurnGitTransaction } from "./gitops.js";
9
+
10
+ export interface CreateTurnObserverOptions {
11
+ basePath: string;
12
+ gitAction: "commit" | "snapshot" | "status-only";
13
+ gitPush: boolean;
14
+ enableAudit: boolean;
15
+ enableGitops: boolean;
16
+ }
17
+
18
+ export function createTurnObserver(options: CreateTurnObserverOptions): UokTurnObserver {
19
+ let current: TurnContract | null = null;
20
+ const phaseResults: TurnResult["phaseResults"] = [];
21
+
22
+ return {
23
+ onTurnStart(contract): void {
24
+ current = contract;
25
+ phaseResults.length = 0;
26
+
27
+ if (options.enableGitops) {
28
+ writeTurnGitTransaction({
29
+ basePath: options.basePath,
30
+ traceId: contract.traceId,
31
+ turnId: contract.turnId,
32
+ unitType: contract.unitType,
33
+ unitId: contract.unitId,
34
+ stage: "turn-start",
35
+ action: options.gitAction,
36
+ push: options.gitPush,
37
+ status: "ok",
38
+ metadata: {
39
+ iteration: contract.iteration,
40
+ sidecarKind: contract.sidecarKind,
41
+ },
42
+ });
43
+ }
44
+
45
+ if (options.enableAudit) {
46
+ emitUokAuditEvent(
47
+ options.basePath,
48
+ buildAuditEnvelope({
49
+ traceId: contract.traceId,
50
+ turnId: contract.turnId,
51
+ category: "orchestration",
52
+ type: "turn-start",
53
+ payload: {
54
+ iteration: contract.iteration,
55
+ unitType: contract.unitType,
56
+ unitId: contract.unitId,
57
+ sidecarKind: contract.sidecarKind,
58
+ },
59
+ }),
60
+ );
61
+ }
62
+ },
63
+
64
+ onPhaseResult(phase, action, data): void {
65
+ phaseResults.push({
66
+ phase,
67
+ action,
68
+ ts: new Date().toISOString(),
69
+ data,
70
+ });
71
+
72
+ if (!current || !options.enableGitops) return;
73
+ if (phase === "dispatch") {
74
+ writeTurnGitTransaction({
75
+ basePath: options.basePath,
76
+ traceId: current.traceId,
77
+ turnId: current.turnId,
78
+ unitType: data?.unitType as string | undefined,
79
+ unitId: data?.unitId as string | undefined,
80
+ stage: "stage",
81
+ action: options.gitAction,
82
+ push: options.gitPush,
83
+ status: "ok",
84
+ metadata: { action },
85
+ });
86
+ }
87
+ if (phase === "unit") {
88
+ writeTurnGitTransaction({
89
+ basePath: options.basePath,
90
+ traceId: current.traceId,
91
+ turnId: current.turnId,
92
+ unitType: data?.unitType as string | undefined,
93
+ unitId: data?.unitId as string | undefined,
94
+ stage: "checkpoint",
95
+ action: options.gitAction,
96
+ push: options.gitPush,
97
+ status: "ok",
98
+ metadata: { action },
99
+ });
100
+ }
101
+ if (phase === "finalize") {
102
+ writeTurnGitTransaction({
103
+ basePath: options.basePath,
104
+ traceId: current.traceId,
105
+ turnId: current.turnId,
106
+ unitType: data?.unitType as string | undefined,
107
+ unitId: data?.unitId as string | undefined,
108
+ stage: "publish",
109
+ action: options.gitAction,
110
+ push: options.gitPush,
111
+ status: "ok",
112
+ metadata: { action },
113
+ });
114
+ }
115
+ },
116
+
117
+ onTurnResult(result): void {
118
+ const merged: TurnResult = {
119
+ ...result,
120
+ phaseResults: result.phaseResults.length > 0 ? result.phaseResults : [...phaseResults],
121
+ };
122
+
123
+ if (options.enableAudit) {
124
+ emitUokAuditEvent(
125
+ options.basePath,
126
+ buildAuditEnvelope({
127
+ traceId: merged.traceId,
128
+ turnId: merged.turnId,
129
+ category: "orchestration",
130
+ type: "turn-result",
131
+ payload: {
132
+ unitType: merged.unitType,
133
+ unitId: merged.unitId,
134
+ status: merged.status,
135
+ failureClass: merged.failureClass,
136
+ error: merged.error,
137
+ phaseCount: merged.phaseResults.length,
138
+ },
139
+ }),
140
+ );
141
+ }
142
+
143
+ if (options.enableGitops) {
144
+ const closeout: TurnCloseoutRecord = merged.closeout ?? {
145
+ traceId: merged.traceId,
146
+ turnId: merged.turnId,
147
+ unitType: merged.unitType,
148
+ unitId: merged.unitId,
149
+ status: merged.status,
150
+ failureClass: merged.failureClass,
151
+ gitAction: options.gitAction,
152
+ gitPushed: options.gitPush,
153
+ finishedAt: merged.finishedAt,
154
+ };
155
+ writeTurnCloseoutGitRecord(options.basePath, closeout);
156
+ }
157
+
158
+ current = null;
159
+ phaseResults.length = 0;
160
+ },
161
+ };
162
+ }
@@ -0,0 +1,112 @@
1
+ import type { TaskMetadata } from "../complexity-classifier.js";
2
+ import { computeTaskRequirements, filterToolsForProvider } from "../model-router.js";
3
+ import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js";
4
+
5
+ export interface ModelCandidate {
6
+ id: string;
7
+ provider: string;
8
+ api: string;
9
+ }
10
+
11
+ export interface ModelPolicyDecision {
12
+ modelId: string;
13
+ provider: string;
14
+ allowed: boolean;
15
+ reason: string;
16
+ }
17
+
18
+ export interface ModelPolicyOptions {
19
+ basePath: string;
20
+ traceId: string;
21
+ turnId?: string;
22
+ unitType?: string;
23
+ taskMetadata?: TaskMetadata;
24
+ currentProvider?: string;
25
+ allowCrossProvider?: boolean;
26
+ requiredTools?: string[];
27
+ deniedProviders?: string[];
28
+ allowedApis?: string[];
29
+ }
30
+
31
+ export function buildRequirementVector(unitType?: string, taskMetadata?: TaskMetadata): Partial<Record<string, number>> {
32
+ if (!unitType) return {};
33
+ return computeTaskRequirements(unitType, taskMetadata) as unknown as Partial<Record<string, number>>;
34
+ }
35
+
36
+ export function applyModelPolicyFilter<T extends ModelCandidate>(
37
+ candidates: T[],
38
+ options: ModelPolicyOptions,
39
+ ): {
40
+ eligible: T[];
41
+ decisions: ModelPolicyDecision[];
42
+ requirements: Partial<Record<string, number>>;
43
+ } {
44
+ const requiredTools = options.requiredTools ?? [];
45
+ const deniedProviders = new Set((options.deniedProviders ?? []).map((p) => p.toLowerCase()));
46
+ const allowedApis = options.allowedApis ? new Set(options.allowedApis) : null;
47
+ const requirements = buildRequirementVector(options.unitType, options.taskMetadata);
48
+ const decisions: ModelPolicyDecision[] = [];
49
+ const eligible: T[] = [];
50
+
51
+ for (const model of candidates) {
52
+ let allowed = true;
53
+ let reason = "allowed";
54
+
55
+ if (options.allowCrossProvider === false && options.currentProvider && model.provider !== options.currentProvider) {
56
+ allowed = false;
57
+ reason = `cross-provider routing disabled (${model.provider} != ${options.currentProvider})`;
58
+ }
59
+
60
+ if (allowed && deniedProviders.has(model.provider.toLowerCase())) {
61
+ allowed = false;
62
+ reason = `provider denied by policy: ${model.provider}`;
63
+ }
64
+
65
+ if (allowed && allowedApis && !allowedApis.has(model.api)) {
66
+ allowed = false;
67
+ reason = `transport/api denied by policy: ${model.api}`;
68
+ }
69
+
70
+ if (allowed && requiredTools.length > 0) {
71
+ const compatibility = filterToolsForProvider(requiredTools, model.api);
72
+ if (compatibility.filtered.length > 0) {
73
+ allowed = false;
74
+ reason = `tool policy denied (${compatibility.filtered.join(", ")}) for ${model.api}`;
75
+ }
76
+ }
77
+
78
+ const decision: ModelPolicyDecision = {
79
+ modelId: model.id,
80
+ provider: model.provider,
81
+ allowed,
82
+ reason,
83
+ };
84
+ decisions.push(decision);
85
+
86
+ emitUokAuditEvent(
87
+ options.basePath,
88
+ buildAuditEnvelope({
89
+ traceId: options.traceId,
90
+ turnId: options.turnId,
91
+ category: "model-policy",
92
+ type: allowed ? "model-policy-allow" : "model-policy-deny",
93
+ payload: {
94
+ modelId: model.id,
95
+ provider: model.provider,
96
+ api: model.api,
97
+ reason,
98
+ unitType: options.unitType,
99
+ requirements,
100
+ },
101
+ }),
102
+ );
103
+
104
+ if (allowed) eligible.push(model);
105
+ }
106
+
107
+ return {
108
+ eligible,
109
+ decisions,
110
+ requirements,
111
+ };
112
+ }
@@ -0,0 +1,156 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import type { GSDState, Phase } from "../types.js";
5
+ import { gsdRoot, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
6
+ import { isDbAvailable, getMilestoneSlices, getSliceTasks, type SliceRow } from "../gsd-db.js";
7
+ import type { UokGraphNode } from "./contracts.js";
8
+
9
+ const PLAN_V2_CLARIFY_ROUND_LIMIT = 3;
10
+ const EXECUTION_ENTRY_PHASES: ReadonlySet<Phase> = new Set([
11
+ "executing",
12
+ "summarizing",
13
+ "validating-milestone",
14
+ "completing-milestone",
15
+ ]);
16
+
17
+ export interface PlanV2CompileResult {
18
+ ok: boolean;
19
+ reason?: string;
20
+ graphPath?: string;
21
+ nodeCount?: number;
22
+ clarifyRoundLimit?: number;
23
+ researchSynthesized?: boolean;
24
+ draftContextIncluded?: boolean;
25
+ finalizedContextIncluded?: boolean;
26
+ }
27
+
28
+ function graphOutputPath(basePath: string): string {
29
+ return join(gsdRoot(basePath), "runtime", "uok-plan-v2-graph.json");
30
+ }
31
+
32
+ function hasFileContent(path: string | null): boolean {
33
+ if (!path || !existsSync(path)) return false;
34
+ try {
35
+ return readFileSync(path, "utf-8").trim().length > 0;
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ function countSliceResearchArtifacts(basePath: string, milestoneId: string, slices: SliceRow[]): number {
42
+ let count = 0;
43
+ for (const slice of slices) {
44
+ if (hasFileContent(resolveSliceFile(basePath, milestoneId, slice.id, "RESEARCH"))) {
45
+ count += 1;
46
+ }
47
+ }
48
+ return count;
49
+ }
50
+
51
+ function isExecutionEntryPhase(phase: Phase): boolean {
52
+ return EXECUTION_ENTRY_PHASES.has(phase);
53
+ }
54
+
55
+ export function compileUnitGraphFromState(basePath: string, state: GSDState): PlanV2CompileResult {
56
+ const mid = state.activeMilestone?.id;
57
+ if (!mid) return { ok: false, reason: "no active milestone" };
58
+ if (!isDbAvailable()) return { ok: false, reason: "database not available" };
59
+
60
+ const slices = getMilestoneSlices(mid).sort((a, b) => Number(a.sequence ?? 0) - Number(b.sequence ?? 0));
61
+ const nodes: UokGraphNode[] = [];
62
+ const clarifyRoundLimit = PLAN_V2_CLARIFY_ROUND_LIMIT;
63
+ const draftContextIncluded = hasFileContent(resolveMilestoneFile(basePath, mid, "CONTEXT-DRAFT"));
64
+ const finalizedContextIncluded = hasFileContent(resolveMilestoneFile(basePath, mid, "CONTEXT"));
65
+ const researchSynthesized = hasFileContent(resolveMilestoneFile(basePath, mid, "RESEARCH"))
66
+ || countSliceResearchArtifacts(basePath, mid, slices) > 0;
67
+
68
+ if (isExecutionEntryPhase(state.phase) && !finalizedContextIncluded) {
69
+ const reason = draftContextIncluded
70
+ ? "milestone context draft exists but finalized CONTEXT.md is missing"
71
+ : "missing milestone CONTEXT.md";
72
+ return {
73
+ ok: false,
74
+ reason,
75
+ clarifyRoundLimit,
76
+ researchSynthesized,
77
+ draftContextIncluded,
78
+ finalizedContextIncluded,
79
+ };
80
+ }
81
+
82
+ for (const slice of slices) {
83
+ const sid = slice.id;
84
+ const tasks = getSliceTasks(mid, sid)
85
+ .sort((a, b) => Number(a.sequence ?? 0) - Number(b.sequence ?? 0));
86
+
87
+ let previousTaskNodeId: string | null = null;
88
+ for (const task of tasks) {
89
+ const nodeId = `execute-task:${mid}:${sid}:${task.id}`;
90
+ const dependsOn = previousTaskNodeId ? [previousTaskNodeId] : [];
91
+ nodes.push({
92
+ id: nodeId,
93
+ kind: "unit",
94
+ dependsOn,
95
+ writes: task.key_files,
96
+ metadata: {
97
+ unitType: "execute-task",
98
+ unitId: `${mid}.${sid}.${task.id}`,
99
+ title: task.title,
100
+ status: task.status,
101
+ },
102
+ });
103
+ previousTaskNodeId = nodeId;
104
+ }
105
+
106
+ if (previousTaskNodeId) {
107
+ nodes.push({
108
+ id: `complete-slice:${mid}:${sid}`,
109
+ kind: "verification",
110
+ dependsOn: [previousTaskNodeId],
111
+ metadata: {
112
+ unitType: "complete-slice",
113
+ unitId: `${mid}.${sid}`,
114
+ title: slice.title,
115
+ status: slice.status,
116
+ },
117
+ });
118
+ }
119
+ }
120
+
121
+ const output = {
122
+ compiledAt: new Date().toISOString(),
123
+ milestoneId: mid,
124
+ pipeline: {
125
+ clarifyRoundLimit,
126
+ researchSynthesized,
127
+ draftContextIncluded,
128
+ finalizedContextIncluded,
129
+ sourcePhase: state.phase,
130
+ },
131
+ nodes,
132
+ };
133
+
134
+ const outPath = graphOutputPath(basePath);
135
+ mkdirSync(join(gsdRoot(basePath), "runtime"), { recursive: true });
136
+ writeFileSync(outPath, JSON.stringify(output, null, 2) + "\n", "utf-8");
137
+
138
+ return {
139
+ ok: true,
140
+ graphPath: outPath,
141
+ nodeCount: nodes.length,
142
+ clarifyRoundLimit,
143
+ researchSynthesized: output.pipeline.researchSynthesized,
144
+ draftContextIncluded: output.pipeline.draftContextIncluded,
145
+ finalizedContextIncluded: output.pipeline.finalizedContextIncluded,
146
+ };
147
+ }
148
+
149
+ export function ensurePlanV2Graph(basePath: string, state: GSDState): PlanV2CompileResult {
150
+ const compiled = compileUnitGraphFromState(basePath, state);
151
+ if (!compiled.ok) return compiled;
152
+ if ((compiled.nodeCount ?? 0) <= 0) {
153
+ return { ok: false, reason: "compiled graph is empty" };
154
+ }
155
+ return compiled;
156
+ }
@@ -20,6 +20,8 @@ import { appendFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
20
20
  import { join } from "node:path";
21
21
 
22
22
  import { appendNotification } from "./notification-store.js";
23
+ import { buildAuditEnvelope, emitUokAuditEvent } from "./uok/audit.js";
24
+ import { isUnifiedAuditEnabled } from "./uok/audit-toggle.js";
23
25
 
24
26
  // ─── Types ──────────────────────────────────────────────────────────────
25
27
 
@@ -275,6 +277,29 @@ function _push(
275
277
  _buffer.shift();
276
278
  }
277
279
 
280
+ if (_auditBasePath && isUnifiedAuditEnabled()) {
281
+ try {
282
+ emitUokAuditEvent(
283
+ _auditBasePath,
284
+ buildAuditEnvelope({
285
+ traceId: `workflow-log:${component}`,
286
+ turnId: context?.id,
287
+ causedBy: context?.fn ?? context?.tool,
288
+ category: "orchestration",
289
+ type: severity === "error" ? "workflow-log-error" : "workflow-log-warn",
290
+ payload: {
291
+ component,
292
+ message,
293
+ context: context ?? {},
294
+ },
295
+ }),
296
+ );
297
+ } catch (auditEmitErr) {
298
+ // Best-effort: unified audit projection must never block workflow logger.
299
+ _writeStderr(`[gsd:workflow-logger] unified-audit emit failed: ${(auditEmitErr as Error).message}\n`);
300
+ }
301
+ }
302
+
278
303
  // Persist errors to .gsd/audit-log.jsonl so they survive context resets.
279
304
  // Only error-severity entries are persisted — warnings are ephemeral (stderr + buffer)
280
305
  // to avoid log amplification from expected-control-flow catch paths.
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  _getAdapter,
3
- transaction,
3
+ readTransaction,
4
+ restoreManifest,
4
5
  type MilestoneRow,
5
6
  type SliceRow,
6
7
  type TaskRow,
@@ -74,9 +75,7 @@ export function snapshotState(): StateManifest {
74
75
 
75
76
  // Wrap all reads in a deferred transaction so the snapshot is consistent
76
77
  // (all SELECTs see the same DB state even if a concurrent write lands between them).
77
- db.exec("BEGIN DEFERRED");
78
-
79
- try {
78
+ return readTransaction(() => {
80
79
  const rawMilestones = db.prepare("SELECT * FROM milestones ORDER BY id").all() as Record<string, unknown>[];
81
80
  const milestones: MilestoneRow[] = rawMilestones.map((r) => ({
82
81
  id: r["id"] as string,
@@ -186,109 +185,15 @@ export function snapshotState(): StateManifest {
186
185
  verification_evidence,
187
186
  };
188
187
 
189
- db.exec("COMMIT");
190
188
  return result;
191
- } catch (err) {
192
- try { db.exec("ROLLBACK"); } catch { /* ignore rollback failure */ }
193
- throw err;
194
- }
189
+ });
195
190
  }
196
191
 
197
192
  // ─── restore ─────────────────────────────────────────────────────────────
198
-
199
- /**
200
- * Atomically replace all workflow state from a manifest.
201
- * Runs inside a transaction — if any insert fails, no tables are modified.
202
- * Only touches engine tables + decisions. Does NOT modify artifacts or memories.
203
- */
204
- function restore(manifest: StateManifest): void {
205
- const db = requireDb();
206
-
207
- transaction(() => {
208
- // Clear engine tables (order matters for foreign-key-like consistency)
209
- db.exec("DELETE FROM verification_evidence");
210
- db.exec("DELETE FROM tasks");
211
- db.exec("DELETE FROM slices");
212
- db.exec("DELETE FROM milestones");
213
- db.exec("DELETE FROM decisions WHERE 1=1");
214
-
215
- // Restore milestones
216
- const msStmt = db.prepare(
217
- `INSERT INTO milestones (id, title, status, depends_on, created_at, completed_at,
218
- vision, success_criteria, key_risks, proof_strategy,
219
- verification_contract, verification_integration, verification_operational, verification_uat,
220
- definition_of_done, requirement_coverage, boundary_map_markdown)
221
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
222
- );
223
- for (const m of manifest.milestones) {
224
- msStmt.run(
225
- m.id, m.title, m.status,
226
- JSON.stringify(m.depends_on), m.created_at, m.completed_at,
227
- m.vision, JSON.stringify(m.success_criteria), JSON.stringify(m.key_risks),
228
- JSON.stringify(m.proof_strategy),
229
- m.verification_contract, m.verification_integration, m.verification_operational, m.verification_uat,
230
- JSON.stringify(m.definition_of_done), m.requirement_coverage, m.boundary_map_markdown,
231
- );
232
- }
233
-
234
- // Restore slices
235
- const slStmt = db.prepare(
236
- `INSERT INTO slices (milestone_id, id, title, status, risk, depends, demo,
237
- created_at, completed_at, full_summary_md, full_uat_md,
238
- goal, success_criteria, proof_level, integration_closure, observability_impact,
239
- sequence, replan_triggered_at)
240
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
241
- );
242
- for (const s of manifest.slices) {
243
- slStmt.run(
244
- s.milestone_id, s.id, s.title, s.status, s.risk,
245
- JSON.stringify(s.depends), s.demo,
246
- s.created_at, s.completed_at, s.full_summary_md, s.full_uat_md,
247
- s.goal, s.success_criteria, s.proof_level, s.integration_closure, s.observability_impact,
248
- s.sequence, s.replan_triggered_at,
249
- );
250
- }
251
-
252
- // Restore tasks
253
- const tkStmt = db.prepare(
254
- `INSERT INTO tasks (milestone_id, slice_id, id, title, status,
255
- one_liner, narrative, verification_result, duration, completed_at,
256
- blocker_discovered, deviations, known_issues, key_files, key_decisions,
257
- full_summary_md, description, estimate, files, verify,
258
- inputs, expected_output, observability_impact, sequence)
259
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
260
- );
261
- for (const t of manifest.tasks) {
262
- tkStmt.run(
263
- t.milestone_id, t.slice_id, t.id, t.title, t.status,
264
- t.one_liner, t.narrative, t.verification_result, t.duration, t.completed_at,
265
- t.blocker_discovered ? 1 : 0, t.deviations, t.known_issues,
266
- JSON.stringify(t.key_files), JSON.stringify(t.key_decisions),
267
- t.full_summary_md, t.description, t.estimate, JSON.stringify(t.files), t.verify,
268
- JSON.stringify(t.inputs), JSON.stringify(t.expected_output),
269
- t.observability_impact, t.sequence,
270
- );
271
- }
272
-
273
- // Restore decisions
274
- const dcStmt = db.prepare(
275
- `INSERT INTO decisions (seq, id, when_context, scope, decision, choice, rationale, revisable, made_by, superseded_by)
276
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
277
- );
278
- for (const d of manifest.decisions) {
279
- dcStmt.run(d.seq, d.id, d.when_context, d.scope, d.decision, d.choice, d.rationale, d.revisable, d.made_by, d.superseded_by);
280
- }
281
-
282
- // Restore verification evidence
283
- const evStmt = db.prepare(
284
- `INSERT INTO verification_evidence (task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at)
285
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
286
- );
287
- for (const e of manifest.verification_evidence) {
288
- evStmt.run(e.task_id, e.slice_id, e.milestone_id, e.command, e.exit_code, e.verdict, e.duration_ms, e.created_at);
289
- }
290
- });
291
- }
193
+ //
194
+ // The actual restore() implementation lives in gsd-db.ts (single-writer
195
+ // invariant). This module only orchestrates reading the manifest file
196
+ // and handing it to the writer.
292
197
 
293
198
  // ─── writeManifest ───────────────────────────────────────────────────────
294
199
 
@@ -346,6 +251,6 @@ export function bootstrapFromManifest(basePath: string): boolean {
346
251
  return false;
347
252
  }
348
253
 
349
- restore(manifest);
254
+ restoreManifest(manifest);
350
255
  return true;
351
256
  }
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { existsSync, readdirSync, readFileSync } from "node:fs";
7
7
  import { join } from "node:path";
8
- import { _getAdapter, transaction } from "./gsd-db.js";
8
+ import { _getAdapter, bulkInsertLegacyHierarchy } from "./gsd-db.js";
9
9
  import { parseRoadmap, parsePlan } from "./parsers-legacy.js";
10
10
  import { logWarning } from "./workflow-logger.js";
11
11
 
@@ -219,34 +219,26 @@ export function migrateFromMarkdown(basePath: string): void {
219
219
  return;
220
220
  }
221
221
 
222
- const placeholders = migratedMilestoneIds.map(() => "?").join(",");
223
- transaction(() => {
224
- // Clear existing data to handle stale DB shape (DELETE ... IN (...))
225
- db.prepare(`DELETE FROM tasks WHERE milestone_id IN (${placeholders})`).run(...migratedMilestoneIds);
226
- db.prepare(`DELETE FROM slices WHERE milestone_id IN (${placeholders})`).run(...migratedMilestoneIds);
227
- db.prepare(`DELETE FROM milestones WHERE id IN (${placeholders})`).run(...migratedMilestoneIds);
228
-
229
- // Insert milestones
230
- const insertMilestone = db.prepare("INSERT INTO milestones (id, title, status, created_at) VALUES (?, ?, ?, ?)");
231
- for (const m of milestoneInserts) {
232
- insertMilestone.run(m.id, m.title, m.status, now);
233
- }
234
-
235
- // Insert slices (using v10 column names: depends, sequence)
236
- const insertSlice = db.prepare(
237
- "INSERT INTO slices (id, milestone_id, title, status, risk, depends, sequence, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
238
- );
239
- for (const s of sliceInserts) {
240
- insertSlice.run(s.id, s.milestoneId, s.title, s.status, s.risk, "[]", s.sequence, now);
241
- }
242
-
243
- // Insert tasks (using v10 column names: sequence, blocker_discovered, full_summary_md)
244
- const insertTask = db.prepare(
245
- "INSERT INTO tasks (id, slice_id, milestone_id, title, description, status, estimate, files, sequence) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
246
- );
247
- for (const t of taskInserts) {
248
- insertTask.run(t.id, t.sliceId, t.milestoneId, t.title, "", t.status, "", "[]", t.sequence);
249
- }
222
+ bulkInsertLegacyHierarchy({
223
+ milestones: milestoneInserts,
224
+ slices: sliceInserts.map(s => ({
225
+ id: s.id,
226
+ milestoneId: s.milestoneId,
227
+ title: s.title,
228
+ status: s.status,
229
+ risk: s.risk,
230
+ sequence: s.sequence,
231
+ })),
232
+ tasks: taskInserts.map(t => ({
233
+ id: t.id,
234
+ sliceId: t.sliceId,
235
+ milestoneId: t.milestoneId,
236
+ title: t.title,
237
+ status: t.status,
238
+ sequence: t.sequence,
239
+ })),
240
+ clearMilestoneIds: migratedMilestoneIds,
241
+ createdAt: now,
250
242
  });
251
243
  }
252
244
 
@@ -350,7 +350,14 @@ export async function renderStateProjection(basePath: string): Promise<void> {
350
350
  // Probe DB handle — adapter may be set but underlying handle closed
351
351
  const adapter = _getAdapter();
352
352
  if (!adapter) return;
353
- try { adapter.prepare("SELECT 1").get(); } catch { return; }
353
+ try {
354
+ adapter.prepare("SELECT 1").get();
355
+ } catch (err) {
356
+ logWarning("projection", "renderStateProjection: DB handle probe failed, skipping render", {
357
+ error: (err as Error).message,
358
+ });
359
+ return;
360
+ }
354
361
  const state = await deriveState(basePath);
355
362
  const content = renderStateContent(state);
356
363
  const dir = join(basePath, ".gsd");