@ouro.bot/cli 0.1.0-alpha.73 → 0.1.0-alpha.731

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 (530) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -23
  3. package/RepairGuide.ouro/agent.json +5 -0
  4. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  5. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  6. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  7. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  8. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  9. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  12. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  13. package/assets/bluebubbles-host +264 -0
  14. package/changelog.json +4645 -14
  15. package/dist/a2a/card.js +57 -0
  16. package/dist/a2a/client.js +180 -0
  17. package/dist/a2a/config.js +50 -0
  18. package/dist/a2a/delegation-stores.js +56 -0
  19. package/dist/a2a/did-resolution.js +93 -0
  20. package/dist/a2a/identity.js +170 -0
  21. package/dist/a2a/inbound-share.js +107 -0
  22. package/dist/a2a/mission-result-wire.js +196 -0
  23. package/dist/a2a/onboarding.js +115 -0
  24. package/dist/a2a/pin-store.js +132 -0
  25. package/dist/a2a/seen-ledger.js +120 -0
  26. package/dist/a2a/server.js +604 -0
  27. package/dist/a2a/task-store.js +69 -0
  28. package/dist/a2a/transport.js +45 -0
  29. package/dist/a2a/types.js +3 -0
  30. package/dist/arc/attention-types.js +8 -0
  31. package/dist/arc/cares.js +144 -0
  32. package/dist/arc/episodes.js +118 -0
  33. package/dist/arc/evolution.js +490 -0
  34. package/dist/arc/flight-recorder.js +1034 -0
  35. package/dist/arc/intentions.js +134 -0
  36. package/dist/arc/json-store.js +117 -0
  37. package/dist/arc/obligations.js +348 -0
  38. package/dist/arc/packets.js +336 -0
  39. package/dist/arc/presence.js +185 -0
  40. package/dist/arc/task-lifecycle.js +57 -0
  41. package/dist/commerce/store.js +755 -0
  42. package/dist/commerce/types.js +3 -0
  43. package/dist/heart/active-work.js +874 -43
  44. package/dist/heart/agent-entry.js +190 -3
  45. package/dist/heart/approval-store.js +791 -0
  46. package/dist/heart/attachments/image-normalize.js +194 -0
  47. package/dist/heart/attachments/materialize.js +97 -0
  48. package/dist/heart/attachments/originals.js +88 -0
  49. package/dist/heart/attachments/render.js +29 -0
  50. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  51. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  52. package/dist/heart/attachments/sources/index.js +16 -0
  53. package/dist/heart/attachments/store.js +103 -0
  54. package/dist/heart/attachments/types.js +93 -0
  55. package/dist/heart/auth/auth-flow.js +479 -0
  56. package/dist/heart/autonomy-budget.js +434 -0
  57. package/dist/heart/awaiting/await-alert.js +146 -0
  58. package/dist/heart/awaiting/await-expiry.js +108 -0
  59. package/dist/heart/awaiting/await-loader.js +91 -0
  60. package/dist/heart/awaiting/await-parser.js +141 -0
  61. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  62. package/dist/heart/awaiting/await-scheduler.js +378 -0
  63. package/dist/heart/background-operations.js +281 -0
  64. package/dist/heart/bridges/manager.js +137 -17
  65. package/dist/heart/bridges/store.js +14 -2
  66. package/dist/heart/bundle-state.js +168 -0
  67. package/dist/heart/commitments.js +135 -0
  68. package/dist/heart/config-registry.js +331 -0
  69. package/dist/heart/config.js +120 -129
  70. package/dist/heart/context-loss-gauntlet.js +354 -0
  71. package/dist/heart/context-loss-sentinel.js +1155 -0
  72. package/dist/heart/core.js +1763 -320
  73. package/dist/heart/cross-chat-delivery.js +8 -22
  74. package/dist/heart/daemon/agent-config-check.js +451 -0
  75. package/dist/heart/daemon/agent-discovery.js +185 -3
  76. package/dist/heart/daemon/agent-service.js +542 -0
  77. package/dist/heart/daemon/agentic-repair.js +547 -0
  78. package/dist/heart/daemon/await-private-wake.js +59 -0
  79. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  80. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  81. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  82. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  83. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  84. package/dist/heart/daemon/cadence.js +180 -0
  85. package/dist/heart/daemon/cli-defaults.js +832 -0
  86. package/dist/heart/daemon/cli-desk.js +322 -0
  87. package/dist/heart/daemon/cli-exec.js +8620 -0
  88. package/dist/heart/daemon/cli-help.js +705 -0
  89. package/dist/heart/daemon/cli-parse.js +2712 -0
  90. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  91. package/dist/heart/daemon/cli-render.js +777 -0
  92. package/dist/heart/daemon/cli-types.js +8 -0
  93. package/dist/heart/daemon/connect-bay.js +323 -0
  94. package/dist/heart/daemon/daemon-cli.js +29 -2093
  95. package/dist/heart/daemon/daemon-entry.js +842 -10
  96. package/dist/heart/daemon/daemon-health.js +176 -0
  97. package/dist/heart/daemon/daemon-rollup.js +57 -0
  98. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  99. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  100. package/dist/heart/daemon/daemon.js +1610 -87
  101. package/dist/heart/daemon/dns-workflow.js +394 -0
  102. package/dist/heart/daemon/doctor-types.js +8 -0
  103. package/dist/heart/daemon/doctor.js +1689 -0
  104. package/dist/heart/daemon/freshness.js +345 -0
  105. package/dist/heart/daemon/habit-private-wake.js +61 -0
  106. package/dist/heart/daemon/health-monitor.js +142 -11
  107. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  108. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  109. package/dist/heart/daemon/http-health-probe.js +80 -0
  110. package/dist/heart/daemon/human-command-screens.js +234 -0
  111. package/dist/heart/daemon/human-readiness.js +114 -0
  112. package/dist/heart/daemon/inner-status.js +78 -0
  113. package/dist/heart/daemon/interactive-repair.js +394 -0
  114. package/dist/heart/daemon/launchd.js +37 -8
  115. package/dist/heart/daemon/log-tailer.js +79 -10
  116. package/dist/heart/daemon/logs-prune.js +132 -0
  117. package/dist/heart/daemon/mcp-canary.js +524 -0
  118. package/dist/heart/daemon/message-router.js +45 -5
  119. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  120. package/dist/heart/daemon/os-cron-deps.js +135 -0
  121. package/dist/heart/daemon/os-cron.js +22 -14
  122. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  123. package/dist/heart/daemon/ouro-entry.js +3 -1
  124. package/dist/heart/daemon/plugin-cli.js +432 -0
  125. package/dist/heart/daemon/process-manager.js +624 -61
  126. package/dist/heart/daemon/provider-discovery.js +137 -0
  127. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  128. package/dist/heart/daemon/prunable-bundle.js +144 -0
  129. package/dist/heart/daemon/pulse.js +511 -0
  130. package/dist/heart/daemon/readiness-repair.js +365 -0
  131. package/dist/heart/daemon/run-hooks.js +2 -0
  132. package/dist/heart/daemon/runtime-logging.js +41 -14
  133. package/dist/heart/daemon/runtime-metadata.js +2 -30
  134. package/dist/heart/daemon/safe-mode.js +161 -0
  135. package/dist/heart/daemon/sense-manager.js +670 -48
  136. package/dist/heart/daemon/session-id-resolver.js +131 -0
  137. package/dist/heart/daemon/skill-management-installer.js +1 -1
  138. package/dist/heart/daemon/socket-client.js +180 -12
  139. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  140. package/dist/heart/daemon/startup-tui.js +338 -0
  141. package/dist/heart/daemon/task-scheduler.js +117 -39
  142. package/dist/heart/daemon/terminal-ui.js +499 -0
  143. package/dist/heart/daemon/thoughts.js +255 -43
  144. package/dist/heart/daemon/up-progress.js +366 -0
  145. package/dist/heart/daemon/vault-items.js +56 -0
  146. package/dist/heart/delegation.js +1 -4
  147. package/dist/heart/external-events/router.js +121 -0
  148. package/dist/heart/habits/habit-cancel.js +810 -0
  149. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  150. package/dist/heart/habits/habit-migration.js +194 -0
  151. package/dist/heart/habits/habit-parser.js +278 -0
  152. package/dist/heart/habits/habit-runtime-state.js +93 -0
  153. package/dist/heart/habits/habit-scheduler.js +649 -0
  154. package/dist/heart/habits/habit-session-summary.js +318 -0
  155. package/dist/heart/habits/habit-session.js +636 -0
  156. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  157. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  158. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  159. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  160. package/dist/heart/identity.js +174 -59
  161. package/dist/heart/kept-notes.js +289 -0
  162. package/dist/heart/kicks.js +1 -1
  163. package/dist/heart/machine-identity.js +161 -0
  164. package/dist/heart/mail-import-discovery.js +353 -0
  165. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  166. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  167. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  168. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  169. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  170. package/dist/heart/mailbox/mailbox-http.js +99 -0
  171. package/dist/heart/mailbox/mailbox-read.js +39 -0
  172. package/dist/heart/mailbox/mailbox-types.js +27 -0
  173. package/dist/heart/mailbox/mailbox-view.js +197 -0
  174. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  175. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  176. package/dist/heart/mailbox/readers/mail.js +375 -0
  177. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  178. package/dist/heart/mailbox/readers/sessions.js +232 -0
  179. package/dist/heart/mailbox/readers/shared.js +111 -0
  180. package/dist/heart/mcp/mcp-server.js +696 -0
  181. package/dist/heart/migrate-config.js +100 -0
  182. package/dist/heart/model-capabilities.js +11 -0
  183. package/dist/heart/orientation-frame.js +345 -0
  184. package/dist/heart/platform.js +81 -0
  185. package/dist/heart/primitives.js +1 -1
  186. package/dist/heart/private-runtime/decision-renderer.js +156 -0
  187. package/dist/heart/private-runtime/index.js +18 -0
  188. package/dist/heart/private-runtime/ledger.js +218 -0
  189. package/dist/heart/private-runtime/policy.js +214 -0
  190. package/dist/heart/private-runtime/types.js +2 -0
  191. package/dist/heart/progress-story.js +1 -1
  192. package/dist/heart/provider-attempt.js +137 -0
  193. package/dist/heart/provider-binding-resolver.js +273 -0
  194. package/dist/heart/provider-credentials.js +441 -0
  195. package/dist/heart/provider-failover.js +311 -0
  196. package/dist/heart/provider-models.js +81 -0
  197. package/dist/heart/provider-ping.js +262 -0
  198. package/dist/heart/provider-readiness-cache.js +119 -0
  199. package/dist/heart/provider-visibility.js +188 -0
  200. package/dist/heart/providers/anthropic-token.js +131 -0
  201. package/dist/heart/providers/anthropic.js +173 -60
  202. package/dist/heart/providers/azure.js +23 -11
  203. package/dist/heart/providers/error-classification.js +127 -0
  204. package/dist/heart/providers/github-copilot.js +34 -38
  205. package/dist/heart/providers/minimax-vlm.js +189 -0
  206. package/dist/heart/providers/minimax.js +26 -8
  207. package/dist/heart/providers/openai-codex-token.js +349 -0
  208. package/dist/heart/providers/openai-codex.js +55 -40
  209. package/dist/heart/run-ledger.js +247 -0
  210. package/dist/heart/runtime-capability-check.js +170 -0
  211. package/dist/heart/runtime-credentials.js +398 -0
  212. package/dist/heart/runtime-cwd.js +87 -0
  213. package/dist/heart/sense-truth.js +20 -4
  214. package/dist/heart/session-activity.js +90 -24
  215. package/dist/heart/session-events.js +1300 -0
  216. package/dist/heart/session-playback-cli-main.js +5 -0
  217. package/dist/heart/session-playback-cli.js +36 -0
  218. package/dist/heart/session-playback.js +231 -0
  219. package/dist/heart/session-stats-cli-main.js +5 -0
  220. package/dist/heart/session-stats.js +182 -0
  221. package/dist/heart/session-transcript.js +133 -0
  222. package/dist/heart/start-of-turn-packet.js +368 -0
  223. package/dist/heart/streaming.js +604 -207
  224. package/dist/heart/structured-output.js +196 -0
  225. package/dist/heart/sync-classification.js +176 -0
  226. package/dist/heart/sync.js +449 -0
  227. package/dist/heart/target-resolution.js +11 -7
  228. package/dist/heart/tempo.js +93 -0
  229. package/dist/heart/temporal-view.js +41 -0
  230. package/dist/heart/timeouts.js +101 -0
  231. package/dist/heart/tool-activity-callbacks.js +59 -0
  232. package/dist/heart/tool-approval.js +339 -0
  233. package/dist/heart/tool-description.js +155 -0
  234. package/dist/heart/tool-friction.js +55 -0
  235. package/dist/heart/tool-loop.js +200 -0
  236. package/dist/heart/turn-context.js +472 -0
  237. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  238. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  239. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  240. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  241. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  242. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  243. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  244. package/dist/heart/versioning/update-hooks.js +154 -0
  245. package/dist/heart/versioning/version-intent.js +114 -0
  246. package/dist/heart/work-card.js +380 -0
  247. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  248. package/dist/mailbox-ui/assets/index-J8zDwHmE.js +1 -0
  249. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  250. package/dist/mailbox-ui/index.html +16 -0
  251. package/dist/mailroom/attention.js +167 -0
  252. package/dist/mailroom/autonomy.js +209 -0
  253. package/dist/mailroom/blob-store.js +811 -0
  254. package/dist/mailroom/body-cache.js +61 -0
  255. package/dist/mailroom/cache-sync-cli.js +54 -0
  256. package/dist/mailroom/core.js +788 -0
  257. package/dist/mailroom/entry.js +160 -0
  258. package/dist/mailroom/file-store.js +568 -0
  259. package/dist/mailroom/hosted-cache-sync.js +249 -0
  260. package/dist/mailroom/mbox-import.js +393 -0
  261. package/dist/mailroom/migration.js +164 -0
  262. package/dist/mailroom/outbound.js +380 -0
  263. package/dist/mailroom/policy.js +263 -0
  264. package/dist/mailroom/reader.js +292 -0
  265. package/dist/mailroom/search-cache.js +404 -0
  266. package/dist/mailroom/search-relevance.js +319 -0
  267. package/dist/mailroom/smtp-ingress.js +176 -0
  268. package/dist/mailroom/source-state.js +176 -0
  269. package/dist/mailroom/thread.js +109 -0
  270. package/dist/mailroom/travel-extract.js +89 -0
  271. package/dist/mind/bundle-manifest.js +24 -2
  272. package/dist/mind/context.js +273 -111
  273. package/dist/mind/desk-section.js +362 -0
  274. package/dist/mind/diary-integrity.js +60 -0
  275. package/dist/mind/{memory.js → diary.js} +68 -77
  276. package/dist/mind/embedding-provider.js +60 -0
  277. package/dist/mind/file-state.js +179 -0
  278. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  279. package/dist/mind/obligation-steering.js +227 -0
  280. package/dist/mind/pending.js +13 -8
  281. package/dist/mind/prompt-budget.js +479 -0
  282. package/dist/mind/prompt-refresh.js +3 -2
  283. package/dist/mind/prompt.js +1058 -172
  284. package/dist/mind/provenance-trust.js +26 -0
  285. package/dist/mind/record-paths.js +312 -0
  286. package/dist/mind/scrutiny.js +173 -0
  287. package/dist/mind/session-transaction.js +379 -0
  288. package/dist/nerves/cli-logging.js +7 -1
  289. package/dist/nerves/coverage/audit-rules.js +15 -6
  290. package/dist/nerves/coverage/audit.js +28 -2
  291. package/dist/nerves/coverage/cli.js +1 -1
  292. package/dist/nerves/coverage/contract.js +5 -5
  293. package/dist/nerves/coverage/file-completeness.js +139 -5
  294. package/dist/nerves/coverage/run-artifacts.js +55 -35
  295. package/dist/nerves/event-buffer.js +111 -0
  296. package/dist/nerves/index.js +234 -4
  297. package/dist/nerves/observation.js +20 -0
  298. package/dist/nerves/redact.js +79 -0
  299. package/dist/nerves/review/cli-main.js +5 -0
  300. package/dist/nerves/review/cli.js +156 -0
  301. package/dist/nerves/review/core.js +159 -0
  302. package/dist/nerves/runtime.js +5 -1
  303. package/dist/repertoire/ado-client.js +15 -56
  304. package/dist/repertoire/ado-semantic.js +16 -10
  305. package/dist/repertoire/api-client.js +97 -0
  306. package/dist/repertoire/bitwarden-store.js +1045 -0
  307. package/dist/repertoire/bundle-templates.js +71 -0
  308. package/dist/repertoire/bw-installer.js +180 -0
  309. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  310. package/dist/repertoire/coding/context-pack.js +331 -0
  311. package/dist/repertoire/coding/feedback.js +218 -30
  312. package/dist/repertoire/coding/index.js +15 -3
  313. package/dist/repertoire/coding/manager.js +166 -10
  314. package/dist/repertoire/coding/spawner.js +58 -11
  315. package/dist/repertoire/coding/tools.js +242 -14
  316. package/dist/repertoire/coding/workbench-client.js +272 -0
  317. package/dist/repertoire/coding/workbench-manager.js +346 -0
  318. package/dist/repertoire/commerce-errors.js +109 -0
  319. package/dist/repertoire/commerce-self-test.js +156 -0
  320. package/dist/repertoire/credential-access.js +178 -0
  321. package/dist/repertoire/desk/classifier.js +362 -0
  322. package/dist/repertoire/duffel-client.js +185 -0
  323. package/dist/repertoire/github-client.js +14 -55
  324. package/dist/repertoire/graph-client.js +11 -52
  325. package/dist/repertoire/guardrails.js +812 -18
  326. package/dist/repertoire/mcp-client.js +44 -3
  327. package/dist/repertoire/mcp-manager.js +259 -20
  328. package/dist/repertoire/mcp-tools.js +83 -0
  329. package/dist/repertoire/plugin-mcp.js +175 -0
  330. package/dist/repertoire/plugins.js +253 -0
  331. package/dist/repertoire/shell-sessions.js +133 -0
  332. package/dist/repertoire/skills.js +48 -4
  333. package/dist/repertoire/stripe-client.js +131 -0
  334. package/dist/repertoire/tool-arguments.js +104 -0
  335. package/dist/repertoire/tool-results.js +29 -0
  336. package/dist/repertoire/tools-a2a.js +699 -0
  337. package/dist/repertoire/tools-attachments.js +317 -0
  338. package/dist/repertoire/tools-awaiting.js +372 -0
  339. package/dist/repertoire/tools-base.js +67 -1095
  340. package/dist/repertoire/tools-bluebubbles.js +2 -0
  341. package/dist/repertoire/tools-bridge.js +144 -0
  342. package/dist/repertoire/tools-bundle.js +993 -0
  343. package/dist/repertoire/tools-commerce.js +253 -0
  344. package/dist/repertoire/tools-config.js +186 -0
  345. package/dist/repertoire/tools-continuity.js +252 -0
  346. package/dist/repertoire/tools-credential.js +383 -0
  347. package/dist/repertoire/tools-evolution.js +527 -0
  348. package/dist/repertoire/tools-files.js +344 -0
  349. package/dist/repertoire/tools-flight.js +290 -0
  350. package/dist/repertoire/tools-flow.js +119 -0
  351. package/dist/repertoire/tools-github.js +3 -8
  352. package/dist/repertoire/tools-habits.js +103 -0
  353. package/dist/repertoire/tools-mail.js +1828 -0
  354. package/dist/repertoire/tools-notes.js +459 -0
  355. package/dist/repertoire/tools-obligations.js +182 -0
  356. package/dist/repertoire/tools-orientation.js +31 -0
  357. package/dist/repertoire/tools-record.js +482 -0
  358. package/dist/repertoire/tools-rsvp.js +139 -0
  359. package/dist/repertoire/tools-runtime.js +150 -0
  360. package/dist/repertoire/tools-session.js +881 -0
  361. package/dist/repertoire/tools-shell.js +133 -0
  362. package/dist/repertoire/tools-stripe.js +224 -0
  363. package/dist/repertoire/tools-surface.js +355 -0
  364. package/dist/repertoire/tools-teams.js +12 -39
  365. package/dist/repertoire/tools-travel.js +125 -0
  366. package/dist/repertoire/tools-trip.js +982 -0
  367. package/dist/repertoire/tools-user-profile.js +146 -0
  368. package/dist/repertoire/tools-vault.js +40 -0
  369. package/dist/repertoire/tools-voice.js +145 -0
  370. package/dist/repertoire/tools.js +258 -79
  371. package/dist/repertoire/travel-api-client.js +360 -0
  372. package/dist/repertoire/user-profile.js +131 -0
  373. package/dist/repertoire/vault-setup.js +246 -0
  374. package/dist/repertoire/vault-unlock.js +594 -0
  375. package/dist/rsvp/aisleplanner-client.js +354 -0
  376. package/dist/rsvp/cli.js +926 -0
  377. package/dist/rsvp/config.js +327 -0
  378. package/dist/rsvp/cutover.js +433 -0
  379. package/dist/rsvp/diagnostics.js +232 -0
  380. package/dist/rsvp/diff-renderer.js +176 -0
  381. package/dist/rsvp/habit-policy.js +110 -0
  382. package/dist/rsvp/habit-stage.js +123 -0
  383. package/dist/rsvp/incident-bundle.js +97 -0
  384. package/dist/rsvp/migration.js +204 -0
  385. package/dist/rsvp/native-habit-runner.js +630 -0
  386. package/dist/rsvp/outbound-state.js +628 -0
  387. package/dist/rsvp/query.js +118 -0
  388. package/dist/rsvp/replay.js +233 -0
  389. package/dist/rsvp/snapshot.js +232 -0
  390. package/dist/rsvp/spend-ledger.js +175 -0
  391. package/dist/scripts/claude-code-hook.js +41 -0
  392. package/dist/scripts/claude-code-stop-hook.js +47 -0
  393. package/dist/senses/a2a-entry.js +115 -0
  394. package/dist/senses/attention-queue.js +186 -0
  395. package/dist/senses/await-turn-message.js +58 -0
  396. package/dist/senses/bluebubbles/active-turns.js +216 -0
  397. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  398. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  399. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
  400. package/dist/senses/bluebubbles/context-packet.js +207 -0
  401. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  402. package/dist/senses/bluebubbles/entry.js +90 -0
  403. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  404. package/dist/senses/bluebubbles/index.js +3839 -0
  405. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  406. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  407. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  408. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  409. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  410. package/dist/senses/bluebubbles/processed-log.js +133 -0
  411. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  412. package/dist/senses/bluebubbles/replay.js +284 -0
  413. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  414. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  415. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  416. package/dist/senses/bluebubbles/webhook-registration.js +228 -0
  417. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  418. package/dist/senses/cli/bracketed-paste.js +82 -0
  419. package/dist/senses/cli/image-paste.js +287 -0
  420. package/dist/senses/cli/image-ref-navigation.js +75 -0
  421. package/dist/senses/cli/ink-app.js +156 -0
  422. package/dist/senses/cli/inline-diff.js +64 -0
  423. package/dist/senses/cli/input-keys.js +174 -0
  424. package/dist/senses/cli/kill-ring.js +86 -0
  425. package/dist/senses/cli/message-list.js +51 -0
  426. package/dist/senses/cli/ouro-tui.js +607 -0
  427. package/dist/senses/cli/spinner-imperative.js +135 -0
  428. package/dist/senses/cli/spinner.js +101 -0
  429. package/dist/senses/cli/status-line.js +60 -0
  430. package/dist/senses/cli/streaming-markdown.js +526 -0
  431. package/dist/senses/cli/tool-display.js +85 -0
  432. package/dist/senses/cli/tool-render.js +85 -0
  433. package/dist/senses/cli/tui-store.js +241 -0
  434. package/dist/senses/cli/virtual-list.js +35 -0
  435. package/dist/senses/cli-entry.js +60 -8
  436. package/dist/senses/cli-layout.js +100 -0
  437. package/dist/senses/cli.js +640 -312
  438. package/dist/senses/commands.js +66 -3
  439. package/dist/senses/context-packet-ledger.js +371 -0
  440. package/dist/senses/context-packets.js +154 -0
  441. package/dist/senses/habit-lifecycle-guard.js +24 -0
  442. package/dist/senses/habit-turn-message.js +160 -0
  443. package/dist/senses/ingress-evidence.js +2 -0
  444. package/dist/senses/mail-entry.js +66 -0
  445. package/dist/senses/mail.js +524 -0
  446. package/dist/senses/pipeline.js +1075 -176
  447. package/dist/senses/private-runtime-worker.js +740 -0
  448. package/dist/senses/private-runtime.js +1212 -0
  449. package/dist/senses/proactive-content-guard.js +51 -0
  450. package/dist/senses/shared-turn.js +424 -0
  451. package/dist/senses/surface-tool.js +109 -0
  452. package/dist/senses/teams-entry.js +60 -8
  453. package/dist/senses/teams.js +515 -217
  454. package/dist/senses/trust-gate.js +104 -9
  455. package/dist/senses/voice/audio-playback.js +237 -0
  456. package/dist/senses/voice/audio-routing.js +119 -0
  457. package/dist/senses/voice/elevenlabs.js +202 -0
  458. package/dist/senses/voice/floor-control.js +431 -0
  459. package/dist/senses/voice/floor-controller.js +115 -0
  460. package/dist/senses/voice/golden-path.js +116 -0
  461. package/dist/senses/voice/index.js +29 -0
  462. package/dist/senses/voice/meeting.js +113 -0
  463. package/dist/senses/voice/outbound.js +190 -0
  464. package/dist/senses/voice/phone.js +33 -0
  465. package/dist/senses/voice/playback.js +139 -0
  466. package/dist/senses/voice/realtime-eval.js +496 -0
  467. package/dist/senses/voice/realtime-trace.js +531 -0
  468. package/dist/senses/voice/transcript.js +70 -0
  469. package/dist/senses/voice/turn.js +191 -0
  470. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  471. package/dist/senses/voice/twilio-phone.js +5081 -0
  472. package/dist/senses/voice/types.js +2 -0
  473. package/dist/senses/voice/whisper.js +161 -0
  474. package/dist/senses/voice-entry.js +81 -0
  475. package/dist/senses/voice-realtime-eval-command.js +99 -0
  476. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  477. package/dist/senses/voice-twilio-entry.js +87 -0
  478. package/dist/trips/core.js +138 -0
  479. package/dist/trips/store.js +265 -0
  480. package/dist/util/frontmatter.js +69 -0
  481. package/package.json +65 -12
  482. package/skills/agent-commerce.md +113 -0
  483. package/skills/browser-navigation.md +117 -0
  484. package/skills/commerce-setup-guide.md +116 -0
  485. package/skills/commerce-setup.md +84 -0
  486. package/skills/configure-dev-tools.md +99 -0
  487. package/skills/travel-planning.md +138 -0
  488. package/dist/heart/daemon/auth-flow.js +0 -430
  489. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  490. package/dist/heart/daemon/update-hooks.js +0 -138
  491. package/dist/heart/safe-workspace.js +0 -228
  492. package/dist/heart/session-recall.js +0 -116
  493. package/dist/mind/friends/channel.js +0 -84
  494. package/dist/mind/friends/group-context.js +0 -144
  495. package/dist/mind/friends/resolver.js +0 -84
  496. package/dist/mind/friends/store-file.js +0 -190
  497. package/dist/mind/friends/store.js +0 -4
  498. package/dist/mind/friends/tokens.js +0 -26
  499. package/dist/mind/friends/trust-explanation.js +0 -74
  500. package/dist/mind/friends/types.js +0 -29
  501. package/dist/repertoire/tasks/board.js +0 -134
  502. package/dist/repertoire/tasks/index.js +0 -224
  503. package/dist/repertoire/tasks/lifecycle.js +0 -80
  504. package/dist/repertoire/tasks/middleware.js +0 -65
  505. package/dist/repertoire/tasks/parser.js +0 -173
  506. package/dist/repertoire/tasks/scanner.js +0 -132
  507. package/dist/repertoire/tasks/transitions.js +0 -144
  508. package/dist/senses/bluebubbles-entry.js +0 -13
  509. package/dist/senses/bluebubbles.js +0 -1180
  510. package/dist/senses/debug-activity.js +0 -148
  511. package/dist/senses/inner-dialog-worker.js +0 -90
  512. package/dist/senses/inner-dialog.js +0 -480
  513. package/subagents/README.md +0 -7
  514. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  515. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  516. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  517. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  518. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  519. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  520. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  521. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  522. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  523. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  524. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  525. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  526. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  527. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  528. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  529. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  530. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,791 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.ApprovalStoreError = void 0;
40
+ exports.canonicalApprovalArguments = canonicalApprovalArguments;
41
+ exports.parseApprovalRecord = parseApprovalRecord;
42
+ exports.openApprovalStore = openApprovalStore;
43
+ const node_crypto_1 = require("node:crypto");
44
+ const fs = __importStar(require("node:fs"));
45
+ const path = __importStar(require("node:path"));
46
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
47
+ const runtime_1 = require("../nerves/runtime");
48
+ class ApprovalStoreError extends Error {
49
+ code;
50
+ constructor(code, message = code) {
51
+ super(message);
52
+ this.name = "ApprovalStoreError";
53
+ this.code = code;
54
+ }
55
+ }
56
+ exports.ApprovalStoreError = ApprovalStoreError;
57
+ const HASH = /^[a-f0-9]{64}$/;
58
+ const UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i;
59
+ const RECORD_KEYS = [
60
+ "approvalId", "state", "toolCallId", "toolName", "arguments", "argumentDigest", "schemaDigest",
61
+ "toolDigest", "policyDigest", "policyId", "sessionKey", "sessionPath", "baseSessionRevision",
62
+ "suspendedSessionRevision", "checkpointDigest", "requesterId", "transport", "transportUserId",
63
+ "transportChatId", "transportMessageId", "decisionTokenDigest", "expiresAt", "createdAt", "updatedAt",
64
+ "ownerId", "epoch", "attemptedAt", "result", "reason", "frozenAssistantMessage",
65
+ ];
66
+ const STATES = new Set([
67
+ "preparing", "awaiting_prompt_binding", "proposed", "claimed", "attempted", "succeeded", "failed",
68
+ "attempted_indeterminate", "denied", "expired", "drifted", "session_head_changed", "abandoned_before_attempt",
69
+ ]);
70
+ const ATTEMPT_TERMINALS = new Set(["succeeded", "failed", "attempted_indeterminate"]);
71
+ function fail(code) {
72
+ throw new ApprovalStoreError(code);
73
+ }
74
+ function isObject(value) {
75
+ return typeof value === "object" && value !== null && !Array.isArray(value);
76
+ }
77
+ function isTimestamp(value) {
78
+ return typeof value === "string" && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
79
+ }
80
+ function isNonEmpty(value) {
81
+ return typeof value === "string" && value.length > 0;
82
+ }
83
+ function processIsAlive(pid) {
84
+ try {
85
+ process.kill(pid, 0);
86
+ return true;
87
+ }
88
+ catch {
89
+ return false;
90
+ }
91
+ }
92
+ function assertJsonValue(value) {
93
+ if (value === null || typeof value === "string" || typeof value === "boolean")
94
+ return;
95
+ if (typeof value === "number" && Number.isFinite(value))
96
+ return;
97
+ if (Array.isArray(value)) {
98
+ for (const item of value)
99
+ assertJsonValue(item);
100
+ return;
101
+ }
102
+ if (isObject(value)) {
103
+ for (const item of Object.values(value))
104
+ assertJsonValue(item);
105
+ return;
106
+ }
107
+ fail("invalid_json_value");
108
+ }
109
+ function canonicalize(value) {
110
+ if (value === null || typeof value !== "object")
111
+ return JSON.stringify(value);
112
+ if (Array.isArray(value))
113
+ return `[${value.map(canonicalize).join(",")}]`;
114
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalize(value[key])}`).join(",")}}`;
115
+ }
116
+ function sha256(value) {
117
+ return (0, node_crypto_1.createHash)("sha256").update(value, "utf8").digest("hex");
118
+ }
119
+ function canonicalApprovalArguments(value) {
120
+ if (!isObject(value))
121
+ fail("arguments_not_object");
122
+ assertJsonValue(value);
123
+ const canonical = canonicalize(value);
124
+ return { canonical, digest: sha256(canonical) };
125
+ }
126
+ function hasExactKeys(value) {
127
+ const actual = Object.keys(value).sort();
128
+ const expected = [...RECORD_KEYS].sort();
129
+ return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
130
+ }
131
+ function validStateShape(record) {
132
+ const hasOwner = isNonEmpty(record.ownerId);
133
+ const hasAttempt = isTimestamp(record.attemptedAt);
134
+ const hasSuspension = typeof record.suspendedSessionRevision === "string"
135
+ && HASH.test(record.suspendedSessionRevision);
136
+ const hasPromptBinding = isNonEmpty(record.transportMessageId);
137
+ const hasValidOwnershipEpoch = hasOwner ? record.epoch > 0 : record.epoch === 0;
138
+ if (record.state === "preparing") {
139
+ return record.suspendedSessionRevision === null && record.transportMessageId === null
140
+ && !hasOwner && record.epoch === 0 && !hasAttempt && record.result === null && record.reason === null;
141
+ }
142
+ if (record.state === "awaiting_prompt_binding") {
143
+ return hasSuspension && record.transportMessageId === null
144
+ && !hasOwner && record.epoch === 0 && !hasAttempt && record.result === null && record.reason === null;
145
+ }
146
+ if (record.state === "proposed") {
147
+ return hasSuspension && hasPromptBinding
148
+ && !hasOwner && record.epoch === 0 && !hasAttempt && record.result === null && record.reason === null;
149
+ }
150
+ if (record.state === "claimed") {
151
+ return hasSuspension && hasPromptBinding && hasOwner && record.epoch > 0
152
+ && !hasAttempt && record.result === null && record.reason === null;
153
+ }
154
+ if (record.state === "attempted") {
155
+ return hasSuspension && hasPromptBinding && hasOwner && record.epoch > 0
156
+ && hasAttempt && record.result === null && record.reason === null;
157
+ }
158
+ if (ATTEMPT_TERMINALS.has(record.state)) {
159
+ return hasSuspension && hasPromptBinding && hasOwner && record.epoch > 0
160
+ && hasAttempt && isNonEmpty(record.result) && record.reason === null;
161
+ }
162
+ if (record.state === "abandoned_before_attempt") {
163
+ const validPreparingRecovery = !hasOwner && record.epoch === 0
164
+ && record.suspendedSessionRevision === null && record.transportMessageId === null;
165
+ const validClaimRecovery = hasOwner && record.epoch > 0 && hasSuspension && hasPromptBinding;
166
+ return (validPreparingRecovery || validClaimRecovery)
167
+ && !hasAttempt && record.result === null && isNonEmpty(record.reason);
168
+ }
169
+ if (record.state === "drifted") {
170
+ const validPreparingRecovery = !hasOwner && record.epoch === 0
171
+ && record.suspendedSessionRevision === null && record.transportMessageId === null;
172
+ const validPostCheckpoint = !hasOwner && record.epoch === 0 && hasSuspension
173
+ && (hasPromptBinding || record.transportMessageId === null);
174
+ const validPostClaim = hasOwner && record.epoch > 0 && hasSuspension && hasPromptBinding;
175
+ return (validPreparingRecovery || validPostCheckpoint || validPostClaim)
176
+ && !hasAttempt && record.result === null && isNonEmpty(record.reason);
177
+ }
178
+ if (record.state === "denied") {
179
+ return hasValidOwnershipEpoch && hasSuspension && hasPromptBinding
180
+ && !hasAttempt && record.result === null && record.reason === null;
181
+ }
182
+ if (record.state === "expired") {
183
+ return !hasOwner && record.epoch === 0 && hasSuspension
184
+ && (hasPromptBinding || record.transportMessageId === null)
185
+ && !hasAttempt && record.result === null && record.reason === null;
186
+ }
187
+ if (record.state === "session_head_changed") {
188
+ return hasValidOwnershipEpoch && hasSuspension && hasPromptBinding
189
+ && !hasAttempt && record.result === null && isNonEmpty(record.reason);
190
+ }
191
+ return false;
192
+ }
193
+ function parseApprovalRecord(value) {
194
+ if (!isObject(value) || !hasExactKeys(value))
195
+ fail("corrupt_record");
196
+ const record = value;
197
+ if (!UUID.test(record.approvalId))
198
+ fail("corrupt_record");
199
+ for (const field of [
200
+ "toolCallId", "toolName", "policyId", "sessionKey", "sessionPath", "requesterId", "transport",
201
+ "transportUserId", "transportChatId",
202
+ ])
203
+ if (!isNonEmpty(record[field]))
204
+ fail("corrupt_record");
205
+ for (const field of [
206
+ "argumentDigest", "schemaDigest", "toolDigest", "policyDigest", "baseSessionRevision", "checkpointDigest",
207
+ "decisionTokenDigest",
208
+ ])
209
+ if (typeof record[field] !== "string" || !HASH.test(record[field]))
210
+ fail("corrupt_record");
211
+ if (!isObject(record.arguments) || !isObject(record.frozenAssistantMessage))
212
+ fail("corrupt_record");
213
+ assertJsonValue(record.arguments);
214
+ assertJsonValue(record.frozenAssistantMessage);
215
+ if (canonicalApprovalArguments(record.arguments).digest !== record.argumentDigest)
216
+ fail("corrupt_record");
217
+ if (!isTimestamp(record.expiresAt) || !isTimestamp(record.createdAt) || !isTimestamp(record.updatedAt))
218
+ fail("corrupt_record");
219
+ if (record.ownerId !== null && !isNonEmpty(record.ownerId))
220
+ fail("corrupt_record");
221
+ if (record.attemptedAt !== null && !isTimestamp(record.attemptedAt))
222
+ fail("corrupt_record");
223
+ if (record.reason !== null && !isNonEmpty(record.reason))
224
+ fail("corrupt_record");
225
+ if (record.result !== null && !isNonEmpty(record.result))
226
+ fail("corrupt_record");
227
+ if (record.transportMessageId !== null && !isNonEmpty(record.transportMessageId))
228
+ fail("corrupt_record");
229
+ if (record.suspendedSessionRevision !== null
230
+ && (typeof record.suspendedSessionRevision !== "string" || !HASH.test(record.suspendedSessionRevision)))
231
+ fail("corrupt_record");
232
+ if (!Number.isInteger(record.epoch) || record.epoch < 0 || !validStateShape(record) || !STATES.has(record.state))
233
+ fail("corrupt_record");
234
+ return structuredClone(record);
235
+ }
236
+ function assertHash(value, code) {
237
+ if (!HASH.test(value))
238
+ fail(code);
239
+ }
240
+ function assertPrepareInput(input) {
241
+ for (const value of [input.toolCallId, input.toolName, input.policyId, input.sessionKey, input.sessionPath,
242
+ input.requesterId, input.transport, input.transportUserId, input.transportChatId]) {
243
+ if (!isNonEmpty(value))
244
+ fail("invalid_proposal");
245
+ }
246
+ for (const value of [input.schemaDigest, input.toolDigest, input.policyDigest, input.baseSessionRevision, input.checkpointDigest]) {
247
+ assertHash(value, "invalid_proposal");
248
+ }
249
+ if (!isTimestamp(input.expiresAt) || !isObject(input.arguments) || !isObject(input.frozenAssistantMessage))
250
+ fail("invalid_proposal");
251
+ assertJsonValue(input.arguments);
252
+ assertJsonValue(input.frozenAssistantMessage);
253
+ }
254
+ function tokenMatches(token, digest) {
255
+ const actual = Buffer.from(sha256(token), "hex");
256
+ const expected = Buffer.from(digest, "hex");
257
+ return actual.length === expected.length && (0, node_crypto_1.timingSafeEqual)(actual, expected);
258
+ }
259
+ function sameDecisionBinding(record, input) {
260
+ return tokenMatches(input.decisionToken, record.decisionTokenDigest)
261
+ && input.requesterId === record.requesterId
262
+ && input.transport === record.transport
263
+ && input.transportUserId === record.transportUserId
264
+ && input.transportChatId === record.transportChatId
265
+ && input.transportMessageId === record.transportMessageId
266
+ && input.sessionKey === record.sessionKey;
267
+ }
268
+ function operationErrorMeta(operation, error) {
269
+ return {
270
+ operation,
271
+ outcome: "error",
272
+ code: error instanceof ApprovalStoreError ? error.code : "unexpected_error",
273
+ };
274
+ }
275
+ function observePrepare(operation) {
276
+ try {
277
+ const result = operation();
278
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_prepare", message: "approval store prepare completed", meta: { operation: "prepare", outcome: "success" } });
279
+ return result;
280
+ }
281
+ catch (error) {
282
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_prepare", message: "approval store prepare failed", meta: operationErrorMeta("prepare", error) });
283
+ throw error;
284
+ }
285
+ }
286
+ function observeActivate(operation) {
287
+ try {
288
+ const result = operation();
289
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_activate", message: "approval store activation completed", meta: { operation: "activate", outcome: "success" } });
290
+ return result;
291
+ }
292
+ catch (error) {
293
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_activate", message: "approval store activation failed", meta: operationErrorMeta("activate", error) });
294
+ throw error;
295
+ }
296
+ }
297
+ function observeBindPrompt(operation) {
298
+ try {
299
+ const result = operation();
300
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_bind_prompt", message: "approval prompt binding completed", meta: { operation: "bind_prompt", outcome: "success" } });
301
+ return result;
302
+ }
303
+ catch (error) {
304
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_bind_prompt", message: "approval prompt binding failed", meta: operationErrorMeta("bind_prompt", error) });
305
+ throw error;
306
+ }
307
+ }
308
+ function observeDecide(operation) {
309
+ try {
310
+ const result = operation();
311
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_decide", message: "approval decision completed", meta: { operation: "decide", outcome: "success" } });
312
+ return result;
313
+ }
314
+ catch (error) {
315
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_decide", message: "approval decision failed", meta: operationErrorMeta("decide", error) });
316
+ throw error;
317
+ }
318
+ }
319
+ function observeExpire(operation) {
320
+ try {
321
+ const result = operation();
322
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_expire", message: "approval expiry completed", meta: { operation: "expire", outcome: "success" } });
323
+ return result;
324
+ }
325
+ catch (error) {
326
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_expire", message: "approval expiry failed", meta: operationErrorMeta("expire", error) });
327
+ throw error;
328
+ }
329
+ }
330
+ function observeMarkAttempted(operation) {
331
+ try {
332
+ const result = operation();
333
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_mark_attempted", message: "approval attempt marker completed", meta: { operation: "mark_attempted", outcome: "success" } });
334
+ return result;
335
+ }
336
+ catch (error) {
337
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_mark_attempted", message: "approval attempt marker failed", meta: operationErrorMeta("mark_attempted", error) });
338
+ throw error;
339
+ }
340
+ }
341
+ function observeTerminalizeBeforeAttempt(operation) {
342
+ try {
343
+ const result = operation();
344
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_terminalize_before_attempt", message: "approval pre-attempt terminalization completed", meta: { operation: "terminalize_before_attempt", outcome: "success" } });
345
+ return result;
346
+ }
347
+ catch (error) {
348
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_terminalize_before_attempt", message: "approval pre-attempt terminalization failed", meta: operationErrorMeta("terminalize_before_attempt", error) });
349
+ throw error;
350
+ }
351
+ }
352
+ function observeAbandonBeforeAttempt(operation) {
353
+ try {
354
+ const result = operation();
355
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_abandon_before_attempt", message: "approval abandonment completed", meta: { operation: "abandon_before_attempt", outcome: "success" } });
356
+ return result;
357
+ }
358
+ catch (error) {
359
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_abandon_before_attempt", message: "approval abandonment failed", meta: operationErrorMeta("abandon_before_attempt", error) });
360
+ throw error;
361
+ }
362
+ }
363
+ function observeComplete(operation) {
364
+ try {
365
+ const result = operation();
366
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_complete", message: "approval completion completed", meta: { operation: "complete", outcome: "success" } });
367
+ return result;
368
+ }
369
+ catch (error) {
370
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_complete", message: "approval completion failed", meta: operationErrorMeta("complete", error) });
371
+ throw error;
372
+ }
373
+ }
374
+ function observeClaimContinuation(operation) {
375
+ try {
376
+ const result = operation();
377
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_claim_continuation", message: "approval continuation claim completed", meta: { operation: "claim_continuation", outcome: "success" } });
378
+ return result;
379
+ }
380
+ catch (error) {
381
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_claim_continuation", message: "approval continuation claim failed", meta: operationErrorMeta("claim_continuation", error) });
382
+ throw error;
383
+ }
384
+ }
385
+ function observeCompleteContinuation(operation) {
386
+ try {
387
+ const result = operation();
388
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_complete_continuation", message: "approval continuation completion completed", meta: { operation: "complete_continuation", outcome: "success" } });
389
+ return result;
390
+ }
391
+ catch (error) {
392
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_complete_continuation", message: "approval continuation completion failed", meta: operationErrorMeta("complete_continuation", error) });
393
+ throw error;
394
+ }
395
+ }
396
+ function observeMaterializeContinuation(operation) {
397
+ try {
398
+ const result = operation();
399
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_materialize_continuation", message: "approval continuation materialization completed", meta: { operation: "materialize_continuation", outcome: "success" } });
400
+ return result;
401
+ }
402
+ catch (error) {
403
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_materialize_continuation", message: "approval continuation materialization failed", meta: operationErrorMeta("materialize_continuation", error) });
404
+ throw error;
405
+ }
406
+ }
407
+ function observeAttemptContinuation(operation) {
408
+ try {
409
+ const result = operation();
410
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_attempt_continuation", message: "approval continuation attempt completed", meta: { operation: "attempt_continuation", outcome: "success" } });
411
+ return result;
412
+ }
413
+ catch (error) {
414
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_attempt_continuation", message: "approval continuation attempt failed", meta: operationErrorMeta("attempt_continuation", error) });
415
+ throw error;
416
+ }
417
+ }
418
+ function observeRead(operation) {
419
+ try {
420
+ const result = operation();
421
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_read", message: "approval store read completed", meta: { operation: "read", outcome: "success" } });
422
+ return result;
423
+ }
424
+ catch (error) {
425
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_read", message: "approval store read failed", meta: operationErrorMeta("read", error) });
426
+ throw error;
427
+ }
428
+ }
429
+ function observeListPreparing(operation) {
430
+ try {
431
+ const result = operation();
432
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_list_preparing", message: "preparing approval listing completed", meta: { operation: "list_preparing", outcome: "success" } });
433
+ return result;
434
+ }
435
+ catch (error) {
436
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_list_preparing", message: "preparing approval listing failed", meta: operationErrorMeta("list_preparing", error) });
437
+ throw error;
438
+ }
439
+ }
440
+ function observeRecoverPreparing(operation) {
441
+ try {
442
+ const result = operation();
443
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_recover_preparing", message: "preparing approval recovery completed", meta: { operation: "recover_preparing", outcome: "success" } });
444
+ return result;
445
+ }
446
+ catch (error) {
447
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_recover_preparing", message: "preparing approval recovery failed", meta: operationErrorMeta("recover_preparing", error) });
448
+ throw error;
449
+ }
450
+ }
451
+ function observeClose(operation) {
452
+ try {
453
+ const result = operation();
454
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_close", message: "approval store close completed", meta: { operation: "close", outcome: "success" } });
455
+ return result;
456
+ }
457
+ catch (error) {
458
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_close", message: "approval store close failed", meta: operationErrorMeta("close", error) });
459
+ throw error;
460
+ }
461
+ }
462
+ function openApprovalStore(options) {
463
+ fs.mkdirSync(path.dirname(options.databasePath), { recursive: true });
464
+ const database = new better_sqlite3_1.default(options.databasePath);
465
+ database.pragma("journal_mode = WAL");
466
+ database.pragma("busy_timeout = 5000");
467
+ database.exec(`
468
+ CREATE TABLE IF NOT EXISTS approval_actions (
469
+ approval_id TEXT PRIMARY KEY,
470
+ state TEXT NOT NULL,
471
+ epoch INTEGER NOT NULL,
472
+ record_json TEXT NOT NULL
473
+ )
474
+ ;
475
+ CREATE TABLE IF NOT EXISTS approval_continuations (
476
+ approval_id TEXT PRIMARY KEY,
477
+ owner_id TEXT NOT NULL,
478
+ owner_pid INTEGER NOT NULL,
479
+ epoch INTEGER NOT NULL,
480
+ state TEXT NOT NULL,
481
+ claimed_at TEXT NOT NULL,
482
+ materialized_at TEXT,
483
+ attempted_at TEXT,
484
+ continued_at TEXT
485
+ )
486
+ `);
487
+ const now = options.now ?? (() => new Date());
488
+ const randomUUID = options.randomUUID ?? node_crypto_1.randomUUID;
489
+ const randomBytes = options.randomBytes ?? node_crypto_1.randomBytes;
490
+ const rawRead = (approvalId) => {
491
+ const row = database.prepare("SELECT record_json FROM approval_actions WHERE approval_id = ?")
492
+ .get(approvalId);
493
+ if (!row)
494
+ return null;
495
+ try {
496
+ return parseApprovalRecord(JSON.parse(row.record_json));
497
+ }
498
+ catch (error) {
499
+ if (error instanceof ApprovalStoreError)
500
+ throw error;
501
+ fail("corrupt_record");
502
+ }
503
+ };
504
+ const insert = (record) => {
505
+ database.prepare("INSERT INTO approval_actions (approval_id, state, epoch, record_json) VALUES (?, ?, ?, ?)")
506
+ .run(record.approvalId, record.state, record.epoch, JSON.stringify(record));
507
+ };
508
+ const cas = (previous, next) => {
509
+ const changed = database.prepare(`
510
+ UPDATE approval_actions SET state = ?, epoch = ?, record_json = ?
511
+ WHERE approval_id = ? AND state = ? AND epoch = ? AND record_json = ?
512
+ `).run(next.state, next.epoch, JSON.stringify(next), previous.approvalId, previous.state, previous.epoch, JSON.stringify(previous));
513
+ if (changed.changes !== 1)
514
+ fail("transition_conflict");
515
+ return structuredClone(next);
516
+ };
517
+ const requireRecord = (approvalId) => rawRead(approvalId) ?? fail("approval_not_found");
518
+ const timestamp = () => now().toISOString();
519
+ const readContinuationRow = (approvalId) => database.prepare(`
520
+ SELECT owner_id, owner_pid, epoch, state, claimed_at, materialized_at, attempted_at, continued_at
521
+ FROM approval_continuations WHERE approval_id = ?
522
+ `).get(approvalId);
523
+ const combineContinuation = (approval, row) => ({
524
+ ...approval,
525
+ continuationOwnerId: row.owner_id,
526
+ continuationOwnerPid: row.owner_pid,
527
+ continuationEpoch: row.epoch,
528
+ continuationState: row.state,
529
+ continuationClaimedAt: row.claimed_at,
530
+ continuationMaterializedAt: row.materialized_at,
531
+ continuationAttemptedAt: row.attempted_at,
532
+ continuedAt: row.continued_at,
533
+ });
534
+ const transitionContinuation = (input, from, to, timestampColumn) => {
535
+ const approval = requireRecord(input.approvalId);
536
+ const changed = database.prepare(`
537
+ UPDATE approval_continuations SET state = ?, ${timestampColumn} = ?
538
+ WHERE approval_id = ? AND owner_id = ? AND epoch = ? AND state = ?
539
+ `).run(to, timestamp(), input.approvalId, input.ownerId, input.epoch, from);
540
+ if (changed.changes !== 1)
541
+ fail(`continuation_${to}_not_eligible`);
542
+ return combineContinuation(approval, readContinuationRow(input.approvalId));
543
+ };
544
+ return {
545
+ prepare(input) {
546
+ return observePrepare(() => {
547
+ assertPrepareInput(input);
548
+ const approvalId = randomUUID();
549
+ if (!UUID.test(approvalId))
550
+ fail("invalid_approval_id");
551
+ const tokenBytes = randomBytes(32);
552
+ if (tokenBytes.length !== 32)
553
+ fail("invalid_token_entropy");
554
+ const decisionToken = tokenBytes.toString("base64url");
555
+ const createdAt = timestamp();
556
+ const record = {
557
+ approvalId,
558
+ state: "preparing",
559
+ toolCallId: input.toolCallId,
560
+ toolName: input.toolName,
561
+ arguments: structuredClone(input.arguments),
562
+ argumentDigest: canonicalApprovalArguments(input.arguments).digest,
563
+ schemaDigest: input.schemaDigest,
564
+ toolDigest: input.toolDigest,
565
+ policyDigest: input.policyDigest,
566
+ policyId: input.policyId,
567
+ sessionKey: input.sessionKey,
568
+ sessionPath: input.sessionPath,
569
+ baseSessionRevision: input.baseSessionRevision,
570
+ suspendedSessionRevision: null,
571
+ checkpointDigest: input.checkpointDigest,
572
+ requesterId: input.requesterId,
573
+ transport: input.transport,
574
+ transportUserId: input.transportUserId,
575
+ transportChatId: input.transportChatId,
576
+ transportMessageId: null,
577
+ decisionTokenDigest: sha256(decisionToken),
578
+ expiresAt: input.expiresAt,
579
+ createdAt,
580
+ updatedAt: createdAt,
581
+ ownerId: null,
582
+ epoch: 0,
583
+ attemptedAt: null,
584
+ result: null,
585
+ reason: null,
586
+ frozenAssistantMessage: structuredClone(input.frozenAssistantMessage),
587
+ };
588
+ insert(parseApprovalRecord(record));
589
+ return { record: structuredClone(record), decisionToken };
590
+ });
591
+ },
592
+ activate(input) {
593
+ return observeActivate(() => {
594
+ const previous = requireRecord(input.approvalId);
595
+ if (previous.state !== "preparing" || input.checkpointDigest !== previous.checkpointDigest)
596
+ fail("invalid_activation");
597
+ assertHash(input.suspendedSessionRevision, "invalid_activation");
598
+ return cas(previous, { ...previous, state: "awaiting_prompt_binding", suspendedSessionRevision: input.suspendedSessionRevision, updatedAt: timestamp() });
599
+ });
600
+ },
601
+ bindPrompt(input) {
602
+ return observeBindPrompt(() => {
603
+ const previous = requireRecord(input.approvalId);
604
+ if (previous.state !== "awaiting_prompt_binding" || input.transport !== previous.transport
605
+ || input.transportChatId !== previous.transportChatId || !isNonEmpty(input.transportMessageId))
606
+ fail("invalid_prompt_binding");
607
+ return cas(previous, { ...previous, state: "proposed", transportMessageId: input.transportMessageId, updatedAt: timestamp() });
608
+ });
609
+ },
610
+ decide(input) {
611
+ return observeDecide(() => {
612
+ const previous = requireRecord(input.approvalId);
613
+ if (!sameDecisionBinding(previous, input))
614
+ fail("decision_binding_mismatch");
615
+ if (previous.state === "denied" && input.decision === "deny")
616
+ return previous;
617
+ if (previous.state !== "proposed")
618
+ fail("decision_not_eligible");
619
+ if (now().getTime() >= Date.parse(previous.expiresAt)) {
620
+ return cas(previous, { ...previous, state: "expired", updatedAt: timestamp() });
621
+ }
622
+ if (input.decision === "deny") {
623
+ return cas(previous, { ...previous, state: "denied", updatedAt: timestamp() });
624
+ }
625
+ if (!isNonEmpty(input.ownerId))
626
+ fail("invalid_owner");
627
+ options.hooks?.beforeClaimCas?.();
628
+ if (now().getTime() >= Date.parse(previous.expiresAt)) {
629
+ return cas(previous, { ...previous, state: "expired", updatedAt: timestamp() });
630
+ }
631
+ return cas(previous, { ...previous, state: "claimed", ownerId: input.ownerId, epoch: previous.epoch + 1, updatedAt: timestamp() });
632
+ });
633
+ },
634
+ expire(input) {
635
+ return observeExpire(() => {
636
+ const previous = requireRecord(input.approvalId);
637
+ if (previous.state === "expired")
638
+ return previous;
639
+ if ((previous.state !== "proposed" && previous.state !== "awaiting_prompt_binding")
640
+ || now().getTime() < Date.parse(previous.expiresAt))
641
+ fail("expiry_not_eligible");
642
+ return cas(previous, { ...previous, state: "expired", updatedAt: timestamp() });
643
+ });
644
+ },
645
+ markAttempted(input) {
646
+ return observeMarkAttempted(() => {
647
+ const previous = requireRecord(input.approvalId);
648
+ if (previous.state !== "claimed" || previous.ownerId !== input.ownerId || previous.epoch !== input.epoch)
649
+ fail("attempt_not_eligible");
650
+ options.hooks?.beforeAttemptCas?.();
651
+ return cas(previous, { ...previous, state: "attempted", attemptedAt: timestamp(), updatedAt: timestamp() });
652
+ });
653
+ },
654
+ terminalizeBeforeAttempt(input) {
655
+ return observeTerminalizeBeforeAttempt(() => {
656
+ const previous = requireRecord(input.approvalId);
657
+ if (previous.state !== "claimed" || previous.ownerId !== input.ownerId || previous.epoch !== input.epoch
658
+ || (input.state !== "drifted" && input.state !== "session_head_changed") || !isNonEmpty(input.reason)) {
659
+ fail("pre_attempt_terminalization_not_eligible");
660
+ }
661
+ return cas(previous, { ...previous, state: input.state, reason: input.reason, updatedAt: timestamp() });
662
+ });
663
+ },
664
+ abandonBeforeAttempt(input) {
665
+ return observeAbandonBeforeAttempt(() => {
666
+ const previous = requireRecord(input.approvalId);
667
+ if (previous.state === "abandoned_before_attempt" && previous.ownerId === input.ownerId
668
+ && previous.epoch === input.epoch && previous.reason === input.reason)
669
+ return previous;
670
+ if (previous.state !== "claimed" || previous.ownerId !== input.ownerId || previous.epoch !== input.epoch
671
+ || !isNonEmpty(input.reason))
672
+ fail("abandon_not_eligible");
673
+ return cas(previous, { ...previous, state: "abandoned_before_attempt", reason: input.reason, updatedAt: timestamp() });
674
+ });
675
+ },
676
+ complete(input) {
677
+ return observeComplete(() => {
678
+ const previous = requireRecord(input.approvalId);
679
+ if (ATTEMPT_TERMINALS.has(previous.state)) {
680
+ if (previous.state === input.state && previous.ownerId === input.ownerId && previous.epoch === input.epoch
681
+ && previous.result === input.result)
682
+ return previous;
683
+ fail("completion_conflict");
684
+ }
685
+ if (previous.state !== "attempted" || previous.ownerId !== input.ownerId || previous.epoch !== input.epoch
686
+ || !ATTEMPT_TERMINALS.has(input.state) || !isNonEmpty(input.result))
687
+ fail("completion_not_eligible");
688
+ return cas(previous, { ...previous, state: input.state, result: input.result, updatedAt: timestamp() });
689
+ });
690
+ },
691
+ listPreparing() {
692
+ return observeListPreparing(() => {
693
+ const rows = database.prepare("SELECT record_json FROM approval_actions WHERE state = ? ORDER BY approval_id")
694
+ .all("preparing");
695
+ return rows.map((row) => {
696
+ try {
697
+ return parseApprovalRecord(JSON.parse(row.record_json));
698
+ }
699
+ catch (error) {
700
+ if (error instanceof ApprovalStoreError)
701
+ throw error;
702
+ return fail("corrupt_record");
703
+ }
704
+ });
705
+ });
706
+ },
707
+ recoverPreparing(input) {
708
+ return observeRecoverPreparing(() => {
709
+ const previous = requireRecord(input.approvalId);
710
+ if (!isNonEmpty(input.reason))
711
+ fail("recovery_not_eligible");
712
+ if (previous.state === input.state && previous.ownerId === null && previous.epoch === 0
713
+ && previous.attemptedAt === null && previous.reason === input.reason)
714
+ return previous;
715
+ if (previous.state !== "preparing")
716
+ fail("recovery_not_eligible");
717
+ return cas(previous, { ...previous, state: input.state, reason: input.reason, updatedAt: timestamp() });
718
+ });
719
+ },
720
+ claimContinuation(input) {
721
+ return observeClaimContinuation(() => {
722
+ if (!isNonEmpty(input.ownerId))
723
+ fail("invalid_continuation_owner");
724
+ const approval = requireRecord(input.approvalId);
725
+ if (!["succeeded", "failed", "denied", "expired", "drifted", "session_head_changed", "abandoned_before_attempt", "attempted_indeterminate"].includes(approval.state)) {
726
+ fail("continuation_not_eligible");
727
+ }
728
+ const ownerPid = input.ownerPid ?? process.pid;
729
+ const claimedAt = timestamp();
730
+ const inserted = database.prepare(`
731
+ INSERT OR IGNORE INTO approval_continuations
732
+ (approval_id, owner_id, owner_pid, epoch, state, claimed_at, materialized_at, attempted_at, continued_at)
733
+ VALUES (?, ?, ?, 1, 'claimed', ?, NULL, NULL, NULL)
734
+ `).run(input.approvalId, input.ownerId, ownerPid, claimedAt);
735
+ let row = readContinuationRow(input.approvalId);
736
+ let claimed = inserted.changes === 1;
737
+ let interruptedAfterAttempt = false;
738
+ if (!claimed && (row.state === "claimed" || row.state === "materialized") && !processIsAlive(row.owner_pid)) {
739
+ const reclaimed = database.prepare(`
740
+ UPDATE approval_continuations
741
+ SET owner_id = ?, owner_pid = ?, epoch = epoch + 1, claimed_at = ?
742
+ WHERE approval_id = ? AND owner_id = ? AND owner_pid = ? AND epoch = ? AND state = ?
743
+ `).run(input.ownerId, ownerPid, claimedAt, input.approvalId, row.owner_id, row.owner_pid, row.epoch, row.state);
744
+ claimed = reclaimed.changes === 1;
745
+ row = readContinuationRow(input.approvalId);
746
+ }
747
+ if (!claimed && row.state === "attempted" && !processIsAlive(row.owner_pid)) {
748
+ const terminalized = database.prepare(`
749
+ UPDATE approval_continuations
750
+ SET owner_id = ?, owner_pid = ?, epoch = epoch + 1, state = 'completed', claimed_at = ?, continued_at = ?
751
+ WHERE approval_id = ? AND owner_id = ? AND owner_pid = ? AND epoch = ? AND state = 'attempted'
752
+ `).run(input.ownerId, ownerPid, claimedAt, claimedAt, input.approvalId, row.owner_id, row.owner_pid, row.epoch);
753
+ interruptedAfterAttempt = terminalized.changes === 1;
754
+ row = readContinuationRow(input.approvalId);
755
+ }
756
+ return {
757
+ claimed,
758
+ interruptedAfterAttempt,
759
+ record: combineContinuation(approval, row),
760
+ };
761
+ });
762
+ },
763
+ markContinuationMaterialized(input) {
764
+ return observeMaterializeContinuation(() => transitionContinuation(input, "claimed", "materialized", "materialized_at"));
765
+ },
766
+ markContinuationAttempted(input) {
767
+ return observeAttemptContinuation(() => transitionContinuation(input, "materialized", "attempted", "attempted_at"));
768
+ },
769
+ completeContinuation(input) {
770
+ return observeCompleteContinuation(() => {
771
+ const approval = requireRecord(input.approvalId);
772
+ const completedAt = timestamp();
773
+ const changed = database.prepare(`
774
+ UPDATE approval_continuations SET state = 'completed', continued_at = ?
775
+ WHERE approval_id = ? AND owner_id = ? AND epoch = ?
776
+ AND state IN ('materialized', 'attempted') AND continued_at IS NULL
777
+ `).run(completedAt, input.approvalId, input.ownerId, input.epoch);
778
+ if (changed.changes !== 1)
779
+ fail("continuation_completion_not_eligible");
780
+ return combineContinuation(approval, readContinuationRow(input.approvalId));
781
+ });
782
+ },
783
+ read(approvalId) { return observeRead(() => rawRead(approvalId)); },
784
+ close() {
785
+ return observeClose(() => {
786
+ options.hooks?.beforeClose?.();
787
+ database.close();
788
+ });
789
+ },
790
+ };
791
+ }