@ouro.bot/cli 0.1.0-alpha.8 → 0.1.0-alpha.800

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