@north-light/cli 0.3.561 → 0.3.563

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 (579) 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/build-root.d.ts +1 -0
  23. package/dist/build-root.js +1 -1
  24. package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
  25. package/dist/cli.js +7 -7
  26. package/dist/clients/attach/chrome/bash-jobs.d.ts +11 -1
  27. package/dist/clients/attach/chrome/bash-jobs.js +1 -1
  28. package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
  29. package/dist/clients/attach/chrome/roster.js +6 -4
  30. package/dist/clients/attach/overlays/auth.js +2 -2
  31. package/dist/clients/attach/render/chat-view.js +1 -1
  32. package/dist/clients/attach/viewer.js +550 -567
  33. package/dist/commands/canvas-config.js +2 -2
  34. package/dist/commands/canvas-use.js +1 -1
  35. package/dist/commands/human.js +2 -2
  36. package/dist/commands/node/bash.js +3 -3
  37. package/dist/commands/node/create.js +2 -2
  38. package/dist/commands/person-settings.d.ts +1 -0
  39. package/dist/commands/person-settings.js +1 -0
  40. package/dist/commands/pkg/market-manage.d.ts +2 -2
  41. package/dist/commands/pkg/market-manage.js +1 -1
  42. package/dist/commands/pkg/plugin-manage.js +13 -13
  43. package/dist/commands/pkg/shared.js +1 -1
  44. package/dist/commands/profile/default.js +1 -1
  45. package/dist/commands/push.js +2 -3
  46. package/dist/commands/sys/config.js +1 -1
  47. package/dist/commands/sys/connect.js +1 -1
  48. package/dist/commands/sys/context/sysprompt.js +2 -2
  49. package/dist/commands/sys/doctor.js +1 -1
  50. package/dist/commands/sys/join.js +1 -1
  51. package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
  52. package/dist/commands/sys/panels/keybindings-panel.js +1 -1
  53. package/dist/commands/sys/panels/models-panel.d.ts +8 -2
  54. package/dist/commands/sys/panels/models-panel.js +1 -1
  55. package/dist/commands/sys/panels/prefs-panel.d.ts +1 -0
  56. package/dist/commands/sys/panels/prefs-panel.js +1 -1
  57. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  58. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  59. package/dist/commands/sys/panels/provider-panel.js +1 -1
  60. package/dist/commands/sys/provider-login.js +5 -5
  61. package/dist/commands/sys/setup-core.js +3 -3
  62. package/dist/commands/sys/setup-settings-runner.js +1 -1
  63. package/dist/commands/sys/spend.js +3 -3
  64. package/dist/commands/sys/update.js +1 -1
  65. package/dist/core/auth-file.d.ts +11 -19
  66. package/dist/core/auth-file.js +1 -2
  67. package/dist/core/auto-update.d.ts +1 -1
  68. package/dist/core/auto-update.js +4 -4
  69. package/dist/core/bash-jobs.d.ts +29 -71
  70. package/dist/core/bash-jobs.js +9 -10
  71. package/dist/core/blobs/directory.d.ts +3 -0
  72. package/dist/core/blobs/directory.js +1 -0
  73. package/dist/core/blobs/fault.d.ts +3 -0
  74. package/dist/core/blobs/fault.js +1 -0
  75. package/dist/core/blobs/index.d.ts +21 -0
  76. package/dist/core/blobs/index.js +1 -0
  77. package/dist/core/blobs/r2.d.ts +9 -0
  78. package/dist/core/blobs/r2.js +4 -0
  79. package/dist/core/bootstrap.d.ts +1 -1
  80. package/dist/core/bootstrap.js +2 -2
  81. package/dist/core/canvas/canvas.d.ts +9 -7
  82. package/dist/core/canvas/canvas.js +8 -8
  83. package/dist/core/canvas/crons.d.ts +3 -2
  84. package/dist/core/canvas/crons.js +3 -3
  85. package/dist/core/canvas/daemon-owner.d.ts +5 -0
  86. package/dist/core/canvas/daemon-owner.js +1 -1
  87. package/dist/core/canvas/db.d.ts +10 -9
  88. package/dist/core/canvas/db.js +4 -4
  89. package/dist/core/canvas/executions.d.ts +100 -4
  90. package/dist/core/canvas/executions.js +1 -1
  91. package/dist/core/canvas/export-sqlite.js +1 -1
  92. package/dist/core/canvas/focuses.d.ts +4 -0
  93. package/dist/core/canvas/focuses.js +1 -1
  94. package/dist/core/canvas/history.js +9 -9
  95. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +2 -1
  96. package/dist/core/canvas/managed-worktree-sweep-candidates.js +3 -2
  97. package/dist/core/canvas/node-tokens.d.ts +1 -4
  98. package/dist/core/canvas/node-tokens.js +3 -3
  99. package/dist/core/canvas/paths.d.ts +0 -1
  100. package/dist/core/canvas/paths.js +1 -1
  101. package/dist/core/canvas/person-state.d.ts +26 -0
  102. package/dist/core/canvas/person-state.js +1 -0
  103. package/dist/core/canvas/person.d.ts +3 -10
  104. package/dist/core/canvas/person.js +7 -7
  105. package/dist/core/canvas/reconciler-leases.d.ts +12 -0
  106. package/dist/core/canvas/reconciler-leases.js +8 -0
  107. package/dist/core/canvas/recovery.d.ts +4 -0
  108. package/dist/core/canvas/recovery.js +1 -1
  109. package/dist/core/canvas/schema-pg/003-fleet-removals.sql +1 -1
  110. package/dist/core/canvas/schema-pg/005-fleet-blobs.sql +13 -0
  111. package/dist/core/canvas/schema-pg/006-job-rows.sql +20 -0
  112. package/dist/core/canvas/schema-pg/007-ledger-check.sql +117 -0
  113. package/dist/core/canvas/schema-version.d.ts +1 -1
  114. package/dist/core/canvas/schema-version.js +1 -1
  115. package/dist/core/canvas/sessions.d.ts +8 -11
  116. package/dist/core/canvas/sessions.js +1 -4
  117. package/dist/core/canvas/tree.d.ts +4 -2
  118. package/dist/core/canvas/tree.js +6 -6
  119. package/dist/core/canvas/types.d.ts +7 -0
  120. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  121. package/dist/core/command-plugins/bundle.d.ts +1 -1
  122. package/dist/core/command-plugins/bundle.js +1 -1
  123. package/dist/core/command-plugins/compose.d.ts +1 -1
  124. package/dist/core/command-plugins/discovery.d.ts +0 -1
  125. package/dist/core/command-plugins/discovery.js +1 -1
  126. package/dist/core/command-plugins/help-addenda.js +1 -1
  127. package/dist/core/command-plugins/presence.d.ts +2 -0
  128. package/dist/core/command-plugins/presence.js +1 -1
  129. package/dist/core/config.d.ts +16 -15
  130. package/dist/core/config.js +1 -1
  131. package/dist/core/conversation-store/client-worker.js +1 -1
  132. package/dist/core/conversation-store/client.js +2 -2
  133. package/dist/core/conversation-store/index.d.ts +9 -11
  134. package/dist/core/conversation-store/index.js +1 -1
  135. package/dist/core/conversation-store/patch.js +1 -1
  136. package/dist/core/conversation-store/row-store.d.ts +14 -0
  137. package/dist/core/conversation-store/row-store.js +13 -0
  138. package/dist/core/directory/join.d.ts +5 -3
  139. package/dist/core/directory/join.js +1 -1
  140. package/dist/core/env-name.d.ts +1 -0
  141. package/dist/core/env-name.js +1 -1
  142. package/dist/core/environment-recipe.d.ts +15 -0
  143. package/dist/core/environment-recipe.js +1 -0
  144. package/dist/core/environments.js +1 -1
  145. package/dist/core/events/emit.js +2 -2
  146. package/dist/core/events/run-event-chunks.d.ts +25 -0
  147. package/dist/core/events/run-event-chunks.js +5 -0
  148. package/dist/core/feed/messages.js +5 -5
  149. package/dist/core/grants/mirror.d.ts +15 -0
  150. package/dist/core/grants/mirror.js +15 -3
  151. package/dist/core/grants/on-sync.d.ts +9 -5
  152. package/dist/core/grants/on-sync.js +1 -1
  153. package/dist/core/grants/remove.d.ts +1 -6
  154. package/dist/core/grants/remove.js +1 -1
  155. package/dist/core/grants/sync.js +1 -1
  156. package/dist/core/grants/watch.d.ts +15 -9
  157. package/dist/core/grants/watch.js +1 -1
  158. package/dist/core/graph/custom.js +8 -8
  159. package/dist/core/graph/jobs.d.ts +83 -5
  160. package/dist/core/graph/jobs.js +11 -2
  161. package/dist/core/graph/kinds/job.js +2 -2
  162. package/dist/core/graph/names.js +7 -7
  163. package/dist/core/graph/objects.d.ts +5 -1
  164. package/dist/core/graph/objects.js +11 -11
  165. package/dist/core/graph/reader.d.ts +3 -0
  166. package/dist/core/graph/reader.js +3 -3
  167. package/dist/core/graph/repo-sync/identity.d.ts +3 -1
  168. package/dist/core/graph/repo-sync/identity.js +1 -1
  169. package/dist/core/graph/repo-sync/repos.d.ts +1 -1
  170. package/dist/core/graph/repo-sync/repos.js +2 -2
  171. package/dist/core/graph/repo-sync/sync.js +2 -2
  172. package/dist/core/installed-plugins.js +1 -1
  173. package/dist/core/keybindings/persistence.d.ts +1 -1
  174. package/dist/core/keybindings/persistence.js +1 -1
  175. package/dist/core/layout-migrate/loose-keys.d.ts +1 -1
  176. package/dist/core/layout-migrate/loose-keys.js +1 -1
  177. package/dist/core/ledger/account.d.ts +12 -0
  178. package/dist/core/ledger/account.js +2 -0
  179. package/dist/core/ledger/charges.d.ts +2 -2
  180. package/dist/core/ledger/charges.js +1 -1
  181. package/dist/core/ledger/check.d.ts +5 -1
  182. package/dist/core/ledger/check.js +1 -7
  183. package/dist/core/ledger/chunks.d.ts +8 -0
  184. package/dist/core/ledger/chunks.js +2 -0
  185. package/dist/core/ledger/index.d.ts +2 -1
  186. package/dist/core/ledger/index.js +1 -1
  187. package/dist/core/ledger/infra-allowance.d.ts +9 -0
  188. package/dist/core/ledger/infra-allowance.js +1 -0
  189. package/dist/core/ledger/limits.js +3 -3
  190. package/dist/core/ledger/payer.d.ts +1 -1
  191. package/dist/core/ledger/payer.js +1 -1
  192. package/dist/core/ledger/read.d.ts +14 -4
  193. package/dist/core/ledger/read.js +2 -3
  194. package/dist/core/ledger/totals.d.ts +5 -16
  195. package/dist/core/ledger/totals.js +4 -4
  196. package/dist/core/ledger/types.d.ts +12 -3
  197. package/dist/core/llm/run.js +2 -2
  198. package/dist/core/managed-providers.d.ts +72 -0
  199. package/dist/core/managed-providers.js +1 -0
  200. package/dist/core/model-auth/api-credential-store.d.ts +10 -0
  201. package/dist/core/model-auth/api-credential-store.js +1 -0
  202. package/dist/core/model-auth/daemon-login.d.ts +1 -1
  203. package/dist/core/model-auth/daemon-login.js +1 -1
  204. package/dist/core/model-auth/flows.d.ts +5 -4
  205. package/dist/core/model-auth/flows.js +1 -1
  206. package/dist/core/model-auth/handoff-jti.d.ts +3 -4
  207. package/dist/core/model-auth/handoff-jti.js +1 -1
  208. package/dist/core/model-auth/readiness.js +1 -1
  209. package/dist/core/model-config.d.ts +1 -1
  210. package/dist/core/model-config.js +1 -1
  211. package/dist/core/model-routes-pool.d.ts +14 -0
  212. package/dist/core/model-routes-pool.js +1 -0
  213. package/dist/core/model-routes.d.ts +11 -16
  214. package/dist/core/model-routes.js +1 -1
  215. package/dist/core/peer/ingest.d.ts +2 -0
  216. package/dist/core/peer/ingest.js +1 -1
  217. package/dist/core/peer/stubs.d.ts +8 -0
  218. package/dist/core/peer/stubs.js +1 -1
  219. package/dist/core/permissions/evaluator.d.ts +7 -2
  220. package/dist/core/permissions/evaluator.js +2 -2
  221. package/dist/core/plugin-env.js +1 -1
  222. package/dist/core/pool-credential-store.d.ts +2 -5
  223. package/dist/core/pool-credential-store.js +1 -1
  224. package/dist/core/profiles/app-env-store.d.ts +5 -5
  225. package/dist/core/profiles/app-env-store.js +1 -2
  226. package/dist/core/profiles/default-binding.d.ts +5 -5
  227. package/dist/core/profiles/default-binding.js +1 -1
  228. package/dist/core/profiles/env-store.d.ts +10 -21
  229. package/dist/core/profiles/env-store.js +1 -2
  230. package/dist/core/profiles/manifest.d.ts +14 -18
  231. package/dist/core/profiles/manifest.js +1 -1
  232. package/dist/core/profiles/relocate.js +1 -1
  233. package/dist/core/profiles/select.js +21 -21
  234. package/dist/core/provider-credential.d.ts +1 -1
  235. package/dist/core/provider-credential.js +1 -1
  236. package/dist/core/provider-management.d.ts +3 -4
  237. package/dist/core/provider-management.js +1 -1
  238. package/dist/core/providers/bundles.js +2 -2
  239. package/dist/core/providers/call.d.ts +3 -34
  240. package/dist/core/providers/description.d.ts +34 -0
  241. package/dist/core/providers/description.js +0 -0
  242. package/dist/core/providers/token-cache.d.ts +14 -14
  243. package/dist/core/providers/token-cache.js +1 -1
  244. package/dist/core/review/companion.js +1 -1
  245. package/dist/core/runs/activity.d.ts +1 -1
  246. package/dist/core/runs/activity.js +1 -1
  247. package/dist/core/runs/events.d.ts +7 -5
  248. package/dist/core/runs/events.js +2 -6
  249. package/dist/core/runs/operations.d.ts +1 -1
  250. package/dist/core/runs/operations.js +6 -6
  251. package/dist/core/runtime/bearings.js +1 -1
  252. package/dist/core/runtime/broker/attachments-fetch.d.ts +5 -0
  253. package/dist/core/runtime/broker/attachments-fetch.js +1 -0
  254. package/dist/core/runtime/broker/bash-job-launch.d.ts +4 -2
  255. package/dist/core/runtime/broker/bash-job-launch.js +1 -1
  256. package/dist/core/runtime/broker/boot-state.d.ts +9 -0
  257. package/dist/core/runtime/broker/boot-state.js +1 -0
  258. package/dist/core/runtime/broker/cli-relay.d.ts +2 -1
  259. package/dist/core/runtime/broker/cli-relay.js +1 -1
  260. package/dist/core/runtime/broker/client-registry.d.ts +3 -3
  261. package/dist/core/runtime/broker/daemon-ops.d.ts +10 -1
  262. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  263. package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
  264. package/dist/core/runtime/broker/fault-retry.js +1 -1
  265. package/dist/core/runtime/broker/frame-engine-control.js +1 -1
  266. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -0
  267. package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
  268. package/dist/core/runtime/broker/job-reporter.d.ts +18 -0
  269. package/dist/core/runtime/broker/job-reporter.js +2 -0
  270. package/dist/core/runtime/broker/model-adapter.d.ts +3 -0
  271. package/dist/core/runtime/broker/model-adapter.js +3 -2
  272. package/dist/core/runtime/broker/signal-stream.js +1 -1
  273. package/dist/core/runtime/broker/spilled-body.d.ts +5 -0
  274. package/dist/core/runtime/broker/spilled-body.js +1 -0
  275. package/dist/core/runtime/broker/summaries-post.d.ts +5 -0
  276. package/dist/core/runtime/broker/summaries-post.js +1 -0
  277. package/dist/core/runtime/broker/tool-groups.d.ts +3 -0
  278. package/dist/core/runtime/broker/tool-groups.js +1 -1
  279. package/dist/core/runtime/broker/turn-replies.d.ts +1 -0
  280. package/dist/core/runtime/broker/turn-replies.js +1 -1
  281. package/dist/core/runtime/broker-persona-guidance.js +2 -2
  282. package/dist/core/runtime/broker.js +1 -1
  283. package/dist/core/runtime/deliver-live.js +1 -1
  284. package/dist/core/runtime/first-boot-rows.d.ts +8 -0
  285. package/dist/core/runtime/first-boot-rows.js +2 -0
  286. package/dist/core/runtime/fleet.d.ts +13 -12
  287. package/dist/core/runtime/front-door-login.js +1 -1
  288. package/dist/core/runtime/front-door.js +6 -6
  289. package/dist/core/runtime/headless-pi.js +1 -1
  290. package/dist/core/runtime/host.d.ts +14 -3
  291. package/dist/core/runtime/host.js +3 -3
  292. package/dist/core/runtime/invocation.d.ts +6 -0
  293. package/dist/core/runtime/kickoff.d.ts +2 -14
  294. package/dist/core/runtime/kickoff.js +17 -19
  295. package/dist/core/runtime/launch-config-worker.js +1 -1
  296. package/dist/core/runtime/launch.js +2 -2
  297. package/dist/core/runtime/model-registry.js +1 -1
  298. package/dist/core/runtime/node-read.d.ts +4 -6
  299. package/dist/core/runtime/node-read.js +3 -3
  300. package/dist/core/runtime/nodes.js +1 -1
  301. package/dist/core/runtime/outcome-document.d.ts +0 -1
  302. package/dist/core/runtime/outcome-document.js +1 -1
  303. package/dist/core/runtime/output-result.d.ts +15 -0
  304. package/dist/core/runtime/output-result.js +5 -0
  305. package/dist/core/runtime/placement.d.ts +17 -1
  306. package/dist/core/runtime/placement.js +1 -1
  307. package/dist/core/runtime/provider-credential-gate.d.ts +6 -2
  308. package/dist/core/runtime/provider-credential-gate.js +2 -2
  309. package/dist/core/runtime/recovery-hold.d.ts +21 -2
  310. package/dist/core/runtime/recovery-hold.js +2 -1
  311. package/dist/core/runtime/recycle.js +1 -1
  312. package/dist/core/runtime/reset.js +1 -1
  313. package/dist/core/runtime/revive.d.ts +2 -2
  314. package/dist/core/runtime/revive.js +2 -2
  315. package/dist/core/runtime/runner/blaxel/client.d.ts +81 -0
  316. package/dist/core/runtime/runner/blaxel/client.js +1 -0
  317. package/dist/core/runtime/runner/blaxel/image-build.d.ts +74 -0
  318. package/dist/core/runtime/runner/blaxel/image-build.js +5 -0
  319. package/dist/core/runtime/runner/blaxel/runner.d.ts +41 -0
  320. package/dist/core/runtime/runner/blaxel/runner.js +3 -0
  321. package/dist/core/runtime/runner/index.d.ts +8 -0
  322. package/dist/core/runtime/runner/index.js +1 -0
  323. package/dist/core/runtime/runner/process.d.ts +11 -0
  324. package/dist/core/runtime/runner/process.js +1 -0
  325. package/dist/core/runtime/runner/types.d.ts +95 -0
  326. package/dist/core/runtime/runner/types.js +0 -0
  327. package/dist/core/runtime/situational-context.d.ts +3 -6
  328. package/dist/core/runtime/situational-context.js +2 -2
  329. package/dist/core/runtime/situational-live.js +1 -1
  330. package/dist/core/runtime/spawn-env-rows.d.ts +5 -0
  331. package/dist/core/runtime/spawn-env-rows.js +1 -0
  332. package/dist/core/runtime/spawn-env.d.ts +4 -18
  333. package/dist/core/runtime/spawn-env.js +1 -1
  334. package/dist/core/runtime/spawn.js +2 -2
  335. package/dist/core/runtime/stop-guard.d.ts +1 -1
  336. package/dist/core/runtime/stop-guard.js +2 -8
  337. package/dist/core/runtime/structured-output.d.ts +0 -67
  338. package/dist/core/runtime/structured-output.js +3 -8
  339. package/dist/core/runtime/tmux-driver.d.ts +8 -0
  340. package/dist/core/runtime/tmux-driver.js +6 -6
  341. package/dist/core/runtime/view-socket.d.ts +20 -0
  342. package/dist/core/runtime/view-socket.js +3 -1
  343. package/dist/core/runtime/warm-pool.d.ts +13 -1
  344. package/dist/core/runtime/warm-pool.js +1 -1
  345. package/dist/core/scoped-state/legacy-profiles.d.ts +11 -0
  346. package/dist/core/scoped-state/legacy-profiles.js +1 -0
  347. package/dist/core/scoped-state/materialized-plugins.d.ts +18 -0
  348. package/dist/core/scoped-state/materialized-plugins.js +1 -0
  349. package/dist/core/scoped-state/migrate.d.ts +8 -1
  350. package/dist/core/scoped-state/migrate.js +3 -3
  351. package/dist/core/scoped-state/person-rows.d.ts +10 -0
  352. package/dist/core/scoped-state/person-rows.js +6 -0
  353. package/dist/core/scoped-state/person-store.d.ts +72 -0
  354. package/dist/core/scoped-state/person-store.js +1 -0
  355. package/dist/core/secrets/blaxel-launch.d.ts +24 -0
  356. package/dist/core/secrets/blaxel-launch.js +4 -0
  357. package/dist/core/secrets/blaxel-register.d.ts +2 -0
  358. package/dist/core/secrets/blaxel-register.js +1 -0
  359. package/dist/core/secrets/env-rows.d.ts +17 -0
  360. package/dist/core/secrets/env-rows.js +4 -0
  361. package/dist/core/secrets/environment-owner.d.ts +8 -0
  362. package/dist/core/secrets/environment-owner.js +1 -0
  363. package/dist/core/secrets/environment-secrets.d.ts +14 -0
  364. package/dist/core/secrets/environment-secrets.js +1 -0
  365. package/dist/core/secrets/index.d.ts +2 -0
  366. package/dist/core/secrets/index.js +1 -0
  367. package/dist/core/secrets/key.d.ts +3 -0
  368. package/dist/core/secrets/key.js +2 -0
  369. package/dist/core/secrets/seal.d.ts +18 -0
  370. package/dist/core/secrets/seal.js +1 -0
  371. package/dist/core/spaces/mounts.d.ts +1 -1
  372. package/dist/core/spaces/mounts.js +1 -1
  373. package/dist/core/spaces/process.d.ts +1 -1
  374. package/dist/core/spaces/stop.d.ts +7 -5
  375. package/dist/core/spaces/stop.js +2 -2
  376. package/dist/core/spaces/users.d.ts +2 -1
  377. package/dist/core/spaces/users.js +1 -1
  378. package/dist/core/storage/attachments.d.ts +11 -8
  379. package/dist/core/storage/attachments.js +1 -1
  380. package/dist/core/storage/tables.d.ts +4 -0
  381. package/dist/core/storage/tables.js +3 -3
  382. package/dist/core/subscription-state.d.ts +34 -72
  383. package/dist/core/subscription-state.js +1 -4
  384. package/dist/core/substrate/delivery/plan.js +1 -1
  385. package/dist/core/user-settings.js +1 -1
  386. package/dist/daemon/api/app-listener.js +10 -10
  387. package/dist/daemon/api/auth/person-bearer.d.ts +14 -0
  388. package/dist/daemon/api/auth/person-bearer.js +1 -0
  389. package/dist/daemon/api/bridge.js +4 -4
  390. package/dist/daemon/api/document-listener.js +3 -3
  391. package/dist/daemon/api/environment-of.d.ts +18 -0
  392. package/dist/daemon/api/environment-of.js +5 -0
  393. package/dist/daemon/api/handlers/analytics.js +1 -1
  394. package/dist/daemon/api/handlers/app-profiles.d.ts +2 -2
  395. package/dist/daemon/api/handlers/app-profiles.js +1 -1
  396. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  397. package/dist/daemon/api/handlers/bash.js +1 -1
  398. package/dist/daemon/api/handlers/broker-ops.d.ts +3 -0
  399. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  400. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  401. package/dist/daemon/api/handlers/broker-signals.d.ts +0 -3
  402. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  403. package/dist/daemon/api/handlers/canvas.js +4 -4
  404. package/dist/daemon/api/handlers/charges.d.ts +1 -1
  405. package/dist/daemon/api/handlers/charges.js +1 -1
  406. package/dist/daemon/api/handlers/conversations.d.ts +2 -0
  407. package/dist/daemon/api/handlers/conversations.js +3 -0
  408. package/dist/daemon/api/handlers/crons.js +1 -1
  409. package/dist/daemon/api/handlers/daemon.js +1 -1
  410. package/dist/daemon/api/handlers/delivery.d.ts +1 -1
  411. package/dist/daemon/api/handlers/delivery.js +1 -1
  412. package/dist/daemon/api/handlers/docs.js +1 -1
  413. package/dist/daemon/api/handlers/exec.js +1 -1
  414. package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
  415. package/dist/daemon/api/handlers/execution-start.js +2 -0
  416. package/dist/daemon/api/handlers/files.js +1 -1
  417. package/dist/daemon/api/handlers/git-credential.d.ts +11 -0
  418. package/dist/daemon/api/handlers/git-credential.js +1 -0
  419. package/dist/daemon/api/handlers/hook-exec.d.ts +1 -1
  420. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  421. package/dist/daemon/api/handlers/human-requests.js +1 -1
  422. package/dist/daemon/api/handlers/inbox.js +1 -1
  423. package/dist/daemon/api/handlers/messages.js +1 -1
  424. package/dist/daemon/api/handlers/model-config.js +1 -1
  425. package/dist/daemon/api/handlers/modelauth.d.ts +1 -1
  426. package/dist/daemon/api/handlers/modelauth.js +1 -1
  427. package/dist/daemon/api/handlers/node-events.d.ts +6 -0
  428. package/dist/daemon/api/handlers/node-events.js +3 -3
  429. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  430. package/dist/daemon/api/handlers/node-records.js +3 -2
  431. package/dist/daemon/api/handlers/nodes.js +1 -1
  432. package/dist/daemon/api/handlers/objects.js +3 -3
  433. package/dist/daemon/api/handlers/profiles.js +1 -1
  434. package/dist/daemon/api/handlers/providers.js +1 -1
  435. package/dist/daemon/api/handlers/reports.js +9 -13
  436. package/dist/daemon/api/handlers/reviews.js +1 -1
  437. package/dist/daemon/api/handlers/runs.js +1 -1
  438. package/dist/daemon/api/handlers/settings.d.ts +2 -0
  439. package/dist/daemon/api/handlers/settings.js +1 -0
  440. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  441. package/dist/daemon/api/handlers/vendor-status.d.ts +1 -1
  442. package/dist/daemon/api/handlers/vendor-status.js +1 -1
  443. package/dist/daemon/api/handlers/worktree.js +1 -1
  444. package/dist/daemon/api/map.d.ts +2 -2
  445. package/dist/daemon/api/map.js +2 -2
  446. package/dist/daemon/api/operations.js +1 -1
  447. package/dist/daemon/api/reader.d.ts +8 -1
  448. package/dist/daemon/api/reader.js +1 -1
  449. package/dist/daemon/api/router.d.ts +4 -2
  450. package/dist/daemon/api/router.js +1 -1
  451. package/dist/daemon/api/server.d.ts +15 -3
  452. package/dist/daemon/api/server.js +1 -1
  453. package/dist/daemon/api/vendor-signin.d.ts +2 -1
  454. package/dist/daemon/api/vendor-signin.js +19 -19
  455. package/dist/daemon/api/viewer-presence.d.ts +20 -6
  456. package/dist/daemon/api/viewer-presence.js +2 -1
  457. package/dist/daemon/boot-settings.d.ts +3 -0
  458. package/dist/daemon/boot-settings.js +1 -0
  459. package/dist/daemon/broker-signals/bus.d.ts +48 -11
  460. package/dist/daemon/broker-signals/bus.js +1 -1
  461. package/dist/daemon/cron/armed-context.js +1 -1
  462. package/dist/daemon/cron/lease-recovery.js +1 -1
  463. package/dist/daemon/cron/live-runs.d.ts +6 -0
  464. package/dist/daemon/cron/live-runs.js +1 -1
  465. package/dist/daemon/cron/run-socket.js +1 -1
  466. package/dist/daemon/cron-run.js +2 -2
  467. package/dist/daemon/crtrd-cli.js +1 -1
  468. package/dist/daemon/crtrd.d.ts +10 -0
  469. package/dist/daemon/crtrd.js +18 -17
  470. package/dist/daemon/delivery/run-delivery.d.ts +1 -1
  471. package/dist/daemon/delivery/run-delivery.js +1 -1
  472. package/dist/daemon/due-sources.d.ts +1 -1
  473. package/dist/daemon/due-sources.js +1 -1
  474. package/dist/daemon/due.js +7 -6
  475. package/dist/daemon/fleet.d.ts +6 -6
  476. package/dist/daemon/fleet.js +9 -9
  477. package/dist/daemon/park-activity.d.ts +2 -1
  478. package/dist/daemon/park-activity.js +1 -1
  479. package/dist/daemon/park-pending.d.ts +20 -13
  480. package/dist/daemon/park-pending.js +3 -1
  481. package/dist/daemon/profile-delete.js +1 -1
  482. package/dist/daemon/reconcilers/bash-deadline.d.ts +15 -10
  483. package/dist/daemon/reconcilers/bash-deadline.js +1 -3
  484. package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -3
  485. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  486. package/dist/daemon/reconcilers/cron-lane.d.ts +0 -1
  487. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  488. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +2 -9
  489. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  490. package/dist/daemon/reconcilers/grant-effects.d.ts +8 -0
  491. package/dist/daemon/reconcilers/grant-effects.js +1 -0
  492. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +1 -3
  493. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  494. package/dist/daemon/reconcilers/ledger-r2.d.ts +27 -0
  495. package/dist/daemon/reconcilers/ledger-r2.js +7 -0
  496. package/dist/daemon/reconcilers/ledger-sandbox.d.ts +55 -0
  497. package/dist/daemon/reconcilers/ledger-sandbox.js +9 -0
  498. package/dist/daemon/reconcilers/ledger-storage.d.ts +22 -0
  499. package/dist/daemon/reconcilers/ledger-storage.js +5 -0
  500. package/dist/daemon/reconcilers/live-obligation.d.ts +3 -2
  501. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  502. package/dist/daemon/reconcilers/managed-worktree-sweep.d.ts +0 -5
  503. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  504. package/dist/daemon/reconcilers/node-deadline.d.ts +2 -1
  505. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  506. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -2
  507. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  508. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +31 -0
  509. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -0
  510. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.d.ts +5 -0
  511. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.js +2 -0
  512. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  513. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  514. package/dist/daemon/reconcilers/recipe-image.d.ts +49 -0
  515. package/dist/daemon/reconcilers/recipe-image.js +7 -0
  516. package/dist/daemon/reconcilers/row-claim.d.ts +19 -0
  517. package/dist/daemon/reconcilers/row-claim.js +2 -0
  518. package/dist/daemon/reconcilers/storage-due-work.d.ts +18 -3
  519. package/dist/daemon/reconcilers/storage-due-work.js +2 -1
  520. package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -13
  521. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  522. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  523. package/dist/daemon/reconcilers/throttled-lane.d.ts +11 -0
  524. package/dist/daemon/reconcilers/throttled-lane.js +1 -0
  525. package/dist/daemon/review/finish.js +1 -1
  526. package/dist/daemon/run-notices.d.ts +3 -0
  527. package/dist/daemon/run-notices.js +1 -1
  528. package/dist/daemon/runs/append-section.d.ts +4 -1
  529. package/dist/daemon/runs/append-section.js +2 -2
  530. package/dist/daemon/runs/observer.d.ts +3 -2
  531. package/dist/daemon/runs/observer.js +3 -2
  532. package/dist/daemon/runs/view-transport.d.ts +19 -0
  533. package/dist/daemon/runs/view-transport.js +1 -0
  534. package/dist/daemon/structured-requests/boot.d.ts +2 -1
  535. package/dist/daemon/structured-requests/boot.js +1 -1
  536. package/dist/daemon/structured-requests/effects.d.ts +4 -3
  537. package/dist/daemon/structured-requests/effects.js +1 -1
  538. package/dist/daemon/structured-requests/notifier.d.ts +2 -0
  539. package/dist/daemon/structured-requests/notifier.js +1 -1
  540. package/dist/daemon/structured-requests/sidecar.d.ts +4 -3
  541. package/dist/daemon/structured-requests/sidecar.js +1 -1
  542. package/dist/launcher/validate.js +1 -1
  543. package/dist/migrations/004-canvas-documents/index.js +2 -2
  544. package/dist/pi-extensions/broker-local.d.ts +3 -3
  545. package/dist/pi-extensions/broker-local.js +1 -2
  546. package/dist/pi-extensions/canvas-bash-valve.js +6 -6
  547. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  548. package/dist/pi-extensions/canvas-elapsed.js +2 -2
  549. package/dist/pi-extensions/canvas-goal-capture.js +1 -1
  550. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  551. package/dist/pi-extensions/canvas-review-boundary.d.ts +11 -1
  552. package/dist/pi-extensions/canvas-review-boundary.js +3 -3
  553. package/dist/pi-extensions/canvas-stophook.js +1 -1
  554. package/dist/pi-extensions/canvas-structured-output.d.ts +5 -3
  555. package/dist/pi-extensions/canvas-structured-output.js +6 -11
  556. package/dist/pi-extensions/canvas-tool-guide.d.ts +9 -2
  557. package/dist/pi-extensions/canvas-tool-guide.js +6 -6
  558. package/dist/shared/inbox-entry-body.js +7 -7
  559. package/dist/types.d.ts +12 -0
  560. package/docs/sdk/release-notes.md +4 -0
  561. package/package.json +7 -4
  562. package/packages/crouter-identity/package.json +1 -1
  563. package/runtime.lock.json +13 -13
  564. package/scripts/git-credential-crtr +33 -0
  565. package/scripts/sandbox-bootstrap.sh +54 -0
  566. package/scripts/sandbox-start.mjs +320 -0
  567. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +0 -78
  568. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +0 -1179
  569. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +0 -1406
  570. package/dist/core/conversation-store/file-store.d.ts +0 -37
  571. package/dist/core/conversation-store/file-store.js +0 -9
  572. package/dist/core/conversation-store/listener.d.ts +0 -4
  573. package/dist/core/conversation-store/listener.js +0 -8
  574. package/dist/core/scoped-state/profiles.d.ts +0 -27
  575. package/dist/core/scoped-state/profiles.js +0 -1
  576. package/dist/core/scoped-state/providers.d.ts +0 -24
  577. package/dist/core/scoped-state/providers.js +0 -1
  578. package/dist/core/scoped-state/settings.d.ts +0 -28
  579. package/dist/core/scoped-state/settings.js +0 -1
@@ -3,4 +3,7 @@ import type { CanvasDb } from '../../core/canvas/db.js';
3
3
  export declare const TURN_INPUT_TYPE = "crtr-turn-input";
4
4
  export declare const SYSTEM_PROMPT_TYPE = "crtr-system-prompt";
5
5
  export declare const TURN_END_TYPE = "crtr-turn-end";
6
- export declare function appendConversationEvents(db: CanvasDb, runId: string, nodeId: string, entries: SessionEntry[], pendingInputIds: string[]): Promise<string[]>;
6
+ /** The one run-status input that reads files (the armed structured-output request). A caller inside a write transaction
7
+ * computes it first, outside the transaction, and passes it to `appendConversationEvents`. */
8
+ export declare function rootRepromptPending(runId: string, nodeId: string, entries: SessionEntry[]): Promise<boolean>;
9
+ export declare function appendConversationEvents(db: CanvasDb, runId: string, nodeId: string, entries: SessionEntry[], pendingInputIds: string[], repromptPending?: boolean): Promise<string[]>;
@@ -1,2 +1,2 @@
1
- var w=Object.defineProperty;var u=(t,e)=>w(t,"name",{value:e,configurable:!0});import{appendRunEvent as _}from"../../core/runs/events.js";import{openQuestionIds as R}from"../../core/runs/questions.js";import{getNode as T}from"../../core/canvas/canvas.js";import{payerOfGrant as x}from"../../core/grants/mirror.js";import{runSchemaRepromptPending as N}from"../../core/runtime/stop-guard.js";const h="crtr-turn-input",S="crtr-system-prompt",k="crtr-turn-end",f=u(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"zero");function D(t){return typeof t=="string"?t:Array.isArray(t)?t.filter(e=>typeof e?.text=="string").map(e=>e.text).join(`
2
- `):""}u(D,"text");function O(t){if(t==null)return;const{code:e,message:r}=t;if(e!=="content_refused"&&e!=="model_error"||typeof r!="string")throw new Error("invalid crtr-turn-end error");return{code:e,message:r}}u(O,"turnEndError");function j(t){return{input_tokens:t.input??0,output_tokens:t.output??0,cache_read_tokens:t.cacheRead??0,cache_write_tokens:t.cacheWrite??0,cost_usd:t.cost?.total??0}}u(j,"usageParts");async function H(t,e,r,E,g){let d=g;for(const o of E){if(o.type==="custom"&&o.customType===h){const n=o.data?.message_ids;if(!Array.isArray(n)||!n.every(i=>typeof i=="string"))throw new Error("invalid crtr-turn-input message_ids");d=[...new Set([...d,...n])]}if(o.type==="custom"&&o.customType===S){const n=o.data?.text;if(typeof n!="string")throw new Error("invalid crtr-system-prompt text");await _(t,e,r,"node.system_prompt.set",{entry_id:o.id,text:n})}if(o.type==="custom"&&o.customType===k){const n=o.data,i=n?.stop_reason;if(typeof i!="string")throw new Error("invalid crtr-turn-end stop_reason");const a=O(n?.error),s=await t.prepare("SELECT body_json FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'node.turn.started' ORDER BY sequence_number DESC LIMIT 1").get(e,r);if(!s)throw new Error("crtr-turn-end without node.turn.started");const{input:p}=JSON.parse(s.body_json),m=await t.prepare("SELECT status, pi_pid FROM node_rows WHERE run_id = ? AND node_id != ?").all(e,r),c=r===e?await T(e):null,l=m.some(y=>y.pi_pid!==null&&y.status==="active")||c!==null&&await N(c)?"running":(await R(e,t)).length?"waiting_on_user":"idle";await _(t,e,r,"node.turn.completed",{entry_id:o.id,message_ids:p.message_ids,run_status:l,stop_reason:i,...a?{error:a}:{}}),r===e&&await t.prepare("UPDATE nodes SET last_turn_error_json = ? WHERE node_id = ?").run(a?JSON.stringify(a):null,e)}if(o.type==="message"){const n=o.message;if(n.role==="user"){const i=await t.prepare("SELECT type, body_json FROM run_events WHERE run_id = ? AND node_id = ? AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1").get(e,r),a=i?.type==="node.turn.started"?JSON.parse(i.body_json).input.message_ids:[];await _(t,e,r,"node.turn.started",{entry_id:o.id,input:{text:D(n.content),message_ids:[...new Set([...a,...d])]}}),d=[]}if(n.role==="assistant"){let i=!1;const a=u(async()=>{if(i)return;i=!0;const s=n.content.filter(p=>p.type==="text").map(p=>p.text).join("");await _(t,e,r,"node.output_text.done",{entry_id:o.id,text:s,stop_reason:n.stopReason})},"doneText");for(const s of n.content)s.type==="thinking"&&await _(t,e,r,"node.thinking.done",{entry_id:o.id,text:s.thinking}),s.type==="text"&&await a(),s.type==="toolCall"&&(await a(),await _(t,e,r,"node.tool_call.started",{entry_id:o.id,tool_call_id:s.id,name:s.name,arguments:s.arguments}));if(await a(),n.usage){const s=j(n.usage),p=await t.prepare("SELECT usage_json, grant_id FROM nodes WHERE node_id = ?").get(e),m=p.usage_json?JSON.parse(p.usage_json):f(),c=f();for(const l of Object.keys(c))c[l]=m[l]+s[l];await t.prepare("UPDATE nodes SET usage_json = ? WHERE node_id = ?").run(JSON.stringify(c),e),await _(t,e,r,"usage",{entry_id:o.id,served_model:n.model,payer:await x(p.grant_id),...s,usage:c})}await t.prepare("DELETE FROM run_events WHERE run_id = ? AND node_id = ? AND type IN ('node.thinking.delta', 'node.output_text.delta')").run(e,r)}n.role==="toolResult"&&await _(t,e,r,"node.tool_call.completed",{entry_id:o.id,tool_call_id:n.toolCallId,name:n.toolName,result:n.content,status:n.isError?"error":"ok"})}}return d}u(H,"appendConversationEvents");export{S as SYSTEM_PROMPT_TYPE,k as TURN_END_TYPE,h as TURN_INPUT_TYPE,H as appendConversationEvents};
1
+ var T=Object.defineProperty;var _=(t,e)=>T(t,"name",{value:e,configurable:!0});import{appendRunEvent as c}from"../../core/runs/events.js";import{openQuestionIds as x}from"../../core/runs/questions.js";import{getNode as N}from"../../core/canvas/canvas.js";import{payerOfGrant as h}from"../../core/grants/mirror.js";import{runSchemaRepromptPending as S}from"../../core/runtime/stop-guard.js";const k="crtr-turn-input",D="crtr-system-prompt",g="crtr-turn-end",w=_(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"zero");function O(t){return typeof t=="string"?t:Array.isArray(t)?t.filter(e=>typeof e?.text=="string").map(e=>e.text).join(`
2
+ `):""}_(O,"text");function j(t){if(t==null)return;const{code:e,message:n}=t;if(e!=="content_refused"&&e!=="model_error"||typeof n!="string")throw new Error("invalid crtr-turn-end error");return{code:e,message:n}}_(j,"turnEndError");function A(t){return{input_tokens:t.input??0,output_tokens:t.output??0,cache_read_tokens:t.cacheRead??0,cache_write_tokens:t.cacheWrite??0,cost_usd:t.cost?.total??0}}_(A,"usageParts");async function v(t,e,n){if(e!==t||!n.some(f=>f.type==="custom"&&f.customType===g))return!1;const m=await N(t);return m!==null&&await S(m)}_(v,"rootRepromptPending");async function Y(t,e,n,m,f,R){let d=f;for(const r of m){if(r.type==="custom"&&r.customType===k){const o=r.data?.message_ids;if(!Array.isArray(o)||!o.every(i=>typeof i=="string"))throw new Error("invalid crtr-turn-input message_ids");d=[...new Set([...d,...o])]}if(r.type==="custom"&&r.customType===D){const o=r.data?.text;if(typeof o!="string")throw new Error("invalid crtr-system-prompt text");await c(t,e,n,"node.system_prompt.set",{entry_id:r.id,text:o})}if(r.type==="custom"&&r.customType===g){const o=r.data,i=o?.stop_reason;if(typeof i!="string")throw new Error("invalid crtr-turn-end stop_reason");const a=j(o?.error),s=await t.prepare("SELECT body_json FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'node.turn.started' ORDER BY sequence_number DESC LIMIT 1").get(e,n);if(!s)throw new Error("crtr-turn-end without node.turn.started");const{input:p}=JSON.parse(s.body_json),y=await t.prepare("SELECT status, pi_pid FROM node_rows WHERE run_id = ? AND node_id != ?").all(e,n),u=R??await v(e,n,[r]),l=y.some(E=>E.pi_pid!==null&&E.status==="active")||u?"running":(await x(e,t)).length?"waiting_on_user":"idle";await c(t,e,n,"node.turn.completed",{entry_id:r.id,message_ids:p.message_ids,run_status:l,stop_reason:i,...a?{error:a}:{}}),n===e&&await t.prepare("UPDATE nodes SET last_turn_error_json = ? WHERE node_id = ?").run(a?JSON.stringify(a):null,e)}if(r.type==="message"){const o=r.message;if(o.role==="user"){const i=await t.prepare("SELECT type, body_json FROM run_events WHERE run_id = ? AND node_id = ? AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1").get(e,n),a=i?.type==="node.turn.started"?JSON.parse(i.body_json).input.message_ids:[];await c(t,e,n,"node.turn.started",{entry_id:r.id,input:{text:O(o.content),message_ids:[...new Set([...a,...d])]}}),d=[]}if(o.role==="assistant"){let i=!1;const a=_(async()=>{if(i)return;i=!0;const s=o.content.filter(p=>p.type==="text").map(p=>p.text).join("");await c(t,e,n,"node.output_text.done",{entry_id:r.id,text:s,stop_reason:o.stopReason})},"doneText");for(const s of o.content)s.type==="thinking"&&await c(t,e,n,"node.thinking.done",{entry_id:r.id,text:s.thinking}),s.type==="text"&&await a(),s.type==="toolCall"&&(await a(),await c(t,e,n,"node.tool_call.started",{entry_id:r.id,tool_call_id:s.id,name:s.name,arguments:s.arguments}));if(await a(),o.usage){const s=A(o.usage),p=await t.prepare("SELECT usage_json, grant_id FROM nodes WHERE node_id = ?").get(e),y=p.usage_json?JSON.parse(p.usage_json):w(),u=w();for(const l of Object.keys(u))u[l]=y[l]+s[l];await t.prepare("UPDATE nodes SET usage_json = ? WHERE node_id = ?").run(JSON.stringify(u),e),await c(t,e,n,"usage",{entry_id:r.id,served_model:o.model,payer:await h(p.grant_id),...s,usage:u})}await t.prepare("DELETE FROM run_events WHERE run_id = ? AND node_id = ? AND type IN ('node.thinking.delta', 'node.output_text.delta')").run(e,n)}o.role==="toolResult"&&await c(t,e,n,"node.tool_call.completed",{entry_id:r.id,tool_call_id:o.toolCallId,name:o.toolName,result:o.content,status:o.isError?"error":"ok"})}}return d}_(Y,"appendConversationEvents");export{D as SYSTEM_PROMPT_TYPE,g as TURN_END_TYPE,k as TURN_INPUT_TYPE,Y as appendConversationEvents,v as rootRepromptPending};
@@ -1,4 +1,3 @@
1
- export declare function openAssistantMessageStartSequence(nodeId: string): number | null;
2
1
  /** What the model is streaming now in a node's open assistant message. */
3
2
  export type OpenAssistantBlock = {
4
3
  kind: 'thinking' | 'text';
@@ -6,8 +5,10 @@ export type OpenAssistantBlock = {
6
5
  kind: 'tool_call';
7
6
  name: string;
8
7
  };
8
+ /** The start sequence of the node's open assistant message, from the observer's columns; null when none is open or the node has no live broker. */
9
+ export declare function openAssistantMessageStartSequence(nodeId: string): Promise<number | null>;
9
10
  /** The newest block of the node's open assistant message; null when no message is open or nothing has streamed yet. */
10
- export declare function openAssistantBlock(nodeId: string): OpenAssistantBlock | null;
11
+ export declare function openAssistantBlock(nodeId: string): Promise<OpenAssistantBlock | null>;
11
12
  /** Test-only: stop every observer and wait out the polls in flight, so none touches a home the test is about to delete. */
12
13
  export declare function closeRunObserversForTests(): Promise<void>;
13
14
  export declare function ensureRunObserver(nodeId: string, runId: string): Promise<void>;
@@ -1,5 +1,6 @@
1
- var y=Object.defineProperty;var r=(n,t)=>y(n,"name",{value:t,configurable:!0});import{randomUUID as k}from"node:crypto";import{openDb as l}from"../../core/canvas/db.js";import{getNode as g}from"../../core/canvas/canvas.js";import{BrokerClient as D,SocketTransport as T}from"../../core/broker-client/client.js";import{emitRunEvent as p,emitRunSettlement as w}from"../../core/runs/events.js";import{cancelOpenQuestions as I}from"../../core/runs/questions.js";import{emitEvent as c}from"../../core/events/emit.js";import{toRunOutcomeDTO as N}from"../api/map.js";import{readOutputResult as R}from"../../core/runtime/structured-output.js";const b=JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),u=new Map,A=250;class m{static{r(this,"RunObserver")}nodeId;runId;client;timer;status;piPid=null;outcomeRevision;openAssistant=!1;assistantStartSequence=0;block=null;thinking="";output="";pendingThinking="";pendingOutput="";flushTimer;closed=!1;polling;frames=Promise.resolve();constructor(t,i,s,e){this.nodeId=t,this.runId=i,this.status=s,this.outcomeRevision=e,this.timer=setInterval(()=>{this.pollOrClose()},250),this.timer.unref(),u.set(t,this)}static async start(t,i){const s=await l(),e=await s.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = ? ORDER BY sequence_number DESC LIMIT 1").get(t,t===i?"node.settled":"child.settled"),o=await s.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = 'node.status.changed' ORDER BY sequence_number DESC LIMIT 1").get(t),d=new m(t,i,o?JSON.parse(o.body_json).status:void 0,e?JSON.parse(e.body_json).outcome.revision:void 0);return await d.poll(),d}async pollOrClose(){try{await this.poll()}catch(t){this.close(),c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:t})}}poll(){return this.polling===void 0&&(this.polling=this.pollOnce().finally(()=>{this.polling=void 0})),this.polling}async pollOnce(){const t=await g(this.nodeId);if(!t||t.run_id!==this.runId||!await E(this.runId)){this.close();return}this.piPid=t.pi_pid??null;const i=t.pi_pid===null?"dormant":t.status;this.status!==i&&await p(this.runId,this.nodeId,"node.status.changed",{status:i,reason:t.intent??null}),this.status=i;const s=N(t);if(s&&s.revision!==this.outcomeRevision&&Date.now()-Date.parse(s.settled_at)<720*60*6e4){if(this.nodeId===this.runId){const e=await(await l()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(this.runId,this.runId);for(const o of e)await v(o.node_id,this.runId),await u.get(o.node_id)?.poll()}if(this.outcomeRevision=s.revision,this.nodeId===this.runId){const e=s.kind==="result"?R(this.nodeId,t.grantee):void 0;await w(this.runId,this.nodeId,"node.settled",{outcome:s,usage:JSON.parse(t.usage_json??b),...e===void 0?{}:{result:e}})}else await w(this.runId,this.nodeId,"child.settled",{child_node_id:this.nodeId,outcome:s});if(t.grantee&&t.grantee!=="app:terminal"){const e=this.nodeId===this.runId?{run_id:this.runId}:{node_id:this.nodeId};I(e,this.nodeId===this.runId?"the run settled":"the asking node was closed").catch(o=>c({level:"error",event:"daemon.runs.question_cancel_failed",node_id:this.nodeId,error:o}))}}t.pi_pid===null?this.close():await this.connect()}async settlePoll(){await this.polling?.catch(()=>{}),await this.frames}get assistantMessageStartSequence(){return this.openAssistant&&this.client&&this.piPid!==null?this.assistantStartSequence:null}get openBlock(){return this.assistantMessageStartSequence===null?null:this.block}async connect(){if(this.client||this.closed)return;const t=new D(this.nodeId,{transport:new T(this.nodeId,{recordsViewerFaults:!1})});this.client=t,t.on("connect",()=>t.send({type:"hello",role:"observer",client_id:k(),attends:!1}));const i=r(async s=>{if(!(this.closed||this.client!==t)){if(s.type==="message_start"&&s.message.role==="assistant"&&(this.discardDeltas(),this.openAssistant=!0,this.block=null,this.thinking="",this.output="",this.assistantStartSequence=(await(await l()).prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(this.runId)).event_cursor),s.type==="message_update"&&s.message.role==="assistant"&&this.openAssistant){const e=s.message.content;if(!Array.isArray(e))return;const o=e.at(-1);o&&typeof o=="object"&&"type"in o&&(o.type==="toolCall"?this.block={kind:"tool_call",name:"name"in o&&typeof o.name=="string"?o.name:""}:(o.type==="text"||o.type==="thinking")&&(this.block={kind:o.type}));const d=e.filter(a=>a?.type==="thinking").map(a=>a.thinking).join(""),h=e.filter(a=>a?.type==="text").map(a=>a.text).join(""),S=d.startsWith(this.thinking)?d.slice(this.thinking.length):d,O=h.startsWith(this.output)?h.slice(this.output.length):h;this.thinking=d,this.output=h,this.pendingThinking+=S,this.pendingOutput+=O,(this.pendingThinking||this.pendingOutput)&&!this.flushTimer&&(this.flushTimer=setTimeout(()=>{this.flushDeltas().catch(a=>c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:a}))},A),this.flushTimer.unref())}s.type==="message_end"&&s.message.role==="assistant"&&(await this.flushDeltas(),this.openAssistant=!1,this.block=null)}},"handleFrame");t.on("frame",s=>{this.frames=this.frames.then(()=>i(s)).catch(e=>{this.close(),c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:e})})}),t.on("error",()=>{}),t.on("close",()=>{this.client===t&&(this.client=void 0,this.discardDeltas(),this.openAssistant=!1,this.block=null)}),t.connect()}async flushDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0;const t=this.pendingThinking,i=this.pendingOutput;if(this.pendingThinking="",this.pendingOutput="",!this.openAssistant||!t&&!i)return;if(await(await l()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND sequence_number >= ? AND type IN ('node.output_text.done', 'node.thinking.done', 'usage') LIMIT 1").get(this.runId,this.nodeId,this.assistantStartSequence)){this.openAssistant=!1;return}t&&await p(this.runId,this.nodeId,"node.thinking.delta",{delta:t}),i&&await p(this.runId,this.nodeId,"node.output_text.delta",{delta:i})}discardDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0,this.pendingThinking="",this.pendingOutput=""}close(){this.closed=!0,this.discardDeltas(),clearInterval(this.timer),u.delete(this.nodeId);const t=this.client;this.client=void 0,t?.close()}}function J(n){return u.get(n)?.assistantMessageStartSequence??null}r(J,"openAssistantMessageStartSequence");function Y(n){return u.get(n)?.openBlock??null}r(Y,"openAssistantBlock");async function G(){const n=[...u.values()];for(const t of n)t.close();await Promise.all(n.map(t=>t.settlePoll())),await Promise.all([...f.values()].map(t=>t.catch(()=>{})))}r(G,"closeRunObserversForTests");async function E(n){return await(await l()).prepare("SELECT 1 FROM nodes WHERE node_id = ? AND run_id = ? AND event_cursor IS NOT NULL").get(n,n)!==void 0}r(E,"runRootExists");const f=new Map;async function v(n,t){const i=f.get(n);if(i)return i;if(u.has(n))return;const s=L(n,t).finally(()=>f.delete(n));return f.set(n,s),s}r(v,"ensureRunObserver");async function L(n,t){if(await E(t)){if(n!==t){const i=await g(n);!await(await l()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'child.started' LIMIT 1").get(t,n)&&i&&Date.now()-Date.parse(i.created)<720*60*6e4&&await p(t,n,"child.started",{child_node_id:n,kind:i.kind})}await m.start(n,t)}}r(L,"startRunObserver");async function Q(){const n=new Date(Date.now()-2592e6).toISOString(),t=await(await l()).prepare(`SELECT n.node_id, n.run_id, n.pi_pid, COALESCE(n.outcome_revision, 1) AS revision, e.body_json
1
+ var k=Object.defineProperty;var l=(n,e)=>k(n,"name",{value:e,configurable:!0});import{randomUUID as v}from"node:crypto";import{openDb as d,withCanvasWrite as L}from"../../core/canvas/db.js";import{claimReconcilerLease as b,releaseReconcilerLease as O,renewReconcilerLease as C}from"../../core/canvas/reconciler-leases.js";import{getNode as R}from"../../core/canvas/canvas.js";import{BrokerClient as F,SocketTransport as y}from"../../core/broker-client/client.js";import{liveExecutionForNode as M}from"../../core/canvas/executions.js";import{runnerForExecution as x}from"../../core/runtime/runner/index.js";import{connectWssView as H}from"../../core/runtime/view-socket.js";import{ViewLinkTransport as W}from"./view-transport.js";import{emitRunEvent as w,emitRunSettlement as N,emitRunStatus as q}from"../../core/runs/events.js";import{cancelOpenQuestions as U}from"../../core/runs/questions.js";import{emitEvent as c}from"../../core/events/emit.js";import{toRunOutcomeDTO as j}from"../api/map.js";import{readOutputResult as J}from"../../core/runtime/output-result.js";const P=JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),p=new Map,h="run-observer",g=1e4,B=250;async function f(n,e,t){return await L(async i=>await i.prepare("SELECT 1 AS held FROM reconciler_leases WHERE lane = ? AND key = ? AND owner = ? AND expires_at > ? FOR SHARE").get(h,n,e,new Date().toISOString())===void 0?{held:!1}:{held:!0,value:await t()})}l(f,"whileHoldingLease");class S{static{l(this,"RunObserver")}nodeId;runId;owner;client;timer;status;piPid=null;outcomeRevision;openAssistant=!1;assistantStartSequence=0;block=null;thinking="";output="";pendingThinking="";pendingOutput="";flushTimer;closed=!1;lastRenewAt=Date.now();released=Promise.resolve();polling;frames=Promise.resolve();constructor(e,t,i,s,r){this.nodeId=e,this.runId=t,this.owner=i,this.status=s,this.outcomeRevision=r,this.timer=setInterval(()=>{this.pollOrClose()},250),this.timer.unref(),p.set(e,this)}static async start(e,t,i){const s=await d(),r=await s.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = ? ORDER BY sequence_number DESC LIMIT 1").get(e,e===t?"node.settled":"child.settled"),o=await s.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = 'node.status.changed' ORDER BY sequence_number DESC LIMIT 1").get(e),a=new S(e,t,i,o?JSON.parse(o.body_json).status:void 0,r?JSON.parse(r.body_json).outcome.revision:void 0);return await a.writeStream(null,null),await a.poll(),a}async pollOrClose(){try{await this.poll()}catch(e){this.close(),c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:e})}}poll(){return this.polling===void 0&&(this.polling=this.pollOnce().finally(()=>{this.polling=void 0})),this.polling}async holdLease(){return Date.now()-this.lastRenewAt<g/3?!0:await C(h,this.nodeId,this.owner,g)?(this.lastRenewAt=Date.now(),!0):!1}async writeStream(e,t,i=!1){return(await(await d()).prepare(`UPDATE nodes SET ${i?"":`stream_message_seq = ${e===null?"NULL":"(SELECT event_cursor FROM nodes WHERE node_id = ?)"},`} stream_block = ?
2
+ WHERE node_id = ? AND EXISTS (SELECT 1 FROM reconciler_leases WHERE lane = ? AND key = ? AND owner = ? AND expires_at > ?)`).run(...e===null||i?[]:[this.runId],t===null?null:JSON.stringify(t),this.nodeId,h,this.nodeId,this.owner,new Date().toISOString())).changes===1}async pollOnce(){if(this.closed)return;if(!await this.holdLease()){this.close();return}const e=await R(this.nodeId);if(!e||e.run_id!==this.runId||!await D(this.runId)){this.close();return}this.piPid=e.pi_pid??null;const t=e.pi_pid===null?"dormant":e.status;if(this.status!==t){if(!(await f(this.nodeId,this.owner,()=>q(this.runId,this.nodeId,t,e.intent??null))).held){this.close();return}this.status=t}const i=await j(e);if(i&&i.revision!==this.outcomeRevision&&Date.now()-Date.parse(i.settled_at)<720*60*6e4){if(this.nodeId===this.runId){const o=await(await d()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(this.runId,this.runId);for(const a of o)await T(a.node_id,this.runId),await p.get(a.node_id)?.poll()}this.outcomeRevision=i.revision;const s=this.nodeId===this.runId&&i.kind==="result"?await J(this.nodeId):void 0;if(!(await f(this.nodeId,this.owner,()=>this.nodeId===this.runId?N(this.runId,this.nodeId,"node.settled",{outcome:i,usage:JSON.parse(e.usage_json??P),...s===void 0?{}:{result:s}}):N(this.runId,this.nodeId,"child.settled",{child_node_id:this.nodeId,outcome:i}))).held){this.close();return}if(e.grantee&&e.grantee!=="app:terminal"){const o=this.nodeId===this.runId?{run_id:this.runId}:{node_id:this.nodeId};U(o,this.nodeId===this.runId?"the run settled":"the asking node was closed").catch(a=>c({level:"error",event:"daemon.runs.question_cancel_failed",node_id:this.nodeId,error:a}))}}e.pi_pid===null?this.close():await this.connect()}async settlePoll(){await this.polling?.catch(()=>{}),await this.frames,await this.released}async connect(){if(this.client||this.closed)return;const e=await V(this.nodeId);if(this.client||this.closed){e.destroy();return}const t=new F(this.nodeId,{transport:e});this.client=t,t.on("connect",()=>t.send({type:"hello",role:"observer",client_id:v(),attends:!1}));const i=l(async s=>{if(!(this.closed||this.client!==t)){if(s.type==="message_start"&&s.message.role==="assistant"){if(this.discardDeltas(),this.openAssistant=!0,this.block=null,this.thinking="",this.output="",!await this.writeStream("run-cursor",null)){this.close();return}this.assistantStartSequence=Number((await(await d()).prepare("SELECT stream_message_seq FROM nodes WHERE node_id = ?").get(this.nodeId)).stream_message_seq)}if(s.type==="message_update"&&s.message.role==="assistant"&&this.openAssistant){const r=s.message.content;if(!Array.isArray(r))return;const o=r.at(-1);if(o&&typeof o=="object"&&"type"in o&&(o.type==="toolCall"?this.block={kind:"tool_call",name:"name"in o&&typeof o.name=="string"?o.name:""}:(o.type==="text"||o.type==="thinking")&&(this.block={kind:o.type})),!await this.writeStream(null,this.block,!0)){this.close();return}const a=r.filter(u=>u?.type==="thinking").map(u=>u.thinking).join(""),_=r.filter(u=>u?.type==="text").map(u=>u.text).join(""),A=a.startsWith(this.thinking)?a.slice(this.thinking.length):a,I=_.startsWith(this.output)?_.slice(this.output.length):_;this.thinking=a,this.output=_,this.pendingThinking+=A,this.pendingOutput+=I,(this.pendingThinking||this.pendingOutput)&&!this.flushTimer&&(this.flushTimer=setTimeout(()=>{this.flushDeltas().catch(u=>c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:u}))},B),this.flushTimer.unref())}s.type==="message_end"&&s.message.role==="assistant"&&(await this.flushDeltas(),this.openAssistant=!1,this.block=null,await this.writeStream(null,null))}},"handleFrame");t.on("frame",s=>{this.frames=this.frames.then(()=>i(s)).catch(r=>{this.close(),c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:r})})}),t.on("error",()=>{}),t.on("close",()=>{this.client===t&&(this.client=void 0,this.discardDeltas(),this.openAssistant=!1,this.block=null,this.released=this.released.then(async()=>{await this.writeStream(null,null)}).catch(()=>{}))}),t.connect()}async flushDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0;const e=this.pendingThinking,t=this.pendingOutput;if(this.pendingThinking="",this.pendingOutput="",!this.openAssistant||!e&&!t)return;(await f(this.nodeId,this.owner,async()=>{if(await(await d()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND sequence_number >= ? AND type IN ('node.output_text.done', 'node.thinking.done', 'usage') LIMIT 1").get(this.runId,this.nodeId,this.assistantStartSequence)){this.openAssistant=!1;return}e&&await w(this.runId,this.nodeId,"node.thinking.delta",{delta:e}),t&&await w(this.runId,this.nodeId,"node.output_text.delta",{delta:t})})).held||this.close()}discardDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0,this.pendingThinking="",this.pendingOutput=""}close(){if(this.closed)return;this.closed=!0,this.discardDeltas(),clearInterval(this.timer),p.delete(this.nodeId),this.released=this.released.then(async()=>{await this.writeStream(null,null),await O(h,this.nodeId,this.owner)}).then(()=>{}).catch(t=>{c({level:"error",event:"daemon.runs.observer_release_failed",node_id:this.nodeId,error:t})});const e=this.client;this.client=void 0,e?.close()}}async function V(n){const e=await M(n);if(e===null)return new y(n,{recordsViewerFaults:!1});const t=await x(e.runner).viewerAddress(e);return t.kind==="unix"?new y(n,{recordsViewerFaults:!1}):new W(n,()=>H(t.url,t.headers))}l(V,"viewTransport");async function de(n){const e=await(await d()).prepare("SELECT stream_message_seq FROM node_rows WHERE node_id = ? AND pi_pid IS NOT NULL").get(n);return e?.stream_message_seq==null?null:Number(e.stream_message_seq)}l(de,"openAssistantMessageStartSequence");async function ue(n){const e=await(await d()).prepare("SELECT stream_message_seq, stream_block FROM node_rows WHERE node_id = ? AND pi_pid IS NOT NULL").get(n);return e?.stream_message_seq==null||e.stream_block===null?null:JSON.parse(e.stream_block)}l(ue,"openAssistantBlock");async function ce(){const n=[...p.values()];for(const e of n)e.close();await Promise.all(n.map(e=>e.settlePoll())),await Promise.all([...m.values()].map(e=>e.catch(()=>{})))}l(ce,"closeRunObserversForTests");async function D(n){return await(await d()).prepare("SELECT 1 FROM nodes WHERE node_id = ? AND run_id = ? AND event_cursor IS NOT NULL").get(n,n)!==void 0}l(D,"runRootExists");const m=new Map;async function T(n,e){const t=m.get(n);if(t)return t;if(p.has(n))return;const i=Y(n,e).finally(()=>m.delete(n));return m.set(n,i),i}l(T,"ensureRunObserver");async function Y(n,e){if(!await D(e))return;const t=v();if(await b(h,n,t,g)!==void 0)try{if(n!==e){const i=await R(n);if(!await(await d()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'child.started' LIMIT 1").get(e,n)&&i&&Date.now()-Date.parse(i.created)<720*60*6e4&&!(await f(n,t,()=>w(e,n,"child.started",{child_node_id:n,kind:i.kind}))).held)return}await S.start(n,e,t)}catch(i){throw await O(h,n,t).catch(()=>{}),i}}l(Y,"startRunObserver");async function he(){const n=new Date(Date.now()-2592e6).toISOString(),e=await(await d()).prepare(`SELECT n.node_id, n.run_id, n.pi_pid, COALESCE(n.outcome_revision, 1) AS revision, e.body_json
2
3
  FROM node_rows n
3
4
  LEFT JOIN run_events e ON n.pi_pid IS NULL AND e.run_id = n.run_id AND e.node_id = n.node_id
4
5
  AND e.type = CASE WHEN n.node_id = n.run_id THEN 'node.settled' ELSE 'child.settled' END
5
- WHERE n.run_id IS NOT NULL AND (n.pi_pid IS NOT NULL OR (n.outcome_at IS NOT NULL AND n.outcome_at > ? AND n.outcome_reason != 'parked'))`).all(n),i=new Map;for(const e of t){const o=i.get(e.node_id)??{node_id:e.node_id,run_id:e.run_id,reported:!1};e.body_json!==null&&JSON.parse(e.body_json).outcome?.revision===e.revision&&(o.reported=!0),i.set(e.node_id,o)}const s=[...i.values()].filter(e=>!e.reported);for(const e of s)try{await v(e.node_id,e.run_id),_.delete(e.node_id)}catch(o){M(e.node_id,o)}}r(Q,"pollRunObservers");const _=new Map;function M(n,t){const i=t instanceof Error?t.message:String(t);_.get(n)!==i&&(_.set(n,i),c({level:"error",event:"daemon.runs.observer_failed",node_id:n,error:t}))}r(M,"reportObserverFailure");export{G as closeRunObserversForTests,v as ensureRunObserver,Y as openAssistantBlock,J as openAssistantMessageStartSequence,Q as pollRunObservers};
6
+ WHERE n.run_id IS NOT NULL AND (n.pi_pid IS NOT NULL OR (n.outcome_at IS NOT NULL AND n.outcome_at > ? AND n.outcome_reason != 'parked'))`).all(n),t=new Map;for(const s of e){const r=t.get(s.node_id)??{node_id:s.node_id,run_id:s.run_id,reported:!1};s.body_json!==null&&JSON.parse(s.body_json).outcome?.revision===s.revision&&(r.reported=!0),t.set(s.node_id,r)}const i=[...t.values()].filter(s=>!s.reported);for(const s of i)try{await T(s.node_id,s.run_id),E.delete(s.node_id)}catch(r){$(s.node_id,r)}}l(he,"pollRunObservers");const E=new Map;function $(n,e){const t=e instanceof Error?e.message:String(e);E.get(n)!==t&&(E.set(n,t),c({level:"error",event:"daemon.runs.observer_failed",node_id:n,error:e}))}l($,"reportObserverFailure");export{ce as closeRunObserversForTests,T as ensureRunObserver,ue as openAssistantBlock,de as openAssistantMessageStartSequence,he as pollRunObservers};
@@ -0,0 +1,19 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { type RedialOptions, type Transport } from '../../core/broker-client/transport.js';
3
+ import { type ClientToBroker } from '../../core/runtime/broker-protocol.js';
4
+ import type { BrokerViewLink } from '../../core/runtime/view-socket.js';
5
+ export declare class ViewLinkTransport extends EventEmitter implements Transport {
6
+ private readonly nodeId;
7
+ private readonly open;
8
+ private link;
9
+ private decoder;
10
+ private closeEmitted;
11
+ constructor(nodeId: string, open: () => BrokerViewLink);
12
+ connect(): void;
13
+ redial(_options?: RedialOptions): Promise<void>;
14
+ send(frame: ClientToBroker): void;
15
+ destroy(): void;
16
+ private dial;
17
+ /** `error` is emitted only when a listener exists: a bare EventEmitter `error` throws. */
18
+ private emitError;
19
+ }
@@ -0,0 +1 @@
1
+ var h=Object.defineProperty;var n=(s,e)=>h(s,"name",{value:e,configurable:!0});import{EventEmitter as a}from"node:events";import{BrokerUnavailableError as m}from"../../core/broker-client/transport.js";import{CLIENT_READ_CAPS as d,encodeFrame as f,FrameDecoder as c}from"../../core/runtime/broker-protocol.js";class w extends a{static{n(this,"ViewLinkTransport")}nodeId;open;link;decoder=new c(d);closeEmitted=!1;constructor(e,t){super(),this.nodeId=e,this.open=t}connect(){this.dial(()=>this.emit("connect"))}redial(e){return this.destroy(),this.decoder=new c(d),this.closeEmitted=!1,new Promise((t,i)=>{let r=!1;const o=this.dial(()=>{r||(r=!0,this.emit("connect"),t())});o.on("error",l=>{r||(r=!0,o.destroy(),i(l))})})}send(e){if(!(this.link===void 0||this.link.destroyed))try{this.link.write(f(e))}catch{}}destroy(){this.link!==void 0&&!this.link.destroyed&&this.link.destroy()}dial(e){const t=this.open();return this.link=t,t.on("connect",e),t.on("data",i=>{let r;try{r=this.decoder.push(i)}catch(o){this.emitError(new Error(`failed to decode a broker frame: ${String(o)}`)),this.destroy();return}for(const o of r)this.emit("frame",o)}),t.on("error",i=>{const r=i.code==="ECONNREFUSED"||i.code==="ENOTFOUND";this.emitError(r?new m(this.nodeId):new Error(`broker view error: ${i.message}`))}),t.on("close",()=>{this.closeEmitted||(this.closeEmitted=!0,this.emit("close"))}),t}emitError(e){this.listenerCount("error")>0&&this.emit("error",e)}}export{w as ViewLinkTransport};
@@ -1,2 +1,3 @@
1
- /** Rebuild pending sidecars, settle pending requests on terminal nodes, and adopt pre-request-id sidecars. */
1
+ /** At boot, settle the pending request of every node that already ended. The request row is the only
2
+ * copy of a request, so nothing else needs rebuilding. */
2
3
  export declare function reconcileStructuredRequestSidecars(): Promise<void>;
@@ -1 +1 @@
1
- var o=Object.defineProperty;var n=(e,t)=>o(e,"name",{value:t,configurable:!0});import{listNodes as a}from"../../core/canvas/index.js";import{getPendingStructuredRequestForNode as u,registerLegacyStructuredRequest as s,settlePendingStructuredRequestForNode as c}from"../../core/canvas/structured-requests.js";import{readLegacyOutputRequest as l,readOutputRequest as f,writeStructuredRequestSidecar as d}from"../../core/runtime/structured-output.js";import{emitEvent as m}from"../../core/events/emit.js";function _(e){return e.status!=="done"&&e.status!=="dead"&&e.status!=="canceled"?null:e.terminal_reason==="deadline_exceeded"?{intended:"expired",failureReason:"node_deadline_exceeded"}:{intended:"failed",failureReason:e.terminal_reason??"finished"}}n(_,"terminalSettlement");async function y(){for(const e of await a())try{const t=_(e);t!==null&&await c(e.node_id,t);const i=await u(e.node_id);if(i!==null){d(i);continue}if(f(e.node_id).state==="valid"||t!==null)continue;const r=l(e.node_id);r!==null&&d(await s(e.node_id,r.mode,r.schema))}catch(t){m({level:"error",event:"structured_request.boot_reconcile_failed",node_id:e.node_id,error:t})}}n(y,"reconcileStructuredRequestSidecars");export{y as reconcileStructuredRequestSidecars};
1
+ var n=Object.defineProperty;var r=(e,t)=>n(e,"name",{value:t,configurable:!0});import{listNodes as i}from"../../core/canvas/index.js";import{settlePendingStructuredRequestForNode as d}from"../../core/canvas/structured-requests.js";import{emitEvent as o}from"../../core/events/emit.js";function a(e){return e.status!=="done"&&e.status!=="dead"&&e.status!=="canceled"?null:e.terminal_reason==="deadline_exceeded"?{intended:"expired",failureReason:"node_deadline_exceeded"}:{intended:"failed",failureReason:e.terminal_reason??"finished"}}r(a,"terminalSettlement");async function f(){for(const e of await i())try{const t=a(e);t!==null&&await d(e.node_id,t)}catch(t){o({level:"error",event:"structured_request.boot_reconcile_failed",node_id:e.node_id,error:t})}}r(f,"reconcileStructuredRequestSidecars");export{f as reconcileStructuredRequestSidecars};
@@ -1,4 +1,5 @@
1
1
  import { type StructuredRequestRow } from '../../core/canvas/structured-requests.js';
2
- import { type StagedStructuredProjection } from '../../core/runtime/structured-output.js';
3
- /** Replays only durable request-owned effects. A successful final never enters teardown. */
4
- export declare function applySettlementEffects(row: StructuredRequestRow, staged?: StagedStructuredProjection): Promise<void>;
2
+ import type { RowClaim } from '../reconcilers/row-claim.js';
3
+ /** Replays only durable request-owned effects. A successful final never enters teardown. A reconciler passes its row `claim`; each
4
+ * effect then first confirms the claim is still held, so a holder whose claim was taken over stops before enacting. */
5
+ export declare function applySettlementEffects(row: StructuredRequestRow, claim?: RowClaim): Promise<void>;
@@ -1 +1 @@
1
- var o=Object.defineProperty;var n=(e,d)=>o(e,"name",{value:d,configurable:!0});import{markStructuredRequestEffectsDone as l,ownsStructuredRequestDeclineProjection as _,ownsStructuredRequestResultProjection as f,registerStructuredRequestEffectRunner as m}from"../../core/canvas/structured-requests.js";import{getNode as a}from"../../core/canvas/index.js";import{emitEvent as p}from"../../core/events/emit.js";import{requestBrokerTeardown as q}from"../../core/runtime/host.js";import{transition as S}from"../../core/runtime/lifecycle.js";import{expireNodeDeadline as y}from"../reconcilers/node-deadline.js";import{installStagedStructuredProjection as c,readOutputRequest as g,removeOutputSchema as h,stageStructuredResult as x,writeOutputDeclined as D}from"../../core/runtime/structured-output.js";import{enqueueNodeMail as R}from"../../core/feed/messages.js";import{notifyStructuredRequest as v}from"./notifier.js";function b(e){if(e.node_id===null)return!1;const d=g(e.node_id);return d.state==="valid"&&d.request.request_id===e.request_id}n(b,"ownsCurrentSidecar");async function j(e,d){v(e.request_id);let s=!1,u=null;const r=n((t,i)=>{s=!0,p({level:"error",event:t,node_id:e.node_id??void 0,error:i,fields:{request_id:e.request_id}})},"report");if(e.node_id!==null&&e.state==="completed")try{const t=e.submission,i=(await a(e.node_id))?.grantee;await f(e)&&(u=d===void 0?c(x(e.node_id,e.request_id,t,e.result,i)):c(d))}catch(t){r("structured_request.projection_failed",t)}if(e.node_id!==null&&e.state==="declined"&&await _(e)&&e.declined!==null)try{u=D(e.node_id,{mode:e.submission,...e.declined,at:new Date(e.settled_at??Date.now()).toISOString()},(await a(e.node_id))?.grantee)}catch(t){r("structured_request.decline_projection_failed",t)}if(e.node_id!==null&&b(e))try{h(e.node_id,e.request_id)}catch(t){r("structured_request.sidecar_remove_failed",t)}if(e.node_id!==null&&!e.dedicated&&e.state==="expired")try{await R(e.node_id,{kind:"urgent",label:`Structured request ${e.request_id} expired`,bodyJson:{body:`Structured request ${e.request_id} expired. Stop trying to answer it; this request can no longer accept a result.`},urgency:"urgent",wake:1,idempotencyKey:`structured-request-expiry:${e.request_id}`})}catch(t){r("structured_request.expiry_notice_failed",t)}if(e.node_id!==null&&e.dedicated&&(e.state==="expired"||e.state==="canceled"||e.state==="failed"))try{if(e.state==="expired")await y(e.node_id,new Date(e.deadline_at??Date.now()).toISOString(),Date.now());else{const t=await a(e.node_id);t!==null&&(t.status==="active"||t.status==="idle")&&await S(e.node_id,"cancel",{reason:"stranded"});const i=await q(e.node_id);if(!i.confirmed)throw i.error??new Error("broker teardown was not confirmed")}}catch(t){r("structured_request.teardown_failed",t)}s||await l(e.request_id,u)}n(j,"applySettlementEffects"),m(e=>{j(e)});export{j as applySettlementEffects};
1
+ var s=Object.defineProperty;var i=(e,r)=>s(e,"name",{value:r,configurable:!0});import{markStructuredRequestEffectsDone as u,registerStructuredRequestEffectRunner as o}from"../../core/canvas/structured-requests.js";import{getNode as c}from"../../core/canvas/index.js";import{emitEvent as f}from"../../core/events/emit.js";import{requestBrokerTeardown as l}from"../../core/runtime/host.js";import{transition as p}from"../../core/runtime/lifecycle.js";import{expireNodeDeadline as _}from"../reconcilers/node-deadline.js";import{enqueueNodeMail as m}from"../../core/feed/messages.js";import{notifyStructuredRequest as q}from"./notifier.js";async function y(e,r){q(e.request_id);let n=!1;const a=i((t,d)=>{n=!0,f({level:"error",event:t,node_id:e.node_id??void 0,error:d,fields:{request_id:e.request_id}})},"report");if(e.node_id!==null&&!e.dedicated&&e.state==="expired"){await r?.assertOwned();try{await m(e.node_id,{kind:"urgent",label:`Structured request ${e.request_id} expired`,bodyJson:{body:`Structured request ${e.request_id} expired. Stop trying to answer it; this request can no longer accept a result.`},urgency:"urgent",wake:1,idempotencyKey:`structured-request-expiry:${e.request_id}`})}catch(t){a("structured_request.expiry_notice_failed",t)}}if(e.node_id!==null&&e.dedicated&&(e.state==="expired"||e.state==="canceled"||e.state==="failed")){await r?.assertOwned();try{if(e.state==="expired")await _(e.node_id,new Date(e.deadline_at??Date.now()).toISOString(),Date.now(),r);else{const t=await c(e.node_id);t!==null&&(t.status==="active"||t.status==="idle")&&await p(e.node_id,"cancel",{reason:"stranded"});const d=await l(e.node_id);if(!d.confirmed)throw d.error??new Error("broker teardown was not confirmed")}}catch(t){a("structured_request.teardown_failed",t)}}n||await u(e.request_id,null)}i(y,"applySettlementEffects"),o(e=>{y(e)});export{y as applySettlementEffects};
@@ -1,2 +1,4 @@
1
+ /** Each waiter re-reads the request row when woken; a restarted LISTEN connection wakes all of them, since signals sent while it was down are lost. */
1
2
  export declare function subscribeStructuredRequest(requestId: string, listener: () => void): () => void;
3
+ /** Wakes the request's waiters in this process now and in every other process through `crtr_signal`. */
2
4
  export declare function notifyStructuredRequest(requestId: string): void;
@@ -1 +1 @@
1
- var r=Object.defineProperty;var s=(e,t)=>r(e,"name",{value:t,configurable:!0});const o=new Map;function u(e,t){const n=o.get(e)??new Set;return n.add(t),o.set(e,n),()=>{n.delete(t),n.size===0&&o.delete(e)}}s(u,"subscribeStructuredRequest");function i(e){for(const t of o.get(e)??[])t()}s(i,"notifyStructuredRequest");export{i as notifyStructuredRequest,u as subscribeStructuredRequest};
1
+ var c=Object.defineProperty;var n=(e,t)=>c(e,"name",{value:t,configurable:!0});import{brokerSignalBus as d}from"../broker-signals/bus.js";import{openDb as l}from"../../core/canvas/db.js";import{emitEvent as p}from"../../core/events/emit.js";const r=new Map;let s;function u(e){for(const t of r.get(e)??[])t()}n(u,"wakeAll");function g(e,t){const o=r.get(e)??new Set;return o.add(t),r.set(e,o),s??=d.subscribe(u,{kinds:["structured_request"],onListenStart:n(()=>{for(const i of[...r.keys()])u(i)},"onListenStart")}),()=>{if(o.delete(t),!(o.size>0)&&(r.delete(e),r.size===0)){const i=s;s=void 0,i?.then(f=>f())}}}n(g,"subscribeStructuredRequest");function S(e){u(e),l().then(t=>t.prepare("SELECT pg_notify(?, ?)").get("crtr_signal",`structured_request:${e}`)).catch(t=>p({level:"error",event:"structured_request.notify_failed",error:t,fields:{request_id:e}}))}n(S,"notifyStructuredRequest");export{S as notifyStructuredRequest,g as subscribeStructuredRequest};
@@ -1,3 +1,4 @@
1
- import { type StructuredOutputMode } from '../../core/runtime/structured-output.js';
2
- /** Admit legacy node/message schema requests before publishing their sidecar. */
3
- export declare function admitLegacyStructuredOutput(nodeId: string, submission: StructuredOutputMode, schema: Record<string, unknown>, requestMessageId?: string): Promise<string>;
1
+ import { type StructuredRequestRow } from '../../core/canvas/structured-requests.js';
2
+ import type { StructuredOutputMode } from '../../core/runtime/structured-output.js';
3
+ /** Admit a node/message schema request: the pending `structured_requests` row is the whole request. */
4
+ export declare function admitLegacyStructuredOutput(nodeId: string, submission: StructuredOutputMode, schema: Record<string, unknown>, requestMessageId?: string): Promise<StructuredRequestRow>;
@@ -1 +1 @@
1
- var i=Object.defineProperty;var e=(t,r)=>i(t,"name",{value:r,configurable:!0});import{registerLegacyStructuredRequest as a}from"../../core/canvas/structured-requests.js";import{writeStructuredRequestSidecar as o}from"../../core/runtime/structured-output.js";async function p(t,r,u,c){return o(await a(t,r,u,c))}e(p,"admitLegacyStructuredOutput");export{p as admitLegacyStructuredOutput};
1
+ var c=Object.defineProperty;var e=(t,r)=>c(t,"name",{value:r,configurable:!0});import{registerLegacyStructuredRequest as i}from"../../core/canvas/structured-requests.js";async function d(t,r,u,a){return await i(t,r,u,a)}e(d,"admitLegacyStructuredOutput");export{d as admitLegacyStructuredOutput};
@@ -1 +1 @@
1
- var R=Object.defineProperty;var h=(n,t)=>R(n,"name",{value:t,configurable:!0});import{chownSync as P,chmodSync as $,closeSync as l,constants as _,lstatSync as f,mkdirSync as E,openSync as L,realpathSync as A}from"node:fs";import{isAbsolute as G,join as e,relative as T,resolve as j,sep as S}from"node:path";import{loadLinuxNative as q,O_PATH as x,RESOLVE_BENEATH as z,RESOLVE_NO_SYMLINKS as V}from"../native/linux.js";import{APP_UID_MAX as W,APP_UID_MIN as Z,LaunchRefused as s}from"./spec.js";import{systemIdentity as b}from"./users.js";const a=q(),v=x|_.O_NOFOLLOW,g=z|V,M=32768,F=16384,I=49152;function c(n,t){return n===t||n.startsWith(t==="/"?"/":`${t}${S}`)}h(c,"within");function N(n){if(!G(n)||j(n)!==n||n.includes("\0")||n.split(S).includes(".."))throw new s("invalid_spec",`non-canonical source: ${n}`)}h(N,"assertPath");class Q{static{h(this,"SourceValidator")}daemonGid;socketDir;rootFd;runtimeDev;runtimeIno;runtimeFd;root;runtime;constructor(t,d=b().daemonGid,u="/run/crtr"){if(this.daemonGid=d,this.socketDir=u,!a)throw new Error("Linux native addon is required by the root launcher");this.root=A(t),this.runtime=A(e(this.root,"runtime")),this.rootFd=L("/",v),this.runtimeFd=L(this.runtime,v);const r=a.fstat(this.runtimeFd);this.runtimeDev=r.dev,this.runtimeIno=r.ino}close(){l(this.rootFd),l(this.runtimeFd)}openLog(t){if(!a)throw new Error("Linux native addon is required");return a.openat2(this.runtimeFd,`nodes/${t}/job/broker.log`,_.O_WRONLY|_.O_APPEND|_.O_NOFOLLOW,g)}isRuntimeAncestor(t){if(!a)throw new Error("Linux native addon is required");const d=t.split("/").filter(Boolean);for(let u=1;u<=d.length;u++){let r;try{r=a.openat2(this.rootFd,d.slice(0,u).join("/"),v,g)}catch{return!1}try{const m=a.fstat(r);if(m.dev===this.runtimeDev&&m.ino===this.runtimeIno)return!0}finally{l(r)}}return!1}pin(t){if(!a)throw new Error("Linux native addon is required");if(!Number.isInteger(t.uid)||t.uid<Z||t.uid>W)throw new s("invalid_uid","uid outside app range");if(!/^[a-zA-Z0-9][a-zA-Z0-9-]{0,127}$/.test(t.nodeId)||!Array.isArray(t.mounts)||!Array.isArray(t.command)||!t.command.length||!t.command.every(i=>typeof i=="string"&&i.length>0&&!i.includes("\0"))||!t.env||Object.entries(t.env).some(([i,o])=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)||typeof o!="string"||o.includes("\0")))throw new s("invalid_spec","invalid node id, command, environment or mount list");const d=e(this.socketDir,"nodes",t.nodeId),u=e(this.socketDir,"nodes");if(E(u,{recursive:!0,mode:493}),f(u).uid!==0||f(u).gid!==this.daemonGid||!f(u).isDirectory()||(f(u).mode&511)!==504)throw new s("run_source","nodes directory is not root-and-daemon-controlled");E(d,{recursive:!0,mode:504});const r=f(d);if(!r.isDirectory())throw new s("run_source","run folder is not a directory");if(r.uid===0||r.uid===b().daemonUid&&r.gid===this.daemonGid&&(r.mode&511)===504)P(d,t.uid,this.daemonGid),$(d,504);else if(r.uid!==t.uid||r.gid!==this.daemonGid||(r.mode&511)!==504)throw new s("run_source","run folder has wrong owner or mode");const m=[];try{for(const i of t.mounts){if(!i||typeof i.source!="string"||typeof i.writable!="boolean")throw new s("invalid_spec","invalid mount");const o=i.source;N(o);const p=t.pluginRoot===o&&!i.writable&&c(o,e(this.runtime,"plugins"))&&o!==e(this.runtime,"plugins");if(!p&&(c(o,this.runtime)||this.isRuntimeAncestor(o)))throw new s("runtime_source",o);const O=o===e(this.socketDir,"api.sock")||o===e(this.socketDir,"store.sock")||c(o,e(this.socketDir,"bin"))||o===d;if(c(o,this.socketDir)&&!O)throw new s("run_source",o);if(i.writable&&!c(o,e(this.root,"user"))&&!c(o,e(this.root,"apps"))&&o!==d&&o!==e(this.socketDir,"api.sock")&&o!==e(this.socketDir,"store.sock"))throw new s("writable_source",o);if(!c(o,e(this.root,"user"))&&!c(o,e(this.root,"apps"))&&!c(o,this.socketDir)&&!U(o)&&!p)throw new s("invalid_spec",`unknown read-only source: ${o}`);let w;try{w=a.openat2(this.rootFd,T("/",o)||".",v,g)}catch(k){const D=k.code;throw new s(D==="ENOENT"?"source_missing":D==="ELOOP"?"symlink_source":"launch_failed",`${o}: ${String(k)}`)}const y=a.fstat(w).mode&61440;if(![M,F,I].includes(y)||y===I&&!O)throw l(w),new s(y===40960?"symlink_source":"source_type",o);m.push({source:o,writable:i.writable,fd:w,kind:y})}if(N(t.cwd),!m.some(i=>i.kind===F&&c(t.cwd,i.source)))throw new s("invalid_spec","cwd is not mounted");return m}catch(i){for(const o of m)l(o.fd);throw i}}}function U(n){return["/usr","/bin","/lib","/lib64","/opt/crouter","/etc/passwd","/etc/group","/etc/resolv.conf","/etc/hosts","/etc/ssl","/etc/ca-certificates"].some(t=>c(n,t))}h(U,"isSystemSource");export{Q as SourceValidator};
1
+ var R=Object.defineProperty;var l=(n,o)=>R(n,"name",{value:o,configurable:!0});import{chownSync as P,chmodSync as $,closeSync as h,constants as _,lstatSync as f,mkdirSync as L,openSync as k,realpathSync as A}from"node:fs";import{isAbsolute as G,join as s,relative as T,resolve as j,sep as S}from"node:path";import{loadLinuxNative as q,O_PATH as x,RESOLVE_BENEATH as z,RESOLVE_NO_SYMLINKS as V}from"../native/linux.js";import{APP_UID_MAX as W,APP_UID_MIN as Z,LaunchRefused as e}from"./spec.js";import{systemIdentity as b}from"./users.js";const a=q(),v=x|_.O_NOFOLLOW,g=z|V,M=32768,F=16384,I=49152;function c(n,o){return n===o||n.startsWith(o==="/"?"/":`${o}${S}`)}l(c,"within");function N(n){if(!G(n)||j(n)!==n||n.includes("\0")||n.split(S).includes(".."))throw new e("invalid_spec",`non-canonical source: ${n}`)}l(N,"assertPath");class Q{static{l(this,"SourceValidator")}daemonGid;socketDir;rootFd;runtimeDev;runtimeIno;runtimeFd;root;runtime;constructor(o,d=b().daemonGid,u="/run/crtr"){if(this.daemonGid=d,this.socketDir=u,!a)throw new Error("Linux native addon is required by the root launcher");this.root=A(o),this.runtime=A(s(this.root,"runtime")),this.rootFd=k("/",v),this.runtimeFd=k(this.runtime,v);const r=a.fstat(this.runtimeFd);this.runtimeDev=r.dev,this.runtimeIno=r.ino}close(){h(this.rootFd),h(this.runtimeFd)}openLog(o){if(!a)throw new Error("Linux native addon is required");return a.openat2(this.runtimeFd,`nodes/${o}/job/broker.log`,_.O_WRONLY|_.O_APPEND|_.O_NOFOLLOW,g)}isRuntimeAncestor(o){if(!a)throw new Error("Linux native addon is required");const d=o.split("/").filter(Boolean);for(let u=1;u<=d.length;u++){let r;try{r=a.openat2(this.rootFd,d.slice(0,u).join("/"),v,g)}catch{return!1}try{const m=a.fstat(r);if(m.dev===this.runtimeDev&&m.ino===this.runtimeIno)return!0}finally{h(r)}}return!1}pin(o){if(!a)throw new Error("Linux native addon is required");if(!Number.isInteger(o.uid)||o.uid<Z||o.uid>W)throw new e("invalid_uid","uid outside app range");if(!/^[a-zA-Z0-9][a-zA-Z0-9-]{0,127}$/.test(o.nodeId)||!Array.isArray(o.mounts)||!Array.isArray(o.command)||!o.command.length||!o.command.every(i=>typeof i=="string"&&i.length>0&&!i.includes("\0"))||!o.env||Object.entries(o.env).some(([i,t])=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)||typeof t!="string"||t.includes("\0")))throw new e("invalid_spec","invalid node id, command, environment or mount list");const d=s(this.socketDir,"nodes",o.nodeId),u=s(this.socketDir,"nodes");if(L(u,{recursive:!0,mode:493}),f(u).uid!==0||f(u).gid!==this.daemonGid||!f(u).isDirectory()||(f(u).mode&511)!==504)throw new e("run_source","nodes directory is not root-and-daemon-controlled");L(d,{recursive:!0,mode:504});const r=f(d);if(!r.isDirectory())throw new e("run_source","run folder is not a directory");if(r.uid===0||r.uid===b().daemonUid&&r.gid===this.daemonGid&&(r.mode&511)===504)P(d,o.uid,this.daemonGid),$(d,504);else if(r.uid!==o.uid||r.gid!==this.daemonGid||(r.mode&511)!==504)throw new e("run_source","run folder has wrong owner or mode");const m=[];try{for(const i of o.mounts){if(!i||typeof i.source!="string"||typeof i.writable!="boolean")throw new e("invalid_spec","invalid mount");const t=i.source;N(t);const p=o.pluginRoot===t&&!i.writable&&c(t,s(this.runtime,"plugins"))&&t!==s(this.runtime,"plugins");if(!p&&(c(t,this.runtime)||this.isRuntimeAncestor(t)))throw new e("runtime_source",t);const O=t===s(this.socketDir,"api.sock")||c(t,s(this.socketDir,"bin"))||t===d;if(c(t,this.socketDir)&&!O)throw new e("run_source",t);if(i.writable&&!c(t,s(this.root,"user"))&&!c(t,s(this.root,"apps"))&&t!==d&&t!==s(this.socketDir,"api.sock"))throw new e("writable_source",t);if(!c(t,s(this.root,"user"))&&!c(t,s(this.root,"apps"))&&!c(t,this.socketDir)&&!U(t)&&!p)throw new e("invalid_spec",`unknown read-only source: ${t}`);let w;try{w=a.openat2(this.rootFd,T("/",t)||".",v,g)}catch(E){const D=E.code;throw new e(D==="ENOENT"?"source_missing":D==="ELOOP"?"symlink_source":"launch_failed",`${t}: ${String(E)}`)}const y=a.fstat(w).mode&61440;if(![M,F,I].includes(y)||y===I&&!O)throw h(w),new e(y===40960?"symlink_source":"source_type",t);m.push({source:t,writable:i.writable,fd:w,kind:y})}if(N(o.cwd),!m.some(i=>i.kind===F&&c(o.cwd,i.source)))throw new e("invalid_spec","cwd is not mounted");return m}catch(i){for(const t of m)h(t.fd);throw i}}}function U(n){return["/usr","/bin","/lib","/lib64","/opt/crouter","/etc/passwd","/etc/group","/etc/resolv.conf","/etc/hosts","/etc/ssl","/etc/ca-certificates"].some(o=>c(n,o))}l(U,"isSystemSource");export{Q as SourceValidator};
@@ -1,2 +1,2 @@
1
- var R=Object.defineProperty;var p=(e,n)=>R(e,"name",{value:n,configurable:!0});import{existsSync as f}from"node:fs";import{join as l}from"node:path";import{openDb as m,withCanvasWrite as g}from"../../core/canvas/db.js";import{nodeAgentDir as C,nodeRecordDir as S,onDiskMigrationMarkerPath as k}from"../../core/canvas/paths.js";import{identifyCheckout as E}from"../../core/graph/repo-sync/identity.js";import{profileSpace as L,userRoot as j}from"../../core/layout.js";import{commitConvertedProjectCaps as I,listLegacyProjectCaps as P,listStoredProfiles as _}from"../../core/scoped-state/profiles.js";import{userStore as b}from"../../core/scoped-state/paths.js";import{userScopeRoot as y}from"../../core/scope.js";import{LEGACY_LOCAL_PERSON as O}from"../../core/canvas/legacy-person.js";import{applyPlan as x,readImportRecord as w,storePlanBodies as M}from"./apply.js";import{readLegacyCorpus as v,readMarkerIds as D}from"./legacy/discover.js";import{planImport as A}from"./plan.js";const F=p(()=>({stores:[],counts:{},rewrites:[],droppedFields:[],skipped:[],resolutions:[]}),"emptyReport");async function N(){const e=y(),n=_(e),t=P(e),c=b(e).path,s=n.map(({profileId:r,manifest:a})=>{const i=a.grantee??"app:terminal",d=new Map(t.filter(o=>o.profileId===r).map(o=>[o.path,o.memory]));return{id:r,name:a.name,app:i,memory:L(i,r).dir,projects:a.projects.map(o=>o.path),raw:{projects:a.projects.map(o=>d.has(o.path)?{path:o.path,memory:d.get(o.path)}:{path:o.path})},manifestPath:`${c}#${r}`}}),u=await(await m()).prepareUncached("SELECT node_id, cwd, grantee FROM node_rows ORDER BY created").all(),h=u.map(r=>{const a=r.grantee===O?"app:terminal":r.grantee,i=a?.startsWith("app:")?C(r.node_id,a):null,d=i!==null&&(f(l(i,"context"))||f(l(i,"reports")))?i:S(r.node_id);return{id:r.node_id,dir:d}});return{roots:{userMemory:l(j(),"memory"),profiles:s,nodeCwds:[...new Set(u.map(r=>r.cwd))],nodes:h},stored:n}}p(N,"legacyRoots");async function T(){const{roots:e,stored:n}=await N(),t=v(e),c=await(await m()).prepareUncached(`SELECT o.type, o.name AS handle, i.external_id AS externalId FROM objects o
2
- LEFT JOIN identities i ON i.object = o.id WHERE o.type IN ('person','app','repo','profile')`).all();return A(t,{roots:e,markerIds:D(k()),repoIdentity:E,existingOwners:c,storedProfiles:n.map(s=>({id:s.profileId,deliveryLimits:{...s.manifest.delivery_limits??{}}}))})}p(T,"plan");async function Z(){return await w(await m())!==null}p(Z,"canvasImportDone");async function ee(e){const n=await w(await m());if(n!==null)return{report:e.dryRun?n:F(),blockers:[],dryRun:e.dryRun,pending:!1};const t=await T();if(e.dryRun||t.blockers.length>0)return{report:t.report,blockers:t.blockers,dryRun:e.dryRun,pending:!0};const c=M(t);return I(y(),t.profileLimits),await g(async s=>await x(s,t,c)),{report:t.report,blockers:[],dryRun:!1,pending:!1}}p(ee,"runCanvasImport");export{Z as canvasImportDone,ee as runCanvasImport};
1
+ var R=Object.defineProperty;var c=(r,n)=>R(r,"name",{value:n,configurable:!0});import{existsSync as u}from"node:fs";import{join as y}from"node:path";import{openDb as f,withCanvasWrite as w}from"../../core/canvas/db.js";import{nodeAgentDir as E,nodeRecordDir as S,onDiskMigrationMarkerPath as L}from"../../core/canvas/paths.js";import{identifyCheckout as I}from"../../core/graph/repo-sync/identity.js";import{profileSpace as k,userRoot as C}from"../../core/layout.js";import{deleteLegacyProjectCaps as _,listLegacyProjectCaps as j,readLegacyUserSnapshot as O}from"../../core/scoped-state/legacy-profiles.js";import{personIdAsync as P}from"../../core/canvas/person.js";import{userStore as b}from"../../core/scoped-state/paths.js";import{userScopeRoot as h}from"../../core/scope.js";import{LEGACY_LOCAL_PERSON as A}from"../../core/canvas/legacy-person.js";import{applyPlan as D,readImportRecord as g,storePlanBodies as v}from"./apply.js";import{readLegacyCorpus as x,readMarkerIds as M}from"./legacy/discover.js";import{planImport as N}from"./plan.js";const T=c(()=>({stores:[],counts:{},rewrites:[],droppedFields:[],skipped:[],resolutions:[]}),"emptyReport");async function F(){const r=h(),n=O(r)?.profiles??[],o=j(r),d=b(r).path,s=n.map(({profileId:e,manifest:a})=>{const i=a.grantee??"app:terminal",l=new Map(o.filter(t=>t.profileId===e).map(t=>[t.path,t.memory]));return{id:e,name:a.name,app:i,memory:k(i,e).dir,projects:a.projects.map(t=>t.path),raw:{projects:a.projects.map(t=>l.has(t.path)?{path:t.path,memory:l.get(t.path)}:{path:t.path})},manifestPath:`${d}#${e}`}}),p=await(await f()).prepareUncached("SELECT node_id, cwd, grantee FROM node_rows ORDER BY created").all(),m=p.map(e=>{const a=e.grantee===A?"app:terminal":e.grantee,i=a?.startsWith("app:")?E(e.node_id,a):null,l=i!==null&&(u(y(i,"context"))||u(y(i,"reports")))?i:S(e.node_id);return{id:e.node_id,dir:l}});return{roots:{userMemory:y(C(),"memory"),profiles:s,nodeCwds:[...new Set(p.map(e=>e.cwd))],nodes:m},stored:n}}c(F,"legacyRoots");async function U(){const{roots:r,stored:n}=await F(),o=x(r),d=await(await f()).prepareUncached(`SELECT o.type, o.name AS handle, i.external_id AS externalId FROM objects o
2
+ LEFT JOIN identities i ON i.object = o.id WHERE o.type IN ('person','app','repo','profile')`).all();return N(o,{roots:r,markerIds:M(L()),repoIdentity:I,existingOwners:d,storedProfiles:n.map(s=>({id:s.profileId,deliveryLimits:{...s.manifest.delivery_limits??{}}}))})}c(U,"plan");async function er(){return await g(await f())!==null}c(er,"canvasImportDone");async function or(r){const n=await g(await f());if(n!==null)return{report:r.dryRun?n:T(),blockers:[],dryRun:r.dryRun,pending:!1};const o=await U();if(r.dryRun||o.blockers.length>0)return{report:o.report,blockers:o.blockers,dryRun:r.dryRun,pending:!0};const d=v(o),s=await P();return await w(async p=>{for(const m of o.profileLimits)if((await p.prepare("UPDATE profiles SET delivery_limits_json = ? WHERE id = ? AND person = ?").run(JSON.stringify(m.deliveryLimits),m.profileId,s)).changes!==1)throw new Error(`no stored profile ${m.profileId}`)}),_(h()),await w(async p=>await D(p,o,d)),{report:o.report,blockers:[],dryRun:!1,pending:!1}}c(or,"runCanvasImport");export{er as canvasImportDone,or as runCanvasImport};
@@ -1,6 +1,6 @@
1
- /** Persist a bare root's first real interactive message without clobbering an
2
- * existing spawning mandate. This is broker-local file state, not canvas.db. */
3
- export declare function captureGoalIfAbsent(nodeId: string, text: string): boolean;
1
+ /** Post a bare root's first real interactive message to crtrd, which stores it as the node's goal only
2
+ * while the goal is empty. Resolves to whether this call stored it. */
3
+ export declare function captureGoalIfAbsent(nodeId: string, text: string): Promise<boolean>;
4
4
  /** The node's `roadmap` document body, read through crtrd (`/v1`), or null. */
5
5
  export declare function readRoadmap(nodeId: string): Promise<string | null>;
6
6
  /** Generate and commit the first name for a node. The initial operation is
@@ -1,2 +1 @@
1
- var f=Object.defineProperty;var o=(i,t)=>f(i,"name",{value:t,configurable:!0});import{existsSync as s,mkdirSync as u,readFileSync as l,writeFileSync as b}from"node:fs";import{join as h}from"node:path";import{contextDir as y}from"../core/canvas/paths.js";import{brokerExtensionState as d,commitBrokerGeneratedName as c}from"../core/runtime/broker/daemon-ops.js";import{publishNodeNamed as N}from"../core/runtime/broker/node-named.js";import{headlessName as x,headlessNameFromConversation as L,sanitizeSessionName as S,sanitizeSessionTitle as k,slugFromPrompt as F,titleFromPrompt as v}from"../core/runtime/naming.js";function R(i,t){const r=y(i),n=h(r,"initial-prompt.md");if(s(n)&&l(n,"utf8").trim()!=="")return!1;const e=t.trim();return e===""?!1:(u(r,{recursive:!0}),b(n,`${e}
2
- `,"utf8"),!0)}o(R,"captureGoalIfAbsent");async function j(i){return(await d(i)).roadmap}o(j,"readRoadmap");function p(i,t){return{description:S(t.name)||F(i),title:k(t.title)||v(i),icon:t.icon}}o(p,"generatedLabel");function B(i,t,r){const n=t.trim();n!==""&&d(i).then(e=>{if((e.node.description??"").trim()==="")return x(n).then(a=>c(i,{kind:"initial",...p(n,a)}))}).then(e=>{!e?.applied||e.editorLabel===void 0||(N({description:e.description??"",title:e.title??"",icon:e.icon??"",editorLabel:e.editorLabel}),r?.(e.editorLabel))}).catch(()=>{})}o(B,"generateAndCommitInitialName");function D(i,t,r,n,e){const a=t.trim();a!==""&&L(a).then(m=>{if(n())return c(i,{kind:"recap",...p(a,m),expected:r})}).then(m=>{m?.applied&&m.editorLabel!==void 0&&e?.(m.editorLabel)}).catch(()=>{})}o(D,"generateAndCommitRecapName");export{R as captureGoalIfAbsent,B as generateAndCommitInitialName,D as generateAndCommitRecapName,j as readRoadmap};
1
+ var f=Object.defineProperty;var r=(e,t)=>f(e,"name",{value:t,configurable:!0});import{localClient as l}from"../api/node-transport.js";import{brokerExecutionId as s,brokerExtensionState as m,commitBrokerGeneratedName as c}from"../core/runtime/broker/daemon-ops.js";import{publishNodeNamed as u}from"../core/runtime/broker/node-named.js";import{headlessName as b,headlessNameFromConversation as h,sanitizeSessionName as x,sanitizeSessionTitle as N,slugFromPrompt as L,titleFromPrompt as k}from"../core/runtime/naming.js";async function G(e,t){const n=t.trim();return n===""?!1:(await l({autostart:!1}).captureBrokerGoal(e,{text:n,expected_execution_id:s()})).captured}r(G,"captureGoalIfAbsent");async function S(e){return(await m(e)).roadmap}r(S,"readRoadmap");function p(e,t){return{description:x(t.name)||L(e),title:N(t.title)||k(e),icon:t.icon}}r(p,"generatedLabel");function g(e,t,n){const o=t.trim();o!==""&&m(e).then(i=>{if((i.node.description??"").trim()==="")return b(o).then(a=>c(e,{kind:"initial",...p(o,a)}))}).then(i=>{!i?.applied||i.editorLabel===void 0||(u({description:i.description??"",title:i.title??"",icon:i.icon??"",editorLabel:i.editorLabel}),n?.(i.editorLabel))}).catch(()=>{})}r(g,"generateAndCommitInitialName");function w(e,t,n,o,i){const a=t.trim();a!==""&&h(a).then(d=>{if(o())return c(e,{kind:"recap",...p(a,d),expected:n})}).then(d=>{d?.applied&&d.editorLabel!==void 0&&i?.(d.editorLabel)}).catch(()=>{})}r(w,"generateAndCommitRecapName");export{G as captureGoalIfAbsent,g as generateAndCommitInitialName,w as generateAndCommitRecapName,S as readRoadmap};
@@ -1,7 +1,7 @@
1
- var ae=Object.defineProperty;var o=(t,n)=>ae(t,"name",{value:n,configurable:!0});import{envBashAutoBgDeadlineMs as ce,envBashValveMs as ue,envNodeId as de}from"../shared/env.js";import{closeSync as le,existsSync as j,mkdirSync as z,openSync as fe,readFileSync as K,readSync as he,rmSync as W,statSync as q,writeFileSync as S}from"node:fs";import{homedir as be}from"node:os";import{dirname as me}from"node:path";import{performance as J}from"node:perf_hooks";import{backgroundBashJob as X,bashJobPaths as pe,cancelBashJobProcessTree as ge,countJobLogLines as we,formatBashElapsed as Y,newBashJobId as ye,normalizeBashJobPurpose as je,tailJobLog as ve,writeJobDeadlineMs as Ee}from"../core/bash-jobs.js";import{MAX_BACKGROUND_BASH_LOG_BYTES as ct,BACKGROUND_BASH_LOG_TRUNCATION_MARKER as ut}from"../core/bash-job-supervisor.js";import{recordBackgroundedJob as _e,stopBrokerBashJob as Se}from"../core/runtime/broker/daemon-ops.js";import{BASH_JOBS_USE_LAUNCHER as Be,launchBashJobSupervisor as Ie}from"../core/runtime/broker/bash-job-launch.js";import{bashCommandRefusal as Le}from"../core/bash-guard.js";import{readConfig as ke}from"../core/config.js";import{PREVIEW_RESULT_PATH_ENV as Ae,previewResultPath as Oe}from"../core/preview-result-path.js";import{Type as B}from"typebox";import{createBashToolDefinition as Q}from"@earendil-works/pi-coding-agent";const xe=200;function Re(){return ue()}o(Re,"resolveValveMs");function Te(t){return pe(t,ye())}o(Te,"makeJobPaths");const I=new Set;let Z=!1;function ee(){for(const t of[...I])try{X(t),I.delete(t)}catch(n){process.stderr.write(`crtr: failed to background bash job ${t.jobId} during broker termination: ${n.message}
2
- `)}}o(ee,"backgroundLiveJobsForTermination");function $e(){Z||(Z=!0,process.prependListener("SIGTERM",ee),process.platform!=="win32"&&process.prependListener("SIGHUP",ee))}o($e,"installTerminationHandoff");const Je=64*1024;function N(t,n,i){let s;try{s=q(t)}catch{return n}if(s.size<=n)return n;const c=fe(t,"r");try{for(;n<s.size;){const b=Math.min(Je,s.size-n),m=Buffer.allocUnsafe(b),a=he(c,m,0,b,n);if(a===0)break;i(m.subarray(0,a)),n+=a}return n}finally{le(c)}}o(N,"tailOnce");function v(t){try{W(t,{recursive:!0,force:!0})}catch{}}o(v,"cleanupJobDir");function Ne(t){try{const n=K(t,"utf8").trim(),i=Number(n);return Number.isFinite(i)?i:null}catch{return null}}o(Ne,"readExitCode");function Ce(t){try{if(q(t).isDirectory())return{cwd:t}}catch{}const n=be();return{cwd:n,warning:`[working directory no longer exists: ${t}; running from ${n}]
3
- `}}o(Ce,"resolveExecutionCwd");function te(t,n,i=()=>null,s,c=()=>{}){return{exec:o(async(b,m,{onData:a,signal:f,timeout:p,env:L})=>new Promise((E,d)=>{const w=i();if(f?.aborted){d(new Error("aborted"));return}const k=Le(b,m);if(k!==null){d(new Error(k));return}const e=Te(n);z(e.dir,{recursive:!0}),S(e.cmdSh,b),S(e.jobLog,""),S(e.jobRun,""),w!==null&&S(e.jobPurpose,w);let l=0,g=!1,_,A,O,C=!1;const ne=Be,M=J.now(),oe=Re();let y;const re=o(()=>{y&&clearInterval(y),f&&f.removeEventListener("abort",H),I.delete(e)},"teardown"),h=o(r=>{g||(g=!0,re(),r())},"finish");let D=!1;function x(r=!1){g||D||(D=!0,y&&clearInterval(y),_e(t,e.jobId,{command:K(e.cmdSh,"utf8"),job_dir:e.dir,log_path:e.jobLog}).then(()=>P(r,""),u=>P(r,`
4
- [crtr could not record job ${e.jobId} (${u.message}); it will NOT message you when it exits. Watch its log.]`)))}o(x,"finishBackground");function P(r,u){const se=Y(J.now()-M);let F="";if(r){const V=ce();Ee(e,Date.now()+V),F=`It will be CANCELED in ${Y(V)} unless you claim it: crtr node bash extend ${e.jobId} --for <duration> (or --keep to run to completion). `}const G=`
5
- [backgrounded as job ${e.jobId} after ${se} in the foreground${r?" (auto)":""}. `+F+(u===""?"It will interrupt you with a message when it exits. ":"")+`Watch: tail -f ${e.jobLog} ; stop: crtr node bash kill ${e.jobId}]`;a(Buffer.from(G+u)),c({jobId:e.jobId,logPath:e.jobLog,notice:G+u}),h(()=>E({exitCode:0}))}o(P,"handOff");function U(){l=N(e.jobLog,l,a);const r=Ne(e.jobExit);h(()=>E({exitCode:r})),v(e.dir)}o(U,"finishForeground");function ie(r=!1){const u=X(e);if(u==="backgrounded"||u==="already-backgrounded"){x(r);return}if(u==="finished"){U();return}h(()=>d(new Error(`bash job ${e.jobId} disappeared before it could be backgrounded`))),v(e.dir)}o(ie,"requestBackground");function R(r){if(!(g||C)){if(l=N(e.jobLog,l,a),j(e.jobBg)){x();return}if(!j(e.jobExit)){if(_===void 0){O??=r;return}if(ne){C=!0,Se(t,e.jobId).then(()=>{h(()=>d(r)),v(e.dir)},u=>h(()=>d(u)));return}_!==void 0&&A!==void 0&&ge(_,A),h(()=>d(r)),v(e.dir)}}}o(R,"requestStop");function H(){R(new Error("aborted"))}o(H,"onAbort"),f&&f.addEventListener("abort",H,{once:!0});const T=Ce(m);T.warning&&a(Buffer.from(T.warning));let $=L??process.env;s!==void 0&&(z(me(s),{recursive:!0}),W(s,{force:!0}),$={...$,[Ae]:s}),Ie(t,e,n,T.cwd,$).then(r=>{_=r.pgid,A=r.identity,I.add(e),O!==void 0&&R(O)},r=>{h(()=>d(r)),v(e.dir)}),y=setInterval(()=>{if(l=N(e.jobLog,l,a),j(e.jobDone)){U();return}if(j(e.jobBg)){x();return}if(j(e.jobExit))return;const r=J.now()-M;if(p!==void 0&&p>0){r>=p*1e3&&R(new Error(`timeout:${p}`));return}r>=oe&&ie(!0)},xe)}),"exec")}}o(te,"createValveOperations");const Me=["One short clause naming what this step is FOR, in the words of the person you",'are working for \u2014 "Reading the Acme thread", not "Fetching emails" and never','"Running GMAIL_FETCH_EMAILS". A person reads this while the command runs; it',"is the only thing they see of this step. Under about eight words. Omit it for","steps that only touch your own scratch work."].join(" "),De=3;function Pe(t){const n=ve(t.logPath,De),i=Math.max(0,we(t.logPath)-n.length),s=n.length===0?"(no output yet)":n.join(`
1
+ var ce=Object.defineProperty;var o=(e,n)=>ce(e,"name",{value:n,configurable:!0});import{envBashAutoBgDeadlineMs as z,envBashValveMs as ue,envNodeId as de}from"../shared/env.js";import{closeSync as le,existsSync as v,mkdirSync as K,openSync as fe,readFileSync as W,readSync as he,rmSync as q,statSync as X,writeFileSync as $}from"node:fs";import{homedir as be}from"node:os";import{dirname as me}from"node:path";import{performance as N}from"node:perf_hooks";import{backgroundBashJob as Y,bashJobPaths as pe,clearJobDeadlineFile as ge,writeJobDeadlineFile as we,cancelBashJobProcessTree as ye,countJobLogLines as ve,formatBashElapsed as Q,newBashJobId as Ee,normalizeBashJobPurpose as je,tailJobLog as Ie}from"../core/bash-jobs.js";import{MAX_BACKGROUND_BASH_LOG_BYTES as ht,BACKGROUND_BASH_LOG_TRUNCATION_MARKER as bt}from"../core/bash-job-supervisor.js";import{brokerApiUrl as _e,recordBackgroundedJob as Be,reportBrokerJob as Se,stopBrokerBashJob as ke}from"../core/runtime/broker/daemon-ops.js";import{bashJobsUseLauncher as Le,launchBashJobSupervisor as Ae}from"../core/runtime/broker/bash-job-launch.js";import{JobReporter as xe}from"../core/runtime/broker/job-reporter.js";import{bashCommandRefusal as Oe}from"../core/bash-guard.js";import{readConfig as Je}from"../core/config.js";import{PREVIEW_RESULT_PATH_ENV as Re,previewResultPath as Te}from"../core/preview-result-path.js";import{Type as _}from"typebox";import{createBashToolDefinition as Z}from"@earendil-works/pi-coding-agent";const $e=200;function Ne(){return ue()}o(Ne,"resolveValveMs");function Ce(e){return pe(e,Ee())}o(Ce,"makeJobPaths");const B=new Set;let ee=!1;function te(){for(const e of[...B])try{Y(e),B.delete(e)}catch(n){process.stderr.write(`crtr: failed to background bash job ${e.jobId} during broker termination: ${n.message}
2
+ `)}}o(te,"backgroundLiveJobsForTermination");function Me(){ee||(ee=!0,process.prependListener("SIGTERM",te),process.platform!=="win32"&&process.prependListener("SIGHUP",te))}o(Me,"installTerminationHandoff");const De=64*1024;function C(e,n,i){let s;try{s=X(e)}catch{return n}if(s.size<=n)return n;const c=fe(e,"r");try{for(;n<s.size;){const b=Math.min(De,s.size-n),m=Buffer.allocUnsafe(b),u=he(c,m,0,b,n);if(u===0)break;i(m.subarray(0,u)),n+=u}return n}finally{le(c)}}o(C,"tailOnce");function E(e){try{q(e,{recursive:!0,force:!0})}catch{}}o(E,"cleanupJobDir");function Pe(e){try{const n=W(e,"utf8").trim(),i=Number(n);return Number.isFinite(i)?i:null}catch{return null}}o(Pe,"readExitCode");function Ue(e){try{if(X(e).isDirectory())return{cwd:e}}catch{}const n=be();return{cwd:n,warning:`[working directory no longer exists: ${e}; running from ${n}]
3
+ `}}o(Ue,"resolveExecutionCwd");function ne(e,n,i=()=>null,s,c=()=>{}){return{exec:o(async(b,m,{onData:u,signal:f,timeout:p,env:S})=>new Promise((j,d)=>{const w=i();if(f?.aborted){d(new Error("aborted"));return}const k=Oe(b,m);if(k!==null){d(new Error(k));return}const t=Ce(n);K(t.dir,{recursive:!0}),$(t.cmdSh,b),$(t.jobLog,""),$(t.jobRun,"");let l=0,g=!1,I,L,A,M=!1;const oe=Le(),D=N.now(),re=Ne();let y;const ie=o(()=>{y&&clearInterval(y),f&&f.removeEventListener("abort",G),B.delete(t)},"teardown"),h=o(r=>{g||(g=!0,ie(),r())},"finish");let P=!1;function x(r=!1){if(g||P)return;P=!0,y&&clearInterval(y);const a=r?Date.now()+z():void 0;a!==void 0&&we(t,a),Be(e,t.jobId,{command:W(t.cmdSh,"utf8"),...w===null?{}:{purpose:w},...a===void 0?{}:{deadline_at_ms:a}}).then(()=>{try{ge(t)}catch{}U(r,"")},T=>U(r,`
4
+ [crtr could not record job ${t.jobId} (${T.message}); it will NOT message you when it exits. Watch its log.]`))}o(x,"finishBackground");function U(r,a){const T=Q(N.now()-D);let H="";if(r){const ae=z();H=`It will be CANCELED in ${Q(ae)} unless you claim it: crtr node bash extend ${t.jobId} --for <duration> (or --keep to run to completion). `}const V=`
5
+ [backgrounded as job ${t.jobId} after ${T} in the foreground${r?" (auto)":""}. `+H+(a===""?"It will interrupt you with a message when it exits. ":"")+`Watch: tail -f ${t.jobLog} ; stop: crtr node bash kill ${t.jobId}]`;u(Buffer.from(V+a)),c({jobId:t.jobId,logPath:t.jobLog,notice:V+a}),h(()=>j({exitCode:0}))}o(U,"handOff");function F(){l=C(t.jobLog,l,u);const r=Pe(t.jobExit);h(()=>j({exitCode:r})),E(t.dir)}o(F,"finishForeground");function se(r=!1){const a=Y(t);if(a==="backgrounded"||a==="already-backgrounded"){x(r);return}if(a==="finished"){F();return}h(()=>d(new Error(`bash job ${t.jobId} disappeared before it could be backgrounded`))),E(t.dir)}o(se,"requestBackground");function O(r){if(!(g||M)){if(l=C(t.jobLog,l,u),v(t.jobBg)){x();return}if(!v(t.jobExit)){if(I===void 0){A??=r;return}if(oe){M=!0,ke(e,t.jobId).then(()=>{h(()=>d(r)),E(t.dir)},a=>h(()=>d(a)));return}I!==void 0&&L!==void 0&&ye(I,L),h(()=>d(r)),E(t.dir)}}}o(O,"requestStop");function G(){O(new Error("aborted"))}o(G,"onAbort"),f&&f.addEventListener("abort",G,{once:!0});const J=Ue(m);J.warning&&u(Buffer.from(J.warning));let R=S??process.env;s!==void 0&&(K(me(s),{recursive:!0}),q(s,{force:!0}),R={...R,[Re]:s}),Ae(e,t,n,J.cwd,R).then(r=>{I=r.pgid,L=r.identity,B.add(t),A!==void 0&&O(A)},r=>{h(()=>d(r)),E(t.dir)}),y=setInterval(()=>{if(l=C(t.jobLog,l,u),v(t.jobDone)){F();return}if(v(t.jobBg)){x();return}if(v(t.jobExit))return;const r=N.now()-D;if(p!==void 0&&p>0){r>=p*1e3&&O(new Error(`timeout:${p}`));return}r>=re&&se(!0)},$e)}),"exec")}}o(ne,"createValveOperations");const Fe=["One short clause naming what this step is FOR, in the words of the person you",'are working for \u2014 "Reading the Acme thread", not "Fetching emails" and never','"Running GMAIL_FETCH_EMAILS". A person reads this while the command runs; it',"is the only thing they see of this step. Under about eight words. Omit it for","steps that only touch your own scratch work."].join(" "),Ge=3;function He(e){const n=Ie(e.logPath,Ge),i=Math.max(0,ve(e.logPath)-n.length),s=n.length===0?"(no output yet)":n.join(`
6
6
  `),c=i===0?"":`
7
- [${i} earlier output line${i===1?"":"s"} are in the job log only]`;return{content:[{type:"text",text:`${s}${c}${t.notice}`}],details:void 0}}o(Pe,"handoffResult");function Ue(t){return{...t,parameters:B.Object({purpose:B.Optional(B.String({description:Me})),...t.parameters.properties})}}o(Ue,"withPurpose");const He=["A command that needs longer than one call \u2014 a test lane, a build, a soak \u2014 is started with","`crtr node bash run '<command>'`, which returns at once and wakes you with the exit code; the job is a canvas","object others can watch. Do not use `&`, `nohup`, `setsid`, or a cron that polls a log. A foreground command","past 5 minutes is moved to a job automatically; a `timeout` kills it and everything it started."].join(" ");function Fe(t){const{command:n,...i}=t.parameters.properties;return{...t,parameters:B.Object({command:{...n,description:`${n.description??""} ${He}`.trim()},...i})}}o(Fe,"withJobGuidance");function Ge(t,n,i,s){const c=Fe(Q(i,{operations:te(t,n)}));return{...s?Ue(c):c,execute:o(async(a,f,p,L,E)=>{const d=s?je(f.purpose):null;let w=null;const e=await Q(i,{operations:te(t,n,()=>d,Oe(a),g=>{w=g})}).execute(a,f,p,L,E),l=w;return l===null?e:Pe(l)},"execute")}}o(Ge,"createValveToolDefinition");function Ve(t){const n=de();if(n===void 0||n.trim()==="")return;const i=process.env.CRTR_CONTEXT_DIR;i===void 0||i.trim()===""||($e(),t.on("session_start",(s,c)=>{t.registerTool(Ge(n,i,c.cwd,ke("user").bash_tool_purpose))}))}o(Ve,"default");export{ut as BACKGROUND_BASH_LOG_TRUNCATION_MARKER,ct as MAX_BACKGROUND_BASH_LOG_BYTES,te as createValveOperations,Ge as createValveToolDefinition,Ve as default};
7
+ [${i} earlier output line${i===1?"":"s"} are in the job log only]`;return{content:[{type:"text",text:`${s}${c}${e.notice}`}],details:void 0}}o(He,"handoffResult");function Ve(e){return{...e,parameters:_.Object({purpose:_.Optional(_.String({description:Fe})),...e.parameters.properties})}}o(Ve,"withPurpose");const ze=["A command that needs longer than one call \u2014 a test lane, a build, a soak \u2014 is started with","`crtr node bash run '<command>'`, which returns at once and wakes you with the exit code; the job is a canvas","object others can watch. Do not use `&`, `nohup`, `setsid`, or a cron that polls a log. A foreground command","past 5 minutes is moved to a job automatically; a `timeout` kills it and everything it started."].join(" ");function Ke(e){const{command:n,...i}=e.parameters.properties;return{...e,parameters:_.Object({command:{...n,description:`${n.description??""} ${ze}`.trim()},...i})}}o(Ke,"withJobGuidance");function We(e,n,i,s){const c=Ke(Z(i,{operations:ne(e,n)}));return{...s?Ve(c):c,execute:o(async(u,f,p,S,j)=>{const d=s?je(f.purpose):null;let w=null;const t=await Z(i,{operations:ne(e,n,()=>d,Te(u),g=>{w=g})}).execute(u,f,p,S,j),l=w;return l===null?t:He(l)},"execute")}}o(We,"createValveToolDefinition");function qe(e){const n=de();if(n===void 0||n.trim()==="")return;const i=process.env.CRTR_CONTEXT_DIR;i===void 0||i.trim()===""||(Me(),_e()!==void 0&&new xe(i,(s,c)=>Se(n,s,c)).start(),e.on("session_start",(s,c)=>{e.registerTool(We(n,i,c.cwd,Je("user").bash_tool_purpose))}))}o(qe,"default");export{bt as BACKGROUND_BASH_LOG_TRUNCATION_MARKER,ht as MAX_BACKGROUND_BASH_LOG_BYTES,ne as createValveOperations,We as createValveToolDefinition,qe as default};
@@ -1,2 +1,2 @@
1
- var w=Object.defineProperty;var s=(t,e)=>w(t,"name",{value:e,configurable:!0});import{envNodeId as b}from"../shared/env.js";import{CONTEXT_INTRO_CUSTOM_TYPE as a,formatCard as C}from"../shared/generated-context.js";import{brokerDelivery as m,brokerExtensionState as f}from"../core/runtime/broker/daemon-ops.js";import{buildForkBearingsFromState as p}from"../core/runtime/broker-extension-render.js";import{acknowledgePersonaBaseline as T}from"../core/runtime/broker-persona-guidance.js";import{situationalContextEnvelope as l}from"../core/runtime/situational-context.js";async function O(t){return(await m(t,{activity:"boot"})).content}s(O,"buildContextIntro");async function P(t){const e=await f(t);return p(e,l(t)??"")}s(P,"buildForkContextIntro");function g(t){const e=t.content;return typeof e=="string"?e:Array.isArray(e)?e.filter(r=>typeof r?.text=="string").map(r=>r.text).join(`
2
- `):""}s(g,"entryText");function v(t){t.on("session_start",async(e,r)=>{const n=b();if(n===void 0||n.trim()==="")return;const x=e?.reason,i=await f(n);if(i.warm_spare||x==="new"&&i.node.parent===null)return;const c=r.sessionManager.getBranch().filter(o=>o.type==="custom_message"&&o.customType===a);if(c.some(o=>o.details?.nodeId===n||g(o).includes(n)))return;const d=await m(n,{activity:"boot",inherited:c.length>0}),y=d.inherited===!0?p(i,l(n)??""):d.content,u=C("bearings",{},y);if(t.sendMessage({customType:a,content:u,display:!0,details:{nodeId:n}}),!r.sessionManager.getBranch().some(o=>o.type==="custom_message"&&o.customType===a&&o.details?.nodeId===n&&g(o)===u))throw new Error(`Pi did not materialize the context baseline for ${n}`);await T(i)})}s(v,"registerCanvasContextIntro");var S=v;export{a as CONTEXT_INTRO_CUSTOM_TYPE,O as buildContextIntro,P as buildForkContextIntro,S as default,v as registerCanvasContextIntro};
1
+ var x=Object.defineProperty;var s=(e,t)=>x(e,"name",{value:t,configurable:!0});import{envNodeId as w}from"../shared/env.js";import{CONTEXT_INTRO_CUSTOM_TYPE as a,formatCard as b}from"../shared/generated-context.js";import{brokerDelivery as m}from"../core/runtime/broker/daemon-ops.js";import{boundExtensionState as f}from"../core/runtime/broker/boot-state.js";import{buildForkBearingsFromState as l}from"../core/runtime/broker-extension-render.js";import{acknowledgePersonaBaseline as T}from"../core/runtime/broker-persona-guidance.js";async function N(e){return(await m(e,{activity:"boot"})).content}s(N,"buildContextIntro");async function O(e){const t=await f(e);return l(t,t.situational_card??"")}s(O,"buildForkContextIntro");function p(e){const t=e.content;return typeof t=="string"?t:Array.isArray(t)?t.filter(r=>typeof r?.text=="string").map(r=>r.text).join(`
2
+ `):""}s(p,"entryText");function _(e){e.on("session_start",async(t,r)=>{const o=w();if(o===void 0||o.trim()==="")return;const g=t?.reason,i=await f(o);if(i.warm_spare||g==="new"&&i.node.parent===null)return;const c=r.sessionManager.getBranch().filter(n=>n.type==="custom_message"&&n.customType===a);if(c.some(n=>n.details?.nodeId===o||p(n).includes(o)))return;const d=await m(o,{activity:"boot",inherited:c.length>0}),y=d.inherited===!0?l(i,i.situational_card??""):d.content,u=b("bearings",{},y);if(e.sendMessage({customType:a,content:u,display:!0,details:{nodeId:o}}),!r.sessionManager.getBranch().some(n=>n.type==="custom_message"&&n.customType===a&&n.details?.nodeId===o&&p(n)===u))throw new Error(`Pi did not materialize the context baseline for ${o}`);await T(i)})}s(_,"registerCanvasContextIntro");var P=_;export{a as CONTEXT_INTRO_CUSTOM_TYPE,N as buildContextIntro,O as buildForkContextIntro,P as default,_ as registerCanvasContextIntro};
@@ -1,2 +1,2 @@
1
- var f=Object.defineProperty;var d=(e,t)=>f(e,"name",{value:t,configurable:!0});import{envNodeId as h}from"../shared/env.js";import{brokerExtensionState as p}from"../core/runtime/broker/daemon-ops.js";import{crtrPreviewRecords as m}from"../core/preview-registry.js";const g="This is how long you have been on this work, shown because you have delegates. Finishing sooner is worth something: keep independent work running in parallel and take the quicker path when quality is unchanged. It is not a budget; never trade verification or scope for time.";function w(e){const t=Math.floor(Math.max(0,e)/1e3),o=Math.floor(t/60),r=Math.floor(o/60);return`elapsed ${r>0?`${r}h `:""}${o%60}m ${t%60}s`}d(w,"elapsedLine");function v(e){return m(e).some(t=>t.path==="node new"&&t.error===void 0)}d(v,"spawnedChild");function x(e,t=p,o=Date.now){const r=h();if(r===void 0||r.trim()==="")return;let l,a=o(),i=!1,c=!1;e.on("session_start",async()=>{a=o(),c=!1;const n=await t(r);if(l=n.node.lifecycle,i=i||n.children.length>0,l==="terminal"){const s=Date.parse(n.node.created);Number.isFinite(s)&&(a=s)}}),e.on("input",n=>{l==="resident"&&n?.streamingBehavior===void 0&&(a=o())}),e.on("tool_result",n=>{if(!i&&v(n)&&(i=!0),!i)return;const s=w(o()-a),u=c?s:`${s}
2
- ${g}`;return c=!0,{content:[...n.content,{type:"text",text:u}]}})}d(x,"registerCanvasElapsed");var I=x;export{I as default,x as registerCanvasElapsed};
1
+ var f=Object.defineProperty;var l=(e,t)=>f(e,"name",{value:t,configurable:!0});import{envNodeId as h}from"../shared/env.js";import{boundExtensionState as p,retireBootExtensionState as m}from"../core/runtime/broker/boot-state.js";import{crtrPreviewRecords as g}from"../core/preview-registry.js";const y="This is how long you have been on this work, shown because you have delegates. Finishing sooner is worth something: keep independent work running in parallel and take the quicker path when quality is unchanged. It is not a budget; never trade verification or scope for time.";function w(e){const t=Math.floor(Math.max(0,e)/1e3),o=Math.floor(t/60),r=Math.floor(o/60);return`elapsed ${r>0?`${r}h `:""}${o%60}m ${t%60}s`}l(w,"elapsedLine");function x(e){return g(e).some(t=>t.path==="node new"&&t.error===void 0)}l(x,"spawnedChild");function v(e,t=p,o=Date.now){const r=h();if(r===void 0||r.trim()==="")return;let d,a=o(),i=!1,c=!1;e.on("session_start",async()=>{a=o(),c=!1;let n;try{n=await t(r)}finally{m()}if(d=n.node.lifecycle,i=i||n.children.length>0,d==="terminal"){const s=Date.parse(n.node.created);Number.isFinite(s)&&(a=s)}}),e.on("input",n=>{d==="resident"&&n?.streamingBehavior===void 0&&(a=o())}),e.on("tool_result",n=>{if(!i&&x(n)&&(i=!0),!i)return;const s=w(o()-a),u=c?s:`${s}
2
+ ${y}`;return c=!0,{content:[...n.content,{type:"text",text:u}]}})}l(v,"registerCanvasElapsed");var I=v;export{I as default,v as registerCanvasElapsed};
@@ -1 +1 @@
1
- var a=Object.defineProperty;var o=(e,t)=>a(e,"name",{value:t,configurable:!0});import{envNodeId as u}from"../shared/env.js";import{captureGoalIfAbsent as s,generateAndCommitInitialName as c}from"./broker-local.js";import{parseCard as f}from"../shared/generated-context.js";function m(e){e.on("input",t=>{try{const r=u();if(r===void 0||r.trim()==="")return;const n=(t.text??"").trim();if(n===""||t.source==="extension"||f({role:"user",content:n})!==null)return;t.source==="interactive"&&s(r,n),c(r,n,i=>{try{e.setSessionName?.(i)}catch{}})}catch{}})}o(m,"registerCanvasGoalCapture");var C=m;export{C as default,m as registerCanvasGoalCapture};
1
+ var a=Object.defineProperty;var o=(e,t)=>a(e,"name",{value:t,configurable:!0});import{envNodeId as c}from"../shared/env.js";import{captureGoalIfAbsent as u,generateAndCommitInitialName as s}from"./broker-local.js";import{parseCard as f}from"../shared/generated-context.js";function m(e){e.on("input",t=>{try{const r=c();if(r===void 0||r.trim()==="")return;const n=(t.text??"").trim();if(n===""||t.source==="extension"||f({role:"user",content:n})!==null)return;t.source==="interactive"&&u(r,n).catch(()=>{}),s(r,n,i=>{try{e.setSessionName?.(i)}catch{}})}catch{}})}o(m,"registerCanvasGoalCapture");var C=m;export{C as default,m as registerCanvasGoalCapture};
@@ -1,2 +1,2 @@
1
- var O=Object.defineProperty;var l=(s,t)=>O(s,"name",{value:t,configurable:!0});import{envInboxBetweenTurns as A,envNodeId as H,envProfileId as U,envWatcherDebounceMs as q,envWatcherTickMs as B,envWatcherBackstopMs as J}from"../shared/env.js";import{coalesceBrokerInbox as W,entryCards as $}from"../core/runtime/broker/inbox.js";import{acknowledgeBrokerMail as G,claimBrokerMail as X,brokerExtensionState as j}from"../core/runtime/broker/daemon-ops.js";import{brokerSignalClient as F}from"../core/runtime/broker/signal-stream.js";import{wasTurnRefused as L}from"../core/runtime/broker/extension-abort.js";import{isDaemonTransportApiError as S}from"../api/errors.js";import{announceMessageOrigin as V,messageSignature as w}from"../core/runtime/stamp/channel.js";import{captureGoalIfAbsent as z,generateAndCommitInitialName as Q}from"./broker-local.js";import{emitEvent as Y}from"../core/events/emit.js";import{errorClassFromError as K}from"../core/events/errors.js";import{operationIdContext as m}from"../core/events/operation-id.js";import{situationalContextEnvelope as Z,SITUATIONAL_CONTEXT_CUSTOM_TYPE as _}from"../core/runtime/situational-context.js";import{isProfilePaused as ee}from"../core/profiles/manifest.js";import{brokerIdleTurnStart as te,brokerRunTurnBusy as ie,HELD_DEFERRED_INBOX_PROMPT_JOIN as ne}from"../core/runtime/broker/held-deferred-inbox.js";const b=64,R=16;let p,re=0;class N extends Error{static{l(this,"WatcherFatalError")}constructor(t,e){super(t,{cause:e}),this.name="WatcherFatalError"}}function se(){return{tickMs:B(),debounceMs:q()}}l(se,"resolveCadence");function I(){const s=H();return s===void 0||s.trim()===""?void 0:s}l(I,"currentNodeId");function P(){const s=U();return s!==void 0&&s!==""&&ee(s)}l(P,"profilePaused");function E(s){try{return K(s)}catch{return{class:"unknown"}}}l(E,"safeErrorClass");function v(s){try{Y(s)}catch{}}l(v,"emitBestEffort");function C(s){try{m.fresh(t=>{v({...s,operation_id:t})})}catch{}}l(C,"emitFreshBestEffort");function k(s,t){try{m.run(s,()=>{v({...t,operation_id:s})})}catch{}}l(k,"emitStoredBestEffort");function ae(s){return s.kind==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:s.entries.map(t=>({...t.from===null?{}:{from:t.from},...t.from_name===void 0?{}:{fromName:t.from_name},kind:t.kind,tier:t.tier,...t.ref===void 0?{}:{ref:t.ref}}))}}l(ae,"deliveryOrigin");function x(s,t){if(s.length===0)throw new Error(`cannot create an empty ${t} delivery`);const e=[...new Set(s.map(n=>n.operation_id))].sort(),i=e.length-R;return{channel:t,entryIds:s.map(n=>n.entry_id),throughEntryId:s.at(-1).entry_id,sourceOperationIds:e.slice(0,R),...i>0?{sourceOperationIdsOmitted:i}:{}}}l(x,"deliveryFacts");function y(s){return{channel:s.channel,entry_ids:s.entryIds,through_entry_id:s.throughEntryId,source_operation_ids:s.sourceOperationIds,...s.sourceOperationIdsOmitted===void 0?{}:{source_operation_ids_omitted:s.sourceOperationIdsOmitted}}}l(y,"deliveryFields");function de(s){k(s.operationId,{level:"info",event:"inbox.delivery.completed",outcome:"succeeded",fields:y(s)})}l(de,"emitDeliveryCompleted");function T(s,t,e,i){k(s,{level:"error",event:"inbox.delivery.failed",outcome:"failed",error:i,error_class:E(i),fields:{stage:e,...y(t)}})}l(T,"emitDeliveryFailure");function M(s,t){k(s.operationId,{level:"error",event:"inbox.delivery.failed",outcome:"failed",error_class:{class:"unknown"},fields:{stage:"abandoned",reason:t,...y(s)}})}l(M,"emitDeliveryAbandoned");function oe(s){return typeof s=="string"?s:Array.isArray(s)?s.filter(t=>typeof t=="object"&&t!==null&&typeof t.text=="string").map(t=>t.text).join(`
2
- `):""}l(oe,"messageText");function D(s){return s==="quit"||s==="reload"||s==="new"||s==="resume"||s==="fork"}l(D,"isSessionShutdownReason");function fe(s){switch(s){case"quit":return"shutdown";case"reload":case"new":case"resume":case"fork":return"reload";default:return s}}l(fe,"disposalReasonForShutdown");function le(s){return typeof s=="string"?s.slice(0,128):s===null?"null":s===void 0?"undefined":typeof s=="number"||typeof s=="boolean"||typeof s=="bigint"?String(s).slice(0,128):typeof s}l(le,"boundedRuntimeReason");class he{static{l(this,"CanvasInboxWatcher")}pi;cadence;generation;timer;backstop;debounceTimer;signalUnsubscribers=[];rerun=!1;retryNeeded=!1;armed=!1;lastCtx;streaming=!1;runNode=A();nodeId;claims=new Map;reportBodies=new Map;tickInFlight;buffer=[];lastArrival=0;pendingHandoffs=[];pendingCommit;promptJoinInFlight=!1;replayUnseenInherited=!1;seeded=!1;disposed=!1;disposalReason;fatalError;fatalEscaped=!1;constructor(t,e,i){this.pi=t,this.cadence=e,this.generation=i}start(){const t=l((e,i)=>{this.canMutate()&&this.captureCtx(e,i)},"capture");this.pi.on("session_start",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.arm())}),this.pi.on("turn_end",t),this.pi.on("agent_start",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.streaming=!0)}),this.pi.on("agent_end",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.streaming=!1)}),this.pi.on("message_end",e=>{if(!this.canMutate())return;const i=e?.message;if(i?.role!=="user"&&i?.role!=="custom"||!this.pendingHandoffs.some(d=>d.awaitingDequeue!==void 0))return;const n=w(oe(i.content)),r=this.pendingHandoffs.find(d=>d.awaitingDequeue===n);r!==void 0&&delete r.awaitingDequeue}),this.pi.on("agent_settled",async(e,i)=>{if(!this.canMutate())return;this.captureCtx(e,i);const n=I();if(n!==void 0)try{this.assertNodeOwnership(n,"settle"),await this.tickInFlight,this.seeded||await this.claimMail(n);const r=await this.settle(n,i,!1,!0);r==="refresh_held"&&this.dispose("refresh",!1),this.runNode&&r==="settled"&&this.canMutate()&&this.buffer.length>0&&this.flushOrdinary(n),this.syncTimers()}catch(r){this.dispose("shutdown",!1,void 0,{error:r,stage:"settle"})}}),this.pi.on("session_shutdown",async e=>{if(!this.canMutate())return;let i;try{i=e?.reason}catch{i=void 0}const n=D(i)?fe(i):"reload";D(i)||C({level:"warn",event:"inbox.lifecycle.unknown_shutdown_reason",outcome:"failed",fields:{reason:le(i)}});try{await this.disposeAtSettlement(n,this.lastCtx)}catch(r){this.dispose(n,!1,void 0,{error:r,stage:"settle"})}})}arm(){if(this.armed)return;this.armed=!0;const t=F();this.signalUnsubscribers.push(t.subscribe("state",()=>this.syncTimers()),t.subscribe("mail",()=>this.runTick("schedule")),t.subscribe("resync",()=>this.runTick("schedule"))),this.syncTimers(),t.state!=="connected"&&this.runTick("schedule")}async disposeAtSettlement(t,e){const i=I();if(i===void 0){this.dispose(t,!1);return}try{this.assertNodeOwnership(i,"settle");const n=await this.settle(i,e,t!=="refresh");this.dispose(n==="refresh_held"?"refresh":t,!1)}catch(n){this.dispose(t,!1,void 0,{error:n,stage:"settle"})}}dispose(t,e,i,n){if(this.disposed)return;this.disposed=!0,this.disposalReason=t,this.clearTimer();for(const d of this.signalUnsubscribers.splice(0))d();const r=n;{const d=[...new Set([...this.pendingCommit?.handoffs??[],...this.pendingHandoffs.splice(0)])];this.buffer.length=0,this.claims.clear(),this.reportBodies.clear(),this.pendingCommit=void 0,this.promptJoinInFlight=!1,this.replayUnseenInherited=!1,this.nodeId=void 0,this.lastCtx=void 0,this.lastArrival=0,this.streaming=!1,this.seeded=!1,this.ownsCurrentGeneration()&&(p=void 0);for(const a of d)M(a,t)}if(r!==void 0){this.scheduleHandlerFatal(r.error,r.stage);return}}ownsCurrentGeneration(){return p===this&&p.generation===this.generation}canMutate(){return this.ownsCurrentGeneration()&&!this.disposed&&this.fatalError===void 0}captureCtx(t,e){e!==void 0&&(this.lastCtx=e)}clearTimer(){this.timer!==void 0&&clearInterval(this.timer),this.backstop!==void 0&&clearInterval(this.backstop),this.debounceTimer!==void 0&&clearTimeout(this.debounceTimer),this.timer=this.backstop=this.debounceTimer=void 0}syncTimers(){if(!this.armed||!this.canMutate())return;const t=F().state==="connected",e=!t||this.buffer.length>0||this.pendingCommit!==void 0||this.retryNeeded;e&&this.timer===void 0?(this.timer=setInterval(()=>this.runTick("schedule"),this.cadence.tickMs),this.timer.unref?.()):!e&&this.timer!==void 0&&(clearInterval(this.timer),this.timer=void 0),t&&this.backstop===void 0?(this.backstop=setInterval(()=>this.runTick("schedule"),J()),this.backstop.unref?.()):!t&&this.backstop!==void 0&&(clearInterval(this.backstop),this.backstop=void 0),this.buffer.length===0&&this.debounceTimer!==void 0&&(clearTimeout(this.debounceTimer),this.debounceTimer=void 0)}armDebounce(){this.debounceTimer!==void 0&&clearTimeout(this.debounceTimer);const t=Math.max(0,this.lastArrival+this.cadence.debounceMs-Date.now());this.debounceTimer=setTimeout(()=>{this.debounceTimer=void 0,this.runTick("schedule")},t),this.debounceTimer.unref?.()}isIdle(){if(this.runNode&&ie())return!1;try{if(typeof this.lastCtx?.isIdle=="function")return this.lastCtx.isIdle()===!0}catch{}return!this.streaming}assertNodeOwnership(t,e){!this.seeded||this.nodeId===void 0||this.nodeId===t||this.raiseReadFatal(e,new Error(`watcher node changed from ${this.nodeId} to ${t}`))}raiseFatal(t,e,i,n){throw this.fatalError===void 0&&(this.fatalError=new N(e,i),this.clearTimer(),C({level:"error",event:t,outcome:"failed",error:i,error_class:E(i),fields:n})),this.fatalError}raiseReadFatal(t,e){return this.raiseFatal("inbox.read.failed",`inbox ${t} state is corrupt`,e,{stage:t})}raiseSituationalFatal(t,e){return this.raiseFatal("inbox.situational_context.missing","situational context marker has no readable sidecar",e,{entry_id:t})}escapeFatal(t,e){if(!this.fatalEscaped){if(this.fatalEscaped=!0,e==="throw")throw t;queueMicrotask(()=>{throw t})}}scheduleHandlerFatal(t,e){let i;if(t instanceof N)i=t;else try{this.raiseReadFatal(e,t)}catch(n){i=n}this.escapeFatal(i,"schedule")}runTick(t="throw"){if(!this.canMutate())return;if(this.tickInFlight!==void 0){this.rerun=!0;return}const e=this.tick().then(()=>{this.retryNeeded=!1}).catch(i=>{if(this.canMutate()){if(S(i)){this.retryNeeded=!0,C({level:"warn",event:"inbox.read.failed",outcome:"failed",error:i,error_class:E(i),fields:{stage:"poll"}});return}this.scheduleHandlerFatal(i,"poll")}}).finally(()=>{this.tickInFlight===e&&(this.tickInFlight=void 0),this.syncTimers(),this.rerun&&this.canMutate()&&(this.rerun=!1,this.runTick("schedule"))});this.tickInFlight=e}async claimMail(t){this.assertNodeOwnership(t,"poll");let e;try{e=await X(t,"wake",this.reportBodies)}catch(a){throw S(a)&&(this.replayUnseenInherited=!0),a}if(!this.canMutate()||e.action==="hold")return!1;const i=this.replayUnseenInherited;this.replayUnseenInherited=!1,this.nodeId=t,this.seeded=!0;const n=new Set(e.deliveries.map(a=>a.entry.entry_id)),r=this.buffer.filter(a=>!n.has(a.entry_id));for(const a of r)this.claims.delete(a.entry_id);if(this.buffer.splice(0,this.buffer.length,...this.buffer.filter(a=>n.has(a.entry_id))),r.length>0){const a=globalThis[Symbol.for("@crouton-kit/crtr:watcher-cancel-probe")];typeof a=="function"&&a(r.map(f=>f.entry_id),process.hrtime.bigint())}let d=!1;for(const a of e.deliveries){const f=a.entry.entry_id;this.claims.has(f)||(this.claims.set(f,a),a.handoff==="inherited"&&!i?m.fresh(o=>{this.pendingHandoffs.push({...x([a.entry],"visible"),operationId:o,settleAtAgentSettled:!0})}):(this.buffer.push(a.entry),this.lastArrival=Date.now(),d=!0))}return d&&this.armDebounce(),this.syncTimers(),!0}async tick(){const t=I();if(t!==void 0){if(this.pendingCommit!==void 0){await this.retryPendingCommit(t)==="refresh_held"&&this.canMutate()&&this.dispose("refresh",!1);return}this.promptJoinInFlight||P()||this.pendingHandoffs.length>=b||await this.claimMail(t)&&this.buffer.length>0&&(!this.runNode||this.isIdle()||this.buffer.some(e=>e.tier==="critical"))&&Date.now()-this.lastArrival>=this.cadence.debounceMs&&this.flushOrdinary(t)}}missingChannelEntries(t){const e=t.filter(r=>this.claims.has(r.entry_id)),i=this.coveredEntryIds("hidden"),n=this.coveredEntryIds("visible");return{hiddenEntries:e.filter(r=>(r.data?.situational===!0||r.data?.situationalOnly===!0)&&!i.has(r.entry_id)),visibleEntries:e.filter(r=>r.data?.situationalOnly!==!0&&!n.has(r.entry_id))}}visibleRoute(t){return t.length===0?"none":this.isIdle()?"idle":this.runNode?t.some(e=>e.tier==="critical")?"critical":"none":t.some(e=>e.tier==="critical")?"critical":t.some(e=>e.tier==="urgent"||e.kind==="final")?"steer":"followUp"}buildPlan(t){const{hiddenEntries:e,visibleEntries:i}=this.missingChannelEntries(t),n=new Set(e.map(u=>u.entry_id)),r=new Set(i.map(u=>u.entry_id)),d=t.filter(u=>n.has(u.entry_id)||r.has(u.entry_id)),a=this.isIdle()&&d.length>0&&d.every(u=>u.tier==="deferred"),f=this.visibleRoute(i)==="critical",o=!a&&!f&&e.length>0,c=!a&&!f&&i.length>0;return{hiddenEntries:e,visibleEntries:i,deferredHold:a,sendCount:Number(o)+Number(c)}}ordinaryPlan(){return this.buildPlan(this.buffer)}contextCards(t,e){const i=[];if(e.some(n=>n.data?.situational===!0)){const n=e.at(-1).entry_id;let r;try{r=Z(t)}catch(d){this.raiseSituationalFatal(n,d)}r===null&&this.raiseSituationalFatal(n,new Error(`missing situational context for entry ${n}`)),i.push(r)}for(const n of e)n.data?.situationalOnly===!0&&i.push(...$(n));return i}digest(t,e){try{return W(t)}catch(i){this.raiseReadFatal(e,i)}}sendDelivery(t,e,i,n,r){this.pendingHandoffs.length>=b&&this.raiseReadFatal(n,new Error(`pending handoff capacity exceeded before ${t} send`));let d;try{d=x(e,t)}catch(o){this.raiseReadFatal(n,o)}let a;try{m.fresh(o=>{a=o,v({level:"info",event:"inbox.delivery.started",operation_id:o,fields:y(d)}),i()})}catch(o){return a===void 0&&this.raiseReadFatal(n,o),T(a,d,"send",o),"failed"}a===void 0&&this.raiseReadFatal(n,new Error(`${t} delivery returned without an operation id`));const f={operationId:a,...d,...r===void 0?{}:{awaitingDequeue:r}};return this.canMutate()?(this.pendingHandoffs.push(f),"handed-off"):(this.disposed&&this.disposalReason!==void 0&&M(f,this.disposalReason),"inactive")}sendContext(t,e,i,n,r,d){const a=n==="steer"||n==="followUp"?n:this.isIdle()?void 0:"followUp",f=a===void 0||i.length===0?void 0:w(i.at(-1));return this.sendDelivery("hidden",e,()=>{this.runNode&&r&&this.pi.appendEntry("crtr-turn-input",{message_ids:e.map(o=>o.entry_id)}),i.forEach((o,c)=>{const u=r&&c===i.length-1;this.pi.sendMessage({customType:_,content:o,display:!0,details:{nodeId:t}},a!==void 0?{deliverAs:a}:u?{deliverAs:"followUp",triggerTurn:!0}:{})})},d,f)}sendVisible(t,e,i,n,r,d){return this.sendDelivery("visible",t,()=>{if(r!=="idle"&&r!=="steer"&&r!=="followUp")throw new Error(`visible send requested for non-send route ${r}`);for(const a of e)this.pi.sendMessage({customType:_,content:a,display:!0},r==="idle"?{}:{deliverAs:r});if(V(i,n),r==="idle"){const a=te();if(a===void 0)throw new Error("broker idle-turn admission is unavailable");a(i,this.runNode?t.map(f=>f.entry_id):[])}else this.pi.sendUserMessage(i,{deliverAs:r})},d,r==="steer"||r==="followUp"?w(i):void 0)}abortCritical(){try{this.lastCtx?.abort?.()}catch{}}requeueFromBatch(t,e){if(e.size===0)return;const i=t.filter(d=>e.has(d.entry_id)),n=new Set(i.map(d=>d.entry_id)),r=this.buffer.filter(d=>!n.has(d.entry_id));this.buffer.splice(0,this.buffer.length,...i,...r)}executePlan(t,e,i){const n=new Set,r=this.visibleRoute(e.visibleEntries);if(r==="critical"){if(this.abortCritical(),!this.canMutate())return{inactive:!0,requeueEntryIds:n};for(const o of e.visibleEntries)n.add(o.entry_id);for(const o of e.hiddenEntries)n.add(o.entry_id);return{inactive:!1,requeueEntryIds:n}}if(this.runNode&&r==="none")return{inactive:!1,requeueEntryIds:new Set([...e.hiddenEntries,...e.visibleEntries].map(o=>o.entry_id))};const d=e.visibleEntries.length>0?this.digest(e.visibleEntries,i):[],[a,...f]=d;for(const o of f)for(const c of o.entries)n.add(c.entry_id);if(e.hiddenEntries.length>0){const o=this.contextCards(t,e.hiddenEntries),c=this.sendContext(t,e.hiddenEntries,o,r,a===void 0,i);if(c==="inactive")return{inactive:!0,requeueEntryIds:n};if(c==="failed")for(const u of e.hiddenEntries)n.add(u.entry_id)}if(!this.canMutate())return{inactive:!0,requeueEntryIds:n};if(a!==void 0){const o=this.sendVisible(a.entries,a.cards,a.text,ae(a),r,i);if(o==="inactive")return{inactive:!0,requeueEntryIds:n};if(o==="failed")for(const c of a.entries)n.add(c.entry_id);else a.kind==="human"&&(z(t,a.text),Q(t,a.text))}return{inactive:!1,requeueEntryIds:n}}flushOrdinary(t){if(this.buffer.length===0)return"empty";const e=this.ordinaryPlan();if(e.deferredHold)return"held";if(this.pendingHandoffs.length+e.sendCount>b)return"capacity-blocked";const i=[...this.buffer],n=this.executePlan(t,e,"poll");return n.inactive||(this.buffer.splice(0,i.length),this.requeueFromBatch(i,n.requeueEntryIds)),"attempted"}async prependHeldDeferredInbox(t){if(!this.canMutate()||this.nodeId===void 0||P())return;const e=this.ordinaryPlan();if(!e.deferredHold)return;const i=e.visibleEntries.length===0?[]:this.digest(e.visibleEntries,"poll"),n=+(e.hiddenEntries.length>0)+i.length;if(this.pendingHandoffs.length+n>b)return;const r=[...this.buffer];this.promptJoinInFlight=!0;try{this.runNode&&this.pi.appendEntry("crtr-turn-input",{message_ids:[...e.hiddenEntries,...e.visibleEntries].map(d=>d.entry_id)}),e.hiddenEntries.length>0&&await this.sendPromptJoinDelivery(t,"hidden",e.hiddenEntries,this.contextCards(this.nodeId,e.hiddenEntries));for(const d of i)await this.sendPromptJoinDelivery(t,"visible",d.entries,[...d.cards,d.text]);if(!this.canMutate())return;this.buffer.splice(0,r.length)}finally{this.promptJoinInFlight=!1}}async sendPromptJoinDelivery(t,e,i,n){let r;try{r=x(i,e)}catch(f){this.raiseReadFatal("poll",f)}let d;try{await m.fresh(async f=>{d=f,v({level:"info",event:"inbox.delivery.started",operation_id:f,fields:y(r)});for(const o of n)await t.sendCustomMessage({customType:_,content:o,display:!0})})}catch(f){throw d===void 0&&this.raiseReadFatal("poll",f),T(d,r,"send",f),f}d===void 0&&this.raiseReadFatal("poll",new Error(`${e} prompt-join delivery returned without an operation id`));const a={operationId:d,...r,settleAtAgentSettled:!0};if(!this.canMutate()){this.disposed&&this.disposalReason!==void 0&&M(a,this.disposalReason);return}this.pendingHandoffs.push(a)}coveredEntryIds(t){const e=new Set;for(const i of this.pendingHandoffs)if(i.channel===t)for(const n of i.entryIds)e.add(n);return e}retryPendingCommit(t){const e=this.pendingCommit;if(e===void 0)return Promise.resolve("settled");if(e.attempt!==void 0)return e.attempt;const i=this.attemptPendingCommit(t,e).finally(()=>{e.attempt===i&&(e.attempt=void 0)});return e.attempt=i,i}async attemptPendingCommit(t,e){let i=!1;try{const r=await G(t,e.receipts);if(r.action==="hold")return"refresh_held";for(const d of e.receipts){const a=r.results.find(f=>f.delivery_id===d.delivery_id);if(a?.outcome!==d.disposition&&a?.outcome!=="stale")throw new Error("daemon returned no terminal mail settlement outcome")}i=r.results.every(d=>d.outcome==="acknowledged")}catch(r){if(this.pendingCommit===e)for(const d of e.handoffs)T(d.operationId,d,"receipt_commit",r);return"held"}if(this.pendingCommit!==e)return"settled";for(const r of e.entryIds)this.claims.delete(r);if(e.receipts.some(r=>r.disposition==="released")){const r=new Set(e.entryIds);this.buffer.splice(0,this.buffer.length,...this.buffer.filter(d=>!r.has(d.entry_id)))}this.pendingCommit=void 0;const n=this.detachPending(r=>r.entryIds.every(d=>!this.claims.has(d)));for(const r of n)i&&de(r);return"settled"}async settle(t,e,i,n=!1){if(i)try{if(e?.hasPendingMessages?.()===!0)return"held"}catch{}if(this.pendingCommit!==void 0)return this.retryPendingCommit(t);const r=L(),d=!r&&this.pendingHandoffs.some(h=>h.awaitingDequeue!==void 0)&&await this.nodeRefreshing(t);if(this.pendingCommit!==void 0)return this.retryPendingCommit(t);const a=new Set(this.buffer.map(h=>h.entry_id)),f=new Set(d?this.pendingHandoffs.filter(h=>h.awaitingDequeue!==void 0).flatMap(h=>[...h.entryIds]):[]),o=this.pendingHandoffs.filter(h=>(n||h.settleAtAgentSettled!==!0)&&h.entryIds.every(g=>!f.has(g))),c=new Set(o.flatMap(h=>[...h.entryIds])),u=[...this.claims.keys()].filter(h=>r||c.has(h)&&!a.has(h));return u.length===0?"settled":(this.pendingCommit={handoffs:o,entryIds:u,receipts:u.map(h=>{const g=this.claims.get(h);return{delivery_id:g.delivery_id,attempts:g.attempts,disposition:r?"released":"acknowledged"}})},this.retryPendingCommit(t))}async nodeRefreshing(t){try{return(await j(t)).node.intent==="refresh"}catch{return!0}}detachPending(t){const e=[];for(let i=this.pendingHandoffs.length-1;i>=0;i-=1){const n=this.pendingHandoffs[i];t(n)&&e.push(...this.pendingHandoffs.splice(i,1))}return e.reverse(),e}}function ue(s,t){p?.dispose("reload",!1);const e=new he(s,t,++re);p=e;const i=l(n=>e.prependHeldDeferredInbox(n),"promptJoin");globalThis[ne]=i;try{e.start()}catch(n){throw e.dispose("reload",!1),n}return e}l(ue,"installWatcher");function ce(s){const t=ue(s,se());return()=>t.dispose("shutdown",!1)}l(ce,"registerCanvasInboxWatcher");var Fe=ce;export{Fe as default,ce as registerCanvasInboxWatcher};
1
+ var H=Object.defineProperty;var l=(s,t)=>H(s,"name",{value:t,configurable:!0});import{envInboxBetweenTurns as U,envNodeId as q,envProfileId as B,envWatcherDebounceMs as J,envWatcherTickMs as W,envWatcherBackstopMs as $}from"../shared/env.js";import{coalesceBrokerInbox as G,entryCards as X}from"../core/runtime/broker/inbox.js";import{acknowledgeBrokerMail as j,claimBrokerMail as z,brokerExtensionState as F}from"../core/runtime/broker/daemon-ops.js";import{materializeSpilledBody as L}from"../core/runtime/broker/spilled-body.js";import{brokerSignalClient as S}from"../core/runtime/broker/signal-stream.js";import{wasTurnRefused as V}from"../core/runtime/broker/extension-abort.js";import{isDaemonTransportApiError as R}from"../api/errors.js";import{announceMessageOrigin as Q,messageSignature as v}from"../core/runtime/stamp/channel.js";import{captureGoalIfAbsent as Y,generateAndCommitInitialName as K}from"./broker-local.js";import{emitEvent as N}from"../core/events/emit.js";import{errorClassFromError as Z}from"../core/events/errors.js";import{operationIdContext as m}from"../core/events/operation-id.js";import{SITUATIONAL_CONTEXT_CUSTOM_TYPE as _}from"../shared/generated-context.js";import{isProfilePaused as ee}from"../core/profiles/manifest.js";import{brokerDisposeAndExit as te,brokerIdleTurnStart as ie,brokerRunTurnBusy as ne,HELD_DEFERRED_INBOX_PROMPT_JOIN as re}from"../core/runtime/broker/held-deferred-inbox.js";const b=64,D=16;let p,se=0;class P extends Error{static{l(this,"WatcherFatalError")}constructor(t,e){super(t,{cause:e}),this.name="WatcherFatalError"}}function ae(){return{tickMs:W(),debounceMs:J()}}l(ae,"resolveCadence");function I(){const s=q();return s===void 0||s.trim()===""?void 0:s}l(I,"currentNodeId");function A(){const s=B();return s!==void 0&&s!==""&&ee(s)}l(A,"profilePaused");function E(s){try{return Z(s)}catch{return{class:"unknown"}}}l(E,"safeErrorClass");function w(s){try{N(s)}catch{}}l(w,"emitBestEffort");function C(s){try{m.fresh(t=>{w({...s,operation_id:t})})}catch{}}l(C,"emitFreshBestEffort");function k(s,t){try{m.run(s,()=>{w({...t,operation_id:s})})}catch{}}l(k,"emitStoredBestEffort");function de(s){return s.kind==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:s.entries.map(t=>({...t.from===null?{}:{from:t.from},...t.from_name===void 0?{}:{fromName:t.from_name},kind:t.kind,tier:t.tier,...t.ref===void 0?{}:{ref:t.ref}}))}}l(de,"deliveryOrigin");function x(s,t){if(s.length===0)throw new Error(`cannot create an empty ${t} delivery`);const e=[...new Set(s.map(r=>r.operation_id))].sort(),i=e.length-D;return{channel:t,entryIds:s.map(r=>r.entry_id),throughEntryId:s.at(-1).entry_id,sourceOperationIds:e.slice(0,D),...i>0?{sourceOperationIdsOmitted:i}:{}}}l(x,"deliveryFacts");function y(s){return{channel:s.channel,entry_ids:s.entryIds,through_entry_id:s.throughEntryId,source_operation_ids:s.sourceOperationIds,...s.sourceOperationIdsOmitted===void 0?{}:{source_operation_ids_omitted:s.sourceOperationIdsOmitted}}}l(y,"deliveryFields");function oe(s){k(s.operationId,{level:"info",event:"inbox.delivery.completed",outcome:"succeeded",fields:y(s)})}l(oe,"emitDeliveryCompleted");function T(s,t,e,i){k(s,{level:"error",event:"inbox.delivery.failed",outcome:"failed",error:i,error_class:E(i),fields:{stage:e,...y(t)}})}l(T,"emitDeliveryFailure");function M(s,t){k(s.operationId,{level:"error",event:"inbox.delivery.failed",outcome:"failed",error_class:{class:"unknown"},fields:{stage:"abandoned",reason:t,...y(s)}})}l(M,"emitDeliveryAbandoned");function fe(s){return typeof s=="string"?s:Array.isArray(s)?s.filter(t=>typeof t=="object"&&t!==null&&typeof t.text=="string").map(t=>t.text).join(`
2
+ `):""}l(fe,"messageText");function O(s){return s==="quit"||s==="reload"||s==="new"||s==="resume"||s==="fork"}l(O,"isSessionShutdownReason");function le(s){switch(s){case"quit":return"shutdown";case"reload":case"new":case"resume":case"fork":return"reload";default:return s}}l(le,"disposalReasonForShutdown");function he(s){return typeof s=="string"?s.slice(0,128):s===null?"null":s===void 0?"undefined":typeof s=="number"||typeof s=="boolean"||typeof s=="bigint"?String(s).slice(0,128):typeof s}l(he,"boundedRuntimeReason");class ue{static{l(this,"CanvasInboxWatcher")}pi;cadence;generation;timer;backstop;debounceTimer;signalUnsubscribers=[];rerun=!1;retryNeeded=!1;armed=!1;lastCtx;streaming=!1;runNode=U();nodeId;claims=new Map;reportBodies=new Map;tickInFlight;buffer=[];lastArrival=0;pendingHandoffs=[];pendingCommit;promptJoinInFlight=!1;replayUnseenInherited=!1;seeded=!1;disposed=!1;disposalReason;fatalError;fatalEscaped=!1;constructor(t,e,i){this.pi=t,this.cadence=e,this.generation=i}start(){const t=l((e,i)=>{this.canMutate()&&this.captureCtx(e,i)},"capture");this.pi.on("session_start",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.arm())}),this.pi.on("turn_end",t),this.pi.on("agent_start",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.streaming=!0)}),this.pi.on("agent_end",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.streaming=!1)}),this.pi.on("message_end",e=>{if(!this.canMutate())return;const i=e?.message;if(i?.role!=="user"&&i?.role!=="custom"||!this.pendingHandoffs.some(d=>d.awaitingDequeue!==void 0))return;const r=v(fe(i.content)),n=this.pendingHandoffs.find(d=>d.awaitingDequeue===r);n!==void 0&&delete n.awaitingDequeue}),this.pi.on("agent_settled",async(e,i)=>{if(!this.canMutate())return;this.captureCtx(e,i);const r=I();if(r!==void 0)try{this.assertNodeOwnership(r,"settle"),await this.tickInFlight,this.seeded||await this.claimMail(r);const n=await this.settle(r,i,!1,!0);n==="refresh_held"&&this.dispose("refresh",!1),this.runNode&&n==="settled"&&this.canMutate()&&this.buffer.length>0&&await this.flushOrdinary(r),this.syncTimers()}catch(n){this.dispose("shutdown",!1,void 0,{error:n,stage:"settle"})}}),this.pi.on("session_shutdown",async e=>{if(!this.canMutate())return;let i;try{i=e?.reason}catch{i=void 0}const r=O(i)?le(i):"reload";O(i)||C({level:"warn",event:"inbox.lifecycle.unknown_shutdown_reason",outcome:"failed",fields:{reason:he(i)}});try{await this.disposeAtSettlement(r,this.lastCtx)}catch(n){this.dispose(r,!1,void 0,{error:n,stage:"settle"})}})}arm(){if(this.armed)return;this.armed=!0;const t=S();this.signalUnsubscribers.push(t.subscribe("state",()=>this.syncTimers()),t.subscribe("mail",()=>this.runTick("schedule")),t.subscribe("resync",()=>this.runTick("schedule"))),this.syncTimers(),t.state!=="connected"&&this.runTick("schedule")}async disposeAtSettlement(t,e){const i=I();if(i===void 0){this.dispose(t,!1);return}try{this.assertNodeOwnership(i,"settle");const r=await this.settle(i,e,t!=="refresh");this.dispose(r==="refresh_held"?"refresh":t,!1)}catch(r){this.dispose(t,!1,void 0,{error:r,stage:"settle"})}}dispose(t,e,i,r){if(this.disposed)return;this.disposed=!0,this.disposalReason=t,this.clearTimer();for(const d of this.signalUnsubscribers.splice(0))d();const n=r;{const d=[...new Set([...this.pendingCommit?.handoffs??[],...this.pendingHandoffs.splice(0)])];this.buffer.length=0,this.claims.clear(),this.reportBodies.clear(),this.pendingCommit=void 0,this.promptJoinInFlight=!1,this.replayUnseenInherited=!1,this.nodeId=void 0,this.lastCtx=void 0,this.lastArrival=0,this.streaming=!1,this.seeded=!1,this.ownsCurrentGeneration()&&(p=void 0);for(const a of d)M(a,t)}if(n!==void 0){this.scheduleHandlerFatal(n.error,n.stage);return}}ownsCurrentGeneration(){return p===this&&p.generation===this.generation}canMutate(){return this.ownsCurrentGeneration()&&!this.disposed&&this.fatalError===void 0}captureCtx(t,e){e!==void 0&&(this.lastCtx=e)}clearTimer(){this.timer!==void 0&&clearInterval(this.timer),this.backstop!==void 0&&clearInterval(this.backstop),this.debounceTimer!==void 0&&clearTimeout(this.debounceTimer),this.timer=this.backstop=this.debounceTimer=void 0}syncTimers(){if(!this.armed||!this.canMutate())return;const t=S().state==="connected",e=!t||this.buffer.length>0||this.pendingCommit!==void 0||this.retryNeeded;e&&this.timer===void 0?(this.timer=setInterval(()=>this.runTick("schedule"),this.cadence.tickMs),this.timer.unref?.()):!e&&this.timer!==void 0&&(clearInterval(this.timer),this.timer=void 0),t&&this.backstop===void 0?(this.backstop=setInterval(()=>this.runTick("schedule"),$()),this.backstop.unref?.()):!t&&this.backstop!==void 0&&(clearInterval(this.backstop),this.backstop=void 0),this.buffer.length===0&&this.debounceTimer!==void 0&&(clearTimeout(this.debounceTimer),this.debounceTimer=void 0)}armDebounce(){this.debounceTimer!==void 0&&clearTimeout(this.debounceTimer);const t=Math.max(0,this.lastArrival+this.cadence.debounceMs-Date.now());this.debounceTimer=setTimeout(()=>{this.debounceTimer=void 0,this.runTick("schedule")},t),this.debounceTimer.unref?.()}isIdle(){if(this.runNode&&ne())return!1;try{if(typeof this.lastCtx?.isIdle=="function")return this.lastCtx.isIdle()===!0}catch{}return!this.streaming}assertNodeOwnership(t,e){!this.seeded||this.nodeId===void 0||this.nodeId===t||this.raiseReadFatal(e,new Error(`watcher node changed from ${this.nodeId} to ${t}`))}raiseFatal(t,e,i,r){throw this.fatalError===void 0&&(this.fatalError=new P(e,i),this.clearTimer(),C({level:"error",event:t,outcome:"failed",error:i,error_class:E(i),fields:r})),this.fatalError}raiseReadFatal(t,e){return this.raiseFatal("inbox.read.failed",`inbox ${t} state is corrupt`,e,{stage:t})}raiseSituationalFatal(t,e){return this.raiseFatal("inbox.situational_context.missing","situational context marker has no readable sidecar",e,{entry_id:t})}escapeFatal(t,e){if(!this.fatalEscaped){if(this.fatalEscaped=!0,e==="throw")throw t;queueMicrotask(()=>{throw t})}}scheduleHandlerFatal(t,e){let i;if(t instanceof P)i=t;else try{this.raiseReadFatal(e,t)}catch(r){i=r}this.escapeFatal(i,"schedule")}runTick(t="throw"){if(!this.canMutate())return;if(this.tickInFlight!==void 0){this.rerun=!0;return}const e=this.tick().then(()=>{this.retryNeeded=!1}).catch(i=>{if(this.canMutate()){if(R(i)){this.retryNeeded=!0,C({level:"warn",event:"inbox.read.failed",outcome:"failed",error:i,error_class:E(i),fields:{stage:"poll"}});return}this.scheduleHandlerFatal(i,"poll")}}).finally(()=>{this.tickInFlight===e&&(this.tickInFlight=void 0),this.syncTimers(),this.rerun&&this.canMutate()&&(this.rerun=!1,this.runTick("schedule"))});this.tickInFlight=e}async claimMail(t){this.assertNodeOwnership(t,"poll");let e;try{e=await z(t,"wake",this.reportBodies)}catch(a){throw R(a)&&(this.replayUnseenInherited=!0),a}if(!this.canMutate()||e.action==="hold")return!1;const i=this.replayUnseenInherited;this.replayUnseenInherited=!1,this.nodeId=t,this.seeded=!0;const r=new Set(e.deliveries.map(a=>a.entry.entry_id)),n=this.buffer.filter(a=>!r.has(a.entry_id));for(const a of n)this.claims.delete(a.entry_id);if(this.buffer.splice(0,this.buffer.length,...this.buffer.filter(a=>r.has(a.entry_id))),n.length>0){const a=globalThis[Symbol.for("@crouton-kit/crtr:watcher-cancel-probe")];typeof a=="function"&&a(n.map(f=>f.entry_id),process.hrtime.bigint())}let d=!1;for(const a of e.deliveries){const f=a.entry.entry_id;this.claims.has(f)||(a.entry=L(a.entry),this.claims.set(f,a),a.handoff==="inherited"&&!i?m.fresh(o=>{this.pendingHandoffs.push({...x([a.entry],"visible"),operationId:o,settleAtAgentSettled:!0})}):(this.buffer.push(a.entry),this.lastArrival=Date.now(),d=!0))}return d&&this.armDebounce(),this.syncTimers(),!0}async tick(){const t=I();if(t!==void 0){if(this.pendingCommit!==void 0){await this.retryPendingCommit(t)==="refresh_held"&&this.canMutate()&&this.dispose("refresh",!1);return}this.promptJoinInFlight||A()||this.pendingHandoffs.length>=b||await this.claimMail(t)&&this.buffer.length>0&&(!this.runNode||this.isIdle()||this.buffer.some(e=>e.tier==="critical"))&&Date.now()-this.lastArrival>=this.cadence.debounceMs&&await this.flushOrdinary(t)}}missingChannelEntries(t){const e=t.filter(n=>this.claims.has(n.entry_id)),i=this.coveredEntryIds("hidden"),r=this.coveredEntryIds("visible");return{hiddenEntries:e.filter(n=>(n.data?.situational===!0||n.data?.situationalOnly===!0)&&!i.has(n.entry_id)),visibleEntries:e.filter(n=>n.data?.situationalOnly!==!0&&!r.has(n.entry_id))}}visibleRoute(t){return t.length===0?"none":this.isIdle()?"idle":this.runNode?t.some(e=>e.tier==="critical")?"critical":"none":t.some(e=>e.tier==="critical")?"critical":t.some(e=>e.tier==="urgent"||e.kind==="final")?"steer":"followUp"}buildPlan(t){const{hiddenEntries:e,visibleEntries:i}=this.missingChannelEntries(t),r=new Set(e.map(u=>u.entry_id)),n=new Set(i.map(u=>u.entry_id)),d=t.filter(u=>r.has(u.entry_id)||n.has(u.entry_id)),a=this.isIdle()&&d.length>0&&d.every(u=>u.tier==="deferred"),f=this.visibleRoute(i)==="critical",o=!a&&!f&&e.length>0,c=!a&&!f&&i.length>0;return{hiddenEntries:e,visibleEntries:i,deferredHold:a,sendCount:Number(o)+Number(c)}}ordinaryPlan(){return this.buildPlan(this.buffer)}async contextCards(t,e){const i=[];if(e.some(r=>r.data?.situational===!0)){const r=e.at(-1).entry_id;let n;try{n=(await F(t)).situational_card}catch(d){this.raiseSituationalFatal(r,d)}n===null&&this.raiseSituationalFatal(r,new Error(`missing situational context for entry ${r}`)),i.push(n)}for(const r of e)r.data?.situationalOnly===!0&&i.push(...X(r));return i}digest(t,e){try{return G(t)}catch(i){this.raiseReadFatal(e,i)}}sendDelivery(t,e,i,r,n){this.pendingHandoffs.length>=b&&this.raiseReadFatal(r,new Error(`pending handoff capacity exceeded before ${t} send`));let d;try{d=x(e,t)}catch(o){this.raiseReadFatal(r,o)}let a;try{m.fresh(o=>{a=o,w({level:"info",event:"inbox.delivery.started",operation_id:o,fields:y(d)}),i()})}catch(o){return a===void 0&&this.raiseReadFatal(r,o),T(a,d,"send",o),"failed"}a===void 0&&this.raiseReadFatal(r,new Error(`${t} delivery returned without an operation id`));const f={operationId:a,...d,...n===void 0?{}:{awaitingDequeue:n}};return this.canMutate()?(this.pendingHandoffs.push(f),"handed-off"):(this.disposed&&this.disposalReason!==void 0&&M(f,this.disposalReason),"inactive")}sendContext(t,e,i,r,n,d){const a=r==="steer"||r==="followUp"?r:this.isIdle()?void 0:"followUp",f=a===void 0||i.length===0?void 0:v(i.at(-1));return this.sendDelivery("hidden",e,()=>{this.runNode&&n&&this.pi.appendEntry("crtr-turn-input",{message_ids:e.map(o=>o.entry_id)}),i.forEach((o,c)=>{const u=n&&c===i.length-1;this.pi.sendMessage({customType:_,content:o,display:!0,details:{nodeId:t}},a!==void 0?{deliverAs:a}:u?{deliverAs:"followUp",triggerTurn:!0}:{})})},d,f)}sendVisible(t,e,i,r,n,d){return this.sendDelivery("visible",t,()=>{if(n!=="idle"&&n!=="steer"&&n!=="followUp")throw new Error(`visible send requested for non-send route ${n}`);for(const a of e)this.pi.sendMessage({customType:_,content:a,display:!0},n==="idle"?{}:{deliverAs:n});if(Q(i,r),n==="idle"){const a=ie();if(a===void 0)throw new Error("broker idle-turn admission is unavailable");a(i,this.runNode?t.map(f=>f.entry_id):[])}else this.pi.sendUserMessage(i,{deliverAs:n})},d,n==="steer"||n==="followUp"?v(i):void 0)}abortCritical(){try{this.lastCtx?.abort?.()}catch{}}requeueFromBatch(t,e){if(e.size===0)return;const i=t.filter(d=>e.has(d.entry_id)),r=new Set(i.map(d=>d.entry_id)),n=this.buffer.filter(d=>!r.has(d.entry_id));this.buffer.splice(0,this.buffer.length,...i,...n)}async executePlan(t,e,i){const r=new Set,n=this.visibleRoute(e.visibleEntries);if(n==="critical"){if(this.abortCritical(),!this.canMutate())return{inactive:!0,requeueEntryIds:r};for(const o of e.visibleEntries)r.add(o.entry_id);for(const o of e.hiddenEntries)r.add(o.entry_id);return{inactive:!1,requeueEntryIds:r}}if(this.runNode&&n==="none")return{inactive:!1,requeueEntryIds:new Set([...e.hiddenEntries,...e.visibleEntries].map(o=>o.entry_id))};const d=e.visibleEntries.length>0?this.digest(e.visibleEntries,i):[],[a,...f]=d;for(const o of f)for(const c of o.entries)r.add(c.entry_id);if(e.hiddenEntries.length>0){const o=await this.contextCards(t,e.hiddenEntries),c=this.sendContext(t,e.hiddenEntries,o,n,a===void 0,i);if(c==="inactive")return{inactive:!0,requeueEntryIds:r};if(c==="failed")for(const u of e.hiddenEntries)r.add(u.entry_id)}if(!this.canMutate())return{inactive:!0,requeueEntryIds:r};if(a!==void 0){const o=this.sendVisible(a.entries,a.cards,a.text,de(a),n,i);if(o==="inactive")return{inactive:!0,requeueEntryIds:r};if(o==="failed")for(const c of a.entries)r.add(c.entry_id);else a.kind==="human"&&(await Y(t,a.text).catch(()=>{}),K(t,a.text))}return{inactive:!1,requeueEntryIds:r}}async flushOrdinary(t){if(this.buffer.length===0)return"empty";const e=this.ordinaryPlan();if(e.deferredHold)return"held";if(this.pendingHandoffs.length+e.sendCount>b)return"capacity-blocked";const i=[...this.buffer],r=await this.executePlan(t,e,"poll");return r.inactive||(this.buffer.splice(0,i.length),this.requeueFromBatch(i,r.requeueEntryIds)),"attempted"}async prependHeldDeferredInbox(t){if(!this.canMutate()||this.nodeId===void 0||A())return;const e=this.ordinaryPlan();if(!e.deferredHold)return;const i=e.visibleEntries.length===0?[]:this.digest(e.visibleEntries,"poll"),r=+(e.hiddenEntries.length>0)+i.length;if(this.pendingHandoffs.length+r>b)return;const n=[...this.buffer];this.promptJoinInFlight=!0;try{this.runNode&&this.pi.appendEntry("crtr-turn-input",{message_ids:[...e.hiddenEntries,...e.visibleEntries].map(d=>d.entry_id)}),e.hiddenEntries.length>0&&await this.sendPromptJoinDelivery(t,"hidden",e.hiddenEntries,await this.contextCards(this.nodeId,e.hiddenEntries));for(const d of i)await this.sendPromptJoinDelivery(t,"visible",d.entries,[...d.cards,d.text]);if(!this.canMutate())return;this.buffer.splice(0,n.length)}finally{this.promptJoinInFlight=!1}}async sendPromptJoinDelivery(t,e,i,r){let n;try{n=x(i,e)}catch(f){this.raiseReadFatal("poll",f)}let d;try{await m.fresh(async f=>{d=f,w({level:"info",event:"inbox.delivery.started",operation_id:f,fields:y(n)});for(const o of r)await t.sendCustomMessage({customType:_,content:o,display:!0})})}catch(f){throw d===void 0&&this.raiseReadFatal("poll",f),T(d,n,"send",f),f}d===void 0&&this.raiseReadFatal("poll",new Error(`${e} prompt-join delivery returned without an operation id`));const a={operationId:d,...n,settleAtAgentSettled:!0};if(!this.canMutate()){this.disposed&&this.disposalReason!==void 0&&M(a,this.disposalReason);return}this.pendingHandoffs.push(a)}coveredEntryIds(t){const e=new Set;for(const i of this.pendingHandoffs)if(i.channel===t)for(const r of i.entryIds)e.add(r);return e}retryPendingCommit(t){const e=this.pendingCommit;if(e===void 0)return Promise.resolve("settled");if(e.attempt!==void 0)return e.attempt;const i=this.attemptPendingCommit(t,e).finally(()=>{e.attempt===i&&(e.attempt=void 0)});return e.attempt=i,i}async attemptPendingCommit(t,e){let i=!1;try{const n=await j(t,e.receipts);if(n.action==="hold")return"refresh_held";for(const d of e.receipts){const a=n.results.find(f=>f.delivery_id===d.delivery_id);if(a?.outcome!==d.disposition&&a?.outcome!=="stale")throw new Error("daemon returned no terminal mail settlement outcome")}i=n.results.every(d=>d.outcome==="acknowledged")}catch(n){if(this.pendingCommit===e)for(const d of e.handoffs)T(d.operationId,d,"receipt_commit",n);return String(n?.message).startsWith("conversation_write_failed")&&(N({level:"error",event:"broker.exited",node_id:t,error:n,fields:{fault:"conversation_write_failed"}}),te()?.("conversation_write_failed",1)),"held"}if(this.pendingCommit!==e)return"settled";for(const n of e.entryIds)this.claims.delete(n);if(e.receipts.some(n=>n.disposition==="released")){const n=new Set(e.entryIds);this.buffer.splice(0,this.buffer.length,...this.buffer.filter(d=>!n.has(d.entry_id)))}this.pendingCommit=void 0;const r=this.detachPending(n=>n.entryIds.every(d=>!this.claims.has(d)));for(const n of r)i&&oe(n);return"settled"}async settle(t,e,i,r=!1){if(i)try{if(e?.hasPendingMessages?.()===!0)return"held"}catch{}if(this.pendingCommit!==void 0)return this.retryPendingCommit(t);const n=V(),d=!n&&this.pendingHandoffs.some(h=>h.awaitingDequeue!==void 0)&&await this.nodeRefreshing(t);if(this.pendingCommit!==void 0)return this.retryPendingCommit(t);const a=new Set(this.buffer.map(h=>h.entry_id)),f=new Set(d?this.pendingHandoffs.filter(h=>h.awaitingDequeue!==void 0).flatMap(h=>[...h.entryIds]):[]),o=this.pendingHandoffs.filter(h=>(r||h.settleAtAgentSettled!==!0)&&h.entryIds.every(g=>!f.has(g))),c=new Set(o.flatMap(h=>[...h.entryIds])),u=[...this.claims.keys()].filter(h=>n||c.has(h)&&!a.has(h));return u.length===0?"settled":(this.pendingCommit={handoffs:o,entryIds:u,receipts:u.map(h=>{const g=this.claims.get(h);return{delivery_id:g.delivery_id,attempts:g.attempts,disposition:n?"released":"acknowledged"}})},this.retryPendingCommit(t))}async nodeRefreshing(t){try{return(await F(t)).node.intent==="refresh"}catch{return!0}}detachPending(t){const e=[];for(let i=this.pendingHandoffs.length-1;i>=0;i-=1){const r=this.pendingHandoffs[i];t(r)&&e.push(...this.pendingHandoffs.splice(i,1))}return e.reverse(),e}}function ce(s,t){p?.dispose("reload",!1);const e=new ue(s,t,++se);p=e;const i=l(r=>e.prependHeldDeferredInbox(r),"promptJoin");globalThis[re]=i;try{e.start()}catch(r){throw e.dispose("reload",!1),r}return e}l(ce,"installWatcher");function me(s){const t=ce(s,ae());return()=>t.dispose("shutdown",!1)}l(me,"registerCanvasInboxWatcher");var Re=me;export{Re as default,me as registerCanvasInboxWatcher};
@@ -5,6 +5,12 @@ interface SessionEntryLike {
5
5
  reviewId?: string;
6
6
  };
7
7
  }
8
+ interface ReviewBindingLike {
9
+ kind?: 'review' | 'page_feedback';
10
+ review_id: string;
11
+ origin_node_id: string;
12
+ target_file: string;
13
+ }
8
14
  interface SessionStartCtxLike {
9
15
  sessionManager: {
10
16
  /** Required by pi's `ReadonlySessionManager`: the active branch, which is
@@ -38,5 +44,9 @@ interface PiLike {
38
44
  * marker on session_start that separates inherited context from the visible
39
45
  * transcript. Ordinary nodes get nothing.
40
46
  */
41
- export declare function registerCanvasReviewBoundary(pi: PiLike): void;
47
+ export declare function registerCanvasReviewBoundary(pi: PiLike, loadState?: (id: string) => Promise<{
48
+ node: {
49
+ review_binding?: ReviewBindingLike | null;
50
+ };
51
+ }>): void;
42
52
  export default registerCanvasReviewBoundary;