@north-light/cli 0.3.561 → 0.3.562

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 (573) hide show
  1. package/dist/api/client.d.ts +27 -4
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/bash-jobs.d.ts +5 -1
  6. package/dist/api/dto/broker-ops.d.ts +25 -1
  7. package/dist/api/dto/charges.d.ts +9 -2
  8. package/dist/api/dto/delivery.d.ts +26 -2
  9. package/dist/api/dto/execution-start.d.ts +57 -0
  10. package/dist/api/dto/execution-start.js +0 -0
  11. package/dist/api/dto/modelauth.d.ts +5 -0
  12. package/dist/api/dto/node-records.d.ts +16 -0
  13. package/dist/api/dto/objects.d.ts +1 -1
  14. package/dist/api/dto/reports.d.ts +0 -3
  15. package/dist/api/dto/run-events.d.ts +7 -1
  16. package/dist/api/dto/settings.d.ts +55 -0
  17. package/dist/api/dto/settings.js +0 -0
  18. package/dist/api/index.d.ts +2 -0
  19. package/dist/api/index.js +1 -1
  20. package/dist/api/routes.d.ts +11 -0
  21. package/dist/api/routes.js +1 -1
  22. package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
  23. package/dist/cli.js +7 -7
  24. package/dist/clients/attach/chrome/bash-jobs.d.ts +11 -1
  25. package/dist/clients/attach/chrome/bash-jobs.js +1 -1
  26. package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
  27. package/dist/clients/attach/chrome/roster.js +6 -4
  28. package/dist/clients/attach/overlays/auth.js +2 -2
  29. package/dist/clients/attach/render/chat-view.js +1 -1
  30. package/dist/clients/attach/viewer.js +550 -567
  31. package/dist/commands/canvas-config.js +2 -2
  32. package/dist/commands/canvas-use.js +1 -1
  33. package/dist/commands/human.js +2 -2
  34. package/dist/commands/node/bash.js +3 -3
  35. package/dist/commands/node/create.js +2 -2
  36. package/dist/commands/person-settings.d.ts +1 -0
  37. package/dist/commands/person-settings.js +1 -0
  38. package/dist/commands/pkg/market-manage.d.ts +2 -2
  39. package/dist/commands/pkg/market-manage.js +1 -1
  40. package/dist/commands/pkg/plugin-manage.js +13 -13
  41. package/dist/commands/pkg/shared.js +1 -1
  42. package/dist/commands/profile/default.js +1 -1
  43. package/dist/commands/push.js +2 -3
  44. package/dist/commands/sys/config.js +1 -1
  45. package/dist/commands/sys/connect.js +1 -1
  46. package/dist/commands/sys/context/sysprompt.js +2 -2
  47. package/dist/commands/sys/doctor.js +1 -1
  48. package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
  49. package/dist/commands/sys/panels/keybindings-panel.js +1 -1
  50. package/dist/commands/sys/panels/models-panel.d.ts +8 -2
  51. package/dist/commands/sys/panels/models-panel.js +1 -1
  52. package/dist/commands/sys/panels/prefs-panel.d.ts +1 -0
  53. package/dist/commands/sys/panels/prefs-panel.js +1 -1
  54. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  55. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  56. package/dist/commands/sys/panels/provider-panel.js +1 -1
  57. package/dist/commands/sys/provider-login.js +5 -5
  58. package/dist/commands/sys/setup-core.js +3 -3
  59. package/dist/commands/sys/setup-settings-runner.js +1 -1
  60. package/dist/commands/sys/spend.js +3 -3
  61. package/dist/commands/sys/update.js +1 -1
  62. package/dist/core/auth-file.d.ts +11 -19
  63. package/dist/core/auth-file.js +1 -2
  64. package/dist/core/auto-update.d.ts +1 -1
  65. package/dist/core/auto-update.js +4 -4
  66. package/dist/core/bash-jobs.d.ts +29 -71
  67. package/dist/core/bash-jobs.js +9 -10
  68. package/dist/core/blobs/directory.d.ts +3 -0
  69. package/dist/core/blobs/directory.js +1 -0
  70. package/dist/core/blobs/fault.d.ts +3 -0
  71. package/dist/core/blobs/fault.js +1 -0
  72. package/dist/core/blobs/index.d.ts +21 -0
  73. package/dist/core/blobs/index.js +1 -0
  74. package/dist/core/blobs/r2.d.ts +9 -0
  75. package/dist/core/blobs/r2.js +4 -0
  76. package/dist/core/bootstrap.d.ts +1 -1
  77. package/dist/core/bootstrap.js +2 -2
  78. package/dist/core/canvas/canvas.d.ts +9 -7
  79. package/dist/core/canvas/canvas.js +8 -8
  80. package/dist/core/canvas/crons.d.ts +3 -2
  81. package/dist/core/canvas/crons.js +3 -3
  82. package/dist/core/canvas/daemon-owner.d.ts +5 -0
  83. package/dist/core/canvas/daemon-owner.js +1 -1
  84. package/dist/core/canvas/db.d.ts +10 -9
  85. package/dist/core/canvas/db.js +4 -4
  86. package/dist/core/canvas/executions.d.ts +100 -4
  87. package/dist/core/canvas/executions.js +1 -1
  88. package/dist/core/canvas/export-sqlite.js +1 -1
  89. package/dist/core/canvas/focuses.d.ts +4 -0
  90. package/dist/core/canvas/focuses.js +1 -1
  91. package/dist/core/canvas/history.js +9 -9
  92. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +2 -1
  93. package/dist/core/canvas/managed-worktree-sweep-candidates.js +3 -2
  94. package/dist/core/canvas/node-tokens.d.ts +1 -4
  95. package/dist/core/canvas/node-tokens.js +3 -3
  96. package/dist/core/canvas/paths.d.ts +0 -1
  97. package/dist/core/canvas/paths.js +1 -1
  98. package/dist/core/canvas/person-state.d.ts +26 -0
  99. package/dist/core/canvas/person-state.js +1 -0
  100. package/dist/core/canvas/person.d.ts +3 -10
  101. package/dist/core/canvas/person.js +7 -7
  102. package/dist/core/canvas/reconciler-leases.d.ts +12 -0
  103. package/dist/core/canvas/reconciler-leases.js +8 -0
  104. package/dist/core/canvas/recovery.d.ts +4 -0
  105. package/dist/core/canvas/recovery.js +1 -1
  106. package/dist/core/canvas/schema-pg/003-fleet-removals.sql +1 -1
  107. package/dist/core/canvas/schema-pg/005-fleet-blobs.sql +13 -0
  108. package/dist/core/canvas/schema-pg/006-job-rows.sql +20 -0
  109. package/dist/core/canvas/schema-pg/007-ledger-check.sql +117 -0
  110. package/dist/core/canvas/schema-version.d.ts +1 -1
  111. package/dist/core/canvas/schema-version.js +1 -1
  112. package/dist/core/canvas/sessions.d.ts +8 -11
  113. package/dist/core/canvas/sessions.js +1 -4
  114. package/dist/core/canvas/tree.d.ts +4 -2
  115. package/dist/core/canvas/tree.js +6 -6
  116. package/dist/core/canvas/types.d.ts +7 -0
  117. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  118. package/dist/core/command-plugins/bundle.d.ts +1 -1
  119. package/dist/core/command-plugins/bundle.js +1 -1
  120. package/dist/core/command-plugins/compose.d.ts +1 -1
  121. package/dist/core/command-plugins/discovery.d.ts +0 -1
  122. package/dist/core/command-plugins/discovery.js +1 -1
  123. package/dist/core/command-plugins/help-addenda.js +1 -1
  124. package/dist/core/command-plugins/presence.d.ts +2 -0
  125. package/dist/core/command-plugins/presence.js +1 -1
  126. package/dist/core/config.d.ts +16 -15
  127. package/dist/core/config.js +1 -1
  128. package/dist/core/conversation-store/client-worker.js +1 -1
  129. package/dist/core/conversation-store/client.js +2 -2
  130. package/dist/core/conversation-store/index.d.ts +9 -11
  131. package/dist/core/conversation-store/index.js +1 -1
  132. package/dist/core/conversation-store/patch.js +1 -1
  133. package/dist/core/conversation-store/row-store.d.ts +14 -0
  134. package/dist/core/conversation-store/row-store.js +13 -0
  135. package/dist/core/directory/join.js +1 -1
  136. package/dist/core/env-name.d.ts +1 -0
  137. package/dist/core/env-name.js +1 -1
  138. package/dist/core/environment-recipe.d.ts +15 -0
  139. package/dist/core/environment-recipe.js +1 -0
  140. package/dist/core/environments.js +1 -1
  141. package/dist/core/events/emit.js +2 -2
  142. package/dist/core/events/run-event-chunks.d.ts +25 -0
  143. package/dist/core/events/run-event-chunks.js +5 -0
  144. package/dist/core/feed/messages.js +5 -5
  145. package/dist/core/grants/mirror.d.ts +15 -0
  146. package/dist/core/grants/mirror.js +15 -3
  147. package/dist/core/grants/on-sync.d.ts +9 -5
  148. package/dist/core/grants/on-sync.js +1 -1
  149. package/dist/core/grants/remove.d.ts +1 -6
  150. package/dist/core/grants/remove.js +1 -1
  151. package/dist/core/grants/sync.js +1 -1
  152. package/dist/core/grants/watch.d.ts +15 -9
  153. package/dist/core/grants/watch.js +1 -1
  154. package/dist/core/graph/custom.js +8 -8
  155. package/dist/core/graph/jobs.d.ts +83 -5
  156. package/dist/core/graph/jobs.js +11 -2
  157. package/dist/core/graph/kinds/job.js +2 -2
  158. package/dist/core/graph/names.js +7 -7
  159. package/dist/core/graph/objects.d.ts +5 -1
  160. package/dist/core/graph/objects.js +11 -11
  161. package/dist/core/graph/reader.d.ts +3 -0
  162. package/dist/core/graph/reader.js +3 -3
  163. package/dist/core/graph/repo-sync/identity.d.ts +3 -1
  164. package/dist/core/graph/repo-sync/identity.js +1 -1
  165. package/dist/core/graph/repo-sync/repos.d.ts +1 -1
  166. package/dist/core/graph/repo-sync/repos.js +2 -2
  167. package/dist/core/graph/repo-sync/sync.js +2 -2
  168. package/dist/core/installed-plugins.js +1 -1
  169. package/dist/core/keybindings/persistence.d.ts +1 -1
  170. package/dist/core/keybindings/persistence.js +1 -1
  171. package/dist/core/layout-migrate/loose-keys.d.ts +1 -1
  172. package/dist/core/layout-migrate/loose-keys.js +1 -1
  173. package/dist/core/ledger/account.d.ts +12 -0
  174. package/dist/core/ledger/account.js +2 -0
  175. package/dist/core/ledger/charges.d.ts +2 -2
  176. package/dist/core/ledger/charges.js +1 -1
  177. package/dist/core/ledger/check.d.ts +5 -1
  178. package/dist/core/ledger/check.js +1 -7
  179. package/dist/core/ledger/chunks.d.ts +8 -0
  180. package/dist/core/ledger/chunks.js +2 -0
  181. package/dist/core/ledger/index.d.ts +2 -1
  182. package/dist/core/ledger/index.js +1 -1
  183. package/dist/core/ledger/infra-allowance.d.ts +9 -0
  184. package/dist/core/ledger/infra-allowance.js +1 -0
  185. package/dist/core/ledger/limits.js +3 -3
  186. package/dist/core/ledger/payer.d.ts +1 -1
  187. package/dist/core/ledger/payer.js +1 -1
  188. package/dist/core/ledger/read.d.ts +14 -4
  189. package/dist/core/ledger/read.js +2 -3
  190. package/dist/core/ledger/totals.d.ts +5 -16
  191. package/dist/core/ledger/totals.js +4 -4
  192. package/dist/core/ledger/types.d.ts +12 -3
  193. package/dist/core/llm/run.js +2 -2
  194. package/dist/core/managed-providers.d.ts +72 -0
  195. package/dist/core/managed-providers.js +1 -0
  196. package/dist/core/model-auth/api-credential-store.d.ts +10 -0
  197. package/dist/core/model-auth/api-credential-store.js +1 -0
  198. package/dist/core/model-auth/daemon-login.d.ts +1 -1
  199. package/dist/core/model-auth/daemon-login.js +1 -1
  200. package/dist/core/model-auth/flows.d.ts +5 -4
  201. package/dist/core/model-auth/flows.js +1 -1
  202. package/dist/core/model-auth/handoff-jti.d.ts +3 -4
  203. package/dist/core/model-auth/handoff-jti.js +1 -1
  204. package/dist/core/model-auth/readiness.js +1 -1
  205. package/dist/core/model-config.d.ts +1 -1
  206. package/dist/core/model-config.js +1 -1
  207. package/dist/core/model-routes-pool.d.ts +14 -0
  208. package/dist/core/model-routes-pool.js +1 -0
  209. package/dist/core/model-routes.d.ts +11 -16
  210. package/dist/core/model-routes.js +1 -1
  211. package/dist/core/peer/ingest.d.ts +2 -0
  212. package/dist/core/peer/ingest.js +1 -1
  213. package/dist/core/peer/stubs.d.ts +8 -0
  214. package/dist/core/peer/stubs.js +1 -1
  215. package/dist/core/permissions/evaluator.d.ts +7 -2
  216. package/dist/core/permissions/evaluator.js +2 -2
  217. package/dist/core/plugin-env.js +1 -1
  218. package/dist/core/pool-credential-store.d.ts +2 -5
  219. package/dist/core/pool-credential-store.js +1 -1
  220. package/dist/core/profiles/app-env-store.d.ts +5 -5
  221. package/dist/core/profiles/app-env-store.js +1 -2
  222. package/dist/core/profiles/default-binding.d.ts +5 -5
  223. package/dist/core/profiles/default-binding.js +1 -1
  224. package/dist/core/profiles/env-store.d.ts +10 -21
  225. package/dist/core/profiles/env-store.js +1 -2
  226. package/dist/core/profiles/manifest.d.ts +14 -18
  227. package/dist/core/profiles/manifest.js +1 -1
  228. package/dist/core/profiles/relocate.js +1 -1
  229. package/dist/core/profiles/select.js +21 -21
  230. package/dist/core/provider-credential.d.ts +1 -1
  231. package/dist/core/provider-credential.js +1 -1
  232. package/dist/core/provider-management.d.ts +3 -4
  233. package/dist/core/provider-management.js +1 -1
  234. package/dist/core/providers/bundles.js +2 -2
  235. package/dist/core/providers/call.d.ts +3 -34
  236. package/dist/core/providers/description.d.ts +34 -0
  237. package/dist/core/providers/description.js +0 -0
  238. package/dist/core/providers/token-cache.d.ts +14 -14
  239. package/dist/core/providers/token-cache.js +1 -1
  240. package/dist/core/review/companion.js +1 -1
  241. package/dist/core/runs/activity.d.ts +1 -1
  242. package/dist/core/runs/activity.js +1 -1
  243. package/dist/core/runs/events.d.ts +7 -5
  244. package/dist/core/runs/events.js +2 -6
  245. package/dist/core/runs/operations.d.ts +1 -1
  246. package/dist/core/runs/operations.js +6 -6
  247. package/dist/core/runtime/bearings.js +1 -1
  248. package/dist/core/runtime/broker/attachments-fetch.d.ts +5 -0
  249. package/dist/core/runtime/broker/attachments-fetch.js +1 -0
  250. package/dist/core/runtime/broker/bash-job-launch.d.ts +4 -2
  251. package/dist/core/runtime/broker/bash-job-launch.js +1 -1
  252. package/dist/core/runtime/broker/boot-state.d.ts +9 -0
  253. package/dist/core/runtime/broker/boot-state.js +1 -0
  254. package/dist/core/runtime/broker/cli-relay.d.ts +2 -1
  255. package/dist/core/runtime/broker/cli-relay.js +1 -1
  256. package/dist/core/runtime/broker/client-registry.d.ts +3 -3
  257. package/dist/core/runtime/broker/daemon-ops.d.ts +10 -1
  258. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  259. package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
  260. package/dist/core/runtime/broker/fault-retry.js +1 -1
  261. package/dist/core/runtime/broker/frame-engine-control.js +1 -1
  262. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -0
  263. package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
  264. package/dist/core/runtime/broker/job-reporter.d.ts +18 -0
  265. package/dist/core/runtime/broker/job-reporter.js +2 -0
  266. package/dist/core/runtime/broker/model-adapter.d.ts +3 -0
  267. package/dist/core/runtime/broker/model-adapter.js +3 -2
  268. package/dist/core/runtime/broker/signal-stream.js +1 -1
  269. package/dist/core/runtime/broker/spilled-body.d.ts +5 -0
  270. package/dist/core/runtime/broker/spilled-body.js +1 -0
  271. package/dist/core/runtime/broker/summaries-post.d.ts +5 -0
  272. package/dist/core/runtime/broker/summaries-post.js +1 -0
  273. package/dist/core/runtime/broker/tool-groups.d.ts +3 -0
  274. package/dist/core/runtime/broker/tool-groups.js +1 -1
  275. package/dist/core/runtime/broker/turn-replies.d.ts +1 -0
  276. package/dist/core/runtime/broker/turn-replies.js +1 -1
  277. package/dist/core/runtime/broker-persona-guidance.js +2 -2
  278. package/dist/core/runtime/broker.js +1 -1
  279. package/dist/core/runtime/deliver-live.js +1 -1
  280. package/dist/core/runtime/first-boot-rows.d.ts +8 -0
  281. package/dist/core/runtime/first-boot-rows.js +2 -0
  282. package/dist/core/runtime/fleet.d.ts +13 -12
  283. package/dist/core/runtime/front-door-login.js +1 -1
  284. package/dist/core/runtime/front-door.js +6 -6
  285. package/dist/core/runtime/headless-pi.js +1 -1
  286. package/dist/core/runtime/host.d.ts +14 -3
  287. package/dist/core/runtime/host.js +3 -3
  288. package/dist/core/runtime/invocation.d.ts +6 -0
  289. package/dist/core/runtime/kickoff.d.ts +2 -14
  290. package/dist/core/runtime/kickoff.js +17 -19
  291. package/dist/core/runtime/launch-config-worker.js +1 -1
  292. package/dist/core/runtime/launch.js +2 -2
  293. package/dist/core/runtime/model-registry.js +1 -1
  294. package/dist/core/runtime/node-read.d.ts +4 -6
  295. package/dist/core/runtime/node-read.js +3 -3
  296. package/dist/core/runtime/nodes.js +1 -1
  297. package/dist/core/runtime/outcome-document.d.ts +0 -1
  298. package/dist/core/runtime/outcome-document.js +1 -1
  299. package/dist/core/runtime/output-result.d.ts +15 -0
  300. package/dist/core/runtime/output-result.js +5 -0
  301. package/dist/core/runtime/placement.d.ts +17 -1
  302. package/dist/core/runtime/placement.js +1 -1
  303. package/dist/core/runtime/provider-credential-gate.d.ts +6 -2
  304. package/dist/core/runtime/provider-credential-gate.js +2 -2
  305. package/dist/core/runtime/recovery-hold.d.ts +21 -2
  306. package/dist/core/runtime/recovery-hold.js +2 -1
  307. package/dist/core/runtime/recycle.js +1 -1
  308. package/dist/core/runtime/reset.js +1 -1
  309. package/dist/core/runtime/revive.d.ts +2 -2
  310. package/dist/core/runtime/revive.js +2 -2
  311. package/dist/core/runtime/runner/blaxel/client.d.ts +81 -0
  312. package/dist/core/runtime/runner/blaxel/client.js +1 -0
  313. package/dist/core/runtime/runner/blaxel/image-build.d.ts +74 -0
  314. package/dist/core/runtime/runner/blaxel/image-build.js +5 -0
  315. package/dist/core/runtime/runner/blaxel/runner.d.ts +41 -0
  316. package/dist/core/runtime/runner/blaxel/runner.js +3 -0
  317. package/dist/core/runtime/runner/index.d.ts +8 -0
  318. package/dist/core/runtime/runner/index.js +1 -0
  319. package/dist/core/runtime/runner/process.d.ts +11 -0
  320. package/dist/core/runtime/runner/process.js +1 -0
  321. package/dist/core/runtime/runner/types.d.ts +95 -0
  322. package/dist/core/runtime/runner/types.js +0 -0
  323. package/dist/core/runtime/situational-context.d.ts +3 -6
  324. package/dist/core/runtime/situational-context.js +2 -2
  325. package/dist/core/runtime/situational-live.js +1 -1
  326. package/dist/core/runtime/spawn-env-rows.d.ts +5 -0
  327. package/dist/core/runtime/spawn-env-rows.js +1 -0
  328. package/dist/core/runtime/spawn-env.d.ts +4 -18
  329. package/dist/core/runtime/spawn-env.js +1 -1
  330. package/dist/core/runtime/spawn.js +2 -2
  331. package/dist/core/runtime/stop-guard.d.ts +1 -1
  332. package/dist/core/runtime/stop-guard.js +2 -8
  333. package/dist/core/runtime/structured-output.d.ts +0 -67
  334. package/dist/core/runtime/structured-output.js +3 -8
  335. package/dist/core/runtime/tmux-driver.d.ts +8 -0
  336. package/dist/core/runtime/tmux-driver.js +6 -6
  337. package/dist/core/runtime/view-socket.d.ts +20 -0
  338. package/dist/core/runtime/view-socket.js +3 -1
  339. package/dist/core/runtime/warm-pool.d.ts +13 -1
  340. package/dist/core/runtime/warm-pool.js +1 -1
  341. package/dist/core/scoped-state/legacy-profiles.d.ts +11 -0
  342. package/dist/core/scoped-state/legacy-profiles.js +1 -0
  343. package/dist/core/scoped-state/materialized-plugins.d.ts +18 -0
  344. package/dist/core/scoped-state/materialized-plugins.js +1 -0
  345. package/dist/core/scoped-state/migrate.d.ts +8 -1
  346. package/dist/core/scoped-state/migrate.js +3 -3
  347. package/dist/core/scoped-state/person-rows.d.ts +10 -0
  348. package/dist/core/scoped-state/person-rows.js +6 -0
  349. package/dist/core/scoped-state/person-store.d.ts +72 -0
  350. package/dist/core/scoped-state/person-store.js +1 -0
  351. package/dist/core/secrets/blaxel-launch.d.ts +24 -0
  352. package/dist/core/secrets/blaxel-launch.js +4 -0
  353. package/dist/core/secrets/blaxel-register.d.ts +2 -0
  354. package/dist/core/secrets/blaxel-register.js +1 -0
  355. package/dist/core/secrets/env-rows.d.ts +17 -0
  356. package/dist/core/secrets/env-rows.js +4 -0
  357. package/dist/core/secrets/environment-owner.d.ts +8 -0
  358. package/dist/core/secrets/environment-owner.js +1 -0
  359. package/dist/core/secrets/environment-secrets.d.ts +14 -0
  360. package/dist/core/secrets/environment-secrets.js +1 -0
  361. package/dist/core/secrets/index.d.ts +2 -0
  362. package/dist/core/secrets/index.js +1 -0
  363. package/dist/core/secrets/key.d.ts +3 -0
  364. package/dist/core/secrets/key.js +2 -0
  365. package/dist/core/secrets/seal.d.ts +18 -0
  366. package/dist/core/secrets/seal.js +1 -0
  367. package/dist/core/spaces/mounts.d.ts +1 -1
  368. package/dist/core/spaces/mounts.js +1 -1
  369. package/dist/core/spaces/process.d.ts +1 -1
  370. package/dist/core/spaces/stop.d.ts +7 -5
  371. package/dist/core/spaces/stop.js +2 -2
  372. package/dist/core/spaces/users.d.ts +2 -1
  373. package/dist/core/spaces/users.js +1 -1
  374. package/dist/core/storage/attachments.d.ts +11 -8
  375. package/dist/core/storage/attachments.js +1 -1
  376. package/dist/core/storage/tables.d.ts +4 -0
  377. package/dist/core/storage/tables.js +3 -3
  378. package/dist/core/subscription-state.d.ts +34 -72
  379. package/dist/core/subscription-state.js +1 -4
  380. package/dist/core/substrate/delivery/plan.js +1 -1
  381. package/dist/core/user-settings.js +1 -1
  382. package/dist/daemon/api/app-listener.js +10 -10
  383. package/dist/daemon/api/auth/person-bearer.d.ts +14 -0
  384. package/dist/daemon/api/auth/person-bearer.js +1 -0
  385. package/dist/daemon/api/bridge.js +4 -4
  386. package/dist/daemon/api/document-listener.js +3 -3
  387. package/dist/daemon/api/environment-of.d.ts +18 -0
  388. package/dist/daemon/api/environment-of.js +5 -0
  389. package/dist/daemon/api/handlers/analytics.js +1 -1
  390. package/dist/daemon/api/handlers/app-profiles.d.ts +2 -2
  391. package/dist/daemon/api/handlers/app-profiles.js +1 -1
  392. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  393. package/dist/daemon/api/handlers/bash.js +1 -1
  394. package/dist/daemon/api/handlers/broker-ops.d.ts +3 -0
  395. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  396. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  397. package/dist/daemon/api/handlers/broker-signals.d.ts +0 -3
  398. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  399. package/dist/daemon/api/handlers/canvas.js +4 -4
  400. package/dist/daemon/api/handlers/charges.d.ts +1 -1
  401. package/dist/daemon/api/handlers/charges.js +1 -1
  402. package/dist/daemon/api/handlers/conversations.d.ts +2 -0
  403. package/dist/daemon/api/handlers/conversations.js +3 -0
  404. package/dist/daemon/api/handlers/crons.js +1 -1
  405. package/dist/daemon/api/handlers/daemon.js +1 -1
  406. package/dist/daemon/api/handlers/delivery.d.ts +1 -1
  407. package/dist/daemon/api/handlers/delivery.js +1 -1
  408. package/dist/daemon/api/handlers/docs.js +1 -1
  409. package/dist/daemon/api/handlers/exec.js +1 -1
  410. package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
  411. package/dist/daemon/api/handlers/execution-start.js +2 -0
  412. package/dist/daemon/api/handlers/files.js +1 -1
  413. package/dist/daemon/api/handlers/git-credential.d.ts +11 -0
  414. package/dist/daemon/api/handlers/git-credential.js +1 -0
  415. package/dist/daemon/api/handlers/hook-exec.d.ts +1 -1
  416. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  417. package/dist/daemon/api/handlers/human-requests.js +1 -1
  418. package/dist/daemon/api/handlers/inbox.js +1 -1
  419. package/dist/daemon/api/handlers/messages.js +1 -1
  420. package/dist/daemon/api/handlers/model-config.js +1 -1
  421. package/dist/daemon/api/handlers/modelauth.d.ts +1 -1
  422. package/dist/daemon/api/handlers/modelauth.js +1 -1
  423. package/dist/daemon/api/handlers/node-events.d.ts +6 -0
  424. package/dist/daemon/api/handlers/node-events.js +3 -3
  425. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  426. package/dist/daemon/api/handlers/node-records.js +3 -2
  427. package/dist/daemon/api/handlers/nodes.js +1 -1
  428. package/dist/daemon/api/handlers/objects.js +3 -3
  429. package/dist/daemon/api/handlers/profiles.js +1 -1
  430. package/dist/daemon/api/handlers/providers.js +1 -1
  431. package/dist/daemon/api/handlers/reports.js +9 -13
  432. package/dist/daemon/api/handlers/reviews.js +1 -1
  433. package/dist/daemon/api/handlers/runs.js +1 -1
  434. package/dist/daemon/api/handlers/settings.d.ts +2 -0
  435. package/dist/daemon/api/handlers/settings.js +1 -0
  436. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  437. package/dist/daemon/api/handlers/vendor-status.d.ts +1 -1
  438. package/dist/daemon/api/handlers/vendor-status.js +1 -1
  439. package/dist/daemon/api/handlers/worktree.js +1 -1
  440. package/dist/daemon/api/map.d.ts +2 -2
  441. package/dist/daemon/api/map.js +2 -2
  442. package/dist/daemon/api/operations.js +1 -1
  443. package/dist/daemon/api/reader.d.ts +8 -1
  444. package/dist/daemon/api/reader.js +1 -1
  445. package/dist/daemon/api/router.d.ts +4 -2
  446. package/dist/daemon/api/router.js +1 -1
  447. package/dist/daemon/api/server.d.ts +15 -3
  448. package/dist/daemon/api/server.js +1 -1
  449. package/dist/daemon/api/vendor-signin.d.ts +2 -1
  450. package/dist/daemon/api/vendor-signin.js +19 -19
  451. package/dist/daemon/api/viewer-presence.d.ts +20 -6
  452. package/dist/daemon/api/viewer-presence.js +2 -1
  453. package/dist/daemon/broker-signals/bus.d.ts +48 -11
  454. package/dist/daemon/broker-signals/bus.js +1 -1
  455. package/dist/daemon/cron/armed-context.js +1 -1
  456. package/dist/daemon/cron/lease-recovery.js +1 -1
  457. package/dist/daemon/cron/live-runs.d.ts +6 -0
  458. package/dist/daemon/cron/live-runs.js +1 -1
  459. package/dist/daemon/cron/run-socket.js +1 -1
  460. package/dist/daemon/cron-run.js +2 -2
  461. package/dist/daemon/crtrd-cli.js +1 -1
  462. package/dist/daemon/crtrd.d.ts +10 -0
  463. package/dist/daemon/crtrd.js +18 -17
  464. package/dist/daemon/delivery/run-delivery.d.ts +1 -1
  465. package/dist/daemon/delivery/run-delivery.js +1 -1
  466. package/dist/daemon/due-sources.d.ts +1 -1
  467. package/dist/daemon/due-sources.js +1 -1
  468. package/dist/daemon/due.js +7 -6
  469. package/dist/daemon/fleet.d.ts +6 -6
  470. package/dist/daemon/fleet.js +9 -9
  471. package/dist/daemon/park-activity.d.ts +2 -1
  472. package/dist/daemon/park-activity.js +1 -1
  473. package/dist/daemon/park-pending.d.ts +20 -13
  474. package/dist/daemon/park-pending.js +3 -1
  475. package/dist/daemon/profile-delete.js +1 -1
  476. package/dist/daemon/reconcilers/bash-deadline.d.ts +15 -10
  477. package/dist/daemon/reconcilers/bash-deadline.js +1 -3
  478. package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -3
  479. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  480. package/dist/daemon/reconcilers/cron-lane.d.ts +0 -1
  481. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  482. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +2 -9
  483. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  484. package/dist/daemon/reconcilers/grant-effects.d.ts +8 -0
  485. package/dist/daemon/reconcilers/grant-effects.js +1 -0
  486. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +1 -3
  487. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  488. package/dist/daemon/reconcilers/ledger-r2.d.ts +27 -0
  489. package/dist/daemon/reconcilers/ledger-r2.js +7 -0
  490. package/dist/daemon/reconcilers/ledger-sandbox.d.ts +55 -0
  491. package/dist/daemon/reconcilers/ledger-sandbox.js +9 -0
  492. package/dist/daemon/reconcilers/ledger-storage.d.ts +22 -0
  493. package/dist/daemon/reconcilers/ledger-storage.js +5 -0
  494. package/dist/daemon/reconcilers/live-obligation.d.ts +3 -2
  495. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  496. package/dist/daemon/reconcilers/managed-worktree-sweep.d.ts +0 -5
  497. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  498. package/dist/daemon/reconcilers/node-deadline.d.ts +2 -1
  499. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  500. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -2
  501. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  502. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +31 -0
  503. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -0
  504. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.d.ts +5 -0
  505. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.js +2 -0
  506. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  507. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  508. package/dist/daemon/reconcilers/recipe-image.d.ts +49 -0
  509. package/dist/daemon/reconcilers/recipe-image.js +7 -0
  510. package/dist/daemon/reconcilers/row-claim.d.ts +19 -0
  511. package/dist/daemon/reconcilers/row-claim.js +2 -0
  512. package/dist/daemon/reconcilers/storage-due-work.d.ts +18 -3
  513. package/dist/daemon/reconcilers/storage-due-work.js +2 -1
  514. package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -13
  515. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  516. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  517. package/dist/daemon/reconcilers/throttled-lane.d.ts +11 -0
  518. package/dist/daemon/reconcilers/throttled-lane.js +1 -0
  519. package/dist/daemon/review/finish.js +1 -1
  520. package/dist/daemon/run-notices.d.ts +3 -0
  521. package/dist/daemon/run-notices.js +1 -1
  522. package/dist/daemon/runs/append-section.d.ts +4 -1
  523. package/dist/daemon/runs/append-section.js +2 -2
  524. package/dist/daemon/runs/observer.d.ts +3 -2
  525. package/dist/daemon/runs/observer.js +3 -2
  526. package/dist/daemon/runs/view-transport.d.ts +19 -0
  527. package/dist/daemon/runs/view-transport.js +1 -0
  528. package/dist/daemon/structured-requests/boot.d.ts +2 -1
  529. package/dist/daemon/structured-requests/boot.js +1 -1
  530. package/dist/daemon/structured-requests/effects.d.ts +4 -3
  531. package/dist/daemon/structured-requests/effects.js +1 -1
  532. package/dist/daemon/structured-requests/notifier.d.ts +2 -0
  533. package/dist/daemon/structured-requests/notifier.js +1 -1
  534. package/dist/daemon/structured-requests/sidecar.d.ts +4 -3
  535. package/dist/daemon/structured-requests/sidecar.js +1 -1
  536. package/dist/launcher/validate.js +1 -1
  537. package/dist/migrations/004-canvas-documents/index.js +2 -2
  538. package/dist/pi-extensions/broker-local.d.ts +3 -3
  539. package/dist/pi-extensions/broker-local.js +1 -2
  540. package/dist/pi-extensions/canvas-bash-valve.js +6 -6
  541. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  542. package/dist/pi-extensions/canvas-elapsed.js +2 -2
  543. package/dist/pi-extensions/canvas-goal-capture.js +1 -1
  544. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  545. package/dist/pi-extensions/canvas-review-boundary.d.ts +11 -1
  546. package/dist/pi-extensions/canvas-review-boundary.js +3 -3
  547. package/dist/pi-extensions/canvas-stophook.js +1 -1
  548. package/dist/pi-extensions/canvas-structured-output.d.ts +5 -3
  549. package/dist/pi-extensions/canvas-structured-output.js +6 -11
  550. package/dist/pi-extensions/canvas-tool-guide.d.ts +9 -2
  551. package/dist/pi-extensions/canvas-tool-guide.js +6 -6
  552. package/dist/shared/inbox-entry-body.js +7 -7
  553. package/dist/types.d.ts +12 -0
  554. package/docs/sdk/release-notes.md +4 -0
  555. package/package.json +7 -4
  556. package/packages/crouter-identity/package.json +1 -1
  557. package/runtime.lock.json +13 -13
  558. package/scripts/git-credential-crtr +33 -0
  559. package/scripts/sandbox-bootstrap.sh +54 -0
  560. package/scripts/sandbox-start.mjs +320 -0
  561. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +0 -78
  562. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +0 -1179
  563. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +0 -1406
  564. package/dist/core/conversation-store/file-store.d.ts +0 -37
  565. package/dist/core/conversation-store/file-store.js +0 -9
  566. package/dist/core/conversation-store/listener.d.ts +0 -4
  567. package/dist/core/conversation-store/listener.js +0 -8
  568. package/dist/core/scoped-state/profiles.d.ts +0 -27
  569. package/dist/core/scoped-state/profiles.js +0 -1
  570. package/dist/core/scoped-state/providers.d.ts +0 -24
  571. package/dist/core/scoped-state/providers.js +0 -1
  572. package/dist/core/scoped-state/settings.d.ts +0 -28
  573. package/dist/core/scoped-state/settings.js +0 -1
@@ -1,2 +1,4 @@
1
+ import type { InstalledPlugin } from '../../types.js';
1
2
  /** Whether an enabled command plugin survives nearest-scope name shadowing. */
2
3
  export declare function hasEffectiveCommandPlugins(startDir?: string, profileId?: string | null): boolean;
4
+ export declare function effectiveCommandPlugins(startDir?: string, profileId?: string | null): InstalledPlugin[];
@@ -1 +1 @@
1
- var a=Object.defineProperty;var n=(o,t)=>a(o,"name",{value:t,configurable:!0});import{listInstalledPlugins as f,listInstalledPluginsInRoot as m}from"../resolver.js";import{projectScopeRoots as d}from"../scope.js";function l(o=process.cwd(),t){const s=new Set,r=n(e=>s.has(e.name)?!1:(s.add(e.name),e.enabled&&(e.manifest.commands!==void 0||e.manifest.transport!==void 0)),"consider");for(const e of d(o,t))if(m("project",e).some(r))return!0;return f("user").some(r)}n(l,"hasEffectiveCommandPlugins");export{l as hasEffectiveCommandPlugins};
1
+ var u=Object.defineProperty;var f=(t,s)=>u(t,"name",{value:s,configurable:!0});import{listInstalledPlugins as d,listInstalledPluginsInRoot as a}from"../resolver.js";import{projectScopeRoots as i}from"../scope.js";import{isSandboxedNode as p}from"../../shared/env.js";import{providerRootClaims as l}from"../providers/roots.js";function j(t=process.cwd(),s){const r=new Set,n=f(o=>r.has(o.name)?!1:(r.add(o.name),o.enabled&&(o.manifest.commands!==void 0||o.manifest.transport!==void 0)),"consider");for(const o of i(t,s))if(a("project",o).some(n))return!0;return d("user").some(n)}f(j,"hasEffectiveCommandPlugins");function v(t=process.cwd(),s){const r=new Set,n=[],o=f(e=>{r.has(e.name)||(r.add(e.name),n.push(e))},"consider");for(const e of i(t,s))for(const c of a("project",e))o(c);if(!p())for(const e of d("user"))o(e);const{skipped:m}=l(n);return n.filter(e=>!m.has(e.name)).filter(e=>e.enabled&&(e.manifest.commands!==void 0||e.manifest.transport!==void 0))}f(v,"effectiveCommandPlugins");export{v as effectiveCommandPlugins,j as hasEffectiveCommandPlugins};
@@ -1,6 +1,6 @@
1
1
  import type { PageComponentRegistration, Scope, ScopeConfig, ScopeState, HumanActionConfig, KindConfig, ModelLaddersConfig, ModelProvider, ModelStrength, ModelRouteConfig, ModelRoutingConfig, ProviderOptionsConfig } from '../types.js';
2
2
  import { type BindingId } from './keybindings/catalog.js';
3
- import type { RotationConfig } from './subscription-state.js';
3
+ import type { RotationConfig } from './managed-providers.js';
4
4
  export declare function configPath(scope: Scope): string | null;
5
5
  export declare function statePath(scope: Scope): string | null;
6
6
  export interface BrokerConfigSnapshot {
@@ -26,16 +26,17 @@ export declare function readRawSettingsForTarget(target: RawSettingsTarget): {
26
26
  settings: Record<string, unknown> | null;
27
27
  revision: string;
28
28
  };
29
- export declare function replaceRawSettingsForTarget(target: RawSettingsTarget, next: Record<string, unknown>, ifRevision: string): {
29
+ export declare function replaceRawSettingsForTarget(target: RawSettingsTarget, next: Record<string, unknown>, ifRevision: string): Promise<{
30
30
  revision: string;
31
31
  changed: boolean;
32
- };
32
+ }>;
33
33
  type RawConfig = Record<string, unknown>;
34
- export declare function updateRawConfigAtomically(scope: Scope, mutate: (latest: RawConfig) => RawConfig): RawConfig;
35
- export declare function writeConfig(scope: Scope, config: ScopeConfig): void;
36
- export declare function writeRawConfig(scope: Scope, config: Partial<ScopeConfig>): void;
37
- export declare function writeState(scope: Scope, state: ScopeState): void;
38
- export declare function ensureScopeInitialized(scope: Scope, root: string): void;
34
+ export declare function updateRawConfigAtomically(scope: Scope, mutate: (latest: RawConfig) => RawConfig): Promise<RawConfig>;
35
+ export declare function writeConfig(scope: Scope, config: ScopeConfig): Promise<void>;
36
+ export declare function writeRawConfig(scope: Scope, config: Partial<ScopeConfig>): Promise<void>;
37
+ export declare function writeState(scope: Scope, state: ScopeState): Promise<void>;
38
+ /** A project scope is a directory holding `config.json`; the user and profile scopes are the person's rows and need no directory setup. */
39
+ export declare function ensureScopeInitialized(scope: Scope, root: string): Promise<void>;
39
40
  /** Normalize the user-owned list of attach actions allowed to bridge through an
40
41
  * occupied tmux root binding. Unknown and non-attach ids have no effect. */
41
42
  export declare function normalizeTmuxPassthrough(raw: unknown): BindingId[];
@@ -207,16 +208,16 @@ export declare function persistModelLadders(root: string, patch: {
207
208
  defaultProvider?: ModelProvider;
208
209
  anthropic?: Partial<Record<ModelStrength, string>>;
209
210
  openai?: Partial<Record<ModelStrength, string>>;
210
- }): void;
211
+ }): Promise<void>;
211
212
  /** Persist one complete route at one exact config root. The route is the only
212
213
  * raw route entry touched; unrelated routes and local ladder defaults remain
213
214
  * absent. Pass `undefined` to remove this scope's entry, which resumes lower
214
215
  * scope inheritance rather than introducing a tombstone. */
215
- export declare function persistModelRoute(root: string, routeId: string, route: ModelRouteConfig | undefined): void;
216
+ export declare function persistModelRoute(root: string, routeId: string, route: ModelRouteConfig | undefined): Promise<void>;
216
217
  /** Mutate one exact config root. Setup uses this for profile and explicit
217
218
  * project targets that cannot be represented by the user/project Scope enum. */
218
- export declare function updateConfigAtRoot(root: string, mutate: (cfg: ScopeConfig) => void): ScopeConfig;
219
- export declare function updateConfig(scope: Scope, mutate: (cfg: ScopeConfig) => void): ScopeConfig;
219
+ export declare function updateConfigAtRoot(root: string, mutate: (cfg: ScopeConfig) => void): Promise<ScopeConfig>;
220
+ export declare function updateConfig(scope: Scope, mutate: (cfg: ScopeConfig) => void): Promise<ScopeConfig>;
220
221
  /** Persist one sparse kind-model field at an exact config root. The sparse
221
222
  * patch keeps every unrelated kind and launch knob inherited from lower
222
223
  * scopes instead of freezing a materialized registry snapshot. */
@@ -225,9 +226,9 @@ export declare function persistDefaultKindModel(opts: {
225
226
  kind: string;
226
227
  model: string;
227
228
  orchestrator?: boolean;
228
- }): {
229
+ }): Promise<{
229
230
  path: string;
230
231
  field: 'model' | 'orchestratorModel';
231
- };
232
- export declare function updateState(scope: Scope, mutate: (s: ScopeState) => void): ScopeState;
232
+ }>;
233
+ export declare function updateState(scope: Scope, mutate: (s: ScopeState) => void): Promise<ScopeState>;
233
234
  export {};
@@ -1 +1 @@
1
- var qe=Object.defineProperty;var s=(e,n)=>qe(e,"name",{value:n,configurable:!0});import{envProfileId as Ge}from"../shared/env.js";import{basename as Q,join as ee}from"node:path";import{existsSync as Be,mkdirSync as We,statSync as He}from"node:fs";import{isDeepStrictEqual as Je}from"node:util";import{CONFIG_FILE as Ze,STATE_FILE as Ye,CONDENSED_HISTORY_MODES as Ve,MOUSE_MODE_DEFAULTS as Xe,WHIP_MESSAGE_MODES as Qe,DEFAULT_WHIP_MESSAGES as ne,defaultScopeConfig as w,defaultScopeState as oe,defaultModelLaddersConfig as en,defaultKindsConfig as nn,defaultRemoteCanvasConfig as on}from"../types.js";import{BINDING_CATALOG as tn,BINDING_IDS as rn,isAttachPaneBinding as sn}from"./keybindings/catalog.js";import{notFound as cn}from"./errors.js";import{emitEvent as un}from"./events/emit.js";import{atomicWriteJson as te,readJsonIfExists as q,ensureDir as dn}from"./fs-utils.js";import{scopeRoot as h,requireScopeRoot as A,findProjectScopeRoots as fn,userScopeRoot as I}from"./scope.js";import{listInstalledPluginsInRoot as re}from"./installed-plugins.js";import{profileDir as G,listProfiles as ie}from"./profiles/manifest.js";import{canonicalRoot as S,projectStore as ln,userStore as se}from"./scoped-state/paths.js";import{convertLegacyScopedStore as an,initializeFreshScopedStore as mn}from"./scoped-state/migrate.js";import{mutateRawSettings as pn,readBookkeeping as gn,readRawSettings as yn,readRawSettingsWithRevision as hn,replaceRawSettings as bn,writeBookkeeping as _n,writeRawSettings as vn}from"./scoped-state/settings.js";import{withExclusiveDirectoryLock as kn}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as wn}from"./user-settings.js";import{normalizeWorkingGerunds as An}from"../shared/working-activity.js";import{mergePageComponentLayers as Sn,normalizePageComponents as ce}from"./human/page-catalog.js";function _(e){return ee(e,Ze)}s(_,"configPathFor");function ue(e,n){return kn(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(ue,"withConfigPathLock");function jn(e){return ee(e,Ye)}s(jn,"statePathFor");function ko(e){const n=h(e);return n?_(n):null}s(ko,"configPath");function wo(e){const n=h(e);return n?jn(n):null}s(wo,"statePath");function g(e){const n=S(e),o=S(I());if(n===o)return{store:se(o),key:"user",kind:"user",root:o};if(Q(n)===".crouter")return an({kind:"project",root:n}),{store:ln(n),key:"project",kind:"project",root:n};for(const t of ie()){const r=S(G(t.profileId));if(n===r)return{store:se(o),key:`profile:${t.profileId}`,kind:"profile",root:r,profileId:t.profileId}}throw new Error(`settings root is not a recognized owner: ${e}`)}s(g,"settingsOwnerForRoot");function P(e){if(Q(e)===".crouter"){let n;try{n=S(e)}catch(o){if(o.code==="ENOENT")return null;throw o}if(n!==S(I()))return q(_(e))}return yn(g(e))}s(P,"readRawAtRoot");function B(e,n){const o=g(e);if(o.kind==="project"){ue(_(o.root),t=>te(t,n,{createParent:!1}));return}vn(o,n)}s(B,"writeRawAtRoot");function j(e,n){const o=g(e);return o.kind==="project"?ue(_(o.root),t=>{const r=n(q(t)??{});return te(t,r.next,{createParent:!1}),r.value}):pn(o,t=>n(t))}s(j,"mutateRawAtRoot");const T=globalThis,C=Symbol.for("crtr.broker.config-snapshot");function Ao(e){T[C]=e}s(Ao,"installBrokerConfigSnapshot");function So(){return T[C]}s(So,"brokerConfigSnapshot");function Rn(e){const n=T[C];if(n){if(e!=="user")throw new Error(`broker config snapshot has no ${e} scope`);return n.user}const o=h(e);return o?xn(o):w()}s(Rn,"readConfig");function xn(e){const n=P(e);return n?D(n):w()}s(xn,"readConfigAtRoot");function On(e){const n=h(e);if(!n)return oe();try{return gn(g(n))}catch(o){if(e==="project"&&!Be(n))return oe();throw o}}s(On,"readState");class En extends Error{static{s(this,"InvalidRawSettingsError")}constructor(n){super(`settings cannot be merged: ${n instanceof Error?n.message:String(n)}`),this.name="InvalidRawSettingsError"}}function de(e){if(e.scope==="user")return g(I());if(!ie().some(n=>n.profileId===e.profileId))throw cn(`profile not found: ${e.profileId}`,{received:e.profileId,next:"Run `crtr profile list` to see available profiles."});return g(G(e.profileId))}s(de,"rawSettingsOwnerForTarget");function jo(e){return hn(de(e))}s(jo,"readRawSettingsForTarget");function Ro(e,n,o){return bn(de(e),n,o,t=>{try{D(t)}catch(r){throw new En(r)}})}s(Ro,"replaceRawSettingsForTarget");function xo(e,n){const o=A(e);return j(o,t=>{const r=n(t);return{value:r,next:r}})}s(xo,"updateRawConfigAtomically");function Oo(e,n){B(A(e),n)}s(Oo,"writeConfig");function Eo(e,n){B(A(e),n)}s(Eo,"writeRawConfig");function In(e,n){const o=A(e);_n(g(o),n)}s(In,"writeState");function Io(e,n){if(e==="project")try{We(n)}catch(t){if(t.code!=="EEXIST"||!He(n).isDirectory())throw t}else dn(n);const o=g(e==="user"?I():n);mn({kind:o.kind==="user"?"user":"project",root:o.store.root}),o.kind==="project"&&q(_(o.root))===null&&B(o.root,{schema_version:w().schema_version})}s(Io,"ensureScopeInitialized");function Pn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))Array.isArray(t)&&t.every(r=>typeof r=="string")&&(n[o]=[...t]);return n}s(Pn,"normalizeKeybindings");const Tn=new Set(tn.filter(sn).map(e=>e.id));function Cn(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&rn.has(n)&&Tn.has(n)))]:[]}s(Cn,"normalizeTmuxPassthrough");function $(e,n=en()){const o=n;if(e===null||typeof e!="object")return o;const t=e,r={anthropic:{...o.anthropic},openai:{...o.openai},...o.defaultProvider!==void 0?{defaultProvider:o.defaultProvider}:{}};(t.defaultProvider==="anthropic"||t.defaultProvider==="openai")&&(r.defaultProvider=t.defaultProvider);for(const i of["anthropic","openai"]){const c=t[i];if(!(c===null||typeof c!="object"))for(const[u,d]of Object.entries(c))(u==="ultra"||u==="strong"||u==="medium"||u==="light")&&typeof d=="string"&&(r[i][u]=d)}return r}s($,"mergeModelLadders");function fe(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}s(fe,"validStrength");const W=["ultra","strong","medium","light"];function H(){return Object.create(null)}s(H,"routeRecord");function R(e,n,o){Object.defineProperty(e,n,{value:o,writable:!0,enumerable:!0,configurable:!0})}s(R,"setRouteRecord");function le(e){const n=H();for(const[o,t]of Object.entries(e??{}))R(n,o,t);return n}s(le,"copyRouteRecord");function x(e,n){un({level:"warn",event:"config.model_routes.invalid",fields:{route_id:e,rule:n}})}s(x,"routeInvalid");function M(e,n={}){const o=le(n);if(e===null||typeof e!="object"||Array.isArray(e))return o;for(const[t,r]of Object.entries(e)){if(t.trim()===""){x(t,"route id must be a non-empty string");continue}if(r===null||typeof r!="object"||Array.isArray(r)){x(t,"route must be an object");continue}const i=r,c=o[t],u={...c};let d;for(const l of["family","credentialSource","providerId"]){const f=i[l];if(f!==void 0){if(typeof f!="string"||f.trim()===""){d=`${l} must be a non-empty string`;break}u[l]=f}}if(d===void 0&&i.models!==void 0)if(i.models===null||typeof i.models!="object"||Array.isArray(i.models))d="models must be an object";else{const l={...c?.models};for(const[f,a]of Object.entries(i.models)){if(!fe(f)){d=`models.${f} is not a model strength`;break}if(typeof a!="string"||a.trim()===""){d=`models.${f} must be a non-empty provider/id ref`;break}const m=a.indexOf("/");if(m<=0||m===a.length-1){d=`models.${f} must be provider/id`;break}l[f]=a}u.models=l}if(d===void 0&&u.models!==void 0&&u.providerId!==void 0){for(const[l,f]of Object.entries(u.models))if(f.slice(0,f.indexOf("/"))!==u.providerId){d=`models.${l} provider prefix must equal providerId`;break}}if(d!==void 0){x(t,d);continue}R(o,t,u)}return o}s(M,"mergeModelRoutePatches");function ae(e){const n=H(),o=H();for(const[t,r]of Object.entries(e)){if(r.family===void 0||r.credentialSource===void 0||r.providerId===void 0||r.models===void 0){x(t,"route must include family, credentialSource, providerId, and models");continue}const i=W.filter(c=>r.models[c]===void 0);if(i.length>0){x(t,`incomplete route; missing strengths: ${i.join(", ")}`),R(o,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models});continue}R(n,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models})}return{complete:n,legacy:o}}s(ae,"resolveModelRoutes");function $n(e,n){if(e.trim()==="")throw new Error("model route id must be a non-empty string");for(const t of["family","credentialSource","providerId"])if(typeof n[t]!="string"||n[t].trim()==="")throw new Error(`model route "${e}" ${t} must be a non-empty string`);const o=W.filter(t=>n.models?.[t]===void 0);if(o.length>0)throw new Error(`model route "${e}" is incomplete; missing strengths: ${o.join(", ")}`);for(const t of W){const r=n.models[t];if(typeof r!="string"||r.trim()==="")throw new Error(`model route "${e}" models.${t} must be a non-empty provider/id ref`);const i=r.indexOf("/");if(i<=0||i===r.length-1)throw new Error(`model route "${e}" models.${t} must be provider/id`);if(r.slice(0,i)!==n.providerId)throw new Error(`model route "${e}" models.${t} provider prefix must equal providerId`)}}s($n,"assertCompleteModelRoute");function N(e,n){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return n;const o=e,t=s(i=>Array.isArray(i)&&i.every(c=>typeof c=="string"&&c.trim()!=="")?[...i]:void 0,"strings"),r=Array.isArray(o.strengthFallback)&&o.strengthFallback.every(i=>fe(i))?[...o.strengthFallback]:void 0;return{...t(o.credentialSourceOrder)!==void 0?{credentialSourceOrder:t(o.credentialSourceOrder)}:{},...t(o.familyOrder)!==void 0?{familyOrder:t(o.familyOrder)}:{},...r!==void 0?{strengthFallback:r}:{}}}s(N,"mergeModelRouting");function Mn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Mn,"isInheritAllGlob");function L(e,n=[]){const o=e,t=Array.isArray(o?.allow)?o.allow.filter(r=>typeof r=="string"):[];for(const r of t)if(Mn(r))throw new Error(`spawnEnv.allow: "${r}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...n,...t])]}}s(L,"mergeSpawnEnv");function F(e,n={}){const o={};for(const[t,r]of Object.entries(n))o[t]={...r};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){if(r===null||typeof r!="object")continue;const i={...o[t]},c=r.fastMode;typeof c=="boolean"&&(i.fastMode=c),o[t]=i}return o}s(F,"mergeProviderOptions");const me=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,Nn=new Set(["crtr","crtrd"]);function z(e,n){if(n==="bin"&&Nn.has(e))return`${n}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!me.test(e))return`${n}.${e} is not a safe bare command name (expected ${me.source})`}s(z,"bareCommandNameIssue");function Ln(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"bin",message:"bin must be a JSON object mapping bare command name to a relative path"}];const n=[];for(const[o,t]of Object.entries(e)){const r=z(o,"bin");r!==void 0&&n.push({name:o,message:r}),(typeof t!="string"||t.trim()==="")&&n.push({name:o,message:`bin.${o} must be a non-empty relative path to an executable inside the contributor root`})}return n}s(Ln,"binDeclarationIssues");function Fn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))z(o,"bin")===void 0&&(typeof t!="string"||t.trim()===""||(n[o]=t));return n}s(Fn,"normalizeBin");const pe=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function zn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];const n=[];for(const[o,t]of Object.entries(e)){const r=[];if(pe.test(o)||r.push(`action name must match ${pe.source}`),t===null||typeof t!="object"||Array.isArray(t))r.push("action must be an object with argv and cwd");else{const i=t,c=Object.keys(i).filter(u=>u!=="argv"&&u!=="cwd");c.length>0&&r.push(`action has unsupported field${c.length===1?"":"s"}: ${c.join(", ")}`),(!Array.isArray(i.argv)||i.argv.length===0||!i.argv.every(u=>typeof u=="string"&&u.length>0))&&r.push("argv must be a non-empty array of non-empty strings"),(typeof i.cwd!="string"||i.cwd.length===0)&&r.push("cwd is required and must be a non-empty string")}r.length>0&&n.push({name:o,reason:r.join("; ")})}return n}s(zn,"humanActionDeclarationIssues");function Dn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(zn(e).map(t=>t.name)),o={};for(const[t,r]of Object.entries(e)){if(n.has(t))continue;const i=r;o[t]={argv:[...i.argv],cwd:i.cwd}}return o}s(Dn,"normalizeHumanActions");function Po(e){return Ln(e).map(n=>n.message)}s(Po,"invalidPluginBinReasons");function To(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))z(o,"requires")===void 0&&(typeof t!="string"||t.trim()===""||/[\r\n]/.test(t)||(n[o]=t));return n}s(To,"normalizeRequires");function Co(e){if(e===null||typeof e!="object"||Array.isArray(e))return["requires must be a JSON object mapping a bare executable name to a one-line install hint"];const n=[];for(const[o,t]of Object.entries(e)){const r=z(o,"requires");r!==void 0&&n.push(r),typeof t!="string"||t.trim()===""?n.push(`requires.${o} must be a non-empty one-line install hint`):/[\r\n]/.test(t)&&n.push(`requires.${o} must be a one-line install hint`)}return n}s(Co,"invalidPluginRequiresReasons");function ge(e){if(e===null||typeof e!="object")return null;const n=e,o={};typeof n.whenToUse=="string"&&n.whenToUse.trim()!==""&&(o.whenToUse=n.whenToUse),typeof n.model=="string"&&n.model.trim()!==""&&(o.model=n.model),typeof n.orchestratorModel=="string"&&n.orchestratorModel.trim()!==""&&(o.orchestratorModel=n.orchestratorModel);const t=s(r=>Array.isArray(r)&&r.every(i=>typeof i=="string"),"isStringArray");return t(n.tools)&&(o.tools=n.tools),t(n.extensions)&&(o.extensions=n.extensions),t(n.availableTo)&&(o.availableTo=n.availableTo),Object.keys(o).length>0?o:null}s(ge,"normalizeKindFields");function O(e,n=nn()){const o={...n};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){const i=ge(r);if(i===null)continue;const c=o[t];c!==void 0?o[t]={...c,...i}:i.whenToUse!==void 0&&(o[t]=i)}return o}s(O,"mergeKinds");function ye(e,n,o){if(n===null)return o;const t=re(e,n).filter(i=>i.enabled&&i.manifest.kinds!==void 0).sort((i,c)=>i.name.localeCompare(c.name));let r=o;for(const i of t)r=O(i.manifest.kinds,r);return r}s(ye,"layerPluginKinds");function $o(){const e=[{origin:"config.json",components:Rn("user").page_components}],n=h("user");if(n!==null){const o=re("user",n).filter(t=>t.enabled&&t.manifest.page_components!==void 0).sort((t,r)=>t.name.localeCompare(r.name));for(const t of o){const r=`plugin "${t.name}" page_components`;e.push({origin:`plugin "${t.name}"`,components:ce(t.manifest.page_components,r)})}}return Sn(e)}s($o,"resolvePageComponents");const J=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function Mo(e){if(e===null||typeof e!="object"||Array.isArray(e))return["kinds must be a JSON object keyed by kind name"];const n=[],o=s(t=>Array.isArray(t)&&t.every(r=>typeof r=="string"),"isStringArray");for(const[t,r]of Object.entries(e)){if(t.trim()===""){n.push("kinds contains an empty kind name");continue}if(r===null||typeof r!="object"||Array.isArray(r)){n.push(`kinds.${t} must be a JSON object`);continue}const i=r;for(const c of Object.keys(i))J.has(c)||n.push(`kinds.${t}.${c} is not a KindConfig field (expected one of: ${[...J].join(", ")})`);i.whenToUse!==void 0&&(typeof i.whenToUse!="string"||i.whenToUse.trim()==="")&&n.push(`kinds.${t}.whenToUse must be a non-empty string`);for(const c of["model","orchestratorModel"])i[c]!==void 0&&(typeof i[c]!="string"||i[c].trim()==="")&&n.push(`kinds.${t}.${c} must be a non-empty string`);for(const c of["tools","extensions","availableTo"])i[c]!==void 0&&!o(i[c])&&n.push(`kinds.${t}.${c} must be an array of strings`);ge(r)===null&&n.push(`kinds.${t} has no valid KindConfig field \u2014 an entry must set at least one of: ${[...J].join(", ")} (whenToUse is required when the kind exists in no lower layer)`)}return n}s(Mo,"invalidPluginKindsReasons");function Un(e){if(e===null||typeof e!="object")return null;const n=e;if(typeof n.previewEndpoint!="string"||n.previewEndpoint.trim()===""||typeof n.relayTokenRef!="string"||n.relayTokenRef.trim()==="")return null;const o={previewEndpoint:n.previewEndpoint,relayTokenRef:n.relayTokenRef};return typeof n.cpOrigin=="string"&&n.cpOrigin.trim()!==""&&(o.cpOrigin=n.cpOrigin),o}s(Un,"normalizeRemoteCanvasTarget");function Kn(e,n=on()){const o={...n.targets};if(e!==null&&typeof e=="object"){const t=e;if(t.targets!==null&&typeof t.targets=="object")for(const[r,i]of Object.entries(t.targets)){const c=Un(i);c!==null&&(o[r]=c)}}return{targets:o}}s(Kn,"mergeRemoteCanvas");function he(e,n){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:n}s(he,"normalizeMode");function E(e,n){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:n}s(E,"normalizePositiveInteger");function qn(e,n){const o=e!==null&&typeof e=="object"?e:{},t=E(o.warning,n.warning),r=E(o.automaticReviveCap,n.automaticReviveCap);return t<=r?{warning:t,automaticReviveCap:r}:{...n}}s(qn,"mergeBrokerThresholds");function Gn(e,n){return{unattendedParkMs:E((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(Gn,"mergeLifecycle");function Bn(e){if(!Array.isArray(e))return[...ne];const n=e.filter(o=>typeof o=="string"&&o.trim()!=="").map(o=>o.trim());return n.length>0?n:[...ne]}s(Bn,"normalizeWhipMessages");function Wn(e,n){if(e===null||typeof e!="object")return{...n};const o=e.tcp;return{tcp:typeof o=="string"?o:n.tcp}}s(Wn,"mergeApi");function D(e){const n=w(),o=n.schema_version,t=e.marketplaces===void 0?{}:e.marketplaces,r=e.plugins===void 0?{}:e.plugins,i=e.auto_update,c=i&&typeof i.interval_hours=="number"?i.interval_hours:void 0,u=c!==void 0&&Number.isFinite(c)&&c>=0?c:n.auto_update.interval_hours,d={crtr:he(i?.crtr,n.auto_update.crtr),content:he(i?.content,n.auto_update.content),interval_hours:u},l=e.max_panes_per_window,f=E(l,n.max_panes_per_window),a=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:n.auto_open_child_viewers,m=qn(e.brokerThresholds,n.brokerThresholds),b=Gn(e.lifecycle,n.lifecycle),U=typeof e.completion_bell=="boolean"?e.completion_bell:n.completion_bell,p=e.working_gerunds===void 0?[...n.working_gerunds]:An(e.working_gerunds),_e=typeof e.whip_mode=="boolean"?e.whip_mode:n.whip_mode,ve=ce(e.page_components),ke=typeof e.page_surface=="boolean"?e.page_surface:n.page_surface,we=Bn(e.whip_messages),Ae=Qe.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,Se=Xe.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,je=E(e.live_cycles,n.live_cycles),Re=Ve.includes(e.condensed_history)?e.condensed_history:n.condensed_history,xe=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:n.bash_tool_purpose,Oe=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:n.fold_finished_tools,Ee=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:n.summarize_tool_calls,Ie=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:n.detailed_tool_recaps,Pe=Number.isInteger(e.document_port)&&e.document_port>=1&&e.document_port<=65535?e.document_port:n.document_port,Te=typeof e.consolidate_replies=="boolean"?e.consolidate_replies:n.consolidate_replies,Ce=Pn(e.keybindings),$e=Cn(e.tmux_passthrough),Me=$(e.modelLadders),Ne=F(e.providerOptions,n.providerOptions),K=ae(M(e.modelRoutes)),Z=K.complete,Y=N(e.modelRouting,void 0),Le=O(e.kinds),Fe=Kn(e.remoteCanvas),ze=Wn(e.api,n.api),v=e.paths;if(v?.user_files!==void 0&&(typeof v.user_files!="string"||!v.user_files.startsWith("/")))throw new Error("paths.user_files must be an absolute path");const y=e.ledger;if(y?.take_pct!==void 0&&(typeof y.take_pct!="number"||!Number.isFinite(y.take_pct)||y.take_pct<0||y.take_pct>100))throw new Error("ledger.take_pct must be a number from 0 to 100");const V=e.store,k=e.runtime;if(k?.person_uids!==void 0&&(!Array.isArray(k.person_uids)||!k.person_uids.every(X=>Number.isSafeInteger(X)&&X>=0)))throw new Error("runtime.person_uids must be an array of nonnegative integer uids");const De=L(e.spawnEnv,n.spawnEnv?.allow),Ue=Fn(e.bin),Ke=Dn(e.humanActions);return{bin:Ue,humanActions:Ke,schema_version:o,marketplaces:t,plugins:r,auto_update:d,max_panes_per_window:f,auto_open_child_viewers:a,brokerThresholds:m,lifecycle:b,completion_bell:U,working_gerunds:p,whip_mode:_e,page_components:ve,page_surface:ke,whip_messages:we,whip_message_mode:Ae,mouse_mode_default:Se,live_cycles:je,condensed_history:Re,bash_tool_purpose:xe,fold_finished_tools:Oe,summarize_tool_calls:Ee,detailed_tool_recaps:Ie,document_port:Pe,consolidate_replies:Te,keybindings:Ce,tmux_passthrough:$e,modelLadders:Me,providerOptions:Ne,...Object.keys(Z).length>0?{modelRoutes:Z}:{},...Object.keys(K.legacy).length>0?{legacyModelRoutes:K.legacy}:{},...Y!==void 0?{modelRouting:Y}:{},kinds:Le,remoteCanvas:Fe,api:ze,...v?{paths:v}:{},...y?{ledger:y}:{},...V?{store:V}:{},...k?{runtime:k}:{},spawnEnv:De}}s(D,"mergeConfig");function Hn(e){return P(e)}s(Hn,"readRawConfigAtRoot");function Jn(e){const n=h(e);return n?Hn(n):null}s(Jn,"readRawScopeConfig");function Zn(e){if(e===null||e==="")return null;try{return P(G(e))}catch{return null}}s(Zn,"readRawProfileConfig");function Yn(e,n){return[...fn(e,n)].reverse().map(r=>({root:r,raw:P(r)}))}s(Yn,"readRawProjectScopeConfigs");function be(e=process.cwd(),n=Ge()||null){const o=T[C];if(o)return o.launch;const t=w(),r=Jn("user"),i=Zn(n),c=Yn(e,n);let u=O(r?.kinds,ye("user",h("user"),t.kinds)),d=$(r?.modelLadders,t.modelLadders),l=F(r?.providerOptions,t.providerOptions),f=M(r?.modelRoutes),a=N(r?.modelRouting,void 0),m=L(r?.spawnEnv,t.spawnEnv?.allow);i!==null&&(u=O(i.kinds,u),d=$(i.modelLadders,d),l=F(i.providerOptions,l),f=M(i.modelRoutes,f),a=N(i.modelRouting,a),m=L(i.spawnEnv,m.allow));for(const{root:U,raw:p}of c)u=O(p?.kinds,ye("project",U,u)),p!==null&&(d=$(p.modelLadders,d),l=F(p.providerOptions,l),f=M(p.modelRoutes,f),a=N(p.modelRouting,a),m=L(p.spawnEnv,m.allow));const b=ae(f);return{kinds:u,modelLadders:d,providerOptions:l,...Object.keys(b.complete).length>0?{modelRoutes:b.complete}:{},...Object.keys(b.legacy).length>0?{legacyModelRoutes:b.legacy}:{},...a!==void 0?{modelRouting:a}:{},spawnEnv:m}}s(be,"readMergedLaunchConfig");function No(e){return be().kinds[e]}s(No,"resolveKindConfig");function Lo(e){const n=be().kinds,o=[];for(const[t,r]of Object.entries(n)){const i=t.indexOf("/");if(i===-1)continue;const c=t.slice(0,i),u=r.availableTo??[c];(u.includes("*")||u.includes(e))&&o.push({kind:t,whenToUse:r.whenToUse})}return o.sort((t,r)=>t.kind.localeCompare(r.kind))}s(Lo,"subKindsAvailableTo");function Vn(e,n,o){const t={...e??{}};t.anthropic!==void 0&&(t.anthropic={...t.anthropic}),t.openai!==void 0&&(t.openai={...t.openai}),o.defaultProvider!==n.defaultProvider&&o.defaultProvider!==void 0&&(t.defaultProvider=o.defaultProvider);for(const i of["anthropic","openai"])for(const c of["ultra","strong","medium","light"])o[i][c]!==n[i][c]&&(t[i]={...t[i]??{},[c]:o[i][c]});return t.defaultProvider!==void 0||t.anthropic!==void 0||t.openai!==void 0?t:void 0}s(Vn,"sparseModelLaddersToPersist");function Xn(e,n){return j(e,o=>{const t=D(o),r=D(o);n(r);const i={...o};for(const u of wn)u!=="modelLadders"&&!Je(r[u],t[u])&&(i[u]=r[u]);const c=Vn(o.modelLadders,t.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Xn,"mutateConfigAtRoot");function Fo(e,n){j(e,o=>{const t=o.modelLadders??{},r={...t};n.defaultProvider!==void 0&&(r.defaultProvider=n.defaultProvider);for(const i of["anthropic","openai"])n[i]!==void 0&&(r[i]={...t[i]??{},...n[i]});return{value:void 0,next:{...o,modelLadders:r}}})}s(Fo,"persistModelLadders");function zo(e,n,o){if(o!==void 0)$n(n,o);else if(n.trim()==="")throw new Error("model route id must be a non-empty string");j(e,t=>{const r=le(t.modelRoutes??{});o===void 0?delete r[n]:R(r,n,{...o,models:{...o.models}});const i={...t};return Object.keys(r).length===0?delete i.modelRoutes:i.modelRoutes=r,{value:void 0,next:i}})}s(zo,"persistModelRoute");function Qn(e,n){return Xn(e,n)}s(Qn,"updateConfigAtRoot");function Do(e,n){return Qn(A(e),n)}s(Do,"updateConfig");function Uo(e){const n=e.orchestrator===!0?"orchestratorModel":"model";return j(e.root,o=>{const t={...o.kinds??{},[e.kind]:{...(o.kinds??{})[e.kind],[n]:e.model}};return{value:void 0,next:{...o,kinds:t}}}),{path:_(e.root),field:n}}s(Uo,"persistDefaultKindModel");function Ko(e,n){const o=On(e);return n(o),In(e,o),o}s(Ko,"updateState");export{En as InvalidRawSettingsError,Ln as binDeclarationIssues,So as brokerConfigSnapshot,ko as configPath,Io as ensureScopeInitialized,zn as humanActionDeclarationIssues,Ao as installBrokerConfigSnapshot,Po as invalidPluginBinReasons,Mo as invalidPluginKindsReasons,Co as invalidPluginRequiresReasons,Fn as normalizeBin,Dn as normalizeHumanActions,To as normalizeRequires,Cn as normalizeTmuxPassthrough,Uo as persistDefaultKindModel,Fo as persistModelLadders,zo as persistModelRoute,Rn as readConfig,xn as readConfigAtRoot,be as readMergedLaunchConfig,Hn as readRawConfigAtRoot,Jn as readRawScopeConfig,jo as readRawSettingsForTarget,On as readState,Ro as replaceRawSettingsForTarget,No as resolveKindConfig,$o as resolvePageComponents,wo as statePath,Lo as subKindsAvailableTo,Do as updateConfig,Qn as updateConfigAtRoot,xo as updateRawConfigAtomically,Ko as updateState,Oo as writeConfig,Eo as writeRawConfig,In as writeState};
1
+ var Ze=Object.defineProperty;var s=(e,n)=>Ze(e,"name",{value:n,configurable:!0});import{envProfileId as Ye}from"../shared/env.js";import{basename as re,join as ie}from"node:path";import{existsSync as Ve,mkdirSync as Xe,statSync as Qe}from"node:fs";import{isDeepStrictEqual as en}from"node:util";import{CONFIG_FILE as nn,STATE_FILE as on,CONDENSED_HISTORY_MODES as tn,MOUSE_MODE_DEFAULTS as rn,WHIP_MESSAGE_MODES as sn,DEFAULT_WHIP_MESSAGES as se,defaultScopeConfig as k,defaultScopeState as ce,defaultModelLaddersConfig as cn,defaultKindsConfig as un,defaultRemoteCanvasConfig as dn}from"../types.js";import{BINDING_CATALOG as an,BINDING_IDS as fn,isAttachPaneBinding as ln}from"./keybindings/catalog.js";import{notFound as mn}from"./errors.js";import{emitEvent as pn}from"./events/emit.js";import{atomicWriteJson as B,readJsonIfExists as C,ensureDir as gn}from"./fs-utils.js";import{scopeRoot as y,requireScopeRoot as A,findProjectScopeRoots as yn,userScopeRoot as ue}from"./scope.js";import{listInstalledPluginsInRoot as de}from"./installed-plugins.js";import{profileDir as ae,listProfiles as fe}from"./profiles/manifest.js";import{canonicalRoot as S}from"./scoped-state/paths.js";import{readCachedSettings as H,readCachedState as hn,revisionOf as J,SettingsRevisionConflictError as le,writeSettings as W}from"./scoped-state/person-store.js";import{withExclusiveDirectoryLock as _n}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as bn}from"./user-settings.js";import{normalizeWorkingGerunds as vn}from"../shared/working-activity.js";import{mergePageComponentLayers as wn,normalizePageComponents as me}from"./human/page-catalog.js";function _(e){return ie(e,nn)}s(_,"configPathFor");function Z(e,n){return _n(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(Z,"withConfigPathLock");function Y(e){return ie(e,on)}s(Y,"statePathFor");function _o(e){const n=y(e);return n?_(n):null}s(_o,"configPath");function bo(e){const n=y(e);return n?Y(n):null}s(bo,"statePath");function j(e){const n=S(e),o=S(ue());if(n===o)return{key:"user",kind:"user",root:o};if(re(n)===".crouter")return{key:"project",kind:"project",root:n};for(const t of fe()){const r=S(ae(t.profileId));if(n===r)return{key:`profile:${t.profileId}`,kind:"profile",root:r,profileId:t.profileId}}throw new Error(`settings root is not a recognized owner: ${e}`)}s(j,"settingsOwnerForRoot");function T(e){if(re(e)===".crouter"){let n;try{n=S(e)}catch(o){if(o.code==="ENOENT")return null;throw o}if(n!==S(ue()))return C(_(e))}return H(j(e).key).settings}s(T,"readRawAtRoot");async function pe(e,n){let o;return await W(t=>{const r=t.settings[e],i=n(structuredClone(r??{}));return o=i.value,[{op:"settings.replace",owner:e,raw:i.next,ifRevision:J(r)}]}),o}s(pe,"mutatePersonSettings");async function V(e,n){const o=j(e);if(o.kind==="project"){Z(_(o.root),t=>B(t,n,{createParent:!1}));return}await pe(o.key,()=>({value:void 0,next:n}))}s(V,"writeRawAtRoot");async function x(e,n){const o=j(e);return o.kind==="project"?Z(_(o.root),t=>{const r=n(C(t)??{});return B(t,r.next,{createParent:!1}),r.value}):await pe(o.key,n)}s(x,"mutateRawAtRoot");const $=globalThis,M=Symbol.for("crtr.broker.config-snapshot");function vo(e){$[M]=e}s(vo,"installBrokerConfigSnapshot");function wo(){return $[M]}s(wo,"brokerConfigSnapshot");function kn(e){const n=$[M];if(n){if(e!=="user")throw new Error(`broker config snapshot has no ${e} scope`);return n.user}const o=y(e);return o?An(o):k()}s(kn,"readConfig");function An(e){const n=T(e);return n?U(n):k()}s(An,"readConfigAtRoot");function Sn(e){const n=C(Y(e));return{marketplaces:n?.marketplaces??{},plugins:n?.plugins??{},activeCanvas:n?.activeCanvas??null,...n?.last_self_check===void 0?{}:{last_self_check:n.last_self_check}}}s(Sn,"readProjectState");function jn(e){const n=y(e);return n?e==="project"?Ve(n)?Sn(n):ce():hn(j(n).key):ce()}s(jn,"readState");class xn extends Error{static{s(this,"InvalidRawSettingsError")}constructor(n){super(`settings cannot be merged: ${n instanceof Error?n.message:String(n)}`),this.name="InvalidRawSettingsError"}}function ge(e){if(e.scope==="user")return"user";if(!fe().some(n=>n.profileId===e.profileId))throw mn(`profile not found: ${e.profileId}`,{received:e.profileId,next:"Run `crtr profile list` to see available profiles."});return`profile:${e.profileId}`}s(ge,"rawSettingsKeyForTarget");function ko(e){return H(ge(e))}s(ko,"readRawSettingsForTarget");async function Ao(e,n,o){const t=ge(e);try{U(n)}catch(u){throw new xn(u)}if(H(t).revision!==o)throw new le;const i=await W(u=>J(u.settings[t])===o?[{op:"settings.replace",owner:t,raw:n,ifRevision:o}]:(()=>{throw new le})()),c=J(i.settings[t]);return{revision:c,changed:c!==o}}s(Ao,"replaceRawSettingsForTarget");async function So(e,n){const o=A(e);return await x(o,t=>{const r=n(t);return{value:r,next:r}})}s(So,"updateRawConfigAtomically");async function jo(e,n){await V(A(e),n)}s(jo,"writeConfig");async function xo(e,n){await V(A(e),n)}s(xo,"writeRawConfig");function Rn(e,n){Z(Y(e),o=>B(o,n,{createParent:!1}))}s(Rn,"writeProjectState");async function En(e,n){const o=A(e);if(e==="project"){Rn(o,n);return}const t=j(o).key;await W(()=>[{op:"state.write",owner:t,state:n}])}s(En,"writeState");async function Ro(e,n){if(e!=="project"){gn(n);return}try{Xe(n)}catch(o){if(o.code!=="EEXIST"||!Qe(n).isDirectory())throw o}C(_(n))===null&&await V(n,{schema_version:k().schema_version})}s(Ro,"ensureScopeInitialized");function On(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))Array.isArray(t)&&t.every(r=>typeof r=="string")&&(n[o]=[...t]);return n}s(On,"normalizeKeybindings");const Pn=new Set(an.filter(ln).map(e=>e.id));function In(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&fn.has(n)&&Pn.has(n)))]:[]}s(In,"normalizeTmuxPassthrough");function N(e,n=cn()){const o=n;if(e===null||typeof e!="object")return o;const t=e,r={anthropic:{...o.anthropic},openai:{...o.openai},...o.defaultProvider!==void 0?{defaultProvider:o.defaultProvider}:{}};(t.defaultProvider==="anthropic"||t.defaultProvider==="openai")&&(r.defaultProvider=t.defaultProvider);for(const i of["anthropic","openai"]){const c=t[i];if(!(c===null||typeof c!="object"))for(const[u,d]of Object.entries(c))(u==="ultra"||u==="strong"||u==="medium"||u==="light")&&typeof d=="string"&&(r[i][u]=d)}return r}s(N,"mergeModelLadders");function ye(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}s(ye,"validStrength");const X=["ultra","strong","medium","light"];function Q(){return Object.create(null)}s(Q,"routeRecord");function R(e,n,o){Object.defineProperty(e,n,{value:o,writable:!0,enumerable:!0,configurable:!0})}s(R,"setRouteRecord");function he(e){const n=Q();for(const[o,t]of Object.entries(e??{}))R(n,o,t);return n}s(he,"copyRouteRecord");function E(e,n){pn({level:"warn",event:"config.model_routes.invalid",fields:{route_id:e,rule:n}})}s(E,"routeInvalid");function L(e,n={}){const o=he(n);if(e===null||typeof e!="object"||Array.isArray(e))return o;for(const[t,r]of Object.entries(e)){if(t.trim()===""){E(t,"route id must be a non-empty string");continue}if(r===null||typeof r!="object"||Array.isArray(r)){E(t,"route must be an object");continue}const i=r,c=o[t],u={...c};let d;for(const f of["family","credentialSource","providerId"]){const a=i[f];if(a!==void 0){if(typeof a!="string"||a.trim()===""){d=`${f} must be a non-empty string`;break}u[f]=a}}if(d===void 0&&i.models!==void 0)if(i.models===null||typeof i.models!="object"||Array.isArray(i.models))d="models must be an object";else{const f={...c?.models};for(const[a,l]of Object.entries(i.models)){if(!ye(a)){d=`models.${a} is not a model strength`;break}if(typeof l!="string"||l.trim()===""){d=`models.${a} must be a non-empty provider/id ref`;break}const m=l.indexOf("/");if(m<=0||m===l.length-1){d=`models.${a} must be provider/id`;break}f[a]=l}u.models=f}if(d===void 0&&u.models!==void 0&&u.providerId!==void 0){for(const[f,a]of Object.entries(u.models))if(a.slice(0,a.indexOf("/"))!==u.providerId){d=`models.${f} provider prefix must equal providerId`;break}}if(d!==void 0){E(t,d);continue}R(o,t,u)}return o}s(L,"mergeModelRoutePatches");function _e(e){const n=Q(),o=Q();for(const[t,r]of Object.entries(e)){if(r.family===void 0||r.credentialSource===void 0||r.providerId===void 0||r.models===void 0){E(t,"route must include family, credentialSource, providerId, and models");continue}const i=X.filter(c=>r.models[c]===void 0);if(i.length>0){E(t,`incomplete route; missing strengths: ${i.join(", ")}`),R(o,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models});continue}R(n,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models})}return{complete:n,legacy:o}}s(_e,"resolveModelRoutes");function Cn(e,n){if(e.trim()==="")throw new Error("model route id must be a non-empty string");for(const t of["family","credentialSource","providerId"])if(typeof n[t]!="string"||n[t].trim()==="")throw new Error(`model route "${e}" ${t} must be a non-empty string`);const o=X.filter(t=>n.models?.[t]===void 0);if(o.length>0)throw new Error(`model route "${e}" is incomplete; missing strengths: ${o.join(", ")}`);for(const t of X){const r=n.models[t];if(typeof r!="string"||r.trim()==="")throw new Error(`model route "${e}" models.${t} must be a non-empty provider/id ref`);const i=r.indexOf("/");if(i<=0||i===r.length-1)throw new Error(`model route "${e}" models.${t} must be provider/id`);if(r.slice(0,i)!==n.providerId)throw new Error(`model route "${e}" models.${t} provider prefix must equal providerId`)}}s(Cn,"assertCompleteModelRoute");function F(e,n){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return n;const o=e,t=s(i=>Array.isArray(i)&&i.every(c=>typeof c=="string"&&c.trim()!=="")?[...i]:void 0,"strings"),r=Array.isArray(o.strengthFallback)&&o.strengthFallback.every(i=>ye(i))?[...o.strengthFallback]:void 0;return{...t(o.credentialSourceOrder)!==void 0?{credentialSourceOrder:t(o.credentialSourceOrder)}:{},...t(o.familyOrder)!==void 0?{familyOrder:t(o.familyOrder)}:{},...r!==void 0?{strengthFallback:r}:{}}}s(F,"mergeModelRouting");function Tn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Tn,"isInheritAllGlob");function z(e,n=[]){const o=e,t=Array.isArray(o?.allow)?o.allow.filter(r=>typeof r=="string"):[];for(const r of t)if(Tn(r))throw new Error(`spawnEnv.allow: "${r}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...n,...t])]}}s(z,"mergeSpawnEnv");function D(e,n={}){const o={};for(const[t,r]of Object.entries(n))o[t]={...r};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){if(r===null||typeof r!="object")continue;const i={...o[t]},c=r.fastMode;typeof c=="boolean"&&(i.fastMode=c),o[t]=i}return o}s(D,"mergeProviderOptions");const be=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,$n=new Set(["crtr","crtrd"]);function K(e,n){if(n==="bin"&&$n.has(e))return`${n}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!be.test(e))return`${n}.${e} is not a safe bare command name (expected ${be.source})`}s(K,"bareCommandNameIssue");function Mn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"bin",message:"bin must be a JSON object mapping bare command name to a relative path"}];const n=[];for(const[o,t]of Object.entries(e)){const r=K(o,"bin");r!==void 0&&n.push({name:o,message:r}),(typeof t!="string"||t.trim()==="")&&n.push({name:o,message:`bin.${o} must be a non-empty relative path to an executable inside the contributor root`})}return n}s(Mn,"binDeclarationIssues");function Nn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))K(o,"bin")===void 0&&(typeof t!="string"||t.trim()===""||(n[o]=t));return n}s(Nn,"normalizeBin");const ve=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Ln(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];const n=[];for(const[o,t]of Object.entries(e)){const r=[];if(ve.test(o)||r.push(`action name must match ${ve.source}`),t===null||typeof t!="object"||Array.isArray(t))r.push("action must be an object with argv and cwd");else{const i=t,c=Object.keys(i).filter(u=>u!=="argv"&&u!=="cwd");c.length>0&&r.push(`action has unsupported field${c.length===1?"":"s"}: ${c.join(", ")}`),(!Array.isArray(i.argv)||i.argv.length===0||!i.argv.every(u=>typeof u=="string"&&u.length>0))&&r.push("argv must be a non-empty array of non-empty strings"),(typeof i.cwd!="string"||i.cwd.length===0)&&r.push("cwd is required and must be a non-empty string")}r.length>0&&n.push({name:o,reason:r.join("; ")})}return n}s(Ln,"humanActionDeclarationIssues");function Fn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(Ln(e).map(t=>t.name)),o={};for(const[t,r]of Object.entries(e)){if(n.has(t))continue;const i=r;o[t]={argv:[...i.argv],cwd:i.cwd}}return o}s(Fn,"normalizeHumanActions");function Eo(e){return Mn(e).map(n=>n.message)}s(Eo,"invalidPluginBinReasons");function Oo(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))K(o,"requires")===void 0&&(typeof t!="string"||t.trim()===""||/[\r\n]/.test(t)||(n[o]=t));return n}s(Oo,"normalizeRequires");function Po(e){if(e===null||typeof e!="object"||Array.isArray(e))return["requires must be a JSON object mapping a bare executable name to a one-line install hint"];const n=[];for(const[o,t]of Object.entries(e)){const r=K(o,"requires");r!==void 0&&n.push(r),typeof t!="string"||t.trim()===""?n.push(`requires.${o} must be a non-empty one-line install hint`):/[\r\n]/.test(t)&&n.push(`requires.${o} must be a one-line install hint`)}return n}s(Po,"invalidPluginRequiresReasons");function we(e){if(e===null||typeof e!="object")return null;const n=e,o={};typeof n.whenToUse=="string"&&n.whenToUse.trim()!==""&&(o.whenToUse=n.whenToUse),typeof n.model=="string"&&n.model.trim()!==""&&(o.model=n.model),typeof n.orchestratorModel=="string"&&n.orchestratorModel.trim()!==""&&(o.orchestratorModel=n.orchestratorModel);const t=s(r=>Array.isArray(r)&&r.every(i=>typeof i=="string"),"isStringArray");return t(n.tools)&&(o.tools=n.tools),t(n.extensions)&&(o.extensions=n.extensions),t(n.availableTo)&&(o.availableTo=n.availableTo),Object.keys(o).length>0?o:null}s(we,"normalizeKindFields");function O(e,n=un()){const o={...n};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){const i=we(r);if(i===null)continue;const c=o[t];c!==void 0?o[t]={...c,...i}:i.whenToUse!==void 0&&(o[t]=i)}return o}s(O,"mergeKinds");function ke(e,n,o){if(n===null)return o;const t=de(e,n).filter(i=>i.enabled&&i.manifest.kinds!==void 0).sort((i,c)=>i.name.localeCompare(c.name));let r=o;for(const i of t)r=O(i.manifest.kinds,r);return r}s(ke,"layerPluginKinds");function Io(){const e=[{origin:"config.json",components:kn("user").page_components}],n=y("user");if(n!==null){const o=de("user",n).filter(t=>t.enabled&&t.manifest.page_components!==void 0).sort((t,r)=>t.name.localeCompare(r.name));for(const t of o){const r=`plugin "${t.name}" page_components`;e.push({origin:`plugin "${t.name}"`,components:me(t.manifest.page_components,r)})}}return wn(e)}s(Io,"resolvePageComponents");const ee=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function Co(e){if(e===null||typeof e!="object"||Array.isArray(e))return["kinds must be a JSON object keyed by kind name"];const n=[],o=s(t=>Array.isArray(t)&&t.every(r=>typeof r=="string"),"isStringArray");for(const[t,r]of Object.entries(e)){if(t.trim()===""){n.push("kinds contains an empty kind name");continue}if(r===null||typeof r!="object"||Array.isArray(r)){n.push(`kinds.${t} must be a JSON object`);continue}const i=r;for(const c of Object.keys(i))ee.has(c)||n.push(`kinds.${t}.${c} is not a KindConfig field (expected one of: ${[...ee].join(", ")})`);i.whenToUse!==void 0&&(typeof i.whenToUse!="string"||i.whenToUse.trim()==="")&&n.push(`kinds.${t}.whenToUse must be a non-empty string`);for(const c of["model","orchestratorModel"])i[c]!==void 0&&(typeof i[c]!="string"||i[c].trim()==="")&&n.push(`kinds.${t}.${c} must be a non-empty string`);for(const c of["tools","extensions","availableTo"])i[c]!==void 0&&!o(i[c])&&n.push(`kinds.${t}.${c} must be an array of strings`);we(r)===null&&n.push(`kinds.${t} has no valid KindConfig field \u2014 an entry must set at least one of: ${[...ee].join(", ")} (whenToUse is required when the kind exists in no lower layer)`)}return n}s(Co,"invalidPluginKindsReasons");function zn(e){if(e===null||typeof e!="object")return null;const n=e;if(typeof n.previewEndpoint!="string"||n.previewEndpoint.trim()===""||typeof n.relayTokenRef!="string"||n.relayTokenRef.trim()==="")return null;const o={previewEndpoint:n.previewEndpoint,relayTokenRef:n.relayTokenRef};return typeof n.cpOrigin=="string"&&n.cpOrigin.trim()!==""&&(o.cpOrigin=n.cpOrigin),o}s(zn,"normalizeRemoteCanvasTarget");function Dn(e,n=dn()){const o={...n.targets};if(e!==null&&typeof e=="object"){const t=e;if(t.targets!==null&&typeof t.targets=="object")for(const[r,i]of Object.entries(t.targets)){const c=zn(i);c!==null&&(o[r]=c)}}return{targets:o}}s(Dn,"mergeRemoteCanvas");function Ae(e,n){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:n}s(Ae,"normalizeMode");function P(e,n){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:n}s(P,"normalizePositiveInteger");function Kn(e,n){const o=e!==null&&typeof e=="object"?e:{},t=P(o.warning,n.warning),r=P(o.automaticReviveCap,n.automaticReviveCap);return t<=r?{warning:t,automaticReviveCap:r}:{...n}}s(Kn,"mergeBrokerThresholds");function Un(e,n){return{unattendedParkMs:P((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(Un,"mergeLifecycle");function qn(e){if(!Array.isArray(e))return[...se];const n=e.filter(o=>typeof o=="string"&&o.trim()!=="").map(o=>o.trim());return n.length>0?n:[...se]}s(qn,"normalizeWhipMessages");function Gn(e,n){if(e===null||typeof e!="object")return{...n};const o=e.tcp;return{tcp:typeof o=="string"?o:n.tcp}}s(Gn,"mergeApi");function U(e){const n=k(),o=n.schema_version,t=e.marketplaces===void 0?{}:e.marketplaces,r=e.plugins===void 0?{}:e.plugins,i=e.auto_update,c=i&&typeof i.interval_hours=="number"?i.interval_hours:void 0,u=c!==void 0&&Number.isFinite(c)&&c>=0?c:n.auto_update.interval_hours,d={crtr:Ae(i?.crtr,n.auto_update.crtr),content:Ae(i?.content,n.auto_update.content),interval_hours:u},f=e.max_panes_per_window,a=P(f,n.max_panes_per_window),l=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:n.auto_open_child_viewers,m=Kn(e.brokerThresholds,n.brokerThresholds),h=Un(e.lifecycle,n.lifecycle),q=typeof e.completion_bell=="boolean"?e.completion_bell:n.completion_bell,g=e.working_gerunds===void 0?[...n.working_gerunds]:vn(e.working_gerunds),je=typeof e.whip_mode=="boolean"?e.whip_mode:n.whip_mode,xe=me(e.page_components),Re=typeof e.page_surface=="boolean"?e.page_surface:n.page_surface,Ee=qn(e.whip_messages),Oe=sn.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,Pe=rn.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,Ie=P(e.live_cycles,n.live_cycles),Ce=tn.includes(e.condensed_history)?e.condensed_history:n.condensed_history,Te=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:n.bash_tool_purpose,$e=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:n.fold_finished_tools,Me=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:n.summarize_tool_calls,Ne=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:n.detailed_tool_recaps,Le=Number.isInteger(e.document_port)&&e.document_port>=1&&e.document_port<=65535?e.document_port:n.document_port,Fe=typeof e.consolidate_replies=="boolean"?e.consolidate_replies:n.consolidate_replies,ze=On(e.keybindings),De=In(e.tmux_passthrough),Ke=N(e.modelLadders),Ue=D(e.providerOptions,n.providerOptions),G=_e(L(e.modelRoutes)),ne=G.complete,oe=F(e.modelRouting,void 0),qe=O(e.kinds),Ge=Dn(e.remoteCanvas),Be=Gn(e.api,n.api),b=e.paths;if(b?.user_files!==void 0&&(typeof b.user_files!="string"||!b.user_files.startsWith("/")))throw new Error("paths.user_files must be an absolute path");const p=e.ledger;if(p?.take_pct!==void 0&&(typeof p.take_pct!="number"||!Number.isFinite(p.take_pct)||p.take_pct<0||p.take_pct>100))throw new Error("ledger.take_pct must be a number from 0 to 100");for(const w of["sandbox_usd_per_gb_hour","sandbox_standby_s","storage_usd_per_gb_month","sandbox_disk_usd_per_gb_month","infra_free_usd_per_month"]){const I=p?.[w];if(I!==void 0&&(typeof I!="number"||!Number.isFinite(I)||I<0))throw new Error(`ledger.${w} must be a number of at least 0`)}if(p?.r2_move!==void 0&&typeof p.r2_move!="boolean")throw new Error("ledger.r2_move must be true or false");const te=e.store,v=e.runtime;if(v?.person_uids!==void 0&&(!Array.isArray(v.person_uids)||!v.person_uids.every(w=>Number.isSafeInteger(w)&&w>=0)))throw new Error("runtime.person_uids must be an array of nonnegative integer uids");const He=z(e.spawnEnv,n.spawnEnv?.allow),Je=Nn(e.bin),We=Fn(e.humanActions);return{bin:Je,humanActions:We,schema_version:o,marketplaces:t,plugins:r,auto_update:d,max_panes_per_window:a,auto_open_child_viewers:l,brokerThresholds:m,lifecycle:h,completion_bell:q,working_gerunds:g,whip_mode:je,page_components:xe,page_surface:Re,whip_messages:Ee,whip_message_mode:Oe,mouse_mode_default:Pe,live_cycles:Ie,condensed_history:Ce,bash_tool_purpose:Te,fold_finished_tools:$e,summarize_tool_calls:Me,detailed_tool_recaps:Ne,document_port:Le,consolidate_replies:Fe,keybindings:ze,tmux_passthrough:De,modelLadders:Ke,providerOptions:Ue,...Object.keys(ne).length>0?{modelRoutes:ne}:{},...Object.keys(G.legacy).length>0?{legacyModelRoutes:G.legacy}:{},...oe!==void 0?{modelRouting:oe}:{},kinds:qe,remoteCanvas:Ge,api:Be,...b?{paths:b}:{},...p?{ledger:p}:{},...te?{store:te}:{},...v?{runtime:v}:{},spawnEnv:He}}s(U,"mergeConfig");function Bn(e){return T(e)}s(Bn,"readRawConfigAtRoot");function Hn(e){const n=y(e);return n?Bn(n):null}s(Hn,"readRawScopeConfig");function Jn(e){if(e===null||e==="")return null;try{return T(ae(e))}catch{return null}}s(Jn,"readRawProfileConfig");function Wn(e,n){return[...yn(e,n)].reverse().map(r=>({root:r,raw:T(r)}))}s(Wn,"readRawProjectScopeConfigs");function Se(e=process.cwd(),n=Ye()||null){const o=$[M];if(o)return o.launch;const t=k(),r=Hn("user"),i=Jn(n),c=Wn(e,n);let u=O(r?.kinds,ke("user",y("user"),t.kinds)),d=N(r?.modelLadders,t.modelLadders),f=D(r?.providerOptions,t.providerOptions),a=L(r?.modelRoutes),l=F(r?.modelRouting,void 0),m=z(r?.spawnEnv,t.spawnEnv?.allow);i!==null&&(u=O(i.kinds,u),d=N(i.modelLadders,d),f=D(i.providerOptions,f),a=L(i.modelRoutes,a),l=F(i.modelRouting,l),m=z(i.spawnEnv,m.allow));for(const{root:q,raw:g}of c)u=O(g?.kinds,ke("project",q,u)),g!==null&&(d=N(g.modelLadders,d),f=D(g.providerOptions,f),a=L(g.modelRoutes,a),l=F(g.modelRouting,l),m=z(g.spawnEnv,m.allow));const h=_e(a);return{kinds:u,modelLadders:d,providerOptions:f,...Object.keys(h.complete).length>0?{modelRoutes:h.complete}:{},...Object.keys(h.legacy).length>0?{legacyModelRoutes:h.legacy}:{},...l!==void 0?{modelRouting:l}:{},spawnEnv:m}}s(Se,"readMergedLaunchConfig");function To(e){return Se().kinds[e]}s(To,"resolveKindConfig");function $o(e){const n=Se().kinds,o=[];for(const[t,r]of Object.entries(n)){const i=t.indexOf("/");if(i===-1)continue;const c=t.slice(0,i),u=r.availableTo??[c];(u.includes("*")||u.includes(e))&&o.push({kind:t,whenToUse:r.whenToUse})}return o.sort((t,r)=>t.kind.localeCompare(r.kind))}s($o,"subKindsAvailableTo");function Zn(e,n,o){const t={...e??{}};t.anthropic!==void 0&&(t.anthropic={...t.anthropic}),t.openai!==void 0&&(t.openai={...t.openai}),o.defaultProvider!==n.defaultProvider&&o.defaultProvider!==void 0&&(t.defaultProvider=o.defaultProvider);for(const i of["anthropic","openai"])for(const c of["ultra","strong","medium","light"])o[i][c]!==n[i][c]&&(t[i]={...t[i]??{},[c]:o[i][c]});return t.defaultProvider!==void 0||t.anthropic!==void 0||t.openai!==void 0?t:void 0}s(Zn,"sparseModelLaddersToPersist");async function Yn(e,n){return await x(e,o=>{const t=U(o),r=U(o);n(r);const i={...o};for(const u of bn)u!=="modelLadders"&&!en(r[u],t[u])&&(i[u]=r[u]);const c=Zn(o.modelLadders,t.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Yn,"mutateConfigAtRoot");async function Mo(e,n){await x(e,o=>{const t=o.modelLadders??{},r={...t};n.defaultProvider!==void 0&&(r.defaultProvider=n.defaultProvider);for(const i of["anthropic","openai"])n[i]!==void 0&&(r[i]={...t[i]??{},...n[i]});return{value:void 0,next:{...o,modelLadders:r}}})}s(Mo,"persistModelLadders");async function No(e,n,o){if(o!==void 0)Cn(n,o);else if(n.trim()==="")throw new Error("model route id must be a non-empty string");await x(e,t=>{const r=he(t.modelRoutes??{});o===void 0?delete r[n]:R(r,n,{...o,models:{...o.models}});const i={...t};return Object.keys(r).length===0?delete i.modelRoutes:i.modelRoutes=r,{value:void 0,next:i}})}s(No,"persistModelRoute");async function Vn(e,n){return await Yn(e,n)}s(Vn,"updateConfigAtRoot");async function Lo(e,n){return await Vn(A(e),n)}s(Lo,"updateConfig");async function Fo(e){const n=e.orchestrator===!0?"orchestratorModel":"model";return await x(e.root,o=>{const t={...o.kinds??{},[e.kind]:{...(o.kinds??{})[e.kind],[n]:e.model}};return{value:void 0,next:{...o,kinds:t}}}),{path:_(e.root),field:n}}s(Fo,"persistDefaultKindModel");async function zo(e,n){const o=jn(e);return n(o),await En(e,o),o}s(zo,"updateState");export{xn as InvalidRawSettingsError,Mn as binDeclarationIssues,wo as brokerConfigSnapshot,_o as configPath,Ro as ensureScopeInitialized,Ln as humanActionDeclarationIssues,vo as installBrokerConfigSnapshot,Eo as invalidPluginBinReasons,Co as invalidPluginKindsReasons,Po as invalidPluginRequiresReasons,Nn as normalizeBin,Fn as normalizeHumanActions,Oo as normalizeRequires,In as normalizeTmuxPassthrough,Fo as persistDefaultKindModel,Mo as persistModelLadders,No as persistModelRoute,kn as readConfig,An as readConfigAtRoot,Se as readMergedLaunchConfig,Bn as readRawConfigAtRoot,Hn as readRawScopeConfig,ko as readRawSettingsForTarget,jn as readState,Ao as replaceRawSettingsForTarget,To as resolveKindConfig,Io as resolvePageComponents,bo as statePath,$o as subKindsAvailableTo,Lo as updateConfig,Vn as updateConfigAtRoot,So as updateRawConfigAtomically,zo as updateState,jo as writeConfig,xo as writeRawConfig,En as writeState};
@@ -1 +1 @@
1
- var c=Object.defineProperty;var i=(e,n)=>c(e,"name",{value:n,configurable:!0});import{parentPort as g,workerData as y}from"node:worker_threads";import{request as m}from"node:http";import{request as b}from"node:https";g?.on("message",e=>{const{address:n,token:d}=y,s=n.startsWith("http")?new URL(e.path,n):null,p=e.data===void 0?void 0:JSON.stringify(e.data),f=i(t=>{const u=[];t.on("data",a=>u.push(a)),t.on("aborted",()=>r({error:"conversation store response ended before completion"})),t.on("error",a=>r({error:a.message})),t.on("end",()=>r({status:t.statusCode,body:Buffer.concat(u).toString("utf8"),path:t.headers["x-conversation-path"],tail:t.headers["x-conversation-tail"]}))},"onResponse"),o=s?(s.protocol==="https:"?b:m)(s,{method:e.method},f):m({socketPath:n,path:e.path,method:e.method},f);let h=!1;function r(t){h||(h=!0,e.reply.postMessage(t),e.signal&&(Atomics.store(new Int32Array(e.signal),0,1),Atomics.notify(new Int32Array(e.signal),0)),e.reply.close())}i(r,"finish"),e.reply.on("message",t=>{t==="cancel"&&o.destroy()}),o.once("error",t=>r({error:t.message})),d&&o.setHeader("authorization",`Bearer ${d}`),p!==void 0?(o.setHeader("content-type","application/json"),o.end(p)):o.end()});
1
+ var E=Object.defineProperty;var s=(e,t)=>E(e,"name",{value:t,configurable:!0});import{parentPort as M,workerData as N}from"node:worker_threads";import{request as v}from"node:http";import{request as $}from"node:https";const{address:l,token:b}=N,r=[],m=new Set;let w=!1,d=0,c=500,y;const I=Number(process.env.CRTR_CONVERSATION_COMMIT_DEADLINE_MS??15*6e4),k=process.env.CRTR_NODE_DEADLINE_AT?Date.parse(process.env.CRTR_NODE_DEADLINE_AT):1/0,O=s(()=>Math.max(1e3,Math.min(6e4,k-Date.now())),"requestTimeoutMs");function P(e){return new Promise(t=>setTimeout(t,e))}s(P,"wait");function _(e){return new Promise(t=>{const i=`/v1${e.path}`,n=l.startsWith("http")?new URL(l.replace(/\/$/,"")+i):null,u=e.data===void 0?void 0:JSON.stringify(e.data);let g=!1;const f=s(o=>{g||(g=!0,t(o))},"finish"),T=s(o=>{const D=[];o.on("data",h=>D.push(h)),o.on("aborted",()=>f({error:"conversation store response ended before completion"})),o.on("error",h=>f({error:h.message})),o.on("end",()=>f({status:o.statusCode,body:Buffer.concat(D).toString("utf8"),path:o.headers["x-conversation-path"],tail:o.headers["x-conversation-tail"]}))},"onResponse"),a=n?(n.protocol==="https:"?$:v)(n,{method:e.method},T):v({socketPath:l,path:i,method:e.method},T);a.on("error",o=>f({error:o.message})),a.setTimeout(O(),()=>{f({error:"conversation store request timed out"}),a.destroy()}),e.reply?.on("message",o=>{o==="cancel"&&a.destroy()}),b&&a.setHeader("authorization",`Bearer ${b}`),u!==void 0?(a.setHeader("content-type","application/json"),a.end(u)):a.end()})}s(_,"send");function p(e,t){e.reply?.postMessage(t),e.signal&&(Atomics.store(new Int32Array(e.signal),0,1),Atomics.notify(new Int32Array(e.signal),0)),e.reply?.close()}s(p,"answer");function q(e){y=e;for(const t of r.splice(0))t.kind!=="append"&&p(t,{error:`conversation_write_failed: ${e}`});d=0,c=500}s(q,"giveUp");const A=s(e=>!!e.error||!e.status||e.status>=400,"failed");async function R(e){if(d||(d=Date.now()),Date.now()-d>=I||Date.now()>=k){q(e);return}await P(c),c=Math.min(c*2,3e4)}s(R,"backoff");async function S(){if(!w){w=!0;try{for(;r.length;){const e=r[0];if(e.kind==="append"){const t=[];for(;r[t.length]?.kind==="append"&&r[t.length]?.path===e.path;)t.push(r[t.length]);const i=t.flatMap(u=>u.data.entries),n=await _({method:"POST",path:e.path,data:{entries:i}});if(A(n)){await R(n.error??n.body??`HTTP ${n.status}`);continue}d=0,c=500,m.add(e.path.replace(/\/entries$/,"")),r.splice(0,t.length);continue}if(e.kind==="flush"){if(y){p(e,{error:`conversation_write_failed: ${y}`}),r.shift();continue}let t;for(const i of m){const n=await _({method:"POST",path:`${i}/commit`});if(A(n)){t=n.error??n.body??`HTTP ${n.status}`;break}m.delete(i)}if(t){await R(t);continue}d=0,c=500,p(e,{status:200}),r.shift();continue}p(e,await _(e)),r.shift()}}finally{w=!1}}}s(S,"drain"),M?.on("message",e=>{r.push(e),S()});
@@ -1,2 +1,2 @@
1
- var k=Object.defineProperty;var s=(l,w)=>k(l,"name",{value:w,configurable:!0});import{MessageChannel as p,Worker as S,receiveMessageOnPort as b}from"node:worker_threads";import{ConversationNotFoundError as g}from"./index.js";function N(l,w){const u=new S(new URL(import.meta.url.endsWith(".ts")?"./client-worker.ts":"./client-worker.js",import.meta.url),{workerData:{address:l,token:w}});u.unref();let c;u.on("error",e=>{c=e}),u.on("exit",e=>{c=new Error(`conversation store worker exited with ${e}`)});function m(e,r,t){if(!t)throw new Error("conversation store worker returned no reply");if(t.error)throw new Error(t.error);if(t.status===404)throw new g(r.split("/")[2]??r);if(!t.status||t.status>=400)throw new Error(`conversation store ${e} ${r} failed (${t.status}): ${t.body}`);return{body:t.body??"",...t.path?{path:t.path}:{},...t.tail?{tail:Number(t.tail)}:{}}}s(m,"settle");function n(e,r,t){if(c)throw c;const o=new SharedArrayBuffer(4),{port1:i,port2:d}=new p;try{if(u.postMessage({method:e,path:r,data:t,signal:o,reply:d},[d]),Atomics.wait(new Int32Array(o),0,0,3e4)==="timed-out")throw i.postMessage("cancel"),new Error(`conversation store request timed out: ${e} ${r}`);return m(e,r,b(i)?.message)}finally{i.close()}}s(n,"call");function E(e,r){if(c)return Promise.reject(c);const{port1:t,port2:o}=new p;return new Promise((i,d)=>{const f=setTimeout(()=>{t.postMessage("cancel"),t.close(),d(new Error(`conversation store request timed out: ${e} ${r}`))},3e4);f.unref(),t.once("message",v=>{clearTimeout(f),t.close();try{i(m(e,r,v))}catch(T){d(T)}}),u.postMessage({method:e,path:r,reply:o},[o])})}s(E,"callAsync");const a=s(e=>`/conversations/${encodeURIComponent(e)}`,"url"),$=s(e=>{const[r,...t]=e.body.trimEnd().split(`
2
- `).map(i=>JSON.parse(i)),o=t;return e.tail===void 0?{header:r,entries:o,path:e.path??""}:{header:r,entries:o.slice(0,e.tail-1),tail:o.slice(e.tail-1),path:e.path??""}},"parseRead"),h=s((e,r)=>r?`${a(e)}?head=${r.head}&tail=${r.tail}`:a(e),"readPath");return{create(e,r,t,o){return JSON.parse(n("POST","/conversations",{node_id:e,header:r,entries:t,path:o}).body).conversation_id},append(e,r,t){n("POST",`${a(e)}/entries`,{entries:r,...t?.dedupe?{dedupe:!0}:{}})},replace(e,r,t){n("PUT",a(e),{header:r,entries:t})},read(e,r){return $(n("GET",h(e,r)))},async readAsync(e,r){return $(await E("GET",h(e,r)))},header(e){return JSON.parse(n("GET",`${a(e)}/header`).body)},fork(e,r,t,o){return JSON.parse(n("POST",`${a(e)}/fork`,{node_id:r,leaf_id:t,cwd:o}).body).conversation_id},list(e){const r=e===void 0?"":`?node_id=${encodeURIComponent(e)}`;return JSON.parse(n("GET",`/conversations${r}`).body).conversations},delete(e){n("DELETE",a(e))}}}s(N,"createStoreClient");export{N as createStoreClient};
1
+ var P=Object.defineProperty;var s=(l,f)=>P(l,"name",{value:f,configurable:!0});import{MessageChannel as p,Worker as S,receiveMessageOnPort as O}from"node:worker_threads";import{ConversationNotFoundError as b}from"./index.js";function A(l,f){const i=new S(new URL(import.meta.url.endsWith(".ts")?"./client-worker.ts":"./client-worker.js",import.meta.url),{workerData:{address:l,token:f}});i.unref();let n;i.on("error",e=>{n=e}),i.on("exit",e=>{n=new Error(`conversation store worker exited with ${e}`)});function m(e,r,t){if(!t)throw new Error("conversation store worker returned no reply");if(t.error)throw new Error(t.error);if(t.status===404)throw new b(r.split("/")[2]??r);if(!t.status||t.status>=400)throw new Error(`conversation store ${e} ${r} failed (${t.status}): ${t.body}`);return{body:t.body??"",...t.path?{path:t.path}:{},...t.tail?{tail:Number(t.tail)}:{}}}s(m,"settle");function c(e,r,t){if(n)throw n;const o=new SharedArrayBuffer(4),{port1:a,port2:d}=new p;try{if(i.postMessage({method:e,path:r,data:t,signal:o,reply:d},[d]),Atomics.wait(new Int32Array(o),0,0,3e4)==="timed-out")throw a.postMessage("cancel"),new Error(`conversation store request timed out: ${e} ${r}`);return m(e,r,O(a)?.message)}finally{a.close()}}s(c,"call");function E(e,r){if(n)return Promise.reject(n);const{port1:t,port2:o}=new p;return new Promise((a,d)=>{const w=setTimeout(()=>{t.postMessage("cancel"),t.close(),d(new Error(`conversation store request timed out: ${e} ${r}`))},3e4);w.unref(),t.once("message",g=>{clearTimeout(w),t.close();try{a(m(e,r,g))}catch(k){d(k)}}),i.postMessage({method:e,path:r,reply:o},[o])})}s(E,"callAsync");const u=s(e=>`/conversations/${encodeURIComponent(e)}`,"url");function v(e,r){if(n)throw n;i.postMessage({kind:"append",method:"POST",path:`${u(e)}/entries`,data:{entries:r}})}s(v,"enqueueAppend");function T(){if(n)return Promise.reject(n);const{port1:e,port2:r}=new p;return new Promise((t,o)=>{e.once("message",a=>{e.close();try{m("POST","/commit",a),t()}catch(d){o(d)}}),i.postMessage({kind:"flush",method:"POST",path:"/commit",reply:r},[r])})}s(T,"flush");const h=s(e=>{const[r,...t]=e.body.trimEnd().split(`
2
+ `).map(a=>JSON.parse(a)),o=t;return e.tail===void 0?{header:r,entries:o,path:e.path??""}:{header:r,entries:o.slice(0,e.tail-1),tail:o.slice(e.tail-1),path:e.path??""}},"parseRead"),$=s((e,r)=>r?`${u(e)}?head=${r.head}&tail=${r.tail}`:u(e),"readPath");return{create(e,r,t,o){return JSON.parse(c("POST","/conversations",{node_id:e,header:r,entries:t,path:o}).body).conversation_id},append(e,r){v(e,r)},flush:T,replace(e,r,t){c("PUT",u(e),{header:r,entries:t})},read(e,r){return h(c("GET",$(e,r)))},async readAsync(e,r){return h(await E("GET",$(e,r)))},header(e){return JSON.parse(c("GET",`${u(e)}/header`).body)},fork(e,r,t,o){return JSON.parse(c("POST",`${u(e)}/fork`,{node_id:r,leaf_id:t,cwd:o}).body).conversation_id},list(e){const r=e===void 0?"":`?node_id=${encodeURIComponent(e)}`;return JSON.parse(c("GET",`/conversations${r}`).body).conversations},delete(e){c("DELETE",u(e))}}}s(A,"createStoreClient");export{A as createStoreClient};
@@ -23,12 +23,10 @@ export interface ConversationWindow {
23
23
  * `ConversationStore` so a change to the daemon's store never changes pi's contract. */
24
24
  export interface ConversationStoreClient {
25
25
  create(nodeId: string, header: SessionHeader, entries: SessionEntry[], path?: string): string;
26
- /** `dedupe` makes the append idempotent by entry id: an entry already in the file is skipped.
27
- * A caller sets it when an earlier attempt failed ambiguously (the connection ended before a
28
- * response), because the store may have written the entries anyway. */
29
- append(id: string, entries: SessionEntry[], options?: {
30
- dedupe?: boolean;
31
- }): void;
26
+ /** Enqueue entries in order without blocking the broker's event loop. */
27
+ append(id: string, entries: SessionEntry[]): void;
28
+ /** Wait for pending appends and seal each dirty conversation. */
29
+ flush(): Promise<void>;
32
30
  replace(id: string, header: SessionHeader, entries: SessionEntry[]): void;
33
31
  /** Given a window and a file larger than head + tail bytes, `entries` holds the entries wholly
34
32
  * inside the first `head` bytes and `tail` those wholly inside the last `tail` bytes.
@@ -55,9 +53,7 @@ export interface ConversationStoreClient {
55
53
  /** The daemon's file store (`createFileStore`, installed by `sessions.ts`). */
56
54
  export interface ConversationStore {
57
55
  create(nodeId: string, header: SessionHeader, entries: SessionEntry[], path?: string): Promise<string>;
58
- append(id: string, entries: SessionEntry[], options?: {
59
- dedupe?: boolean;
60
- }): Promise<void>;
56
+ append(id: string, entries: SessionEntry[]): Promise<void>;
61
57
  replace(id: string, header: SessionHeader, entries: SessionEntry[]): Promise<void>;
62
58
  read(id: string, window?: ConversationWindow): Promise<{
63
59
  header: SessionHeader;
@@ -84,15 +80,17 @@ export interface ConversationStore {
84
80
  }
85
81
  export declare function conversationIdFromPath(path: string): string | null;
86
82
  export declare function defaultConversationRoot(): string;
87
- export declare function storeAddress(): string;
83
+ /** Where the client reaches the daemon's /v1 API: `CRTR_API_URL` (an http(s) URL) or the API socket path. */
84
+ export declare function conversationApiAddress(): string;
88
85
  export declare function installConversationStore(store: ConversationStore | undefined): void;
89
86
  /** The installed store, else the client over the store socket with each call awaited. */
90
87
  export declare function conversationStore(): ConversationStore;
91
88
  /** The synchronous store pi's `SessionManager` statics call: always the client over the store socket (the installed
92
89
  * store is async, so it cannot serve a synchronous caller). */
93
90
  export declare function conversationClient(): ConversationStoreClient;
91
+ /** The broker settles mail only after its queued entries and part object are durable. */
92
+ export declare function flushConversation(): Promise<void>;
94
93
  /** Read a conversation without parking the event loop on the store worker. */
95
94
  export declare function readConversationAsync(id: string, window?: ConversationWindow): Promise<Awaited<ReturnType<ConversationStore['read']>>>;
96
- export { createFileStore, sessionDirectory, type AppendSection, type ConversationCanvas, type ConversationWrite } from './file-store.js';
97
95
  export { installSessionManagerStorePatch } from './patch.js';
98
96
  export { findOrphanedParents, relinkOrphanedParents, repairConversationFile, type FileRepair, type OrphanRelink } from './repair.js';
@@ -1 +1 @@
1
- var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});import{appsRoot as i,socketDir as p}from"../layout.js";import{join as d}from"node:path";import{createStoreClient as f}from"./client.js";import{currentNodeToken as u}from"../runtime/broker/node-token.js";class l extends Error{static{o(this,"ConversationNotFoundError")}code="not_found";constructor(r){super(`conversation not found: ${r}`)}}function h(e){return e instanceof l}o(h,"isConversationNotFound");function k(e){return/(?:^|\/)[^/]+_([0-9a-f-]{36})\.jsonl$/i.exec(e)?.[1]??null}o(k,"conversationIdFromPath");function R(){return i()}o(R,"defaultConversationRoot");function m(){return process.env.CRTR_STORE_ADDRESS||d(p(),"store.sock")}o(m,"storeAddress");let t,s;function A(e){t=e}o(A,"installConversationStore");function F(){if(t)return t;const e=a();return{create:o(async(...r)=>e.create(...r),"create"),append:o(async(...r)=>e.append(...r),"append"),replace:o(async(...r)=>e.replace(...r),"replace"),read:o(async(...r)=>e.read(...r),"read"),header:o(async(...r)=>e.header(...r),"header"),fork:o(async(...r)=>e.fork(...r),"fork"),list:o(async(...r)=>e.list(...r),"list"),delete:o(async r=>e.delete(r),"delete")}}o(F,"conversationStore");function a(){const e=m();return s?.address!==e&&(s={address:e,store:f(e,u())}),s.store}o(a,"conversationClient");async function D(e,r){if(t)return t.read(e,r);const n=a();return n.readAsync?n.readAsync(e,r):n.read(e,r)}o(D,"readConversationAsync");import{createFileStore as _,sessionDirectory as N}from"./file-store.js";import{installSessionManagerStorePatch as T}from"./patch.js";import{findOrphanedParents as $,relinkOrphanedParents as g,repairConversationFile as I}from"./repair.js";export{l as ConversationNotFoundError,a as conversationClient,k as conversationIdFromPath,F as conversationStore,_ as createFileStore,R as defaultConversationRoot,$ as findOrphanedParents,A as installConversationStore,T as installSessionManagerStorePatch,h as isConversationNotFound,D as readConversationAsync,g as relinkOrphanedParents,I as repairConversationFile,N as sessionDirectory,m as storeAddress};
1
+ var c=Object.defineProperty;var n=(e,r)=>c(e,"name",{value:r,configurable:!0});import{appsRoot as i}from"../layout.js";import{apiSocketPath as p}from"../canvas/paths.js";import{createStoreClient as u}from"./client.js";import{currentNodeToken as f}from"../runtime/broker/node-token.js";class d extends Error{static{n(this,"ConversationNotFoundError")}code="not_found";constructor(r){super(`conversation not found: ${r}`)}}function C(e){return e instanceof d}n(C,"isConversationNotFound");function A(e){return/(?:^|\/)[^/]+_([0-9a-f-]{36})\.jsonl$/i.exec(e)?.[1]??null}n(A,"conversationIdFromPath");function P(){return i()}n(P,"defaultConversationRoot");function l(){return process.env.CRTR_API_URL||p()}n(l,"conversationApiAddress");let t,a;function S(e){t=e}n(S,"installConversationStore");function k(){if(t)return t;const e=s();return{create:n(async(...r)=>e.create(...r),"create"),append:n(async(r,o)=>e.append(r,o),"append"),replace:n(async(...r)=>e.replace(...r),"replace"),read:n(async(...r)=>e.read(...r),"read"),header:n(async(...r)=>e.header(...r),"header"),fork:n(async(...r)=>e.fork(...r),"fork"),list:n(async(...r)=>e.list(...r),"list"),delete:n(async r=>e.delete(r),"delete")}}n(k,"conversationStore");function s(){const e=l();return a?.address!==e&&(a={address:e,store:u(e,f())}),a.store}n(s,"conversationClient");async function R(){t||await s().flush()}n(R,"flushConversation");async function F(e,r){if(t)return t.read(e,r);const o=s();return o.readAsync?o.readAsync(e,r):o.read(e,r)}n(F,"readConversationAsync");import{installSessionManagerStorePatch as E}from"./patch.js";import{findOrphanedParents as O,relinkOrphanedParents as T,repairConversationFile as $}from"./repair.js";export{d as ConversationNotFoundError,l as conversationApiAddress,s as conversationClient,A as conversationIdFromPath,k as conversationStore,P as defaultConversationRoot,O as findOrphanedParents,R as flushConversation,S as installConversationStore,E as installSessionManagerStorePatch,C as isConversationNotFound,F as readConversationAsync,T as relinkOrphanedParents,$ as repairConversationFile};
@@ -1 +1 @@
1
- var P=Object.defineProperty;var c=(a,r)=>P(a,"name",{value:r,configurable:!0});import{dirname as E,resolve as A}from"node:path";import{SessionManager as w}from"@earendil-works/pi-coding-agent";import{conversationClient as R,conversationIdFromPath as O}from"./index.js";import{findOrphanedParents as T}from"./repair.js";import{emitEvent as I}from"../events/emit.js";const f=new WeakMap;function k(a){a>0&&Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,a)}c(k,"sleep");function C(){const a=Number(process.env.CRTR_CONVERSATION_APPEND_RETRY_MS);return Number.isFinite(a)&&a>=0?a:500}c(C,"retryDelayMs");let x=!1;function z(a,r=R()){if(x)return;const l=w.prototype,h=w;for(const e of["_setSessionFile","_rewriteFile","_persist","createBranchedSession","newSession"])if(typeof l[e]!="function")throw new Error(`pi SessionManager.${e} changed; store patch cannot start`);for(const e of["create","open","continueRecent","forkFrom","findById","list","listAll"])if(typeof h[e]!="function")throw new Error(`pi SessionManager.${e} changed; store patch cannot start`);const M=l.createBranchedSession,y=l.newSession;function N(e,s){const t=T(s);t.length!==0&&I({level:"error",event:"conversation.orphaned_parent",fields:{conversation_id:e,orphan_count:t.length,orphans:t.slice(0,20).map(i=>({entry_id:i.entryId,missing_parent_id:i.missingParentId}))}})}c(N,"reportOrphans");function _(e,s){const{header:t,entries:i,path:o}=r.read(e);N(t.id,i);const n=w.inMemory(s??t.cwd);n.sessionFile=o,n.sessionDir=E(o),n._loadEntries([t,...i]),n.persist=!0,n.flushed=!0;const u=n.fileEntries[0];return u?.type==="session"&&u.version!==t.version&&n._rewriteFile(),n}c(_,"fromStore");function m(e){const[s,...t]=e.fileEntries;if(!s||s.type!=="session")throw new Error("conversation has no session header");r.create(a,s,t),e.sessionFile=r.header(s.id).path,e.sessionDir=E(e.sessionFile),e.flushed=!0,f.delete(e)}c(m,"persistNew");function B(e,s){const t=f.get(e)??{entries:[],ambiguous:!1};t.entries.push(s),f.set(e,t);let i;for(let o=0;o<2;o++){o>0&&k(C());try{r.append(e.sessionId,t.entries,t.ambiguous?{dedupe:!0}:void 0),f.delete(e);return}catch(n){i=n,t.ambiguous=!0}}throw I({level:"error",event:"conversation.append_failed",error:i,fields:{conversation_id:e.sessionId,pending_entries:t.entries.length}}),i}c(B,"appendInOrder");function g(e){const s=O(e);if(!s)throw new Error(`invalid conversation path: ${e}`);return s}c(g,"idOf"),l._setSessionFile=function(e){const{header:s,entries:t}=r.read(g(e));this.sessionFile=r.header(s.id).path,this.sessionDir=E(this.sessionFile),N(s.id,t),this._loadEntries([s,...t]),this.flushed=!0,f.delete(this)},l._rewriteFile=function(){if(!this.persist||!this.sessionFile)return;const[e,...s]=this.fileEntries;if(!e||e.type!=="session")throw new Error("conversation has no session header");r.replace(e.id,e,s),f.delete(this)},l._persist=function(e){!this.persist||!this.sessionFile||(this.flushed?B(this,e):m(this))},l.newSession=function(e){if(!this.persist)return y.call(this,e);const s=this.flushed&&this.fileEntries.length===1&&this.sessionFile!==void 0?this.sessionId:void 0;if(s!==void 0&&(e?.id===void 0||e.id===s)){const t=this.sessionFile;y.call(this,{...e,id:s});const i=this.fileEntries[0];if(!i||i.type!=="session")throw new Error("conversation has no session header");return r.replace(s,i,[]),this.sessionFile=t,this.flushed=!0,t}return y.call(this,e),m(this),this.sessionFile},l.createBranchedSession=function(e){if(!this.persist)return M.call(this,e);const s=this.sessionFile;this.persist=!1;try{M.call(this,e)}finally{this.persist=!0}const t=this.fileEntries[0];if(!t||t.type!=="session")throw new Error("branch has no header");return this.fileEntries[0]={...t,parentSession:s},m(this),this.sessionFile},h.create=(e,s,t)=>{const i=w.inMemory(e,t);return i.persist=!0,m(i),i},h.open=(e,s,t)=>_(g(e),t),h.continueRecent=e=>{const s=r.list().find(t=>t.header.cwd===A(e));return s?_(s.conversation_id,e):h.create(e)},h.forkFrom=(e,s)=>_(r.fork(g(e),a,void 0,s)),h.findById=(e,s)=>r.list().find(t=>t.conversation_id===s&&t.header.cwd===A(e))?.path;function b(e){return r.list().filter(s=>e===void 0||s.header.cwd===A(e)).map(s=>{let t,i=0,o="",n;const u=[];for(const p of r.read(s.conversation_id).entries){if(p.type==="session_info"&&(t=p.name?.trim()||void 0),p.type!=="message")continue;i++;const d=p.message;if(d.role!=="user"&&d.role!=="assistant")continue;const D=typeof d.timestamp=="number"?d.timestamp:Date.parse(p.timestamp);Number.isNaN(D)||(n=Math.max(n??0,D));const F=typeof d.content=="string"?d.content:Array.isArray(d.content)?d.content.filter(S=>S.type==="text").map(S=>S.text??"").join(" "):"";F&&(u.push(F),!o&&d.role==="user"&&(o=F))}const v=new Date(s.header.timestamp);return{path:s.path,id:s.conversation_id,cwd:s.header.cwd,...t?{name:t}:{},...s.header.parentSession?{parentSessionPath:s.header.parentSession}:{},created:v,modified:n&&n>0?new Date(n):Number.isNaN(v.getTime())?new Date(s.mtime):v,messageCount:i,firstMessage:o||"(no messages)",allMessagesText:u.join(" ")}})}c(b,"sessionInfos"),h.list=async(e,s,t,i)=>{i?.throwIfAborted();const o=b(e);return t?.(o.length,o.length,o),o},h.listAll=async(...e)=>(e.find(t=>t instanceof AbortSignal)?.throwIfAborted(),b()),x=!0}c(z,"installSessionManagerStorePatch");export{z as installSessionManagerStorePatch};
1
+ var x=Object.defineProperty;var d=(p,n)=>x(p,"name",{value:n,configurable:!0});import{dirname as S,resolve as E}from"node:path";import{SessionManager as m}from"@earendil-works/pi-coding-agent";import{conversationClient as B,conversationIdFromPath as P}from"./index.js";import{findOrphanedParents as O}from"./repair.js";import{emitEvent as k}from"../events/emit.js";let N=!1;function z(p,n=B()){if(N)return;const c=m.prototype,a=m;for(const e of["_setSessionFile","_rewriteFile","_persist","createBranchedSession","newSession"])if(typeof c[e]!="function")throw new Error(`pi SessionManager.${e} changed; store patch cannot start`);for(const e of["create","open","continueRecent","forkFrom","findById","list","listAll"])if(typeof a[e]!="function")throw new Error(`pi SessionManager.${e} changed; store patch cannot start`);const D=c.createBranchedSession,w=c.newSession;function M(e,s){const t=O(s);t.length!==0&&k({level:"error",event:"conversation.orphaned_parent",fields:{conversation_id:e,orphan_count:t.length,orphans:t.slice(0,20).map(i=>({entry_id:i.entryId,missing_parent_id:i.missingParentId}))}})}d(M,"reportOrphans");function y(e,s){const{header:t,entries:i,path:o}=n.read(e);M(t.id,i);const r=m.inMemory(s??t.cwd);r.sessionFile=o,r.sessionDir=S(o),r._loadEntries([t,...i]),r.persist=!0,r.flushed=!0;const l=r.fileEntries[0];return l?.type==="session"&&l.version!==t.version&&r._rewriteFile(),r}d(y,"fromStore");function u(e){const[s,...t]=e.fileEntries;if(!s||s.type!=="session")throw new Error("conversation has no session header");n.create(p,s,t),e.sessionFile=n.header(s.id).path,e.sessionDir=S(e.sessionFile),e.flushed=!0}d(u,"persistNew");function b(e,s){n.append(e.sessionId,[s])}d(b,"appendInOrder");function g(e){const s=P(e);if(!s)throw new Error(`invalid conversation path: ${e}`);return s}d(g,"idOf"),c._setSessionFile=function(e){const{header:s,entries:t}=n.read(g(e));this.sessionFile=n.header(s.id).path,this.sessionDir=S(this.sessionFile),M(s.id,t),this._loadEntries([s,...t]),this.flushed=!0},c._rewriteFile=function(){if(!this.persist||!this.sessionFile)return;const[e,...s]=this.fileEntries;if(!e||e.type!=="session")throw new Error("conversation has no session header");n.replace(e.id,e,s)},c._persist=function(e){!this.persist||!this.sessionFile||(this.flushed?b(this,e):u(this))},c.newSession=function(e){if(!this.persist)return w.call(this,e);const s=this.flushed&&this.fileEntries.length===1&&this.sessionFile!==void 0?this.sessionId:void 0;if(s!==void 0&&(e?.id===void 0||e.id===s)){const t=this.sessionFile;w.call(this,{...e,id:s});const i=this.fileEntries[0];if(!i||i.type!=="session")throw new Error("conversation has no session header");return n.replace(s,i,[]),this.sessionFile=t,this.flushed=!0,t}return w.call(this,e),u(this),this.sessionFile},c.createBranchedSession=function(e){if(!this.persist)return D.call(this,e);const s=this.sessionFile;this.persist=!1;try{D.call(this,e)}finally{this.persist=!0}const t=this.fileEntries[0];if(!t||t.type!=="session")throw new Error("branch has no header");return this.fileEntries[0]={...t,parentSession:s},u(this),this.sessionFile},a.create=(e,s,t)=>{const i=m.inMemory(e,t);return i.persist=!0,u(i),i},a.open=(e,s,t)=>y(g(e),t),a.continueRecent=e=>{const s=n.list().find(t=>t.header.cwd===E(e));return s?y(s.conversation_id,e):a.create(e)},a.forkFrom=(e,s)=>y(n.fork(g(e),p,void 0,s)),a.findById=(e,s)=>n.list().find(t=>t.conversation_id===s&&t.header.cwd===E(e))?.path;function I(e){return n.list().filter(s=>e===void 0||s.header.cwd===E(e)).map(s=>{let t,i=0,o="",r;const l=[];for(const f of n.read(s.conversation_id).entries){if(f.type==="session_info"&&(t=f.name?.trim()||void 0),f.type!=="message")continue;i++;const h=f.message;if(h.role!=="user"&&h.role!=="assistant")continue;const A=typeof h.timestamp=="number"?h.timestamp:Date.parse(f.timestamp);Number.isNaN(A)||(r=Math.max(r??0,A));const F=typeof h.content=="string"?h.content:Array.isArray(h.content)?h.content.filter(v=>v.type==="text").map(v=>v.text??"").join(" "):"";F&&(l.push(F),!o&&h.role==="user"&&(o=F))}const _=new Date(s.header.timestamp);return{path:s.path,id:s.conversation_id,cwd:s.header.cwd,...t?{name:t}:{},...s.header.parentSession?{parentSessionPath:s.header.parentSession}:{},created:_,modified:r&&r>0?new Date(r):Number.isNaN(_.getTime())?new Date(s.mtime):_,messageCount:i,firstMessage:o||"(no messages)",allMessagesText:l.join(" ")}})}d(I,"sessionInfos"),a.list=async(e,s,t,i)=>{i?.throwIfAborted();const o=I(e);return t?.(o.length,o.length,o),o},a.listAll=async(...e)=>(e.find(t=>t instanceof AbortSignal)?.throwIfAborted(),I()),N=!0}d(z,"installSessionManagerStorePatch");export{z as installSessionManagerStorePatch};
@@ -0,0 +1,14 @@
1
+ import { type ConversationStore } from './index.js';
2
+ /** Durable tail rows, with immutable JSONL parts. All broker-visible writes pass through this store. */
3
+ export declare function createRowStore(): ConversationStore & {
4
+ commit(id: string): Promise<number>;
5
+ importLegacy(runId?: string): Promise<void>;
6
+ recover(rows: Array<{
7
+ session_id: string;
8
+ node_id: string;
9
+ transcript_path: string | null;
10
+ }>): void;
11
+ };
12
+ /** Rewrite part 0's header `cwd` under the conversation's row lock, leaving later parts and tail rows untouched.
13
+ * Returns false when the header's cwd is not `oldCwd`. */
14
+ export declare function relocateConversationHeader(id: string, oldCwd: string, newCwd: string): Promise<boolean>;
@@ -0,0 +1,13 @@
1
+ var H=Object.defineProperty;var f=(o,t)=>H(o,"name",{value:t,configurable:!0});import{randomUUID as g}from"node:crypto";import{existsSync as W,readFileSync as q,rmSync as A}from"node:fs";import{join as B}from"node:path";import{SessionManager as j}from"@earendil-works/pi-coding-agent";import{blobStore as l}from"../blobs/index.js";import{openDb as w,withCanvasWrite as y}from"../canvas/db.js";import{appSpace as J}from"../layout.js";import{appendConversationEvents as T,rootRepromptPending as L}from"../../daemon/runs/append-section.js";import{ConversationNotFoundError as R}from"./index.js";const O="s.unbound_at IS NULL DESC, s.created_at DESC, s.seq DESC",D=f((o,t,n)=>`conversations/${o}/${t}/${n}.jsonl`,"keyFor"),k=f(o=>o.map(t=>JSON.stringify(t)+`
2
+ `).join(""),"encode"),$=f(o=>o.split(`
3
+ `).filter(Boolean).map(t=>JSON.parse(t)),"decode"),h=f(()=>new Date().toISOString(),"at");async function N(o,t,n=!1){const i=await o.prepare(`SELECT s.binding_id, s.node_id, s.transcript_path, s.input_ids_json, s.source_session_id, n.run_id FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY ${O} LIMIT 1${n?" FOR UPDATE OF s":""}`).get(t);if(!i)throw new R(t);return i}f(N,"binding");async function b(o,t){return await o.prepare("SELECT seq, blob_key, bytes, entries, created FROM conversation_parts WHERE conversation_id = ? ORDER BY seq").all(t)}f(b,"parts");async function Y(o,t){return await o.prepare("SELECT seq, body, bytes, created FROM conversation_entries WHERE conversation_id = ? ORDER BY seq").all(t)}f(Y,"tail");async function I(o,t){const n=await o.prepare(`SELECT 'part' AS kind, seq, blob_key, NULL AS body, bytes, entries, created FROM conversation_parts WHERE conversation_id = ?
4
+ UNION ALL SELECT 'tail', seq, NULL, body, bytes, NULL, created FROM conversation_entries WHERE conversation_id = ? ORDER BY 1, 2`).all(t,t);return{parts:n.filter(i=>i.kind==="part").map(({seq:i,blob_key:s,bytes:a,entries:e,created:r})=>({seq:Number(i),blob_key:s,bytes:Number(a),entries:Number(e),created:r})),tail:n.filter(i=>i.kind==="tail").map(({seq:i,body:s,bytes:a,created:e})=>({seq:Number(i),body:s,bytes:Number(a),created:e}))}}f(I,"snapshot");const C=1024*1024;async function m(o,t,n){const i=[];let s=0;const a=await l();for(const e of o.parts){const r=Math.max(t,s),c=Math.min(n,s+e.bytes);if(r<c){const d=await a.get(e.blob_key,{start:r-s,length:c-r});if(!d)throw new Error(`missing conversation object: ${e.blob_key}`);i.push(d)}s+=e.bytes}for(const e of o.tail){const r=Math.max(t,s),c=Math.min(n,s+e.bytes);r<c&&i.push(Buffer.from(e.body+`
5
+ `).subarray(r-s,c-s)),s+=e.bytes}return Buffer.concat(i)}f(m,"bytesOf");const M=new Map;async function U(o,t,n){const i=await w();if(await i.prepare("SELECT 1 FROM conversation_parts WHERE conversation_id = ? AND seq = 0").get(o)||!W(n))return;let s=q(n);const a=s.lastIndexOf(10);if(a<0)return;s=s.subarray(0,a+1);const e=await i.prepare("SELECT s.binding_id, s.node_id, s.event_offset, s.input_ids_json, s.source_session_id, n.run_id FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY "+O+" LIMIT 1").get(o);let r=[];if(e?.run_id&&e.event_offset!==null){const p=Number(e.event_offset);if(s.length<p)throw new Error(`conversation shorter than indexed offset: ${o}`);r=$(s.subarray(p).toString("utf8")).filter(u=>u.type!=="session")}const c=e?.run_id?await L(e.run_id,e.node_id,r):!1,d=D(t,o,0);await(await l()).put(d,s),await y(async p=>{if(!await p.prepare("INSERT INTO conversation_parts (conversation_id, seq, blob_key, bytes, entries, created) VALUES (?, 0, ?, ?, ?, ?) ON CONFLICT DO NOTHING RETURNING seq").get(o,d,s.length,Math.max(0,s.toString("utf8").split(`
6
+ `).filter(Boolean).length-1),h())||!e?.run_id||e.event_offset===null)return;const _=e.source_session_id?[]:await T(p,e.run_id,e.node_id,r,JSON.parse(e.input_ids_json),c);await p.prepare("UPDATE sessions SET event_offset = ?, indexed_entry_id = ?, input_ids_json = ? WHERE binding_id = ?").run(s.length,r.at(-1)?.id??null,JSON.stringify(_),e.binding_id)})}f(U,"importOne");async function S(o,t){const n=await t.prepare(`SELECT s.binding_id, s.node_id, s.transcript_path, s.input_ids_json, s.source_session_id, n.run_id FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY ${O} LIMIT 1`).get(o),i=M.get(o);if(!n&&!i)throw new R(o);let s=(await b(t,o))[0];if(!s){const c=i?.path??n?.transcript_path??void 0;c&&await U(o,i?.node??n.node_id,c),s=(await b(t,o))[0]}if(!s||s.seq!==0)throw new R(o);const a=await(await l()).get(s.blob_key,{start:0,length:Math.min(s.bytes,256*1024)});if(!a)throw new Error(`missing conversation object: ${s.blob_key}`);const e=a.indexOf(10);if(e<0)throw new Error(`invalid conversation header: ${o}`);const r=JSON.parse(a.subarray(0,e).toString("utf8"));if(r.type!=="session"||r.id!==o)throw new Error(`invalid conversation header: ${o}`);return{header:r,path:n?.transcript_path??i?.path??"",binding:n}}f(S,"initial");function et(){const o={async create(t,n,i,s){const e=await(await w()).prepare("SELECT grantee, run_id FROM node_rows WHERE node_id = ?").get(t);if(!e)throw new Error(`missing conversation owner ${t}`);const r=n.id,c=B(J(e.grantee).conversations,t,`${n.timestamp.replace(/[:.]/g,"-")}_${r}.jsonl`),d=k([n,...i]),p=D(t,r,0),u=e.run_id?await L(e.run_id,t,i):!1;return await(await l()).put(p,d),await y(async _=>{if(await _.prepare("SELECT 1 FROM conversation_parts WHERE conversation_id = ?").get(r))throw new Error(`conversation already exists: ${r}`);const E=h(),v=n.parentSession?await _.prepare("SELECT session_id FROM sessions WHERE transcript_path = ? LIMIT 1").get(n.parentSession):void 0;if(await _.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at, unbound_at) VALUES (?, ?, ?, ?, ?, NULL, ?, ?, ?)").run(g(),r,t,c,v?v.session_id:null,E,E,E),await _.prepare("INSERT INTO conversation_parts (conversation_id, seq, blob_key, bytes, entries, created) VALUES (?, 0, ?, ?, ?, ?)").run(r,p,Buffer.byteLength(d),i.length,E),e.run_id&&!v){const F=await T(_,e.run_id,t,i,[],u);await _.prepare("UPDATE sessions SET indexed_entry_id = ?, input_ids_json = ? WHERE session_id = ? AND node_id = ?").run(i.at(-1)?.id??null,JSON.stringify(F),r,t)}}),r},async append(t,n){if(!n.length)return;const i=await N(await w(),t),s=i.run_id?await L(i.run_id,i.node_id,n):!1;await y(async a=>{const e=await N(a,t,!0);if(!(await b(a,t)).length)throw new R(t);const r=[];for(const c of n){const d=JSON.stringify(c);await a.prepare("INSERT INTO conversation_entries (conversation_id, entry_id, body, bytes, execution_id, created) VALUES (?, ?, ?, ?, NULL, ?) ON CONFLICT (conversation_id, entry_id) DO NOTHING RETURNING entry_id").get(t,c.id,d,Buffer.byteLength(d)+1,h())&&r.push(c)}if(e.run_id&&r.length){const c=await T(a,e.run_id,e.node_id,r,JSON.parse(e.input_ids_json??"[]"),s);await a.prepare("UPDATE sessions SET indexed_entry_id = ?, input_ids_json = ? WHERE binding_id = ?").run(r.at(-1).id,JSON.stringify(c),e.binding_id)}})},async readLines(t){const n=await w(),{path:i}=await S(t,n),s=await I(n,t),a=s.parts.reduce((r,c)=>r+c.bytes,0)+s.tail.reduce((r,c)=>r+c.bytes,0);async function*e(){let r="";for(let c=0;c<a;c+=C){const d=r+(await m(s,c,Math.min(a,c+C))).toString("latin1"),p=d.lastIndexOf(`
7
+ `);r=d.slice(p+1);for(const u of d.slice(0,p+1).split(`
8
+ `))u&&(yield Buffer.from(u,"latin1").toString("utf8"))}r&&(yield Buffer.from(r,"latin1").toString("utf8"))}return f(e,"lines"),{path:i,lines:e()}},async read(t,n){const i=await w(),{header:s,path:a}=await S(t,i),e=await I(i,t),r=e.parts.reduce((_,E)=>_+E.bytes,0)+e.tail.reduce((_,E)=>_+E.bytes,0),c=f(_=>$(_).filter(E=>E.type!=="session"),"entriesOf");if(!n||r<=n.head+n.tail)return{header:s,entries:c((await m(e,0,r)).toString("utf8")),path:a};const d=(await m(e,0,Math.max(0,n.head))).toString("utf8").split(`
9
+ `);d.pop();const p=Math.max(0,r-n.tail),u=(await m(e,p>0?p-1:0,r)).toString("utf8").split(`
10
+ `);return p>0&&u.shift(),{header:s,entries:c(d.join(`
11
+ `)),tail:c(u.join(`
12
+ `)),path:a}},async header(t){const n=await w(),{header:i,path:s}=await S(t,n),a=await I(n,t);return{header:i,path:s,mtime:Date.parse(a.tail.at(-1)?.created??a.parts.at(-1).created),size:a.parts.reduce((e,r)=>e+r.bytes,0)+a.tail.reduce((e,r)=>e+r.bytes,0)}},async list(t){const i=await(await w()).prepare(`SELECT DISTINCT ON (s.session_id) s.session_id, s.node_id FROM sessions s JOIN conversation_parts p ON p.conversation_id = s.session_id WHERE s.session_id IS NOT NULL ORDER BY s.session_id, ${O}`).all(),s=[];for(const a of i){if(t&&a.node_id!==t)continue;const e=await o.header(a.session_id);s.push({conversation_id:a.session_id,node_id:a.node_id,...e})}return s.sort((a,e)=>e.mtime-a.mtime)},async replace(t,n,i){if(n.id!==t)throw new Error("replacement header id differs from conversation id");const s=await w(),a=await N(s,t);if(a.run_id)throw new Error(`run conversation ${t} is append-only; replace refused`);const e=`conversations/${a.node_id}/${t}/0-${g()}.jsonl`,r=k([n,...i]);await(await l()).put(e,r);const c=await y(async d=>{if((await N(d,t,!0)).run_id)throw new Error(`run conversation ${t} is append-only; replace refused`);const u=await b(d,t);return await d.prepare("DELETE FROM conversation_parts WHERE conversation_id = ?").run(t),await d.prepare("DELETE FROM conversation_entries WHERE conversation_id = ?").run(t),await d.prepare("INSERT INTO conversation_parts (conversation_id, seq, blob_key, bytes, entries, created) VALUES (?, 0, ?, ?, ?, ?)").run(t,e,Buffer.byteLength(r),i.length,h()),u});for(const d of c)await(await l()).delete(d.blob_key)},async fork(t,n,i,s){const a=await o.read(t);let e=a.entries;if(i!==void 0){const r=j.inMemory(a.header.cwd,void 0,[a.header,...e]);r.createBranchedSession(i),e=r.getEntries()}return await o.create(n??(await S(t,await w())).binding?.node_id??M.get(t).node,{...a.header,id:g(),timestamp:h(),cwd:s??a.header.cwd,parentSession:a.path},e)},async delete(t,n){const i=await w(),s=await b(i,t);await y(async a=>{await a.prepare("DELETE FROM conversation_entries WHERE conversation_id = ?").run(t),await a.prepare("DELETE FROM conversation_parts WHERE conversation_id = ?").run(t),await a.prepare("DELETE FROM sessions WHERE session_id = ?").run(t)});for(const a of s)await(await l()).delete(a.blob_key);n&&A(n,{force:!0})},async commit(t){return await y(async n=>{const i=await N(n,t,!0),s=await Y(n,t),a=await b(n,t);if(!s.length)return a.at(-1)?.seq??0;const e=(a.at(-1)?.seq??0)+1,r=D(i.node_id,t,e),c=s.map(d=>d.body+`
13
+ `).join("");return await(await l()).put(r,c),process.env.CRTR_FAULT_CONVERSATION==="commit_exit_after_put"&&process.exit(1),await n.prepare("INSERT INTO conversation_parts (conversation_id, seq, blob_key, bytes, entries, created) VALUES (?, ?, ?, ?, ?, ?)").run(t,e,r,Buffer.byteLength(c),s.length,h()),await n.prepare("DELETE FROM conversation_entries WHERE conversation_id = ? AND seq <= ?").run(t,s.at(-1).seq),e})},async importLegacy(t){const i=await(await w()).prepare(`SELECT DISTINCT ON (s.session_id) s.session_id, s.node_id, s.transcript_path FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id IS NOT NULL AND s.transcript_path IS NOT NULL ${t?"AND n.run_id = ?":""} ORDER BY s.session_id, ${O}`).all(...t?[t]:[]);for(const s of i)await U(s.session_id,s.node_id,s.transcript_path)},recover(t){for(const n of t)n.transcript_path&&M.set(n.session_id,{node:n.node_id,path:n.transcript_path})}};return o}f(et,"createRowStore");async function nt(o,t,n){const i=await w(),s=await N(i,o),a=(await b(i,o))[0];if(!a||a.seq!==0)return!1;const e=await(await l()).get(a.blob_key);if(!e)throw new Error(`missing conversation object: ${a.blob_key}`);const r=e.indexOf(10);if(r<0)throw new Error(`invalid conversation header: ${o}`);const c=JSON.parse(e.subarray(0,r).toString("utf8"));if(c.type!=="session"||c.id!==o)throw new Error(`invalid conversation header: ${o}`);if(c.cwd!==t)return!1;const d=Buffer.concat([Buffer.from(JSON.stringify({...c,cwd:n})),e.subarray(r)]),p=`conversations/${s.node_id}/${o}/0-${g()}.jsonl`;await(await l()).put(p,d);const u=await y(async _=>await _.prepare("UPDATE conversation_parts SET blob_key = ?, bytes = ? WHERE conversation_id = ? AND seq = 0 AND blob_key = ? RETURNING seq").get(p,d.length,o,a.blob_key)!==void 0);if(await(await l()).delete(u?a.blob_key:p).catch(()=>{}),!u)throw new Error(`conversation header changed during relocation: ${o}`);return!0}f(nt,"relocateConversationHeader");export{et as createRowStore,nt as relocateConversationHeader};
@@ -1 +1 @@
1
- var J=Object.defineProperty;var s=(t,r)=>J(t,"name",{value:r,configurable:!0});import{createHash as N,generateKeyPairSync as R,randomUUID as U}from"node:crypto";import{existsSync as I,mkdirSync as D,readdirSync as L,rmSync as y}from"node:fs";import{hostname as O}from"node:os";import{join as b}from"node:path";import{InputError as p}from"../io.js";import{network as k}from"../errors.js";import{secretsDir as j}from"../layout.js";import{apiSocketPath as C}from"../canvas/paths.js";import{daemonAnswers as K}from"../layout-migrate/index.js";import{atomicWriteJson as _,readJsonIfExists as x}from"../fs-utils.js";import{updateConfig as T}from"../config.js";import{launcherPresent as A}from"../grants/sandboxes.js";import{crtrVersion as W}from"../../shared/crtr-version.js";import{pluginsDir as q}from"../scope.js";import{userScopeRoot as z}from"../scope.js";import{rewriteLocalProfileGrantees as B}from"../scoped-state/profiles.js";import{withJoinLock as F}from"./join-lock.js";function l(){return b(j(),"runtime-client.json")}s(l,"clientPath");function S(t){if(typeof t!="string")return!1;try{const{protocol:r}=new URL(t);return r==="http:"||r==="https:"}catch{return!1}}s(S,"isUrl");function $(t){const r=t??{},{runtime:u,client_id:e,issuer:a,owner:n,url:o}=r;if(typeof u!="string"||!/^runtime:.+/.test(u)||typeof e!="string"||e===""||!S(a)||typeof n!="string"||!/^user:.+/.test(n)||!S(o))throw k("directory registration answer is missing runtime, client_id, issuer, owner, or url");const{machine_id:i,is_default:c}=r;return{runtime:u,client_id:e,issuer:a,owner:n,url:o,...typeof i=="string"?{machine_id:i}:{},...typeof c=="boolean"?{is_default:c}:{}}}s($,"registration");function w(){return b(j(),"runtime-client.pending.json")}s(w,"pendingPath");function G(){try{const t=q("user");return!t||!I(t)?[]:L(t,{withFileTypes:!0}).filter(r=>r.isDirectory()&&!r.name.startsWith(".")).map(r=>r.name).sort()}catch{return[]}}s(G,"installedPluginIds");async function V(t,r,u,e){const a=`${t.replace(/\/$/,"")}/v1/runtimes/registration`;let n;try{n=await fetch(a,{method:"PUT",headers:{authorization:`Bearer ${r}`,"content-type":"application/json"},body:JSON.stringify({jwk:u,name:e,platform:`${process.platform}-${process.arch}`,crtr_version:W(),plugins:G(),sandboxed:A()}),signal:AbortSignal.timeout(3e4)})}catch(i){throw k(`directory registration request to ${a} failed: ${i instanceof Error?i.message:String(i)}`)}const o=await n.text();if(!n.ok)throw n.status<500&&y(w(),{force:!0}),new p({error:"join_refused",message:`directory refused the registration: ${n.status} ${o.slice(0,500)}`,next:`Create a new join token at ${t.replace(/\/$/,"")}/account/machines (tokens are single-use and expire after 10 minutes), and run \`crtr sys join\` again.`});try{return $(JSON.parse(o))}catch(i){throw i instanceof SyntaxError?k("directory registration answer is not JSON"):i}}s(V,"register");function P(t){T("user",r=>{r.runtime=t.is_default===!1?{issuer:t.issuer,audience:t.url,unsandboxed:!0}:{...r.runtime,issuer:t.issuer,audience:t.url}}),B(z())}s(P,"commit");function mt(){const t=x(l());if(t?.token_sha256===void 0)return null;const{owner:r}=t;if(typeof r!="string"||!/^user:.+/.test(r))throw new Error(`${l()} was written by join but has a missing or invalid owner`);return r}s(mt,"joinedOwner");function v(t){return new p({error:"daemon_running",message:`cannot join while a daemon answers on ${t}`,next:"This daemon is managed outside crtr, so join cannot restart it: stop the daemon that owns this volume, then run `crtr sys join` again."})}s(v,"daemonRunningError");async function E(t,r,u,e){const a=x(l());if(a?.token_sha256===e)return{joined:$(a),registered:!1};D(j(),{recursive:!0,mode:448});let n=x(w());if(n?.token_sha256!==e||n.directory!==t||!n.jwk||!n.public_jwk){const{privateKey:h,publicKey:f}=R("ec",{namedCurve:"P-256"}),d=U();n={token_sha256:e,directory:t,jwk:{...h.export({format:"jwk"}),kid:d,alg:"ES256",use:"sig"},public_jwk:{...f.export({format:"jwk"}),kid:d,alg:"ES256",use:"sig"}},_(w(),n,{mode:384})}const{jwk:o,public_jwk:i}=n,c=await V(t,r,i,u);return{joined:c,registered:!0,client:{jwk:o,kid:o.kid,alg:"ES256",...c,token_sha256:e}}}s(E,"obtainRegistration");async function pt(t,r,u=O(),e){if(!S(t))throw new p({error:"invalid_directory",message:"directory must be an http or https URL",received:t,field:"directory",next:"Pass the directory base URL, for example https://directory.example."});if(r==="")throw new p({error:"invalid_token",message:"token is empty",field:"token",next:"Pass the enrollment token provisioning supplied."});const a=C(),n=N("sha256").update(r).digest("hex");if(e===void 0){if(await K(a))throw v(a);const{joined:o,registered:i,client:c}=await E(t,r,u,n);return c&&(_(l(),c,{mode:384}),y(w(),{force:!0})),P(o),{...o,registered:i,daemon:"not_running"}}return F(async()=>{const o=s(()=>new p({error:"join_inside_node",message:"a daemon is running and this command is inside a node: stopping the daemon would kill this node's broker and this command with it",next:"Run `crtr sys join` from a plain terminal outside any crtr node. It stops the daemon, joins, and starts it again for you."}),"refuseInsideNode");if(await e.running()&&e.insideNode())throw o();const{joined:i,registered:c,client:h}=await E(t,r,u,n);let f=!1,d;try{if(await e.running()){if(e.insideNode())throw o();if(f=!0,await e.stop(),await e.running())throw v(a)}if(h&&(_(l(),h,{mode:384}),y(w(),{force:!0})),P(i),await e.running()){if(e.insideNode())throw o();f=!0,await e.stop()}}catch(m){d=m}let g={daemon:"not_running"};if(d===void 0||f)try{await e.start(),g={daemon:f?"restarted":"started"}}catch(m){g={daemon:"restart_failed",daemon_error:m instanceof Error?m.message:String(m)}}if(d!==void 0)throw d;return g.daemon==="started"&&await e.firstSync?.(),{...i,registered:c,...g}})}s(pt,"joinDirectory");export{G as installedPluginIds,pt as joinDirectory,mt as joinedOwner};
1
+ var I=Object.defineProperty;var a=(t,e)=>I(t,"name",{value:e,configurable:!0});import{createHash as N,generateKeyPairSync as J,randomUUID as L}from"node:crypto";import{existsSync as R,mkdirSync as U,readdirSync as O,rmSync as y}from"node:fs";import{hostname as C}from"node:os";import{join as b}from"node:path";import{InputError as p}from"../io.js";import{network as k}from"../errors.js";import{secretsDir as _}from"../layout.js";import{apiSocketPath as D}from"../canvas/paths.js";import{daemonAnswers as A}from"../layout-migrate/index.js";import{atomicWriteJson as j,readJsonIfExists as x}from"../fs-utils.js";import{updateConfig as K}from"../config.js";import{launcherPresent as T}from"../grants/sandboxes.js";import{crtrVersion as W}from"../../shared/crtr-version.js";import{pluginsDir as q}from"../scope.js";import{writeSettings as z}from"../scoped-state/person-store.js";import{LEGACY_LOCAL_PERSON as B}from"../canvas/legacy-person.js";import{withJoinLock as F}from"./join-lock.js";function l(){return b(_(),"runtime-client.json")}a(l,"clientPath");function S(t){if(typeof t!="string")return!1;try{const{protocol:e}=new URL(t);return e==="http:"||e==="https:"}catch{return!1}}a(S,"isUrl");function $(t){const e=t??{},{runtime:o,client_id:r,issuer:u,owner:n,url:s}=e;if(typeof o!="string"||!/^runtime:.+/.test(o)||typeof r!="string"||r===""||!S(u)||typeof n!="string"||!/^user:.+/.test(n)||!S(s))throw k("directory registration answer is missing runtime, client_id, issuer, owner, or url");const{machine_id:i,is_default:c}=e;return{runtime:o,client_id:r,issuer:u,owner:n,url:s,...typeof i=="string"?{machine_id:i}:{},...typeof c=="boolean"?{is_default:c}:{}}}a($,"registration");function w(){return b(_(),"runtime-client.pending.json")}a(w,"pendingPath");function G(){try{const t=q("user");return!t||!R(t)?[]:O(t,{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.name.startsWith(".")).map(e=>e.name).sort()}catch{return[]}}a(G,"installedPluginIds");async function V(t,e,o,r){const u=`${t.replace(/\/$/,"")}/v1/runtimes/registration`;let n;try{n=await fetch(u,{method:"PUT",headers:{authorization:`Bearer ${e}`,"content-type":"application/json"},body:JSON.stringify({jwk:o,name:r,platform:`${process.platform}-${process.arch}`,crtr_version:W(),plugins:G(),sandboxed:T()}),signal:AbortSignal.timeout(3e4)})}catch(i){throw k(`directory registration request to ${u} failed: ${i instanceof Error?i.message:String(i)}`)}const s=await n.text();if(!n.ok)throw n.status<500&&y(w(),{force:!0}),new p({error:"join_refused",message:`directory refused the registration: ${n.status} ${s.slice(0,500)}`,next:`Create a new join token at ${t.replace(/\/$/,"")}/account/machines (tokens are single-use and expire after 10 minutes), and run \`crtr sys join\` again.`});try{return $(JSON.parse(s))}catch(i){throw i instanceof SyntaxError?k("directory registration answer is not JSON"):i}}a(V,"register");async function E(t){await K("user",e=>{e.runtime=t.is_default===!1?{issuer:t.issuer,audience:t.url,unsandboxed:!0}:{...e.runtime,issuer:t.issuer,audience:t.url}}),await z(e=>e.profiles.filter(o=>o.manifest.grantee===B).map(o=>({op:"profile.update",profile:{profileId:o.profileId,manifest:{...o.manifest,grantee:"app:terminal"}}})))}a(E,"commit");function mt(){const t=x(l());if(t?.token_sha256===void 0)return null;const{owner:e}=t;if(typeof e!="string"||!/^user:.+/.test(e))throw new Error(`${l()} was written by join but has a missing or invalid owner`);return e}a(mt,"joinedOwner");function P(t){return new p({error:"daemon_running",message:`cannot join while a daemon answers on ${t}`,next:"This daemon is managed outside crtr, so join cannot restart it: stop the daemon that owns this volume, then run `crtr sys join` again."})}a(P,"daemonRunningError");async function v(t,e,o,r){const u=x(l());if(u?.token_sha256===r)return{joined:$(u),registered:!1};U(_(),{recursive:!0,mode:448});let n=x(w());if(n?.token_sha256!==r||n.directory!==t||!n.jwk||!n.public_jwk){const{privateKey:g,publicKey:d}=J("ec",{namedCurve:"P-256"}),f=L();n={token_sha256:r,directory:t,jwk:{...g.export({format:"jwk"}),kid:f,alg:"ES256",use:"sig"},public_jwk:{...d.export({format:"jwk"}),kid:f,alg:"ES256",use:"sig"}},j(w(),n,{mode:384})}const{jwk:s,public_jwk:i}=n,c=await V(t,e,i,o);return{joined:c,registered:!0,client:{jwk:s,kid:s.kid,alg:"ES256",...c,token_sha256:r}}}a(v,"obtainRegistration");async function pt(t,e,o=C(),r){if(!S(t))throw new p({error:"invalid_directory",message:"directory must be an http or https URL",received:t,field:"directory",next:"Pass the directory base URL, for example https://directory.example."});if(e==="")throw new p({error:"invalid_token",message:"token is empty",field:"token",next:"Pass the enrollment token provisioning supplied."});const u=D(),n=N("sha256").update(e).digest("hex");if(r===void 0){if(await A(u))throw P(u);const{joined:s,registered:i,client:c}=await v(t,e,o,n);return c&&(j(l(),c,{mode:384}),y(w(),{force:!0})),await E(s),{...s,registered:i,daemon:"not_running"}}return F(async()=>{const s=a(()=>new p({error:"join_inside_node",message:"a daemon is running and this command is inside a node: stopping the daemon would kill this node's broker and this command with it",next:"Run `crtr sys join` from a plain terminal outside any crtr node. It stops the daemon, joins, and starts it again for you."}),"refuseInsideNode");if(await r.running()&&r.insideNode())throw s();const{joined:i,registered:c,client:g}=await v(t,e,o,n);let d=!1,f;try{if(await r.running()){if(r.insideNode())throw s();if(d=!0,await r.stop(),await r.running())throw P(u)}if(g&&(j(l(),g,{mode:384}),y(w(),{force:!0})),await E(i),await r.running()){if(r.insideNode())throw s();d=!0,await r.stop()}}catch(m){f=m}let h={daemon:"not_running"};if(f===void 0||d)try{await r.start(),h={daemon:d?"restarted":"started"}}catch(m){h={daemon:"restart_failed",daemon_error:m instanceof Error?m.message:String(m)}}if(f!==void 0)throw f;return h.daemon==="started"&&await r.firstSync?.(),{...i,registered:c,...h}})}a(pt,"joinDirectory");export{G as installedPluginIds,pt as joinDirectory,mt as joinedOwner};
@@ -4,3 +4,4 @@ export interface EnvNameValidation {
4
4
  }
5
5
  /** Validate an environment variable identifier without reading its value. */
6
6
  export declare function validateEnvVarName(name: unknown): EnvNameValidation;
7
+ export declare function isReservedEnvName(name: string): boolean;
@@ -1 +1 @@
1
- var a=Object.defineProperty;var t=(r,e)=>a(r,"name",{value:e,configurable:!0});function s(r){const e=[];return typeof r!="string"?e.push("env var name must be a string"):/^[A-Za-z_][A-Za-z0-9_]*$/.test(r)||e.push("env var name must start with letter/underscore, followed by alphanumeric/underscore"),{isValid:e.length===0,errors:e}}t(s,"validateEnvVarName");export{s as validateEnvVarName};
1
+ var s=Object.defineProperty;var r=(e,t)=>s(e,"name",{value:t,configurable:!0});function i(e){const t=[];return typeof e!="string"?t.push("env var name must be a string"):/^[A-Za-z_][A-Za-z0-9_]*$/.test(e)||t.push("env var name must start with letter/underscore, followed by alphanumeric/underscore"),{isValid:t.length===0,errors:t}}r(i,"validateEnvVarName");const n="CRTR_",a=new Set(["HOME"]);function o(e){return e.startsWith(n)||a.has(e)}r(o,"isReservedEnvName");export{o as isReservedEnvName,i as validateEnvVarName};
@@ -0,0 +1,15 @@
1
+ export interface EnvironmentRecipeInput {
2
+ repositories: Array<{
3
+ name: string;
4
+ github_full_name: string;
5
+ default_branch: string;
6
+ }>;
7
+ setup_script: string | null;
8
+ /** pi package sources, one per line. */
9
+ pi_packages: string | null;
10
+ }
11
+ /** Replaces the recipe of a cloud environment. Returns the recipe revision after the write and whether it changed. */
12
+ export declare function setEnvironmentRecipe(environmentId: string, recipe: EnvironmentRecipeInput): Promise<{
13
+ revision: number;
14
+ changed: boolean;
15
+ }>;
@@ -0,0 +1 @@
1
+ var c=Object.defineProperty;var p=(r,n)=>c(r,"name",{value:n,configurable:!0});import{withCanvasWrite as u}from"./canvas/db.js";async function h(r,n){const o=new Set;for(const e of n.repositories){if(!/^[A-Za-z0-9._-]+$/.test(e.name)||e.name==="."||e.name==="..")throw new Error(`repository name ${JSON.stringify(e.name)} is not a plain directory name`);if(o.has(e.name))throw new Error(`repository name ${e.name} appears twice in the recipe`);o.add(e.name)}return await u(async e=>{const t=await e.prepare("SELECT kind, recipe_revision, setup_script, pi_packages FROM environments WHERE object = ? FOR UPDATE").get(r);if(t===void 0)throw new Error(`no environment ${r}`);if(t.kind!=="blaxel")throw new Error(`environment ${r} is a ${t.kind} environment; only a cloud (blaxel) environment has a recipe image`);const s=await e.prepare("SELECT name, github_full_name, default_branch FROM environment_repos WHERE environment = ? ORDER BY position").all(r);if(t.setup_script===n.setup_script&&t.pi_packages===n.pi_packages&&s.length===n.repositories.length&&s.every((a,i)=>a.name===n.repositories[i].name&&a.github_full_name===n.repositories[i].github_full_name&&a.default_branch===n.repositories[i].default_branch))return{revision:Number(t.recipe_revision),changed:!1};await e.prepare("DELETE FROM environment_repos WHERE environment = ?").run(r);const m=e.prepare("INSERT INTO environment_repos (environment, position, name, github_full_name, default_branch) VALUES (?, ?, ?, ?, ?)");for(const[a,i]of n.repositories.entries())await m.run(r,a,i.name,i.github_full_name,i.default_branch);const _=await e.prepare("UPDATE environments SET setup_script = ?, pi_packages = ?, recipe_revision = recipe_revision + 1 WHERE object = ? RETURNING recipe_revision").get(n.setup_script,n.pi_packages,r);return{revision:Number(_.recipe_revision),changed:!0}})}p(h,"setEnvironmentRecipe");export{h as setEnvironmentRecipe};
@@ -1 +1 @@
1
- var s=Object.defineProperty;var i=(e,r)=>s(e,"name",{value:r,configurable:!0});import{openDb as p,withCanvasWrite as w}from"./canvas/db.js";import{createObject as u,ownerForGrantee as E}from"./graph/objects.js";import{writeActsFor as h}from"./permissions/facts.js";import{personIdAsync as v}from"./canvas/person.js";let t=null;async function S(e){const r=new Date().toISOString(),o=await w(async n=>{const c=await n.prepare("SELECT object FROM environments WHERE machine_id = ?").get(e);if(c!==void 0)return await n.prepare("UPDATE environments SET last_seen_at = ? WHERE machine_id = ?").run(r,e),{environmentId:c.object,created:!1};const m=await E(n,"app:terminal"),a=await u(n,{type:"environment",kind:"machine",owner:m.id,privacy:"public",name:e,preview:"machine"});return await h(n,a.id,await v()),await n.prepare("INSERT INTO environments (object, kind, machine_id, last_seen_at) VALUES (?, 'machine', ?, ?)").run(a.id,e,r),{environmentId:a.id,created:!0}});return t={environmentId:o.environmentId,machineId:e},o}i(S,"registerMachineEnvironment");async function T(e){t!==null&&await(await p()).prepare("UPDATE environments SET last_seen_at = ? WHERE machine_id = ?").run(e,t.machineId)}i(T,"touchMachineEnvironment");function g(){if(t===null)throw new Error("the machine environment is not registered yet");return t.environmentId}i(g,"machineEnvironmentId");export{g as machineEnvironmentId,S as registerMachineEnvironment,T as touchMachineEnvironment};
1
+ var s=Object.defineProperty;var i=(e,r)=>s(e,"name",{value:r,configurable:!0});import{openDb as p,withCanvasWrite as u}from"./canvas/db.js";import{createObject as w,ownerForGrantee as E}from"./graph/objects.js";import{writeActsFor as d}from"./permissions/facts.js";import{isCloudRole as h,personIdAsync as v}from"./canvas/person.js";let t=null;async function S(e){const r=new Date().toISOString(),o=await u(async n=>{const c=await n.prepare("SELECT object FROM environments WHERE machine_id = ?").get(e);if(c!==void 0)return await n.prepare("UPDATE environments SET last_seen_at = ? WHERE machine_id = ?").run(r,e),{environmentId:c.object,created:!1};const m=await E(n,"app:terminal"),a=await w(n,{type:"environment",kind:"machine",owner:m.id,privacy:"public",name:e,preview:"machine"});return h()||await d(n,a.id,await v()),await n.prepare("INSERT INTO environments (object, kind, machine_id, last_seen_at) VALUES (?, 'machine', ?, ?)").run(a.id,e,r),{environmentId:a.id,created:!0}});return t={environmentId:o.environmentId,machineId:e},o}i(S,"registerMachineEnvironment");async function T(e){t!==null&&await(await p()).prepare("UPDATE environments SET last_seen_at = ? WHERE machine_id = ?").run(e,t.machineId)}i(T,"touchMachineEnvironment");function g(){if(t===null)throw new Error("the machine environment is not registered yet");return t.environmentId}i(g,"machineEnvironmentId");export{g as machineEnvironmentId,S as registerMachineEnvironment,T as touchMachineEnvironment};
@@ -1,3 +1,3 @@
1
- var i=Object.defineProperty;var n=(o,e)=>i(o,"name",{value:e,configurable:!0});import{appendBufferedDaemonRecord as s,appendRotatingRecord as f}from"../log.js";import{buildEnvelope as c}from"./envelope.js";import{serializeEventRecord as m}from"./serialize.js";import{eventSource as p}from"./source.js";import{envExecutionId as a}from"../../shared/env.js";import{appendBrokerLog as u}from"../runtime/broker/daemon-ops.js";let t=Promise.resolve();function E(){return t}n(E,"flushBrokerLog");function l(o,e){t=t.then(async()=>{try{const{appended:r}=await u(o,e);r||process.stderr.write(`[broker] log.jsonl refused record: ${e}
1
+ var i=Object.defineProperty;var n=(o,e)=>i(o,"name",{value:e,configurable:!0});import{appendBufferedDaemonRecord as s,appendRotatingRecord as f}from"../log.js";import{buildEnvelope as a}from"./envelope.js";import{serializeEventRecord as c}from"./serialize.js";import{eventSource as m}from"./source.js";import{isSandboxedNode as p}from"../../shared/env.js";import{appendBrokerLog as u}from"../runtime/broker/daemon-ops.js";let l,t=Promise.resolve();function E(){return t}n(E,"flushBrokerLog");function _(o,e){t=t.then(async()=>{try{const{appended:r}=await u(o,e);r||process.stderr.write(`[broker] log.jsonl refused record: ${e}
2
2
  `)}catch(r){process.stderr.write(`[broker] log.jsonl append failed (${r instanceof Error?r.message:String(r)}): ${e}
3
- `)}})}n(l,"queueBrokerRecord");function w(o){const e=p();if(e===void 0)return!1;if(e.component==="broker"&&e.node_id!==void 0&&o.node_id!==void 0&&o.node_id!==e.node_id)throw new TypeError(`broker event target node_id must match bound node_id; received ${o.node_id}`);if(o.level==="debug"&&process.env.CRTR_LOG!=="debug")return!1;const r=c({...o,component:e.component,...e.node_id===void 0?{}:{node_id:e.node_id},...e.stream_id===void 0?{}:{stream_id:e.stream_id}}),d=m(r);return e.component==="broker"&&e.node_id!==void 0&&a()!==void 0?(l(e.node_id,d),!0):e.component==="daemon"?s(e.path,d):f(e.path,d)}n(w,"emitEvent");export{w as emitEvent,E as flushBrokerLog};
3
+ `)}})}n(_,"queueBrokerRecord");function B(o){const e=m();if(e===void 0)return!1;if(e.component==="broker"&&e.node_id!==void 0&&o.node_id!==void 0&&o.node_id!==e.node_id)throw new TypeError(`broker event target node_id must match bound node_id; received ${o.node_id}`);if(o.level==="debug"&&process.env.CRTR_LOG!=="debug")return!1;const r=a({...o,component:e.component,...e.node_id===void 0?{}:{node_id:e.node_id},...e.stream_id===void 0?{}:{stream_id:e.stream_id}}),d=c(r);return e.component==="broker"&&e.node_id!==void 0&&(l??=p())?(_(e.node_id,d),!0):e.component==="daemon"?s(e.path,d):f(e.path,d)}n(B,"emitEvent");export{B as emitEvent,E as flushBrokerLog};
@@ -0,0 +1,25 @@
1
+ import type { RunEvent } from '../../api/dto/run-events.js';
2
+ import type { BlobStore } from '../blobs/index.js';
3
+ /** One fixed 128-sequence range of a run's archived events and the immutable objects that hold it. Passes that archive
4
+ * different rows of one range write different objects; the range's events are their union. */
5
+ export interface RunEventChunk {
6
+ first: number;
7
+ last: number;
8
+ keys: string[];
9
+ }
10
+ /** List a run's archived ranges in order, each with the keys of the objects holding it. */
11
+ export declare function listRunEventChunks(store: BlobStore, runId: string): Promise<RunEventChunk[]>;
12
+ /** Read a range's events, each sequence once, ordered by sequence. An event body never changes after it is written,
13
+ * so a sequence held by more than one object (a retried or concurrent pass) has the same body in each. A missing object is an error. */
14
+ export declare function readRunEventChunk(store: BlobStore, chunk: RunEventChunk): Promise<RunEvent[]>;
15
+ /**
16
+ * Archive the same 14-day payload/30-day control events formerly deleted by expireRunEvents.
17
+ * No transaction, connection or lock is held across compression or blob I/O: the rows are read, each range's
18
+ * rows become one immutable object whose key carries a digest of its content, and only then does a short
19
+ * transaction delete the rows. Nothing is ever read back and merged, so there is no object a stale or
20
+ * concurrent archiver could overwrite with fewer rows: it can only write an object with the same content
21
+ * under the same key, or a different one under its own key, and readers take the union by sequence.
22
+ * A crash or failed put leaves the rows (the next pass archives them again); rows are deleted only after
23
+ * their object is durable. Returns the number of rows this pass deleted.
24
+ */
25
+ export declare function archiveExpiredRunEvents(store: BlobStore, now: number, limit?: number): Promise<number>;
@@ -0,0 +1,5 @@
1
+ var g=Object.defineProperty;var u=(e,s)=>g(e,"name",{value:s,configurable:!0});import{createHash as v}from"node:crypto";import{promisify as w}from"node:util";import{zstdCompress as k,zstdDecompress as S}from"node:zlib";import{openDb as $,withCanvasWrite as x}from"../canvas/db.js";const D=w(k),N=w(S),l=128,R=16,_=["node.tool_call.completed","node.tool_call.started","node.system_prompt.set","node.thinking.done","node.output_text.done"],h=u(e=>`events/${e}/`,"prefix"),b=u(e=>String(e).padStart(R,"0"),"pad"),I=u(e=>{const s=Math.floor((e-1)/l)*l+1;return{first:s,last:s+l-1}},"range"),q=u((e,s,n,t)=>`${h(e)}${b(s)}-${b(n)}-${t}.jsonl.zst`,"chunkKey");async function z(e,s){const n=new Map;for(const t of await e.list(h(s))){const o=/\/(\d{16})-(\d{16})-[0-9a-f]{32}\.jsonl\.zst$/.exec(t);if(!o)throw new Error(`not a run-event chunk key: ${t}`);const c=Number(o[1]),a=n.get(c);a?a.keys.push(t):n.set(c,{first:c,last:Number(o[2]),keys:[t]})}return[...n.values()].sort((t,o)=>t.first-o.first)}u(z,"listRunEventChunks");async function H(e,s){const n=new Map;for(const t of s.keys){const o=await e.get(t);if(o===null)throw new Error(`run-event chunk missing: ${t}`);const c=(await N(o)).toString("utf8");for(const a of c===""?[]:c.split(`
2
+ `)){const i=JSON.parse(a);n.has(i.sequence_number)||n.set(i.sequence_number,i)}}return[...n.values()].sort((t,o)=>t.sequence_number-o.sequence_number)}u(H,"readRunEventChunk");async function A(e,s,n=128){if(!Number.isSafeInteger(n)||n<0)throw new TypeError("limit must be a nonnegative safe integer");if(n===0)return 0;const t=new Date(s-336*60*6e4).toISOString(),o=new Date(s-720*60*6e4).toISOString(),c=_.map(()=>"?").join(", "),a=await(await $()).prepare(`SELECT run_id, sequence_number, body_json FROM run_events
3
+ WHERE ts < ? AND (ts < ? OR type IN (${c})) ORDER BY ts LIMIT ?`).all(t,o,..._,n),i=new Map;for(const r of a){const{first:p,last:d}=I(Number(r.sequence_number)),f=`${r.run_id}
4
+ ${p}`,m=i.get(f);m?m.rows.push(r):i.set(f,{runId:r.run_id,first:p,last:d,rows:[r]})}for(const{runId:r,first:p,last:d,rows:f}of i.values()){const m=f.map(E=>E.body_json).join(`
5
+ `),y=v("sha256").update(m).digest("hex").slice(0,32);await e.put(q(r,p,d,y),await D(Buffer.from(m,"utf8")))}return await x(async r=>{const p=r.prepare("DELETE FROM run_events WHERE run_id = ? AND sequence_number = ?");let d=0;for(const f of a)d+=Number((await p.run(f.run_id,f.sequence_number)).changes);return d})}u(A,"archiveExpiredRunEvents");export{A as archiveExpiredRunEvents,z as listRunEventChunks,H as readRunEventChunk};