@north-light/crouter 0.3.349 → 0.3.351

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 (629) hide show
  1. package/bin/crtr-launcher +4 -0
  2. package/bin/runtime-generation-manifest.mjs +12 -2
  3. package/dist/api/client.d.ts +50 -7
  4. package/dist/api/client.js +2 -2
  5. package/dist/api/dto/analytics.d.ts +184 -0
  6. package/dist/api/dto/analytics.js +0 -0
  7. package/dist/api/dto/broker-ops.d.ts +43 -1
  8. package/dist/api/dto/config.d.ts +11 -0
  9. package/dist/api/dto/grants.d.ts +14 -0
  10. package/dist/api/dto/grants.js +0 -0
  11. package/dist/api/dto/human-requests.d.ts +14 -0
  12. package/dist/api/dto/memory.d.ts +6 -0
  13. package/dist/api/dto/modelauth.d.ts +35 -0
  14. package/dist/api/dto/node-records.d.ts +35 -0
  15. package/dist/api/dto/node-records.js +0 -0
  16. package/dist/api/dto/nodes.d.ts +5 -0
  17. package/dist/api/dto/profiles.d.ts +38 -3
  18. package/dist/api/dto/worktree.d.ts +11 -0
  19. package/dist/api/errors.d.ts +23 -1
  20. package/dist/api/errors.js +1 -1
  21. package/dist/api/index.d.ts +2 -0
  22. package/dist/api/index.js +1 -1
  23. package/dist/api/node-transport.js +1 -1
  24. package/dist/api/routes.d.ts +22 -0
  25. package/dist/api/routes.js +1 -1
  26. package/dist/build-root.d.ts +6 -1
  27. package/dist/build-root.js +1 -1
  28. package/dist/builtin-memory/crouter-sdk/client.md +34 -0
  29. package/dist/builtin-memory/crouter-sdk/errors.md +2 -0
  30. package/dist/builtin-memory/crouter-sdk/memory.md +2 -2
  31. package/dist/builtin-memory/crouter-sdk/streaming.md +21 -0
  32. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +8 -4
  33. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +39 -118
  34. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +6 -1
  35. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +41 -27
  36. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +52 -29
  37. package/dist/cli.js +9 -8
  38. package/dist/clients/attach/chrome/inbox-strip.js +1 -1
  39. package/dist/clients/attach/chrome/roster.js +1 -1
  40. package/dist/clients/attach/config.js +1 -1
  41. package/dist/clients/attach/overlays/auth.js +2 -2
  42. package/dist/clients/attach/overlays/graph.js +1 -1
  43. package/dist/clients/attach/render/tool-calls.js +3 -3
  44. package/dist/clients/attach/session/connection.js +1 -1
  45. package/dist/clients/attach/session/profile-files.js +1 -1
  46. package/dist/clients/attach/viewer.js +1569 -816
  47. package/dist/commands/api-client.js +3 -3
  48. package/dist/commands/broker-permissions.d.ts +2 -0
  49. package/dist/commands/broker-permissions.js +1 -0
  50. package/dist/commands/canvas-analytics/chart.d.ts +52 -0
  51. package/dist/commands/canvas-analytics/chart.js +1 -0
  52. package/dist/commands/canvas-analytics/drilldown.d.ts +34 -0
  53. package/dist/commands/canvas-analytics/drilldown.js +1 -0
  54. package/dist/commands/canvas-analytics/format.d.ts +29 -0
  55. package/dist/commands/canvas-analytics/format.js +1 -0
  56. package/dist/commands/canvas-analytics/graph-detail.d.ts +2 -0
  57. package/dist/commands/canvas-analytics/graph-detail.js +2 -0
  58. package/dist/commands/canvas-analytics/graphs.d.ts +9 -0
  59. package/dist/commands/canvas-analytics/graphs.js +1 -0
  60. package/dist/commands/canvas-analytics/memory.d.ts +2 -0
  61. package/dist/commands/canvas-analytics/memory.js +1 -0
  62. package/dist/commands/canvas-analytics/overview.d.ts +2 -0
  63. package/dist/commands/canvas-analytics/overview.js +1 -0
  64. package/dist/commands/canvas-analytics/shell.d.ts +60 -0
  65. package/dist/commands/canvas-analytics/shell.js +2 -0
  66. package/dist/commands/canvas-analytics/time.d.ts +2 -0
  67. package/dist/commands/canvas-analytics/time.js +1 -0
  68. package/dist/commands/canvas-analytics/usage.d.ts +2 -0
  69. package/dist/commands/canvas-analytics/usage.js +1 -0
  70. package/dist/commands/canvas-analytics/view.d.ts +85 -0
  71. package/dist/commands/canvas-analytics/view.js +1 -0
  72. package/dist/commands/canvas-analytics.d.ts +2 -0
  73. package/dist/commands/canvas-analytics.js +1 -0
  74. package/dist/commands/canvas-prune.js +1 -1
  75. package/dist/commands/canvas.js +1 -1
  76. package/dist/commands/cron.js +5 -5
  77. package/dist/commands/human/components.d.ts +2 -0
  78. package/dist/commands/human/components.js +2 -2
  79. package/dist/commands/human/prompts.js +1 -1
  80. package/dist/commands/human/queue.js +1 -1
  81. package/dist/commands/memory/client.d.ts +11 -0
  82. package/dist/commands/memory/client.js +1 -0
  83. package/dist/commands/memory/delete.js +1 -1
  84. package/dist/commands/memory/edit.js +3 -3
  85. package/dist/commands/memory/find.js +1 -1
  86. package/dist/commands/memory/history.js +4 -4
  87. package/dist/commands/memory/lint.js +1 -1
  88. package/dist/commands/memory/list.d.ts +0 -2
  89. package/dist/commands/memory/list.js +1 -1
  90. package/dist/commands/memory/move.js +1 -1
  91. package/dist/commands/memory/origin.js +1 -1
  92. package/dist/commands/memory/read.d.ts +0 -5
  93. package/dist/commands/memory/read.js +3 -3
  94. package/dist/commands/memory/shared.d.ts +0 -178
  95. package/dist/commands/memory/shared.js +1 -12
  96. package/dist/commands/memory/write.js +5 -5
  97. package/dist/commands/node/bash.js +5 -5
  98. package/dist/commands/node/create.d.ts +0 -17
  99. package/dist/commands/node/create.js +2 -3
  100. package/dist/commands/node/inspect.js +6 -6
  101. package/dist/commands/node/lifecycle.js +2 -2
  102. package/dist/commands/node-context.js +2 -2
  103. package/dist/commands/node-inspect-artifacts.js +6 -6
  104. package/dist/commands/pkg/browse/catalog.js +1 -1
  105. package/dist/commands/pkg/browse/model.d.ts +1 -1
  106. package/dist/commands/pkg/market-manage.js +1 -1
  107. package/dist/commands/pkg/plugin-manage.js +10 -10
  108. package/dist/commands/profile/daemon-profiles.d.ts +13 -0
  109. package/dist/commands/profile/daemon-profiles.js +4 -0
  110. package/dist/commands/profile/delete.js +1 -1
  111. package/dist/commands/profile/env.d.ts +6 -0
  112. package/dist/commands/profile/env.js +2 -2
  113. package/dist/commands/profile/kind.js +1 -2
  114. package/dist/commands/profile/list.js +1 -1
  115. package/dist/commands/profile/meta.js +1 -1
  116. package/dist/commands/profile/new.js +1 -1
  117. package/dist/commands/profile/pause.js +1 -1
  118. package/dist/commands/profile/project.js +1 -1
  119. package/dist/commands/profile/rename.js +1 -1
  120. package/dist/commands/profile/show.js +1 -1
  121. package/dist/commands/profile.js +1 -1
  122. package/dist/commands/push.js +3 -3
  123. package/dist/commands/surface-inspect.js +1 -1
  124. package/dist/commands/sys/branch.js +1 -1
  125. package/dist/commands/sys/config.js +1 -1
  126. package/dist/commands/sys/connect.js +3 -3
  127. package/dist/commands/sys/context/admin/actions.js +1 -1
  128. package/dist/commands/sys/context/admin/model.d.ts +1 -0
  129. package/dist/commands/sys/context/admin/model.js +1 -1
  130. package/dist/commands/sys/context/admin.js +1 -1
  131. package/dist/commands/sys/context/expose.js +2 -1
  132. package/dist/commands/sys/context/prompt-review.js +2 -2
  133. package/dist/commands/sys/context/resolve.js +7 -7
  134. package/dist/commands/sys/context/sysprompt.js +1 -1
  135. package/dist/commands/sys/join.d.ts +1 -0
  136. package/dist/commands/sys/join.js +1 -0
  137. package/dist/commands/sys/migrate.js +1 -1
  138. package/dist/commands/sys/panels/models-panel.js +1 -1
  139. package/dist/commands/sys/panels/profiles-panel.d.ts +0 -1
  140. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  141. package/dist/commands/sys/provider-login.js +6 -6
  142. package/dist/commands/sys/setup-core.d.ts +1 -1
  143. package/dist/commands/sys/setup-core.js +6 -6
  144. package/dist/commands/sys/setup-settings-runner.js +1 -1
  145. package/dist/commands/sys/setup.js +1 -1
  146. package/dist/commands/sys/spaces.d.ts +1 -0
  147. package/dist/commands/sys/spaces.js +2 -0
  148. package/dist/commands/sys/sync-deps.js +2 -2
  149. package/dist/commands/sys/sync-project-guidance.js +4 -4
  150. package/dist/commands/sys/sync-skills.js +2 -2
  151. package/dist/commands/sys/worktrees.d.ts +1 -0
  152. package/dist/commands/sys/worktrees.js +1 -1
  153. package/dist/commands/sys.js +1 -1
  154. package/dist/core/auth-file.js +2 -2
  155. package/dist/core/bash-job-supervisor.d.ts +6 -0
  156. package/dist/core/bash-job-supervisor.js +4 -0
  157. package/dist/core/bash-jobs.d.ts +13 -6
  158. package/dist/core/bash-jobs.js +8 -7
  159. package/dist/core/broker-client/transport-relay.d.ts +6 -3
  160. package/dist/core/broker-client/transport-relay.js +1 -1
  161. package/dist/core/broker-client/transport-socket.d.ts +6 -1
  162. package/dist/core/broker-client/transport-socket.js +1 -1
  163. package/dist/core/canvas/canvas.d.ts +39 -18
  164. package/dist/core/canvas/canvas.js +21 -20
  165. package/dist/core/canvas/context-strip.d.ts +20 -0
  166. package/dist/core/canvas/context-strip.js +5 -0
  167. package/dist/core/canvas/crons.d.ts +12 -20
  168. package/dist/core/canvas/crons.js +15 -13
  169. package/dist/core/canvas/db.js +2 -2
  170. package/dist/core/canvas/deliveries.d.ts +4 -1
  171. package/dist/core/canvas/deliveries.js +1 -1
  172. package/dist/core/canvas/executions.js +1 -1
  173. package/dist/core/canvas/history.d.ts +2 -1
  174. package/dist/core/canvas/history.js +17 -18
  175. package/dist/core/canvas/memory-reads.d.ts +19 -0
  176. package/dist/core/canvas/memory-reads.js +1 -0
  177. package/dist/core/canvas/migrations.d.ts +0 -4
  178. package/dist/core/canvas/migrations.js +99 -32
  179. package/dist/core/canvas/nav-render.js +1 -1
  180. package/dist/core/canvas/node-agent-paths.d.ts +8 -0
  181. package/dist/core/canvas/node-agent-paths.js +1 -0
  182. package/dist/core/canvas/node-recap.d.ts +2 -2
  183. package/dist/core/canvas/node-recap.js +2 -2
  184. package/dist/core/canvas/node-tokens.d.ts +24 -0
  185. package/dist/core/canvas/node-tokens.js +5 -0
  186. package/dist/core/canvas/paths.d.ts +16 -19
  187. package/dist/core/canvas/paths.js +1 -1
  188. package/dist/core/canvas/render-source.d.ts +2 -2
  189. package/dist/core/canvas/render-source.js +6 -9
  190. package/dist/core/canvas/sessions.d.ts +18 -0
  191. package/dist/core/canvas/sessions.js +4 -1
  192. package/dist/core/canvas/types.d.ts +22 -6
  193. package/dist/core/command-hooks/compose.js +1 -1
  194. package/dist/core/command-hooks/discovery.d.ts +15 -1
  195. package/dist/core/command-hooks/discovery.js +1 -1
  196. package/dist/core/command-hooks/help.d.ts +2 -2
  197. package/dist/core/command-hooks/lifecycle-create.d.ts +1 -1
  198. package/dist/core/command-hooks/lifecycle-create.js +1 -1
  199. package/dist/core/command-hooks/transport/exec-invoke.d.ts +2 -0
  200. package/dist/core/command-hooks/transport/exec-invoke.js +1 -1
  201. package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +1 -0
  202. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  203. package/dist/core/command-hooks/transport/plan.d.ts +3 -0
  204. package/dist/core/command-hooks/transport/plan.js +1 -0
  205. package/dist/core/command-plugins/discovery.js +1 -1
  206. package/dist/core/command.d.ts +6 -2
  207. package/dist/core/command.js +6 -6
  208. package/dist/core/config.d.ts +8 -5
  209. package/dist/core/config.js +1 -1
  210. package/dist/core/conversation-store/client-worker.d.ts +1 -0
  211. package/dist/core/conversation-store/client-worker.js +1 -0
  212. package/dist/core/conversation-store/client.d.ts +2 -0
  213. package/dist/core/conversation-store/client.js +2 -0
  214. package/dist/core/conversation-store/file-store.d.ts +37 -0
  215. package/dist/core/conversation-store/file-store.js +9 -0
  216. package/dist/core/conversation-store/index.d.ts +50 -0
  217. package/dist/core/conversation-store/index.js +1 -0
  218. package/dist/core/conversation-store/listener.d.ts +4 -0
  219. package/dist/core/conversation-store/listener.js +3 -0
  220. package/dist/core/conversation-store/patch.d.ts +1 -0
  221. package/dist/core/conversation-store/patch.js +1 -0
  222. package/dist/core/directory/join.d.ts +27 -0
  223. package/dist/core/directory/join.js +1 -0
  224. package/dist/core/disk-usage.d.ts +4 -0
  225. package/dist/core/disk-usage.js +1 -0
  226. package/dist/core/events/emit.d.ts +2 -0
  227. package/dist/core/events/emit.js +3 -1
  228. package/dist/core/feed/feed.js +4 -4
  229. package/dist/core/feed/messages.d.ts +3 -0
  230. package/dist/core/feed/messages.js +6 -6
  231. package/dist/core/fs-utils.d.ts +2 -0
  232. package/dist/core/fs-utils.js +3 -3
  233. package/dist/core/grants/local.d.ts +4 -0
  234. package/dist/core/grants/local.js +1 -0
  235. package/dist/core/grants/mirror.d.ts +44 -0
  236. package/dist/core/grants/mirror.js +4 -0
  237. package/dist/core/grants/on-sync.d.ts +22 -0
  238. package/dist/core/grants/on-sync.js +1 -0
  239. package/dist/core/grants/remove.d.ts +7 -0
  240. package/dist/core/grants/remove.js +1 -0
  241. package/dist/core/grants/sandboxes.d.ts +7 -0
  242. package/dist/core/grants/sandboxes.js +1 -0
  243. package/dist/core/grants/sync.d.ts +12 -0
  244. package/dist/core/grants/sync.js +1 -0
  245. package/dist/core/help/memory-extensions.d.ts +3 -0
  246. package/dist/core/help/memory-extensions.js +2 -0
  247. package/dist/core/help.d.ts +14 -0
  248. package/dist/core/help.js +7 -7
  249. package/dist/core/host-exports/builtins.js +3 -3
  250. package/dist/core/host-exports/export.js +3 -3
  251. package/dist/core/human/action-binding.d.ts +2 -0
  252. package/dist/core/human/action-binding.js +1 -1
  253. package/dist/core/human/feedback-companion.d.ts +0 -1
  254. package/dist/core/human/feedback-companion.js +1 -1
  255. package/dist/core/human/page-schema.d.ts +1 -1
  256. package/dist/core/inspector/core.d.ts +2 -0
  257. package/dist/core/inspector/core.js +1 -1
  258. package/dist/core/inspector/tui.js +2 -2
  259. package/dist/core/installed-plugins.js +1 -1
  260. package/dist/core/io.js +6 -6
  261. package/dist/core/keybindings/catalog.d.ts +1 -1
  262. package/dist/core/keybindings/catalog.js +1 -1
  263. package/dist/core/layout-migrate/index.d.ts +15 -0
  264. package/dist/core/layout-migrate/index.js +4 -0
  265. package/dist/core/layout-migrate/paths.d.ts +26 -0
  266. package/dist/core/layout-migrate/paths.js +1 -0
  267. package/dist/core/layout-migrate/stored-paths.d.ts +2 -0
  268. package/dist/core/layout-migrate/stored-paths.js +11 -0
  269. package/dist/core/layout-migrate/stores.d.ts +17 -0
  270. package/dist/core/layout-migrate/stores.js +4 -0
  271. package/dist/core/layout.d.ts +26 -0
  272. package/dist/core/layout.js +2 -0
  273. package/dist/core/llm/run.d.ts +60 -0
  274. package/dist/core/llm/run.js +4 -0
  275. package/dist/core/memory/cli-selector.d.ts +13 -0
  276. package/dist/core/memory/cli-selector.js +1 -0
  277. package/dist/core/memory/history.d.ts +5 -4
  278. package/dist/core/memory/history.js +6 -6
  279. package/dist/core/memory/inline-ref-inventory.d.ts +2 -1
  280. package/dist/core/memory/inline-ref-inventory.js +1 -1
  281. package/dist/core/memory/lint.js +2 -2
  282. package/dist/core/memory/mutation-domain.d.ts +2 -2
  283. package/dist/core/memory/mutation-domain.js +8 -7
  284. package/dist/core/memory/mutations.js +1 -1
  285. package/dist/core/memory/service.d.ts +5 -0
  286. package/dist/core/memory/service.js +2 -2
  287. package/dist/core/memory-resolver.d.ts +11 -7
  288. package/dist/core/memory-resolver.js +2 -2
  289. package/dist/core/model-auth/daemon-login.d.ts +13 -0
  290. package/dist/core/model-auth/daemon-login.js +1 -0
  291. package/dist/core/model-auth/flows.d.ts +45 -0
  292. package/dist/core/model-auth/flows.js +1 -0
  293. package/dist/core/model-auth/handoff-jti.d.ts +4 -0
  294. package/dist/core/model-auth/handoff-jti.js +1 -0
  295. package/dist/core/model-routes.js +1 -1
  296. package/dist/core/nested-stores.d.ts +2 -1
  297. package/dist/core/nested-stores.js +1 -2
  298. package/dist/core/preview-registry.js +2 -2
  299. package/dist/core/profiles/env-store.js +2 -2
  300. package/dist/core/profiles/manifest.d.ts +16 -5
  301. package/dist/core/profiles/manifest.js +1 -1
  302. package/dist/core/provider-management.js +1 -1
  303. package/dist/core/review/birth.js +1 -1
  304. package/dist/core/review/companion.d.ts +0 -2
  305. package/dist/core/review/companion.js +1 -1
  306. package/dist/core/review/fork.js +2 -2
  307. package/dist/core/review/realize.js +1 -1
  308. package/dist/core/review/stage.d.ts +1 -1
  309. package/dist/core/review/stage.js +1 -1
  310. package/dist/core/review/types.d.ts +1 -1
  311. package/dist/core/runs/events.d.ts +34 -0
  312. package/dist/core/runs/events.js +1 -0
  313. package/dist/core/runs/operations.d.ts +43 -0
  314. package/dist/core/runs/operations.js +12 -0
  315. package/dist/core/runtime/bearings-render.d.ts +2 -2
  316. package/dist/core/runtime/bearings-render.js +11 -11
  317. package/dist/core/runtime/bearings.js +2 -2
  318. package/dist/core/runtime/broker/cli-relay.d.ts +5 -0
  319. package/dist/core/runtime/broker/cli-relay.js +1 -0
  320. package/dist/core/runtime/broker/client-registry.d.ts +0 -5
  321. package/dist/core/runtime/broker/client-registry.js +1 -1
  322. package/dist/core/runtime/broker/daemon-ops.d.ts +28 -1
  323. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  324. package/dist/core/runtime/broker/engine-drive.d.ts +0 -2
  325. package/dist/core/runtime/broker/engine-drive.js +1 -1
  326. package/dist/core/runtime/broker/fault-retry.d.ts +9 -0
  327. package/dist/core/runtime/broker/fault-retry.js +1 -1
  328. package/dist/core/runtime/broker/frame-dispatch.d.ts +5 -9
  329. package/dist/core/runtime/broker/frame-dispatch.js +1 -1
  330. package/dist/core/runtime/broker/frame-engine-control.d.ts +3 -2
  331. package/dist/core/runtime/broker/frame-engine-control.js +1 -1
  332. package/dist/core/runtime/broker/frame-memory-refs.d.ts +4 -3
  333. package/dist/core/runtime/broker/frame-memory-refs.js +1 -1
  334. package/dist/core/runtime/broker/frame-read.js +1 -1
  335. package/dist/core/runtime/broker/frame-session.js +1 -1
  336. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -1
  337. package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
  338. package/dist/core/runtime/broker/inbox.d.ts +1 -2
  339. package/dist/core/runtime/broker/inbox.js +7 -10
  340. package/dist/core/runtime/broker/model-adapter.d.ts +9 -0
  341. package/dist/core/runtime/broker/model-adapter.js +2 -0
  342. package/dist/core/runtime/broker/node-token.d.ts +3 -0
  343. package/dist/core/runtime/broker/node-token.js +1 -0
  344. package/dist/core/runtime/broker/read-ops.js +1 -1
  345. package/dist/core/runtime/broker/rebind.d.ts +2 -0
  346. package/dist/core/runtime/broker/rebind.js +1 -1
  347. package/dist/core/runtime/broker/tool-groups.js +1 -1
  348. package/dist/core/runtime/broker/turn-ignition.d.ts +3 -3
  349. package/dist/core/runtime/broker/turn-ignition.js +1 -1
  350. package/dist/core/runtime/broker-cli.js +3 -3
  351. package/dist/core/runtime/broker-extension-render.d.ts +2 -5
  352. package/dist/core/runtime/broker-extension-render.js +4 -4
  353. package/dist/core/runtime/broker-persona-guidance.js +3 -3
  354. package/dist/core/runtime/broker-protocol.d.ts +7 -8
  355. package/dist/core/runtime/broker.js +1 -1
  356. package/dist/core/runtime/canvas-extensions.d.ts +1 -0
  357. package/dist/core/runtime/canvas-extensions.js +1 -1
  358. package/dist/core/runtime/close.d.ts +9 -0
  359. package/dist/core/runtime/close.js +1 -1
  360. package/dist/core/runtime/deliver-live.js +1 -1
  361. package/dist/core/runtime/fleet.d.ts +1 -1
  362. package/dist/core/runtime/front-door-login.js +1 -1
  363. package/dist/core/runtime/front-door.js +2 -2
  364. package/dist/core/runtime/headless-pi.d.ts +1 -1
  365. package/dist/core/runtime/headless-pi.js +1 -1
  366. package/dist/core/runtime/host.d.ts +1 -1
  367. package/dist/core/runtime/host.js +3 -1
  368. package/dist/core/runtime/invocation.d.ts +3 -0
  369. package/dist/core/runtime/kickoff.d.ts +1 -0
  370. package/dist/core/runtime/kickoff.js +16 -16
  371. package/dist/core/runtime/launch-target.d.ts +1 -1
  372. package/dist/core/runtime/launch-target.js +1 -1
  373. package/dist/core/runtime/launch.d.ts +10 -35
  374. package/dist/core/runtime/launch.js +1 -1
  375. package/dist/core/runtime/lifecycle.js +2 -2
  376. package/dist/core/runtime/memory.d.ts +1 -1
  377. package/dist/core/runtime/memory.js +1 -1
  378. package/dist/core/runtime/model-registry.js +1 -1
  379. package/dist/core/runtime/model-swap.d.ts +17 -19
  380. package/dist/core/runtime/model-swap.js +1 -1
  381. package/dist/core/runtime/node-read.js +3 -2
  382. package/dist/core/runtime/nodes.d.ts +7 -0
  383. package/dist/core/runtime/nodes.js +1 -1
  384. package/dist/core/runtime/outcome-document.js +1 -1
  385. package/dist/core/runtime/package-health.js +2 -2
  386. package/dist/core/runtime/persona.js +2 -2
  387. package/dist/core/runtime/pi-vendored.js +1 -1
  388. package/dist/core/runtime/placement-tmux.d.ts +1 -1
  389. package/dist/core/runtime/placement-tmux.js +1 -1
  390. package/dist/core/runtime/placement.js +1 -1
  391. package/dist/core/runtime/promote.js +1 -1
  392. package/dist/core/runtime/provider-credential-gate.js +2 -2
  393. package/dist/core/runtime/recovery-hold.d.ts +2 -0
  394. package/dist/core/runtime/recovery-hold.js +1 -0
  395. package/dist/core/runtime/recycle.js +1 -1
  396. package/dist/core/runtime/reopen.js +1 -1
  397. package/dist/core/runtime/reset.js +1 -1
  398. package/dist/core/runtime/revive.d.ts +1 -1
  399. package/dist/core/runtime/revive.js +2 -3
  400. package/dist/core/runtime/roadmap.js +4 -4
  401. package/dist/core/runtime/run-command.d.ts +6 -0
  402. package/dist/core/runtime/run-command.js +1 -1
  403. package/dist/core/runtime/session-branch.d.ts +2 -8
  404. package/dist/core/runtime/session-branch.js +1 -1
  405. package/dist/core/runtime/session-list-cache.d.ts +6 -22
  406. package/dist/core/runtime/session-list-cache.js +1 -1
  407. package/dist/core/runtime/situational-context.js +2 -2
  408. package/dist/core/runtime/spawn-env.d.ts +6 -6
  409. package/dist/core/runtime/spawn-env.js +1 -1
  410. package/dist/core/runtime/spawn.d.ts +5 -0
  411. package/dist/core/runtime/spawn.js +2 -2
  412. package/dist/core/runtime/stop-guard.js +2 -2
  413. package/dist/core/runtime/stop-signals.d.ts +2 -2
  414. package/dist/core/runtime/stop-signals.js +1 -1
  415. package/dist/core/runtime/structured-output.d.ts +10 -4
  416. package/dist/core/runtime/structured-output.js +4 -4
  417. package/dist/core/runtime/tmux-bindings.js +3 -3
  418. package/dist/core/runtime/tmux-driver.d.ts +4 -0
  419. package/dist/core/runtime/tmux-driver.js +7 -7
  420. package/dist/core/runtime/view-socket.d.ts +9 -2
  421. package/dist/core/runtime/view-socket.js +1 -1
  422. package/dist/core/runtime/warm-pool.js +1 -1
  423. package/dist/core/scope.d.ts +3 -2
  424. package/dist/core/scope.js +1 -1
  425. package/dist/core/scoped-state/db.js +1 -1
  426. package/dist/core/scoped-state/migrate.js +3 -3
  427. package/dist/core/scoped-state/profiles.d.ts +2 -1
  428. package/dist/core/scoped-state/profiles.js +1 -1
  429. package/dist/core/scoped-state/schema.d.ts +2 -1
  430. package/dist/core/scoped-state/schema.js +4 -4
  431. package/dist/core/scopes.d.ts +2 -2
  432. package/dist/core/scopes.js +1 -1
  433. package/dist/core/secrets.d.ts +1 -0
  434. package/dist/core/secrets.js +2 -2
  435. package/dist/core/spaces/mounts.d.ts +32 -0
  436. package/dist/core/spaces/mounts.js +1 -0
  437. package/dist/core/spaces/open-beneath.d.ts +71 -0
  438. package/dist/core/spaces/open-beneath.js +1 -0
  439. package/dist/core/spaces/permissions.d.ts +46 -0
  440. package/dist/core/spaces/permissions.js +1 -0
  441. package/dist/core/spaces/process.d.ts +27 -0
  442. package/dist/core/spaces/process.js +1 -0
  443. package/dist/core/spaces/space.d.ts +8 -0
  444. package/dist/core/spaces/space.js +2 -0
  445. package/dist/core/spaces/stop.d.ts +8 -0
  446. package/dist/core/spaces/stop.js +2 -0
  447. package/dist/core/spaces/users.d.ts +19 -0
  448. package/dist/core/spaces/users.js +1 -0
  449. package/dist/core/subscription-state.d.ts +2 -0
  450. package/dist/core/subscription-state.js +3 -3
  451. package/dist/core/substrate/frontmatter-validation.js +1 -1
  452. package/dist/core/substrate/injected-store.d.ts +28 -3
  453. package/dist/core/substrate/injected-store.js +2 -1
  454. package/dist/core/substrate/listings.js +1 -1
  455. package/dist/core/substrate/memory-events.d.ts +6 -0
  456. package/dist/core/substrate/memory-events.js +1 -0
  457. package/dist/core/substrate/on-read-node.js +1 -1
  458. package/dist/core/substrate/on-read.d.ts +6 -6
  459. package/dist/core/substrate/on-read.js +5 -5
  460. package/dist/core/substrate/plan.js +1 -1
  461. package/dist/core/substrate/render-node.js +1 -1
  462. package/dist/core/substrate/render.d.ts +4 -3
  463. package/dist/core/substrate/render.js +38 -38
  464. package/dist/core/substrate/schema.d.ts +6 -0
  465. package/dist/core/substrate/schema.js +1 -1
  466. package/dist/core/tui/panel.js +1 -1
  467. package/dist/core/user-settings.d.ts +12 -0
  468. package/dist/core/user-settings.js +1 -1
  469. package/dist/core/worktree-mutation-async.js +5 -5
  470. package/dist/core/worktree-quarantine.js +1 -1
  471. package/dist/core/worktree-remove.d.ts +15 -0
  472. package/dist/core/worktree-remove.js +1 -0
  473. package/dist/core/worktree-sweep.js +6 -6
  474. package/dist/daemon/analytics/compute.d.ts +37 -0
  475. package/dist/daemon/analytics/compute.js +1 -0
  476. package/dist/daemon/analytics/scan-worker.d.ts +1 -0
  477. package/dist/daemon/analytics/scan-worker.js +2 -0
  478. package/dist/daemon/analytics/scan.d.ts +37 -0
  479. package/dist/daemon/analytics/scan.js +1 -0
  480. package/dist/daemon/api/app-listener.d.ts +11 -0
  481. package/dist/daemon/api/app-listener.js +21 -0
  482. package/dist/daemon/api/bridge.js +5 -5
  483. package/dist/daemon/api/handlers/analytics.d.ts +2 -0
  484. package/dist/daemon/api/handlers/analytics.js +1 -0
  485. package/dist/daemon/api/handlers/attach.js +1 -1
  486. package/dist/daemon/api/handlers/bash-jobs.js +2 -2
  487. package/dist/daemon/api/handlers/bash.js +1 -1
  488. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  489. package/dist/daemon/api/handlers/canvas.d.ts +1 -1
  490. package/dist/daemon/api/handlers/canvas.js +6 -6
  491. package/dist/daemon/api/handlers/crons.js +1 -1
  492. package/dist/daemon/api/handlers/files.d.ts +1 -1
  493. package/dist/daemon/api/handlers/files.js +1 -1
  494. package/dist/daemon/api/handlers/health.js +2 -2
  495. package/dist/daemon/api/handlers/hook-exec.d.ts +2 -0
  496. package/dist/daemon/api/handlers/hook-exec.js +1 -0
  497. package/dist/daemon/api/handlers/human-requests.js +1 -1
  498. package/dist/daemon/api/handlers/inbox.js +1 -1
  499. package/dist/daemon/api/handlers/llm.d.ts +2 -0
  500. package/dist/daemon/api/handlers/llm.js +3 -0
  501. package/dist/daemon/api/handlers/memory-reads.d.ts +4 -0
  502. package/dist/daemon/api/handlers/memory-reads.js +1 -0
  503. package/dist/daemon/api/handlers/memory.js +5 -1
  504. package/dist/daemon/api/handlers/messages.js +2 -2
  505. package/dist/daemon/api/handlers/modelauth.js +1 -1
  506. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  507. package/dist/daemon/api/handlers/node-records.d.ts +2 -0
  508. package/dist/daemon/api/handlers/node-records.js +3 -0
  509. package/dist/daemon/api/handlers/nodes.d.ts +1 -1
  510. package/dist/daemon/api/handlers/nodes.js +1 -1
  511. package/dist/daemon/api/handlers/profiles.d.ts +4 -1
  512. package/dist/daemon/api/handlers/profiles.js +1 -1
  513. package/dist/daemon/api/handlers/reports.js +5 -3
  514. package/dist/daemon/api/handlers/reviews.d.ts +1 -1
  515. package/dist/daemon/api/handlers/reviews.js +1 -1
  516. package/dist/daemon/api/handlers/run-routes.d.ts +2 -0
  517. package/dist/daemon/api/handlers/run-routes.js +1 -0
  518. package/dist/daemon/api/handlers/runs.d.ts +9 -0
  519. package/dist/daemon/api/handlers/runs.js +1 -0
  520. package/dist/daemon/api/handlers/subscriptions.js +1 -1
  521. package/dist/daemon/api/handlers/worktree.js +1 -1
  522. package/dist/daemon/api/map.d.ts +10 -4
  523. package/dist/daemon/api/map.js +2 -2
  524. package/dist/daemon/api/operations.d.ts +18 -0
  525. package/dist/daemon/api/operations.js +1 -0
  526. package/dist/daemon/api/principal.d.ts +42 -0
  527. package/dist/daemon/api/principal.js +1 -0
  528. package/dist/daemon/api/router.d.ts +27 -3
  529. package/dist/daemon/api/router.js +1 -1
  530. package/dist/daemon/api/server.d.ts +4 -0
  531. package/dist/daemon/api/server.js +1 -1
  532. package/dist/daemon/api/vendor-signin.d.ts +7 -0
  533. package/dist/daemon/api/vendor-signin.js +77 -0
  534. package/dist/daemon/api/viewer-presence.d.ts +3 -0
  535. package/dist/daemon/api/viewer-presence.js +1 -0
  536. package/dist/daemon/cron/armed-context.d.ts +4 -0
  537. package/dist/daemon/cron/armed-context.js +1 -1
  538. package/dist/daemon/cron/escalation.js +3 -3
  539. package/dist/daemon/cron/lease-recovery.js +1 -1
  540. package/dist/daemon/cron/sinks.js +2 -2
  541. package/dist/daemon/cron-run.d.ts +5 -5
  542. package/dist/daemon/cron-run.js +1 -1
  543. package/dist/daemon/crtrd.js +8 -7
  544. package/dist/daemon/delivery/run-delivery.d.ts +4 -0
  545. package/dist/daemon/delivery/run-delivery.js +1 -1
  546. package/dist/daemon/fleet.d.ts +1 -1
  547. package/dist/daemon/fleet.js +6 -6
  548. package/dist/daemon/human/finish.js +7 -7
  549. package/dist/daemon/joined-owner.d.ts +5 -0
  550. package/dist/daemon/joined-owner.js +1 -0
  551. package/dist/daemon/manage.js +2 -2
  552. package/dist/daemon/messaging/node-message.js +1 -1
  553. package/dist/daemon/park-activity.js +1 -1
  554. package/dist/daemon/reconcilers/bash-deadline.js +1 -1
  555. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  556. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  557. package/dist/daemon/reconcilers/delivery-lane.js +1 -1
  558. package/dist/daemon/reconcilers/live-obligation.d.ts +7 -0
  559. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  560. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  561. package/dist/daemon/reconcilers/storage-maintenance.d.ts +20 -1
  562. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  563. package/dist/daemon/runs/append-section.d.ts +6 -0
  564. package/dist/daemon/runs/append-section.js +2 -0
  565. package/dist/daemon/runs/observer.d.ts +5 -0
  566. package/dist/daemon/runs/observer.js +4 -0
  567. package/dist/launcher/bwrap.d.ts +4 -0
  568. package/dist/launcher/bwrap.js +2 -0
  569. package/dist/launcher/client.d.ts +2 -0
  570. package/dist/launcher/client.js +3 -0
  571. package/dist/launcher/main.d.ts +1 -0
  572. package/dist/launcher/main.js +3 -0
  573. package/dist/launcher/netrule.d.ts +1 -0
  574. package/dist/launcher/netrule.js +1 -0
  575. package/dist/launcher/seccomp.d.ts +1 -0
  576. package/dist/launcher/seccomp.js +1 -0
  577. package/dist/launcher/spec.d.ts +88 -0
  578. package/dist/launcher/spec.js +1 -0
  579. package/dist/launcher/users.d.ts +18 -0
  580. package/dist/launcher/users.js +7 -0
  581. package/dist/launcher/validate.d.ts +22 -0
  582. package/dist/launcher/validate.js +1 -0
  583. package/dist/migrations/corpus.js +3 -3
  584. package/dist/migrations/runner.js +1 -1
  585. package/dist/native/linux/addon.node +0 -0
  586. package/dist/native/linux.d.ts +29 -0
  587. package/dist/native/linux.js +1 -0
  588. package/dist/pi-extensions/broker-local.js +2 -2
  589. package/dist/pi-extensions/canvas-bash-valve.d.ts +1 -3
  590. package/dist/pi-extensions/canvas-bash-valve.js +4 -7
  591. package/dist/pi-extensions/canvas-context-intro.d.ts +1 -2
  592. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  593. package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
  594. package/dist/pi-extensions/canvas-inbox-watcher.d.ts +2 -1
  595. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -1
  596. package/dist/pi-extensions/canvas-passive-context.d.ts +1 -1
  597. package/dist/pi-extensions/canvas-passive-context.js +11 -11
  598. package/dist/pi-extensions/canvas-recap.js +6 -6
  599. package/dist/pi-extensions/canvas-stophook.js +1 -1
  600. package/dist/pi-extensions/canvas-structured-output.js +4 -4
  601. package/dist/pi-extensions/canvas-tool-guide.js +1 -1
  602. package/dist/pi-extensions/system-prompt-entry.d.ts +15 -0
  603. package/dist/pi-extensions/system-prompt-entry.js +1 -0
  604. package/dist/shared/env.d.ts +5 -1
  605. package/dist/shared/env.js +1 -1
  606. package/dist/shared/strip-cd-prefix.d.ts +1 -0
  607. package/dist/shared/strip-cd-prefix.js +1 -0
  608. package/dist/types.d.ts +31 -15
  609. package/docs/cli/memory-and-preferences.md +3 -1
  610. package/docs/sdk/client.md +34 -0
  611. package/docs/sdk/errors.md +2 -0
  612. package/docs/sdk/memory.md +2 -2
  613. package/docs/sdk/streaming.md +21 -0
  614. package/package.json +18 -4
  615. package/packages/crouter-identity/dist/index.d.ts +54 -0
  616. package/packages/crouter-identity/dist/index.js +166 -0
  617. package/packages/crouter-identity/package.json +33 -0
  618. package/runtime.lock.json +34 -8
  619. package/scripts/build-native-linux.mjs +16 -0
  620. package/scripts/install-runtime.mjs +9 -7
  621. package/scripts/lib/isolation-env.mjs +42 -0
  622. package/scripts/runtime-smoke.mjs +49 -0
  623. package/src/native/linux/addon.c +249 -0
  624. package/dist/core/profiles/state-block.d.ts +0 -4
  625. package/dist/core/profiles/state-block.js +0 -3
  626. package/dist/core/runtime/broker/auth-reload.d.ts +0 -41
  627. package/dist/core/runtime/broker/auth-reload.js +0 -1
  628. package/dist/core/substrate/cli-context-delivery.d.ts +0 -22
  629. package/dist/core/substrate/cli-context-delivery.js +0 -1
@@ -1,10 +1,10 @@
1
- var _=Object.defineProperty;var r=(t,e)=>_(t,"name",{value:e,configurable:!0});import{getRequest as y,getRequestByInboxTicket as b,presentationDir as q}from"../../core/human/requests.js";import{buildPageSummary as v}from"../../core/human/summary.js";import{validateFinalPageResponses as $}from"../../core/human/tickets.js";import{composeHumanCompletion as j}from"../../core/human/completion.js";import{describePageAnswer as k}from"../../core/human/answer.js";import{renderAnswerText as S}from"../../core/human/answer-text.js";import{readPageFeedback as T}from"../../core/human/feedback.js";import{pageDocumentSha256 as A}from"../../core/human/feedback-companion.js";import{pagePath as N}from"../../core/human/convention.js";import{retireCompanion as f}from"../companion-retire.js";import{settleHumanRequest as h}from"./settle.js";function d(t){const e=y(t)??b(t);if(e===null||e.kind!=="page")throw new Error(`unknown page request: ${t}`);return e}r(d,"requestForTicket");function c(t){try{const e=JSON.parse(t.specification_json);if(typeof e!="object"||e===null)throw new Error("not an object");return e}catch(e){throw new Error(`corrupt page specification: ${t.request_id}`,{cause:e})}}r(c,"manifest");function u(t,e){if(t.action_json!==null)try{const n=JSON.parse(t.action_json);if(n.schema!=="crtr.human-action-binding/v1"||!Array.isArray(n.argv)||typeof n.cwd!="string")throw new Error("invalid binding");return{destinationId:n.name,adapter:{adapter:"subprocess",argv:n.argv,cwd:n.cwd},bodyJson:j({requestId:t.request_id,result:e,binding:n,source:c(t).source??{}})}}catch(n){throw new Error(`corrupt frozen completion action: ${t.request_id}`,{cause:n})}}r(u,"completionAction");function O(t,e=80){const n=t.split(`
2
- `)[0]??"";return n.length>e?`${n.slice(0,e-1)}\u2026`:n}r(O,"firstLine");function E(t){try{return c(t).title}catch{return}}r(E,"pageTitle");function g(t){let e;try{const n=T(t.request_dir);if(n.companionNodeId===void 0)return"";e=[],n.firstCommentedSha256!==void 0&&A(t.request_dir)!==n.firstCommentedSha256&&e.push(`The page changed during feedback: the person commented on it and its companion conversation (node ${n.companionNodeId}) revised it in place. Reread the final page at ${N(q(t),c(t).dialect)} before interpreting this outcome.`);const o=n.comments.filter(i=>i.status==="open");if(o.length>0){const i=o.map(a=>[...a.quote.split(`
3
- `).map(s=>`> ${s}`),a.note].join(`
4
- `));e.push([`Feedback left unresolved at settlement \u2014 the companion conversation (node ${n.companionNodeId}) had not dealt with these items:`,...i].join(`
1
+ var _=Object.defineProperty;var r=(t,n)=>_(t,"name",{value:n,configurable:!0});import{getRequest as y,getRequestByInboxTicket as b,presentationDir as q}from"../../core/human/requests.js";import{buildPageSummary as v}from"../../core/human/summary.js";import{validateFinalPageResponses as $}from"../../core/human/tickets.js";import{composeHumanCompletion as j}from"../../core/human/completion.js";import{describePageAnswer as k}from"../../core/human/answer.js";import{renderAnswerText as S}from"../../core/human/answer-text.js";import{readPageFeedback as T}from"../../core/human/feedback.js";import{pageDocumentSha256 as A}from"../../core/human/feedback-companion.js";import{pagePath as N}from"../../core/human/convention.js";import{retireCompanion as f}from"../companion-retire.js";import{settleHumanRequest as h}from"./settle.js";function c(t){const n=y(t)??b(t);if(n===null||n.kind!=="page")throw new Error(`unknown page request: ${t}`);return n}r(c,"requestForTicket");function d(t){try{const n=JSON.parse(t.specification_json);if(typeof n!="object"||n===null)throw new Error("not an object");return n}catch(n){throw new Error(`corrupt page specification: ${t.request_id}`,{cause:n})}}r(d,"manifest");function u(t,n){if(t.action_json!==null)try{const e=JSON.parse(t.action_json);if(e.schema!=="crtr.human-action-binding/v1"||!Array.isArray(e.argv)||typeof e.cwd!="string")throw new Error("invalid binding");return{destinationId:e.name,adapter:{adapter:"subprocess",argv:e.argv,cwd:e.cwd,node_id:t.requester_node_id,...e.app?{app:e.app}:{}},bodyJson:j({requestId:t.request_id,result:n,binding:e,source:d(t).source??{}})}}catch(e){throw new Error(`corrupt frozen completion action: ${t.request_id}`,{cause:e})}}r(u,"completionAction");function O(t,n=80){const e=t.split(`
2
+ `)[0]??"";return e.length>n?`${e.slice(0,n-1)}\u2026`:e}r(O,"firstLine");function E(t){try{return d(t).title}catch{return}}r(E,"pageTitle");function g(t){let n;try{const e=T(t.request_dir);if(e.companionNodeId===void 0)return"";n=[],e.firstCommentedSha256!==void 0&&A(t.request_dir)!==e.firstCommentedSha256&&n.push(`The page changed during feedback: the person commented on it and its companion conversation (node ${e.companionNodeId}) revised it in place. Reread the final page at ${N(q(t),d(t).dialect)} before interpreting this outcome.`);const o=e.comments.filter(i=>i.status==="open");if(o.length>0){const i=o.map(s=>[...s.quote.split(`
3
+ `).map(a=>`> ${a}`),s.note].join(`
4
+ `));n.push([`Feedback left unresolved at settlement \u2014 the companion conversation (node ${e.companionNodeId}) had not dealt with these items:`,...i].join(`
5
5
 
6
- `))}}catch{return""}return e.length===0?"":`
6
+ `))}}catch{return""}return n.length===0?"":`
7
7
 
8
- ${e.join(`
8
+ ${n.join(`
9
9
 
10
- `)}`}r(g,"feedbackAddendum");function I(t,e){const n=k(c(t),e.responses,{completedAt:e.completedAt});return S(n)+g(t)}r(I,"answerBody");function J(t,e,n){const o=E(t),i=o===void 0?`the human interaction ${t.request_id}`:`\u201C${o}\u201D`,a=n!==void 0&&n!==""?n:"no reason was given";return(e?`The user dismissed ${i} without answering \u2014 a deliberate \u201Cno, I'm not answering this.\u201D Treat it as a rejection: no response will arrive, no partial answer exists, and the same ask must not be raised again.`:`${o===void 0?`The human interaction ${t.request_id}`:`The page \u201C${o}\u201D`} was canceled \u2014 ${a}. No response will arrive, and any partial answers the user had entered were discarded unsent.`)+g(t)}r(J,"cancelBody");function w(t,e,n,o){if(t.requester_node_id!==null)return{label:O(n),disposition:e,body_json:{body:n,result:o}}}r(w,"notification");function l(t){return t.companion_node_id===null?void 0:{retire:r(async(e,n)=>{await f(e,n)},"retire")}}r(l,"retire");async function M(t,e,n={}){const o=d(t),i=c(o),a=$(i,e),s={schema:"crtr.page-response/v1",kind:"page",responses:a,summary:v(i,a),completedAt:n.completedAt??new Date().toISOString(),...n.actor===void 0?{}:{actor:n.actor}},m=await h({request_id:o.request_id,outcome:"answered",result_json:JSON.stringify(s),notification:r(p=>w(p,"human-answer",I(p,s),s),"notification"),...u(o,s)===void 0?{}:{completion_action:u(o,s)},...l(o)===void 0?{}:{post_commit:l(o)}});if(m.outcome==="already_settled"){if(m.request.result_json===null)throw new Error(`settled page request lacks a result: ${o.request_id}`);return JSON.parse(m.request.result_json)}return s}r(M,"resolvePageTicket");async function Q(t,e){const n=d(t),i={schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:new Date().toISOString(),...e.reason===void 0?{}:{reason:e.reason},...e.actor===void 0?{}:{actor:e.actor},...e.disposition===void 0?{}:{disposition:e.disposition}},a=await h({request_id:n.request_id,outcome:e.disposition==="dismissed"?"dismissed":"canceled",result_json:JSON.stringify(i),notification:r(s=>w(s,"human-canceled",J(s,e.disposition==="dismissed",e.reason),i),"notification"),...u(n,i)===void 0?{}:{completion_action:u(n,i)},...l(n)===void 0?{}:{post_commit:l(n)}});if(a.outcome==="already_settled"){if(a.request.result_json===null)throw new Error(`settled page request lacks a result: ${n.request_id}`);return{outcome:"already_settled",result:JSON.parse(a.request.result_json)}}return{outcome:"settled",result:i}}r(Q,"cancelHumanTicket");async function U(t){return d(t).state==="settled"}r(U,"deliverTerminalResult");async function V(t,e){const n=d(t);n.companion_node_id!==null&&await f(n.companion_node_id,e)}r(V,"settleFeedbackCompanion");export{Q as cancelHumanTicket,U as deliverTerminalResult,M as resolvePageTicket,V as settleFeedbackCompanion};
10
+ `)}`}r(g,"feedbackAddendum");function I(t,n){const e=k(d(t),n.responses,{completedAt:n.completedAt});return S(e)+g(t)}r(I,"answerBody");function J(t,n,e){const o=E(t),i=o===void 0?`the human interaction ${t.request_id}`:`\u201C${o}\u201D`,s=e!==void 0&&e!==""?e:"no reason was given";return(n?`The user dismissed ${i} without answering \u2014 a deliberate \u201Cno, I'm not answering this.\u201D Treat it as a rejection: no response will arrive, no partial answer exists, and the same ask must not be raised again.`:`${o===void 0?`The human interaction ${t.request_id}`:`The page \u201C${o}\u201D`} was canceled \u2014 ${s}. No response will arrive, and any partial answers the user had entered were discarded unsent.`)+g(t)}r(J,"cancelBody");function w(t,n,e,o){if(t.requester_node_id!==null)return{label:O(e),disposition:n,body_json:{body:e,result:o}}}r(w,"notification");function l(t){return t.companion_node_id===null?void 0:{retire:r(async(n,e)=>{await f(n,e)},"retire")}}r(l,"retire");async function M(t,n,e={}){const o=c(t),i=d(o),s=$(i,n),a={schema:"crtr.page-response/v1",kind:"page",responses:s,summary:v(i,s),completedAt:e.completedAt??new Date().toISOString(),...e.actor===void 0?{}:{actor:e.actor}},m=await h({request_id:o.request_id,outcome:"answered",result_json:JSON.stringify(a),notification:r(p=>w(p,"human-answer",I(p,a),a),"notification"),...u(o,a)===void 0?{}:{completion_action:u(o,a)},...l(o)===void 0?{}:{post_commit:l(o)}});if(m.outcome==="already_settled"){if(m.request.result_json===null)throw new Error(`settled page request lacks a result: ${o.request_id}`);return JSON.parse(m.request.result_json)}return a}r(M,"resolvePageTicket");async function Q(t,n){const e=c(t),i={schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:new Date().toISOString(),...n.reason===void 0?{}:{reason:n.reason},...n.actor===void 0?{}:{actor:n.actor},...n.disposition===void 0?{}:{disposition:n.disposition}},s=await h({request_id:e.request_id,outcome:n.disposition==="dismissed"?"dismissed":"canceled",result_json:JSON.stringify(i),notification:r(a=>w(a,"human-canceled",J(a,n.disposition==="dismissed",n.reason),i),"notification"),...u(e,i)===void 0?{}:{completion_action:u(e,i)},...l(e)===void 0?{}:{post_commit:l(e)}});if(s.outcome==="already_settled"){if(s.request.result_json===null)throw new Error(`settled page request lacks a result: ${e.request_id}`);return{outcome:"already_settled",result:JSON.parse(s.request.result_json)}}return{outcome:"settled",result:i}}r(Q,"cancelHumanTicket");async function U(t){return c(t).state==="settled"}r(U,"deliverTerminalResult");async function V(t,n){const e=c(t);e.companion_node_id!==null&&await f(e.companion_node_id,n)}r(V,"settleFeedbackCompanion");export{Q as cancelHumanTicket,U as deliverTerminalResult,M as resolvePageTicket,V as settleFeedbackCompanion};
@@ -0,0 +1,5 @@
1
+ /** Rows changed, or null when this runtime has not joined a directory. */
2
+ export declare function applyJoinedOwner(): {
3
+ owner: string;
4
+ rows: number;
5
+ } | null;
@@ -0,0 +1 @@
1
+ var i=Object.defineProperty;var t=(r,e)=>i(r,"name",{value:e,configurable:!0});import{withCanvasWrite as m}from"../core/canvas/db.js";import{rewriteLocalNodeIdentity as p}from"../core/canvas/canvas.js";import{rewriteLocalNodeTokenIdentity as a}from"../core/canvas/node-tokens.js";import{joinedOwner as f}from"../core/directory/join.js";import{LOCAL_TERMINAL_GRANT_ID as n}from"../core/grants/local.js";import{dropLocalGrantMirror as l}from"../core/grants/mirror.js";import{rewriteLocalRunEventGrantee as c}from"../core/runs/events.js";import{rewriteLocalIdempotencyGrantee as w}from"../core/runs/operations.js";function O(){const r=f();if(r===null)return null;const e=m(o=>p(o,r,n)+a(o,r,n)+l(o)+c(o)+w(o));return{owner:r,rows:e}}t(O,"applyJoinedOwner");export{O as applyJoinedOwner};
@@ -1,2 +1,2 @@
1
- var H=Object.defineProperty;var o=(e,t)=>H(e,"name",{value:t,configurable:!0});import{spawn as B,execFileSync as k}from"node:child_process";import{createRequire as K}from"node:module";import{dirname as T,join as h}from"node:path";import{fileURLToPath as G,pathToFileURL as b}from"node:url";import{existsSync as j,lstatSync as Y,mkdirSync as X,openSync as z,closeSync as V}from"node:fs";import{crtrHome as x}from"../core/canvas/paths.js";import{bindDaemonEventSource as q,eventSource as J}from"../core/events/source.js";import{hostExecPath as L}from"../core/runtime/branded-host.js";import{isDaemonRunning as Q,readPidfile as g,isPidAlive as w}from"./pidfile.js";import{DAEMON_STARTUP_WINDOW_MS as C}from"./startup-policy.js";import{exclusiveLockOwnerPid as Z}from"../core/exclusive-lock.js";import{onDiskMigrationLockPath as ee}from"../core/canvas/paths.js";import{envNoDaemonAutostart as te}from"../shared/env.js";import{waitForDaemonAvailability as re}from"../api/index.js";import{localClient as ne}from"../api/node-transport.js";const oe=["CRTR_NODE_ID","CRTR_KIND","CRTR_MODE","CRTR_LIFECYCLE","CRTR_NODE_CWD","CRTR_CONTEXT_DIR","CRTR_CYCLES","CRTR_PROFILE_ID","CRTR_PARENT_NODE_ID","CRTR_FRONT_DOOR","TMUX","TMUX_PANE","CRTR_BROKER_ENGINE","CRTR_PI_BINARY","NODE_OPTIONS"];function $(){const e={...process.env};for(const t of oe)delete e[t];return e}o($,"sanitizedDaemonEnv");function ae(){for(let e=T(G(import.meta.url));;e=T(e)){if(j(h(e,"bin","runtime-generation-manifest.mjs")))return e;if(T(e)===e)throw new Error(`cannot locate the crouter generation root from ${import.meta.url}`)}}o(ae,"generationRoot");async function F(){const e=ae(),t=b(h(e,"bin","runtime-generation-manifest.mjs")).href,{runtimeHome:r}=await import(t);try{Y(h(r(),"selected"))}catch(c){if(c.code!=="ENOENT")throw c;return["--conditions","crtr-src","--import",b(K(import.meta.url).resolve("tsx/esm")).href,h(e,"src","daemon","crtrd-cli.ts")]}const n=b(h(e,"bin","runtime-selector.mjs")).href,{tryResolveRuntime:i}=await import(n),s=i("daemon");if(!s.ok)throw new Error(`cannot resolve the selected runtime generation's daemon entry: ${s.error}`);return[s.runtime.entryPath]}o(F,"resolveDaemonLaunch");function ie(e,t){return e.includes(` --canvas-home ${t} `)||e.endsWith(` --canvas-home ${t}`)}o(ie,"daemonCommandDeclaresCanvasHome");function se(){let e;try{e=k("ps",["-ax","-o","pid=,command="],{encoding:"utf8",timeout:2e3})}catch{return[]}const t=x(),r=[];for(const n of e.split(`
2
- `)){if(!n.includes("daemon/crtrd")||!ie(n,t))continue;const i=n.trim(),s=i.indexOf(" ");if(s<0)continue;const c=Number.parseInt(i.slice(0,s),10);Number.isInteger(c)&&c!==process.pid&&r.push(c)}return r}o(se,"findDaemonPids");function Ce(e){const t=se().filter(n=>n!==e);for(const n of t)try{process.kill(n,"SIGTERM")}catch{}if(t.length===0)return t;const r=Date.now()+2e3;for(;Date.now()<r&&t.some(n=>w(n));)k("sleep",["0.1"]);for(const n of t)if(w(n))try{process.kill(n,"SIGKILL")}catch{}return t}o(Ce,"sweepStrayDaemons");async function $e(){const e=process.execve;if(e===void 0)throw new Error(`this Node.js ${process.version} runtime cannot replace PID 1 with the successor daemon`);const t=L(),r=await F();return e(t,[t,...r,"--canvas-home",x()],$())}o($e,"execDaemon");const U=2e4,O=10,M=1e3;async function N(e=M){const t=Math.min(e,M);return ne({autostart:!1,timeoutMs:t}).probeHealthz(t)}o(N,"probeDaemonHealth");function ce(e){const t=e instanceof Error?e.message:String(e);if(typeof e!="object"||e===null)return t;const r=e.code,n=e.cause,i=typeof r=="string"?r:n?.code;return typeof i=="string"&&!t.includes(i)?`${t}: ${i}`:t}o(ce,"probeErrorMessage");async function W(e=M){const t=await N(e);if(t.startup_blocked!==void 0){const r=g()??process.pid;throw new R(r,t.startup_blocked)}if(!t.ok)throw new Error("crtrd health check reported not ready")}o(W,"probeDaemonServing");async function Fe(){try{return await W(),!0}catch{return!1}}o(Fe,"isDaemonServing");function I(e){return new Promise(t=>{setTimeout(t,e)})}o(I,"sleepMs");class R extends Error{static{o(this,"DaemonStartupBlockedError")}constructor(t,r){super(`daemon ${t} is running but normal startup is blocked: ${r}`),this.name="DaemonStartupBlockedError"}}class A extends Error{static{o(this,"DaemonNotPreparedError")}constructor(t,r){super(r===void 0?`daemon ${t} is serving but did not report the prepared startup phase`:`daemon ${t} reported startup phase ${r}, not prepared`),this.name="DaemonNotPreparedError"}}async function ue(e,t=C,r={},n="ready"){const i=r.readPidfile??g,s=r.isPidAlive??w,c=r.childExited,u=r.isDaemonServing,_=r.probeDaemonServing??(async f=>{if(u!==void 0){if(await u())return;throw new Error("crtrd health check reported not ready")}await W(f)}),E=r.probeDaemonHealth??N,a=r.sleepMs??I,D=r.now??Date.now;let y=null,l=null;return await re({windowMs:t,pollIntervalMs:O,now:D,sleep:a,retry:o(f=>f!==l,"retry"),probe:o(async f=>{const d=i();if(d===null||!s(d)){const p=c?.();throw p!=null&&(p.signal!==null?l=new Error(`daemon ${e} exited before becoming ready (by ${p.signal})`):p.code!==0&&(l=new Error(`daemon ${e} exited before becoming ready (with exit code ${p.code??"?"})`)),l!==null)?l:new Error(`daemon ${e} has no live pidfile owner`)}if(n==="ready"){try{await _(f)}catch(p){throw p instanceof R&&(l=p),p}y=d;return}const m=await E(f);if(m.startup_phase==="prepared"){y=d;return}throw m.startup_phase==="blocked"?(l=new R(d,m.startup_blocked??"on-disk migration is blocked"),l):m.startup_phase==="ready"?(l=new A(d,m.startup_phase),l):new Error(`daemon ${d} is ${m.startup_phase??"not reporting a startup phase"}; waiting for prepared`)},"probe")}),y===e?null:y}o(ue,"verifyDaemonStartup");async function le(e,t=U,r={}){const n=r.readPidfile??g,i=r.isPidAlive??w,s=r.sleepMs??I,c=r.now??Date.now,u=c()+t;for(;c()<=u;){if(!i(e)&&n()!==e)return;await s(O)}throw new Error(`daemon ${e} did not exit and release its pidfile within ${t}ms`)}o(le,"waitForDaemonExit");const pe=2e3,de=5e3;async function fe(e,t=U,r={}){const n=r.isPidAlive??w,i=r.sleepMs??I,s=r.now??Date.now;try{process.kill(e,"SIGTERM")}catch{}try{return await le(e,t,r),"terminated"}catch{}try{process.kill(e,"SIGKILL")}catch{}const c=s()+pe;for(;s()<=c;){if(!n(e))return"killed";await i(O)}throw new Error(`daemon ${e} survived both SIGTERM and SIGKILL`)}o(fe,"stopDaemonProcess");async function me(e={}){const t=e.targetPhase??"ready",r=g();if(r!==null&&w(r))try{const a=await N();if(t==="prepared"){if(a.startup_phase==="prepared")return{started:!1,existing_pid:r,startup_phase:a.startup_phase};throw new A(r,a.startup_phase)}return a.ok?{started:!1,existing_pid:r,...a.startup_phase===void 0?{}:{startup_phase:a.startup_phase}}:{started:!1,existing_pid:r,running:!0,serving:!1,probe_error:a.startup_blocked??"crtrd health check reported not ready",...a.startup_phase===void 0?{}:{startup_phase:a.startup_phase}}}catch(a){if(a instanceof A)throw a;return{started:!1,existing_pid:r,running:!0,serving:!1,probe_error:ce(a)}}X(x(),{recursive:!0});const n=await F(),i=h(x(),"crtrd.err"),s=z(i,"a");J()===void 0&&q();const c=B(L(),[...n,"--canvas-home",x(),...t==="prepared"?["--prepare"]:[]],{detached:!0,stdio:["ignore",s,s],env:$()});V(s);const u=c.pid;if(u===void 0)throw new Error("daemon spawn did not return a pid");let _=null;c.once("exit",(a,D)=>{_={code:a,signal:D}}),c.unref();let E;try{E=await ue(u,C,{childExited:o(()=>_,"childExited")},t)}catch(a){const D=Z(ee())===u;if(_===null&&!D&&!(a instanceof R))try{await fe(u,de)}catch{}throw a}return E!==null?{started:!1,existing_pid:E,startup_phase:t}:{started:!0,pid:u,startup_phase:t}}o(me,"spawnDaemon");function he(){return te()||process.argv.includes("--no-autostart")}o(he,"autostartDisabled");const we=5e3,_e=6e4;let P=!1,v=0,S=0;function Ee(e){return Math.min(we*2**(e-1),_e)}o(Ee,"autostartBackoffMs");function De(){v=0,S=0}o(De,"resetDaemonAutostart");function Ue(e={}){const t=e.isDaemonRunning??Q,r=e.spawnDaemon??me,n=e.now??Date.now;if(!he()&&!P&&!(n()<S)){if(t()){De();return}P=!0,r().then(()=>{v=0,S=0},i=>{v+=1,S=n()+Ee(v)}).finally(()=>{P=!1})}}o(Ue,"ensureDaemon");export{oe as DAEMON_ENV_STRIP_KEYS,A as DaemonNotPreparedError,R as DaemonStartupBlockedError,he as autostartDisabled,ie as daemonCommandDeclaresCanvasHome,Ue as ensureDaemon,$e as execDaemon,se as findDaemonPids,Fe as isDaemonServing,N as probeDaemonHealth,W as probeDaemonServing,ce as probeErrorMessage,De as resetDaemonAutostart,$ as sanitizedDaemonEnv,me as spawnDaemon,fe as stopDaemonProcess,Ce as sweepStrayDaemons,ue as verifyDaemonStartup,le as waitForDaemonExit};
1
+ var B=Object.defineProperty;var o=(e,t)=>B(e,"name",{value:t,configurable:!0});import{spawn as K,execFileSync as k}from"node:child_process";import{createRequire as G}from"node:module";import{dirname as T,join as w}from"node:path";import{fileURLToPath as j,pathToFileURL as b}from"node:url";import{existsSync as L,lstatSync as Y,mkdirSync as X,openSync as z,closeSync as V}from"node:fs";import{crtrHome as x}from"../core/canvas/paths.js";import{bindDaemonEventSource as q,eventSource as J}from"../core/events/source.js";import{hostExecPath as C}from"../core/runtime/branded-host.js";import{isDaemonRunning as Q,readPidfile as y,isPidAlive as f}from"./pidfile.js";import{DAEMON_STARTUP_WINDOW_MS as $}from"./startup-policy.js";import{exclusiveLockOwnerPid as Z}from"../core/exclusive-lock.js";import{onDiskMigrationLockPath as ee}from"../core/canvas/paths.js";import{envNoDaemonAutostart as te}from"../shared/env.js";import{waitForDaemonAvailability as re}from"../api/index.js";import{localClient as ne}from"../api/node-transport.js";const oe=["CRTR_NODE_ID","CRTR_KIND","CRTR_MODE","CRTR_LIFECYCLE","CRTR_NODE_CWD","CRTR_CONTEXT_DIR","CRTR_CYCLES","CRTR_PROFILE_ID","CRTR_PARENT_NODE_ID","CRTR_FRONT_DOOR","TMUX","TMUX_PANE","CRTR_BROKER_ENGINE","CRTR_PI_BINARY","NODE_OPTIONS"];function F(){const e={...process.env};for(const t of oe)delete e[t];return e}o(F,"sanitizedDaemonEnv");function ae(){for(let e=T(j(import.meta.url));;e=T(e)){if(L(w(e,"bin","runtime-generation-manifest.mjs")))return e;if(T(e)===e)throw new Error(`cannot locate the crouter generation root from ${import.meta.url}`)}}o(ae,"generationRoot");async function U(){const e=ae(),t=b(w(e,"bin","runtime-generation-manifest.mjs")).href,{runtimeHome:r}=await import(t);try{Y(w(r(),"selected"))}catch(c){if(c.code!=="ENOENT")throw c;return["--conditions","crtr-src","--import",b(G(import.meta.url).resolve("tsx/esm")).href,w(e,"src","daemon","crtrd-cli.ts")]}const n=b(w(e,"bin","runtime-selector.mjs")).href,{tryResolveRuntime:i}=await import(n),s=i("daemon");if(!s.ok)throw new Error(`cannot resolve the selected runtime generation's daemon entry: ${s.error}`);return[s.runtime.entryPath]}o(U,"resolveDaemonLaunch");function ie(e,t){return e.includes(` --canvas-home ${t} `)||e.endsWith(` --canvas-home ${t}`)}o(ie,"daemonCommandDeclaresCanvasHome");function se(){let e;try{e=k("ps",["-ax","-o","pid=,command="],{encoding:"utf8",timeout:2e3})}catch{return[]}const t=x(),r=[];for(const n of e.split(`
2
+ `)){if(!n.includes("daemon/crtrd")||!ie(n,t))continue;const i=n.trim(),s=i.indexOf(" ");if(s<0)continue;const c=Number.parseInt(i.slice(0,s),10);Number.isInteger(c)&&c!==process.pid&&r.push(c)}return r}o(se,"findDaemonPids");function Ce(e){const t=se().filter(n=>n!==e);for(const n of t)try{process.kill(n,"SIGTERM")}catch{}if(t.length===0)return t;const r=Date.now()+2e3;for(;Date.now()<r&&t.some(n=>f(n));)k("sleep",["0.1"]);for(const n of t)if(f(n))try{process.kill(n,"SIGKILL")}catch{}return t}o(Ce,"sweepStrayDaemons");async function $e(){const e=process.execve;if(e===void 0)throw new Error(`this Node.js ${process.version} runtime cannot replace PID 1 with the successor daemon`);const t=C(),r=await U();return e(t,[t,...r,"--canvas-home",x()],F())}o($e,"execDaemon");const W=2e4,O=10,M=1e3;async function N(e=M){const t=Math.min(e,M);return ne({autostart:!1,timeoutMs:t}).probeHealthz(t)}o(N,"probeDaemonHealth");function ce(e){const t=e instanceof Error?e.message:String(e);if(typeof e!="object"||e===null)return t;const r=e.code,n=e.cause,i=typeof r=="string"?r:n?.code;return typeof i=="string"&&!t.includes(i)?`${t}: ${i}`:t}o(ce,"probeErrorMessage");async function H(e=M){const t=await N(e);if(t.startup_blocked!==void 0){const r=y()??process.pid;throw new R(r,t.startup_blocked)}if(!t.ok)throw new Error("crtrd health check reported not ready")}o(H,"probeDaemonServing");async function Fe(){try{return await H(),!0}catch{return!1}}o(Fe,"isDaemonServing");function I(e){return new Promise(t=>{setTimeout(t,e)})}o(I,"sleepMs");class R extends Error{static{o(this,"DaemonStartupBlockedError")}constructor(t,r){super(`daemon ${t} is running but normal startup is blocked: ${r}`),this.name="DaemonStartupBlockedError"}}class A extends Error{static{o(this,"DaemonNotPreparedError")}constructor(t,r){super(r===void 0?`daemon ${t} is serving but did not report the prepared startup phase`:`daemon ${t} reported startup phase ${r}, not prepared`),this.name="DaemonNotPreparedError"}}async function ue(e,t=$,r={},n="ready"){const i=r.readPidfile??y,s=r.isPidAlive??f,c=r.childExited,u=r.isDaemonServing,_=r.probeDaemonServing??(async m=>{if(u!==void 0){if(await u())return;throw new Error("crtrd health check reported not ready")}await H(m)}),E=r.probeDaemonHealth??N,a=r.sleepMs??I,D=r.now??Date.now;let g=null,l=null;return await re({windowMs:t,pollIntervalMs:O,now:D,sleep:a,retry:o(m=>m!==l,"retry"),probe:o(async m=>{const d=i();if(d===null||!s(d)){const p=c?.();throw p!=null&&(p.signal!==null?l=new Error(`daemon ${e} exited before becoming ready (by ${p.signal})`):p.code!==0&&(l=new Error(`daemon ${e} exited before becoming ready (with exit code ${p.code??"?"})`)),l!==null)?l:new Error(`daemon ${e} has no live pidfile owner`)}if(n==="ready"){try{await _(m)}catch(p){throw p instanceof R&&(l=p),p}g=d;return}const h=await E(m);if(h.startup_phase==="prepared"){g=d;return}throw h.startup_phase==="blocked"?(l=new R(d,h.startup_blocked??"on-disk migration is blocked"),l):h.startup_phase==="ready"?(l=new A(d,h.startup_phase),l):new Error(`daemon ${d} is ${h.startup_phase??"not reporting a startup phase"}; waiting for prepared`)},"probe")}),g===e?null:g}o(ue,"verifyDaemonStartup");async function le(e,t=W,r={}){const n=r.readPidfile??y,i=r.isPidAlive??f,s=r.sleepMs??I,c=r.now??Date.now,u=c()+t;for(;c()<=u;){if(!i(e)&&n()!==e)return;await s(O)}throw new Error(`daemon ${e} did not exit and release its pidfile within ${t}ms`)}o(le,"waitForDaemonExit");const pe=2e3,de=5e3;async function fe(e,t=W,r={}){const n=r.isPidAlive??f,i=r.sleepMs??I,s=r.now??Date.now;try{process.kill(e,"SIGTERM")}catch{}try{return await le(e,t,r),"terminated"}catch{}try{process.kill(e,"SIGKILL")}catch{}const c=s()+pe;for(;s()<=c;){if(!n(e))return"killed";await i(O)}throw new Error(`daemon ${e} survived both SIGTERM and SIGKILL`)}o(fe,"stopDaemonProcess");async function me(e={}){if(process.platform==="linux"&&L("/run/crtr/launcher.sock")&&!f(y()??-1))throw new Error("crtrd is managed by the root launcher; it cannot self-daemonize");const t=e.targetPhase??"ready",r=y();if(r!==null&&f(r))try{const a=await N();if(t==="prepared"){if(a.startup_phase==="prepared")return{started:!1,existing_pid:r,startup_phase:a.startup_phase};throw new A(r,a.startup_phase)}return a.ok?{started:!1,existing_pid:r,...a.startup_phase===void 0?{}:{startup_phase:a.startup_phase}}:{started:!1,existing_pid:r,running:!0,serving:!1,probe_error:a.startup_blocked??"crtrd health check reported not ready",...a.startup_phase===void 0?{}:{startup_phase:a.startup_phase}}}catch(a){if(a instanceof A)throw a;return{started:!1,existing_pid:r,running:!0,serving:!1,probe_error:ce(a)}}X(x(),{recursive:!0});const n=await U(),i=w(x(),"crtrd.err"),s=z(i,"a");J()===void 0&&q();const c=K(C(),[...n,"--canvas-home",x(),...t==="prepared"?["--prepare"]:[]],{detached:!0,stdio:["ignore",s,s],env:F()});V(s);const u=c.pid;if(u===void 0)throw new Error("daemon spawn did not return a pid");let _=null;c.once("exit",(a,D)=>{_={code:a,signal:D}}),c.unref();let E;try{E=await ue(u,$,{childExited:o(()=>_,"childExited")},t)}catch(a){const D=Z(ee())===u;if(_===null&&!D&&!(a instanceof R))try{await fe(u,de)}catch{}throw a}return E!==null?{started:!1,existing_pid:E,startup_phase:t}:{started:!0,pid:u,startup_phase:t}}o(me,"spawnDaemon");function he(){return te()||process.argv.includes("--no-autostart")}o(he,"autostartDisabled");const we=5e3,_e=6e4;let P=!1,v=0,S=0;function Ee(e){return Math.min(we*2**(e-1),_e)}o(Ee,"autostartBackoffMs");function De(){v=0,S=0}o(De,"resetDaemonAutostart");function Ue(e={}){const t=e.isDaemonRunning??Q,r=e.spawnDaemon??me,n=e.now??Date.now;if(!he()&&!P&&!(n()<S)){if(t()){De();return}P=!0,r().then(()=>{v=0,S=0},i=>{v+=1,S=n()+Ee(v)}).finally(()=>{P=!1})}}o(Ue,"ensureDaemon");export{oe as DAEMON_ENV_STRIP_KEYS,A as DaemonNotPreparedError,R as DaemonStartupBlockedError,he as autostartDisabled,ie as daemonCommandDeclaresCanvasHome,Ue as ensureDaemon,$e as execDaemon,se as findDaemonPids,Fe as isDaemonServing,N as probeDaemonHealth,H as probeDaemonServing,ce as probeErrorMessage,De as resetDaemonAutostart,F as sanitizedDaemonEnv,me as spawnDaemon,fe as stopDaemonProcess,Ce as sweepStrayDaemons,ue as verifyDaemonStartup,le as waitForDaemonExit};
@@ -1 +1 @@
1
- var a=Object.defineProperty;var r=(e,i)=>a(e,"name",{value:i,configurable:!0});import{getNode as l}from"../../core/canvas/canvas.js";import{cancelCronsOnWake as c}from"../../core/canvas/crons.js";import{withFreshTerminalGuard as y}from"../../core/canvas/canvas.js";import{enqueueNodeMail as _}from"../../core/feed/messages.js";import{BrokerUnreachableError as s}from"../../core/runtime/broker-request.js";import{deliverLive as p}from"../../core/runtime/interactive-deliver.js";import{isBrokerLive as u}from"../../core/runtime/model-swap.js";import{reviveNode as v}from"../../core/runtime/revive.js";import{hasNoNaturalCycle as b}from"../../core/runtime/revive-all.js";import{ReviewOperationError as h}from"../../core/review/types.js";import{formatCard as k}from"../../shared/generated-context.js";import{isProfilePaused as w}from"../../core/profiles/manifest.js";function t(e,i){throw new h("delivery_unroutable",i==="origin_missing"?"message target was not found":"message target has no natural delivery cycle",{node_id:e,reason:i})}r(t,"deliveryUnroutable");function m(e,i){const n=y(e,b,i);return n.kind==="missing"&&t(e,"origin_missing"),n.kind==="terminal"&&t(e,"no_natural_cycle"),n.result}r(m,"guardRoutable");async function F(e){m(e.node_id,()=>{});let i=l(e.node_id);if(i===null&&t(e.node_id,"origin_missing"),e.mode==="interactive"&&!w(i.profile_id)&&u(i))try{return await p(e.node_id,e.runtime===void 0?e.body:k(e.runtime.kind,e.runtime.facts,e.body),{origin:e.from==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...e.from==null?{}:{from:e.from},kind:"message",tier:"normal"}]}}),m(e.node_id,()=>{}),c(e.node_id),{entry_id:null,via:"engine",revived:!1}}catch(o){if(!(o instanceof s))throw o}const n=m(e.node_id,()=>_(e.node_id,{senderNodeId:e.from??null,kind:"message",label:e.label,bodyJson:{...e.data,body:e.body},urgency:e.mode==="quiet"?"deferred":"normal",wake:1}));let f=!1,d;if(n.urgency!=="deferred"&&(i=l(e.node_id),i===null&&t(e.node_id,"origin_missing"),!u(i)))try{const o=await v(e.node_id,{resume:!0,capacity:"freeze"});f=o.launch!==void 0,o.outcome==="frozen"&&(d="capacity_frozen")}catch{}return{entry_id:n.messageId,via:"inbox",revived:f,...d===void 0?{}:{reason:d}}}r(F,"deliverNodeMessage");export{F as deliverNodeMessage};
1
+ var a=Object.defineProperty;var r=(e,i)=>a(e,"name",{value:i,configurable:!0});import{getNode as u}from"../../core/canvas/canvas.js";import{cancelCronsOnWake as c}from"../../core/canvas/crons.js";import{withFreshTerminalGuard as _}from"../../core/canvas/canvas.js";import{enqueueNodeMail as y}from"../../core/feed/messages.js";import{BrokerUnreachableError as s}from"../../core/runtime/broker-request.js";import{deliverLive as p}from"../../core/runtime/interactive-deliver.js";import{isBrokerLive as l}from"../../core/runtime/model-swap.js";import{reviveNode as v}from"../../core/runtime/revive.js";import{hasNoNaturalCycle as b}from"../../core/runtime/revive-all.js";import{ReviewOperationError as h}from"../../core/review/types.js";import{formatCard as k}from"../../shared/generated-context.js";import{isProfilePaused as w}from"../../core/profiles/manifest.js";function t(e,i){throw new h("delivery_unroutable",i==="origin_missing"?"message target was not found":"message target has no natural delivery cycle",{node_id:e,reason:i})}r(t,"deliveryUnroutable");function m(e,i){const n=_(e,b,i);return n.kind==="missing"&&t(e,"origin_missing"),n.kind==="terminal"&&t(e,"no_natural_cycle"),n.result}r(m,"guardRoutable");async function F(e){m(e.node_id,()=>{});let i=u(e.node_id);if(i===null&&t(e.node_id,"origin_missing"),e.mode==="interactive"&&!i.run_id&&!w(i.profile_id)&&l(i))try{return await p(e.node_id,e.runtime===void 0?e.body:k(e.runtime.kind,e.runtime.facts,e.body),{origin:e.from==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...e.from==null?{}:{from:e.from},kind:"message",tier:"normal"}]}}),m(e.node_id,()=>{}),c(e.node_id),{entry_id:null,via:"engine",revived:!1}}catch(o){if(!(o instanceof s))throw o}const n=m(e.node_id,()=>y(e.node_id,{senderNodeId:e.from??null,kind:"message",label:e.label,bodyJson:{...e.data,body:e.body},urgency:e.mode==="quiet"?"deferred":"normal",wake:1}));let f=!1,d;if(n.urgency!=="deferred"&&(i=u(e.node_id),i===null&&t(e.node_id,"origin_missing"),!l(i)))try{const o=await v(e.node_id,{resume:!0,capacity:"freeze"});f=o.launch!==void 0,o.outcome==="frozen"&&(d="capacity_frozen")}catch{}return{entry_id:n.messageId,via:"inbox",revived:f,...d===void 0?{}:{reason:d}}}r(F,"deliverNodeMessage");export{F as deliverNodeMessage};
@@ -1 +1 @@
1
- var a=Object.defineProperty;var i=(r,t)=>a(r,"name",{value:t,configurable:!0});import{statSync as f}from"node:fs";import{emitEvent as m}from"../core/events/emit.js";import{hasWakeMailSince as n}from"../core/canvas/deliveries.js";import{readLiveTurn as o}from"../core/canvas/recovery.js";import{parkEvent as u}from"./reconcilers/live-obligation.js";function c(r,t){if(r==null)return!1;try{return f(r).mtimeMs>=t}catch(e){return e.code==="ENOENT"?!1:(m({level:"warn",event:"broker.park.session_activity_scan_failed",error:e}),!0)}}i(c,"mainSessionActivitySince");function S(r,t,e){return!e.activity&&o(r)?.busy!==!0&&!c(t.pi_session_file,e.startedAt)&&!n(r,e.startedAt)&&u(r,t.lifecycle)==="park"}i(S,"shouldParkAfterSummary");export{c as mainSessionActivitySince,S as shouldParkAfterSummary};
1
+ var a=Object.defineProperty;var i=(r,t)=>a(r,"name",{value:t,configurable:!0});import{conversationIdFromPath as n,conversationStore as f,ConversationNotFoundError as u}from"../core/conversation-store/index.js";import{emitEvent as m}from"../core/events/emit.js";import{hasWakeMailSince as c}from"../core/canvas/deliveries.js";import{readLiveTurn as s}from"../core/canvas/recovery.js";import{parkEvent as l}from"./reconcilers/live-obligation.js";function v(r,t){if(r==null)return!1;const e=n(r);if(e===null)return!1;try{return f().header(e).mtime>=t}catch(o){return o instanceof u?!1:(m({level:"warn",event:"broker.park.session_activity_scan_failed",error:o}),!0)}}i(v,"mainSessionActivitySince");function d(r,t,e){return!e.activity&&s(r)?.busy!==!0&&!v(t.pi_session_file,e.startedAt)&&!c(r,e.startedAt)&&l(r,t.lifecycle)==="park"}i(d,"shouldParkAfterSummary");export{v as mainSessionActivitySince,d as shouldParkAfterSummary};
@@ -1 +1 @@
1
- var m=Object.defineProperty;var c=(s,o)=>m(s,"name",{value:o,configurable:!0});import{bashJobPaths as u,expiredAutoBackgroundBashJobs as h,formatBashElapsed as p,stopBackgroundBashJob as b}from"../../core/bash-jobs.js";import{isSafeNodeId as n}from"../../core/canvas/paths.js";import{contextDir as _}from"../../core/canvas/paths.js";import{enqueueNodeMail as g}from"../../core/feed/messages.js";import{emitEvent as d}from"../../core/events/emit.js";import{operationIdContext as l}from"../../core/events/operation-id.js";import{isProfilePaused as N}from"../../core/profiles/manifest.js";const k=5*1e3;class w{static{c(this,"BashDeadlineReconciler")}lastScanAt=Number.NEGATIVE_INFINITY;async run(o,r){if(!(o-this.lastScanAt<k)){this.lastScanAt=o;for(const e of r.rows){if(e.status==="dead"||N(e.profile_id))continue;const a=_(e.node_id);let i;try{i=h(a,o)}catch(t){l.fresh(()=>{d({level:"error",event:"bash_deadline.scan_failed",...n(e.node_id)?{node_id:e.node_id}:{},error:t})});continue}for(const t of i)await this.cancel(e.node_id,a,t.jobId,o-t.startedAtMs)}}}async cancel(o,r,e,a){if((await b(r,e)).kind!=="stopped")return;const t=u(r,e);l.fresh(()=>{try{d({level:"info",event:"bash_deadline.canceled",...n(o)?{node_id:o}:{},fields:{job_id:e}}),g(o,{senderNodeId:null,urgency:"urgent",wake:1,kind:"urgent",label:"background bash job canceled at its deadline",bodyJson:{body:`Background bash job ${e} was canceled after ${p(a)} because its background deadline passed and you did not claim it. Next time, give a long command more room up front (a larger inline timeout), or claim the job with \`crtr node bash extend ${e} --for <duration>\` before the deadline. Log: ${t.jobLog} Command: ${t.cmdSh}`}})}catch(f){d({level:"error",event:"bash_deadline.notice_failed",...n(o)?{node_id:o}:{},error:f,fields:{job_id:e}})}})}}export{w as BashDeadlineReconciler};
1
+ var p=Object.defineProperty;var m=(l,t)=>p(l,"name",{value:t,configurable:!0});import{bashJobPaths as b,completedBackgroundBashJobs as _,expiredAutoBackgroundBashJobs as g,formatBashElapsed as h,stopBackgroundBashJob as y}from"../../core/bash-jobs.js";import{isSafeNodeId as n}from"../../core/canvas/paths.js";import{contextDir as k}from"../../core/canvas/node-agent-paths.js";import{enqueueNodeMail as u}from"../../core/feed/messages.js";import{emitEvent as i}from"../../core/events/emit.js";import{operationIdContext as c}from"../../core/events/operation-id.js";import{isProfilePaused as $}from"../../core/profiles/manifest.js";const v=5*1e3;class E{static{m(this,"BashDeadlineReconciler")}lastScanAt=Number.NEGATIVE_INFINITY;async run(t,a){if(!(t-this.lastScanAt<v)){this.lastScanAt=t;for(const e of a.rows){if(e.status==="dead"||$(e.profile_id))continue;const r=k(e.node_id);let s;try{s=g(r,t)}catch(o){c.fresh(()=>{i({level:"error",event:"bash_deadline.scan_failed",...n(e.node_id)?{node_id:e.node_id}:{},error:o})});continue}if(process.platform==="linux")try{for(const o of _(r)){const d=b(r,o.jobId),f=`Background bash job ${o.jobId} finished (exit ${o.exitCode}) after ${h(t-o.startedAtMs)}. Log: ${d.jobLog} Command: ${d.cmdSh}`;u(e.node_id,{senderNodeId:null,urgency:"urgent",wake:1,kind:"message",label:f.slice(0,120),bodyJson:{body:f},idempotencyKey:`bash-completed:${e.node_id}:${o.jobId}`})}}catch(o){c.fresh(()=>i({level:"error",event:"bash_completion.delivery_failed",...n(e.node_id)?{node_id:e.node_id}:{},error:o}))}for(const o of s)await this.cancel(e.node_id,r,o.jobId,t-o.startedAtMs)}}}async cancel(t,a,e,r){if((await y(a,e,!1,t)).kind!=="stopped")return;const o=b(a,e);c.fresh(()=>{try{i({level:"info",event:"bash_deadline.canceled",...n(t)?{node_id:t}:{},fields:{job_id:e}}),u(t,{senderNodeId:null,urgency:"urgent",wake:1,kind:"urgent",label:"background bash job canceled at its deadline",bodyJson:{body:`Background bash job ${e} was canceled after ${h(r)} because its background deadline passed and you did not claim it. Next time, give a long command more room up front (a larger inline timeout), or claim the job with \`crtr node bash extend ${e} --for <duration>\` before the deadline. Log: ${o.jobLog} Command: ${o.cmdSh}`}})}catch(d){i({level:"error",event:"bash_deadline.notice_failed",...n(t)?{node_id:t}:{},error:d,fields:{job_id:e}})}})}}export{E as BashDeadlineReconciler};
@@ -17,7 +17,7 @@ type TreeSample = {
17
17
  } | null;
18
18
  export interface BrokerSupervisionOptions {
19
19
  readTreeSample?: (pid: number) => Promise<TreeSample>;
20
- signal?: (pid: number, signal: NodeJS.Signals) => void;
20
+ signal?: (pid: number, signal: NodeJS.Signals) => void | Promise<void>;
21
21
  }
22
22
  export interface SaturationContext {
23
23
  fleet: FleetRegistry;
@@ -1,4 +1,4 @@
1
- var H=Object.defineProperty;var p=(s,e)=>H(s,"name",{value:e,configurable:!0});import{statSync as V}from"node:fs";import{join as k}from"node:path";import{homedir as I}from"node:os";import{execFile as K}from"node:child_process";import{promisify as z}from"node:util";import{getNode as A,isWarmSpare as J,subscribersOf as x}from"../../core/canvas/index.js";import{contextDir as Q,isSafeNodeId as u}from"../../core/canvas/paths.js";import{fullName as O}from"../../core/canvas/labels.js";import{recordedPidLiveness as G}from"../../core/canvas/pid.js";import{transition as X}from"../../core/runtime/lifecycle.js";import{readFault as L,readLiveTurn as C,recordFault as Z}from"../../core/canvas/recovery.js";import{errorClassFromFault as ee}from"../../core/fault-classifier.js";import{nextFaultRetry as te}from"../../core/runtime/fault-recovery.js";import{fanDoctrineWake as W}from"../../core/runtime/close.js";import{headlessBrokerHost as y}from"../../core/runtime/host.js";import{reloadAuthLive as ne}from"../../core/runtime/auth-reload.js";import{emitEvent as f}from"../../core/events/emit.js";import{operationIdContext as R}from"../../core/events/operation-id.js";import{hasUnseenWakeMail as re,resetStaleExecutionMail as ie}from"../../core/canvas/deliveries.js";import{activeBackgroundBashJobs as ae}from"../../core/bash-jobs.js";import{focusOf as se}from"../../core/runtime/placement.js";import{hasAttachedBrokerViewers as oe}from"../../core/runtime/broker/client-registry.js";import{deliverLive as le}from"../../core/runtime/interactive-deliver.js";import{BrokerUnreachableError as de}from"../../core/runtime/broker-request.js";import{formatCard as ce,PARK_SUMMARY_PROMPT as ue}from"../../shared/generated-context.js";import{brokerThresholdsForDaemon as fe}from"../../core/runtime/fleet.js";import{readConfig as pe}from"../../core/config.js";import{scopedStoreExists as me}from"../../core/scoped-state/db.js";import{providerStore as he}from"../../core/scoped-state/paths.js";import{providerRevision as _e}from"../../core/scoped-state/providers.js";import{beginPendingPark as ge,consumePendingPark as b,pendingParkIds as ve,pendingParkStartedAt as ke}from"../park-pending.js";import{shouldParkAfterSummary as ye}from"../park-activity.js";import{applyParkEvent as N,parkEvent as be}from"./live-obligation.js";import{envNoDaemonAutostart as we,envTestUnattendedParkMs as Se,parkSummaryGraceMs as Ae,envUnattendedParkMs as Ne}from"../../shared/env.js";const P=z(K);function Pe(s){return C(s)?.busy===!0}p(Pe,"liveBusy");function gt(s){const e=C(s)?.progressAt;if(e==null)return null;const t=Date.parse(e);return Number.isNaN(t)?null:t}p(gt,"liveTurnProgressMs");function B(s,e){return e===null?null:`${s}:${e}`}p(B,"incarnationOf");function F(s){const e=C(s.node_id),t=e?.busy===!0&&e.progressAt!==null?Date.parse(e.progressAt):Number.NaN,a=s.launched_at===null||s.launched_at===void 0?Number.NaN:Date.parse(s.launched_at);return!Number.isFinite(t)||!Number.isFinite(a)||t<a?null:t}p(F,"busySinceForIncarnation");const U=3*6e4,q=2e4,D=20*6e4,Me=2,Te=5*6e4;function $e(){const s=Ne();if(s!==void 0)return s;const e=pe("user").lifecycle.unattendedParkMs;return we()?Se()??e:e}p($e,"unattendedParkMsForDaemon");function Y(){return Ae()}p(Y,"parkSummaryGraceMsForDaemon");function Ee(s,e,t,a){return s!==!0||e!=="refresh"||t?"leave":a===null||a<U?"pending":"kill"}p(Ee,"yieldStallVerdict");function Ce(s){return!s.busy||s.quietForMs===null||s.quietForMs<D?"leave":s.cpuPercent===null||s.hasDescendants!==!1&&s.cpuPercent>Me?"pending":"wedged"}p(Ce,"wedgeVerdict");function j(s){const e=new Map,t=new Map;for(const a of s.split(`
2
- `)){const i=a.trim();if(i==="")continue;const n=i.split(/\s+/);if(n.length<3)continue;const o=Number(n[0]),r=Number(n[1]),d=Number(n[2]);if(!Number.isFinite(o)||!Number.isFinite(r)||!Number.isFinite(d))continue;e.set(o,d);const c=t.get(r);c===void 0?t.set(r,[o]):c.push(o)}return{byPid:e,childrenOf:t}}p(j,"parsePsTree");function Re(s,e){const{byPid:t,childrenOf:a}=j(s);if(!t.has(e))return null;let i=0;const n=[e],o=new Set;for(;n.length>0;){const r=n.pop();if(o.has(r))continue;o.add(r),i+=t.get(r)??0;const d=a.get(r);d!==void 0&&n.push(...d)}return i}p(Re,"sumTreeCpu");function Fe(s,e){const{byPid:t,childrenOf:a}=j(s);return t.has(e)?(a.get(e)??[]).length>0:null}p(Fe,"treeHasDescendants");function De(){const s=process.env.PI_CODING_AGENT_DIR;return s!==void 0&&s!==""?s==="~"||s.startsWith("~/")?k(I(),s.slice(1)):s:k(I(),".pi","agent")}p(De,"piAgentDir");function Ie(s){return[k(s,"auth.json"),k(s,"anthropic-credentials.json"),k(s,"openai-codex-credentials.json")]}p(Ie,"piCredentialPaths");class vt{static{p(this,"BrokerSupervisionReconciler")}yieldStalls=new Map;wedgeNotifiedAt=new Map;fatalFaultNotifiedAt=new Map;unattendedSince=new Map;sampleTree;signal;knownCredentialRevision=null;lastOverCapWarnAt=Number.NEGATIVE_INFINITY;constructor(e={}){this.sampleTree=e.readTreeSample??(t=>this.readTreeSample(t)),this.signal=e.signal??((t,a)=>process.kill(t,a))}async runFleetPreamble(e){return await this.handleAuthReload(e),fe()}warnIfSaturated(e){if(e.fleet.size()<e.thresholds.warning||!e.lifecycle.acceptsDetachedWork())return;const t=R.fresh(()=>this.warnOverCapInTmux(e.fleet.size(),e.thresholds,e.frozen));e.lifecycle.registerDetached(t)}async run(e,t){const a=$e();for(const i of t.rows){const n=i.node_id,o=t.fleet.get(n);if(o===void 0||i.status!=="active"&&i.status!=="idle"){this.unattendedSince.delete(n);continue}await R.fresh(async()=>{try{this.handleYieldStall(i,o,t.fleet,e),await this.handleWedgeDetection(i,o,t.fleet,e),this.handleFatalFault(n),this.handleUnattendedParking(n,A(n),o.pid,e,t,a)}catch(r){this.unattendedSince.delete(n),f({level:"error",event:"broker.supervision.failed",...u(n)?{node_id:n}:{fields:{affected_node_id:n}},error:r})}})}for(const i of this.unattendedSince.keys())t.fleet.has(i)||this.unattendedSince.delete(i);for(const i of ve())t.fleet.has(i)||b(i);ie(e)}parkResetCondition(e,t,a,i){if(t.pi_session_id==null||t.pi_pid!==a||t.status==="done"||t.status==="canceled"||t.status==="dead"||t.intent!==null||ae(Q(e)).length>0||se(e)!==null||oe(e))return!0;const n=L(e);return n!==null&&n.retry.disposition==="auto"&&n.retry.by==="daemon"&&(n.kind==="connection"||n.kind==="rate-limit"||n.kind==="overloaded")&&(n.retry.nextAt!==void 0||te(n,i)!==null)?!0:re(e)}handleUnattendedParking(e,t,a,i,n,o){if(J(e)){this.unattendedSince.delete(e),b(e);return}if(t===null){this.unattendedSince.delete(e),b(e);return}const r=this.parkResetCondition(e,t,a,i),d=ke(e);if(d!==void 0){if(i-d<Y())return;const m=b(e);if(m===void 0||(this.unattendedSince.delete(e),!ye(e,t,m)))return;f({level:"warn",event:"broker.park.summary_expired",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},grace_ms:Y()}}),N(e,"park"),y.teardown(e);return}if(r||Pe(e)){this.unattendedSince.delete(e);return}const c=this.unattendedSince.get(e);if(c===void 0){this.unattendedSince.set(e,i);return}if(i-c<o)return;this.unattendedSince.delete(e);const l=be(e,t.lifecycle);if(l==="release"){N(e,l),y.teardown(e);return}if(l==="cancel"){N(e,l),y.teardown(e);return}n.lifecycle.acceptsDetachedWork()&&(ge(e,i),n.lifecycle.registerDetached(this.requestParkSummary(e)))}async requestParkSummary(e){try{const t=await le(e,ce("park",{},ue),{origin:{type:"runtime",kind:"park"}});f({level:"info",event:"broker.park.summary_requested",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},route:t}})}catch(t){if(b(e)===void 0)return;if(t instanceof de){N(e,"park"),y.teardown(e);return}f({level:"error",event:"broker.park.summary_failed",...u(e)?{node_id:e}:{fields:{affected_node_id:e}},error:t})}}async warnOverCapInTmux(e,t,a){const i=Date.now();if(i-this.lastOverCapWarnAt<Te)return;this.lastOverCapWarnAt=i;const{warning:n,automaticReviveCap:o}=t,r=a.stalled+a.waitingOnMail;f({level:"warn",event:"broker.capacity.warning",fields:{live_count:e,warning_threshold:n,hard_cap:o,frozen_stalled:a.stalled,frozen_waiting_on_mail:a.waitingOnMail}});const d=r===0?"":` \u2014 ${r} frozen (${a.stalled} stalled, ${a.waitingOnMail} waiting on mail)`,c=`\u26A0 crtrd: ${e} live brokers (warning ${n}; hard cap ${o})${d} \u2014 possible broker leak. ps -ax | grep broker-cli.js`;try{const l=await P("tmux",["list-clients","-F","#{client_name}"],{encoding:"utf8",timeout:2e3});if(typeof l.stdout!="string")return;await Promise.allSettled(l.stdout.split(`
3
- `).map(async m=>{if(m!=="")try{await P("tmux",["display-message","-C","-d","10000","-c",m,c],{encoding:"utf8",timeout:2e3})}catch{try{await P("tmux",["display-message","-c",m,c],{encoding:"utf8",timeout:2e3})}catch(h){f({level:"error",event:"broker.capacity.tmux_display_failed",error:h,fields:{client:m}})}}}))}catch(l){f({level:"error",event:"broker.capacity.tmux_list_clients_failed",error:l})}}handleYieldStall(e,t,a,i){const n=e.node_id,o=B(t.pid,e.pi_pid_identity);if(e.intent!=="refresh"||F(e)!==null||o===null){o!==null&&this.yieldStalls.delete(o);return}let r=this.yieldStalls.get(o);if(r===void 0){r={since:i},this.yieldStalls.set(o,r);return}if(Ee(!0,e.intent,!1,i-r.since)!=="kill")return;const d=A(n);if(!(a.get(n)!==t||d?.pi_pid!==t.pid||d.pi_pid_identity!==e.pi_pid_identity||G(t.pid,e.pi_pid_identity)!=="alive"))if(r.termedAt===void 0){if(!this.signalYieldStall(n,t.pid,"SIGTERM"))return;r.termedAt=i,f({level:"warn",event:"broker.yield_stall.sigterm",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,elapsed_ms:i-r.since,grace_ms:U}})}else i-r.termedAt>=q&&this.signalYieldStall(n,t.pid,"SIGKILL")&&f({level:"warn",event:"broker.yield_stall.sigkill",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,elapsed_ms:i-r.termedAt,grace_ms:q,stall_elapsed_ms:i-r.since}})}signalYieldStall(e,t,a){try{return this.signal(t,a),!0}catch(i){return f({level:"error",event:"broker.yield_stall.signal_failed",...u(e)?{node_id:e}:{},error:i,fields:{...u(e)?{}:{affected_node_id:e},pid:t,signal:a}}),!1}}async readTreeSample(e){try{const{stdout:t}=await P("ps",["-ax","-o","pid=,ppid=,pcpu="],{encoding:"utf8",timeout:2e3});if(typeof t!="string")return null;const a=Re(t,e),i=Fe(t,e);return a===null||i===null?null:{cpuPercent:a,hasDescendants:i}}catch{return null}}async handleWedgeDetection(e,t,a,i){const n=e.node_id,o=B(t.pid,e.pi_pid_identity),r=F(e);if(r===null||o===null){o!==null&&this.wedgeNotifiedAt.delete(o);return}const d=i-r,c=d>=D?await this.sampleTree(t.pid):null,l=A(n),m=l===null?null:F(l);if(a.get(n)!==t||l===null||l.pi_pid!==t.pid||l.pi_pid_identity!==e.pi_pid_identity||m!==r)return;const h=c?.cpuPercent??null,_=c?.hasDescendants??null;if(Ce({busy:!0,quietForMs:d,cpuPercent:h,hasDescendants:_})!=="wedged"||this.wedgeNotifiedAt.get(o)===r)return;this.wedgeNotifiedAt.set(o,r);const w=O(l),S=Math.round((d??D)/6e4),M=_??!0,v=!M&&G(t.pid,e.pi_pid_identity)!=="alive"?"pid_identity_unproven":null;let T=!1,$=!1,g;if(M)g=`Child wedged \u2014 ${w} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and its process is near-idle. It will NOT recover on its own \u2014 read \`crtr memory read wedged-child-on-runaway-bash\` and kill the runaway SUBPROCESS (not this node) so its turn can resume with no lost context.`;else if(v!==null)g=`Child wedged \u2014 ${w} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon did not SIGTERM the broker because its PID identity cannot be confirmed alive.`;else{T=!0;try{this.signal(t.pid,"SIGTERM"),$=!0,g=`Child wedged \u2014 ${w} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon sent SIGTERM to the broker and will resume a cleanly aborted session with a continuation, or start a recovery cycle if the abort cannot settle.`}catch(E){f({level:"error",event:"broker.wedge.signal_failed",...u(n)?{node_id:n}:{},error:E,fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,signal:"SIGTERM"}}),g=`Child wedged \u2014 ${w} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon attempted SIGTERM to the broker, but the signal call failed.`}}f({level:"error",event:"broker.wedge.detected",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,quiet_ms:d,cpu_percent:h,has_descendants:M,kick_attempted:T,kicked:$,...v===null?{}:{kick_suppression_reason:v}}});try{Z(n,{link:"daemon\u2192node",op:"engine wedge",kind:"wedged",retry:{disposition:"manual"},message:g})}catch(E){f({level:"error",event:"broker.wedge.fault_record_failed",...u(n)?{node_id:n}:{fields:{affected_node_id:n}},error:E})}W(n,x(n),g,{reason:"child-wedged",child:n,quiet_ms:d,cpu_percent:h,kick_attempted:T,kicked:$,...v===null?{}:{kick_suppression_reason:v}})}handleFatalFault(e){const t=L(e);if(t===null){this.fatalFaultNotifiedAt.delete(e);return}if(t.retry.disposition!=="fatal"||t.link!=="pi\u2192provider"||this.fatalFaultNotifiedAt.get(e)===t.since)return;const a=A(e),i=a!==null?O(a):e,n=t.kind==="auth",o=(t.message.split(`
4
- `)[0]??"").slice(0,200),r=t.providerError,d=r===void 0?"":` Provider: ${r.provider}/${r.model}.`+(r.status===void 0?"":` HTTP status: ${r.status}.`)+(r.errno===void 0?"":` Errno: ${r.errno}.`)+(r.code===void 0?"":` Code: ${r.code}.`)+(r.body===void 0?"":` Body: ${r.body.slice(0,200)}.`),c=t.kind==="context-overflow",l=a?.parent==null&&a?.lifecycle==="terminal",m=c||l,h=c?`Child failed \u2014 ${i} (${e}) exceeded its model context window and is now dead. Shrink the task or loaded context, or choose a larger-context model before spawning it again. Error: ${o}`:`Child hit a fatal provider fault \u2014 ${i} (${e}) got a non-retryable ${t.kind} error and will NOT recover on its own; `+(l?"its terminal run has failed. ":"it stays alive, and waking it clears the fault as soon as one turn completes \u2014 a wake that hits the same cause fails again. "+(n?"Its provider credential is dead \u2014 re-authenticate (`/login`, or re-auth crtr); the child recovers on its next wake once the auth reloads. ":""))+`Error: ${o}.${d}`;m&&(X(e,"crash",{reason:c?"context_overflow":"provider_fatal",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:t.message,fault_kind:t.kind,error_class:ee(t).class}}}),y.teardown(e).then(_=>{_.confirmed||f({level:"error",event:"fault.fatal.teardown_failed",node_id:e,error:_.error??new Error("Broker teardown not confirmed")})},_=>f({level:"error",event:"fault.fatal.teardown_failed",node_id:e,error:_}))),this.fatalFaultNotifiedAt.set(e,t.since),f({level:"error",event:"fault.fatal.fanout",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},kind:t.kind,link:t.link,terminal_overflow:c,terminal_provider_fault:l}}),W(e,x(e),h,{reason:c?"child-context-overflow":"child-fault-fatal",child:e,kind:t.kind,message:o,...r===void 0?{}:{provider_error:r}})}async handleAuthReload(e){const t=De();let a=0;for(const r of Ie(t))try{a=Math.max(a,V(r).mtimeMs)}catch{}let i=0;const n=he(t);me(n)&&(i=_e(t));const o=`${a}:${i}`;if(this.knownCredentialRevision===null){this.knownCredentialRevision=o;return}o!==this.knownCredentialRevision&&(this.knownCredentialRevision=o,await R.fresh(async()=>{try{const r=Array.from(e.entries(),([l])=>l);if(r.length===0)return;const c=(await Promise.allSettled(r.map(async l=>{try{await ne(l)}catch(m){throw f({level:"error",event:"auth.reload.broker_failed",...u(l)?{node_id:l}:{fields:{broker_id:l}},error:m}),m}}))).filter(l=>l.status==="fulfilled").length;f({level:"info",event:"auth.reload.completed",outcome:c===r.length?"succeeded":"failed",fields:{broker_count:r.length,succeeded_count:c,failed_count:r.length-c}})}catch(r){f({level:"error",event:"auth.reload.failed",error:r})}}))}}export{vt as BrokerSupervisionReconciler,Me as WEDGE_CPU_MAX_PERCENT,D as WEDGE_QUIET_MS,U as YIELD_STALL_GRACE_MS,Y as parkSummaryGraceMsForDaemon,Re as sumTreeCpu,Fe as treeHasDescendants,$e as unattendedParkMsForDaemon,Ce as wedgeVerdict,Ee as yieldStallVerdict};
1
+ var H=Object.defineProperty;var m=(o,e)=>H(o,"name",{value:e,configurable:!0});import{existsSync as j,statSync as K}from"node:fs";import{join as $}from"node:path";import{LAUNCHER_SOCKET as V}from"../../launcher/spec.js";import{launcherRequest as z}from"../../launcher/client.js";import{secretsDir as J}from"../../core/layout.js";import{execFile as Q}from"node:child_process";import{promisify as X}from"node:util";import{getNode as A,isWarmSpare as Z,subscribersOf as D}from"../../core/canvas/index.js";import{isSafeNodeId as u}from"../../core/canvas/paths.js";import{contextDir as ee}from"../../core/canvas/node-agent-paths.js";import{fullName as I}from"../../core/canvas/labels.js";import{recordedPidLiveness as O}from"../../core/canvas/pid.js";import{transition as te}from"../../core/runtime/lifecycle.js";import{readFault as L,readLiveTurn as C,recordFault as ne}from"../../core/canvas/recovery.js";import{errorClassFromFault as re}from"../../core/fault-classifier.js";import{nextFaultRetry as ie}from"../../core/runtime/fault-recovery.js";import{fanDoctrineWake as G}from"../../core/runtime/close.js";import{headlessBrokerHost as v}from"../../core/runtime/host.js";import{reloadAuthLive as ae}from"../../core/runtime/auth-reload.js";import{emitEvent as f}from"../../core/events/emit.js";import{operationIdContext as R}from"../../core/events/operation-id.js";import{hasUnseenWakeMail as se,resetStaleExecutionMail as oe}from"../../core/canvas/deliveries.js";import{activeBackgroundBashJobs as le}from"../../core/bash-jobs.js";import{focusOf as de}from"../../core/runtime/placement.js";import{hasAttachedBrokerViewers as ce}from"../api/viewer-presence.js";import{deliverLive as ue}from"../../core/runtime/interactive-deliver.js";import{BrokerUnreachableError as fe}from"../../core/runtime/broker-request.js";import{formatCard as pe,PARK_SUMMARY_PROMPT as me}from"../../shared/generated-context.js";import{brokerThresholdsForDaemon as he}from"../../core/runtime/fleet.js";import{readConfig as _e}from"../../core/config.js";import{scopedStoreExists as ge}from"../../core/scoped-state/db.js";import{providerStore as ve}from"../../core/scoped-state/paths.js";import{providerRevision as ke}from"../../core/scoped-state/providers.js";import{beginPendingPark as ye,consumePendingPark as y,pendingParkIds as we,pendingParkStartedAt as be}from"../park-pending.js";import{shouldParkAfterSummary as Se}from"../park-activity.js";import{applyParkEvent as w,parkEvent as Ae}from"./live-obligation.js";import{envNoDaemonAutostart as Ne,envTestUnattendedParkMs as Pe,parkSummaryGraceMs as Me,envUnattendedParkMs as Te}from"../../shared/env.js";const N=X(Q);function Ee(o){return C(o)?.busy===!0}m(Ee,"liveBusy");function bt(o){const e=C(o)?.progressAt;if(e==null)return null;const t=Date.parse(e);return Number.isNaN(t)?null:t}m(bt,"liveTurnProgressMs");function W(o,e){return e===null?null:`${o}:${e}`}m(W,"incarnationOf");function F(o){const e=C(o.node_id),t=e?.busy===!0&&e.progressAt!==null?Date.parse(e.progressAt):Number.NaN,i=o.launched_at===null||o.launched_at===void 0?Number.NaN:Date.parse(o.launched_at);return!Number.isFinite(t)||!Number.isFinite(i)||t<i?null:t}m(F,"busySinceForIncarnation");const U=3*6e4,B=2e4,x=20*6e4,$e=2,Ce=5*6e4;function Re(){const o=Te();if(o!==void 0)return o;const e=_e("user").lifecycle.unattendedParkMs;return Ne()?Pe()??e:e}m(Re,"unattendedParkMsForDaemon");function q(){return Me()}m(q,"parkSummaryGraceMsForDaemon");function Fe(o,e,t,i){return o!==!0||e!=="refresh"||t?"leave":i===null||i<U?"pending":"kill"}m(Fe,"yieldStallVerdict");function xe(o){return!o.busy||o.quietForMs===null||o.quietForMs<x?"leave":o.cpuPercent===null||o.hasDescendants!==!1&&o.cpuPercent>$e?"pending":"wedged"}m(xe,"wedgeVerdict");function Y(o){const e=new Map,t=new Map;for(const i of o.split(`
2
+ `)){const a=i.trim();if(a==="")continue;const n=a.split(/\s+/);if(n.length<3)continue;const s=Number(n[0]),r=Number(n[1]),d=Number(n[2]);if(!Number.isFinite(s)||!Number.isFinite(r)||!Number.isFinite(d))continue;e.set(s,d);const c=t.get(r);c===void 0?t.set(r,[s]):c.push(s)}return{byPid:e,childrenOf:t}}m(Y,"parsePsTree");function De(o,e){const{byPid:t,childrenOf:i}=Y(o);if(!t.has(e))return null;let a=0;const n=[e],s=new Set;for(;n.length>0;){const r=n.pop();if(s.has(r))continue;s.add(r),a+=t.get(r)??0;const d=i.get(r);d!==void 0&&n.push(...d)}return a}m(De,"sumTreeCpu");function Ie(o,e){const{byPid:t,childrenOf:i}=Y(o);return t.has(e)?(i.get(e)??[]).length>0:null}m(Ie,"treeHasDescendants");function Oe(o){return[$(o,"auth.json"),$(o,"anthropic-credentials.json"),$(o,"openai-codex-credentials.json")]}m(Oe,"piCredentialPaths");class St{static{m(this,"BrokerSupervisionReconciler")}yieldStalls=new Map;wedgeNotifiedAt=new Map;fatalFaultNotifiedAt=new Map;unattendedSince=new Map;sampleTree;signal;knownCredentialRevision=null;lastOverCapWarnAt=Number.NEGATIVE_INFINITY;constructor(e={}){this.sampleTree=e.readTreeSample??(t=>this.readTreeSample(t)),this.signal=e.signal??((t,i)=>{if(process.platform==="linux"&&j(V)){if(i!=="SIGTERM"&&i!=="SIGKILL")throw new Error(`unsupported launcher signal ${i}`);return z({operation:"stop",pid:t,signal:i}).then(()=>{})}process.kill(t,i)})}async runFleetPreamble(e){return await this.handleAuthReload(e),he()}warnIfSaturated(e){if(e.fleet.size()<e.thresholds.warning||!e.lifecycle.acceptsDetachedWork())return;const t=R.fresh(()=>this.warnOverCapInTmux(e.fleet.size(),e.thresholds,e.frozen));e.lifecycle.registerDetached(t)}async run(e,t){const i=Re();for(const a of t.rows){const n=a.node_id,s=t.fleet.get(n);if(s===void 0||a.status!=="active"&&a.status!=="idle"){this.unattendedSince.delete(n);continue}await R.fresh(async()=>{try{await this.handleYieldStall(a,s,t.fleet,e),await this.handleWedgeDetection(a,s,t.fleet,e),this.handleFatalFault(n),this.handleUnattendedParking(n,A(n),s.pid,e,t,i)}catch(r){this.unattendedSince.delete(n),f({level:"error",event:"broker.supervision.failed",...u(n)?{node_id:n}:{fields:{affected_node_id:n}},error:r})}})}for(const a of this.unattendedSince.keys())t.fleet.has(a)||this.unattendedSince.delete(a);for(const a of we())t.fleet.has(a)||y(a);oe(e)}parkResetCondition(e,t,i,a){if(t.pi_session_id==null||t.pi_pid!==i||t.status==="done"||t.status==="canceled"||t.status==="dead"||t.intent!==null||le(ee(e)).length>0||de(e)!==null||ce(e))return!0;const n=L(e);return n!==null&&n.retry.disposition==="auto"&&n.retry.by==="daemon"&&(n.kind==="connection"||n.kind==="rate-limit"||n.kind==="overloaded")&&(n.retry.nextAt!==void 0||ie(n,a)!==null)?!0:se(e)}handleUnattendedParking(e,t,i,a,n,s){if(Z(e)){this.unattendedSince.delete(e),y(e);return}if(t===null){this.unattendedSince.delete(e),y(e);return}const r=this.parkResetCondition(e,t,i,a),d=be(e);if(d!==void 0){if(a-d<q())return;const p=y(e);if(p===void 0||(this.unattendedSince.delete(e),!Se(e,t,p)))return;f({level:"warn",event:"broker.park.summary_expired",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},grace_ms:q()}}),w(e,"park"),v.teardown(e);return}if(r||Ee(e)){this.unattendedSince.delete(e);return}const c=this.unattendedSince.get(e);if(c===void 0){this.unattendedSince.set(e,a);return}if(a-c<s)return;this.unattendedSince.delete(e);const l=Ae(e,t.lifecycle);if(l==="release"){w(e,l),v.teardown(e);return}if(l==="cancel"){w(e,l),v.teardown(e);return}if(t.grantee!==void 0&&t.grantee!=="app:terminal"){w(e,"park"),v.teardown(e);return}n.lifecycle.acceptsDetachedWork()&&(ye(e,a),n.lifecycle.registerDetached(this.requestParkSummary(e)))}async requestParkSummary(e){try{const t=await ue(e,pe("park",{},me),{origin:{type:"runtime",kind:"park"}});f({level:"info",event:"broker.park.summary_requested",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},route:t}})}catch(t){if(y(e)===void 0)return;if(t instanceof fe){w(e,"park"),v.teardown(e);return}f({level:"error",event:"broker.park.summary_failed",...u(e)?{node_id:e}:{fields:{affected_node_id:e}},error:t})}}async warnOverCapInTmux(e,t,i){const a=Date.now();if(a-this.lastOverCapWarnAt<Ce)return;this.lastOverCapWarnAt=a;const{warning:n,automaticReviveCap:s}=t,r=i.stalled+i.waitingOnMail;f({level:"warn",event:"broker.capacity.warning",fields:{live_count:e,warning_threshold:n,hard_cap:s,frozen_stalled:i.stalled,frozen_waiting_on_mail:i.waitingOnMail}});const d=r===0?"":` \u2014 ${r} frozen (${i.stalled} stalled, ${i.waitingOnMail} waiting on mail)`,c=`\u26A0 crtrd: ${e} live brokers (warning ${n}; hard cap ${s})${d} \u2014 possible broker leak. ps -ax | grep broker-cli.js`;try{const l=await N("tmux",["list-clients","-F","#{client_name}"],{encoding:"utf8",timeout:2e3});if(typeof l.stdout!="string")return;await Promise.allSettled(l.stdout.split(`
3
+ `).map(async p=>{if(p!=="")try{await N("tmux",["display-message","-C","-d","10000","-c",p,c],{encoding:"utf8",timeout:2e3})}catch{try{await N("tmux",["display-message","-c",p,c],{encoding:"utf8",timeout:2e3})}catch(h){f({level:"error",event:"broker.capacity.tmux_display_failed",error:h,fields:{client:p}})}}}))}catch(l){f({level:"error",event:"broker.capacity.tmux_list_clients_failed",error:l})}}async handleYieldStall(e,t,i,a){const n=e.node_id,s=W(t.pid,e.pi_pid_identity);if(e.intent!=="refresh"||F(e)!==null||s===null){s!==null&&this.yieldStalls.delete(s);return}let r=this.yieldStalls.get(s);if(r===void 0){r={since:a},this.yieldStalls.set(s,r);return}if(Fe(!0,e.intent,!1,a-r.since)!=="kill")return;const d=A(n);if(!(i.get(n)!==t||d?.pi_pid!==t.pid||d.pi_pid_identity!==e.pi_pid_identity||O(t.pid,e.pi_pid_identity)!=="alive"))if(r.termedAt===void 0){if(!await this.signalYieldStall(n,t.pid,"SIGTERM"))return;r.termedAt=a,f({level:"warn",event:"broker.yield_stall.sigterm",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,elapsed_ms:a-r.since,grace_ms:U}})}else a-r.termedAt>=B&&await this.signalYieldStall(n,t.pid,"SIGKILL")&&f({level:"warn",event:"broker.yield_stall.sigkill",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,elapsed_ms:a-r.termedAt,grace_ms:B,stall_elapsed_ms:a-r.since}})}async signalYieldStall(e,t,i){try{return await this.signal(t,i),!0}catch(a){return f({level:"error",event:"broker.yield_stall.signal_failed",...u(e)?{node_id:e}:{},error:a,fields:{...u(e)?{}:{affected_node_id:e},pid:t,signal:i}}),!1}}async readTreeSample(e){try{const{stdout:t}=await N("ps",["-ax","-o","pid=,ppid=,pcpu="],{encoding:"utf8",timeout:2e3});if(typeof t!="string")return null;const i=De(t,e),a=Ie(t,e);return i===null||a===null?null:{cpuPercent:i,hasDescendants:a}}catch{return null}}async handleWedgeDetection(e,t,i,a){const n=e.node_id,s=W(t.pid,e.pi_pid_identity),r=F(e);if(r===null||s===null){s!==null&&this.wedgeNotifiedAt.delete(s);return}const d=a-r,c=d>=x?await this.sampleTree(t.pid):null,l=A(n),p=l===null?null:F(l);if(i.get(n)!==t||l===null||l.pi_pid!==t.pid||l.pi_pid_identity!==e.pi_pid_identity||p!==r)return;const h=c?.cpuPercent??null,_=c?.hasDescendants??null;if(xe({busy:!0,quietForMs:d,cpuPercent:h,hasDescendants:_})!=="wedged"||this.wedgeNotifiedAt.get(s)===r)return;this.wedgeNotifiedAt.set(s,r);const b=I(l),S=Math.round((d??x)/6e4),P=_??!0,k=!P&&O(t.pid,e.pi_pid_identity)!=="alive"?"pid_identity_unproven":null;let M=!1,T=!1,g;if(P)g=`Child wedged \u2014 ${b} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and its process is near-idle. It will NOT recover on its own \u2014 read \`crtr memory read wedged-child-on-runaway-bash\` and kill the runaway SUBPROCESS (not this node) so its turn can resume with no lost context.`;else if(k!==null)g=`Child wedged \u2014 ${b} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon did not SIGTERM the broker because its PID identity cannot be confirmed alive.`;else{M=!0;try{await this.signal(t.pid,"SIGTERM"),T=!0,g=`Child wedged \u2014 ${b} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon sent SIGTERM to the broker and will resume a cleanly aborted session with a continuation, or start a recovery cycle if the abort cannot settle.`}catch(E){f({level:"error",event:"broker.wedge.signal_failed",...u(n)?{node_id:n}:{},error:E,fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,signal:"SIGTERM"}}),g=`Child wedged \u2014 ${b} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon attempted SIGTERM to the broker, but the signal call failed.`}}f({level:"error",event:"broker.wedge.detected",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,quiet_ms:d,cpu_percent:h,has_descendants:P,kick_attempted:M,kicked:T,...k===null?{}:{kick_suppression_reason:k}}});try{ne(n,{link:"daemon\u2192node",op:"engine wedge",kind:"wedged",retry:{disposition:"manual"},message:g})}catch(E){f({level:"error",event:"broker.wedge.fault_record_failed",...u(n)?{node_id:n}:{fields:{affected_node_id:n}},error:E})}G(n,D(n),g,{reason:"child-wedged",child:n,quiet_ms:d,cpu_percent:h,kick_attempted:M,kicked:T,...k===null?{}:{kick_suppression_reason:k}})}handleFatalFault(e){const t=L(e);if(t===null){this.fatalFaultNotifiedAt.delete(e);return}if(t.retry.disposition!=="fatal"||t.link!=="pi\u2192provider"||this.fatalFaultNotifiedAt.get(e)===t.since)return;const i=A(e),a=i!==null?I(i):e,n=t.kind==="auth",s=(t.message.split(`
4
+ `)[0]??"").slice(0,200),r=t.providerError,d=r===void 0?"":` Provider: ${r.provider}/${r.model}.`+(r.status===void 0?"":` HTTP status: ${r.status}.`)+(r.errno===void 0?"":` Errno: ${r.errno}.`)+(r.code===void 0?"":` Code: ${r.code}.`)+(r.body===void 0?"":` Body: ${r.body.slice(0,200)}.`),c=t.kind==="context-overflow",l=i?.parent==null&&i?.lifecycle==="terminal",p=c||l,h=c?`Child failed \u2014 ${a} (${e}) exceeded its model context window and is now dead. Shrink the task or loaded context, or choose a larger-context model before spawning it again. Error: ${s}`:`Child hit a fatal provider fault \u2014 ${a} (${e}) got a non-retryable ${t.kind} error and will NOT recover on its own; `+(l?"its terminal run has failed. ":"it stays alive, and waking it clears the fault as soon as one turn completes \u2014 a wake that hits the same cause fails again. "+(n?"Its provider credential is dead \u2014 re-authenticate (`/login`, or re-auth crtr); the child recovers on its next wake once the auth reloads. ":""))+`Error: ${s}.${d}`;p&&(te(e,"crash",{reason:c?"context_overflow":"provider_fatal",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:t.message,fault_kind:t.kind,error_class:re(t).class}}}),v.teardown(e).then(_=>{_.confirmed||f({level:"error",event:"fault.fatal.teardown_failed",node_id:e,error:_.error??new Error("Broker teardown not confirmed")})},_=>f({level:"error",event:"fault.fatal.teardown_failed",node_id:e,error:_}))),this.fatalFaultNotifiedAt.set(e,t.since),f({level:"error",event:"fault.fatal.fanout",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},kind:t.kind,link:t.link,terminal_overflow:c,terminal_provider_fault:l}}),G(e,D(e),h,{reason:c?"child-context-overflow":"child-fault-fatal",child:e,kind:t.kind,message:s,...r===void 0?{}:{provider_error:r}})}async handleAuthReload(e){const t=J();let i=0;for(const r of Oe(t))try{i=Math.max(i,K(r).mtimeMs)}catch{}let a=0;const n=ve(t);ge(n)&&(a=ke(t));const s=`${i}:${a}`;if(this.knownCredentialRevision===null){this.knownCredentialRevision=s;return}s!==this.knownCredentialRevision&&(this.knownCredentialRevision=s,await R.fresh(async()=>{try{const r=Array.from(e.entries(),([l])=>l);if(r.length===0)return;const c=(await Promise.allSettled(r.map(async l=>{try{await ae(l)}catch(p){throw f({level:"error",event:"auth.reload.broker_failed",...u(l)?{node_id:l}:{fields:{broker_id:l}},error:p}),p}}))).filter(l=>l.status==="fulfilled").length;f({level:"info",event:"auth.reload.completed",outcome:c===r.length?"succeeded":"failed",fields:{broker_count:r.length,succeeded_count:c,failed_count:r.length-c}})}catch(r){f({level:"error",event:"auth.reload.failed",error:r})}}))}}export{St as BrokerSupervisionReconciler,$e as WEDGE_CPU_MAX_PERCENT,x as WEDGE_QUIET_MS,U as YIELD_STALL_GRACE_MS,q as parkSummaryGraceMsForDaemon,De as sumTreeCpu,Ie as treeHasDescendants,Re as unattendedParkMsForDaemon,xe as wedgeVerdict,Fe as yieldStallVerdict};
@@ -1 +1 @@
1
- var m=Object.defineProperty;var s=(e,r)=>m(e,"name",{value:r,configurable:!0});import{randomUUID as p}from"node:crypto";import{rmSync as y}from"node:fs";import{claimExternalActionDelivery as I,dueExternalActionDeliveries as g,messageBodyForDelivery as h,settleDelivery as a}from"../../core/canvas/deliveries.js";import{getNode as v}from"../../core/canvas/canvas.js";import{emitEvent as l}from"../../core/events/emit.js";import{operationIdContext as c}from"../../core/events/operation-id.js";import{createPageRequest as w,getRequest as D}from"../../core/human/requests.js";import{synthesizedPageDocument as _,writeSynthesizedPage as k}from"../../core/human/page-synth.js";import{preparePage as $}from"../../core/human/page-authoring.js";import{resolvePageComponents as q}from"../../core/config.js";import{spawnChild as x}from"../../core/runtime/spawn.js";import{runDelivery as E}from"../delivery/run-delivery.js";const f=p();function N(e){if(e.adapter===null||typeof e.adapter.adapter!="string")throw new Error(`delivery ${e.deliveryId} has no adapter`);return e.adapter}s(N,"adapterFor");function d(e,r,t){a(e.deliveryId,e.attempts,r,{state:"permanent_failed",failure:{kind:"spawn_error",message:t}},Date.now())}s(d,"failed");async function P(e,r,t){const n=v(t.nodeId);if(n!==null){if(n.frozen_at!==null||n.pi_session_id!==null||n.status==="idle"||n.status==="done"||n.status==="canceled"){a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now());return}d(e,r,n.status==="dead"?`cron spawn ${t.nodeId} recorded a failed birth`:`cron spawn ${t.nodeId} found an incomplete birth`);return}try{await x({nodeId:t.nodeId,kind:t.kind,cwd:t.cwd,prompt:t.prompt,...t.root?{root:!0,rootLifecycle:t.rootLifecycle}:{parent:t.parent},readiness:"launch",profile:t.profile,wakeOrigin:t.wakeOrigin}),a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now())}catch(o){d(e,r,`cron spawn ${t.nodeId} failed: ${o instanceof Error?o.message:String(o)}`),c.fresh(()=>l({level:"error",event:"delivery.cron_spawn_failed",node_id:t.nodeId,error:o,fields:{delivery_id:e.deliveryId}}))}}s(P,"deliverSpawn");function b(e,r){const t=k(_(e.title,e.summary,r,!1));try{return $({sourceFile:t.path,source:{sessionName:e.sessionName,...e.profileName===null?{}:{profileName:e.profileName}},productKinds:q(),delivery:{placement:"inline",inbox:!0,reply:!1}})}finally{y(t.dir,{recursive:!0,force:!0})}}s(b,"preparedCronPage");function z(e,r,t,n){if(D(t.requestId)!==null){a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now());return}const o=typeof n?.stdout=="string"?n.stdout:null;if(o===null){d(e,r,`cron human ${t.requestId} has no frozen stdout`);return}try{w({request_id:t.requestId,prepared:b(t,o)}),a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now())}catch(i){d(e,r,`cron human ${t.requestId} failed: ${i instanceof Error?i.message:String(i)}`)}}s(z,"deliverHuman");async function S(e,r){const t=N(e),n=h(e.deliveryId);if(n===null){d(e,r,`delivery ${e.deliveryId} has no message body`);return}if(t.adapter==="subprocess"){await E({argv:t.argv,cwd:t.cwd,document:n,attempt:e.attempts},o=>{a(e.deliveryId,e.attempts,r,o,Date.now())});return}if(t.adapter==="cron_spawn"){await P(e,r,t);return}z(e,r,t,n)}s(S,"deliverExternal");class J{static{s(this,"DeliveryLaneReconciler")}run(r,t){if(!t.lifecycle.acceptsDetachedWork())return;let n;try{n=g(r)}catch(o){c.fresh(()=>l({level:"error",event:"delivery.scan_failed",error:o}));return}for(const o of n)try{const i=I(o.deliveryId,r,f);if(i===null)continue;t.lifecycle.registerDetached(S(i,f).catch(u=>{c.fresh(()=>l({level:"error",event:"delivery.failed",error:u,fields:{delivery_id:i.deliveryId}}))}))}catch(i){c.fresh(()=>l({level:"error",event:"delivery.claim_failed",error:i,fields:{delivery_id:o.deliveryId}}))}}}export{J as DeliveryLaneReconciler,f as deliveryDaemonInstanceId};
1
+ var p=Object.defineProperty;var s=(e,r)=>p(e,"name",{value:r,configurable:!0});import{randomUUID as h}from"node:crypto";import{rmSync as g}from"node:fs";import{claimExternalActionDelivery as y,dueExternalActionDeliveries as I,messageBodyForDelivery as v,settleDelivery as a}from"../../core/canvas/deliveries.js";import{getNode as w}from"../../core/canvas/canvas.js";import{emitEvent as c}from"../../core/events/emit.js";import{operationIdContext as u}from"../../core/events/operation-id.js";import{createPageRequest as _,getRequest as f}from"../../core/human/requests.js";import{synthesizedPageDocument as D,writeSynthesizedPage as k}from"../../core/human/page-synth.js";import{preparePage as $}from"../../core/human/page-authoring.js";import{resolvePageComponents as q}from"../../core/config.js";import{spawnChild as E}from"../../core/runtime/spawn.js";import{runDelivery as x}from"../delivery/run-delivery.js";const m=h();function N(e){if(e.adapter===null||typeof e.adapter.adapter!="string")throw new Error(`delivery ${e.deliveryId} has no adapter`);return e.adapter}s(N,"adapterFor");function d(e,r,t){a(e.deliveryId,e.attempts,r,{state:"permanent_failed",failure:{kind:"spawn_error",message:t}},Date.now())}s(d,"failed");async function P(e,r,t){const n=w(t.nodeId);if(n!==null){if(n.frozen_at!==null||n.pi_session_id!==null||n.status==="idle"||n.status==="done"||n.status==="canceled"){a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now());return}d(e,r,n.status==="dead"?`cron spawn ${t.nodeId} recorded a failed birth`:`cron spawn ${t.nodeId} found an incomplete birth`);return}try{await E({nodeId:t.nodeId,kind:t.kind,cwd:t.cwd,prompt:t.prompt,...t.root?{root:!0,rootLifecycle:t.rootLifecycle}:{parent:t.parent},readiness:"launch",profile:t.profile,wakeOrigin:t.wakeOrigin}),a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now())}catch(o){d(e,r,`cron spawn ${t.nodeId} failed: ${o instanceof Error?o.message:String(o)}`),u.fresh(()=>c({level:"error",event:"delivery.cron_spawn_failed",node_id:t.nodeId,error:o,fields:{delivery_id:e.deliveryId}}))}}s(P,"deliverSpawn");function b(e,r){const t=k(D(e.title,e.summary,r,!1));try{return $({sourceFile:t.path,source:{sessionName:e.sessionName,...e.profileName===null?{}:{profileName:e.profileName}},productKinds:q(),delivery:{placement:"inline",inbox:!0,reply:!1}})}finally{g(t.dir,{recursive:!0,force:!0})}}s(b,"preparedCronPage");function z(e,r,t,n){if(f(t.requestId)!==null){a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now());return}const o=typeof n?.stdout=="string"?n.stdout:null;if(o===null){d(e,r,`cron human ${t.requestId} has no frozen stdout`);return}try{_({request_id:t.requestId,prepared:b(t,o)}),a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now())}catch(i){d(e,r,`cron human ${t.requestId} failed: ${i instanceof Error?i.message:String(i)}`)}}s(z,"deliverHuman");async function S(e,r){const t=N(e),n=v(e.deliveryId);if(n===null){d(e,r,`delivery ${e.deliveryId} has no message body`);return}if(t.adapter==="subprocess"){let o=t.node_id;if(o===void 0){const i=e.idempotencyKey;if(i?.startsWith("node-outcome:"))o=i.slice(13);else if(i?.startsWith("human-action:")){const l=f(i.slice(13));if(!l)throw new Error(`delivery ${e.deliveryId} has no originating human request`);o=l.requester_node_id}else throw new Error(`delivery ${e.deliveryId} has no originating app`)}await x({argv:t.argv,cwd:t.cwd,document:n,attempt:e.attempts,nodeId:o,...t.app?{app:t.app}:{}},i=>{a(e.deliveryId,e.attempts,r,i,Date.now())});return}if(t.adapter==="cron_spawn"){await P(e,r,t);return}z(e,r,t,n)}s(S,"deliverExternal");class J{static{s(this,"DeliveryLaneReconciler")}run(r,t){if(!t.lifecycle.acceptsDetachedWork())return;let n;try{n=I(r)}catch(o){u.fresh(()=>c({level:"error",event:"delivery.scan_failed",error:o}));return}for(const o of n)try{const i=y(o.deliveryId,r,m);if(i===null)continue;t.lifecycle.registerDetached(S(i,m).catch(l=>{u.fresh(()=>c({level:"error",event:"delivery.failed",error:l,fields:{delivery_id:i.deliveryId}}))}))}catch(i){u.fresh(()=>c({level:"error",event:"delivery.claim_failed",error:i,fields:{delivery_id:o.deliveryId}}))}}}export{J as DeliveryLaneReconciler,m as deliveryDaemonInstanceId};
@@ -1,5 +1,6 @@
1
1
  import { type Lifecycle } from '../../core/canvas/index.js';
2
2
  import { type LifecycleEvent } from '../../core/runtime/lifecycle.js';
3
+ import type { FleetRegistry } from '../../core/runtime/fleet.js';
3
4
  /** Durable work that requires a node to remain automatically wakeable. */
4
5
  export declare function hasLiveObligation(nodeId: string): boolean;
5
6
  /** Whether anything would drive a turn if this node's engine came back right
@@ -11,6 +12,12 @@ export declare function hasLiveObligation(nodeId: string): boolean;
11
12
  * Deferred mail deliberately does not count: it rides the node's next natural
12
13
  * cycle rather than causing one. */
13
14
  export declare function hasPendingWake(nodeId: string): boolean;
15
+ /** The retention sweep's hold: a node with a launch claim, durable work that
16
+ * must wake it, or a person looking at it is never pruned, whatever its age.
17
+ * Unseen mail is deliberately not a hold: it never wakes a terminal node, and
18
+ * children keep writing a finished manager's inbox, so it would retain most
19
+ * finished history forever. The stale sweep checks unseen mail itself. */
20
+ export declare function retentionHold(fleet: Pick<FleetRegistry, 'isClaimed'>): (nodeId: string) => boolean;
14
21
  /** Whether a person is looking at this node right now: a focused viewer pane,
15
22
  * or a broker client that declared itself attending. A client that hellos with
16
23
  * `attends: false` is a system observer and deliberately does not count, which
@@ -1 +1 @@
1
- var c=Object.defineProperty;var e=(r,t)=>c(r,"name",{value:t,configurable:!0});import{newestReportRef as p,hasActiveLiveSubscription as l,hasLiveMessageWait as h,hasLiveSubscriber as m,hasPendingCronWake as k,subscribersOf as b}from"../../core/canvas/index.js";import{fullName as g}from"../../core/canvas/labels.js";import{countTickets as w}from"../../core/canvas/attention.js";import{hasUnseenWakeMail as s}from"../../core/canvas/deliveries.js";import{readOutputRequest as v}from"../../core/runtime/structured-output.js";import{focusOf as x}from"../../core/runtime/placement.js";import{hasAttachedBrokerViewers as W}from"../../core/runtime/broker/client-registry.js";import{fanDoctrineWake as $}from"../../core/runtime/close.js";import{readFault as y}from"../../core/canvas/recovery.js";import{transition as n}from"../../core/runtime/lifecycle.js";function o(r){return l(r)||h(r)||k(r)||w(r)>0||v(r).state!=="absent"}e(o,"hasLiveObligation");function C(r){return o(r)||s(r)?!0:u(r)}e(C,"hasPendingWake");function u(r){return x(r)!==null||W(r)}e(u,"hasHumanViewer");function D(r,t){if(u(r)||o(r))return"release";const i=y(r);return i?.link==="pi\u2192provider"&&i.retry.disposition==="fatal"?"release":t==="resident"?s(r)?"release":"park":s(r)||m(r)?"release":"cancel"}e(D,"parkEvent");function F(r,t){const i=t==="cancel"?n(r,t,{reason:"stranded"}):n(r,t);if(t!=="park")return;const a=p(r),f=a===null?`It left no report behind; \`crtr node inspect show ${r}\` shows where it stands.`:`Its latest report is where it left things: \`crtr canvas history read ${a}\`.`;$(r,b(r),`Resident concluded \u2014 ${g(i)} (${r}) had nothing left to wake it through its unattended grace, so its conversation was concluded. It submitted no final report. ${f} A message to it reopens it on a fresh cycle.`,{reason:"child-auto-done",child:r},"deferred")}e(F,"applyParkEvent");export{F as applyParkEvent,u as hasHumanViewer,o as hasLiveObligation,C as hasPendingWake,D as parkEvent};
1
+ var c=Object.defineProperty;var e=(r,t)=>c(r,"name",{value:t,configurable:!0});import{newestReportRef as l,hasActiveLiveSubscription as p,hasLiveMessageWait as m,hasLiveSubscriber as h,hasPendingCronWake as k,subscribersOf as b}from"../../core/canvas/index.js";import{fullName as g}from"../../core/canvas/labels.js";import{countTickets as w}from"../../core/canvas/attention.js";import{hasUnseenWakeMail as s}from"../../core/canvas/deliveries.js";import{readOutputRequest as v}from"../../core/runtime/structured-output.js";import{focusOf as x}from"../../core/runtime/placement.js";import{hasAttachedBrokerViewers as W}from"../api/viewer-presence.js";import{fanDoctrineWake as $}from"../../core/runtime/close.js";import{readFault as y}from"../../core/canvas/recovery.js";import{transition as u}from"../../core/runtime/lifecycle.js";function a(r){return p(r)||m(r)||k(r)||w(r)>0||v(r).state!=="absent"}e(a,"hasLiveObligation");function q(r){return a(r)||s(r)?!0:n(r)}e(q,"hasPendingWake");function B(r){return t=>r.isClaimed(t)||a(t)||n(t)}e(B,"retentionHold");function n(r){return x(r)!==null||W(r)}e(n,"hasHumanViewer");function D(r,t){if(n(r)||a(r))return"release";const i=y(r);return i?.link==="pi\u2192provider"&&i.retry.disposition==="fatal"?"release":t==="resident"?s(r)?"release":"park":s(r)||h(r)?"release":"cancel"}e(D,"parkEvent");function F(r,t){const i=t==="cancel"?u(r,t,{reason:"stranded"}):u(r,t);if(t!=="park")return;const o=l(r),f=o===null?`It left no report behind; \`crtr node inspect show ${r}\` shows where it stands.`:`Its latest report is where it left things: \`crtr canvas history read ${o}\`.`;$(r,b(r),`Resident concluded \u2014 ${g(i)} (${r}) had nothing left to wake it through its unattended grace, so its conversation was concluded. It submitted no final report. ${f} A message to it reopens it on a fresh cycle.`,{reason:"child-auto-done",child:r},"deferred")}e(F,"applyParkEvent");export{F as applyParkEvent,n as hasHumanViewer,a as hasLiveObligation,q as hasPendingWake,D as parkEvent,B as retentionHold};
@@ -1 +1 @@
1
- var u=Object.defineProperty;var f=(a,i)=>u(a,"name",{value:i,configurable:!0});import{clearFrozen as c,endLiveExecution as l,getNode as m}from"../../../core/canvas/index.js";import{isSafeNodeId as h}from"../../../core/canvas/paths.js";import{recordedPidLiveness as o}from"../../../core/canvas/pid.js";import{emitEvent as _}from"../../../core/events/emit.js";import{operationIdContext as y}from"../../../core/events/operation-id.js";import{readInterruptedTurn as P}from"../../../core/canvas/recovery.js";import{isProfilePaused as p}from"../../../core/profiles/manifest.js";import{classifyDeadNode as k}from"../../fleet.js";import{applyParkEvent as v,hasPendingWake as z,parkEvent as L}from"../live-obligation.js";import{FreezeLaneReconciler as E}from"./freeze-lane.js";import{isInBackoff as I}from"./respawn-policy.js";import{handleTerminatingRow as R}from"./terminating.js";import{wantsExecution as M}from"./wants-execution.js";function N(a){return a.status==="done"||a.status==="canceled"||a.status==="dead"}f(N,"isTerminal");class J{static{f(this,"NodeLifecycleReconciler")}freezeLane=new E;async run(i,e){const n=[];for(const r of e.rows)await y.fresh(async()=>{try{await this.classifyRow(i,r,e,n)}catch(t){const s=r.node_id;_({level:"error",event:"node.lifecycle.classify_failed",...h(s)?{node_id:s}:{fields:{affected_node_id:s}},error:t})}});return this.freezeLane.run(i,{fleet:e.fleet,candidates:n})}async classifyRow(i,e,n,r){const t=e.node_id;if(N(e)){if(R(e,n.fleet.has(t)))return;e.pi_pid!=null&&o(e.pi_pid,e.pi_pid_identity)==="dead"&&l(t,{reason:"observed-dead"}),e.frozen_at!=null&&r.push({row:e,enact:"thaw"});return}if(n.fleet.has(t)){p(e.profile_id)?n.fleet.interruptForProfilePause(t):this.thawMark(e);return}if(p(e.profile_id)){this.freezeLane.endEpisode(t);return}const s=e.pi_pid!=null&&o(e.pi_pid,e.pi_pid_identity)==="dead";if(s&&!n.fleet.hasProfilePauseInterruption(t)&&l(t,{reason:"observed-dead"}),!M(e)){this.thawMark(e),this.settleParked(e);return}if(I(e,i))return;if(e.status==="idle"){r.push({row:e,enact:"idle-release"});return}if(e.pi_pid==null){if(e.respawn_not_before!=null){r.push({row:e,enact:"policy"});return}e.frozen_at!=null&&r.push({row:e,enact:"thaw"});return}if(!s)return;const d=k(m(t),P(t)?.interrupted===!0,z(t));if(d==="respawn-fresh"||d==="respawn-cycle"||d==="respawn-resume"){r.push({row:e,enact:"policy"});return}await n.fleet.applyDeadRowPolicy(t),this.thawMark(e)}thawMark(i){i.frozen_at!=null&&c(i.node_id)}settleParked(i){if(i.status!=="idle")return;this.freezeLane.endEpisode(i.node_id);const e=L(i.node_id,i.lifecycle);e!=="release"&&v(i.node_id,e)}}export{J as NodeLifecycleReconciler};
1
+ var u=Object.defineProperty;var f=(a,i)=>u(a,"name",{value:i,configurable:!0});import{clearFrozen as c,endLiveExecution as l,getNode as m}from"../../../core/canvas/index.js";import{isSafeNodeId as h}from"../../../core/canvas/paths.js";import{recordedPidLiveness as o}from"../../../core/canvas/pid.js";import{emitEvent as _}from"../../../core/events/emit.js";import{operationIdContext as y}from"../../../core/events/operation-id.js";import{readInterruptedTurn as P}from"../../../core/canvas/recovery.js";import{isProfilePaused as p}from"../../../core/profiles/manifest.js";import{isRecoveryHeld as v}from"../../../core/runtime/recovery-hold.js";import{classifyDeadNode as k}from"../../fleet.js";import{applyParkEvent as z,hasPendingWake as L,parkEvent as E}from"../live-obligation.js";import{FreezeLaneReconciler as R}from"./freeze-lane.js";import{isInBackoff as I}from"./respawn-policy.js";import{handleTerminatingRow as M}from"./terminating.js";import{wantsExecution as N}from"./wants-execution.js";function b(a){return a.status==="done"||a.status==="canceled"||a.status==="dead"}f(b,"isTerminal");class O{static{f(this,"NodeLifecycleReconciler")}freezeLane=new R;async run(i,e){const r=[];for(const n of e.rows)await y.fresh(async()=>{try{await this.classifyRow(i,n,e,r)}catch(t){const s=n.node_id;_({level:"error",event:"node.lifecycle.classify_failed",...h(s)?{node_id:s}:{fields:{affected_node_id:s}},error:t})}});return this.freezeLane.run(i,{fleet:e.fleet,candidates:r})}async classifyRow(i,e,r,n){const t=e.node_id;if(b(e)){if(M(e,r.fleet.has(t)))return;e.pi_pid!=null&&o(e.pi_pid,e.pi_pid_identity)==="dead"&&l(t,{reason:"observed-dead"}),e.frozen_at!=null&&n.push({row:e,enact:"thaw"});return}if(r.fleet.has(t)){p(e.profile_id)?r.fleet.interruptForProfilePause(t):this.thawMark(e);return}if(p(e.profile_id)){this.freezeLane.endEpisode(t);return}if(v(t))return;const s=e.pi_pid!=null&&o(e.pi_pid,e.pi_pid_identity)==="dead";if(s&&!r.fleet.hasProfilePauseInterruption(t)&&l(t,{reason:"observed-dead"}),!N(e)){this.thawMark(e),this.settleParked(e);return}if(I(e,i))return;if(e.status==="idle"){n.push({row:e,enact:"idle-release"});return}if(e.pi_pid==null){if(e.respawn_not_before!=null){n.push({row:e,enact:"policy"});return}e.frozen_at!=null&&n.push({row:e,enact:"thaw"});return}if(!s)return;const d=k(m(t),P(t)?.interrupted===!0,L(t));if(d==="respawn-fresh"||d==="respawn-cycle"||d==="respawn-resume"){n.push({row:e,enact:"policy"});return}await r.fleet.applyDeadRowPolicy(t),this.thawMark(e)}thawMark(i){i.frozen_at!=null&&c(i.node_id)}settleParked(i){if(i.status!=="idle")return;this.freezeLane.endEpisode(i.node_id);const e=E(i.node_id,i.lifecycle);e!=="release"&&z(i.node_id,e)}}export{O as NodeLifecycleReconciler};
@@ -1,6 +1,9 @@
1
1
  import type { FleetRegistry } from '../../core/runtime/fleet.js';
2
2
  import type { DetachedWorkLifecycle } from './broker-supervision.js';
3
3
  export declare const DEAD_REAP_GRACE_MS: number;
4
+ export declare const RETENTION_SWEEP_INTERVAL_MS: number;
5
+ export declare const RETENTION_TTL_DAYS = 14;
6
+ export declare const CONTEXT_STRIP_GRACE_MS: number;
4
7
  export interface StorageMaintenanceContext {
5
8
  /** Carries the managed-worktree sweep's detached Git work off this tick. */
6
9
  lifecycle: DetachedWorkLifecycle;
@@ -12,11 +15,27 @@ export interface StorageMaintenanceContext {
12
15
  * managed-worktree reconciliation gets its start-up pass. */
13
16
  export declare class StorageMaintenanceReconciler {
14
17
  private lastSpareSweepAt;
18
+ private lastRunExpiryAt;
19
+ private lastRetentionSweepAt;
20
+ private lastContextStripAt;
21
+ private contextStripInFlight;
15
22
  private focusGcInFlight;
16
23
  private readonly worktreeSweep;
17
24
  run(now: number, ctx: StorageMaintenanceContext): void;
18
- /** Milliseconds since terminal state, launch/settlement, or disposable telemetry changed. Inbox activity is deliberately excluded: children can keep writing a dead manager's inbox. */
25
+ /** Milliseconds since the node's last activity ({@link lastActivityMs}). */
19
26
  private msSinceTerminalActivity;
27
+ /** Delete terminal nodes quiet for {@link RETENTION_TTL_DAYS}, at most once per
28
+ * {@link RETENTION_SWEEP_INTERVAL_MS}. Rows are deleted on the tick; their
29
+ * directories are removed as detached work so a large sweep never blocks it. */
30
+ private sweepRetention;
31
+ /** Register one detached context-strip pass, at most once per
32
+ * {@link RETENTION_SWEEP_INTERVAL_MS} and never overlapping another. */
33
+ private scheduleContextStrip;
34
+ /** Replace bulky context-folder content of finished nodes quiet for
35
+ * {@link CONTEXT_STRIP_GRACE_MS} with tombstones. A node is stripped again
36
+ * only after new activity. App runs are skipped: their files belong to the
37
+ * app's user. */
38
+ private stripFinishedContexts;
20
39
  /** Reap only physical placement residue of terminal nodes. The durable row,
21
40
  * graph, and on-disk state remain available for a later manual revive. */
22
41
  private reapDeadResidue;
@@ -1 +1 @@
1
- var l=Object.defineProperty;var c=(a,r)=>l(a,"name",{value:r,configurable:!0});import{statSync as f}from"node:fs";import{join as u}from"node:path";import{closeFocusRow as _,getFocusById as p,listFocuses as m,listNodes as h}from"../../core/canvas/index.js";import{isSafeNodeId as n,jobDir as S}from"../../core/canvas/paths.js";import{emitEvent as i}from"../../core/events/emit.js";import{operationIdContext as s}from"../../core/events/operation-id.js";import{listLivePanesAsync as v,tearDownNode as w}from"../../core/runtime/placement.js";import{reapStaleSpares as g}from"../../core/runtime/warm-pool.js";import{ManagedWorktreeSweepReconciler as y}from"./managed-worktree-sweep.js";const I=10*6e4,N=60*1e3;class b{static{c(this,"StorageMaintenanceReconciler")}lastSpareSweepAt=Number.NEGATIVE_INFINITY;focusGcInFlight=!1;worktreeSweep=new y;run(r,t){this.reapDeadResidue(r),this.scheduleFocusGc(t),this.gcWarmPool(r),this.worktreeSweep.run(r,t)}msSinceTerminalActivity(r,t){const e=[r.created,r.launched_at,r.last_settled_at,r.finalized_at,r.outcome_at].map(d=>d==null?Number.NaN:Date.parse(d));let o=Math.max(0,...e.filter(Number.isFinite));try{o=Math.max(o,f(u(S(r.node_id),"telemetry.json")).mtimeMs)}catch{}return o===0?Number.POSITIVE_INFINITY:t-o}reapDeadResidue(r){let t;try{t=h({status:["done","canceled","dead"]})}catch(e){s.fresh(()=>{i({level:"error",event:"residue.reap_scan.failed",error:e})});return}for(const e of t)if(!(e.pane==null&&e.window==null&&e.tmux_session==null)){try{if(this.msSinceTerminalActivity(e,r)<I)continue}catch(o){s.fresh(()=>{i({level:"error",event:"residue.reap.failed",...n(e.node_id)?{node_id:e.node_id}:{},error:o,fields:{...n(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}})});continue}s.fresh(()=>{try{i({level:"info",event:"residue.reaped",...n(e.node_id)?{node_id:e.node_id}:{},fields:{...n(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}}),w(e.node_id)}catch(o){i({level:"error",event:"residue.reap.failed",...n(e.node_id)?{node_id:e.node_id}:{},error:o,fields:{...n(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}})}})}}scheduleFocusGc(r){if(this.focusGcInFlight||!r.lifecycle.acceptsDetachedWork())return;this.focusGcInFlight=!0;const t=this.gcStaleFocuses().finally(()=>{this.focusGcInFlight=!1});r.lifecycle.registerDetached(t)}async gcStaleFocuses(){let r;try{r=m()}catch(e){s.fresh(()=>{i({level:"error",event:"focus.gc.failed",error:e})});return}if(r.length===0)return;let t;try{t=await v()}catch(e){s.fresh(()=>{i({level:"error",event:"focus.gc.failed",error:e})});return}if(t!==null)for(const e of r){if(e.pane===null||t.has(e.pane))continue;if(!s.fresh(()=>{try{return p(e.focus_id)?.pane!==e.pane||(i({level:"info",event:"focus.gc.removed",...n(e.node_id)?{node_id:e.node_id}:{},fields:{focus_id:e.focus_id,focus_node_id:e.node_id,pane:e.pane}}),_(e.focus_id)),!0}catch(d){return i({level:"error",event:"focus.gc.failed",error:d}),!1}}))return}}gcWarmPool(r){r-this.lastSpareSweepAt<N||(this.lastSpareSweepAt=r,s.fresh(()=>{const t=g();t.length>0&&i({level:"info",event:"warm_pool.spares_reaped",outcome:"succeeded",fields:{reaped_count:t.length}})}))}}export{I as DEAD_REAP_GRACE_MS,b as StorageMaintenanceReconciler};
1
+ var I=Object.defineProperty;var c=(f,t)=>I(f,"name",{value:t,configurable:!0});import{rm as y}from"node:fs/promises";import{closeFocusRow as g,getFocusById as N,listFocuses as E,listNodes as h}from"../../core/canvas/index.js";import{getNode as A,lastActivityMs as u,pruneNodes as x}from"../../core/canvas/canvas.js";import{lastContextStripMs as R,stripContextDir as T}from"../../core/canvas/context-strip.js";import{isSafeNodeId as d}from"../../core/canvas/paths.js";import{emitEvent as i}from"../../core/events/emit.js";import{operationIdContext as o}from"../../core/events/operation-id.js";import{listLivePanesAsync as w,tearDownNode as F}from"../../core/runtime/placement.js";import{reapStaleSpares as D}from"../../core/runtime/warm-pool.js";import{ManagedWorktreeSweepReconciler as C}from"./managed-worktree-sweep.js";import{expireRunEvents as G}from"../../core/runs/events.js";import{retentionHold as m}from"./live-obligation.js";import{pruneMemoryReads as P}from"../../core/canvas/memory-reads.js";const M=10*6e4,b=60*1e3,v=5*6e4,W=14,V=1440*6e4;class U{static{c(this,"StorageMaintenanceReconciler")}lastSpareSweepAt=Number.NEGATIVE_INFINITY;lastRunExpiryAt=Number.NEGATIVE_INFINITY;lastRetentionSweepAt=Number.NEGATIVE_INFINITY;lastContextStripAt=Number.NEGATIVE_INFINITY;contextStripInFlight=!1;focusGcInFlight=!1;worktreeSweep=new C;run(t,r){if(this.reapDeadResidue(t),this.scheduleFocusGc(r),this.gcWarmPool(t),t-this.lastRunExpiryAt>=60*6e4){G(t);try{P(t)}catch(e){console.warn(`memory-read log prune failed: ${String(e)}`)}this.lastRunExpiryAt=t}this.sweepRetention(t,r),this.scheduleContextStrip(t,r),this.worktreeSweep.run(t,r)}msSinceTerminalActivity(t,r){const e=u(t);return e===0?Number.POSITIVE_INFINITY:r-e}sweepRetention(t,r){t-this.lastRetentionSweepAt<v||r.lifecycle.acceptsDetachedWork()&&(this.lastRetentionSweepAt=t,o.fresh(()=>{try{const e=x({ttlDays:W,held:m(r.fleet),removeDirs:c(s=>{r.lifecycle.registerDetached(Promise.all(s.map(l=>y(l,{recursive:!0,force:!0}))).then(()=>{}).catch(l=>{o.fresh(()=>{i({level:"error",event:"canvas.retention.failed",error:l})})}))},"removeDirs")});e.pruned.length>0&&i({level:"info",event:"canvas.retention.pruned",outcome:"succeeded",fields:{pruned_count:e.pruned.length}})}catch(e){i({level:"error",event:"canvas.retention.failed",error:e})}}))}scheduleContextStrip(t,r){if(this.contextStripInFlight||t-this.lastContextStripAt<v||!r.lifecycle.acceptsDetachedWork())return;this.lastContextStripAt=t,this.contextStripInFlight=!0;const e=this.stripFinishedContexts(t,r).finally(()=>{this.contextStripInFlight=!1});r.lifecycle.registerDetached(e)}async stripFinishedContexts(t,r){const e=m(r.fleet),s=c(n=>n!==null&&["done","canceled","dead"].includes(n.status)&&(n.pi_pid??null)===null&&(n.frozen_at??null)===null&&(n.run_id??null)===null&&u(n)<t-V&&!e(n.node_id),"eligible");let l=0,p=0;try{for(const n of h({status:["done","canceled","dead"]})){if(!d(n.node_id)||!s(n))continue;const _=await R(n.node_id);if(_!==null&&_>=u(n)||!s(A(n.node_id)))continue;let a;try{a=await T(n.node_id)}catch(S){o.fresh(()=>{i({level:"warn",event:"canvas.context_strip.node_failed",error:S,fields:{node_id:n.node_id}})});continue}a.removed.length>0&&(l+=1,p+=a.bytes)}}catch(n){o.fresh(()=>{i({level:"error",event:"canvas.context_strip.failed",error:n})})}l>0&&o.fresh(()=>{i({level:"info",event:"canvas.context_strip.completed",outcome:"succeeded",fields:{node_count:l,bytes:p}})})}reapDeadResidue(t){let r;try{r=h({status:["done","canceled","dead"]})}catch(e){o.fresh(()=>{i({level:"error",event:"residue.reap_scan.failed",error:e})});return}for(const e of r)if(!(e.pane==null&&e.window==null&&e.tmux_session==null)){try{if(this.msSinceTerminalActivity(e,t)<M)continue}catch(s){o.fresh(()=>{i({level:"error",event:"residue.reap.failed",...d(e.node_id)?{node_id:e.node_id}:{},error:s,fields:{...d(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}})});continue}o.fresh(()=>{try{i({level:"info",event:"residue.reaped",...d(e.node_id)?{node_id:e.node_id}:{},fields:{...d(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}}),F(e.node_id)}catch(s){i({level:"error",event:"residue.reap.failed",...d(e.node_id)?{node_id:e.node_id}:{},error:s,fields:{...d(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}})}})}}scheduleFocusGc(t){if(this.focusGcInFlight||!t.lifecycle.acceptsDetachedWork())return;this.focusGcInFlight=!0;const r=this.gcStaleFocuses().finally(()=>{this.focusGcInFlight=!1});t.lifecycle.registerDetached(r)}async gcStaleFocuses(){let t;try{t=E()}catch(e){o.fresh(()=>{i({level:"error",event:"focus.gc.failed",error:e})});return}if(t.length===0)return;let r;try{r=await w()}catch(e){o.fresh(()=>{i({level:"error",event:"focus.gc.failed",error:e})});return}if(r!==null)for(const e of t){if(e.pane===null||r.has(e.pane))continue;if(!o.fresh(()=>{try{return N(e.focus_id)?.pane!==e.pane||(i({level:"info",event:"focus.gc.removed",...d(e.node_id)?{node_id:e.node_id}:{},fields:{focus_id:e.focus_id,focus_node_id:e.node_id,pane:e.pane}}),g(e.focus_id)),!0}catch(l){return i({level:"error",event:"focus.gc.failed",error:l}),!1}}))return}}gcWarmPool(t){t-this.lastSpareSweepAt<b||(this.lastSpareSweepAt=t,o.fresh(()=>{const r=D();r.length>0&&i({level:"info",event:"warm_pool.spares_reaped",outcome:"succeeded",fields:{reaped_count:r.length}})}))}}export{V as CONTEXT_STRIP_GRACE_MS,M as DEAD_REAP_GRACE_MS,v as RETENTION_SWEEP_INTERVAL_MS,W as RETENTION_TTL_DAYS,U as StorageMaintenanceReconciler};
@@ -0,0 +1,6 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { SessionEntry } from '../../core/conversation-store/index.js';
3
+ export declare const TURN_INPUT_TYPE = "crtr-turn-input";
4
+ export declare const SYSTEM_PROMPT_TYPE = "crtr-system-prompt";
5
+ export declare const TURN_END_TYPE = "crtr-turn-end";
6
+ export declare function appendConversationEvents(db: DatabaseSync, runId: string, nodeId: string, entries: SessionEntry[], pendingInputIds: string[]): string[];
@@ -0,0 +1,2 @@
1
+ var y=Object.defineProperty;var p=(e,n)=>y(e,"name",{value:n,configurable:!0});import{appendRunEvent as E}from"../../core/runs/events.js";const g="crtr-turn-input",T="crtr-system-prompt",h="crtr-turn-end",l=p(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"zero");function x(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>typeof n?.text=="string").map(n=>n.text).join(`
2
+ `):""}p(x,"text");function R(e){return{input_tokens:e.input??0,output_tokens:e.output??0,cache_read_tokens:e.cacheRead??0,cache_write_tokens:e.cacheWrite??0,cost_usd:e.cost?.total??0}}p(R,"usageParts");function w(e,n,d,m,f){let c=f;for(const s of m){if(s.type==="custom"&&s.customType===g){const t=s.data?.message_ids;if(!Array.isArray(t)||!t.every(o=>typeof o=="string"))throw new Error("invalid crtr-turn-input message_ids");c=t}const r=p((t,o)=>E(e,n,d,t,{...o,entry_id:s.id}),"emit");if(s.type==="custom"&&s.customType===T){const t=s.data?.text;if(typeof t!="string")throw new Error("invalid crtr-system-prompt text");r("node.system_prompt.set",{text:t})}if(s.type==="custom"&&s.customType===h){const t=s.data?.stop_reason;if(typeof t!="string")throw new Error("invalid crtr-turn-end stop_reason");const o=e.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(n,d);if(!o)throw new Error("crtr-turn-end without node.turn.started");const{input:u}=JSON.parse(o.body_json),i=e.prepare("SELECT status, pi_pid FROM node_rows WHERE run_id = ? AND node_id != ?").all(n,d).some(a=>a.pi_pid!==null&&a.status==="active")?"running":"idle";r("node.turn.completed",{message_ids:u.message_ids,run_status:i,stop_reason:t})}if(s.type==="message"){const t=s.message;if(t.role==="user"&&(r("node.turn.started",{input:{text:x(t.content),message_ids:c}}),c=[]),t.role==="assistant"){for(const o of t.content)o.type==="thinking"&&r("node.thinking.done",{text:o.thinking}),o.type==="text"&&r("node.output_text.done",{text:o.text,stop_reason:t.stopReason}),o.type==="toolCall"&&r("node.tool_call.started",{tool_call_id:o.id,name:o.name,arguments:o.arguments});if(t.usage){const o=R(t.usage),u=e.prepare("SELECT usage_json FROM nodes WHERE node_id = ?").get(n),_=u.usage_json?JSON.parse(u.usage_json):l(),i=l();for(const a of Object.keys(i))i[a]=_[a]+o[a];e.prepare("UPDATE nodes SET usage_json = ? WHERE node_id = ?").run(JSON.stringify(i),n),r("usage",{served_model:t.model,...o,usage:i})}}t.role==="toolResult"&&r("node.tool_call.completed",{tool_call_id:t.toolCallId,name:t.toolName,result:t.content,status:t.isError?"error":"ok"})}}return c}p(w,"appendConversationEvents");export{T as SYSTEM_PROMPT_TYPE,h as TURN_END_TYPE,g as TURN_INPUT_TYPE,w as appendConversationEvents};
@@ -0,0 +1,5 @@
1
+ export declare function openAssistantMessageStartSequence(nodeId: string): number | null;
2
+ export declare function ensureRunObserver(nodeId: string, runId: string): void;
3
+ /** Observes run nodes with a live broker, plus those whose current outcome
4
+ * (settled within the event retention window) has no `node.settled` event yet. */
5
+ export declare function pollRunObservers(): void;
@@ -0,0 +1,4 @@
1
+ var f=Object.defineProperty;var a=(s,t)=>f(s,"name",{value:t,configurable:!0});import{randomUUID as S}from"node:crypto";import{openDb as d}from"../../core/canvas/db.js";import{getNode as h}from"../../core/canvas/canvas.js";import{BrokerClient as g,SocketTransport as I}from"../../core/broker-client/client.js";import{emitRunEvent as l,emitRunSettlement as E}from"../../core/runs/events.js";import{toRunOutcomeDTO as D}from"../api/map.js";const u=new Map;class R{static{a(this,"RunObserver")}nodeId;runId;client;timer;status;outcomeRevision;openAssistant=!1;assistantStartSequence=0;thinking="";output="";closed=!1;constructor(t,e){this.nodeId=t,this.runId=e;const n=d(),o=n.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = ? ORDER BY sequence_number DESC LIMIT 1").get(t,t===e?"node.settled":"child.settled");o&&(this.outcomeRevision=JSON.parse(o.body_json).outcome.revision);const i=n.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = 'node.status.changed' ORDER BY sequence_number DESC LIMIT 1").get(t);i&&(this.status=JSON.parse(i.body_json).status),this.timer=setInterval(()=>this.poll(),250),this.timer.unref(),u.set(t,this),this.poll()}poll(){const t=h(this.nodeId);if(!t||t.run_id!==this.runId){this.close();return}const e=t.pi_pid===null?"dormant":t.status;this.status!==e&&l(this.runId,this.nodeId,"node.status.changed",{status:e,reason:t.intent??null}),this.status=e;const n=D(t);if(n&&n.revision!==this.outcomeRevision&&Date.now()-Date.parse(n.settled_at)<720*60*6e4){if(this.nodeId===this.runId){const o=d().prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(this.runId,this.runId);for(const i of o)m(i.node_id,this.runId),u.get(i.node_id)?.poll()}this.outcomeRevision=n.revision,this.nodeId===this.runId?E(this.runId,this.nodeId,"node.settled",{outcome:n,usage:JSON.parse(t.usage_json??"{}")}):E(this.runId,this.nodeId,"child.settled",{child_node_id:this.nodeId,outcome:n})}t.pi_pid===null?this.close():this.connect()}get assistantMessageStartSequence(){return this.openAssistant&&this.client&&h(this.nodeId)?.pi_pid!=null?this.assistantStartSequence:null}connect(){if(this.client||this.closed)return;const t=new g(this.nodeId,{transport:new I(this.nodeId,{recordsViewerFaults:!1})});this.client=t,t.on("connect",()=>t.send({type:"hello",role:"observer",client_id:S(),attends:!1})),t.on("frame",e=>{if(e.type==="message_start"&&e.message.role==="assistant"&&(this.openAssistant=!0,this.thinking="",this.output="",this.assistantStartSequence=d().prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(this.runId).event_cursor),e.type==="message_update"&&e.message.role==="assistant"&&this.openAssistant){if(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}const o=e.message.content;if(!Array.isArray(o))return;const i=o.filter(r=>r?.type==="thinking").map(r=>r.thinking).join(""),c=o.filter(r=>r?.type==="text").map(r=>r.text).join(""),p=i.startsWith(this.thinking)?i.slice(this.thinking.length):i,_=c.startsWith(this.output)?c.slice(this.output.length):c;this.thinking=i,this.output=c,p&&l(this.runId,this.nodeId,"node.thinking.delta",{delta:p}),_&&l(this.runId,this.nodeId,"node.output_text.delta",{delta:_})}e.type==="message_end"&&e.message.role==="assistant"&&(this.openAssistant=!1)}),t.on("error",()=>{}),t.on("close",()=>{this.client===t&&(this.client=void 0,this.openAssistant=!1)}),t.connect()}close(){this.closed=!0,clearInterval(this.timer),u.delete(this.nodeId);const t=this.client;this.client=void 0,t?.close()}}function k(s){return u.get(s)?.assistantMessageStartSequence??null}a(k,"openAssistantMessageStartSequence");function m(s,t){if(!u.has(s)){if(s!==t){const e=h(s);!d().prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'child.started' LIMIT 1").get(t,s)&&e&&Date.now()-Date.parse(e.created)<720*60*6e4&&l(t,s,"child.started",{child_node_id:s,kind:e.kind})}new R(s,t)}}a(m,"ensureRunObserver");function b(){const s=new Date(Date.now()-2592e6).toISOString(),t=d().prepare(`SELECT n.node_id, n.run_id FROM node_rows n 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 > ?
2
+ AND n.outcome_reason != 'parked' AND NOT EXISTS (
3
+ SELECT 1 FROM run_events e WHERE e.run_id = n.run_id AND e.node_id = n.node_id AND e.type = CASE WHEN n.node_id = n.run_id THEN 'node.settled' ELSE 'child.settled' END
4
+ AND json_extract(e.body_json, '$.outcome.revision') = COALESCE(n.outcome_revision, 1))))`).all(s);for(const e of t)m(e.node_id,e.run_id)}a(b,"pollRunObservers");export{m as ensureRunObserver,k as openAssistantMessageStartSequence,b as pollRunObservers};
@@ -0,0 +1,4 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+ import { type LaunchSpec } from './spec.js';
3
+ import type { SourceValidator } from './validate.js';
4
+ export declare function launchSandbox(spec: LaunchSpec, tokenFd: number | undefined, validator: SourceValidator, dataGid: number, onSpawn?: (child: ChildProcess) => void): Promise<ChildProcess>;
@@ -0,0 +1,2 @@
1
+ var B=Object.defineProperty;var l=(e,o)=>B(e,"name",{value:o,configurable:!0});import{spawn as k}from"node:child_process";import{closeSync as g}from"node:fs";import{join as m}from"node:path";import{loadLinuxNative as _}from"../native/linux.js";import{seccompFd as A}from"./seccomp.js";import{LaunchRefused as d}from"./spec.js";const E=_();function $(e,o){const s=m(o.runtime,"nodes",e.nodeId,"job","broker.log");if(e.log!==s)throw new d("log_refused","log must be this node\u2019s broker.log");try{return o.openLog(e.nodeId)}catch(f){throw new d("log_refused",String(f))}}l($,"openLog");async function T(e,o,s,f,y){if(!E)throw new Error("Linux native addon is required");const x=m(s.runtime,"nodes",e.nodeId,"job","broker.log");if(e.log!==x)throw new d("log_refused","log must be this node\u2019s broker.log");const b=s.pin(e);let u,p;try{if(e.capture===void 0)u=$(e,s);else if(!Number.isInteger(e.capture.stdoutBytes)||e.capture.stdoutBytes<0||e.capture.stdoutBytes>10*1024*1024||!Number.isInteger(e.capture.stderrBytes)||e.capture.stderrBytes<0||e.capture.stderrBytes>10*1024*1024||e.capture.stdin!==void 0&&Buffer.byteLength(e.capture.stdin)>10*1024*1024)throw new d("invalid_spec","invalid capture limits");p=A();const a=[],w=l(n=>(a.push(n),a.length+4),"addFd"),c=["--unshare-pid","--unshare-ipc","--unshare-uts","--die-with-parent","--new-session","--clearenv","--tmpfs","/","--proc","/proc","--dev","/dev","--perms","1777","--tmpfs","/tmp"],h=new Set;for(const n of b){let r=m(n.source,"..");const i=[];for(;r!=="/"&&!h.has(r);)i.push(r),r=m(r,"..");for(const v of i.reverse())c.push("--perms","0755","--dir",v),h.add(v);const I=w(n.fd);c.push(n.writable?"--bind-fd":"--ro-bind-fd",String(I),n.source),n.kind===16384&&h.add(n.source)}const S=w(p);c.push("--seccomp",String(S));const L=Object.entries(e.env).map(([n,r])=>`${n}=${r}`);c.push("--setenv","PATH","/usr/bin:/bin","--chdir",e.cwd,"--","/bin/setpriv","--reuid",String(e.uid),"--regid",String(f),"--groups",String(f),"--no-new-privs","--bounding-set=-all","--inh-caps=-all","--ambient-caps=-all","--","/usr/bin/env","-i",...L,"/bin/sh","-c",'printf "READY\\n" >&4; exec 4>&-; exec "$@"',"sh",...e.command);const t=k("/usr/bin/bwrap",c,{stdio:[e.capture?.stdin===void 0?"ignore":"pipe",e.capture?"pipe":u,e.capture?"pipe":u,o??"ignore","pipe",...a],env:{PATH:"/usr/bin:/bin"},cwd:"/",detached:!1});y?.(t),e.capture?.stdin!==void 0&&(t.stdin?.on("error",()=>{}),t.stdin?.end(e.capture.stdin));try{await new Promise((n,r)=>{t.once("error",r),t.once("exit",i=>r(new d("launch_failed",`bwrap exited before sandbox command: ${i}`))),t.stdio[4]?.once("data",i=>i.toString()===`READY
2
+ `?n():r(new d("launch_failed","invalid sandbox readiness")))})}catch(n){throw t.kill("SIGKILL"),n}return t.stdio[4]?.destroy(),t}finally{u!==void 0&&g(u),p!==void 0&&g(p);for(const a of b)g(a.fd)}}l(T,"launchSandbox");export{T as launchSandbox};
@@ -0,0 +1,2 @@
1
+ import { type LauncherReply, type LauncherRequest } from './spec.js';
2
+ export declare function launcherRequest(request: LauncherRequest, fds?: number[], path?: string): Promise<LauncherReply>;
@@ -0,0 +1,3 @@
1
+ var h=Object.defineProperty;var s=(t,i)=>h(t,"name",{value:i,configurable:!0});import{connect as w}from"node:net";import{loadLinuxNative as m}from"../native/linux.js";import{LAUNCHER_SOCKET as p,LaunchRefused as y}from"./spec.js";const d=m();async function N(t,i=[],u=p){if(!d)throw new Error("Linux launcher client requires the native addon");const e=w(u);try{await new Promise((c,r)=>{e.once("connect",c),e.once("error",r)});const a=e._handle?.fd;if(a===void 0||a<0)throw new Error("launcher socket fd unavailable");d.sendFds(a,JSON.stringify(t),i);const f=await new Promise((c,r)=>{let o="";e.on("data",l=>{o+=l.toString(),o.includes(`
2
+ `)&&c(o.slice(0,o.indexOf(`
3
+ `)))}),e.once("end",()=>r(new Error("launcher disconnected without reply"))),e.once("error",r)}),n=JSON.parse(f);if("refusal"in n)throw new y(n.refusal,`launcher refused ${n.refusal}`);return n}finally{e.destroy()}}s(N,"launcherRequest");export{N as launcherRequest};
@@ -0,0 +1 @@
1
+ export declare function runLauncher(): Promise<void>;
@@ -0,0 +1,3 @@
1
+ var D=Object.defineProperty;var f=(l,d)=>D(l,"name",{value:d,configurable:!0});import{spawn as J}from"node:child_process";import{createHash as j}from"node:crypto";import{chownSync as B,chmodSync as O,closeSync as q,existsSync as V,mkdirSync as P,readFileSync as z,rmSync as Q,statSync as W}from"node:fs";import{createServer as X}from"node:net";import{dirname as H,join as K}from"node:path";import{fileURLToPath as Y}from"node:url";import{loadLinuxNative as Z}from"../native/linux.js";import{envHomeOverride as ee}from"../shared/env.js";import{launchSandbox as te}from"./bwrap.js";import{installNetworkRule as re}from"./netrule.js";import{LAUNCHER_SOCKET as h,LaunchRefused as p}from"./spec.js";import{systemIdentity as ne,AppUsers as oe}from"./users.js";import{SourceValidator as se}from"./validate.js";const C=Z();function U(l){const d=l._handle?.fd;if(d===void 0||d<0)throw new Error("launcher socket fd unavailable");return d}f(U,"socketFd");async function ie(){if(process.platform!=="linux"||process.getuid?.()!==0||!C)throw new Error("launcher requires Linux root and its native addon");const{daemonUid:l,daemonGid:d,dataGid:E}=ne(),v=H(h);if(P(v,{recursive:!0,mode:493}),(W(v).mode&511)!==493)throw new Error(`${v} must be mode 0755`);B(v,l,d),process.umask(7);const R=K(v,"nodes");P(R,{recursive:!0,mode:504}),B(R,0,d),O(R,504);const L=new se(ee()||"/",d),x=new oe(E);re();const m=new Map,w=new Map,$=f((t,c)=>{const r=c.capture,e=j("sha256"),s=f((u,a)=>{let I=0,S=!1;const b=[];return{take(T){a?.update(T);const _=Math.max(0,Math.min(T.length,u-I));_&&(b.push(T.subarray(0,_)),I+=_),_!==T.length&&(S=!0)},result:f(()=>({text:Buffer.concat(b).toString("utf8"),truncated:S}),"result")}},"chunks"),n=s(r.stdoutBytes,e),i=s(r.stderrBytes);let o=Buffer.alloc(0),g=0;return t.stdout?.on("data",u=>n.take(u)),t.stderr?.on("data",u=>{const a=u;r.stderrTail?(g+=a.length,o=a.length>=r.stderrBytes?a.subarray(a.length-r.stderrBytes):Buffer.concat([o,a]).subarray(Math.max(0,o.length+a.length-r.stderrBytes))):i.take(a)}),new Promise(u=>t.once("close",(a,I)=>{const S=n.result(),b=r.stderrTail?{text:o.toString("utf8"),truncated:g>r.stderrBytes}:i.result();u({exitCode:a,signal:I,stdout:S.text,stderr:b.text,stdoutTruncated:S.truncated,stderrTruncated:b.truncated,stdoutSha256:e.digest("hex")})}))},"captureExit"),F=f(t=>{const c=new Set;for(;t>1&&!c.has(t);){const r=m.get(t);if(r)return r;c.add(t);try{const e=z(`/proc/${t}/status`,"utf8");t=Number(/^PPid:\s*(\d+)/m.exec(e)?.[1]??0)}catch{return null}}return null},"sandboxForPid");let y,k=!1;const A=K(H(Y(import.meta.url)),"../daemon/crtrd-cli.js"),G=f(()=>{k||(y=J("/bin/setpriv",["--reuid",String(l),"--regid",String(d),"--groups",String(E),"--",process.execPath,A,...process.argv.slice(2)],{stdio:"inherit",env:{...process.env,CRTR_LAUNCHER_SOCKET:h,CRTR_HOME:L.root}}),y.once("exit",()=>{y=void 0,k||G()}),y.once("error",t=>{console.error("crtrd spawn failed:",t),process.exitCode=1,k=!0}))},"startDaemon");V(h)&&Q(h);const N=X({pauseOnConnect:!0},t=>{const c=[];(async()=>{try{if(C.peerCred(U(t)).uid!==l)throw new p("invalid_spec","launcher peer is not crtrd");let r;for(;;)try{r=C.recvFds(U(t));break}catch(n){if(n.code!=="EINTR")throw n}c.push(...r.fds);const e=JSON.parse(r.data);let s;switch(e.operation){case"launch":{if(c.length>1||!x.has(e.spec.uid))throw new p("invalid_uid","app uid is not registered");let n,i;try{i=await te(e.spec,c[0],L,E,o=>{if(!o.pid)throw new p("launch_failed","bwrap has no pid");if(n=o.pid,m.set(o.pid,{child:o,uid:e.spec.uid,nodeId:e.spec.nodeId,mounts:e.spec.mounts}),o.once("exit",()=>m.delete(o.pid)),e.spec.capture){const g=o.pid,u=$(o,e.spec);w.set(g,u),u.then(()=>{setTimeout(()=>{w.get(g)===u&&w.delete(g)},3e5).unref()})}})}catch(o){throw n!==void 0&&w.delete(n),o}if(!i.pid)throw new p("launch_failed","bwrap has no pid");s={pid:i.pid};break}case"wait":{const n=w.get(e.pid);if(!n)throw new p("invalid_spec","unknown captured sandbox pid");const i=await n;w.delete(e.pid),s={result:i};break}case"stop":{const n=Number.isInteger(e.pid)?F(e.pid):null;if(!n||e.nodeId!==void 0&&n.nodeId!==e.nodeId)throw new p("invalid_spec","unknown sandbox pid");if(e.signal!==void 0&&e.signal!=="SIGTERM"&&e.signal!=="SIGKILL")throw new p("invalid_spec","invalid stop signal");n.child.kill(e.signal??"SIGKILL"),s={ok:!0};break}case"user.create":s={uid:x.create(e.app,e.uid)};break;case"user.delete":{if([...m.values()].some(n=>n.uid===e.uid))throw new p("invalid_spec","stop this app\u2019s sandboxes before deleting its user");x.delete(e.uid),s={ok:!0};break}case"users.sync":x.sync(e.users),s={ok:!0};break;case"list":s={sandboxes:[...m].map(([n,i])=>({pid:n,uid:i.uid,nodeId:i.nodeId,mounts:i.mounts}))};break;case"daemon.handover":y?.kill("SIGTERM"),s={ok:!0};break;default:throw new p("invalid_spec","unknown launcher operation")}t.end(`${JSON.stringify(s)}
2
+ `)}catch(r){const e=r instanceof p?r.refusal:"launch_failed";console.error(`launcher refusal ${e}:`,r),t.end(`${JSON.stringify({refusal:e})}
3
+ `)}finally{for(const r of c)q(r)}})()});await new Promise((t,c)=>{N.once("error",c),N.listen(h,t)}),B(h,l,d),O(h,384);const M=f(()=>{k=!0,y?.kill("SIGTERM");for(const{child:t}of m.values())t.kill("SIGKILL");N.close(),L.close()},"shutdown");process.once("SIGTERM",M),process.once("SIGINT",M),G()}f(ie,"runLauncher"),await ie().catch(l=>{console.error(l),process.exitCode=1});export{ie as runLauncher};
@@ -0,0 +1 @@
1
+ export declare function installNetworkRule(): void;
@@ -0,0 +1 @@
1
+ var l=Object.defineProperty;var i=(t,r)=>l(t,"name",{value:r,configurable:!0});import{spawnSync as f}from"node:child_process";import{networkInterfaces as c}from"node:os";import{APP_UID_MAX as d,APP_UID_MIN as a}from"./spec.js";function n(t,r){const s=["-w","-t","filter"],e=f(t,[...s,"-C","OUTPUT",...r],{encoding:"utf8"});if(e.status===0)return;if(e.status!==1)throw new Error(`${t} rule check failed: ${e.stderr}`);const o=f(t,[...s,"-I","OUTPUT","1",...r],{encoding:"utf8"});if(o.status!==0)throw new Error(`${t} rule install failed: ${o.stderr||o.error}`)}i(n,"rule");function $(){const t=["-m","owner","--uid-owner",`${a}-${d}`],r=new Set(["127.0.0.0/8"]),s=new Set(["::1/128"]);for(const e of Object.values(c()))for(const o of e??[])(o.family==="IPv4"?r:s).add(`${o.address.split("%")[0]}/${o.family==="IPv4"?32:128}`);for(const e of r)n("iptables",[...t,"-p","tcp","--dport","8080","-d",e,"-j","DROP"]);for(const e of s)n("ip6tables",[...t,"-p","tcp","--dport","8080","-d",e,"-j","DROP"]);n("iptables",[...t,"-d","169.254.169.254/32","-j","DROP"]),n("ip6tables",[...t,"-d","fd00:ec2::254/128","-j","DROP"])}i($,"installNetworkRule");export{$ as installNetworkRule};
@@ -0,0 +1 @@
1
+ export declare function seccompFd(): number;
@@ -0,0 +1 @@
1
+ var y=Object.defineProperty;var p=(s,o)=>y(s,"name",{value:o,configurable:!0});import{mkdtempSync as h,openSync as E,unlinkSync as k,writeFileSync as w,rmdirSync as S,constants as L}from"node:fs";const b={x64:{clone:56,clone3:435,unshare:272,setns:308,mount:165,umount2:166,ptrace:101,bpf:321,keyctl:250,add_key:248,request_key:249,init_module:175,finit_module:313,delete_module:176,pivot_root:155,open_tree:428,move_mount:429,fsopen:430,fsconfig:431,fsmount:432,mount_setattr:442},arm64:{clone:220,clone3:435,unshare:97,setns:268,mount:40,umount2:39,ptrace:117,bpf:280,keyctl:219,add_key:217,request_key:218,init_module:105,finit_module:273,delete_module:106,pivot_root:41,open_tree:428,move_mount:429,fsopen:430,fsconfig:431,fsmount:432,mount_setattr:442}},u=32,a=21,d=69,c=6,i=327681,O=327718,g=2147418112,N=268435456;function I(){const s=b[process.arch];if(!s)throw new Error(`unsupported seccomp architecture: ${process.arch}`);const o=[],e=p((t,n,f,l)=>o.push([t,n,f,l]),"push");e(u,0,0,4),e(a,1,0,process.arch==="x64"?3221225534:3221225655),e(c,0,0,i),e(u,0,0,0),process.arch==="x64"&&(e(d,0,1,1073741824),e(c,0,0,i));for(const[t,n]of Object.entries(s))t==="clone"||t==="unshare"?(e(a,0,3,n),e(u,0,0,16),e(d,0,1,N),e(c,0,0,i),e(u,0,0,0)):(e(a,0,1,n),e(c,0,0,t==="clone3"?O:i));e(c,0,0,g);const r=Buffer.alloc(o.length*8);for(let t=0;t<o.length;t++){const[n,f,l,x]=o[t];r.writeUInt16LE(n,t*8),r.writeUInt8(f,t*8+2),r.writeUInt8(l,t*8+3),r.writeUInt32LE(x,t*8+4)}const _=h("/run/crtr/seccomp-"),m=`${_}/filter`;try{return w(m,r,{mode:384,flag:"wx"}),E(m,L.O_RDONLY)}finally{k(m),S(_)}}p(I,"seccompFd");export{I as seccompFd};