@north-light/crouter 0.3.311 → 0.3.313

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 (520) hide show
  1. package/dist/api/client.d.ts +27 -30
  2. package/dist/api/client.js +80 -67
  3. package/dist/api/dto/broker-ops.d.ts +10 -20
  4. package/dist/api/dto/canvas.d.ts +1 -10
  5. package/dist/api/dto/health.d.ts +113 -0
  6. package/dist/api/dto/human-requests.d.ts +14 -3
  7. package/dist/api/dto/human.d.ts +2 -48
  8. package/dist/api/dto/human.js +3 -2
  9. package/dist/api/dto/inbox.d.ts +14 -0
  10. package/dist/api/dto/mail.d.ts +43 -0
  11. package/dist/api/dto/nodes.d.ts +11 -8
  12. package/dist/api/dto/recovery.d.ts +96 -0
  13. package/dist/api/dto/reviews.d.ts +2 -2
  14. package/dist/api/routes.d.ts +9 -6
  15. package/dist/api/routes.js +11 -11
  16. package/dist/build-root.d.ts +4 -0
  17. package/dist/build-root.js +11 -1
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
  22. package/dist/cli.js +10 -1
  23. package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
  24. package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
  25. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  26. package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
  27. package/dist/clients/attach/chrome/inbox-strip.js +17 -9
  28. package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
  29. package/dist/clients/attach/chrome/ticket-panel.js +77 -46
  30. package/dist/clients/attach/overlays/graph.js +6 -9
  31. package/dist/clients/attach/render/chat-view.d.ts +5 -4
  32. package/dist/clients/attach/render/chat-view.js +22 -13
  33. package/dist/clients/attach/render/page-block.d.ts +11 -7
  34. package/dist/clients/attach/render/page-block.js +64 -55
  35. package/dist/clients/attach/viewer.js +746 -735
  36. package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
  37. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
  38. package/dist/clients/inbox/controller.d.ts +42 -14
  39. package/dist/clients/inbox/controller.js +240 -124
  40. package/dist/clients/inbox/dto-adapt.d.ts +28 -0
  41. package/dist/clients/inbox/dto-adapt.js +93 -0
  42. package/dist/clients/inbox/page-adapter.d.ts +5 -4
  43. package/dist/clients/inbox/page-adapter.js +12 -12
  44. package/dist/clients/inbox/resolve.d.ts +10 -5
  45. package/dist/clients/inbox/resolve.js +13 -12
  46. package/dist/clients/inbox/review/review-client.d.ts +0 -1
  47. package/dist/clients/inbox/review/review-client.js +0 -4
  48. package/dist/clients/inbox/review-adapter.d.ts +2 -1
  49. package/dist/clients/inbox/review-adapter.js +3 -5
  50. package/dist/clients/inbox/surface.d.ts +2 -2
  51. package/dist/clients/inbox/surface.js +19 -8
  52. package/dist/clients/inbox/tui.d.ts +3 -3
  53. package/dist/commands/__tests__/human.test.js +31 -15
  54. package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
  55. package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
  56. package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
  57. package/dist/commands/api-client.d.ts +5 -4
  58. package/dist/commands/api-client.js +13 -7
  59. package/dist/commands/canvas-history/shared.js +1 -1
  60. package/dist/commands/canvas-history.js +1 -1
  61. package/dist/commands/canvas-roster.js +1 -1
  62. package/dist/commands/canvas.js +1 -2
  63. package/dist/commands/human/feedback.js +20 -17
  64. package/dist/commands/human/prompts.js +45 -36
  65. package/dist/commands/human/queue.js +73 -123
  66. package/dist/commands/human/review.js +6 -16
  67. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
  68. package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
  69. package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
  70. package/dist/commands/node-inspect-artifacts.js +1 -1
  71. package/dist/commands/node-lifecycle-revive.d.ts +2 -2
  72. package/dist/commands/node-lifecycle-revive.js +9 -19
  73. package/dist/commands/pkg/plugin-manage.js +0 -1
  74. package/dist/commands/profile/show.js +4 -12
  75. package/dist/commands/surface-tmux-spread.js +1 -5
  76. package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
  77. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
  78. package/dist/commands/sys/branch.d.ts +2 -0
  79. package/dist/commands/sys/branch.js +19 -0
  80. package/dist/commands/sys/config.js +106 -33
  81. package/dist/commands/sys/daemon.d.ts +2 -0
  82. package/dist/commands/sys/daemon.js +130 -7
  83. package/dist/commands/sys/doctor.js +5 -15
  84. package/dist/commands/sys/migrate.js +21 -92
  85. package/dist/commands/sys/setup-settings-runner.js +4 -2
  86. package/dist/commands/sys.js +2 -15
  87. package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
  88. package/dist/core/__tests__/boot.test.js +32 -25
  89. package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
  90. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
  91. package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
  92. package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
  93. package/dist/core/__tests__/canvas.test.js +18 -47
  94. package/dist/core/__tests__/child-death-wake.test.js +29 -7
  95. package/dist/core/__tests__/cli-help-contract.test.js +2 -0
  96. package/dist/core/__tests__/close.test.js +29 -10
  97. package/dist/core/__tests__/collectible.test.js +2 -1
  98. package/dist/core/__tests__/config-change-delta.test.js +2 -0
  99. package/dist/core/__tests__/context-intro.test.js +17 -5
  100. package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
  101. package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
  102. package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
  103. package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
  104. package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
  105. package/dist/core/__tests__/daemon-boot.test.js +51 -14
  106. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  107. package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
  108. package/dist/core/__tests__/focuses.test.js +10 -5
  109. package/dist/core/__tests__/helpers/harness.js +50 -18
  110. package/dist/core/__tests__/history-inbox.test.js +12 -16
  111. package/dist/core/__tests__/human-action-delivery.test.js +48 -28
  112. package/dist/core/__tests__/human-actions.test.js +7 -3
  113. package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
  114. package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
  115. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
  116. package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
  117. package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
  118. package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
  119. package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
  120. package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
  121. package/dist/core/__tests__/integration/lifecycle-hooks.test.js +312 -1
  122. package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
  123. package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
  124. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
  125. package/dist/core/__tests__/integration/revive.test.js +67 -21
  126. package/dist/core/__tests__/integration/spawn-root.test.js +62 -19
  127. package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
  128. package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
  129. package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
  130. package/dist/core/__tests__/kickoff.test.js +36 -39
  131. package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
  132. package/dist/core/__tests__/lifecycle.test.js +2 -1
  133. package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
  134. package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
  135. package/dist/core/__tests__/migration.test.js +145 -31
  136. package/dist/core/__tests__/model-pin-durability.test.js +4 -1
  137. package/dist/core/__tests__/model-routes-config.test.js +13 -5
  138. package/dist/core/__tests__/node-outcome.test.js +93 -26
  139. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +4 -3
  140. package/dist/core/__tests__/on-read-dedup-resume.test.js +8 -7
  141. package/dist/core/__tests__/on-read-nested-store.test.js +8 -7
  142. package/dist/core/__tests__/passive-subscription.test.js +50 -157
  143. package/dist/core/__tests__/plugin-kinds.test.js +6 -4
  144. package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
  145. package/dist/core/__tests__/plugin-page-components.test.js +6 -4
  146. package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
  147. package/dist/core/__tests__/profile-project-memory-delivery.test.js +35 -32
  148. package/dist/core/__tests__/prune.test.js +11 -5
  149. package/dist/core/__tests__/push-final-guard.test.js +14 -7
  150. package/dist/core/__tests__/relaunch-root.test.js +30 -2
  151. package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
  152. package/dist/core/__tests__/repository-root-identity.test.js +4 -0
  153. package/dist/core/__tests__/review-model-floor.test.js +6 -3
  154. package/dist/core/__tests__/revive-all.test.js +13 -3
  155. package/dist/core/__tests__/revive-capacity.test.js +26 -4
  156. package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
  157. package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
  158. package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
  159. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
  160. package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
  161. package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
  162. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
  163. package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
  164. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
  165. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +5 -4
  166. package/dist/core/__tests__/stop-guard.test.js +2 -1
  167. package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
  168. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +19 -5
  169. package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
  170. package/dist/core/bootstrap.js +2 -0
  171. package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
  172. package/dist/core/broker-client/transport-socket.d.ts +1 -0
  173. package/dist/core/broker-client/transport-socket.js +13 -5
  174. package/dist/core/canvas/__tests__/attention.test.js +29 -35
  175. package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
  176. package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
  177. package/dist/core/canvas/attention.d.ts +2 -5
  178. package/dist/core/canvas/attention.js +15 -64
  179. package/dist/core/canvas/boot.d.ts +6 -7
  180. package/dist/core/canvas/boot.js +5 -9
  181. package/dist/core/canvas/canvas.d.ts +13 -109
  182. package/dist/core/canvas/canvas.js +140 -401
  183. package/dist/core/canvas/crons.d.ts +2 -0
  184. package/dist/core/canvas/crons.js +16 -15
  185. package/dist/core/canvas/daemon-owner.js +10 -0
  186. package/dist/core/canvas/db.d.ts +2 -2
  187. package/dist/core/canvas/db.js +2 -18
  188. package/dist/core/canvas/deliveries.d.ts +104 -0
  189. package/dist/core/canvas/deliveries.js +354 -0
  190. package/dist/core/canvas/executions.d.ts +29 -0
  191. package/dist/core/canvas/executions.js +68 -0
  192. package/dist/core/canvas/history.js +35 -35
  193. package/dist/core/canvas/index.d.ts +3 -1
  194. package/dist/core/canvas/index.js +3 -1
  195. package/dist/core/canvas/migrations.js +20 -12
  196. package/dist/core/canvas/nav-model.js +1 -3
  197. package/dist/core/canvas/nav-render.d.ts +4 -4
  198. package/dist/core/canvas/nav-render.js +11 -21
  199. package/dist/core/canvas/node-sql-migration.d.ts +3 -0
  200. package/dist/core/canvas/node-sql-migration.js +261 -0
  201. package/dist/core/canvas/paths.d.ts +2 -16
  202. package/dist/core/canvas/paths.js +2 -31
  203. package/dist/core/canvas/recovery.d.ts +76 -0
  204. package/dist/core/canvas/recovery.js +588 -0
  205. package/dist/core/canvas/remote-canvas-source.js +4 -0
  206. package/dist/core/canvas/render-source.d.ts +16 -27
  207. package/dist/core/canvas/render-source.js +16 -45
  208. package/dist/core/canvas/sessions.d.ts +33 -0
  209. package/dist/core/canvas/sessions.js +78 -0
  210. package/dist/core/canvas/types.d.ts +33 -33
  211. package/dist/core/canvas/types.js +2 -5
  212. package/dist/core/canvas/waits.d.ts +18 -0
  213. package/dist/core/canvas/waits.js +70 -0
  214. package/dist/core/canvas/worktrees.d.ts +40 -0
  215. package/dist/core/canvas/worktrees.js +93 -0
  216. package/dist/core/command-hooks/artifact.d.ts +6 -0
  217. package/dist/core/command-hooks/artifact.js +22 -6
  218. package/dist/core/command-hooks/discovery.d.ts +2 -0
  219. package/dist/core/command-hooks/discovery.js +2 -0
  220. package/dist/core/command-hooks/lifecycle-catalog.d.ts +20 -2
  221. package/dist/core/command-hooks/lifecycle-catalog.js +7 -2
  222. package/dist/core/command-hooks/lifecycle-create.d.ts +4 -0
  223. package/dist/core/command-hooks/lifecycle-create.js +51 -0
  224. package/dist/core/command-hooks/schema.d.ts +2 -2
  225. package/dist/core/command-hooks/schema.js +5 -4
  226. package/dist/core/command-hooks/transport/exec-invoke.js +3 -1
  227. package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +18 -8
  228. package/dist/core/command-hooks/transport/exec-lifecycle.js +89 -30
  229. package/dist/core/config.d.ts +17 -12
  230. package/dist/core/config.js +106 -155
  231. package/dist/core/errors.d.ts +1 -0
  232. package/dist/core/errors.js +4 -0
  233. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  234. package/dist/core/feed/feed.d.ts +0 -6
  235. package/dist/core/feed/feed.js +68 -56
  236. package/dist/core/feed/inbox.d.ts +7 -81
  237. package/dist/core/feed/inbox.js +46 -378
  238. package/dist/core/feed/messages.d.ts +58 -0
  239. package/dist/core/feed/messages.js +217 -0
  240. package/dist/core/fs-utils.d.ts +4 -0
  241. package/dist/core/fs-utils.js +21 -1
  242. package/dist/core/human/answer.d.ts +1 -1
  243. package/dist/core/human/answer.js +1 -1
  244. package/dist/core/human/claim.d.ts +1 -1
  245. package/dist/core/human/claim.js +2 -4
  246. package/dist/core/human/component-docs.js +1 -1
  247. package/dist/core/human/feedback-companion.js +4 -3
  248. package/dist/core/human/feedback.d.ts +5 -8
  249. package/dist/core/human/feedback.js +57 -85
  250. package/dist/core/human/page-authoring.d.ts +30 -0
  251. package/dist/core/human/page-authoring.js +19 -0
  252. package/dist/core/human/requests.d.ts +136 -0
  253. package/dist/core/human/requests.js +515 -0
  254. package/dist/core/human/root.d.ts +0 -7
  255. package/dist/core/human/root.js +0 -17
  256. package/dist/core/human/scan.d.ts +2 -7
  257. package/dist/core/human/scan.js +48 -132
  258. package/dist/core/human/summary.d.ts +1 -1
  259. package/dist/core/human/summary.js +1 -1
  260. package/dist/core/human/tickets.d.ts +23 -83
  261. package/dist/core/human/tickets.js +92 -243
  262. package/dist/core/human/types.d.ts +5 -1
  263. package/dist/core/installed-plugins.js +8 -3
  264. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  265. package/dist/core/locked-file.d.ts +6 -3
  266. package/dist/core/locked-file.js +36 -9
  267. package/dist/core/memory/extensions.js +2 -0
  268. package/dist/core/preview-registry.js +0 -1
  269. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  270. package/dist/core/profiles/default-binding.d.ts +0 -4
  271. package/dist/core/profiles/default-binding.js +12 -58
  272. package/dist/core/profiles/env-store.js +8 -3
  273. package/dist/core/profiles/manifest.d.ts +2 -37
  274. package/dist/core/profiles/manifest.js +35 -161
  275. package/dist/core/profiles/select.js +3 -0
  276. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  277. package/dist/core/review/__tests__/comments.test.js +28 -10
  278. package/dist/core/review/__tests__/remap.test.js +28 -10
  279. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  280. package/dist/core/review/birth.d.ts +1 -1
  281. package/dist/core/review/birth.js +34 -5
  282. package/dist/core/review/comments.js +1 -1
  283. package/dist/core/review/companion.d.ts +1 -1
  284. package/dist/core/review/companion.js +2 -2
  285. package/dist/core/review/document.js +1 -1
  286. package/dist/core/review/project.d.ts +5 -1
  287. package/dist/core/review/project.js +14 -36
  288. package/dist/core/review/realize.d.ts +3 -6
  289. package/dist/core/review/realize.js +51 -168
  290. package/dist/core/review/remap.js +1 -1
  291. package/dist/core/review/stage.d.ts +3 -2
  292. package/dist/core/review/stage.js +2 -3
  293. package/dist/core/review/store.d.ts +3 -21
  294. package/dist/core/review/store.js +140 -186
  295. package/dist/core/review/types.d.ts +0 -1
  296. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  297. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  298. package/dist/core/runtime/broker/auth-reload.js +9 -10
  299. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  300. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  301. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  302. package/dist/core/runtime/broker/extension-abort.js +11 -0
  303. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  304. package/dist/core/runtime/broker/fault-retry.js +142 -95
  305. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  306. package/dist/core/runtime/broker/inbox.js +4 -92
  307. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  308. package/dist/core/runtime/broker/rebind.js +21 -12
  309. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  310. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  311. package/dist/core/runtime/broker.js +28 -22
  312. package/dist/core/runtime/close.d.ts +3 -9
  313. package/dist/core/runtime/close.js +16 -27
  314. package/dist/core/runtime/fault.d.ts +3 -93
  315. package/dist/core/runtime/fault.js +9 -419
  316. package/dist/core/runtime/kickoff.d.ts +3 -6
  317. package/dist/core/runtime/kickoff.js +12 -18
  318. package/dist/core/runtime/launch.js +1 -1
  319. package/dist/core/runtime/lifecycle.js +40 -7
  320. package/dist/core/runtime/nodes.d.ts +5 -1
  321. package/dist/core/runtime/nodes.js +26 -11
  322. package/dist/core/runtime/placement.js +2 -2
  323. package/dist/core/runtime/recycle.js +24 -14
  324. package/dist/core/runtime/reset.js +26 -7
  325. package/dist/core/runtime/revive.js +226 -217
  326. package/dist/core/runtime/spawn.d.ts +4 -1
  327. package/dist/core/runtime/spawn.js +43 -5
  328. package/dist/core/runtime/warm-pool.d.ts +2 -2
  329. package/dist/core/runtime/warm-pool.js +23 -3
  330. package/dist/core/scoped-state/db.d.ts +7 -0
  331. package/dist/core/scoped-state/db.js +92 -0
  332. package/dist/core/scoped-state/migrate.d.ts +11 -0
  333. package/dist/core/scoped-state/migrate.js +198 -0
  334. package/dist/core/scoped-state/paths.d.ts +9 -0
  335. package/dist/core/scoped-state/paths.js +27 -0
  336. package/dist/core/scoped-state/profiles.d.ts +12 -0
  337. package/dist/core/scoped-state/profiles.js +62 -0
  338. package/dist/core/scoped-state/providers.d.ts +16 -0
  339. package/dist/core/scoped-state/providers.js +8 -0
  340. package/dist/core/scoped-state/schema.d.ts +3 -0
  341. package/dist/core/scoped-state/schema.js +26 -0
  342. package/dist/core/scoped-state/settings.d.ts +28 -0
  343. package/dist/core/scoped-state/settings.js +82 -0
  344. package/dist/core/subscription-state.d.ts +29 -48
  345. package/dist/core/subscription-state.js +176 -712
  346. package/dist/core/worktree-close.js +4 -4
  347. package/dist/core/worktree-mutation-async.js +2 -2
  348. package/dist/core/worktree-sweep.js +11 -16
  349. package/dist/core/worktree.js +6 -12
  350. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  351. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  352. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  353. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  354. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  355. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +41 -17
  356. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  357. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  358. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  359. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  360. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  361. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  362. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  363. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  364. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  365. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +6 -3
  366. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  367. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  368. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  369. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  370. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  371. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +29 -43
  372. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  373. package/dist/daemon/api/bridge.js +1 -1
  374. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  375. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  376. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  377. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  378. package/dist/daemon/api/handlers/canvas.js +2 -44
  379. package/dist/daemon/api/handlers/daemon.js +41 -0
  380. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  381. package/dist/daemon/api/handlers/health.js +10 -5
  382. package/dist/daemon/api/handlers/human-requests.js +168 -188
  383. package/dist/daemon/api/handlers/human.js +3 -148
  384. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  385. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  386. package/dist/daemon/api/handlers/inbox.js +21 -120
  387. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  388. package/dist/daemon/api/handlers/messages.js +73 -15
  389. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  390. package/dist/daemon/api/handlers/nodes.d.ts +1 -0
  391. package/dist/daemon/api/handlers/nodes.js +41 -42
  392. package/dist/daemon/api/handlers/reviews.js +4 -29
  393. package/dist/daemon/api/map.d.ts +25 -3
  394. package/dist/daemon/api/map.js +84 -14
  395. package/dist/daemon/api/server.js +68 -9
  396. package/dist/daemon/control.d.ts +18 -0
  397. package/dist/daemon/cron/disposition.d.ts +2 -0
  398. package/dist/daemon/cron/disposition.js +8 -5
  399. package/dist/daemon/cron/settle.js +37 -13
  400. package/dist/daemon/cron/sinks.d.ts +18 -1
  401. package/dist/daemon/cron/sinks.js +47 -93
  402. package/dist/daemon/crtrd-cli.js +4 -19
  403. package/dist/daemon/crtrd.d.ts +2 -0
  404. package/dist/daemon/crtrd.js +206 -81
  405. package/dist/daemon/fleet.js +5 -6
  406. package/dist/daemon/human/finish.d.ts +12 -24
  407. package/dist/daemon/human/finish.js +88 -285
  408. package/dist/daemon/human/settle.d.ts +40 -0
  409. package/dist/daemon/human/settle.js +89 -0
  410. package/dist/daemon/human/sweep.d.ts +20 -5
  411. package/dist/daemon/human/sweep.js +56 -60
  412. package/dist/daemon/manage.d.ts +21 -16
  413. package/dist/daemon/manage.js +85 -51
  414. package/dist/daemon/messaging/node-message.d.ts +1 -1
  415. package/dist/daemon/messaging/node-message.js +9 -12
  416. package/dist/daemon/park-activity.js +3 -3
  417. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  418. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  419. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  420. package/dist/daemon/reconcilers/controller-death.js +6 -18
  421. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  422. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  423. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  424. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  425. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  426. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  427. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  428. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  429. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  430. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  431. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  432. package/dist/daemon/review/companion.js +5 -11
  433. package/dist/daemon/review/deliver.d.ts +1 -5
  434. package/dist/daemon/review/deliver.js +3 -52
  435. package/dist/daemon/review/finish.d.ts +2 -27
  436. package/dist/daemon/review/finish.js +79 -263
  437. package/dist/daemon/review/sweep.d.ts +3 -10
  438. package/dist/daemon/review/sweep.js +13 -131
  439. package/dist/daemon/startup-policy.d.ts +0 -5
  440. package/dist/daemon/startup-policy.js +0 -5
  441. package/dist/hook-authoring.d.ts +28 -2
  442. package/dist/hook-authoring.js +53 -1
  443. package/dist/index.d.ts +3 -2
  444. package/dist/index.js +1 -1
  445. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  446. package/dist/migrations/__tests__/activation.test.js +9 -6
  447. package/dist/migrations/activation.d.ts +3 -2
  448. package/dist/migrations/activation.js +2 -4
  449. package/dist/migrations/corpus.d.ts +2 -5
  450. package/dist/migrations/corpus.js +9 -20
  451. package/dist/migrations/runner.d.ts +3 -1
  452. package/dist/migrations/runner.js +6 -2
  453. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  454. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  455. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  456. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  457. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  458. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  459. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  460. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  461. package/dist/pi-extensions/canvas-stophook.js +47 -31
  462. package/dist/shared/env.d.ts +1 -0
  463. package/dist/shared/env.js +3 -0
  464. package/package.json +1 -1
  465. package/runtime.lock.json +5 -5
  466. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  467. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  468. package/dist/clients/inbox/review-visibility.js +0 -19
  469. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  470. package/dist/commands/canvas-rebuild-index.js +0 -46
  471. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  472. package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
  473. package/dist/core/__tests__/human-deliver.test.js +0 -256
  474. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  475. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  476. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  477. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  478. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  479. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  480. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  481. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  482. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  483. package/dist/core/canvas/human-deliveries.js +0 -75
  484. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  485. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  486. package/dist/core/feed/passive.d.ts +0 -3
  487. package/dist/core/feed/passive.js +0 -53
  488. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  489. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  490. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  491. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  492. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  493. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  494. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  495. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  496. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  497. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  498. package/dist/core/review/ticket-filter.d.ts +0 -17
  499. package/dist/core/review/ticket-filter.js +0 -21
  500. package/dist/core/runtime/broker/passive.d.ts +0 -17
  501. package/dist/core/runtime/broker/passive.js +0 -44
  502. package/dist/core/runtime/busy.d.ts +0 -46
  503. package/dist/core/runtime/busy.js +0 -150
  504. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  505. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  506. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  507. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  508. package/dist/daemon/human/deliver-action.d.ts +0 -3
  509. package/dist/daemon/human/deliver-action.js +0 -9
  510. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  511. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  512. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  513. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  514. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  515. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  516. package/dist/daemon/startup-block-marker.d.ts +0 -25
  517. package/dist/daemon/startup-block-marker.js +0 -99
  518. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  519. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  520. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
@@ -60,6 +60,7 @@ import { createHash } from 'node:crypto';
60
60
  import { claimWarmSpare, deleteNode, getNode, listNodes, listWarmSpares, registerWarmSpare, unregisterWarmSpare, updateNode, warmSpareCount, } from '../canvas/index.js';
61
61
  import { recordedPidLiveness } from '../canvas/pid.js';
62
62
  import { nowIso } from '../fs-utils.js';
63
+ import { admitNodeCreate } from '../command-hooks/lifecycle-create.js';
63
64
  import { spawnChildPrepared } from './spawn.js';
64
65
  import { buildLaunchSpecAsync } from './launch.js';
65
66
  import { setModelLive } from './model-swap.js';
@@ -110,15 +111,34 @@ async function resolveRecipe(request) {
110
111
  return { key: warmRecipeKey(request.cwd, request.profileId, launch), launch, request };
111
112
  }
112
113
  /** Claim a spare for `request`, reshaped onto its persona — or null when the
113
- * pool cannot serve it. The caller falls back to a cold spawn; a claim never
114
- * fails the create. */
114
+ * pool cannot serve it. The caller falls back to a cold spawn; a refused
115
+ * create hook leaves the spare untouched and rejects the create. */
115
116
  export async function claimWarmNode(request, birth = {}) {
116
117
  const recipe = await resolveRecipe(request);
118
+ if (warmSpareCount(recipe.key) === 0)
119
+ return null;
117
120
  const created = nowIso();
118
121
  // The claim's requested deadline and delivery registration move with its
119
122
  // marker deletion, so the spare becomes caller-owned only as a fully armed
120
123
  // birth. meta.json follows with the same created stamp.
121
- const nodeId = claimWarmSpare(recipe.key, created, birth);
124
+ const releaseCreateGate = await admitNodeCreate({
125
+ kind: request.kind,
126
+ mode: request.mode,
127
+ cwd: request.cwd,
128
+ profile: request.profileId,
129
+ root: true,
130
+ parentId: null,
131
+ requestingNodeId: request.creator,
132
+ lifecycle: 'resident',
133
+ replaces: null,
134
+ });
135
+ let nodeId;
136
+ try {
137
+ nodeId = claimWarmSpare(recipe.key, created, birth);
138
+ }
139
+ finally {
140
+ releaseCreateGate();
141
+ }
122
142
  if (nodeId === null)
123
143
  return null;
124
144
  const spare = getNode(nodeId);
@@ -0,0 +1,7 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import type { ScopedStore } from './paths.js';
3
+ export declare function scopedStoreExists(store: ScopedStore): boolean;
4
+ export declare function openScopedStore(store: ScopedStore): DatabaseSync;
5
+ export declare function createScopedStore(store: ScopedStore, create: (db: DatabaseSync) => void): void;
6
+ export declare function withScopedWrite<T>(store: ScopedStore, run: (db: DatabaseSync) => T): T;
7
+ export declare function closeScopedStores(): void;
@@ -0,0 +1,92 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import { chmodSync, existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs';
3
+ import { SCOPED_SCHEMA_VERSION } from './schema.js';
4
+ const handles = new Map();
5
+ function version(db) {
6
+ return Number(db.prepare('PRAGMA user_version').get().user_version);
7
+ }
8
+ function secure(path) {
9
+ if (existsSync(path))
10
+ chmodSync(path, 0o600);
11
+ for (const suffix of ['-wal', '-shm'])
12
+ if (existsSync(`${path}${suffix}`))
13
+ chmodSync(`${path}${suffix}`, 0o600);
14
+ }
15
+ export function scopedStoreExists(store) {
16
+ return existsSync(store.path);
17
+ }
18
+ export function openScopedStore(store) {
19
+ const cached = handles.get(store.path);
20
+ if (cached !== undefined)
21
+ return cached;
22
+ if (!existsSync(store.path))
23
+ throw new Error(`scoped SQL store is not initialized: ${store.path}; crtr was updated and \`crtr sys daemon restart\` converts local state`);
24
+ const db = new DatabaseSync(store.path);
25
+ db.exec('PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;');
26
+ const found = version(db);
27
+ if (found === 0) {
28
+ db.close();
29
+ throw new Error(`scoped SQL store is uninitialized: ${store.path}; crtr was updated and \`crtr sys daemon restart\` converts local state`);
30
+ }
31
+ if (found > SCOPED_SCHEMA_VERSION) {
32
+ db.close();
33
+ throw new Error(`scoped SQL store ${store.path} uses unsupported schema version ${found}`);
34
+ }
35
+ if (found !== SCOPED_SCHEMA_VERSION) {
36
+ db.close();
37
+ throw new Error(`scoped SQL store ${store.path} requires an explicit conversion`);
38
+ }
39
+ secure(store.path);
40
+ handles.set(store.path, db);
41
+ return db;
42
+ }
43
+ export function createScopedStore(store, create) {
44
+ if (existsSync(store.path))
45
+ throw new Error(`scoped SQL store already exists: ${store.path}`);
46
+ mkdirSync(store.root, { recursive: true, mode: 0o700 });
47
+ if (!statSync(store.root).isDirectory())
48
+ throw new Error(`scoped SQL root is not a directory: ${store.root}`);
49
+ chmodSync(store.root, 0o700);
50
+ writeFileSync(store.path, '', { mode: 0o600 });
51
+ const db = new DatabaseSync(store.path);
52
+ try {
53
+ db.exec('PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON; BEGIN IMMEDIATE;');
54
+ create(db);
55
+ db.exec('COMMIT');
56
+ }
57
+ catch (error) {
58
+ try {
59
+ db.exec('ROLLBACK');
60
+ }
61
+ catch { }
62
+ throw error;
63
+ }
64
+ finally {
65
+ secure(store.path);
66
+ db.close();
67
+ }
68
+ }
69
+ export function withScopedWrite(store, run) {
70
+ const db = openScopedStore(store);
71
+ if (db.isTransaction)
72
+ return run(db);
73
+ db.exec('BEGIN IMMEDIATE');
74
+ try {
75
+ const value = run(db);
76
+ db.exec('COMMIT');
77
+ secure(store.path);
78
+ return value;
79
+ }
80
+ catch (error) {
81
+ try {
82
+ db.exec('ROLLBACK');
83
+ }
84
+ catch { }
85
+ throw error;
86
+ }
87
+ }
88
+ export function closeScopedStores() {
89
+ for (const db of handles.values())
90
+ db.close();
91
+ handles.clear();
92
+ }
@@ -0,0 +1,11 @@
1
+ export declare function initializeFreshScopedStore(input: {
2
+ kind: 'user' | 'project' | 'provider';
3
+ root: string;
4
+ }): void;
5
+ /** Conversion is intentionally explicit. Deployment coordination must prove all legacy writers at these shared roots are stopped before calling it. */
6
+ export declare function convertLegacyScopedStore(input: {
7
+ kind: 'user' | 'project' | 'provider';
8
+ root: string;
9
+ }): void;
10
+ /** Converts legacy provider pools only after the activation owner has stopped every writer sharing this agent directory. */
11
+ export declare function convertLegacyProviderStore(agentDir: string): Promise<void>;
@@ -0,0 +1,198 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from 'node:fs';
3
+ import { dirname, join, relative } from 'node:path';
4
+ import lockfile from 'proper-lockfile';
5
+ import { CONFIG_FILE, PROFILE_DIR, STATE_FILE } from '../../types.js';
6
+ import { LockedJsonFile } from '../locked-file.js';
7
+ import { createScopedStore, scopedStoreExists } from './db.js';
8
+ import { providerStore, projectStore, userStore } from './paths.js';
9
+ import { createScopedSchema } from './schema.js';
10
+ function writeOwnerRoot(db, key, root) { db.prepare('UPDATE scope_owners SET root=? WHERE owner_key=?').run(root, key); }
11
+ function json(path) { return JSON.parse(readFileSync(path, 'utf8')); }
12
+ function existsLegacy(paths) { return paths.some(existsSync); }
13
+ function preserve(root, paths) { const target = join(root, '.legacy-scoped-state'); mkdirSync(target, { recursive: true, mode: 0o700 }); chmodSync(target, 0o700); for (const path of paths)
14
+ if (existsSync(path) && statSync(path).isFile()) {
15
+ const fromRoot = relative(root, path);
16
+ if (fromRoot === '' || fromRoot.startsWith('..'))
17
+ throw new Error(`legacy state is outside its owning root: ${path}`);
18
+ const destination = join(target, fromRoot);
19
+ mkdirSync(dirname(destination), { recursive: true, mode: 0o700 });
20
+ copyFileSync(path, destination);
21
+ chmodSync(destination, 0o600);
22
+ } }
23
+ const PROFILE_ID_SHAPE = /^[a-z0-9]+(?:-[a-z0-9]+)*-[0-9a-f]{8}$/;
24
+ function userLegacyPaths(root) { const out = [join(root, CONFIG_FILE), join(root, STATE_FILE), join(root, 'profile-defaults.json')]; const profiles = join(root, PROFILE_DIR); if (existsSync(profiles))
25
+ for (const entry of readdirSync(profiles, { withFileTypes: true }))
26
+ if (entry.isDirectory() && PROFILE_ID_SHAPE.test(entry.name))
27
+ out.push(join(profiles, entry.name, 'profile.json'), join(profiles, entry.name, CONFIG_FILE), join(profiles, entry.name, STATE_FILE)); return out; }
28
+ function providerLegacyPaths(agentDir) { return [join(agentDir, 'anthropic-subscriptions.json'), join(agentDir, 'openai-codex-subscriptions.json'), join(agentDir, 'provider-rotation.json')]; }
29
+ function withLegacyProjectStateLock(root, run) {
30
+ const path = join(root, STATE_FILE);
31
+ const release = lockfile.lockSync(path, { realpath: false, retries: 0, stale: 30_000, update: 10_000 });
32
+ try {
33
+ return run();
34
+ }
35
+ finally {
36
+ release();
37
+ }
38
+ }
39
+ export function initializeFreshScopedStore(input) {
40
+ const store = input.kind === 'user' ? userStore(input.root) : input.kind === 'project' ? projectStore(input.root) : providerStore(input.root);
41
+ if (scopedStoreExists(store))
42
+ return;
43
+ const legacy = input.kind === 'user' ? userLegacyPaths(store.root) : input.kind === 'project' ? [join(store.root, STATE_FILE)] : providerLegacyPaths(store.root);
44
+ const legacyPath = legacy.find(existsSync);
45
+ if (legacyPath !== undefined)
46
+ throw new Error(`legacy scoped state exists at ${legacyPath}; crtr was updated and \`crtr sys daemon restart\` converts local state`);
47
+ createScopedStore(store, (db) => { createScopedSchema(db, input.kind); if (input.kind !== 'provider')
48
+ writeOwnerRoot(db, input.kind === 'user' ? 'user' : 'project', store.root); });
49
+ }
50
+ /** Conversion is intentionally explicit. Deployment coordination must prove all legacy writers at these shared roots are stopped before calling it. */
51
+ export function convertLegacyScopedStore(input) {
52
+ const store = input.kind === 'user' ? userStore(input.root) : input.kind === 'project' ? projectStore(input.root) : providerStore(input.root);
53
+ if (scopedStoreExists(store))
54
+ return;
55
+ if (input.kind === 'provider')
56
+ throw new Error('provider conversion requires convertLegacyProviderStore() under coordinated shared-agent-dir activation');
57
+ const paths = input.kind === 'user' ? userLegacyPaths(store.root) : [join(store.root, STATE_FILE)];
58
+ const convert = () => {
59
+ if (scopedStoreExists(store))
60
+ return;
61
+ createScopedStore(store, (db) => {
62
+ createScopedSchema(db, input.kind);
63
+ const owner = input.kind === 'user' ? 'user' : 'project';
64
+ writeOwnerRoot(db, owner, store.root);
65
+ if (input.kind === 'user')
66
+ importUser(db, store.root);
67
+ else
68
+ importState(db, owner, join(store.root, STATE_FILE));
69
+ });
70
+ if (existsLegacy(paths))
71
+ preserve(store.root, paths);
72
+ };
73
+ if (input.kind === 'project')
74
+ withLegacyProjectStateLock(store.root, convert);
75
+ else
76
+ convert();
77
+ }
78
+ function parseLegacyProviderPool(path) {
79
+ if (!existsSync(path))
80
+ return [];
81
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
82
+ if (!Array.isArray(raw))
83
+ throw new Error(`legacy subscription pool is malformed: ${path}`);
84
+ const labels = new Set();
85
+ return raw.map((item, position) => {
86
+ if (item === null || typeof item !== 'object' || Array.isArray(item))
87
+ throw new Error(`legacy subscription pool entry ${position + 1} is malformed: ${path}`);
88
+ const value = item;
89
+ const label = typeof value.label === 'string' ? value.label.trim() : '';
90
+ const refresh = typeof value.refresh === 'string' ? value.refresh.trim() : '';
91
+ const access = typeof value.access === 'string' ? value.access.trim() : '';
92
+ const expires = Number(value.expires);
93
+ if (!label || !refresh || !access || !Number.isFinite(expires))
94
+ throw new Error(`legacy subscription pool entry ${position + 1} is incomplete: ${path}`);
95
+ const labelKey = label.toLowerCase();
96
+ if (labels.has(labelKey))
97
+ throw new Error(`legacy subscription pool has duplicate label "${label}": ${path}`);
98
+ labels.add(labelKey);
99
+ const timing = (field) => Number.isFinite(Number(value[field])) ? Number(value[field]) : 0;
100
+ const accountId = typeof value.accountId === 'string' && value.accountId.trim() !== '' ? value.accountId.trim() : undefined;
101
+ return { label, refresh, access, expires, rateLimitedUntil: timing('rateLimitedUntil'), lastAttemptAt: timing('lastAttemptAt'), lastRateLimitedAt: timing('lastRateLimitedAt'), ...(value.authFailure === 'invalid_grant' ? { authFailure: 'invalid_grant' } : {}), ...(accountId ? { accountId } : {}) };
102
+ });
103
+ }
104
+ function parseLegacyRotation(path) {
105
+ if (!existsSync(path))
106
+ return {};
107
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
108
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
109
+ throw new Error(`legacy provider rotation settings are malformed: ${path}`);
110
+ const value = raw;
111
+ return { ...(value.defaultFallbackStrength === 'ultra' || value.defaultFallbackStrength === 'strong' || value.defaultFallbackStrength === 'medium' || value.defaultFallbackStrength === 'light' ? { defaultFallbackStrength: value.defaultFallbackStrength } : {}), ...(typeof value.revertWhenAvailable === 'boolean' ? { revertWhenAvailable: value.revertWhenAvailable } : {}) };
112
+ }
113
+ async function withLegacyProviderLocks(paths, run) {
114
+ const releases = [];
115
+ try {
116
+ for (const path of paths)
117
+ if (existsSync(path))
118
+ releases.push(await lockfile.lock(path, { realpath: false, retries: 0, stale: 30_000, update: 10_000 }));
119
+ return await run();
120
+ }
121
+ finally {
122
+ await Promise.allSettled(releases.reverse().map((release) => release()));
123
+ }
124
+ }
125
+ /** Converts legacy provider pools only after the activation owner has stopped every writer sharing this agent directory. */
126
+ export async function convertLegacyProviderStore(agentDir) {
127
+ const store = providerStore(agentDir);
128
+ if (scopedStoreExists(store))
129
+ return;
130
+ const paths = providerLegacyPaths(store.root);
131
+ await withLegacyProviderLocks(paths, async () => {
132
+ if (scopedStoreExists(store))
133
+ return;
134
+ const pools = new Map(paths.slice(0, 2).map((path, index) => [index === 0 ? 'anthropic' : 'openai-codex', parseLegacyProviderPool(path)]));
135
+ const rotation = parseLegacyRotation(paths[2]);
136
+ preserve(store.root, paths);
137
+ for (const [provider, pool] of pools) {
138
+ const accounts = Object.fromEntries(pool.map((entry) => { const id = randomUUID(); return [id, { refresh: entry.refresh, access: entry.access, expires: entry.expires, ...(entry.accountId ? { accountId: entry.accountId } : {}) }]; }));
139
+ const file = new LockedJsonFile(join(store.root, `${provider}-credentials.json`), true, '{"version":1,"accounts":{}}\n');
140
+ await file.withLockAsync(async (_current, _held, publish) => { publish(`${JSON.stringify({ version: 1, accounts })}\n`); return { result: undefined }; });
141
+ }
142
+ createScopedStore(store, (db) => {
143
+ createScopedSchema(db, 'provider');
144
+ for (const [provider, pool] of pools) {
145
+ const accounts = JSON.parse(readFileSync(join(store.root, `${provider}-credentials.json`), 'utf8'));
146
+ const ids = Object.keys(accounts.accounts);
147
+ const insert = db.prepare('INSERT INTO managed_accounts(provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure) VALUES(?,?,?,?,?,?,?,?,?)');
148
+ pool.forEach((entry, position) => insert.run(provider, ids[position], entry.label, entry.label.toLowerCase(), position, entry.lastAttemptAt, entry.lastRateLimitedAt, entry.rateLimitedUntil, entry.authFailure ?? null));
149
+ }
150
+ if (rotation.defaultFallbackStrength !== undefined || rotation.revertWhenAvailable !== undefined)
151
+ db.prepare('INSERT INTO rotation_settings(singleton,default_fallback_strength,revert_when_available) VALUES(1,?,?)').run(rotation.defaultFallbackStrength ?? null, rotation.revertWhenAvailable === undefined ? null : rotation.revertWhenAvailable ? 1 : 0);
152
+ });
153
+ });
154
+ }
155
+ function importSettings(db, owner, path) { if (!existsSync(path))
156
+ return; const raw = json(path); if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
157
+ throw new Error(`legacy config is malformed: ${path}`); db.prepare('INSERT INTO scope_settings(owner_key,raw_json) VALUES(?,?)').run(owner, JSON.stringify(raw)); }
158
+ function importState(db, owner, path) { if (!existsSync(path))
159
+ return; const raw = json(path); if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
160
+ throw new Error(`legacy state is malformed: ${path}`); const state = raw; db.prepare('INSERT INTO scope_bookkeeping(owner_key,last_self_check,active_canvas) VALUES(?,?,?)').run(owner, state.last_self_check ?? null, state.activeCanvas ?? null); const market = db.prepare('INSERT INTO scope_marketplaces(owner_key,name,last_updated) VALUES(?,?,?)'); for (const [name, value] of Object.entries(state.marketplaces ?? {}))
161
+ market.run(owner, name, value.last_updated ?? null); const plugins = db.prepare('INSERT INTO scope_plugins(owner_key,name,last_updated,etag,checked_at) VALUES(?,?,?,?,?)'); for (const [name, value] of Object.entries(state.plugins ?? {}))
162
+ plugins.run(owner, name, value.last_updated ?? null, value.etag ?? null, value.checked_at ?? null); }
163
+ function importUser(db, root) {
164
+ importSettings(db, 'user', join(root, CONFIG_FILE));
165
+ importState(db, 'user', join(root, STATE_FILE));
166
+ const profiles = join(root, PROFILE_DIR);
167
+ if (existsSync(profiles))
168
+ for (const entry of readdirSync(profiles, { withFileTypes: true })) {
169
+ if (!entry.isDirectory() || !PROFILE_ID_SHAPE.test(entry.name))
170
+ continue;
171
+ const id = entry.name;
172
+ const profileRoot = join(profiles, id);
173
+ const path = join(profileRoot, 'profile.json');
174
+ if (!existsSync(path))
175
+ throw new Error(`legacy profile manifest is missing: ${path}`);
176
+ const manifest = json(path);
177
+ if (!manifest || typeof manifest !== 'object' || !Array.isArray(manifest.projects) || typeof manifest.name !== 'string' || typeof manifest.created_at !== 'string')
178
+ throw new Error(`legacy profile manifest is malformed: ${path}`);
179
+ db.prepare('INSERT INTO profiles(id,name,created_at,last_used_at,paused_at,home,default_kind,metadata_json) VALUES(?,?,?,?,?,?,?,?)').run(id, manifest.name, manifest.created_at, manifest.last_used_at ?? null, manifest.paused_at ?? null, manifest.home ?? null, manifest.default_kind ?? null, JSON.stringify(manifest.metadata ?? {}));
180
+ db.prepare('INSERT INTO scope_owners(owner_key,kind,root,profile_id) VALUES(?,?,?,?)').run(`profile:${id}`, 'profile', profileRoot, id);
181
+ const project = db.prepare('INSERT INTO profile_projects(profile_id,path,position,memory) VALUES(?,?,?,?)');
182
+ manifest.projects.forEach((p, position) => project.run(id, p.path, position, p.memory));
183
+ importSettings(db, `profile:${id}`, join(profileRoot, CONFIG_FILE));
184
+ importState(db, `profile:${id}`, join(profileRoot, STATE_FILE));
185
+ }
186
+ const defaults = join(root, 'profile-defaults.json');
187
+ if (existsSync(defaults)) {
188
+ const raw = json(defaults);
189
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
190
+ throw new Error(`legacy profile defaults are malformed: ${defaults}`);
191
+ const insert = db.prepare('INSERT INTO profile_defaults(directory,profile_id) VALUES(?,?)');
192
+ for (const [directory, id] of Object.entries(raw)) {
193
+ if (typeof id !== 'string')
194
+ throw new Error(`legacy profile default is malformed: ${defaults}`);
195
+ insert.run(directory, id);
196
+ }
197
+ }
198
+ }
@@ -0,0 +1,9 @@
1
+ export type ScopedStore = {
2
+ path: string;
3
+ root: string;
4
+ kind: 'user' | 'project' | 'provider';
5
+ };
6
+ export declare function canonicalRoot(root: string): string;
7
+ export declare function userStore(root: string): ScopedStore;
8
+ export declare function projectStore(root: string): ScopedStore;
9
+ export declare function providerStore(agentDir: string): ScopedStore;
@@ -0,0 +1,27 @@
1
+ import { existsSync, realpathSync } from 'node:fs';
2
+ import { basename, dirname, join, resolve } from 'node:path';
3
+ export function canonicalRoot(root) {
4
+ const absolute = resolve(root);
5
+ let existing = absolute;
6
+ const missing = [];
7
+ while (!existsSync(existing)) {
8
+ const parent = dirname(existing);
9
+ if (parent === existing)
10
+ return absolute;
11
+ missing.unshift(basename(existing));
12
+ existing = parent;
13
+ }
14
+ return resolve(realpathSync(existing), ...missing);
15
+ }
16
+ export function userStore(root) {
17
+ const canonical = canonicalRoot(root);
18
+ return { path: join(canonical, 'operations.db'), root: canonical, kind: 'user' };
19
+ }
20
+ export function projectStore(root) {
21
+ const canonical = canonicalRoot(root);
22
+ return { path: join(canonical, 'operations.db'), root: canonical, kind: 'project' };
23
+ }
24
+ export function providerStore(agentDir) {
25
+ const canonical = canonicalRoot(agentDir);
26
+ return { path: join(canonical, 'crouter-operations.db'), root: canonical, kind: 'provider' };
27
+ }
@@ -0,0 +1,12 @@
1
+ import type { ProfileManifest } from '../../types.js';
2
+ export type StoredProfile = {
3
+ profileId: string;
4
+ manifest: ProfileManifest;
5
+ };
6
+ export declare function listStoredProfiles(root: string): StoredProfile[];
7
+ export declare function getStoredProfile(root: string, id: string): StoredProfile | null;
8
+ export declare function insertStoredProfile(root: string, profile: StoredProfile, profileRoot: string): void;
9
+ export declare function updateStoredProfile(root: string, id: string, mutate: (current: ProfileManifest) => ProfileManifest): StoredProfile | null;
10
+ export declare function deleteStoredProfile(root: string, id: string): boolean;
11
+ export declare function readStoredDefaults(root: string): Record<string, string>;
12
+ export declare function mutateStoredDefaults(root: string, mutate: (current: Record<string, string>) => Record<string, string>): Record<string, string>;
@@ -0,0 +1,62 @@
1
+ import { canonicalRoot, userStore } from './paths.js';
2
+ import { openScopedStore, withScopedWrite } from './db.js';
3
+ function store(root) { return userStore(root); }
4
+ function rowToProfile(row, projects) {
5
+ return { profileId: row.id, manifest: { schema_version: 1, name: row.name, projects, home: row.home, paused_at: row.paused_at, ...(row.default_kind === null ? {} : { default_kind: row.default_kind }), ...(Object.keys(JSON.parse(row.metadata_json)).length === 0 ? {} : { metadata: JSON.parse(row.metadata_json) }), created_at: row.created_at, last_used_at: row.last_used_at } };
6
+ }
7
+ function get(db, id) {
8
+ const row = db.prepare('SELECT id, name, created_at, last_used_at, paused_at, home, default_kind, metadata_json FROM profiles WHERE id=?').get(id);
9
+ if (!row)
10
+ return null;
11
+ const projects = db.prepare('SELECT path, memory FROM profile_projects WHERE profile_id=? ORDER BY position').all(id);
12
+ return rowToProfile(row, projects);
13
+ }
14
+ export function listStoredProfiles(root) {
15
+ const db = openScopedStore(store(root));
16
+ const ids = db.prepare('SELECT id FROM profiles ORDER BY rowid').all();
17
+ return ids.map(({ id }) => get(db, id)).filter(Boolean);
18
+ }
19
+ export function getStoredProfile(root, id) { return get(openScopedStore(store(root)), id); }
20
+ export function insertStoredProfile(root, profile, profileRoot) {
21
+ withScopedWrite(store(root), (db) => {
22
+ db.prepare('INSERT INTO profiles(id,name,created_at,last_used_at,paused_at,home,default_kind,metadata_json) VALUES(?,?,?,?,?,?,?,?)').run(profile.profileId, profile.manifest.name, profile.manifest.created_at, profile.manifest.last_used_at, profile.manifest.paused_at, profile.manifest.home, profile.manifest.default_kind ?? null, JSON.stringify(profile.manifest.metadata ?? {}));
23
+ db.prepare('INSERT INTO scope_owners(owner_key,kind,root,profile_id) VALUES(?,?,?,?)').run(`profile:${profile.profileId}`, 'profile', canonicalRoot(profileRoot), profile.profileId);
24
+ const insert = db.prepare('INSERT INTO profile_projects(profile_id,path,position,memory) VALUES(?,?,?,?)');
25
+ profile.manifest.projects.forEach((project, position) => insert.run(profile.profileId, project.path, position, project.memory));
26
+ });
27
+ }
28
+ export function updateStoredProfile(root, id, mutate) {
29
+ return withScopedWrite(store(root), (db) => {
30
+ const current = get(db, id);
31
+ if (!current)
32
+ return null;
33
+ const next = mutate(current.manifest);
34
+ db.prepare('UPDATE profiles SET name=?, last_used_at=?, paused_at=?, home=?, default_kind=?, metadata_json=? WHERE id=?').run(next.name, next.last_used_at, next.paused_at, next.home, next.default_kind ?? null, JSON.stringify(next.metadata ?? {}), id);
35
+ db.prepare('DELETE FROM profile_projects WHERE profile_id=?').run(id);
36
+ const insert = db.prepare('INSERT INTO profile_projects(profile_id,path,position,memory) VALUES(?,?,?,?)');
37
+ next.projects.forEach((project, position) => insert.run(id, project.path, position, project.memory));
38
+ return { profileId: id, manifest: next };
39
+ });
40
+ }
41
+ export function deleteStoredProfile(root, id) {
42
+ return withScopedWrite(store(root), (db) => {
43
+ if (!get(db, id))
44
+ return false;
45
+ const owner = `profile:${id}`;
46
+ db.prepare('DELETE FROM scope_settings WHERE owner_key=?').run(owner);
47
+ db.prepare('DELETE FROM scope_bookkeeping WHERE owner_key=?').run(owner);
48
+ db.prepare('DELETE FROM scope_marketplaces WHERE owner_key=?').run(owner);
49
+ db.prepare('DELETE FROM scope_plugins WHERE owner_key=?').run(owner);
50
+ db.prepare('DELETE FROM scope_owners WHERE owner_key=?').run(owner);
51
+ db.prepare('DELETE FROM profiles WHERE id=?').run(id);
52
+ return true;
53
+ });
54
+ }
55
+ export function readStoredDefaults(root) {
56
+ const db = openScopedStore(store(root));
57
+ return Object.fromEntries(db.prepare('SELECT directory,profile_id FROM profile_defaults').all().map((row) => [row.directory, row.profile_id]));
58
+ }
59
+ export function mutateStoredDefaults(root, mutate) {
60
+ return withScopedWrite(store(root), (db) => { const current = Object.fromEntries(db.prepare('SELECT directory,profile_id FROM profile_defaults').all().map((row) => [row.directory, row.profile_id])); const next = mutate(current); db.prepare('DELETE FROM profile_defaults').run(); const insert = db.prepare('INSERT INTO profile_defaults(directory,profile_id) VALUES(?,?)'); for (const [directory, id] of Object.entries(next))
61
+ insert.run(directory, id); return next; });
62
+ }
@@ -0,0 +1,16 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ export type ProviderRow = {
3
+ providerId: string;
4
+ id: string;
5
+ label: string;
6
+ labelKey: string;
7
+ position: number;
8
+ lastAttemptAt: number;
9
+ lastRateLimitedAt: number;
10
+ rateLimitedUntil: number;
11
+ authFailure?: 'invalid_grant';
12
+ };
13
+ export declare function providerRows(agentDir: string, providerId: string): ProviderRow[];
14
+ export declare function providerRowByReference(db: DatabaseSync, providerId: string, ref: string): ProviderRow | undefined;
15
+ export declare function providerWrite<T>(agentDir: string, run: (db: DatabaseSync) => T): T;
16
+ export declare function providerRevision(agentDir: string): number;
@@ -0,0 +1,8 @@
1
+ import { openScopedStore, withScopedWrite } from './db.js';
2
+ import { providerStore } from './paths.js';
3
+ function map(row) { return { providerId: row.provider_id, id: row.id, label: row.label, labelKey: row.label_key, position: row.position, lastAttemptAt: row.last_attempt_at, lastRateLimitedAt: row.last_rate_limited_at, rateLimitedUntil: row.rate_limited_until, ...(row.auth_failure ? { authFailure: row.auth_failure } : {}) }; }
4
+ const ROW_COLUMNS = 'provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure';
5
+ export function providerRows(agentDir, providerId) { const db = openScopedStore(providerStore(agentDir)); return db.prepare(`SELECT ${ROW_COLUMNS} FROM managed_accounts WHERE provider_id=? ORDER BY position`).all(providerId).map(map); }
6
+ export function providerRowByReference(db, providerId, ref) { const needle = ref.trim().toLowerCase(); const position = Number.parseInt(needle, 10); const row = (Number.isFinite(position) && String(position) === needle && position >= 1 ? db.prepare(`SELECT ${ROW_COLUMNS} FROM managed_accounts WHERE provider_id=? AND position=?`).get(providerId, position - 1) : db.prepare(`SELECT ${ROW_COLUMNS} FROM managed_accounts WHERE provider_id=? AND label_key=?`).get(providerId, needle)); return row ? map(row) : undefined; }
7
+ export function providerWrite(agentDir, run) { return withScopedWrite(providerStore(agentDir), (db) => { const value = run(db); db.prepare('UPDATE provider_revision SET revision=revision+1 WHERE singleton=1').run(); return value; }); }
8
+ export function providerRevision(agentDir) { const db = openScopedStore(providerStore(agentDir)); return db.prepare('SELECT revision FROM provider_revision WHERE singleton=1').get().revision; }
@@ -0,0 +1,3 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ export declare const SCOPED_SCHEMA_VERSION = 1;
3
+ export declare function createScopedSchema(db: DatabaseSync, kind: 'user' | 'project' | 'provider'): void;
@@ -0,0 +1,26 @@
1
+ export const SCOPED_SCHEMA_VERSION = 1;
2
+ const SCOPE_SCHEMA = `
3
+ CREATE TABLE scope_owners (owner_key TEXT PRIMARY KEY, kind TEXT NOT NULL CHECK(kind IN ('user','profile','project')), root TEXT NOT NULL UNIQUE, profile_id TEXT UNIQUE);
4
+ CREATE TABLE profiles (id TEXT PRIMARY KEY, name TEXT NOT NULL, created_at TEXT NOT NULL, last_used_at TEXT, paused_at TEXT, home TEXT, default_kind TEXT, metadata_json TEXT NOT NULL CHECK(json_valid(metadata_json)));
5
+ CREATE TABLE profile_projects (profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE, path TEXT NOT NULL, position INTEGER NOT NULL, memory TEXT NOT NULL CHECK(memory IN ('none','name','preview','content')), PRIMARY KEY(profile_id,path), UNIQUE(profile_id,position));
6
+ CREATE TABLE profile_defaults (directory TEXT PRIMARY KEY, profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE);
7
+ CREATE TABLE scope_settings (owner_key TEXT PRIMARY KEY REFERENCES scope_owners(owner_key), raw_json TEXT NOT NULL CHECK(json_valid(raw_json)));
8
+ CREATE TABLE scope_bookkeeping (owner_key TEXT PRIMARY KEY REFERENCES scope_owners(owner_key), last_self_check TEXT, active_canvas TEXT);
9
+ CREATE TABLE scope_marketplaces (owner_key TEXT NOT NULL REFERENCES scope_owners(owner_key), name TEXT NOT NULL, last_updated TEXT, PRIMARY KEY(owner_key,name));
10
+ CREATE TABLE scope_plugins (owner_key TEXT NOT NULL REFERENCES scope_owners(owner_key), name TEXT NOT NULL, last_updated TEXT, etag TEXT, checked_at TEXT, PRIMARY KEY(owner_key,name));`;
11
+ const PROVIDER_SCHEMA = `
12
+ CREATE TABLE managed_accounts (provider_id TEXT NOT NULL, id TEXT NOT NULL, label TEXT NOT NULL, label_key TEXT NOT NULL, position INTEGER NOT NULL, last_attempt_at INTEGER NOT NULL, last_rate_limited_at INTEGER NOT NULL, rate_limited_until INTEGER NOT NULL, auth_failure TEXT CHECK(auth_failure IS NULL OR auth_failure='invalid_grant'), PRIMARY KEY(provider_id,id), UNIQUE(provider_id,label_key));
13
+ CREATE INDEX managed_accounts_order ON managed_accounts(provider_id,position);
14
+ CREATE TABLE rotation_settings (singleton INTEGER PRIMARY KEY CHECK(singleton=1), default_fallback_strength TEXT, revert_when_available INTEGER CHECK(revert_when_available IN (0,1)));
15
+ CREATE TABLE provider_revision (singleton INTEGER PRIMARY KEY CHECK(singleton=1), revision INTEGER NOT NULL);`;
16
+ export function createScopedSchema(db, kind) {
17
+ db.exec(kind === 'provider' ? PROVIDER_SCHEMA : SCOPE_SCHEMA);
18
+ if (kind !== 'provider') {
19
+ const ownerKey = kind === 'user' ? 'user' : 'project';
20
+ db.prepare('INSERT INTO scope_owners(owner_key, kind, root, profile_id) VALUES (?, ?, ?, NULL)').run(ownerKey, kind, '');
21
+ }
22
+ else {
23
+ db.prepare('INSERT INTO provider_revision(singleton, revision) VALUES (1, 0)').run();
24
+ }
25
+ db.exec(`PRAGMA user_version = ${SCOPED_SCHEMA_VERSION}`);
26
+ }
@@ -0,0 +1,28 @@
1
+ import type { ScopeState } from '../../types.js';
2
+ import type { ScopedStore } from './paths.js';
3
+ export type SettingsOwner = {
4
+ store: ScopedStore;
5
+ key: string;
6
+ kind: 'user' | 'profile' | 'project';
7
+ root: string;
8
+ profileId?: string;
9
+ };
10
+ export declare class SettingsRevisionConflictError extends Error {
11
+ constructor();
12
+ }
13
+ export declare function readRawSettingsWithRevision(owner: SettingsOwner): {
14
+ settings: Record<string, unknown> | null;
15
+ revision: string;
16
+ };
17
+ export declare function readRawSettings(owner: SettingsOwner): Record<string, unknown> | null;
18
+ export declare function replaceRawSettings(owner: SettingsOwner, next: Record<string, unknown>, ifRevision: string, validate: (settings: Record<string, unknown>) => void): {
19
+ revision: string;
20
+ changed: boolean;
21
+ };
22
+ export declare function writeRawSettings(owner: SettingsOwner, raw: Record<string, unknown>): void;
23
+ export declare function mutateRawSettings<T>(owner: SettingsOwner, mutate: (current: Record<string, unknown>) => {
24
+ value: T;
25
+ next: Record<string, unknown>;
26
+ }): T;
27
+ export declare function readBookkeeping(owner: SettingsOwner): ScopeState;
28
+ export declare function writeBookkeeping(owner: SettingsOwner, state: ScopeState): void;