@ouro.bot/cli 0.1.0-alpha.55 → 0.1.0-alpha.551

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 (386) hide show
  1. package/README.md +133 -19
  2. package/RepairGuide.ouro/agent.json +5 -0
  3. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  4. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  5. package/RepairGuide.ouro/skills/diagnose-bootstrap-drift.md +54 -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/changelog.json +3561 -0
  14. package/dist/arc/attention-types.js +8 -0
  15. package/dist/arc/cares.js +140 -0
  16. package/dist/arc/episodes.js +117 -0
  17. package/dist/arc/intentions.js +133 -0
  18. package/dist/arc/json-store.js +117 -0
  19. package/dist/arc/obligations.js +237 -0
  20. package/dist/arc/packets.js +193 -0
  21. package/dist/arc/presence.js +185 -0
  22. package/dist/arc/task-lifecycle.js +65 -0
  23. package/dist/heart/active-work.js +837 -26
  24. package/dist/heart/agent-entry.js +58 -3
  25. package/dist/heart/attachments/image-normalize.js +194 -0
  26. package/dist/heart/attachments/materialize.js +97 -0
  27. package/dist/heart/attachments/originals.js +88 -0
  28. package/dist/heart/attachments/render.js +29 -0
  29. package/dist/heart/attachments/sources/adapter.js +2 -0
  30. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  31. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  32. package/dist/heart/attachments/sources/index.js +16 -0
  33. package/dist/heart/attachments/store.js +103 -0
  34. package/dist/heart/attachments/types.js +93 -0
  35. package/dist/heart/auth/auth-flow.js +479 -0
  36. package/dist/heart/background-operations.js +281 -0
  37. package/dist/heart/bundle-state.js +168 -0
  38. package/dist/heart/commitments.js +111 -0
  39. package/dist/heart/config-registry.js +304 -0
  40. package/dist/heart/config.js +114 -118
  41. package/dist/heart/core.js +925 -246
  42. package/dist/heart/cross-chat-delivery.js +3 -18
  43. package/dist/heart/daemon/agent-config-check.js +512 -0
  44. package/dist/heart/daemon/agent-discovery.js +102 -3
  45. package/dist/heart/daemon/agent-service.js +522 -0
  46. package/dist/heart/daemon/agentic-repair.js +554 -0
  47. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  48. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  49. package/dist/heart/daemon/cadence.js +70 -0
  50. package/dist/heart/daemon/cli-defaults.js +665 -0
  51. package/dist/heart/daemon/cli-exec.js +7565 -0
  52. package/dist/heart/daemon/cli-help.js +498 -0
  53. package/dist/heart/daemon/cli-parse.js +1590 -0
  54. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  55. package/dist/heart/daemon/cli-render.js +775 -0
  56. package/dist/heart/daemon/cli-types.js +8 -0
  57. package/dist/heart/daemon/connect-bay.js +323 -0
  58. package/dist/heart/daemon/daemon-cli.js +29 -1672
  59. package/dist/heart/daemon/daemon-entry.js +417 -2
  60. package/dist/heart/daemon/daemon-health.js +183 -0
  61. package/dist/heart/daemon/daemon-rollup.js +58 -0
  62. package/dist/heart/daemon/daemon-runtime-sync.js +87 -13
  63. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  64. package/dist/heart/daemon/daemon.js +796 -71
  65. package/dist/heart/daemon/dns-workflow.js +394 -0
  66. package/dist/heart/daemon/doctor-types.js +8 -0
  67. package/dist/heart/daemon/doctor.js +844 -0
  68. package/dist/heart/daemon/drift-detection.js +146 -0
  69. package/dist/heart/daemon/health-monitor.js +122 -1
  70. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  71. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  72. package/dist/heart/daemon/http-health-probe.js +80 -0
  73. package/dist/heart/daemon/human-command-screens.js +234 -0
  74. package/dist/heart/daemon/human-readiness.js +114 -0
  75. package/dist/heart/daemon/inner-status.js +102 -0
  76. package/dist/heart/daemon/interactive-repair.js +394 -0
  77. package/dist/heart/daemon/launchd.js +37 -8
  78. package/dist/heart/daemon/log-tailer.js +82 -12
  79. package/dist/heart/daemon/logs-prune.js +110 -0
  80. package/dist/heart/daemon/mcp-canary.js +297 -0
  81. package/dist/heart/daemon/message-router.js +2 -2
  82. package/dist/heart/daemon/os-cron-deps.js +135 -0
  83. package/dist/heart/daemon/os-cron.js +14 -12
  84. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  85. package/dist/heart/daemon/ouro-entry.js +3 -1
  86. package/dist/heart/daemon/process-manager.js +375 -33
  87. package/dist/heart/daemon/provider-discovery.js +137 -0
  88. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  89. package/dist/heart/daemon/pulse.js +475 -0
  90. package/dist/heart/daemon/readiness-repair.js +365 -0
  91. package/dist/heart/daemon/run-hooks.js +2 -0
  92. package/dist/heart/daemon/runtime-logging.js +67 -16
  93. package/dist/heart/daemon/runtime-metadata.js +3 -31
  94. package/dist/heart/daemon/safe-mode.js +161 -0
  95. package/dist/heart/daemon/sense-manager.js +353 -38
  96. package/dist/heart/daemon/session-id-resolver.js +131 -0
  97. package/dist/heart/daemon/skill-management-installer.js +94 -0
  98. package/dist/heart/daemon/socket-client.js +158 -11
  99. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  100. package/dist/heart/daemon/startup-tui.js +330 -0
  101. package/dist/heart/daemon/task-scheduler.js +3 -25
  102. package/dist/heart/daemon/terminal-ui.js +499 -0
  103. package/dist/heart/daemon/thoughts.js +162 -17
  104. package/dist/heart/daemon/up-progress.js +366 -0
  105. package/dist/heart/daemon/vault-items.js +56 -0
  106. package/dist/heart/delegation.js +1 -1
  107. package/dist/heart/habits/habit-migration.js +189 -0
  108. package/dist/heart/habits/habit-parser.js +140 -0
  109. package/dist/heart/habits/habit-runtime-state.js +100 -0
  110. package/dist/heart/habits/habit-scheduler.js +372 -0
  111. package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
  112. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  113. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  114. package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
  115. package/dist/heart/identity.js +200 -51
  116. package/dist/heart/kept-notes.js +357 -0
  117. package/dist/heart/kicks.js +1 -1
  118. package/dist/heart/machine-identity.js +161 -0
  119. package/dist/heart/mail-import-discovery.js +353 -0
  120. package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
  121. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  122. package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
  123. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  124. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  125. package/dist/heart/mailbox/mailbox-http.js +99 -0
  126. package/dist/heart/mailbox/mailbox-read.js +31 -0
  127. package/dist/heart/mailbox/mailbox-types.js +27 -0
  128. package/dist/heart/mailbox/mailbox-view.js +195 -0
  129. package/dist/heart/mailbox/readers/agent-machine.js +382 -0
  130. package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
  131. package/dist/heart/mailbox/readers/mail.js +362 -0
  132. package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
  133. package/dist/heart/mailbox/readers/sessions.js +232 -0
  134. package/dist/heart/mailbox/readers/shared.js +111 -0
  135. package/dist/heart/mcp/mcp-server.js +683 -0
  136. package/dist/heart/migrate-config.js +100 -0
  137. package/dist/heart/model-capabilities.js +19 -0
  138. package/dist/heart/platform.js +81 -0
  139. package/dist/heart/provider-attempt.js +134 -0
  140. package/dist/heart/provider-binding-resolver.js +255 -0
  141. package/dist/heart/provider-credentials.js +425 -0
  142. package/dist/heart/provider-failover.js +301 -0
  143. package/dist/heart/provider-models.js +81 -0
  144. package/dist/heart/provider-ping.js +262 -0
  145. package/dist/heart/provider-state.js +216 -0
  146. package/dist/heart/provider-visibility.js +188 -0
  147. package/dist/heart/providers/anthropic-token.js +131 -0
  148. package/dist/heart/providers/anthropic.js +139 -52
  149. package/dist/heart/providers/azure.js +97 -13
  150. package/dist/heart/providers/error-classification.js +127 -0
  151. package/dist/heart/providers/github-copilot.js +145 -0
  152. package/dist/heart/providers/minimax-vlm.js +189 -0
  153. package/dist/heart/providers/minimax.js +26 -8
  154. package/dist/heart/providers/openai-codex.js +55 -40
  155. package/dist/heart/runtime-capability-check.js +170 -0
  156. package/dist/heart/runtime-credentials.js +367 -0
  157. package/dist/heart/runtime-cwd.js +87 -0
  158. package/dist/heart/sense-truth.js +11 -4
  159. package/dist/heart/session-activity.js +43 -22
  160. package/dist/heart/session-events.js +1149 -0
  161. package/dist/heart/session-playback-cli-main.js +5 -0
  162. package/dist/heart/session-playback-cli.js +36 -0
  163. package/dist/heart/session-playback.js +231 -0
  164. package/dist/heart/session-stats-cli-main.js +5 -0
  165. package/dist/heart/session-stats.js +182 -0
  166. package/dist/heart/session-transcript.js +243 -0
  167. package/dist/heart/start-of-turn-packet.js +345 -0
  168. package/dist/heart/streaming.js +44 -27
  169. package/dist/heart/sync-classification.js +176 -0
  170. package/dist/heart/sync.js +449 -0
  171. package/dist/heart/target-resolution.js +9 -5
  172. package/dist/heart/tempo.js +93 -0
  173. package/dist/heart/temporal-view.js +41 -0
  174. package/dist/heart/timeouts.js +101 -0
  175. package/dist/heart/tool-activity-callbacks.js +59 -0
  176. package/dist/heart/tool-description.js +139 -0
  177. package/dist/heart/tool-friction.js +55 -0
  178. package/dist/heart/tool-loop.js +200 -0
  179. package/dist/heart/turn-context.js +381 -0
  180. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  181. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  182. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  183. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  184. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  185. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  186. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  187. package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
  188. package/dist/mailbox-ui/assets/index-Cm51CY9W.js +61 -0
  189. package/dist/mailbox-ui/index.html +15 -0
  190. package/dist/mailroom/attention.js +167 -0
  191. package/dist/mailroom/autonomy.js +209 -0
  192. package/dist/mailroom/blob-store.js +674 -0
  193. package/dist/mailroom/body-cache.js +61 -0
  194. package/dist/mailroom/core.js +720 -0
  195. package/dist/mailroom/entry.js +160 -0
  196. package/dist/mailroom/file-store.js +430 -0
  197. package/dist/mailroom/mbox-import.js +383 -0
  198. package/dist/mailroom/outbound.js +380 -0
  199. package/dist/mailroom/policy.js +263 -0
  200. package/dist/mailroom/reader.js +233 -0
  201. package/dist/mailroom/search-cache.js +256 -0
  202. package/dist/mailroom/search-relevance.js +319 -0
  203. package/dist/mailroom/smtp-ingress.js +176 -0
  204. package/dist/mailroom/source-state.js +176 -0
  205. package/dist/mailroom/thread.js +109 -0
  206. package/dist/mailroom/travel-extract.js +89 -0
  207. package/dist/mind/bundle-manifest.js +7 -1
  208. package/dist/mind/context.js +165 -101
  209. package/dist/mind/diary-integrity.js +60 -0
  210. package/dist/mind/{memory.js → diary.js} +62 -75
  211. package/dist/mind/embedding-provider.js +60 -0
  212. package/dist/mind/file-state.js +179 -0
  213. package/dist/mind/friends/channel.js +30 -0
  214. package/dist/mind/friends/resolver.js +54 -2
  215. package/dist/mind/friends/store-file.js +39 -3
  216. package/dist/mind/friends/types.js +2 -2
  217. package/dist/mind/journal-index.js +161 -0
  218. package/dist/mind/note-search.js +268 -0
  219. package/dist/mind/obligation-steering.js +221 -0
  220. package/dist/mind/pending.js +4 -0
  221. package/dist/mind/prompt-refresh.js +3 -2
  222. package/dist/mind/prompt.js +995 -123
  223. package/dist/mind/provenance-trust.js +26 -0
  224. package/dist/mind/scrutiny.js +173 -0
  225. package/dist/nerves/cli-logging.js +7 -1
  226. package/dist/nerves/coverage/audit-rules.js +15 -6
  227. package/dist/nerves/coverage/audit.js +28 -2
  228. package/dist/nerves/coverage/cli.js +1 -1
  229. package/dist/nerves/coverage/contract.js +5 -5
  230. package/dist/nerves/coverage/file-completeness.js +139 -5
  231. package/dist/nerves/coverage/run-artifacts.js +1 -1
  232. package/dist/nerves/event-buffer.js +111 -0
  233. package/dist/nerves/index.js +224 -4
  234. package/dist/nerves/observation.js +20 -0
  235. package/dist/nerves/redact.js +79 -0
  236. package/dist/nerves/review/cli-main.js +5 -0
  237. package/dist/nerves/review/cli.js +156 -0
  238. package/dist/nerves/review/core.js +152 -0
  239. package/dist/nerves/runtime.js +5 -1
  240. package/dist/repertoire/ado-client.js +15 -56
  241. package/dist/repertoire/ado-semantic.js +11 -10
  242. package/dist/repertoire/api-client.js +97 -0
  243. package/dist/repertoire/bitwarden-store.js +816 -0
  244. package/dist/repertoire/bundle-templates.js +72 -0
  245. package/dist/repertoire/bw-installer.js +180 -0
  246. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  247. package/dist/repertoire/coding/context-pack.js +330 -0
  248. package/dist/repertoire/coding/feedback.js +197 -30
  249. package/dist/repertoire/coding/manager.js +158 -9
  250. package/dist/repertoire/coding/spawner.js +55 -9
  251. package/dist/repertoire/coding/tools.js +170 -7
  252. package/dist/repertoire/commerce-errors.js +109 -0
  253. package/dist/repertoire/commerce-self-test.js +156 -0
  254. package/dist/repertoire/credential-access.js +111 -0
  255. package/dist/repertoire/duffel-client.js +185 -0
  256. package/dist/repertoire/github-client.js +14 -55
  257. package/dist/repertoire/graph-client.js +11 -52
  258. package/dist/repertoire/guardrails.js +396 -0
  259. package/dist/repertoire/mcp-client.js +295 -0
  260. package/dist/repertoire/mcp-manager.js +362 -0
  261. package/dist/repertoire/mcp-tools.js +63 -0
  262. package/dist/repertoire/shell-sessions.js +133 -0
  263. package/dist/repertoire/skills.js +15 -24
  264. package/dist/repertoire/stripe-client.js +131 -0
  265. package/dist/repertoire/tasks/board.js +31 -5
  266. package/dist/repertoire/tasks/fix.js +182 -0
  267. package/dist/repertoire/tasks/index.js +16 -4
  268. package/dist/repertoire/tasks/lifecycle.js +2 -2
  269. package/dist/repertoire/tasks/parser.js +3 -2
  270. package/dist/repertoire/tasks/scanner.js +194 -37
  271. package/dist/repertoire/tasks/transitions.js +16 -78
  272. package/dist/repertoire/tool-results.js +29 -0
  273. package/dist/repertoire/tools-attachments.js +317 -0
  274. package/dist/repertoire/tools-base.js +47 -1075
  275. package/dist/repertoire/tools-bluebubbles.js +1 -0
  276. package/dist/repertoire/tools-bridge.js +142 -0
  277. package/dist/repertoire/tools-bundle.js +984 -0
  278. package/dist/repertoire/tools-config.js +185 -0
  279. package/dist/repertoire/tools-continuity.js +248 -0
  280. package/dist/repertoire/tools-credential.js +381 -0
  281. package/dist/repertoire/tools-files.js +342 -0
  282. package/dist/repertoire/tools-flight.js +224 -0
  283. package/dist/repertoire/tools-flow.js +119 -0
  284. package/dist/repertoire/tools-github.js +1 -7
  285. package/dist/repertoire/tools-mail.js +1857 -0
  286. package/dist/repertoire/tools-notes.js +421 -0
  287. package/dist/repertoire/tools-session.js +750 -0
  288. package/dist/repertoire/tools-shell.js +120 -0
  289. package/dist/repertoire/tools-stripe.js +180 -0
  290. package/dist/repertoire/tools-surface.js +243 -0
  291. package/dist/repertoire/tools-teams.js +9 -39
  292. package/dist/repertoire/tools-travel.js +125 -0
  293. package/dist/repertoire/tools-trip.js +604 -0
  294. package/dist/repertoire/tools-user-profile.js +144 -0
  295. package/dist/repertoire/tools-vault.js +40 -0
  296. package/dist/repertoire/tools.js +108 -100
  297. package/dist/repertoire/travel-api-client.js +360 -0
  298. package/dist/repertoire/user-profile.js +131 -0
  299. package/dist/repertoire/vault-setup.js +246 -0
  300. package/dist/repertoire/vault-unlock.js +561 -0
  301. package/dist/scripts/claude-code-hook.js +41 -0
  302. package/dist/scripts/claude-code-stop-hook.js +47 -0
  303. package/dist/senses/attention-queue.js +116 -0
  304. package/dist/senses/bluebubbles/active-turns.js +216 -0
  305. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  306. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  307. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  308. package/dist/senses/bluebubbles/entry.js +77 -0
  309. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  310. package/dist/senses/bluebubbles/index.js +2305 -0
  311. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  312. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  313. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  314. package/dist/senses/bluebubbles/processed-log.js +133 -0
  315. package/dist/senses/bluebubbles/replay.js +137 -0
  316. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  317. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  318. package/dist/senses/cli/bracketed-paste.js +82 -0
  319. package/dist/senses/cli/image-paste.js +287 -0
  320. package/dist/senses/cli/image-ref-navigation.js +75 -0
  321. package/dist/senses/cli/ink-app.js +156 -0
  322. package/dist/senses/cli/inline-diff.js +64 -0
  323. package/dist/senses/cli/input-keys.js +174 -0
  324. package/dist/senses/cli/kill-ring.js +86 -0
  325. package/dist/senses/cli/message-list.js +51 -0
  326. package/dist/senses/cli/ouro-tui.js +607 -0
  327. package/dist/senses/cli/spinner-imperative.js +135 -0
  328. package/dist/senses/cli/spinner.js +101 -0
  329. package/dist/senses/cli/status-line.js +60 -0
  330. package/dist/senses/cli/streaming-markdown.js +526 -0
  331. package/dist/senses/cli/tool-display.js +85 -0
  332. package/dist/senses/cli/tool-render.js +85 -0
  333. package/dist/senses/cli/tui-store.js +240 -0
  334. package/dist/senses/cli/virtual-list.js +35 -0
  335. package/dist/senses/cli-entry.js +60 -8
  336. package/dist/senses/cli-layout.js +187 -0
  337. package/dist/senses/cli.js +520 -209
  338. package/dist/senses/commands.js +66 -3
  339. package/dist/senses/habit-turn-message.js +108 -0
  340. package/dist/senses/inner-dialog-worker.js +175 -21
  341. package/dist/senses/inner-dialog.js +330 -27
  342. package/dist/senses/mail-entry.js +66 -0
  343. package/dist/senses/mail.js +379 -0
  344. package/dist/senses/pipeline.js +569 -182
  345. package/dist/senses/proactive-content-guard.js +51 -0
  346. package/dist/senses/shared-turn.js +248 -0
  347. package/dist/senses/surface-tool.js +68 -0
  348. package/dist/senses/teams-entry.js +60 -8
  349. package/dist/senses/teams.js +387 -98
  350. package/dist/senses/trust-gate.js +100 -5
  351. package/dist/trips/core.js +138 -0
  352. package/dist/trips/store.js +146 -0
  353. package/package.json +38 -7
  354. package/skills/agent-commerce.md +106 -0
  355. package/skills/browser-navigation.md +117 -0
  356. package/skills/commerce-setup-guide.md +116 -0
  357. package/skills/commerce-setup.md +84 -0
  358. package/skills/configure-dev-tools.md +101 -0
  359. package/skills/travel-planning.md +138 -0
  360. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  361. package/dist/heart/daemon/subagent-installer.js +0 -166
  362. package/dist/heart/session-recall.js +0 -116
  363. package/dist/mind/associative-recall.js +0 -209
  364. package/dist/senses/bluebubbles-entry.js +0 -13
  365. package/dist/senses/bluebubbles.js +0 -1177
  366. package/dist/senses/debug-activity.js +0 -148
  367. package/subagents/README.md +0 -86
  368. package/subagents/work-doer.md +0 -237
  369. package/subagents/work-merger.md +0 -618
  370. package/subagents/work-planner.md +0 -390
  371. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  372. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  373. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  374. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  375. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  376. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  377. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  378. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  379. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  380. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  381. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  382. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  383. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  384. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  385. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  386. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,674 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AzureBlobMailroomStore = void 0;
4
+ exports.decryptBlobMessages = decryptBlobMessages;
5
+ const runtime_1 = require("../nerves/runtime");
6
+ const core_1 = require("./core");
7
+ const search_cache_1 = require("./search-cache");
8
+ const MESSAGE_INDEX_PREFIX = "message-index";
9
+ const MESSAGE_INDEX_SORT_MAX_MS = 9_999_999_999_999;
10
+ const MESSAGE_INDEX_SORT_WIDTH = 13;
11
+ const MESSAGE_INDEX_NO_SOURCE = "~";
12
+ // Bumped from 20s after Slugger's HEY-corpus validation revealed that
13
+ // real-world mail bodies (HTML-heavy booking confirmations, MBOX-imported
14
+ // large messages) regularly exceed the original 20s ceiling. 60s with 2
15
+ // attempts = 120s max wait, which is closer to what Azure Blob actually
16
+ // needs for cold reads of a few-MB message body. Index reads still fit
17
+ // comfortably in this budget.
18
+ const DEFAULT_BLOB_OPERATION_TIMEOUT_MS = 60_000;
19
+ const DEFAULT_BLOB_DOWNLOAD_ATTEMPTS = 2;
20
+ const DEFAULT_MESSAGE_FETCH_CONCURRENCY = 20;
21
+ const DEFAULT_MESSAGE_INDEX_BACKFILL_CONCURRENCY = 8;
22
+ const MESSAGE_LIST_SCAN_CONCURRENCY = 32;
23
+ function compareNewestFirst(left, right) {
24
+ return Date.parse(right.receivedAt) - Date.parse(left.receivedAt);
25
+ }
26
+ function compareCandidatesNewestFirst(left, right) {
27
+ return Date.parse(right.lastSeenAt) - Date.parse(left.lastSeenAt);
28
+ }
29
+ function blobText(value) {
30
+ return Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf-8");
31
+ }
32
+ function applyOptionalLimit(items, limit) {
33
+ return typeof limit === "number" ? items.slice(0, limit) : items;
34
+ }
35
+ function positiveInteger(value, fallback) {
36
+ if (typeof value !== "number" || !Number.isFinite(value))
37
+ return fallback;
38
+ const normalized = Math.floor(value);
39
+ return normalized > 0 ? normalized : fallback;
40
+ }
41
+ function blobClientName(blob) {
42
+ return typeof blob.name === "string" && blob.name.trim().length > 0 ? blob.name : "<unknown-blob>";
43
+ }
44
+ function timeoutSignal(timeoutMs) {
45
+ if (typeof AbortSignal.timeout === "function") {
46
+ return {
47
+ signal: AbortSignal.timeout(timeoutMs),
48
+ dispose() {
49
+ return undefined;
50
+ },
51
+ };
52
+ }
53
+ const controller = new AbortController();
54
+ const timer = setTimeout(() => controller.abort(new Error(`The operation timed out after ${timeoutMs}ms`)), timeoutMs);
55
+ return {
56
+ signal: controller.signal,
57
+ dispose() {
58
+ clearTimeout(timer);
59
+ },
60
+ };
61
+ }
62
+ async function withBlobOperationTimeout(timeoutMs, operation) {
63
+ const timeout = timeoutSignal(timeoutMs);
64
+ try {
65
+ return await operation(timeout.signal);
66
+ }
67
+ finally {
68
+ timeout.dispose();
69
+ }
70
+ }
71
+ function normalizeBlobOperationError(action, blob, timeoutMs, error) {
72
+ const message = error instanceof Error ? error.message : String(error);
73
+ if ((error instanceof Error && error.name === "AbortError") || message.toLowerCase().includes("aborted")) {
74
+ return new Error(`${action} ${blobClientName(blob)} timed out after ${timeoutMs}ms`);
75
+ }
76
+ return new Error(`${action} ${blobClientName(blob)} failed: ${message}`);
77
+ }
78
+ function isRetryableBlobDownloadError(error) {
79
+ const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
80
+ return message.includes("timed out") ||
81
+ message.includes("abort") ||
82
+ message.includes("econnreset") ||
83
+ message.includes("etimedout") ||
84
+ message.includes("socket closed");
85
+ }
86
+ function isBlobNotFoundError(error) {
87
+ const maybeStatus = typeof error === "object" && error !== null && "statusCode" in error
88
+ ? error.statusCode
89
+ : undefined;
90
+ if (maybeStatus === 404)
91
+ return true;
92
+ const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
93
+ return message.includes("blobnotfound") ||
94
+ message.includes("the specified blob does not exist") ||
95
+ message.includes("missing blob");
96
+ }
97
+ async function downloadJson(blob, timeoutMs) {
98
+ if (!await blob.exists())
99
+ return null;
100
+ let lastError = null;
101
+ for (let attempt = 1; attempt <= DEFAULT_BLOB_DOWNLOAD_ATTEMPTS; attempt += 1) {
102
+ try {
103
+ const buffer = await withBlobOperationTimeout(timeoutMs, (abortSignal) => {
104
+ return blob.downloadToBuffer(undefined, undefined, { abortSignal });
105
+ });
106
+ return JSON.parse(buffer.toString("utf-8"));
107
+ }
108
+ catch (error) {
109
+ lastError = error;
110
+ if (attempt >= DEFAULT_BLOB_DOWNLOAD_ATTEMPTS || !isRetryableBlobDownloadError(error))
111
+ break;
112
+ }
113
+ }
114
+ throw normalizeBlobOperationError("download", blob, timeoutMs, lastError);
115
+ }
116
+ async function downloadIndexedJson(blob, timeoutMs) {
117
+ let lastError = null;
118
+ for (let attempt = 1; attempt <= DEFAULT_BLOB_DOWNLOAD_ATTEMPTS; attempt += 1) {
119
+ try {
120
+ const buffer = await withBlobOperationTimeout(timeoutMs, (abortSignal) => {
121
+ return blob.downloadToBuffer(undefined, undefined, { abortSignal });
122
+ });
123
+ return JSON.parse(buffer.toString("utf-8"));
124
+ }
125
+ catch (error) {
126
+ if (isBlobNotFoundError(error))
127
+ return null;
128
+ lastError = error;
129
+ if (attempt >= DEFAULT_BLOB_DOWNLOAD_ATTEMPTS || !isRetryableBlobDownloadError(error))
130
+ break;
131
+ }
132
+ }
133
+ throw normalizeBlobOperationError("download", blob, timeoutMs, lastError);
134
+ }
135
+ async function uploadJson(blob, value, timeoutMs) {
136
+ try {
137
+ await withBlobOperationTimeout(timeoutMs, (abortSignal) => {
138
+ return blob.uploadData(blobText(value), { abortSignal });
139
+ });
140
+ }
141
+ catch (error) {
142
+ throw normalizeBlobOperationError("upload", blob, timeoutMs, error);
143
+ }
144
+ }
145
+ async function mapWithConcurrency(items, concurrency, worker) {
146
+ if (items.length === 0)
147
+ return [];
148
+ const results = new Array(items.length);
149
+ let nextIndex = 0;
150
+ const workerLoop = async () => {
151
+ while (true) {
152
+ const current = nextIndex;
153
+ nextIndex += 1;
154
+ if (current >= items.length)
155
+ return;
156
+ results[current] = await worker(items[current], current);
157
+ }
158
+ };
159
+ await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, async () => workerLoop()));
160
+ return results;
161
+ }
162
+ function encodeSourceToken(source) {
163
+ return source ? encodeURIComponent(source.toLowerCase()) : MESSAGE_INDEX_NO_SOURCE;
164
+ }
165
+ function decodeSourceToken(token) {
166
+ return token === MESSAGE_INDEX_NO_SOURCE ? undefined : decodeURIComponent(token);
167
+ }
168
+ function parseSortMs(receivedAt) {
169
+ const parsed = Date.parse(receivedAt);
170
+ if (!Number.isFinite(parsed))
171
+ return 0;
172
+ return Math.max(0, Math.min(MESSAGE_INDEX_SORT_MAX_MS, parsed));
173
+ }
174
+ function messageIndexPrefix(agentId) {
175
+ return `${MESSAGE_INDEX_PREFIX}/${agentId}/`;
176
+ }
177
+ function messageIndexBlobName(message) {
178
+ const sortKey = String(MESSAGE_INDEX_SORT_MAX_MS - parseSortMs(message.receivedAt)).padStart(MESSAGE_INDEX_SORT_WIDTH, "0");
179
+ return `${messageIndexPrefix(message.agentId)}${sortKey}__${message.compartmentKind}__${message.placement}__${encodeSourceToken(message.source)}__${message.id}.json`;
180
+ }
181
+ function messageIndexRecord(message) {
182
+ return {
183
+ schemaVersion: 1,
184
+ id: message.id,
185
+ agentId: message.agentId,
186
+ compartmentKind: message.compartmentKind,
187
+ placement: message.placement,
188
+ ...(message.source ? { source: message.source } : {}),
189
+ receivedAt: message.receivedAt,
190
+ };
191
+ }
192
+ function parseMessageIndexBlobName(name) {
193
+ if (!name.startsWith(`${MESSAGE_INDEX_PREFIX}/`) || !name.endsWith(".json"))
194
+ return null;
195
+ const parts = name.split("/");
196
+ if (parts.length !== 3)
197
+ return null;
198
+ const agentId = parts[1];
199
+ const stem = parts[2].slice(0, -5);
200
+ const [sortKey, compartmentKind, placement, sourceToken, ...idParts] = stem.split("__");
201
+ if (!sortKey || !compartmentKind || !placement || !sourceToken || idParts.length === 0)
202
+ return null;
203
+ if (compartmentKind !== "native" && compartmentKind !== "delegated")
204
+ return null;
205
+ const receivedAtMs = MESSAGE_INDEX_SORT_MAX_MS - Number.parseInt(sortKey, 10);
206
+ return {
207
+ schemaVersion: 1,
208
+ id: idParts.join("__"),
209
+ agentId,
210
+ compartmentKind,
211
+ placement: placement,
212
+ ...(decodeSourceToken(sourceToken) ? { source: decodeSourceToken(sourceToken) } : {}),
213
+ receivedAt: Number.isFinite(receivedAtMs) ? new Date(receivedAtMs).toISOString() : new Date(0).toISOString(),
214
+ };
215
+ }
216
+ function sourceMatchesFilter(source, filter) {
217
+ if (!filter)
218
+ return true;
219
+ if (!source)
220
+ return false;
221
+ return source.toLowerCase() === filter.toLowerCase();
222
+ }
223
+ function messageMatchesFilters(message, filters) {
224
+ return message.agentId === filters.agentId &&
225
+ (filters.placement ? message.placement === filters.placement : true) &&
226
+ (filters.compartmentKind ? message.compartmentKind === filters.compartmentKind : true) &&
227
+ sourceMatchesFilter(message.source, filters.source);
228
+ }
229
+ class AzureBlobMailroomStore {
230
+ serviceClient;
231
+ containerName;
232
+ mailSearchCache;
233
+ blobOperationTimeoutMs;
234
+ messageFetchConcurrency;
235
+ backfillConcurrency;
236
+ containerReady = null;
237
+ constructor(options) {
238
+ this.serviceClient = options.serviceClient;
239
+ this.containerName = options.containerName;
240
+ this.mailSearchCache = options.mailSearchCache ?? null;
241
+ this.blobOperationTimeoutMs = positiveInteger(options.blobOperationTimeoutMs, DEFAULT_BLOB_OPERATION_TIMEOUT_MS);
242
+ this.messageFetchConcurrency = positiveInteger(options.messageFetchConcurrency, DEFAULT_MESSAGE_FETCH_CONCURRENCY);
243
+ this.backfillConcurrency = positiveInteger(options.backfillConcurrency, DEFAULT_MESSAGE_INDEX_BACKFILL_CONCURRENCY);
244
+ (0, runtime_1.emitNervesEvent)({
245
+ component: "senses",
246
+ event: "senses.mail_blob_store_init",
247
+ message: "azure blob mailroom store initialized",
248
+ meta: { containerName: this.containerName },
249
+ });
250
+ }
251
+ get container() {
252
+ return this.serviceClient.getContainerClient(this.containerName);
253
+ }
254
+ async ensureContainer() {
255
+ if (!this.containerReady) {
256
+ this.containerReady = this.container.createIfNotExists().then(() => undefined);
257
+ }
258
+ await this.containerReady;
259
+ }
260
+ messageBlob(id) {
261
+ return this.container.getBlockBlobClient(`messages/${id}.json`);
262
+ }
263
+ messageIndexBlob(name) {
264
+ return this.container.getBlockBlobClient(name);
265
+ }
266
+ candidateBlob(id) {
267
+ return this.container.getBlockBlobClient(`candidates/${id}.json`);
268
+ }
269
+ rawBlob(objectName) {
270
+ return this.container.getBlockBlobClient(objectName);
271
+ }
272
+ decisionsBlob(agentId) {
273
+ return this.container.getBlockBlobClient(`decisions/${agentId}.json`);
274
+ }
275
+ accessLogBlob(agentId) {
276
+ return this.container.getBlockBlobClient(`access-log/${agentId}.jsonl`);
277
+ }
278
+ outboundBlob(id) {
279
+ return this.container.getBlockBlobClient(`outbound/${id}.json`);
280
+ }
281
+ async putMessageIndex(message) {
282
+ await uploadJson(this.messageIndexBlob(messageIndexBlobName(message)), messageIndexRecord(message), this.blobOperationTimeoutMs);
283
+ }
284
+ async removeMessageIndex(message) {
285
+ await this.messageIndexBlob(messageIndexBlobName(message)).deleteIfExists();
286
+ }
287
+ upsertMailSearchCache(message, privateEnvelope) {
288
+ if (!this.mailSearchCache)
289
+ return;
290
+ (0, search_cache_1.upsertMailSearchCacheDocument)(message, privateEnvelope, this.mailSearchCache);
291
+ }
292
+ syncMailSearchCache(message) {
293
+ if (!this.mailSearchCache)
294
+ return;
295
+ (0, search_cache_1.syncMailSearchCacheMetadata)(message, this.mailSearchCache);
296
+ }
297
+ async listMessagesLegacy(filters) {
298
+ const messageBlobNames = [];
299
+ for await (const item of this.container.listBlobsFlat({ prefix: "messages/" })) {
300
+ messageBlobNames.push(item.name);
301
+ }
302
+ const matches = [];
303
+ let nextIndex = 0;
304
+ const worker = async () => {
305
+ while (nextIndex < messageBlobNames.length) {
306
+ const current = messageBlobNames[nextIndex];
307
+ nextIndex += 1;
308
+ const message = await downloadJson(this.container.getBlockBlobClient(current), this.blobOperationTimeoutMs);
309
+ if (!message || !messageMatchesFilters(message, filters))
310
+ continue;
311
+ matches.push(message);
312
+ matches.sort(compareNewestFirst);
313
+ if (typeof filters.limit === "number" && matches.length > filters.limit)
314
+ matches.length = filters.limit;
315
+ }
316
+ };
317
+ await Promise.all(Array.from({ length: Math.min(MESSAGE_LIST_SCAN_CONCURRENCY, Math.max(messageBlobNames.length, 1)) }, async () => worker()));
318
+ return applyOptionalLimit(matches.sort(compareNewestFirst), filters.limit);
319
+ }
320
+ async listMessageIndexRecords(filters) {
321
+ await this.ensureContainer();
322
+ const records = [];
323
+ let sawIndex = false;
324
+ for await (const item of this.container.listBlobsFlat({ prefix: messageIndexPrefix(filters.agentId) })) {
325
+ sawIndex = true;
326
+ const parsed = parseMessageIndexBlobName(item.name);
327
+ if (!parsed || !messageMatchesFilters(parsed, filters))
328
+ continue;
329
+ records.push(parsed);
330
+ if (typeof filters.limit === "number" && records.length >= filters.limit)
331
+ break;
332
+ }
333
+ if (!sawIndex)
334
+ return null;
335
+ const sorted = records.sort((left, right) => Date.parse(right.receivedAt) - Date.parse(left.receivedAt));
336
+ (0, runtime_1.emitNervesEvent)({
337
+ component: "senses",
338
+ event: "senses.mail_blob_store_message_indexes_listed",
339
+ message: "azure blob mailroom store listed message indexes",
340
+ meta: { agentId: filters.agentId, count: sorted.length },
341
+ });
342
+ return applyOptionalLimit(sorted, filters.limit);
343
+ }
344
+ async listMessagesFromIndexes(filters) {
345
+ const records = await this.listMessageIndexRecords(filters);
346
+ if (records === null)
347
+ return null;
348
+ const messageIds = records.map((record) => record.id);
349
+ const messages = (await mapWithConcurrency(messageIds, this.messageFetchConcurrency, async (id) => {
350
+ return downloadJson(this.messageBlob(id), this.blobOperationTimeoutMs);
351
+ }))
352
+ .filter((message) => message !== null)
353
+ .filter((message) => messageMatchesFilters(message, filters))
354
+ .sort(compareNewestFirst);
355
+ return applyOptionalLimit(messages, filters.limit);
356
+ }
357
+ async backfillMessageIndexes(agentId, onProgress) {
358
+ await this.ensureContainer();
359
+ const messageBlobNames = [];
360
+ for await (const item of this.container.listBlobsFlat({ prefix: "messages/" })) {
361
+ messageBlobNames.push(item.name);
362
+ }
363
+ let indexed = 0;
364
+ const failures = [];
365
+ let scanned = 0;
366
+ let nextIndex = 0;
367
+ const worker = async () => {
368
+ while (nextIndex < messageBlobNames.length) {
369
+ const current = messageBlobNames[nextIndex];
370
+ nextIndex += 1;
371
+ try {
372
+ const message = await downloadJson(this.container.getBlockBlobClient(current), this.blobOperationTimeoutMs);
373
+ if (!message)
374
+ continue;
375
+ if (agentId && message.agentId !== agentId)
376
+ continue;
377
+ await uploadJson(this.messageIndexBlob(messageIndexBlobName(message)), messageIndexRecord(message), this.blobOperationTimeoutMs);
378
+ indexed += 1;
379
+ }
380
+ catch (error) {
381
+ failures.push(error instanceof Error ? error.message : String(error));
382
+ }
383
+ finally {
384
+ scanned += 1;
385
+ onProgress?.({ scanned, indexed, failures: failures.length, total: messageBlobNames.length });
386
+ }
387
+ }
388
+ };
389
+ await Promise.all(Array.from({ length: Math.min(this.backfillConcurrency, Math.max(messageBlobNames.length, 1)) }, async () => worker()));
390
+ if (failures.length > 0) {
391
+ const sample = failures.slice(0, 3).join("; ");
392
+ throw new Error(`hosted message index backfill incomplete after indexing ${indexed} message(s); ${failures.length} blob operation(s) failed. first failure(s): ${sample}. rerun the command to retry remaining messages.`);
393
+ }
394
+ (0, runtime_1.emitNervesEvent)({
395
+ component: "senses",
396
+ event: "senses.mail_blob_index_backfilled",
397
+ message: "azure blob mailroom message indexes backfilled",
398
+ meta: { agentId: agentId ?? null, indexed },
399
+ });
400
+ return indexed;
401
+ }
402
+ async putRawMessage(input) {
403
+ await this.ensureContainer();
404
+ const { message, rawPayload, privateEnvelope, candidate } = await (0, core_1.buildStoredMailMessage)(input);
405
+ const messageBlob = this.messageBlob(message.id);
406
+ let existing = null;
407
+ try {
408
+ existing = await downloadJson(messageBlob, this.blobOperationTimeoutMs);
409
+ }
410
+ catch (error) {
411
+ if (isRetryableBlobDownloadError(error) && await messageBlob.exists().catch(() => false)) {
412
+ (0, runtime_1.emitNervesEvent)({
413
+ level: "warn",
414
+ component: "senses",
415
+ event: "senses.mail_blob_store_dedupe_degraded",
416
+ message: "azure blob mailroom store treated an unreadable existing message as a duplicate",
417
+ meta: {
418
+ id: message.id,
419
+ agentId: message.agentId,
420
+ error: error instanceof Error ? error.message : String(error),
421
+ },
422
+ });
423
+ return { created: false, message };
424
+ }
425
+ throw error;
426
+ }
427
+ if (existing) {
428
+ this.upsertMailSearchCache(existing, privateEnvelope);
429
+ await this.putMessageIndex(existing);
430
+ (0, runtime_1.emitNervesEvent)({
431
+ component: "senses",
432
+ event: "senses.mail_blob_store_dedupe",
433
+ message: "azure blob mailroom store deduped existing message",
434
+ meta: { id: message.id, agentId: message.agentId },
435
+ });
436
+ return { created: false, message: existing };
437
+ }
438
+ await this.rawBlob(message.rawObject).uploadData(blobText(rawPayload));
439
+ await this.messageBlob(message.id).uploadData(blobText(message));
440
+ await this.putMessageIndex(message);
441
+ this.upsertMailSearchCache(message, privateEnvelope);
442
+ if (candidate) {
443
+ await this.candidateBlob(candidate.id).uploadData(blobText(candidate));
444
+ }
445
+ (0, runtime_1.emitNervesEvent)({
446
+ component: "senses",
447
+ event: "senses.mail_blob_store_message_written",
448
+ message: "azure blob mailroom store wrote message",
449
+ meta: { id: message.id, agentId: message.agentId, candidate: candidate !== undefined },
450
+ });
451
+ return { created: true, message };
452
+ }
453
+ async getMessage(id) {
454
+ await this.ensureContainer();
455
+ const message = await downloadJson(this.messageBlob(id), this.blobOperationTimeoutMs);
456
+ (0, runtime_1.emitNervesEvent)({
457
+ component: "senses",
458
+ event: "senses.mail_blob_store_message_read",
459
+ message: "azure blob mailroom store read message",
460
+ meta: { id, found: message !== null },
461
+ });
462
+ return message;
463
+ }
464
+ async getIndexedMessageById(id) {
465
+ await this.ensureContainer();
466
+ const message = await downloadIndexedJson(this.messageBlob(id), this.blobOperationTimeoutMs);
467
+ (0, runtime_1.emitNervesEvent)({
468
+ component: "senses",
469
+ event: "senses.mail_blob_store_indexed_message_read",
470
+ message: "azure blob mailroom store read message from known index",
471
+ meta: { id, found: message !== null },
472
+ });
473
+ return message;
474
+ }
475
+ async listMessages(filters) {
476
+ await this.ensureContainer();
477
+ let filtered = await this.listMessagesFromIndexes(filters);
478
+ let source = "index";
479
+ if (filtered === null) {
480
+ filtered = await this.listMessagesLegacy(filters);
481
+ source = "legacy";
482
+ }
483
+ (0, runtime_1.emitNervesEvent)({
484
+ component: "senses",
485
+ event: "senses.mail_blob_store_messages_listed",
486
+ message: "azure blob mailroom store listed messages",
487
+ meta: { agentId: filters.agentId, count: filtered.length, source },
488
+ });
489
+ return filtered;
490
+ }
491
+ async updateMessagePlacement(id, placement) {
492
+ await this.ensureContainer();
493
+ const blob = this.messageBlob(id);
494
+ const message = await downloadJson(blob, this.blobOperationTimeoutMs);
495
+ if (!message) {
496
+ (0, runtime_1.emitNervesEvent)({
497
+ component: "senses",
498
+ event: "senses.mail_blob_store_message_placement_updated",
499
+ message: "azure blob mailroom store message placement update missed",
500
+ meta: { id, placement, found: false },
501
+ });
502
+ return null;
503
+ }
504
+ const updated = { ...message, placement };
505
+ await blob.uploadData(blobText(updated));
506
+ await this.removeMessageIndex(message);
507
+ await this.putMessageIndex(updated);
508
+ this.syncMailSearchCache(updated);
509
+ (0, runtime_1.emitNervesEvent)({
510
+ component: "senses",
511
+ event: "senses.mail_blob_store_message_placement_updated",
512
+ message: "azure blob mailroom store updated message placement",
513
+ meta: { id, placement, found: true },
514
+ });
515
+ return updated;
516
+ }
517
+ async readRawPayload(objectName) {
518
+ await this.ensureContainer();
519
+ const payload = await downloadJson(this.rawBlob(objectName), this.blobOperationTimeoutMs);
520
+ (0, runtime_1.emitNervesEvent)({
521
+ component: "senses",
522
+ event: "senses.mail_blob_store_raw_read",
523
+ message: "azure blob mailroom store read raw payload",
524
+ meta: { objectName, found: payload !== null },
525
+ });
526
+ return payload;
527
+ }
528
+ async putScreenerCandidate(candidate) {
529
+ await this.ensureContainer();
530
+ await this.candidateBlob(candidate.id).uploadData(blobText(candidate));
531
+ (0, runtime_1.emitNervesEvent)({
532
+ component: "senses",
533
+ event: "senses.mail_blob_screener_candidate_written",
534
+ message: "azure blob mail screener candidate written",
535
+ meta: { id: candidate.id, agentId: candidate.agentId, status: candidate.status },
536
+ });
537
+ return candidate;
538
+ }
539
+ async updateScreenerCandidate(candidate) {
540
+ return this.putScreenerCandidate(candidate);
541
+ }
542
+ async listScreenerCandidates(filters) {
543
+ await this.ensureContainer();
544
+ const candidates = [];
545
+ for await (const item of this.container.listBlobsFlat({ prefix: "candidates/" })) {
546
+ const candidate = await downloadJson(this.container.getBlockBlobClient(item.name), this.blobOperationTimeoutMs);
547
+ if (candidate)
548
+ candidates.push(candidate);
549
+ }
550
+ const filtered = candidates
551
+ .filter((candidate) => candidate.agentId === filters.agentId)
552
+ .filter((candidate) => filters.status ? candidate.status === filters.status : true)
553
+ .filter((candidate) => filters.placement ? candidate.placement === filters.placement : true)
554
+ .sort(compareCandidatesNewestFirst)
555
+ .slice(0, filters.limit ?? 50);
556
+ (0, runtime_1.emitNervesEvent)({
557
+ component: "senses",
558
+ event: "senses.mail_blob_screener_candidates_listed",
559
+ message: "azure blob mail screener candidates listed",
560
+ meta: { agentId: filters.agentId, count: filtered.length },
561
+ });
562
+ return filtered;
563
+ }
564
+ async recordMailDecision(entry) {
565
+ await this.ensureContainer();
566
+ const complete = {
567
+ schemaVersion: 1,
568
+ ...entry,
569
+ id: entry.id ?? `decision_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
570
+ createdAt: entry.createdAt ?? new Date().toISOString(),
571
+ };
572
+ const blob = this.decisionsBlob(entry.agentId);
573
+ const existing = await downloadJson(blob, this.blobOperationTimeoutMs).catch(() => null);
574
+ const entries = Array.isArray(existing) ? existing : [];
575
+ entries.push(complete);
576
+ await blob.uploadData(blobText(entries));
577
+ (0, runtime_1.emitNervesEvent)({
578
+ component: "senses",
579
+ event: "senses.mail_blob_decision_recorded",
580
+ message: "azure blob mail decision recorded",
581
+ meta: { agentId: entry.agentId, messageId: entry.messageId, action: entry.action },
582
+ });
583
+ return complete;
584
+ }
585
+ async listMailDecisions(agentId) {
586
+ await this.ensureContainer();
587
+ const entries = await downloadJson(this.decisionsBlob(agentId), this.blobOperationTimeoutMs);
588
+ const safeEntries = Array.isArray(entries) ? entries : [];
589
+ (0, runtime_1.emitNervesEvent)({
590
+ component: "senses",
591
+ event: "senses.mail_blob_decisions_listed",
592
+ message: "azure blob mail decisions listed",
593
+ meta: { agentId, count: safeEntries.length },
594
+ });
595
+ return safeEntries;
596
+ }
597
+ async upsertMailOutbound(record) {
598
+ await this.ensureContainer();
599
+ await this.outboundBlob(record.id).uploadData(blobText(record));
600
+ (0, runtime_1.emitNervesEvent)({
601
+ component: "senses",
602
+ event: "senses.mail_blob_outbound_record_written",
603
+ message: "azure blob mail outbound record written",
604
+ meta: { agentId: record.agentId, id: record.id, status: record.status },
605
+ });
606
+ return record;
607
+ }
608
+ async getMailOutbound(id) {
609
+ await this.ensureContainer();
610
+ const record = await downloadJson(this.outboundBlob(id), this.blobOperationTimeoutMs);
611
+ (0, runtime_1.emitNervesEvent)({
612
+ component: "senses",
613
+ event: "senses.mail_blob_outbound_record_read",
614
+ message: "azure blob mail outbound record read",
615
+ meta: { id, found: record !== null },
616
+ });
617
+ return record;
618
+ }
619
+ async listMailOutbound(agentId) {
620
+ await this.ensureContainer();
621
+ const records = [];
622
+ for await (const item of this.container.listBlobsFlat({ prefix: "outbound/" })) {
623
+ const record = await downloadJson(this.container.getBlockBlobClient(item.name), this.blobOperationTimeoutMs);
624
+ if (record)
625
+ records.push(record);
626
+ }
627
+ const filtered = records
628
+ .filter((record) => record.agentId === agentId)
629
+ .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
630
+ (0, runtime_1.emitNervesEvent)({
631
+ component: "senses",
632
+ event: "senses.mail_blob_outbound_records_listed",
633
+ message: "azure blob mail outbound records listed",
634
+ meta: { agentId, count: filtered.length },
635
+ });
636
+ return filtered;
637
+ }
638
+ async recordAccess(entry) {
639
+ await this.ensureContainer();
640
+ const complete = {
641
+ ...entry,
642
+ id: `access_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
643
+ accessedAt: new Date().toISOString(),
644
+ };
645
+ const blob = this.accessLogBlob(entry.agentId);
646
+ const existing = await downloadJson(blob, this.blobOperationTimeoutMs).catch(() => null);
647
+ const entries = Array.isArray(existing) ? existing : [];
648
+ entries.push(complete);
649
+ await blob.uploadData(blobText(entries));
650
+ (0, runtime_1.emitNervesEvent)({
651
+ component: "senses",
652
+ event: "senses.mail_blob_access_recorded",
653
+ message: "azure blob mail access recorded",
654
+ meta: { agentId: entry.agentId, messageId: entry.messageId ?? null, tool: entry.tool },
655
+ });
656
+ return complete;
657
+ }
658
+ async listAccessLog(agentId) {
659
+ await this.ensureContainer();
660
+ const entries = await downloadJson(this.accessLogBlob(agentId), this.blobOperationTimeoutMs);
661
+ const safeEntries = (Array.isArray(entries) ? entries : []);
662
+ (0, runtime_1.emitNervesEvent)({
663
+ component: "senses",
664
+ event: "senses.mail_blob_access_log_listed",
665
+ message: "azure blob mail access log listed",
666
+ meta: { agentId, count: safeEntries.length },
667
+ });
668
+ return safeEntries;
669
+ }
670
+ }
671
+ exports.AzureBlobMailroomStore = AzureBlobMailroomStore;
672
+ function decryptBlobMessages(messages, privateKeys) {
673
+ return messages.map((message) => (0, core_1.decryptStoredMailMessage)(message, privateKeys));
674
+ }