visionclaw 0.1.219-beta.0 → 0.1.219-dev.codex-issue-2805-worker-runtime.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (520) hide show
  1. package/dist/agent/api-proxy.d.ts +0 -16
  2. package/dist/agent/api-proxy.d.ts.map +1 -1
  3. package/dist/agent/api-proxy.js +9 -8
  4. package/dist/agent/api-proxy.js.map +1 -1
  5. package/dist/agent/browser-launcher.d.ts +3 -0
  6. package/dist/agent/browser-launcher.d.ts.map +1 -1
  7. package/dist/agent/browser-launcher.js +101 -43
  8. package/dist/agent/browser-launcher.js.map +1 -1
  9. package/dist/agent/coding-conventions.d.ts +8 -0
  10. package/dist/agent/coding-conventions.d.ts.map +1 -0
  11. package/dist/agent/coding-conventions.js +19 -0
  12. package/dist/agent/coding-conventions.js.map +1 -0
  13. package/dist/agent/command-handlers.d.ts.map +1 -1
  14. package/dist/agent/command-handlers.js +4 -16
  15. package/dist/agent/command-handlers.js.map +1 -1
  16. package/dist/agent/context-action-restart-fallback.d.ts.map +1 -1
  17. package/dist/agent/context-action-restart-fallback.js +9 -3
  18. package/dist/agent/context-action-restart-fallback.js.map +1 -1
  19. package/dist/agent/context-refresh.d.ts.map +1 -1
  20. package/dist/agent/context-refresh.js +0 -7
  21. package/dist/agent/context-refresh.js.map +1 -1
  22. package/dist/agent/context.d.ts +2 -4
  23. package/dist/agent/context.d.ts.map +1 -1
  24. package/dist/agent/context.js +12 -21
  25. package/dist/agent/context.js.map +1 -1
  26. package/dist/agent/engine-fallback.d.ts +0 -35
  27. package/dist/agent/engine-fallback.d.ts.map +1 -1
  28. package/dist/agent/engine-fallback.js +4 -3
  29. package/dist/agent/engine-fallback.js.map +1 -1
  30. package/dist/agent/engine-switch.d.ts +19 -38
  31. package/dist/agent/engine-switch.d.ts.map +1 -1
  32. package/dist/agent/engine-switch.js +46 -111
  33. package/dist/agent/engine-switch.js.map +1 -1
  34. package/dist/agent/engines/browser-tool-policy.d.ts +12 -1
  35. package/dist/agent/engines/browser-tool-policy.d.ts.map +1 -1
  36. package/dist/agent/engines/browser-tool-policy.js +17 -2
  37. package/dist/agent/engines/browser-tool-policy.js.map +1 -1
  38. package/dist/agent/engines/claude/executor-shell-groups.d.ts +11 -0
  39. package/dist/agent/engines/claude/executor-shell-groups.d.ts.map +1 -0
  40. package/dist/agent/engines/claude/executor-shell-groups.js +22 -0
  41. package/dist/agent/engines/claude/executor-shell-groups.js.map +1 -0
  42. package/dist/agent/engines/claude/session.d.ts +13 -4
  43. package/dist/agent/engines/claude/session.d.ts.map +1 -1
  44. package/dist/agent/engines/claude/session.js +165 -84
  45. package/dist/agent/engines/claude/session.js.map +1 -1
  46. package/dist/agent/engines/pi/shared/usage.d.ts +6 -8
  47. package/dist/agent/engines/pi/shared/usage.d.ts.map +1 -1
  48. package/dist/agent/engines/pi/shared/usage.js +24 -7
  49. package/dist/agent/engines/pi/shared/usage.js.map +1 -1
  50. package/dist/agent/engines/pi/tools.d.ts +3 -10
  51. package/dist/agent/engines/pi/tools.d.ts.map +1 -1
  52. package/dist/agent/engines/pi/tools.js +6 -20
  53. package/dist/agent/engines/pi/tools.js.map +1 -1
  54. package/dist/agent/engines/pi-coding/executor-shell.d.ts +4 -0
  55. package/dist/agent/engines/pi-coding/executor-shell.d.ts.map +1 -0
  56. package/dist/agent/engines/pi-coding/executor-shell.js +175 -0
  57. package/dist/agent/engines/pi-coding/executor-shell.js.map +1 -0
  58. package/dist/agent/engines/pi-coding/session.d.ts +4 -4
  59. package/dist/agent/engines/pi-coding/session.d.ts.map +1 -1
  60. package/dist/agent/engines/pi-coding/session.js +118 -66
  61. package/dist/agent/engines/pi-coding/session.js.map +1 -1
  62. package/dist/agent/engines/pi-coding/tools.d.ts +2 -5
  63. package/dist/agent/engines/pi-coding/tools.d.ts.map +1 -1
  64. package/dist/agent/engines/pi-coding/tools.js +7 -5
  65. package/dist/agent/engines/pi-coding/tools.js.map +1 -1
  66. package/dist/agent/engines/session-types.d.ts +8 -8
  67. package/dist/agent/engines/session-types.d.ts.map +1 -1
  68. package/dist/agent/external-context/interrupt.d.ts +0 -2
  69. package/dist/agent/external-context/interrupt.d.ts.map +1 -1
  70. package/dist/agent/external-context/interrupt.js +0 -1
  71. package/dist/agent/external-context/interrupt.js.map +1 -1
  72. package/dist/agent/external-context/registry.d.ts +0 -2
  73. package/dist/agent/external-context/registry.d.ts.map +1 -1
  74. package/dist/agent/external-context/registry.js +2 -4
  75. package/dist/agent/external-context/registry.js.map +1 -1
  76. package/dist/agent/external-context/runtime.d.ts.map +1 -1
  77. package/dist/agent/external-context/runtime.js +15 -14
  78. package/dist/agent/external-context/runtime.js.map +1 -1
  79. package/dist/agent/external-context/types.d.ts +0 -2
  80. package/dist/agent/external-context/types.d.ts.map +1 -1
  81. package/dist/agent/fast-responder.d.ts +4 -20
  82. package/dist/agent/fast-responder.d.ts.map +1 -1
  83. package/dist/agent/fast-responder.js +28 -42
  84. package/dist/agent/fast-responder.js.map +1 -1
  85. package/dist/agent/interrupt-handler.d.ts +0 -6
  86. package/dist/agent/interrupt-handler.d.ts.map +1 -1
  87. package/dist/agent/interrupt-handler.js +5 -47
  88. package/dist/agent/interrupt-handler.js.map +1 -1
  89. package/dist/agent/lab-run-system-prompt.d.ts.map +1 -1
  90. package/dist/agent/lab-run-system-prompt.js +4 -1
  91. package/dist/agent/lab-run-system-prompt.js.map +1 -1
  92. package/dist/agent/lifecycle-trace.d.ts.map +1 -1
  93. package/dist/agent/lifecycle-trace.js +6 -5
  94. package/dist/agent/lifecycle-trace.js.map +1 -1
  95. package/dist/agent/loop.d.ts +8 -2
  96. package/dist/agent/loop.d.ts.map +1 -1
  97. package/dist/agent/loop.js +287 -156
  98. package/dist/agent/loop.js.map +1 -1
  99. package/dist/agent/memory-protocol.d.ts +2 -2
  100. package/dist/agent/memory-protocol.d.ts.map +1 -1
  101. package/dist/agent/memory-protocol.js +3 -15
  102. package/dist/agent/memory-protocol.js.map +1 -1
  103. package/dist/agent/memory-store.d.ts +58 -0
  104. package/dist/agent/memory-store.d.ts.map +1 -0
  105. package/dist/agent/memory-store.js +152 -0
  106. package/dist/agent/memory-store.js.map +1 -0
  107. package/dist/agent/model-provider.d.ts +18 -5
  108. package/dist/agent/model-provider.d.ts.map +1 -1
  109. package/dist/agent/model-provider.js +58 -18
  110. package/dist/agent/model-provider.js.map +1 -1
  111. package/dist/agent/nightly-maintenance/dreaming-batch.d.ts +184 -0
  112. package/dist/agent/nightly-maintenance/dreaming-batch.d.ts.map +1 -0
  113. package/dist/agent/nightly-maintenance/dreaming-batch.js +192 -0
  114. package/dist/agent/nightly-maintenance/dreaming-batch.js.map +1 -0
  115. package/dist/agent/nightly-maintenance/dreaming-files.d.ts +48 -0
  116. package/dist/agent/nightly-maintenance/dreaming-files.d.ts.map +1 -0
  117. package/dist/agent/nightly-maintenance/dreaming-files.js +109 -0
  118. package/dist/agent/nightly-maintenance/dreaming-files.js.map +1 -0
  119. package/dist/agent/nightly-maintenance/dreaming-ledger.d.ts +62 -0
  120. package/dist/agent/nightly-maintenance/dreaming-ledger.d.ts.map +1 -0
  121. package/dist/agent/nightly-maintenance/dreaming-ledger.js +146 -0
  122. package/dist/agent/nightly-maintenance/dreaming-ledger.js.map +1 -0
  123. package/dist/agent/nightly-maintenance/dreaming-planner.d.ts +86 -0
  124. package/dist/agent/nightly-maintenance/dreaming-planner.d.ts.map +1 -0
  125. package/dist/agent/nightly-maintenance/dreaming-planner.js +304 -0
  126. package/dist/agent/nightly-maintenance/dreaming-planner.js.map +1 -0
  127. package/dist/agent/nightly-maintenance/dreaming-runner.d.ts +93 -0
  128. package/dist/agent/nightly-maintenance/dreaming-runner.d.ts.map +1 -0
  129. package/dist/agent/nightly-maintenance/dreaming-runner.js +156 -0
  130. package/dist/agent/nightly-maintenance/dreaming-runner.js.map +1 -0
  131. package/dist/agent/nightly-maintenance/dreaming-sources.d.ts +115 -0
  132. package/dist/agent/nightly-maintenance/dreaming-sources.d.ts.map +1 -0
  133. package/dist/agent/nightly-maintenance/dreaming-sources.js +270 -0
  134. package/dist/agent/nightly-maintenance/dreaming-sources.js.map +1 -0
  135. package/dist/agent/nightly-maintenance/index.d.ts +28 -8
  136. package/dist/agent/nightly-maintenance/index.d.ts.map +1 -1
  137. package/dist/agent/nightly-maintenance/index.js +42 -15
  138. package/dist/agent/nightly-maintenance/index.js.map +1 -1
  139. package/dist/agent/nightly-maintenance/skill-learning-gate.js +1 -1
  140. package/dist/agent/nightly-maintenance/skill-learning-gate.js.map +1 -1
  141. package/dist/agent/nightly-maintenance/vocabulary-processor.d.ts +1 -1
  142. package/dist/agent/nightly-maintenance/vocabulary-processor.d.ts.map +1 -1
  143. package/dist/agent/product-identity.d.ts +5 -4
  144. package/dist/agent/product-identity.d.ts.map +1 -1
  145. package/dist/agent/product-identity.js +7 -6
  146. package/dist/agent/product-identity.js.map +1 -1
  147. package/dist/agent/public-activity.js +1 -1
  148. package/dist/agent/public-activity.js.map +1 -1
  149. package/dist/agent/runtime-context.d.ts +27 -0
  150. package/dist/agent/runtime-context.d.ts.map +1 -0
  151. package/dist/agent/runtime-context.js +60 -0
  152. package/dist/agent/runtime-context.js.map +1 -0
  153. package/dist/agent/runtime-disclosure-policy.d.ts +6 -0
  154. package/dist/agent/runtime-disclosure-policy.d.ts.map +1 -0
  155. package/dist/agent/runtime-disclosure-policy.js +16 -0
  156. package/dist/agent/runtime-disclosure-policy.js.map +1 -0
  157. package/dist/agent/runtime-surface.d.ts +15 -4
  158. package/dist/agent/runtime-surface.d.ts.map +1 -1
  159. package/dist/agent/runtime-surface.js +0 -1
  160. package/dist/agent/runtime-surface.js.map +1 -1
  161. package/dist/agent/session-manager.d.ts +30 -126
  162. package/dist/agent/session-manager.d.ts.map +1 -1
  163. package/dist/agent/session-manager.js +60 -484
  164. package/dist/agent/session-manager.js.map +1 -1
  165. package/dist/agent/state.d.ts +42 -2
  166. package/dist/agent/state.d.ts.map +1 -1
  167. package/dist/agent/state.js +21 -11
  168. package/dist/agent/state.js.map +1 -1
  169. package/dist/agent/stream-handler.d.ts +6 -13
  170. package/dist/agent/stream-handler.d.ts.map +1 -1
  171. package/dist/agent/stream-handler.js +8 -62
  172. package/dist/agent/stream-handler.js.map +1 -1
  173. package/dist/agent/system-prompt.d.ts +2 -0
  174. package/dist/agent/system-prompt.d.ts.map +1 -1
  175. package/dist/agent/system-prompt.js +21 -20
  176. package/dist/agent/system-prompt.js.map +1 -1
  177. package/dist/agent/tool-usage.d.ts.map +1 -1
  178. package/dist/agent/tool-usage.js +0 -1
  179. package/dist/agent/tool-usage.js.map +1 -1
  180. package/dist/agent/transcript/transcript-backfill.js +3 -3
  181. package/dist/agent/transcript/transcript-backfill.js.map +1 -1
  182. package/dist/agent/transcript/transcript-indexer.d.ts +3 -31
  183. package/dist/agent/transcript/transcript-indexer.d.ts.map +1 -1
  184. package/dist/agent/transcript/transcript-indexer.js +58 -57
  185. package/dist/agent/transcript/transcript-indexer.js.map +1 -1
  186. package/dist/agent/transcript-parsers/trivial-tools.d.ts.map +1 -1
  187. package/dist/agent/transcript-parsers/trivial-tools.js +0 -2
  188. package/dist/agent/transcript-parsers/trivial-tools.js.map +1 -1
  189. package/dist/agent/transcript-parsers/types.d.ts +1 -1
  190. package/dist/agent/transcript-summarizer.d.ts +14 -0
  191. package/dist/agent/transcript-summarizer.d.ts.map +1 -1
  192. package/dist/agent/transcript-summarizer.js +69 -45
  193. package/dist/agent/transcript-summarizer.js.map +1 -1
  194. package/dist/agent/usage/usage-report-queue.d.ts.map +1 -1
  195. package/dist/agent/usage/usage-report-queue.js +53 -52
  196. package/dist/agent/usage/usage-report-queue.js.map +1 -1
  197. package/dist/agent/usage/usage-report-types.d.ts +1 -1
  198. package/dist/agent/usage/usage-report-types.d.ts.map +1 -1
  199. package/dist/agent/vocabulary-glossary.d.ts +3 -3
  200. package/dist/agent/wake-cycle-runner.d.ts +14 -17
  201. package/dist/agent/wake-cycle-runner.d.ts.map +1 -1
  202. package/dist/agent/wake-cycle-runner.js +121 -290
  203. package/dist/agent/wake-cycle-runner.js.map +1 -1
  204. package/dist/builtin-skills/owner-manual/SKILL.md +2 -2
  205. package/dist/calendar/occurrence-ownership.d.ts.map +1 -1
  206. package/dist/calendar/occurrence-ownership.js +6 -5
  207. package/dist/calendar/occurrence-ownership.js.map +1 -1
  208. package/dist/calendar/scheduler.d.ts.map +1 -1
  209. package/dist/calendar/scheduler.js +4 -3
  210. package/dist/calendar/scheduler.js.map +1 -1
  211. package/dist/channels/interface.d.ts +8 -2
  212. package/dist/channels/interface.d.ts.map +1 -1
  213. package/dist/channels/interface.js +8 -1
  214. package/dist/channels/interface.js.map +1 -1
  215. package/dist/channels/manager.d.ts.map +1 -1
  216. package/dist/channels/manager.js +5 -1
  217. package/dist/channels/manager.js.map +1 -1
  218. package/dist/channels/queue.d.ts.map +1 -1
  219. package/dist/channels/queue.js +8 -0
  220. package/dist/channels/queue.js.map +1 -1
  221. package/dist/channels/tui.d.ts +14 -1
  222. package/dist/channels/tui.d.ts.map +1 -1
  223. package/dist/channels/tui.js +64 -2
  224. package/dist/channels/tui.js.map +1 -1
  225. package/dist/cli/index.d.ts +2 -2
  226. package/dist/cli/index.d.ts.map +1 -1
  227. package/dist/cli/index.js +22 -53
  228. package/dist/cli/index.js.map +1 -1
  229. package/dist/config/index.d.ts +13 -7
  230. package/dist/config/index.d.ts.map +1 -1
  231. package/dist/config/index.js +51 -64
  232. package/dist/config/index.js.map +1 -1
  233. package/dist/config/types.d.ts +28 -7
  234. package/dist/config/types.d.ts.map +1 -1
  235. package/dist/config/types.js +22 -20
  236. package/dist/config/types.js.map +1 -1
  237. package/dist/conversations/lazy-runtime.d.ts +5 -0
  238. package/dist/conversations/lazy-runtime.d.ts.map +1 -0
  239. package/dist/conversations/lazy-runtime.js +12 -0
  240. package/dist/conversations/lazy-runtime.js.map +1 -0
  241. package/dist/conversations/runtime.d.ts +17 -0
  242. package/dist/conversations/runtime.d.ts.map +1 -0
  243. package/dist/conversations/runtime.js +92 -0
  244. package/dist/conversations/runtime.js.map +1 -0
  245. package/dist/conversations/scheduler.d.ts +57 -0
  246. package/dist/conversations/scheduler.d.ts.map +1 -0
  247. package/dist/conversations/scheduler.js +175 -0
  248. package/dist/conversations/scheduler.js.map +1 -0
  249. package/dist/data-processing/pipeline.d.ts +0 -2
  250. package/dist/data-processing/pipeline.d.ts.map +1 -1
  251. package/dist/data-processing/pipeline.js +19 -24
  252. package/dist/data-processing/pipeline.js.map +1 -1
  253. package/dist/data-processing/restructure.d.ts +0 -2
  254. package/dist/data-processing/restructure.d.ts.map +1 -1
  255. package/dist/data-processing/restructure.js +6 -9
  256. package/dist/data-processing/restructure.js.map +1 -1
  257. package/dist/data-processing/types.d.ts +2 -9
  258. package/dist/data-processing/types.d.ts.map +1 -1
  259. package/dist/data-processing/types.js +2 -13
  260. package/dist/data-processing/types.js.map +1 -1
  261. package/dist/email/email-route-store.d.ts.map +1 -1
  262. package/dist/email/email-route-store.js +6 -5
  263. package/dist/email/email-route-store.js.map +1 -1
  264. package/dist/i18n/messages.d.ts +26 -2
  265. package/dist/i18n/messages.d.ts.map +1 -1
  266. package/dist/i18n/messages.js +30 -5
  267. package/dist/i18n/messages.js.map +1 -1
  268. package/dist/index.js.map +1 -1
  269. package/dist/logger.d.ts +11 -0
  270. package/dist/logger.d.ts.map +1 -1
  271. package/dist/logger.js +49 -1
  272. package/dist/logger.js.map +1 -1
  273. package/dist/obs/mini-app/status.d.ts.map +1 -1
  274. package/dist/obs/mini-app/status.js +0 -1
  275. package/dist/obs/mini-app/status.js.map +1 -1
  276. package/dist/onboarding/onboarding-service-client.d.ts +1 -0
  277. package/dist/onboarding/onboarding-service-client.d.ts.map +1 -1
  278. package/dist/onboarding/onboarding-service-client.js.map +1 -1
  279. package/dist/onboarding/remote-set-owner.d.ts.map +1 -1
  280. package/dist/onboarding/remote-set-owner.js +0 -1
  281. package/dist/onboarding/remote-set-owner.js.map +1 -1
  282. package/dist/onboarding/set-owner.d.ts +1 -1
  283. package/dist/onboarding/set-owner.d.ts.map +1 -1
  284. package/dist/onboarding/set-owner.js +3 -6
  285. package/dist/onboarding/set-owner.js.map +1 -1
  286. package/dist/reconfigure.d.ts.map +1 -1
  287. package/dist/reconfigure.js +1 -32
  288. package/dist/reconfigure.js.map +1 -1
  289. package/dist/reset.d.ts.map +1 -1
  290. package/dist/reset.js +3 -1
  291. package/dist/reset.js.map +1 -1
  292. package/dist/threads/active-threads-store.d.ts.map +1 -1
  293. package/dist/threads/active-threads-store.js +8 -27
  294. package/dist/threads/active-threads-store.js.map +1 -1
  295. package/dist/threads/dreaming-execution.d.ts +10 -0
  296. package/dist/threads/dreaming-execution.d.ts.map +1 -0
  297. package/dist/threads/dreaming-execution.js +78 -0
  298. package/dist/threads/dreaming-execution.js.map +1 -0
  299. package/dist/threads/execution-authority.d.ts +43 -0
  300. package/dist/threads/execution-authority.d.ts.map +1 -0
  301. package/dist/threads/execution-authority.js +75 -0
  302. package/dist/threads/execution-authority.js.map +1 -0
  303. package/dist/threads/execution-budget.d.ts +107 -0
  304. package/dist/threads/execution-budget.d.ts.map +1 -0
  305. package/dist/threads/execution-budget.js +257 -0
  306. package/dist/threads/execution-budget.js.map +1 -0
  307. package/dist/threads/execution-host.d.ts +17 -0
  308. package/dist/threads/execution-host.d.ts.map +1 -0
  309. package/dist/threads/execution-host.js +66 -0
  310. package/dist/threads/execution-host.js.map +1 -0
  311. package/dist/threads/execution-scheduler.d.ts +162 -0
  312. package/dist/threads/execution-scheduler.d.ts.map +1 -0
  313. package/dist/threads/execution-scheduler.js +413 -0
  314. package/dist/threads/execution-scheduler.js.map +1 -0
  315. package/dist/threads/execution-snapshot.d.ts +91 -0
  316. package/dist/threads/execution-snapshot.d.ts.map +1 -0
  317. package/dist/threads/execution-snapshot.js +146 -0
  318. package/dist/threads/execution-snapshot.js.map +1 -0
  319. package/dist/threads/execution-store.d.ts +374 -0
  320. package/dist/threads/execution-store.d.ts.map +1 -0
  321. package/dist/threads/execution-store.js +910 -0
  322. package/dist/threads/execution-store.js.map +1 -0
  323. package/dist/threads/execution-thread-error.d.ts +9 -0
  324. package/dist/threads/execution-thread-error.d.ts.map +1 -0
  325. package/dist/threads/execution-thread-error.js +12 -0
  326. package/dist/threads/execution-thread-error.js.map +1 -0
  327. package/dist/threads/executor-exit.d.ts +18 -0
  328. package/dist/threads/executor-exit.d.ts.map +1 -0
  329. package/dist/threads/executor-exit.js +21 -0
  330. package/dist/threads/executor-exit.js.map +1 -0
  331. package/dist/threads/foreground-task.d.ts +91 -0
  332. package/dist/threads/foreground-task.d.ts.map +1 -0
  333. package/dist/threads/foreground-task.js +191 -0
  334. package/dist/threads/foreground-task.js.map +1 -0
  335. package/dist/threads/foreman-business.d.ts +9 -0
  336. package/dist/threads/foreman-business.d.ts.map +1 -0
  337. package/dist/threads/foreman-business.js +117 -0
  338. package/dist/threads/foreman-business.js.map +1 -0
  339. package/dist/threads/foreman-client.d.ts +18 -0
  340. package/dist/threads/foreman-client.d.ts.map +1 -0
  341. package/dist/threads/foreman-client.js +51 -0
  342. package/dist/threads/foreman-client.js.map +1 -0
  343. package/dist/threads/foreman-delivery.d.ts +5 -0
  344. package/dist/threads/foreman-delivery.d.ts.map +1 -0
  345. package/dist/threads/foreman-delivery.js +21 -0
  346. package/dist/threads/foreman-delivery.js.map +1 -0
  347. package/dist/threads/foreman-execution.d.ts +32 -0
  348. package/dist/threads/foreman-execution.d.ts.map +1 -0
  349. package/dist/threads/foreman-execution.js +90 -0
  350. package/dist/threads/foreman-execution.js.map +1 -0
  351. package/dist/threads/foreman-host.d.ts +77 -0
  352. package/dist/threads/foreman-host.d.ts.map +1 -0
  353. package/dist/threads/foreman-host.js +891 -0
  354. package/dist/threads/foreman-host.js.map +1 -0
  355. package/dist/threads/foreman-protocol.d.ts +242 -0
  356. package/dist/threads/foreman-protocol.d.ts.map +1 -0
  357. package/dist/threads/foreman-protocol.js +116 -0
  358. package/dist/threads/foreman-protocol.js.map +1 -0
  359. package/dist/threads/foreman-store.d.ts +151 -0
  360. package/dist/threads/foreman-store.d.ts.map +1 -0
  361. package/dist/threads/foreman-store.js +299 -0
  362. package/dist/threads/foreman-store.js.map +1 -0
  363. package/dist/threads/generic-execution.d.ts +25 -0
  364. package/dist/threads/generic-execution.d.ts.map +1 -0
  365. package/dist/threads/generic-execution.js +86 -0
  366. package/dist/threads/generic-execution.js.map +1 -0
  367. package/dist/threads/init-thread-dir.d.ts +2 -2
  368. package/dist/threads/init-thread-dir.d.ts.map +1 -1
  369. package/dist/threads/init-thread-dir.js +6 -6
  370. package/dist/threads/init-thread-dir.js.map +1 -1
  371. package/dist/threads/ipc.d.ts +108 -2
  372. package/dist/threads/ipc.d.ts.map +1 -1
  373. package/dist/threads/ipc.js +14 -2
  374. package/dist/threads/ipc.js.map +1 -1
  375. package/dist/threads/lab-run-thread.d.ts +3 -5
  376. package/dist/threads/lab-run-thread.d.ts.map +1 -1
  377. package/dist/threads/lab-run-thread.js +3 -5
  378. package/dist/threads/lab-run-thread.js.map +1 -1
  379. package/dist/threads/lab-runtime-policy.d.ts +26 -21
  380. package/dist/threads/lab-runtime-policy.d.ts.map +1 -1
  381. package/dist/threads/lab-runtime-policy.js +31 -126
  382. package/dist/threads/lab-runtime-policy.js.map +1 -1
  383. package/dist/threads/process-group.d.ts +41 -0
  384. package/dist/threads/process-group.d.ts.map +1 -0
  385. package/dist/threads/process-group.js +161 -0
  386. package/dist/threads/process-group.js.map +1 -0
  387. package/dist/threads/relay-adapter.d.ts +8 -0
  388. package/dist/threads/relay-adapter.d.ts.map +1 -1
  389. package/dist/threads/relay-adapter.js +26 -1
  390. package/dist/threads/relay-adapter.js.map +1 -1
  391. package/dist/threads/supervisor.d.ts +191 -57
  392. package/dist/threads/supervisor.d.ts.map +1 -1
  393. package/dist/threads/supervisor.js +766 -427
  394. package/dist/threads/supervisor.js.map +1 -1
  395. package/dist/threads/task-workspace.d.ts +8 -0
  396. package/dist/threads/task-workspace.d.ts.map +1 -0
  397. package/dist/threads/task-workspace.js +52 -0
  398. package/dist/threads/task-workspace.js.map +1 -0
  399. package/dist/threads/worker-entry.d.ts.map +1 -1
  400. package/dist/threads/worker-entry.js +314 -34
  401. package/dist/threads/worker-entry.js.map +1 -1
  402. package/dist/threads/worker-execution-runtime.d.ts +75 -0
  403. package/dist/threads/worker-execution-runtime.d.ts.map +1 -0
  404. package/dist/threads/worker-execution-runtime.js +142 -0
  405. package/dist/threads/worker-execution-runtime.js.map +1 -0
  406. package/dist/threads/worker-execution.d.ts +35 -0
  407. package/dist/threads/worker-execution.d.ts.map +1 -0
  408. package/dist/threads/worker-execution.js +2 -0
  409. package/dist/threads/worker-execution.js.map +1 -0
  410. package/dist/threads/worker-runtime-policy.d.ts +42 -0
  411. package/dist/threads/worker-runtime-policy.d.ts.map +1 -0
  412. package/dist/threads/worker-runtime-policy.js +98 -0
  413. package/dist/threads/worker-runtime-policy.js.map +1 -0
  414. package/dist/tools/adapter-tool.d.ts +12 -0
  415. package/dist/tools/adapter-tool.d.ts.map +1 -0
  416. package/dist/tools/adapter-tool.js +2 -0
  417. package/dist/tools/adapter-tool.js.map +1 -0
  418. package/dist/tools/data-service.d.ts +2 -2
  419. package/dist/tools/delegation.d.ts +121 -0
  420. package/dist/tools/delegation.d.ts.map +1 -0
  421. package/dist/tools/delegation.js +106 -0
  422. package/dist/tools/delegation.js.map +1 -0
  423. package/dist/tools/dream-memory.d.ts +122 -0
  424. package/dist/tools/dream-memory.d.ts.map +1 -0
  425. package/dist/tools/dream-memory.js +513 -0
  426. package/dist/tools/dream-memory.js.map +1 -0
  427. package/dist/tools/email.d.ts +1 -1
  428. package/dist/tools/execution-control.d.ts +31 -0
  429. package/dist/tools/execution-control.d.ts.map +1 -0
  430. package/dist/tools/execution-control.js +71 -0
  431. package/dist/tools/execution-control.js.map +1 -0
  432. package/dist/tools/index.d.ts +5 -7
  433. package/dist/tools/index.d.ts.map +1 -1
  434. package/dist/tools/index.js +7 -13
  435. package/dist/tools/index.js.map +1 -1
  436. package/dist/tools/mcp-manager.d.ts +1 -1
  437. package/dist/tools/memory.d.ts +1 -1
  438. package/dist/tools/memory.d.ts.map +1 -1
  439. package/dist/tools/memory.js +69 -45
  440. package/dist/tools/memory.js.map +1 -1
  441. package/dist/tools/notify.d.ts +5 -0
  442. package/dist/tools/notify.d.ts.map +1 -1
  443. package/dist/tools/notify.js +45 -10
  444. package/dist/tools/notify.js.map +1 -1
  445. package/dist/tools/skill.d.ts +1 -1
  446. package/dist/tools/totp.d.ts +1 -1
  447. package/dist/tui/client.d.ts +1 -16
  448. package/dist/tui/client.d.ts.map +1 -1
  449. package/dist/tui/client.js +0 -4
  450. package/dist/tui/client.js.map +1 -1
  451. package/dist/tui/index.d.ts.map +1 -1
  452. package/dist/tui/index.js +0 -41
  453. package/dist/tui/index.js.map +1 -1
  454. package/dist/tui/protocol.d.ts +2 -1
  455. package/dist/tui/protocol.d.ts.map +1 -1
  456. package/dist/tui/protocol.js +2 -1
  457. package/dist/tui/protocol.js.map +1 -1
  458. package/dist/tui/renderer.d.ts.map +1 -1
  459. package/dist/tui/renderer.js +0 -5
  460. package/dist/tui/renderer.js.map +1 -1
  461. package/dist/tui/request-store.d.ts +1 -1
  462. package/dist/tui/request-store.d.ts.map +1 -1
  463. package/dist/tui/request-store.js +2 -2
  464. package/dist/tui/request-store.js.map +1 -1
  465. package/dist/tui/server.d.ts.map +1 -1
  466. package/dist/tui/server.js +137 -25
  467. package/dist/tui/server.js.map +1 -1
  468. package/dist/utils/claude-transcripts.d.ts +6 -0
  469. package/dist/utils/claude-transcripts.d.ts.map +1 -1
  470. package/dist/utils/claude-transcripts.js +8 -2
  471. package/dist/utils/claude-transcripts.js.map +1 -1
  472. package/dist/utils/restart.d.ts.map +1 -1
  473. package/dist/utils/restart.js +6 -0
  474. package/dist/utils/restart.js.map +1 -1
  475. package/dist-agent/bundle.cjs +2 -2
  476. package/package.json +1 -1
  477. package/dist/agent/mailbox.d.ts +0 -50
  478. package/dist/agent/mailbox.d.ts.map +0 -1
  479. package/dist/agent/mailbox.js +0 -124
  480. package/dist/agent/mailbox.js.map +0 -1
  481. package/dist/agent/nightly-maintenance/memory-dreaming-sweep.d.ts +0 -77
  482. package/dist/agent/nightly-maintenance/memory-dreaming-sweep.d.ts.map +0 -1
  483. package/dist/agent/nightly-maintenance/memory-dreaming-sweep.js +0 -158
  484. package/dist/agent/nightly-maintenance/memory-dreaming-sweep.js.map +0 -1
  485. package/dist/agent/nightly-maintenance/memory-dreaming.d.ts +0 -116
  486. package/dist/agent/nightly-maintenance/memory-dreaming.d.ts.map +0 -1
  487. package/dist/agent/nightly-maintenance/memory-dreaming.js +0 -458
  488. package/dist/agent/nightly-maintenance/memory-dreaming.js.map +0 -1
  489. package/dist/threads/task-contracts.d.ts +0 -194
  490. package/dist/threads/task-contracts.d.ts.map +0 -1
  491. package/dist/threads/task-contracts.js +0 -82
  492. package/dist/threads/task-contracts.js.map +0 -1
  493. package/dist/threads/task-sidecar.d.ts +0 -145
  494. package/dist/threads/task-sidecar.d.ts.map +0 -1
  495. package/dist/threads/task-sidecar.js +0 -311
  496. package/dist/threads/task-sidecar.js.map +0 -1
  497. package/dist/threads/task-store.d.ts +0 -172
  498. package/dist/threads/task-store.d.ts.map +0 -1
  499. package/dist/threads/task-store.js +0 -599
  500. package/dist/threads/task-store.js.map +0 -1
  501. package/dist/threads/thread-task-context.d.ts +0 -40
  502. package/dist/threads/thread-task-context.d.ts.map +0 -1
  503. package/dist/threads/thread-task-context.js +0 -160
  504. package/dist/threads/thread-task-context.js.map +0 -1
  505. package/dist/threads/thread-task-controller.d.ts +0 -122
  506. package/dist/threads/thread-task-controller.d.ts.map +0 -1
  507. package/dist/threads/thread-task-controller.js +0 -276
  508. package/dist/threads/thread-task-controller.js.map +0 -1
  509. package/dist/threads/thread-task-runtime.d.ts +0 -354
  510. package/dist/threads/thread-task-runtime.d.ts.map +0 -1
  511. package/dist/threads/thread-task-runtime.js +0 -917
  512. package/dist/threads/thread-task-runtime.js.map +0 -1
  513. package/dist/tools/switch-session.d.ts +0 -15
  514. package/dist/tools/switch-session.d.ts.map +0 -1
  515. package/dist/tools/switch-session.js +0 -88
  516. package/dist/tools/switch-session.js.map +0 -1
  517. package/dist/tools/thread-tasks.d.ts +0 -23
  518. package/dist/tools/thread-tasks.d.ts.map +0 -1
  519. package/dist/tools/thread-tasks.js +0 -122
  520. package/dist/tools/thread-tasks.js.map +0 -1
@@ -0,0 +1,910 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import { DatabaseSync } from "node:sqlite";
4
+ import path from "node:path";
5
+ import { z } from "zod";
6
+ import { getSharedProfileDir } from "../config/index.js";
7
+ import { logger } from "../logger.js";
8
+ /**
9
+ * Host-side record of internal executions: task protocol v1 (#2805 step 1c).
10
+ *
11
+ * This is the execution host's authoritative ledger. The TUI request store
12
+ * separately correlates a localhost request with SSE output. Callers (General, the Lab adapter, Nightly)
13
+ * submit commands; the host owns state transitions; the worker only reports.
14
+ *
15
+ * Two local atomic boundaries, each one SQLite transaction:
16
+ * 1. A submit stores the command, the execution record and its schedulable
17
+ * state together before `accepted` is returned.
18
+ * 2. A state change, its result or event, and the pending delivery to the
19
+ * caller are stored together before the caller is notified.
20
+ *
21
+ * Delivery to the caller is at-least-once: an outbox row stays until the
22
+ * caller acknowledges that the event reached its own durable queue. Consumers
23
+ * deduplicate by `eventId`. The event `seq` is a transport cursor, distinct
24
+ * from the per-execution `revision` used for concurrency control.
25
+ */
26
+ export const EXECUTION_PROTOCOL_VERSION = 1;
27
+ export const EXECUTION_STATES = [
28
+ "queued", "running", "waiting_input", "cancel_requested",
29
+ "succeeded", "failed", "cancelled",
30
+ ];
31
+ const TERMINAL_STATES = new Set(["succeeded", "failed", "cancelled"]);
32
+ export function isTerminalExecutionState(state) {
33
+ return TERMINAL_STATES.has(state);
34
+ }
35
+ /** A caller's internal recipient; never an arbitrary callback URL. */
36
+ export const ExecutionCallerSchema = z.object({
37
+ kind: z.enum(["general", "lab", "nightly", "tui"]),
38
+ /** Recipient reference inside that caller, e.g. a TUI requestId or thread id. */
39
+ ref: z.string().min(1).max(200),
40
+ }).strict();
41
+ export const CheckpointSchema = z.object({
42
+ done: z.array(z.string()).default([]),
43
+ remaining: z.array(z.string()).default([]),
44
+ decisions: z.array(z.string()).default([]),
45
+ blockers: z.array(z.string()).default([]),
46
+ artifactRefs: z.array(z.string()).default([]),
47
+ /** Operations whose outcome is unknown; verify before replaying any of them. */
48
+ uncertainOperations: z.array(z.string()).default([]),
49
+ }).strict();
50
+ export const SubmitPayloadSchema = z.object({
51
+ goal: z.string().min(1).max(20_000),
52
+ requirements: z.array(z.string().max(4_000)).max(64).default([]),
53
+ expectedOutput: z.string().max(4_000).optional(),
54
+ contextSummary: z.string().max(20_000).optional(),
55
+ inputRefs: z.array(z.string().max(512)).max(64).default([]),
56
+ checkpoint: CheckpointSchema.optional(),
57
+ /** Short owner-facing title, used only by the caller's delivery fallback. */
58
+ title: z.string().max(200).optional(),
59
+ /** Accounting carried over from a foreground attempt; never reset by a handoff. */
60
+ foregroundToolCallsUsed: z.number().int().nonnegative().default(0),
61
+ workspaceRef: z.string().max(1_024).optional(),
62
+ workspaceMode: z.enum(["read_only", "shared", "isolated"]).optional(),
63
+ /** Parent Task for shared scheduling; supplied by the trusted task service. */
64
+ parentTaskId: z.string().max(200).optional(),
65
+ preparedWorkspace: z.boolean().optional(),
66
+ /** Host-admitted workspace reads; has no authority for non-General callers. */
67
+ businessRead: z.boolean().optional(),
68
+ priorExecutionId: z.string().max(200).optional(),
69
+ /** Host-only retry identity: replaying the same chat message cannot retry twice. */
70
+ retryDispatchId: z.string().max(64).optional(),
71
+ retrySpecification: z.string().max(64).optional(),
72
+ }).strict();
73
+ export const EXECUTION_EVENT_TYPES = [
74
+ "accepted", "started", "progress", "question", "input_applied", "result", "stopped",
75
+ ];
76
+ export class ExecutionCommandConflictError extends Error {
77
+ constructor(message) {
78
+ super(message);
79
+ this.name = "ExecutionCommandConflictError";
80
+ }
81
+ }
82
+ export function executionStorePath() {
83
+ return path.join(getSharedProfileDir(), "executions.db");
84
+ }
85
+ function callerKey(caller, scope) {
86
+ return `${scope}\u0000${caller.kind}\u0000${caller.ref}`;
87
+ }
88
+ function stableStringify(value) {
89
+ if (Array.isArray(value))
90
+ return `[${value.map((item) => stableStringify(item)).join(",")}]`;
91
+ if (value && typeof value === "object") {
92
+ return `{${Object.entries(value)
93
+ .filter(([, item]) => item !== undefined)
94
+ .sort(([a], [b]) => a.localeCompare(b))
95
+ .map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`)
96
+ .join(",")}}`;
97
+ }
98
+ return JSON.stringify(value);
99
+ }
100
+ /** Digest of authenticated ownership, command type, target and normalized content. */
101
+ function commandDigest(envelope, type, target, content) {
102
+ return createHash("sha256").update(stableStringify({
103
+ scope: envelope.scope, caller: envelope.caller, type, target, content,
104
+ })).digest("hex");
105
+ }
106
+ /**
107
+ * Results quote memory and conversation until they are redacted, so the
108
+ * database is owner-only. SQLite gives the WAL and shm files the database
109
+ * file's mode; files left by an older version are tightened here too.
110
+ */
111
+ function restrictToOwner(dbPath) {
112
+ fs.closeSync(fs.openSync(dbPath, "a", 0o600));
113
+ for (const file of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
114
+ try {
115
+ fs.chmodSync(file, 0o600);
116
+ }
117
+ catch (error) {
118
+ // Not fatal: the store still works, only less private.
119
+ if (error.code !== "ENOENT")
120
+ logger.warn(`[execution] Could not restrict ${path.basename(file)} to its owner`);
121
+ }
122
+ }
123
+ }
124
+ export class ExecutionStore {
125
+ now;
126
+ transactionDepth = 0;
127
+ db;
128
+ statements;
129
+ closed = false;
130
+ eventListeners = new Set();
131
+ /** Events appended inside the open transaction; published only after COMMIT. */
132
+ uncommittedEvents = [];
133
+ constructor(dbPath = executionStorePath(), now = () => new Date()) {
134
+ this.now = now;
135
+ // The supervisor can start before anything else has created the profile directory.
136
+ fs.mkdirSync(path.dirname(dbPath), { recursive: true });
137
+ if (dbPath !== ":memory:")
138
+ restrictToOwner(dbPath);
139
+ this.db = new DatabaseSync(dbPath);
140
+ this.db.exec("PRAGMA journal_mode = WAL");
141
+ // Redacted results (see redactResultContent) must not linger in free pages.
142
+ this.db.exec("PRAGMA secure_delete = ON");
143
+ this.db.exec("PRAGMA busy_timeout = 5000");
144
+ this.db.exec("PRAGMA foreign_keys = ON");
145
+ this.db.exec(`
146
+ CREATE TABLE IF NOT EXISTS executions (
147
+ execution_id TEXT PRIMARY KEY,
148
+ task_id TEXT NOT NULL,
149
+ scope TEXT NOT NULL,
150
+ caller TEXT NOT NULL,
151
+ state TEXT NOT NULL,
152
+ revision INTEGER NOT NULL,
153
+ input_seq INTEGER NOT NULL DEFAULT 0,
154
+ processed_input_seq INTEGER NOT NULL DEFAULT 0,
155
+ worker_instance_id INTEGER NOT NULL DEFAULT 0,
156
+ auto_resume_count INTEGER NOT NULL DEFAULT 0,
157
+ payload TEXT NOT NULL,
158
+ snapshot TEXT NOT NULL,
159
+ open_question_id TEXT,
160
+ result TEXT,
161
+ created_at TEXT NOT NULL,
162
+ updated_at TEXT NOT NULL,
163
+ queued_at TEXT NOT NULL,
164
+ started_at TEXT,
165
+ cancel_requested_at TEXT,
166
+ stopped_at TEXT
167
+ );
168
+ CREATE INDEX IF NOT EXISTS executions_task_idx ON executions(task_id, created_at);
169
+ CREATE INDEX IF NOT EXISTS executions_state_idx ON executions(state, queued_at);
170
+ CREATE TABLE IF NOT EXISTS execution_commands (
171
+ caller_key TEXT NOT NULL,
172
+ command_id TEXT NOT NULL,
173
+ digest TEXT NOT NULL,
174
+ response TEXT NOT NULL,
175
+ created_at TEXT NOT NULL,
176
+ PRIMARY KEY (caller_key, command_id)
177
+ );
178
+ CREATE TABLE IF NOT EXISTS execution_inputs (
179
+ execution_id TEXT NOT NULL REFERENCES executions(execution_id),
180
+ input_seq INTEGER NOT NULL,
181
+ command_id TEXT NOT NULL,
182
+ question_id TEXT,
183
+ text TEXT NOT NULL,
184
+ created_at TEXT NOT NULL,
185
+ PRIMARY KEY (execution_id, input_seq)
186
+ );
187
+ CREATE TABLE IF NOT EXISTS execution_events (
188
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
189
+ event_id TEXT NOT NULL UNIQUE,
190
+ task_id TEXT NOT NULL,
191
+ execution_id TEXT NOT NULL REFERENCES executions(execution_id),
192
+ type TEXT NOT NULL,
193
+ command_id TEXT,
194
+ created_at TEXT NOT NULL,
195
+ payload TEXT NOT NULL
196
+ );
197
+ CREATE INDEX IF NOT EXISTS execution_events_execution_idx ON execution_events(execution_id, seq);
198
+ CREATE TABLE IF NOT EXISTS execution_outbox (
199
+ event_id TEXT PRIMARY KEY REFERENCES execution_events(event_id),
200
+ caller TEXT NOT NULL,
201
+ attempts INTEGER NOT NULL DEFAULT 0,
202
+ next_attempt_at TEXT NOT NULL,
203
+ created_at TEXT NOT NULL
204
+ );
205
+ CREATE TABLE IF NOT EXISTS execution_tool_calls (
206
+ execution_id TEXT NOT NULL REFERENCES executions(execution_id),
207
+ call_id TEXT NOT NULL,
208
+ tool_name TEXT NOT NULL,
209
+ started_at TEXT NOT NULL,
210
+ finished_at TEXT,
211
+ PRIMARY KEY (execution_id, call_id)
212
+ );
213
+ CREATE TABLE IF NOT EXISTS execution_processes (
214
+ execution_id TEXT PRIMARY KEY REFERENCES executions(execution_id),
215
+ pid INTEGER NOT NULL,
216
+ process_start TEXT NOT NULL,
217
+ worker_instance_id INTEGER NOT NULL
218
+ );
219
+ CREATE TABLE IF NOT EXISTS execution_usage (
220
+ execution_id TEXT PRIMARY KEY REFERENCES executions(execution_id),
221
+ usage TEXT NOT NULL
222
+ );
223
+ `);
224
+ const prepare = (sql) => this.db.prepare(sql);
225
+ this.statements = {
226
+ getExecution: prepare("SELECT * FROM executions WHERE execution_id = ?"),
227
+ activeForTask: prepare(`SELECT * FROM executions WHERE task_id = ? AND scope = ?
228
+ AND state IN ('queued','running','waiting_input','cancel_requested') ORDER BY created_at LIMIT 1`),
229
+ latestForTask: prepare("SELECT * FROM executions WHERE task_id = ? AND scope = ? ORDER BY created_at DESC, rowid DESC LIMIT 1"),
230
+ byState: prepare("SELECT * FROM executions WHERE state = ? ORDER BY queued_at, rowid"),
231
+ insertExecution: prepare(`INSERT INTO executions (
232
+ execution_id, task_id, scope, caller, state, revision, payload, snapshot,
233
+ created_at, updated_at, queued_at
234
+ ) VALUES (?, ?, ?, ?, 'queued', 1, ?, ?, ?, ?, ?)`),
235
+ getCommand: prepare("SELECT * FROM execution_commands WHERE caller_key = ? AND command_id = ?"),
236
+ insertCommand: prepare(`INSERT INTO execution_commands (caller_key, command_id, digest, response, created_at)
237
+ VALUES (?, ?, ?, ?, ?)`),
238
+ insertInput: prepare(`INSERT INTO execution_inputs (execution_id, input_seq, command_id, question_id, text, created_at)
239
+ VALUES (?, ?, ?, ?, ?, ?)`),
240
+ inputsAfter: prepare("SELECT * FROM execution_inputs WHERE execution_id = ? AND input_seq > ? ORDER BY input_seq"),
241
+ insertEvent: prepare(`INSERT INTO execution_events (event_id, task_id, execution_id, type, command_id, created_at, payload)
242
+ VALUES (?, ?, ?, ?, ?, ?, ?)`),
243
+ getEventBySeq: prepare("SELECT * FROM execution_events WHERE seq = ?"),
244
+ resultEvents: prepare("SELECT event_id, payload FROM execution_events WHERE execution_id = ? AND type = 'result'"),
245
+ setEventPayload: prepare("UPDATE execution_events SET payload = ? WHERE event_id = ?"),
246
+ eventsAfter: prepare("SELECT * FROM execution_events WHERE execution_id = ? AND seq > ? ORDER BY seq LIMIT 500"),
247
+ insertOutbox: prepare(`INSERT INTO execution_outbox (event_id, caller, next_attempt_at, created_at) VALUES (?, ?, ?, ?)`),
248
+ dueOutbox: prepare(`SELECT e.*, o.caller AS outbox_caller, o.attempts AS outbox_attempts FROM execution_outbox o
249
+ JOIN execution_events e ON e.event_id = o.event_id WHERE o.next_attempt_at <= ? ORDER BY e.seq LIMIT ?`),
250
+ ackOutbox: prepare("DELETE FROM execution_outbox WHERE event_id = ?"),
251
+ deferOutbox: prepare("UPDATE execution_outbox SET attempts = attempts + 1, next_attempt_at = ? WHERE event_id = ?"),
252
+ rescheduleOutbox: prepare("UPDATE execution_outbox SET next_attempt_at = ?"),
253
+ toolStarted: prepare(`INSERT OR IGNORE INTO execution_tool_calls (execution_id, call_id, tool_name, started_at) VALUES (?, ?, ?, ?)`),
254
+ toolFinished: prepare("UPDATE execution_tool_calls SET finished_at = ? WHERE execution_id = ? AND call_id = ? AND finished_at IS NULL"),
255
+ unfinishedTools: prepare("SELECT tool_name, call_id FROM execution_tool_calls WHERE execution_id = ? AND finished_at IS NULL ORDER BY started_at"),
256
+ upsertProcess: prepare(`INSERT INTO execution_processes (execution_id, pid, process_start, worker_instance_id) VALUES (?, ?, ?, ?)
257
+ ON CONFLICT(execution_id) DO UPDATE SET pid = excluded.pid, process_start = excluded.process_start, worker_instance_id = excluded.worker_instance_id`),
258
+ getProcess: prepare("SELECT * FROM execution_processes WHERE execution_id = ?"),
259
+ clearProcess: prepare("DELETE FROM execution_processes WHERE execution_id = ?"),
260
+ taskOwner: prepare("SELECT scope, caller FROM executions WHERE task_id = ? ORDER BY created_at, rowid LIMIT 1"),
261
+ liveWriter: prepare(`SELECT 1 AS found FROM executions e
262
+ WHERE json_extract(e.payload, '$.workspaceRef') = ? AND e.execution_id != ?
263
+ AND (? = 0 OR COALESCE(json_extract(e.payload, '$.workspaceMode'), 'shared') != 'read_only')
264
+ AND (e.state IN ('running','cancel_requested')
265
+ OR EXISTS (SELECT 1 FROM execution_processes p WHERE p.execution_id = e.execution_id))
266
+ LIMIT 1`),
267
+ getUsage: prepare("SELECT usage FROM execution_usage WHERE execution_id = ?"),
268
+ liveExecutions: prepare("SELECT e.* FROM executions e JOIN execution_processes p ON p.execution_id = e.execution_id"),
269
+ attemptsForTask: prepare("SELECT * FROM executions WHERE task_id = ? AND scope = ? ORDER BY created_at, rowid"),
270
+ putUsage: prepare(`INSERT INTO execution_usage (execution_id, usage) VALUES (?, ?)
271
+ ON CONFLICT(execution_id) DO UPDATE SET usage = excluded.usage`),
272
+ };
273
+ }
274
+ // ------------------------------------------------------------- commands
275
+ /**
276
+ * Accept a submit. A replay of the same commandId and content returns the
277
+ * original acceptance; the same key with other content is a conflict.
278
+ * A task that already has a live attempt is never given a second one.
279
+ */
280
+ submit(envelope, input) {
281
+ const payload = SubmitPayloadSchema.parse(input.payload);
282
+ return this.command(envelope, "submit", { taskId: input.taskId ?? null, retryOf: input.retryOf ?? null }, payload, () => {
283
+ const taskId = input.taskId ?? `task-${randomUUID()}`;
284
+ if (input.taskId && !this.ownsTask(input.taskId, envelope)) {
285
+ // A taskId belongs to the caller that first used it; nobody else may
286
+ // attach an attempt to it, even inside the same scope.
287
+ return { kind: "stale", reason: "task_not_owned", record: null };
288
+ }
289
+ const live = this.row(this.statements.activeForTask.get(taskId, envelope.scope));
290
+ if (live) {
291
+ return { kind: "stale", reason: "task_has_live_execution", record: this.toRecord(live) };
292
+ }
293
+ if (input.retryOf) {
294
+ const previous = this.row(this.statements.getExecution.get(input.retryOf));
295
+ if (previous?.task_id !== taskId || previous.scope !== envelope.scope) {
296
+ return { kind: "stale", reason: "retry_target_not_found", record: null };
297
+ }
298
+ if (!isTerminalExecutionState(previous.state)) {
299
+ return { kind: "stale", reason: "retry_target_not_terminal", record: this.toRecord(previous) };
300
+ }
301
+ }
302
+ const executionId = input.executionId ?? `exec-${randomUUID()}`;
303
+ const at = this.timestamp();
304
+ this.statements.insertExecution.run(executionId, taskId, envelope.scope, JSON.stringify(envelope.caller), JSON.stringify(payload), input.snapshot, at, at, at);
305
+ let revision = 1;
306
+ if (input.retryOf) {
307
+ const previousInputs = this.pendingInputs(input.retryOf, 0);
308
+ for (const accepted of previousInputs)
309
+ this.statements.insertInput.run(executionId, accepted.inputSeq, accepted.commandId, accepted.questionId, accepted.text, accepted.createdAt);
310
+ const last = previousInputs.at(-1);
311
+ if (last)
312
+ revision = this.update(this.mustGetRow(executionId), { input_seq: last.inputSeq });
313
+ }
314
+ this.appendEvent(executionId, "accepted", envelope.commandId, { state: "queued", revision });
315
+ const value = { accepted: true, taskId, executionId, state: "queued", revision };
316
+ return { kind: "ok", replay: false, value };
317
+ });
318
+ }
319
+ /**
320
+ * Record an execution the host admits and starts in one step (#2805 1d):
321
+ * a LabRun keeps its own Fin-App lease and capacity contract, so it never
322
+ * sits in this queue. Idempotent on `executionId`; a second admission of the
323
+ * same id returns the existing record instead of creating a new attempt.
324
+ */
325
+ admitAndStart(input) {
326
+ const payload = SubmitPayloadSchema.parse(input.payload);
327
+ ExecutionCallerSchema.parse(input.caller);
328
+ return this.transaction(() => {
329
+ const existing = this.row(this.statements.getExecution.get(input.executionId));
330
+ if (existing) {
331
+ if (existing.state === "queued") {
332
+ const generation = existing.worker_instance_id + 1;
333
+ this.update(existing, { state: "running", worker_instance_id: generation, started_at: existing.started_at ?? this.timestamp() });
334
+ this.statements.upsertProcess.run(input.executionId, input.process.pid, input.process.processStart, generation);
335
+ this.appendEvent(input.executionId, "started", null, { workerInstanceId: generation });
336
+ }
337
+ return this.mustGet(input.executionId);
338
+ }
339
+ const at = this.timestamp();
340
+ this.statements.insertExecution.run(input.executionId, input.taskId, input.scope, JSON.stringify(input.caller), JSON.stringify(payload), input.snapshot, at, at, at);
341
+ this.appendEvent(input.executionId, "accepted", null, { state: "queued", revision: 1 });
342
+ this.update(this.mustGetRow(input.executionId), { state: "running", worker_instance_id: 1, started_at: at });
343
+ this.statements.upsertProcess.run(input.executionId, input.process.pid, input.process.processStart, 1);
344
+ this.appendEvent(input.executionId, "started", null, { workerInstanceId: 1 });
345
+ return this.mustGet(input.executionId);
346
+ });
347
+ }
348
+ /**
349
+ * Host-initiated cancel for an execution whose caller is an external
350
+ * protocol (Fin-App cancel, lease loss). Same state rules as `cancel`.
351
+ */
352
+ requestHostCancel(executionId, reason) {
353
+ return this.transaction(() => {
354
+ const row = this.row(this.statements.getExecution.get(executionId));
355
+ if (!row || isTerminalExecutionState(row.state) || row.state === "cancel_requested") {
356
+ return row ? this.toRecord(row) : null;
357
+ }
358
+ this.update(row, { state: "cancel_requested", cancel_requested_at: this.timestamp() });
359
+ this.appendEvent(executionId, "progress", null, { cancelRequested: true, reason: reason.slice(0, 500) });
360
+ return this.mustGet(executionId);
361
+ });
362
+ }
363
+ /** Store supplementary input. The worker reads it at its next injection boundary. */
364
+ sendInput(envelope, input) {
365
+ return this.command(envelope, "send_input", { executionId: input.executionId }, {
366
+ text: input.text, questionId: input.questionId ?? null,
367
+ }, () => {
368
+ const row = this.owned(input.executionId, envelope);
369
+ if (!row)
370
+ return { kind: "stale", reason: "execution_not_found", record: null };
371
+ if (isTerminalExecutionState(row.state) || row.state === "cancel_requested") {
372
+ return { kind: "stale", reason: "execution_not_accepting_input", record: this.toRecord(row) };
373
+ }
374
+ if (row.result !== null) {
375
+ // The result is committed and waits only for its executor to stop.
376
+ // New input cannot be applied to it; the caller decides what follows.
377
+ return { kind: "stale", reason: "result_pending_stop", record: this.toRecord(row) };
378
+ }
379
+ if (input.questionId !== undefined && input.questionId !== row.open_question_id) {
380
+ return { kind: "stale", reason: "question_not_open", record: this.toRecord(row) };
381
+ }
382
+ const inputSeq = row.input_seq + 1;
383
+ const at = this.timestamp();
384
+ this.statements.insertInput.run(row.execution_id, inputSeq, envelope.commandId, input.questionId ?? null, input.text, at);
385
+ const answering = input.questionId !== undefined;
386
+ // The answered execution resumes in a new executor. While the one that
387
+ // asked is still stopping, it stays waiting_input with the question
388
+ // closed; confirmStopped() queues it once that executor is gone.
389
+ const next = answering && !this.processOf(row.execution_id) ? "queued" : row.state;
390
+ const revision = this.update(row, {
391
+ input_seq: inputSeq,
392
+ ...(answering ? { open_question_id: null } : {}),
393
+ ...(next === "queued" ? { state: next, queued_at: at } : {}),
394
+ });
395
+ return { kind: "ok", replay: false, value: { inputSeq, state: next, revision } };
396
+ });
397
+ }
398
+ /**
399
+ * Record a cancel request. A queued execution has no executor yet and is
400
+ * cancelled immediately; anything running enters `cancel_requested` and only
401
+ * becomes `cancelled` once the host confirms the executor stopped.
402
+ */
403
+ cancel(envelope, input) {
404
+ return this.command(envelope, "cancel", { executionId: input.executionId }, {
405
+ reason: input.reason ?? null, userInitiated: input.userInitiated === true,
406
+ }, () => {
407
+ const row = this.owned(input.executionId, envelope);
408
+ if (!row)
409
+ return { kind: "stale", reason: "execution_not_found", record: null };
410
+ if (isTerminalExecutionState(row.state) || row.state === "cancel_requested") {
411
+ return { kind: "ok", replay: false, value: { state: row.state, revision: row.revision } };
412
+ }
413
+ const at = this.timestamp();
414
+ if (row.state === "queued" || (row.state === "waiting_input" && !this.processOf(row.execution_id))) {
415
+ const result = {
416
+ status: "cancelled", processedInputSeq: row.processed_input_seq,
417
+ ...(input.reason ? { error: { code: "cancelled", message: input.reason } } : {}),
418
+ };
419
+ const revision = this.update(row, { state: "cancelled", cancel_requested_at: at, result: JSON.stringify(result) });
420
+ this.appendEvent(row.execution_id, "result", envelope.commandId, {
421
+ ...result, userInitiated: input.userInitiated === true,
422
+ }, true);
423
+ return { kind: "ok", replay: false, value: { state: "cancelled", revision } };
424
+ }
425
+ const revision = this.update(row, { state: "cancel_requested", cancel_requested_at: at });
426
+ return { kind: "ok", replay: false, value: { state: "cancel_requested", revision } };
427
+ });
428
+ }
429
+ // ------------------------------------------------------ host transitions
430
+ get(executionId) {
431
+ const row = this.row(this.statements.getExecution.get(executionId));
432
+ return row ? this.toRecord(row) : null;
433
+ }
434
+ latestForTask(taskId, scope) {
435
+ const row = this.row(this.statements.latestForTask.get(taskId, scope));
436
+ return row ? this.toRecord(row) : null;
437
+ }
438
+ listByState(state) {
439
+ return this.statements.byState.all(state).map((row) => this.toRecord(row));
440
+ }
441
+ liveExecutions() {
442
+ return this.statements.liveExecutions.all().map((row) => this.toRecord(row));
443
+ }
444
+ attemptsForTask(taskId, scope) {
445
+ return this.statements.attemptsForTask.all(taskId, scope).map((row) => this.toRecord(row));
446
+ }
447
+ /** Atomic, synchronous admission of a set of Tasks. Events publish after commit. */
448
+ atomic(operation) {
449
+ return this.transaction(operation);
450
+ }
451
+ /**
452
+ * The host admitted the execution onto an executor. Never emits `started`
453
+ * from the queue; returns the new writer generation the worker must present.
454
+ */
455
+ markStarted(executionId, process) {
456
+ return this.transaction(() => {
457
+ const row = this.row(this.statements.getExecution.get(executionId));
458
+ if (row?.state !== "queued")
459
+ return null;
460
+ const generation = row.worker_instance_id + 1;
461
+ const at = this.timestamp();
462
+ this.update(row, { state: "running", worker_instance_id: generation, started_at: row.started_at ?? at });
463
+ this.statements.upsertProcess.run(executionId, process.pid, process.processStart, generation);
464
+ this.appendEvent(executionId, "started", null, { workerInstanceId: generation });
465
+ return this.get(executionId);
466
+ });
467
+ }
468
+ /** Record that the worker handed inputs up to `inputSeq` to its model context. */
469
+ markInputApplied(executionId, generation, inputSeq) {
470
+ return this.transaction(() => {
471
+ const row = this.current(executionId, generation);
472
+ if (!row || inputSeq <= row.processed_input_seq || inputSeq > row.input_seq)
473
+ return false;
474
+ this.update(row, { processed_input_seq: inputSeq });
475
+ this.appendEvent(executionId, "input_applied", null, { inputSeq });
476
+ return true;
477
+ });
478
+ }
479
+ pendingInputs(executionId, afterSeq) {
480
+ return this.statements.inputsAfter.all(executionId, afterSeq).map((row) => ({
481
+ executionId: row.execution_id, inputSeq: row.input_seq, commandId: row.command_id,
482
+ questionId: row.question_id, text: row.text, createdAt: row.created_at,
483
+ }));
484
+ }
485
+ recordProgress(executionId, generation, payload) {
486
+ return this.transaction(() => {
487
+ const row = this.current(executionId, generation);
488
+ if (row?.state !== "running")
489
+ return false;
490
+ this.appendEvent(executionId, "progress", null, payload, true);
491
+ return true;
492
+ });
493
+ }
494
+ /** The worker needs an answer. The question is durable; the executor may be released. */
495
+ askQuestion(executionId, generation, question) {
496
+ return this.transaction(() => {
497
+ const row = this.current(executionId, generation);
498
+ if (row?.state !== "running")
499
+ return null;
500
+ const questionId = `q-${randomUUID()}`;
501
+ this.update(row, { state: "waiting_input", open_question_id: questionId });
502
+ this.appendEvent(executionId, "question", null, { questionId, ...question }, true);
503
+ return questionId;
504
+ });
505
+ }
506
+ /**
507
+ * Commit a worker-reported terminal result. The result applies only if the
508
+ * reporter is the current generation and has processed every accepted
509
+ * input; a late report after a committed cancel request becomes `cancelled`
510
+ * while its artifacts are still recorded.
511
+ */
512
+ completeExecution(executionId, generation, report) {
513
+ return this.transaction(() => {
514
+ const row = this.row(this.statements.getExecution.get(executionId));
515
+ if (!row || isTerminalExecutionState(row.state))
516
+ return { rejected: "terminal" };
517
+ if (row.worker_instance_id !== generation)
518
+ return { rejected: "stale_writer" };
519
+ // A waiting (released) executor has nothing left to finish.
520
+ if (row.state !== "running" && row.state !== "cancel_requested")
521
+ return { rejected: "not_running" };
522
+ if (row.state !== "cancel_requested" && report.processedInputSeq < row.input_seq) {
523
+ return { rejected: "unprocessed_input", pendingInputSeq: row.input_seq };
524
+ }
525
+ const status = row.state === "cancel_requested" ? "cancelled" : report.status;
526
+ const result = { ...report, status };
527
+ // A terminal result needs a stopped executor before it is published; the
528
+ // host confirms that separately via confirmStopped().
529
+ this.update(row, { result: JSON.stringify(result) });
530
+ return { committed: row.state };
531
+ });
532
+ }
533
+ /**
534
+ * The host verified that the executor for this generation is stopped:
535
+ * its process exited or was killed and reaped. Only now may the record go
536
+ * terminal and the next writer be admitted.
537
+ */
538
+ confirmStopped(executionId, generation, fallback) {
539
+ return this.transaction(() => {
540
+ const row = this.row(this.statements.getExecution.get(executionId));
541
+ if (row?.worker_instance_id !== generation || isTerminalExecutionState(row.state))
542
+ return null;
543
+ // Already requeued for its next executor: a late confirmation changes nothing.
544
+ if (row.state === "queued")
545
+ return null;
546
+ const at = this.timestamp();
547
+ this.statements.clearProcess.run(executionId);
548
+ if (row.state === "waiting_input") {
549
+ // Released executor. An open question waits for its answer; an answer
550
+ // that arrived while this executor was stopping resumes it now.
551
+ const answered = row.open_question_id === null;
552
+ this.update(row, {
553
+ stopped_at: at,
554
+ ...(answered ? { state: "queued", queued_at: at } : {}),
555
+ });
556
+ this.appendEvent(executionId, "stopped", null, { workerInstanceId: generation, reason: "waiting_input" });
557
+ return this.get(executionId);
558
+ }
559
+ const reported = row.result ? JSON.parse(row.result) : null;
560
+ const result = this.withUsage(executionId, row.state === "cancel_requested"
561
+ ? { ...(reported ?? {}), status: "cancelled", processedInputSeq: reported?.processedInputSeq ?? row.processed_input_seq }
562
+ : reported ?? { status: fallback.status, error: fallback.error, processedInputSeq: row.processed_input_seq });
563
+ this.update(row, { state: result.status, result: JSON.stringify(result), stopped_at: at });
564
+ this.appendEvent(executionId, "stopped", null, { workerInstanceId: generation });
565
+ this.appendEvent(executionId, "result", null, { ...result }, true);
566
+ return this.get(executionId);
567
+ });
568
+ }
569
+ /**
570
+ * Drop a terminal execution's report content once its caller has applied
571
+ * it: `data`, `summary`, and error messages (codes stay). Used for
572
+ * maintenance executions, whose reports quote memory and conversation.
573
+ * Status, usage and every state transition are unchanged.
574
+ */
575
+ redactResultContent(executionId) {
576
+ const redact = (value) => {
577
+ const { data: _data, summary: _summary, error, ...rest } = value;
578
+ const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
579
+ return { ...rest, ...(typeof code === "string" ? { error: { code, message: "" } } : {}), redacted: true };
580
+ };
581
+ const redacted = this.transaction(() => {
582
+ const row = this.row(this.statements.getExecution.get(executionId));
583
+ if (!row || !isTerminalExecutionState(row.state) || !row.result)
584
+ return false;
585
+ this.update(row, { result: JSON.stringify(redact(JSON.parse(row.result))) });
586
+ for (const event of this.statements.resultEvents.all(executionId)) {
587
+ this.statements.setEventPayload.run(JSON.stringify(redact(JSON.parse(event.payload))), event.event_id);
588
+ }
589
+ return true;
590
+ });
591
+ // secure_delete does not reach the WAL: the frames that held the report
592
+ // stay in executions.db-wal until a checkpoint truncates it.
593
+ if (redacted)
594
+ this.truncateWal(executionId);
595
+ return redacted;
596
+ }
597
+ truncateWal(executionId) {
598
+ const outcome = this.db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
599
+ if (outcome?.busy) {
600
+ logger.warn(`[execution] WAL still holds redacted content of execution=${executionId}; a reader blocked the checkpoint`);
601
+ }
602
+ }
603
+ /**
604
+ * Put an interrupted running execution back in the queue under the same
605
+ * executionId. After `maxResumes` interruptions it fails instead, with the
606
+ * last interruption's cause in the error. A host restart is an
607
+ * interruption too (#2805: fail after 3 consecutive interruptions).
608
+ */
609
+ requeueForResume(executionId, generation, maxResumes, lastError) {
610
+ return this.transaction(() => {
611
+ const row = this.row(this.statements.getExecution.get(executionId));
612
+ if (row?.worker_instance_id !== generation || row.state !== "running")
613
+ return null;
614
+ this.statements.clearProcess.run(executionId);
615
+ if (row.auto_resume_count >= maxResumes) {
616
+ const detail = lastError ? `; last: ${lastError.slice(0, 300)}` : "";
617
+ const result = this.withUsage(executionId, {
618
+ status: "failed", processedInputSeq: row.processed_input_seq,
619
+ error: { code: "interrupted", message: `Execution was interrupted ${row.auto_resume_count + 1} times${detail}` },
620
+ ...(row.result ? { checkpoint: JSON.parse(row.result).checkpoint } : {}),
621
+ });
622
+ this.update(row, { state: "failed", result: JSON.stringify(result), stopped_at: this.timestamp() });
623
+ this.appendEvent(executionId, "stopped", null, { workerInstanceId: generation });
624
+ this.appendEvent(executionId, "result", null, { ...result }, true);
625
+ return this.get(executionId);
626
+ }
627
+ this.update(row, { state: "queued", auto_resume_count: row.auto_resume_count + 1, queued_at: this.timestamp() });
628
+ this.appendEvent(executionId, "stopped", null, { workerInstanceId: generation, reason: "resume" });
629
+ return this.get(executionId);
630
+ });
631
+ }
632
+ /**
633
+ * Fail an execution whose executor can never succeed, e.g. it was refused
634
+ * at startup. Retrying would only fail the same way again.
635
+ */
636
+ failPermanently(executionId, generation, error) {
637
+ return this.transaction(() => {
638
+ const row = this.row(this.statements.getExecution.get(executionId));
639
+ if (row?.worker_instance_id !== generation || isTerminalExecutionState(row.state))
640
+ return null;
641
+ const hadExecutor = this.processOf(executionId) !== null;
642
+ this.statements.clearProcess.run(executionId);
643
+ const status = row.state === "cancel_requested" ? "cancelled" : "failed";
644
+ const result = this.withUsage(executionId, { status, error, processedInputSeq: row.processed_input_seq });
645
+ this.update(row, { state: status, result: JSON.stringify(result), stopped_at: this.timestamp() });
646
+ if (hadExecutor)
647
+ this.appendEvent(executionId, "stopped", null, { workerInstanceId: generation });
648
+ this.appendEvent(executionId, "result", null, { ...result }, true);
649
+ return this.get(executionId);
650
+ });
651
+ }
652
+ /** A waiting execution was answered and requeued; resume with the next generation. */
653
+ processOf(executionId) {
654
+ const row = this.statements.getProcess.get(executionId);
655
+ return row ? { pid: row.pid, processStart: row.process_start, workerInstanceId: row.worker_instance_id } : null;
656
+ }
657
+ // ----------------------------------------------------------- usage ledger
658
+ /**
659
+ * Accumulated task budget usage, held by the host (#2805 1b). The worker
660
+ * reports it over IPC; a task cannot reset it by editing local files.
661
+ */
662
+ usageOf(executionId) {
663
+ const row = this.statements.getUsage.get(executionId);
664
+ return row ? JSON.parse(row.usage) : null;
665
+ }
666
+ /**
667
+ * Merge a worker's usage report. Counters only grow: a report lower than
668
+ * what the host already holds (a reset local file, a replayed old report)
669
+ * cannot give the task its budget back.
670
+ */
671
+ recordUsage(executionId, generation, usage) {
672
+ return this.transaction(() => {
673
+ if (!this.current(executionId, generation))
674
+ return false;
675
+ const previous = this.usageOf(executionId) ?? {};
676
+ const merged = { ...previous };
677
+ for (const [key, value] of Object.entries(usage)) {
678
+ const before = previous[key];
679
+ if (typeof value === "number" && typeof before === "number")
680
+ merged[key] = Math.max(before, value);
681
+ else if (before === undefined || before === null)
682
+ merged[key] = value;
683
+ }
684
+ this.statements.putUsage.run(executionId, JSON.stringify(merged));
685
+ return true;
686
+ });
687
+ }
688
+ /** A host-side fact the caller must see, e.g. an executor that cannot be proven stopped. */
689
+ recordHostNotice(executionId, payload) {
690
+ return this.transaction(() => {
691
+ const row = this.row(this.statements.getExecution.get(executionId));
692
+ if (!row || isTerminalExecutionState(row.state))
693
+ return false;
694
+ this.appendEvent(executionId, "progress", null, { ...payload, host: true }, true);
695
+ return true;
696
+ });
697
+ }
698
+ /**
699
+ * Whether another execution may still write to `workspaceRef`: it is
700
+ * running or stopping, or its executor has not been confirmed stopped.
701
+ */
702
+ hasLiveWriter(workspaceRef, exceptExecutionId, reader = false) {
703
+ const row = this.statements.liveWriter.get(workspaceRef, exceptExecutionId ?? "", reader ? 1 : 0);
704
+ return row !== undefined;
705
+ }
706
+ // ------------------------------------------------------- tool-call ledger
707
+ toolCallStarted(executionId, callId, toolName) {
708
+ this.statements.toolStarted.run(executionId, callId, toolName, this.timestamp());
709
+ }
710
+ toolCallFinished(executionId, callId) {
711
+ this.statements.toolFinished.run(this.timestamp(), executionId, callId);
712
+ }
713
+ /** Calls that started but never finished: outcome unknown, verify before replay. */
714
+ unfinishedToolCalls(executionId) {
715
+ return this.statements.unfinishedTools.all(executionId)
716
+ .map((row) => ({ toolName: row.tool_name, callId: row.call_id }));
717
+ }
718
+ // -------------------------------------------------------- events/outbox
719
+ eventsAfter(executionId, afterSeq) {
720
+ return this.statements.eventsAfter.all(executionId, afterSeq).map((row) => this.toEvent(row));
721
+ }
722
+ /** Events still owed to their callers. */
723
+ dueDeliveries(limit = 50) {
724
+ const rows = this.statements.dueOutbox.all(this.timestamp(), limit);
725
+ return rows.map((row) => ({
726
+ event: this.toEvent(row),
727
+ caller: JSON.parse(row.outbox_caller),
728
+ attempts: row.outbox_attempts,
729
+ }));
730
+ }
731
+ /** The caller confirmed the event is in its own durable queue. */
732
+ acknowledgeDelivery(eventId) {
733
+ this.statements.ackOutbox.run(eventId);
734
+ }
735
+ deferDelivery(eventId, retryAt) {
736
+ this.statements.deferOutbox.run(retryAt.toISOString(), eventId);
737
+ }
738
+ /** After a host restart the callers are back too: retry every owed delivery now. */
739
+ rescheduleOwedDeliveries() {
740
+ this.statements.rescheduleOutbox.run(this.timestamp());
741
+ }
742
+ /**
743
+ * Observe every committed event (live streams). Durable delivery to a
744
+ * caller still goes through the outbox; this is a best-effort live feed.
745
+ */
746
+ onEvent(listener) {
747
+ this.eventListeners.add(listener);
748
+ return () => this.eventListeners.delete(listener);
749
+ }
750
+ close() {
751
+ if (this.closed)
752
+ return;
753
+ this.closed = true;
754
+ this.db.close();
755
+ }
756
+ // -------------------------------------------------------------- helpers
757
+ command(envelope, type, target, content, apply) {
758
+ ExecutionCallerSchema.parse(envelope.caller);
759
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,199}$/.test(envelope.commandId))
760
+ throw new Error("Invalid commandId");
761
+ const key = callerKey(envelope.caller, envelope.scope);
762
+ const digest = commandDigest(envelope, type, target, content);
763
+ return this.transaction(() => {
764
+ const previous = this.statements.getCommand.get(key, envelope.commandId);
765
+ if (previous) {
766
+ if (previous.digest !== digest) {
767
+ throw new ExecutionCommandConflictError(`commandId ${envelope.commandId} was already used with different content`);
768
+ }
769
+ const replayed = JSON.parse(previous.response);
770
+ return replayed.kind === "ok" ? { ...replayed, replay: true } : replayed;
771
+ }
772
+ const outcome = apply();
773
+ this.statements.insertCommand.run(key, envelope.commandId, digest, JSON.stringify(outcome), this.timestamp());
774
+ return outcome;
775
+ });
776
+ }
777
+ /** A task id is owned by the scope and caller that first submitted it. */
778
+ ownsTask(taskId, envelope) {
779
+ const first = this.statements.taskOwner.get(taskId);
780
+ if (!first)
781
+ return true;
782
+ if (first.scope !== envelope.scope)
783
+ return false;
784
+ const owner = JSON.parse(first.caller);
785
+ return owner.kind === envelope.caller.kind && owner.ref === envelope.caller.ref;
786
+ }
787
+ owned(executionId, envelope) {
788
+ const row = this.row(this.statements.getExecution.get(executionId));
789
+ if (row?.scope !== envelope.scope)
790
+ return null;
791
+ const caller = JSON.parse(row.caller);
792
+ return caller.kind === envelope.caller.kind && caller.ref === envelope.caller.ref ? row : null;
793
+ }
794
+ current(executionId, generation) {
795
+ const row = this.row(this.statements.getExecution.get(executionId));
796
+ return row?.worker_instance_id === generation && !isTerminalExecutionState(row.state) ? row : null;
797
+ }
798
+ update(row, changes) {
799
+ const revision = row.revision + 1;
800
+ const entries = Object.entries({ ...changes, revision, updated_at: this.timestamp() });
801
+ const sql = `UPDATE executions SET ${entries.map(([key]) => `${key} = ?`).join(", ")}
802
+ WHERE execution_id = ? AND revision = ?`;
803
+ const result = this.db.prepare(sql).run(...entries.map(([, value]) => value), row.execution_id, row.revision);
804
+ if (result.changes !== 1)
805
+ throw new Error(`Execution ${row.execution_id} changed concurrently`);
806
+ return revision;
807
+ }
808
+ appendEvent(executionId, type, commandId, payload, deliver = type === "accepted") {
809
+ const row = this.row(this.statements.getExecution.get(executionId));
810
+ if (!row)
811
+ throw new Error(`Unknown execution ${executionId}`);
812
+ const eventId = `evt-${randomUUID()}`;
813
+ const at = this.timestamp();
814
+ const inserted = this.statements.insertEvent.run(eventId, row.task_id, executionId, type, commandId, at, JSON.stringify(payload));
815
+ if (deliver)
816
+ this.statements.insertOutbox.run(eventId, row.caller, at, at);
817
+ const event = this.toEvent(this.statements.getEventBySeq.get(Number(inserted.lastInsertRowid)));
818
+ this.uncommittedEvents.push({ event, caller: JSON.parse(row.caller) });
819
+ return event;
820
+ }
821
+ transaction(operation) {
822
+ if (this.transactionDepth > 0)
823
+ return operation();
824
+ this.db.exec("BEGIN IMMEDIATE");
825
+ this.transactionDepth += 1;
826
+ let value;
827
+ try {
828
+ value = operation();
829
+ this.db.exec("COMMIT");
830
+ }
831
+ catch (error) {
832
+ this.uncommittedEvents = [];
833
+ this.db.exec("ROLLBACK");
834
+ throw error;
835
+ }
836
+ finally {
837
+ this.transactionDepth -= 1;
838
+ }
839
+ const committed = this.uncommittedEvents;
840
+ this.uncommittedEvents = [];
841
+ for (const { event, caller } of committed) {
842
+ for (const listener of this.eventListeners) {
843
+ try {
844
+ listener(event, caller);
845
+ }
846
+ catch { /* a live listener never fails the commit */ }
847
+ }
848
+ }
849
+ return value;
850
+ }
851
+ /** The host-held usage, attached to every terminal result; cost stays unknown. */
852
+ withUsage(executionId, result) {
853
+ const usage = this.usageOf(executionId);
854
+ return usage ? { ...result, usage: { ...usage, costUsd: null } } : result;
855
+ }
856
+ timestamp() {
857
+ return this.now().toISOString();
858
+ }
859
+ mustGetRow(executionId) {
860
+ const row = this.row(this.statements.getExecution.get(executionId));
861
+ if (!row)
862
+ throw new Error(`Execution ${executionId} disappeared inside its transaction`);
863
+ return row;
864
+ }
865
+ mustGet(executionId) {
866
+ return this.toRecord(this.mustGetRow(executionId));
867
+ }
868
+ row(value) {
869
+ return value ?? null;
870
+ }
871
+ toRecord(row) {
872
+ return {
873
+ taskId: row.task_id,
874
+ executionId: row.execution_id,
875
+ scope: row.scope,
876
+ caller: JSON.parse(row.caller),
877
+ state: row.state,
878
+ revision: row.revision,
879
+ inputSeq: row.input_seq,
880
+ processedInputSeq: row.processed_input_seq,
881
+ workerInstanceId: row.worker_instance_id,
882
+ autoResumeCount: row.auto_resume_count,
883
+ payload: JSON.parse(row.payload),
884
+ snapshot: row.snapshot,
885
+ openQuestionId: row.open_question_id,
886
+ result: row.result ? JSON.parse(row.result) : null,
887
+ usage: this.usageOf(row.execution_id),
888
+ createdAt: row.created_at,
889
+ updatedAt: row.updated_at,
890
+ queuedAt: row.queued_at,
891
+ startedAt: row.started_at,
892
+ cancelRequestedAt: row.cancel_requested_at,
893
+ stoppedAt: row.stopped_at,
894
+ };
895
+ }
896
+ toEvent(row) {
897
+ return {
898
+ protocolVersion: EXECUTION_PROTOCOL_VERSION,
899
+ eventId: row.event_id,
900
+ seq: row.seq,
901
+ taskId: row.task_id,
902
+ executionId: row.execution_id,
903
+ type: row.type,
904
+ ...(row.command_id ? { commandId: row.command_id } : {}),
905
+ createdAt: row.created_at,
906
+ payload: JSON.parse(row.payload),
907
+ };
908
+ }
909
+ }
910
+ //# sourceMappingURL=execution-store.js.map