@ouro.bot/cli 0.1.0-alpha.83 → 0.1.0-alpha.831

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 (647) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -23
  3. package/RepairGuide.ouro/agent.json +5 -0
  4. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  5. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  6. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  7. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  8. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  9. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  12. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  13. package/assets/bluebubbles-host +264 -0
  14. package/assets/sanctuary-host-launcher.sh +16 -0
  15. package/changelog.json +5308 -16
  16. package/deploy/unraid/Dockerfile +54 -0
  17. package/deploy/unraid/README.txt +2983 -0
  18. package/deploy/unraid/audit-container-spec.sh +4 -0
  19. package/deploy/unraid/container-runtime.json +1 -0
  20. package/deploy/unraid/docker-man-template-transaction.mjs +711 -0
  21. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  22. package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
  23. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  24. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  25. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  26. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  27. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  28. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  29. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  30. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  31. package/deploy/unraid/sanctuary-authority-installation.json +36 -0
  32. package/deploy/unraid/sanctuary-authority-service.sh +30 -0
  33. package/deploy/unraid/sanctuary-deployment-target.mjs +710 -0
  34. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  35. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2084 -0
  36. package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
  37. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  38. package/deploy/unraid/sanctuary.ouro/agent.json +66 -0
  39. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  40. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  41. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  42. package/deploy/unraid/sanctuary.ouro/mcp/media-mcp.mjs +795 -0
  43. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  44. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  45. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
  46. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +15 -0
  47. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
  48. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +15 -0
  49. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  50. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +135 -0
  51. package/deploy/unraid/sanctuary.xml +28 -0
  52. package/dist/a2a/card.js +57 -0
  53. package/dist/a2a/client.js +180 -0
  54. package/dist/a2a/config.js +50 -0
  55. package/dist/a2a/delegation-stores.js +56 -0
  56. package/dist/a2a/did-resolution.js +93 -0
  57. package/dist/a2a/identity.js +170 -0
  58. package/dist/a2a/inbound-share.js +107 -0
  59. package/dist/a2a/mission-result-wire.js +196 -0
  60. package/dist/a2a/onboarding.js +115 -0
  61. package/dist/a2a/pin-store.js +132 -0
  62. package/dist/a2a/seen-ledger.js +120 -0
  63. package/dist/a2a/server.js +604 -0
  64. package/dist/a2a/task-store.js +69 -0
  65. package/dist/a2a/transport.js +45 -0
  66. package/dist/a2a/types.js +3 -0
  67. package/dist/arc/attention-types.js +8 -0
  68. package/dist/arc/cares.js +360 -0
  69. package/dist/arc/episodes.js +118 -0
  70. package/dist/arc/evolution.js +490 -0
  71. package/dist/arc/flight-recorder.js +1034 -0
  72. package/dist/arc/intentions.js +134 -0
  73. package/dist/arc/json-store.js +117 -0
  74. package/dist/arc/obligations.js +386 -0
  75. package/dist/arc/packets.js +336 -0
  76. package/dist/arc/presence.js +185 -0
  77. package/dist/arc/task-lifecycle.js +57 -0
  78. package/dist/commerce/store.js +755 -0
  79. package/dist/commerce/types.js +3 -0
  80. package/dist/heart/active-work.js +798 -40
  81. package/dist/heart/agent-entry.js +252 -3
  82. package/dist/heart/approval-files.js +113 -0
  83. package/dist/heart/approval-store.js +960 -0
  84. package/dist/heart/attachments/image-normalize.js +194 -0
  85. package/dist/heart/attachments/materialize.js +97 -0
  86. package/dist/heart/attachments/originals.js +88 -0
  87. package/dist/heart/attachments/render.js +29 -0
  88. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  89. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  90. package/dist/heart/attachments/sources/index.js +18 -0
  91. package/dist/heart/attachments/sources/telegram.js +71 -0
  92. package/dist/heart/attachments/store.js +132 -0
  93. package/dist/heart/attachments/types.js +93 -0
  94. package/dist/heart/auth/auth-flow.js +495 -0
  95. package/dist/heart/autonomy-budget.js +478 -0
  96. package/dist/heart/awaiting/await-alert.js +148 -0
  97. package/dist/heart/awaiting/await-expiry.js +143 -0
  98. package/dist/heart/awaiting/await-loader.js +91 -0
  99. package/dist/heart/awaiting/await-parser.js +149 -0
  100. package/dist/heart/awaiting/await-runtime-state.js +111 -0
  101. package/dist/heart/awaiting/await-scheduler.js +382 -0
  102. package/dist/heart/background-operations.js +281 -0
  103. package/dist/heart/bridges/manager.js +137 -17
  104. package/dist/heart/bridges/store.js +14 -2
  105. package/dist/heart/bundle-state.js +168 -0
  106. package/dist/heart/commitments.js +44 -18
  107. package/dist/heart/config-registry.js +331 -0
  108. package/dist/heart/config.js +174 -131
  109. package/dist/heart/context-loss-gauntlet.js +387 -0
  110. package/dist/heart/context-loss-sentinel.js +1157 -0
  111. package/dist/heart/core.js +2169 -581
  112. package/dist/heart/cross-chat-delivery.js +9 -22
  113. package/dist/heart/daemon/agent-config-check.js +451 -0
  114. package/dist/heart/daemon/agent-discovery.js +185 -3
  115. package/dist/heart/daemon/agent-service.js +542 -0
  116. package/dist/heart/daemon/agentic-repair.js +547 -0
  117. package/dist/heart/daemon/await-private-wake.js +59 -0
  118. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  119. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  120. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  121. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  122. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  123. package/dist/heart/daemon/cadence.js +180 -0
  124. package/dist/heart/daemon/cli-defaults.js +854 -0
  125. package/dist/heart/daemon/cli-desk.js +322 -0
  126. package/dist/heart/daemon/cli-exec.js +8822 -0
  127. package/dist/heart/daemon/cli-help.js +716 -0
  128. package/dist/heart/daemon/cli-parse.js +2771 -0
  129. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  130. package/dist/heart/daemon/cli-render.js +777 -0
  131. package/dist/heart/daemon/cli-types.js +8 -0
  132. package/dist/heart/daemon/connect-bay.js +323 -0
  133. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  134. package/dist/heart/daemon/container-healthcheck.js +112 -0
  135. package/dist/heart/daemon/container-runtime.js +97 -0
  136. package/dist/heart/daemon/container-spec-auditor-main.js +171 -0
  137. package/dist/heart/daemon/container-spec-auditor.js +229 -0
  138. package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
  139. package/dist/heart/daemon/daemon-cli.js +29 -2349
  140. package/dist/heart/daemon/daemon-entry.js +930 -11
  141. package/dist/heart/daemon/daemon-health.js +186 -0
  142. package/dist/heart/daemon/daemon-rollup.js +57 -0
  143. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  144. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  145. package/dist/heart/daemon/daemon.js +2084 -105
  146. package/dist/heart/daemon/dns-workflow.js +394 -0
  147. package/dist/heart/daemon/doctor-types.js +8 -0
  148. package/dist/heart/daemon/doctor.js +1755 -0
  149. package/dist/heart/daemon/freshness.js +345 -0
  150. package/dist/heart/daemon/habit-private-wake.js +61 -0
  151. package/dist/heart/daemon/health-monitor.js +142 -11
  152. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  153. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  154. package/dist/heart/daemon/http-health-probe.js +80 -0
  155. package/dist/heart/daemon/human-command-screens.js +234 -0
  156. package/dist/heart/daemon/human-readiness.js +114 -0
  157. package/dist/heart/daemon/inner-status.js +78 -0
  158. package/dist/heart/daemon/interactive-repair.js +394 -0
  159. package/dist/heart/daemon/launchd.js +37 -8
  160. package/dist/heart/daemon/log-tailer.js +79 -10
  161. package/dist/heart/daemon/logs-prune.js +132 -0
  162. package/dist/heart/daemon/mcp-canary.js +524 -0
  163. package/dist/heart/daemon/message-router.js +65 -5
  164. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  165. package/dist/heart/daemon/os-cron-deps.js +135 -0
  166. package/dist/heart/daemon/os-cron.js +22 -14
  167. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  168. package/dist/heart/daemon/ouro-entry.js +3 -1
  169. package/dist/heart/daemon/plugin-cli.js +432 -0
  170. package/dist/heart/daemon/process-manager.js +733 -61
  171. package/dist/heart/daemon/provider-discovery.js +137 -0
  172. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  173. package/dist/heart/daemon/prunable-bundle.js +144 -0
  174. package/dist/heart/daemon/pulse.js +511 -0
  175. package/dist/heart/daemon/readiness-repair.js +365 -0
  176. package/dist/heart/daemon/run-hooks.js +2 -0
  177. package/dist/heart/daemon/runtime-logging.js +47 -14
  178. package/dist/heart/daemon/runtime-metadata.js +2 -30
  179. package/dist/heart/daemon/runtime-mode.js +13 -2
  180. package/dist/heart/daemon/safe-mode.js +161 -0
  181. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2654 -0
  182. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1830 -0
  183. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  184. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +955 -0
  185. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  186. package/dist/heart/daemon/sanctuary-authority-epoch.js +256 -0
  187. package/dist/heart/daemon/sanctuary-authority-installation.js +140 -0
  188. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  189. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +819 -0
  190. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  191. package/dist/heart/daemon/sanctuary-bundle-migration.js +729 -0
  192. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  193. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +494 -0
  194. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  195. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  196. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  197. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  198. package/dist/heart/daemon/sanctuary-package-management.js +103 -0
  199. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  200. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  201. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +445 -0
  202. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  203. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +630 -0
  204. package/dist/heart/daemon/sense-manager.js +699 -48
  205. package/dist/heart/daemon/session-id-resolver.js +131 -0
  206. package/dist/heart/daemon/skill-management-installer.js +1 -1
  207. package/dist/heart/daemon/socket-client.js +180 -12
  208. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  209. package/dist/heart/daemon/startup-tui.js +339 -0
  210. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  211. package/dist/heart/daemon/task-scheduler.js +117 -39
  212. package/dist/heart/daemon/terminal-ui.js +499 -0
  213. package/dist/heart/daemon/thoughts.js +138 -54
  214. package/dist/heart/daemon/up-progress.js +366 -0
  215. package/dist/heart/daemon/vault-items.js +56 -0
  216. package/dist/heart/delegation.js +1 -4
  217. package/dist/heart/external-events/router.js +1430 -0
  218. package/dist/heart/frontend-approval-runtime.js +506 -0
  219. package/dist/heart/frontend-journal.js +215 -0
  220. package/dist/heart/frontend-session-service.js +237 -0
  221. package/dist/heart/frontend-socket-client.js +164 -0
  222. package/dist/heart/frontend-socket.js +400 -0
  223. package/dist/heart/habits/habit-cancel.js +810 -0
  224. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  225. package/dist/heart/habits/habit-migration.js +194 -0
  226. package/dist/heart/habits/habit-parser.js +278 -0
  227. package/dist/heart/habits/habit-runtime-state.js +93 -0
  228. package/dist/heart/habits/habit-scheduler.js +653 -0
  229. package/dist/heart/habits/habit-session-summary.js +318 -0
  230. package/dist/heart/habits/habit-session.js +636 -0
  231. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  232. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  233. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  234. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  235. package/dist/heart/identity.js +196 -59
  236. package/dist/heart/kept-notes.js +289 -0
  237. package/dist/heart/kicks.js +1 -1
  238. package/dist/heart/machine-identity.js +161 -0
  239. package/dist/heart/mail-import-discovery.js +356 -0
  240. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  241. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  242. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  243. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  244. package/dist/heart/mailbox/mailbox-http-transport.js +129 -0
  245. package/dist/heart/mailbox/mailbox-http.js +99 -0
  246. package/dist/heart/mailbox/mailbox-read.js +39 -0
  247. package/dist/heart/mailbox/mailbox-types.js +27 -0
  248. package/dist/heart/mailbox/mailbox-view.js +197 -0
  249. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  250. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  251. package/dist/heart/mailbox/readers/mail.js +375 -0
  252. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  253. package/dist/heart/mailbox/readers/sessions.js +231 -0
  254. package/dist/heart/mailbox/readers/shared.js +111 -0
  255. package/dist/heart/mcp/mcp-server.js +696 -0
  256. package/dist/heart/migrate-config.js +100 -0
  257. package/dist/heart/model-capabilities.js +11 -0
  258. package/dist/heart/orientation-frame.js +345 -0
  259. package/dist/heart/platform.js +81 -0
  260. package/dist/heart/primitives.js +1 -1
  261. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  262. package/dist/heart/private-runtime/index.js +18 -0
  263. package/dist/heart/private-runtime/ledger.js +221 -0
  264. package/dist/heart/private-runtime/policy.js +252 -0
  265. package/dist/heart/private-runtime/types.js +2 -0
  266. package/dist/heart/progress-story.js +1 -1
  267. package/dist/heart/provider-attempt.js +137 -0
  268. package/dist/heart/provider-binding-resolver.js +273 -0
  269. package/dist/heart/provider-credentials.js +449 -0
  270. package/dist/heart/provider-failover.js +311 -0
  271. package/dist/heart/provider-models.js +96 -0
  272. package/dist/heart/provider-ping.js +265 -0
  273. package/dist/heart/provider-readiness-cache.js +119 -0
  274. package/dist/heart/provider-visibility.js +188 -0
  275. package/dist/heart/providers/anthropic-token.js +131 -0
  276. package/dist/heart/providers/anthropic.js +173 -60
  277. package/dist/heart/providers/azure.js +23 -11
  278. package/dist/heart/providers/error-classification.js +127 -0
  279. package/dist/heart/providers/github-copilot.js +34 -38
  280. package/dist/heart/providers/minimax-vlm.js +189 -0
  281. package/dist/heart/providers/minimax.js +26 -8
  282. package/dist/heart/providers/openai-codex-token.js +349 -0
  283. package/dist/heart/providers/openai-codex.js +55 -40
  284. package/dist/heart/providers/openai-compatible.js +177 -0
  285. package/dist/heart/run-ledger.js +247 -0
  286. package/dist/heart/runtime-capability-check.js +170 -0
  287. package/dist/heart/runtime-credentials.js +607 -0
  288. package/dist/heart/runtime-cwd.js +87 -0
  289. package/dist/heart/sense-truth.js +22 -4
  290. package/dist/heart/session-activity.js +92 -24
  291. package/dist/heart/session-events.js +1504 -0
  292. package/dist/heart/session-playback-cli-main.js +5 -0
  293. package/dist/heart/session-playback-cli.js +36 -0
  294. package/dist/heart/session-playback.js +231 -0
  295. package/dist/heart/session-redaction-repair-cli-main.js +31 -0
  296. package/dist/heart/session-redaction-repair.js +552 -0
  297. package/dist/heart/session-stats-cli-main.js +5 -0
  298. package/dist/heart/session-stats.js +183 -0
  299. package/dist/heart/session-transcript.js +133 -0
  300. package/dist/heart/start-of-turn-packet.js +372 -0
  301. package/dist/heart/steward-policy.js +618 -0
  302. package/dist/heart/streaming.js +604 -207
  303. package/dist/heart/structured-output.js +196 -0
  304. package/dist/heart/sync-classification.js +176 -0
  305. package/dist/heart/sync.js +449 -0
  306. package/dist/heart/target-resolution.js +11 -7
  307. package/dist/heart/tempo.js +93 -0
  308. package/dist/heart/temporal-view.js +41 -0
  309. package/dist/heart/timeouts.js +101 -0
  310. package/dist/heart/tool-activity-callbacks.js +59 -0
  311. package/dist/heart/tool-approval.js +382 -0
  312. package/dist/heart/tool-description.js +155 -0
  313. package/dist/heart/tool-friction.js +55 -0
  314. package/dist/heart/tool-loop.js +200 -0
  315. package/dist/heart/turn-context.js +482 -0
  316. package/dist/heart/turn-execution-lease.js +30 -0
  317. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  318. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  319. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  320. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  321. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  322. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  323. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  324. package/dist/heart/versioning/update-hooks.js +154 -0
  325. package/dist/heart/versioning/version-intent.js +114 -0
  326. package/dist/heart/work-card.js +380 -0
  327. package/dist/mailbox-ui/assets/index-Cyv4mw3Y.js +1 -0
  328. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  329. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  330. package/dist/mailbox-ui/index.html +16 -0
  331. package/dist/mailroom/attention.js +167 -0
  332. package/dist/mailroom/autonomy.js +209 -0
  333. package/dist/mailroom/blob-store.js +889 -0
  334. package/dist/mailroom/body-cache.js +61 -0
  335. package/dist/mailroom/cache-sync-cli.js +58 -0
  336. package/dist/mailroom/core.js +803 -0
  337. package/dist/mailroom/entry.js +160 -0
  338. package/dist/mailroom/file-store.js +568 -0
  339. package/dist/mailroom/hosted-cache-sync.js +384 -0
  340. package/dist/mailroom/mbox-import.js +393 -0
  341. package/dist/mailroom/migration.js +164 -0
  342. package/dist/mailroom/outbound.js +380 -0
  343. package/dist/mailroom/policy.js +263 -0
  344. package/dist/mailroom/reader.js +292 -0
  345. package/dist/mailroom/search-cache.js +513 -0
  346. package/dist/mailroom/search-relevance.js +319 -0
  347. package/dist/mailroom/smtp-ingress.js +176 -0
  348. package/dist/mailroom/source-state.js +176 -0
  349. package/dist/mailroom/thread.js +109 -0
  350. package/dist/mailroom/travel-extract.js +89 -0
  351. package/dist/mind/bundle-manifest.js +24 -2
  352. package/dist/mind/context.js +309 -111
  353. package/dist/mind/desk-section.js +362 -0
  354. package/dist/mind/diary-integrity.js +60 -0
  355. package/dist/mind/{memory.js → diary.js} +68 -77
  356. package/dist/mind/embedding-provider.js +60 -0
  357. package/dist/mind/file-state.js +179 -0
  358. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  359. package/dist/mind/obligation-steering.js +199 -3
  360. package/dist/mind/pending.js +36 -10
  361. package/dist/mind/prompt-budget.js +479 -0
  362. package/dist/mind/prompt-refresh.js +3 -2
  363. package/dist/mind/prompt.js +1050 -189
  364. package/dist/mind/provenance-trust.js +26 -0
  365. package/dist/mind/record-paths.js +312 -0
  366. package/dist/mind/scrutiny.js +173 -0
  367. package/dist/mind/session-transaction.js +564 -0
  368. package/dist/nerves/cli-logging.js +7 -1
  369. package/dist/nerves/coverage/audit-rules.js +15 -6
  370. package/dist/nerves/coverage/audit.js +28 -2
  371. package/dist/nerves/coverage/cli.js +1 -1
  372. package/dist/nerves/coverage/contract.js +5 -5
  373. package/dist/nerves/coverage/file-completeness.js +139 -5
  374. package/dist/nerves/coverage/run-artifacts.js +55 -35
  375. package/dist/nerves/coverage/source-scanner.js +4 -4
  376. package/dist/nerves/event-buffer.js +111 -0
  377. package/dist/nerves/index.js +293 -9
  378. package/dist/nerves/observation.js +20 -0
  379. package/dist/nerves/redact.js +79 -0
  380. package/dist/nerves/review/cli-main.js +5 -0
  381. package/dist/nerves/review/cli.js +156 -0
  382. package/dist/nerves/review/core.js +159 -0
  383. package/dist/nerves/runtime.js +17 -1
  384. package/dist/repertoire/ado-client.js +15 -56
  385. package/dist/repertoire/ado-semantic.js +16 -10
  386. package/dist/repertoire/api-client.js +97 -0
  387. package/dist/repertoire/bitwarden-store.js +1045 -0
  388. package/dist/repertoire/bundle-templates.js +71 -0
  389. package/dist/repertoire/bw-installer.js +180 -0
  390. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  391. package/dist/repertoire/coding/context-pack.js +331 -0
  392. package/dist/repertoire/coding/feedback.js +174 -32
  393. package/dist/repertoire/coding/index.js +15 -3
  394. package/dist/repertoire/coding/manager.js +159 -10
  395. package/dist/repertoire/coding/spawner.js +58 -11
  396. package/dist/repertoire/coding/tools.js +221 -15
  397. package/dist/repertoire/coding/workbench-client.js +272 -0
  398. package/dist/repertoire/coding/workbench-manager.js +346 -0
  399. package/dist/repertoire/commerce-errors.js +109 -0
  400. package/dist/repertoire/commerce-self-test.js +156 -0
  401. package/dist/repertoire/credential-access.js +178 -0
  402. package/dist/repertoire/desk/classifier.js +362 -0
  403. package/dist/repertoire/duffel-client.js +185 -0
  404. package/dist/repertoire/github-client.js +14 -55
  405. package/dist/repertoire/graph-client.js +11 -52
  406. package/dist/repertoire/guardrails.js +811 -18
  407. package/dist/repertoire/mcp-client.js +44 -3
  408. package/dist/repertoire/mcp-manager.js +427 -139
  409. package/dist/repertoire/mcp-tools.js +124 -0
  410. package/dist/repertoire/plugin-mcp.js +175 -0
  411. package/dist/repertoire/plugins.js +253 -0
  412. package/dist/repertoire/relationship-authorization.js +322 -0
  413. package/dist/repertoire/shell-sessions.js +134 -0
  414. package/dist/repertoire/skills.js +48 -4
  415. package/dist/repertoire/stripe-client.js +131 -0
  416. package/dist/repertoire/tool-arguments.js +170 -0
  417. package/dist/repertoire/tool-results.js +29 -0
  418. package/dist/repertoire/tools-a2a.js +699 -0
  419. package/dist/repertoire/tools-attachments.js +322 -0
  420. package/dist/repertoire/tools-awaiting.js +575 -0
  421. package/dist/repertoire/tools-base.js +77 -1138
  422. package/dist/repertoire/tools-bluebubbles.js +2 -0
  423. package/dist/repertoire/tools-bridge.js +144 -0
  424. package/dist/repertoire/tools-bundle.js +993 -0
  425. package/dist/repertoire/tools-commerce.js +253 -0
  426. package/dist/repertoire/tools-config.js +186 -0
  427. package/dist/repertoire/tools-continuity.js +575 -0
  428. package/dist/repertoire/tools-credential.js +383 -0
  429. package/dist/repertoire/tools-evolution.js +527 -0
  430. package/dist/repertoire/tools-files.js +344 -0
  431. package/dist/repertoire/tools-flight.js +290 -0
  432. package/dist/repertoire/tools-flow.js +119 -0
  433. package/dist/repertoire/tools-github.js +3 -8
  434. package/dist/repertoire/tools-habits.js +103 -0
  435. package/dist/repertoire/tools-mail.js +1828 -0
  436. package/dist/repertoire/tools-notes.js +485 -0
  437. package/dist/repertoire/tools-obligations.js +182 -0
  438. package/dist/repertoire/tools-orientation.js +31 -0
  439. package/dist/repertoire/tools-record.js +482 -0
  440. package/dist/repertoire/tools-rsvp.js +139 -0
  441. package/dist/repertoire/tools-runtime.js +150 -0
  442. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  443. package/dist/repertoire/tools-session.js +1133 -0
  444. package/dist/repertoire/tools-shell.js +149 -0
  445. package/dist/repertoire/tools-steward-policy.js +119 -0
  446. package/dist/repertoire/tools-stripe.js +224 -0
  447. package/dist/repertoire/tools-surface.js +369 -0
  448. package/dist/repertoire/tools-teams.js +12 -39
  449. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  450. package/dist/repertoire/tools-travel.js +125 -0
  451. package/dist/repertoire/tools-trip.js +982 -0
  452. package/dist/repertoire/tools-unraid.js +531 -0
  453. package/dist/repertoire/tools-user-profile.js +146 -0
  454. package/dist/repertoire/tools-vault.js +40 -0
  455. package/dist/repertoire/tools-voice.js +145 -0
  456. package/dist/repertoire/tools.js +494 -148
  457. package/dist/repertoire/travel-api-client.js +360 -0
  458. package/dist/repertoire/unraid-client.js +155 -0
  459. package/dist/repertoire/unraid-restart.js +339 -0
  460. package/dist/repertoire/user-profile.js +131 -0
  461. package/dist/repertoire/vault-setup.js +246 -0
  462. package/dist/repertoire/vault-unlock.js +628 -0
  463. package/dist/rsvp/aisleplanner-client.js +354 -0
  464. package/dist/rsvp/cli.js +926 -0
  465. package/dist/rsvp/config.js +327 -0
  466. package/dist/rsvp/cutover.js +433 -0
  467. package/dist/rsvp/diagnostics.js +232 -0
  468. package/dist/rsvp/diff-renderer.js +176 -0
  469. package/dist/rsvp/habit-policy.js +110 -0
  470. package/dist/rsvp/habit-stage.js +123 -0
  471. package/dist/rsvp/incident-bundle.js +97 -0
  472. package/dist/rsvp/migration.js +204 -0
  473. package/dist/rsvp/native-habit-runner.js +630 -0
  474. package/dist/rsvp/outbound-state.js +628 -0
  475. package/dist/rsvp/query.js +118 -0
  476. package/dist/rsvp/replay.js +233 -0
  477. package/dist/rsvp/snapshot.js +232 -0
  478. package/dist/rsvp/spend-ledger.js +175 -0
  479. package/dist/scripts/claude-code-hook.js +41 -0
  480. package/dist/scripts/claude-code-stop-hook.js +47 -0
  481. package/dist/senses/a2a-entry.js +115 -0
  482. package/dist/senses/acp-server.js +386 -0
  483. package/dist/senses/attention-queue.js +186 -0
  484. package/dist/senses/await-turn-message.js +58 -0
  485. package/dist/senses/bluebubbles/active-turns.js +216 -0
  486. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  487. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  488. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
  489. package/dist/senses/bluebubbles/context-packet.js +207 -0
  490. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  491. package/dist/senses/bluebubbles/entry.js +90 -0
  492. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  493. package/dist/senses/bluebubbles/index.js +3841 -0
  494. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  495. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  496. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  497. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  498. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  499. package/dist/senses/bluebubbles/processed-log.js +133 -0
  500. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  501. package/dist/senses/bluebubbles/replay.js +284 -0
  502. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  503. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  504. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  505. package/dist/senses/bluebubbles/webhook-registration.js +228 -0
  506. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  507. package/dist/senses/cli/bracketed-paste.js +82 -0
  508. package/dist/senses/cli/image-paste.js +287 -0
  509. package/dist/senses/cli/image-ref-navigation.js +75 -0
  510. package/dist/senses/cli/ink-app.js +156 -0
  511. package/dist/senses/cli/inline-diff.js +64 -0
  512. package/dist/senses/cli/input-keys.js +174 -0
  513. package/dist/senses/cli/kill-ring.js +86 -0
  514. package/dist/senses/cli/message-list.js +51 -0
  515. package/dist/senses/cli/ouro-tui.js +607 -0
  516. package/dist/senses/cli/spinner-imperative.js +135 -0
  517. package/dist/senses/cli/spinner.js +101 -0
  518. package/dist/senses/cli/status-line.js +60 -0
  519. package/dist/senses/cli/streaming-markdown.js +526 -0
  520. package/dist/senses/cli/tool-display.js +85 -0
  521. package/dist/senses/cli/tool-render.js +85 -0
  522. package/dist/senses/cli/tui-store.js +241 -0
  523. package/dist/senses/cli/virtual-list.js +35 -0
  524. package/dist/senses/cli-entry.js +60 -8
  525. package/dist/senses/cli.js +604 -320
  526. package/dist/senses/commands.js +66 -3
  527. package/dist/senses/context-packet-ledger.js +371 -0
  528. package/dist/senses/context-packets.js +154 -0
  529. package/dist/senses/habit-lifecycle-guard.js +24 -0
  530. package/dist/senses/habit-turn-message.js +160 -0
  531. package/dist/senses/ingress-evidence.js +2 -0
  532. package/dist/senses/mail-entry.js +66 -0
  533. package/dist/senses/mail.js +524 -0
  534. package/dist/senses/pipeline.js +1115 -204
  535. package/dist/senses/private-runtime-worker.js +859 -0
  536. package/dist/senses/private-runtime.js +1517 -0
  537. package/dist/senses/proactive-content-guard.js +51 -0
  538. package/dist/senses/root-host-approval-port.js +345 -0
  539. package/dist/senses/root-host-approval-runtime.js +393 -0
  540. package/dist/senses/sanctuary-authority-resident.js +102 -0
  541. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  542. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  543. package/dist/senses/sanctuary-grounding.js +118 -0
  544. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  545. package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
  546. package/dist/senses/sanctuary-health-runner.js +100 -0
  547. package/dist/senses/sanctuary-health.js +408 -0
  548. package/dist/senses/sanctuary-install-state-contract.js +126 -0
  549. package/dist/senses/sanctuary-interactive-control.js +410 -0
  550. package/dist/senses/sanctuary-media-catalog-contract.js +297 -0
  551. package/dist/senses/sanctuary-media-optimization.js +514 -0
  552. package/dist/senses/sanctuary-runtime.js +340 -0
  553. package/dist/senses/sanctuary-sab.js +85 -0
  554. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  555. package/dist/senses/shared-turn.js +772 -0
  556. package/dist/senses/surface-tool.js +109 -0
  557. package/dist/senses/teams-entry.js +60 -8
  558. package/dist/senses/teams.js +519 -218
  559. package/dist/senses/telegram-admission.js +718 -0
  560. package/dist/senses/telegram-approval-runtime.js +793 -0
  561. package/dist/senses/telegram-attachments.js +186 -0
  562. package/dist/senses/telegram-audit-ledger.js +220 -0
  563. package/dist/senses/telegram-authority-transport.js +231 -0
  564. package/dist/senses/telegram-client.js +1749 -0
  565. package/dist/senses/telegram-effect-adapter.js +896 -0
  566. package/dist/senses/telegram-entry.js +83 -0
  567. package/dist/senses/telegram.js +2324 -0
  568. package/dist/senses/trust-gate.js +104 -9
  569. package/dist/senses/voice/audio-playback.js +237 -0
  570. package/dist/senses/voice/audio-routing.js +119 -0
  571. package/dist/senses/voice/elevenlabs.js +202 -0
  572. package/dist/senses/voice/floor-control.js +431 -0
  573. package/dist/senses/voice/floor-controller.js +115 -0
  574. package/dist/senses/voice/golden-path.js +116 -0
  575. package/dist/senses/voice/index.js +29 -0
  576. package/dist/senses/voice/meeting.js +113 -0
  577. package/dist/senses/voice/outbound.js +190 -0
  578. package/dist/senses/voice/phone.js +33 -0
  579. package/dist/senses/voice/playback.js +139 -0
  580. package/dist/senses/voice/realtime-eval.js +496 -0
  581. package/dist/senses/voice/realtime-trace.js +531 -0
  582. package/dist/senses/voice/transcript.js +70 -0
  583. package/dist/senses/voice/turn.js +191 -0
  584. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  585. package/dist/senses/voice/twilio-phone.js +5031 -0
  586. package/dist/senses/voice/types.js +2 -0
  587. package/dist/senses/voice/whisper.js +161 -0
  588. package/dist/senses/voice-entry.js +81 -0
  589. package/dist/senses/voice-realtime-eval-command.js +99 -0
  590. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  591. package/dist/senses/voice-twilio-entry.js +87 -0
  592. package/dist/trips/core.js +138 -0
  593. package/dist/trips/store.js +265 -0
  594. package/dist/util/frontmatter.js +69 -0
  595. package/npm-shrinkwrap.json +8138 -0
  596. package/package.json +72 -13
  597. package/skills/agent-commerce.md +113 -0
  598. package/skills/browser-navigation.md +117 -0
  599. package/skills/commerce-setup-guide.md +116 -0
  600. package/skills/commerce-setup.md +84 -0
  601. package/skills/configure-dev-tools.md +99 -0
  602. package/skills/travel-planning.md +138 -0
  603. package/dist/heart/daemon/auth-flow.js +0 -430
  604. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  605. package/dist/heart/daemon/ouro-version-manager.js +0 -171
  606. package/dist/heart/daemon/update-hooks.js +0 -138
  607. package/dist/heart/obligations.js +0 -191
  608. package/dist/heart/safe-workspace.js +0 -228
  609. package/dist/heart/session-recall.js +0 -116
  610. package/dist/mind/friends/channel.js +0 -84
  611. package/dist/mind/friends/group-context.js +0 -144
  612. package/dist/mind/friends/resolver.js +0 -84
  613. package/dist/mind/friends/store-file.js +0 -190
  614. package/dist/mind/friends/store.js +0 -4
  615. package/dist/mind/friends/tokens.js +0 -26
  616. package/dist/mind/friends/trust-explanation.js +0 -74
  617. package/dist/mind/friends/types.js +0 -29
  618. package/dist/repertoire/tasks/board.js +0 -134
  619. package/dist/repertoire/tasks/index.js +0 -224
  620. package/dist/repertoire/tasks/lifecycle.js +0 -80
  621. package/dist/repertoire/tasks/middleware.js +0 -65
  622. package/dist/repertoire/tasks/parser.js +0 -173
  623. package/dist/repertoire/tasks/scanner.js +0 -132
  624. package/dist/repertoire/tasks/transitions.js +0 -144
  625. package/dist/senses/bluebubbles-entry.js +0 -13
  626. package/dist/senses/bluebubbles.js +0 -1181
  627. package/dist/senses/debug-activity.js +0 -154
  628. package/dist/senses/inner-dialog-worker.js +0 -90
  629. package/dist/senses/inner-dialog.js +0 -525
  630. package/subagents/README.md +0 -7
  631. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  632. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  633. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  634. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  635. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  636. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  637. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  638. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  639. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  640. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  641. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  642. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  643. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  644. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  645. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  646. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  647. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -1,7 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BlueBubblesIgnoredEventError = void 0;
4
+ exports.describeBlueBubblesReaction = describeBlueBubblesReaction;
5
+ exports.renderBlueBubblesReactionText = renderBlueBubblesReactionText;
3
6
  exports.normalizeBlueBubblesEvent = normalizeBlueBubblesEvent;
4
- const runtime_1 = require("../nerves/runtime");
7
+ const runtime_1 = require("../../nerves/runtime");
8
+ const render_1 = require("../../heart/attachments/render");
9
+ const bluebubbles_1 = require("../../heart/attachments/sources/bluebubbles");
10
+ const IGNORABLE_GUIDLESS_EVENT_TYPES = new Set([
11
+ "chat-read-status-changed",
12
+ ]);
13
+ class BlueBubblesIgnoredEventError extends Error {
14
+ eventType;
15
+ constructor(eventType, message) {
16
+ super(message);
17
+ this.name = "BlueBubblesIgnoredEventError";
18
+ this.eventType = eventType;
19
+ }
20
+ }
21
+ exports.BlueBubblesIgnoredEventError = BlueBubblesIgnoredEventError;
5
22
  function asRecord(value) {
6
23
  return value && typeof value === "object" && !Array.isArray(value)
7
24
  ? value
@@ -75,9 +92,11 @@ function buildChatRef(data, threadOriginatorGuid) {
75
92
  }
76
93
  function extractSender(data, chat) {
77
94
  const handle = asRecord(data.handle) ?? asRecord(data.sender) ?? null;
78
- const rawId = readString(handle, "address") ??
95
+ const observedRawId = readString(handle, "address") ??
79
96
  readString(handle, "id") ??
80
- readString(data, "senderId") ??
97
+ readString(data, "senderId");
98
+ const observed = typeof observedRawId === "string" && observedRawId.trim().length > 0;
99
+ const rawId = observedRawId ??
81
100
  chat.chatIdentifier ??
82
101
  chat.chatGuid ??
83
102
  "unknown";
@@ -88,6 +107,7 @@ function extractSender(data, chat) {
88
107
  externalId,
89
108
  rawId,
90
109
  displayName,
110
+ observed,
91
111
  };
92
112
  }
93
113
  function extractAttachments(data) {
@@ -107,18 +127,14 @@ function extractAttachments(data) {
107
127
  function formatAttachmentText(attachments) {
108
128
  if (attachments.length === 0)
109
129
  return "";
130
+ const renderable = attachments
131
+ .filter((attachment) => typeof attachment.guid === "string" && attachment.guid.trim().length > 0)
132
+ .map((attachment) => (0, bluebubbles_1.buildBlueBubblesAttachmentRecord)(attachment));
133
+ if (renderable.length > 0) {
134
+ return (0, render_1.renderAttachmentBlock)(renderable);
135
+ }
110
136
  const [first] = attachments;
111
- const mime = first.mimeType ?? "";
112
- const label = mime.startsWith("image/")
113
- ? "image attachment"
114
- : mime.startsWith("audio/")
115
- ? "audio attachment"
116
- : "attachment";
117
- const name = first.transferName ? `: ${first.transferName}` : "";
118
- const dimensions = typeof first.width === "number" && typeof first.height === "number" && first.width > 0 && first.height > 0
119
- ? ` (${first.width}x${first.height})`
120
- : "";
121
- return `[${label}${name}${dimensions}]`;
137
+ return `[attachment: ${first.transferName?.trim() || "unknown"}]`;
122
138
  }
123
139
  function formatMessageText(data, attachments) {
124
140
  const text = readString(data, "text")?.trim() ?? "";
@@ -127,16 +143,91 @@ function formatMessageText(data, attachments) {
127
143
  if (balloonBundleId === "com.apple.messages.URLBalloonProvider") {
128
144
  return `${text}\n[link preview attached]`;
129
145
  }
146
+ // B2 fix: when text and attachments both exist, append the attachment
147
+ // marker so downstream senses can see the guid/filename. Previously the
148
+ // marker was dropped whenever text was non-empty, which hid images from
149
+ // the agent when the user captioned a screenshot.
150
+ if (attachments.length > 0) {
151
+ return `${text}\n${formatAttachmentText(attachments)}`;
152
+ }
130
153
  return text;
131
154
  }
132
155
  return formatAttachmentText(attachments);
133
156
  }
134
157
  function normalizeReactionName(value) {
158
+ // chat.db stores associated_message_type as an integer; BlueBubbles forwards it
159
+ // as either the integer, its decimal string, or a name ("love", "-love").
160
+ if (typeof value === "number") {
161
+ return Number.isFinite(value) && value !== 0 ? String(value) : undefined;
162
+ }
135
163
  if (typeof value !== "string")
136
164
  return undefined;
137
165
  const trimmed = value.trim();
138
166
  return trimmed ? trimmed.toLowerCase() : undefined;
139
167
  }
168
+ /**
169
+ * iMessage tapbacks: associated_message_type 2000-2006 add a tapback, 3000-3006
170
+ * remove the same tapback. BlueBubbles may send either the code or the name.
171
+ */
172
+ const REACTION_VOCABULARY = [
173
+ { code: 2000, name: "love", verb: "loved", noun: "love" },
174
+ { code: 2001, name: "like", verb: "liked", noun: "like" },
175
+ { code: 2002, name: "dislike", verb: "disliked", noun: "dislike" },
176
+ { code: 2003, name: "laugh", verb: "laughed at", noun: "laugh" },
177
+ { code: 2004, name: "emphasize", verb: "emphasized", noun: "emphasis" },
178
+ { code: 2005, name: "question", verb: "questioned", noun: "question" },
179
+ { code: 2006, name: "custom", verb: "reacted with custom emoji to", noun: "custom emoji" },
180
+ ];
181
+ const REACTION_EXCERPT_MAX_LENGTH = 80;
182
+ function describeBlueBubblesReaction(raw, rawTransportValue = raw) {
183
+ const stripped = raw.startsWith("-") ? raw.slice(1) : raw;
184
+ const code = /^\d+$/.test(stripped) ? Number(stripped) : undefined;
185
+ const removal = raw.startsWith("-") || (code !== undefined && code >= 3000 && code < 4000);
186
+ const action = removal ? "remove" : "add";
187
+ const entry = REACTION_VOCABULARY.find((candidate) => candidate.name === stripped || candidate.code === code || candidate.code + 1000 === code);
188
+ const canonicalValue = entry?.name ?? "unknown";
189
+ if (!entry)
190
+ return { raw, rawTransportValue, canonicalValue, action };
191
+ return {
192
+ raw,
193
+ rawTransportValue,
194
+ canonicalValue,
195
+ action,
196
+ verb: entry.verb,
197
+ noun: entry.noun,
198
+ };
199
+ }
200
+ function reactionExcerpt(text) {
201
+ return text.length > REACTION_EXCERPT_MAX_LENGTH
202
+ ? `${text.slice(0, REACTION_EXCERPT_MAX_LENGTH - 3)}...`
203
+ : text;
204
+ }
205
+ function reactionTargetPhrase(target) {
206
+ const text = target.text?.trim();
207
+ if (text) {
208
+ const owner = target.fromMe === true ? "your" : target.fromMe === false ? "their" : "a";
209
+ return `${owner} message: "${reactionExcerpt(text)}"`;
210
+ }
211
+ // Never hand the agent a bare "reacted with love" stub — say plainly that the
212
+ // referent is missing so it can ask instead of guessing what was approved.
213
+ return target.guid
214
+ ? `an unidentified message (target guid ${target.guid}; its text could not be resolved)`
215
+ : "an unidentified message (the reaction carried no target message reference)";
216
+ }
217
+ /**
218
+ * Render a reaction as speech the agent can act on: what the tapback was, whether
219
+ * it was added or removed, and which message it points at.
220
+ */
221
+ function renderBlueBubblesReactionText(reaction, target) {
222
+ const phrase = reactionTargetPhrase(target);
223
+ if (reaction.action === "remove") {
224
+ const noun = reaction.noun ?? reaction.raw.replace(/^-/, "");
225
+ return `removed their ${noun} reaction from ${phrase}`;
226
+ }
227
+ return reaction.verb
228
+ ? `${reaction.verb} ${phrase}`
229
+ : `reacted with ${reaction.raw} to ${phrase}`;
230
+ }
140
231
  function stripPartPrefix(guid) {
141
232
  if (!guid)
142
233
  return undefined;
@@ -144,10 +235,10 @@ function stripPartPrefix(guid) {
144
235
  const marker = trimmed.lastIndexOf("/");
145
236
  return marker >= 0 ? trimmed.slice(marker + 1) : trimmed;
146
237
  }
147
- function buildMutationText(mutationType, data, reactionName) {
148
- if (mutationType === "reaction") {
149
- return `reacted with ${reactionName}`;
150
- }
238
+ // Reactions never reach here: `detectMutationType` returns "reaction" only when a
239
+ // reaction name was decoded, and that same name produces the descriptor the caller
240
+ // renders with `renderBlueBubblesReactionText` instead.
241
+ function buildMutationText(mutationType, data) {
151
242
  if (mutationType === "edit") {
152
243
  const editedText = readString(data, "text")?.trim() ?? "";
153
244
  return editedText ? `edited message: ${editedText}` : "edited a message";
@@ -164,17 +255,35 @@ function detectMutationType(eventType, data, reactionName) {
164
255
  if (reactionName)
165
256
  return "reaction";
166
257
  if (eventType === "updated-message") {
167
- if (readNumber(data, "dateRetracted"))
258
+ if (readNumber(data, "dateRetracted") !== undefined)
168
259
  return "unsend";
169
- if (readNumber(data, "dateEdited"))
260
+ if (readNumber(data, "dateEdited") !== undefined)
170
261
  return "edit";
171
- if (readNumber(data, "dateRead"))
262
+ if (readNumber(data, "dateRead") !== undefined)
172
263
  return "read";
173
- if (readBoolean(data, "isDelivered") || readNumber(data, "dateDelivered"))
264
+ if (readBoolean(data, "isDelivered") || readNumber(data, "dateDelivered") !== undefined)
174
265
  return "delivery";
175
266
  }
176
267
  return null;
177
268
  }
269
+ function readProviderRevision(data) {
270
+ const value = data.revision;
271
+ if (typeof value !== "string" && typeof value !== "number")
272
+ return undefined;
273
+ const normalized = String(value).trim();
274
+ return normalized || undefined;
275
+ }
276
+ function mutationEffectiveTimestamp(mutationType, data) {
277
+ if (mutationType === "reaction")
278
+ return readNumber(data, "dateCreated");
279
+ if (mutationType === "edit")
280
+ return readNumber(data, "dateEdited");
281
+ if (mutationType === "unsend")
282
+ return readNumber(data, "dateRetracted");
283
+ if (mutationType === "read")
284
+ return readNumber(data, "dateRead");
285
+ return readNumber(data, "dateDelivered");
286
+ }
178
287
  function normalizeBlueBubblesEvent(payload) {
179
288
  const envelope = asRecord(payload);
180
289
  const eventType = readString(envelope, "type")?.trim() ?? "";
@@ -198,16 +307,33 @@ function normalizeBlueBubblesEvent(payload) {
198
307
  message: "ignored bluebubbles payload without guid",
199
308
  meta: { eventType },
200
309
  });
310
+ if (IGNORABLE_GUIDLESS_EVENT_TYPES.has(eventType)) {
311
+ throw new BlueBubblesIgnoredEventError(eventType, `Ignored BlueBubbles event '${eventType}' without data.guid`);
312
+ }
201
313
  throw new Error("BlueBubbles payload is missing data.guid");
202
314
  }
203
315
  const threadOriginatorGuid = readString(data, "threadOriginatorGuid")?.trim() || undefined;
204
316
  const chat = buildChatRef(data, threadOriginatorGuid);
205
317
  const sender = extractSender(data, chat);
206
318
  const timestamp = readNumber(data, "dateCreated") ?? Date.now();
207
- const fromMe = readBoolean(data, "isFromMe") ?? false;
319
+ const fromMe = readBoolean(data, "isFromMe") ?? null;
208
320
  const attachments = extractAttachments(data);
209
321
  const reactionName = normalizeReactionName(data.associatedMessageType);
322
+ const reaction = reactionName
323
+ ? describeBlueBubblesReaction(reactionName, String(data.associatedMessageType))
324
+ : undefined;
325
+ const targetMessageGuid = reaction
326
+ ? stripPartPrefix(readString(data, "associatedMessageGuid"))
327
+ : undefined;
210
328
  const mutationType = detectMutationType(eventType, data, reactionName);
329
+ const revision = mutationType ? readProviderRevision(data) : undefined;
330
+ const effectiveTimestamp = mutationType
331
+ ? mutationEffectiveTimestamp(mutationType, data)
332
+ : undefined;
333
+ const editedText = mutationType === "edit" ? readString(data, "text") : undefined;
334
+ const retractionTimestamp = mutationType === "unsend"
335
+ ? readNumber(data, "dateRetracted")
336
+ : undefined;
211
337
  const requiresRepair = (readBoolean(data, "hasPayloadData") ?? false) ||
212
338
  attachments.length > 0 ||
213
339
  eventType === "updated-message";
@@ -217,16 +343,21 @@ function normalizeBlueBubblesEvent(payload) {
217
343
  eventType,
218
344
  mutationType,
219
345
  messageGuid,
220
- targetMessageGuid: mutationType === "reaction"
221
- ? stripPartPrefix(readString(data, "associatedMessageGuid"))
222
- : undefined,
346
+ targetMessageGuid,
223
347
  timestamp,
224
348
  fromMe,
225
349
  sender,
226
350
  chat,
227
351
  shouldNotifyAgent: mutationType === "reaction" || mutationType === "edit" || mutationType === "unsend",
228
- textForAgent: buildMutationText(mutationType, data, reactionName),
352
+ textForAgent: reaction
353
+ ? renderBlueBubblesReactionText(reaction, { guid: targetMessageGuid })
354
+ : buildMutationText(mutationType, data),
229
355
  requiresRepair,
356
+ ...(reaction ? { reaction } : {}),
357
+ ...(editedText !== undefined ? { editedText } : {}),
358
+ ...(revision ? { revision } : {}),
359
+ ...(effectiveTimestamp !== undefined ? { effectiveTimestamp } : {}),
360
+ ...(retractionTimestamp !== undefined ? { retractionTimestamp } : {}),
230
361
  }
231
362
  : {
232
363
  kind: "message",
@@ -236,7 +367,7 @@ function normalizeBlueBubblesEvent(payload) {
236
367
  fromMe,
237
368
  sender,
238
369
  chat,
239
- text: readString(data, "text")?.trim() ?? "",
370
+ text: readString(data, "text") ?? "",
240
371
  textForAgent: formatMessageText(data, attachments),
241
372
  attachments,
242
373
  balloonBundleId: readString(data, "balloonBundleId")?.trim() || undefined,
@@ -35,12 +35,13 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getBlueBubblesMutationLogPath = getBlueBubblesMutationLogPath;
37
37
  exports.recordBlueBubblesMutation = recordBlueBubblesMutation;
38
+ exports.listRecordedBlueBubblesMutations = listRecordedBlueBubblesMutations;
38
39
  exports.listBlueBubblesRecoveryCandidates = listBlueBubblesRecoveryCandidates;
39
40
  const fs = __importStar(require("node:fs"));
40
41
  const path = __importStar(require("node:path"));
41
- const runtime_1 = require("../nerves/runtime");
42
- const identity_1 = require("../heart/identity");
43
- const config_1 = require("../heart/config");
42
+ const runtime_1 = require("../../nerves/runtime");
43
+ const identity_1 = require("../../heart/identity");
44
+ const config_1 = require("../../heart/config");
44
45
  function getBlueBubblesMutationLogPath(agentName, sessionKey) {
45
46
  return path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "mutations", `${(0, config_1.sanitizeKey)(sessionKey)}.ndjson`);
46
47
  }
@@ -73,7 +74,7 @@ function recordBlueBubblesMutation(agentName, event) {
73
74
  });
74
75
  return filePath;
75
76
  }
76
- function listBlueBubblesRecoveryCandidates(agentName) {
77
+ function readBlueBubblesMutationRows(agentName) {
77
78
  const rootDir = path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "mutations");
78
79
  let files;
79
80
  try {
@@ -82,7 +83,7 @@ function listBlueBubblesRecoveryCandidates(agentName) {
82
83
  catch {
83
84
  return [];
84
85
  }
85
- const deduped = new Map();
86
+ const entries = [];
86
87
  for (const file of files.filter((entry) => entry.endsWith(".ndjson")).sort()) {
87
88
  const filePath = path.join(rootDir, file);
88
89
  let raw = "";
@@ -98,19 +99,29 @@ function listBlueBubblesRecoveryCandidates(agentName) {
98
99
  continue;
99
100
  try {
100
101
  const entry = JSON.parse(trimmed);
101
- if (typeof entry.messageGuid !== "string"
102
- || !entry.messageGuid.trim()
103
- || entry.fromMe
104
- || entry.shouldNotifyAgent
105
- || (entry.mutationType !== "read" && entry.mutationType !== "delivery")) {
102
+ if (typeof entry.messageGuid !== "string" || !entry.messageGuid.trim())
106
103
  continue;
107
- }
108
- deduped.set(entry.messageGuid, entry);
104
+ entries.push(entry);
109
105
  }
110
106
  catch {
111
- // ignore malformed recovery candidates
107
+ // Keep malformed legacy rows inert while retaining readable audit rows.
112
108
  }
113
109
  }
114
110
  }
111
+ return entries;
112
+ }
113
+ function listRecordedBlueBubblesMutations(agentName) {
114
+ return readBlueBubblesMutationRows(agentName).filter((entry) => (typeof entry.sessionKey === "string" && entry.sessionKey.trim().length > 0));
115
+ }
116
+ function listBlueBubblesRecoveryCandidates(agentName) {
117
+ const deduped = new Map();
118
+ for (const entry of readBlueBubblesMutationRows(agentName)) {
119
+ if (entry.fromMe !== false
120
+ || entry.shouldNotifyAgent
121
+ || (entry.mutationType !== "read" && entry.mutationType !== "delivery")) {
122
+ continue;
123
+ }
124
+ deduped.set(entry.messageGuid, entry);
125
+ }
115
126
  return [...deduped.values()].sort((left, right) => left.recordedAt.localeCompare(right.recordedAt));
116
127
  }
@@ -0,0 +1,308 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.BLUEBUBBLES_OUTBOUND_STATE_POLICY_VERSION = void 0;
37
+ exports.blueBubblesOutboundRecordPath = blueBubblesOutboundRecordPath;
38
+ exports.buildBlueBubblesRouteProof = buildBlueBubblesRouteProof;
39
+ exports.buildBlueBubblesAttachmentProof = buildBlueBubblesAttachmentProof;
40
+ exports.readBlueBubblesOutboundRecord = readBlueBubblesOutboundRecord;
41
+ exports.readBlueBubblesOutboundRecordByIdempotencyKey = readBlueBubblesOutboundRecordByIdempotencyKey;
42
+ exports.reserveBlueBubblesOutbound = reserveBlueBubblesOutbound;
43
+ exports.markBlueBubblesOutboundAccepted = markBlueBubblesOutboundAccepted;
44
+ exports.markBlueBubblesOutboundEnqueued = markBlueBubblesOutboundEnqueued;
45
+ exports.markBlueBubblesOutboundLocalVisible = markBlueBubblesOutboundLocalVisible;
46
+ exports.markBlueBubblesOutboundDelivered = markBlueBubblesOutboundDelivered;
47
+ exports.markBlueBubblesOutboundFailed = markBlueBubblesOutboundFailed;
48
+ exports.markBlueBubblesOutboundPendingManualVerification = markBlueBubblesOutboundPendingManualVerification;
49
+ const fs = __importStar(require("node:fs"));
50
+ const path = __importStar(require("node:path"));
51
+ const node_crypto_1 = require("node:crypto");
52
+ const runtime_1 = require("../../nerves/runtime");
53
+ exports.BLUEBUBBLES_OUTBOUND_STATE_POLICY_VERSION = "bluebubbles-outbound-state/v1";
54
+ function sha256Hex(input) {
55
+ return (0, node_crypto_1.createHash)("sha256").update(input).digest("hex");
56
+ }
57
+ function hash(input) {
58
+ return `sha256:${sha256Hex(canonicalJson(input))}`;
59
+ }
60
+ function canonicalJson(value) {
61
+ if (Array.isArray(value))
62
+ return `[${value.map((entry) => canonicalJson(entry)).join(",")}]`;
63
+ if (value && typeof value === "object") {
64
+ const record = value;
65
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
66
+ }
67
+ return JSON.stringify(value);
68
+ }
69
+ function nowIso(input) {
70
+ return input ?? new Date().toISOString();
71
+ }
72
+ function recordIdFor(idempotencyKey) {
73
+ return `bbout_${sha256Hex(`bluebubbles-outbound:${idempotencyKey}`).slice(0, 32)}`;
74
+ }
75
+ function normalizeText(value) {
76
+ return value.trim().replace(/\s+/g, " ");
77
+ }
78
+ function endpointOrigin(serverUrl) {
79
+ const parsed = new URL(serverUrl);
80
+ return parsed.origin;
81
+ }
82
+ function blueBubblesOutboundDir(agentRoot) {
83
+ return path.join(agentRoot, "state", "bluebubbles", "outbound");
84
+ }
85
+ function blueBubblesOutboundRecordPath(agentRoot, recordId) {
86
+ return path.join(blueBubblesOutboundDir(agentRoot), `${recordId}.json`);
87
+ }
88
+ function buildBlueBubblesRouteProof(chat) {
89
+ const participantHandles = [...chat.participantHandles].sort();
90
+ const base = {
91
+ chatGuid: chat.chatGuid?.trim() || null,
92
+ chatIdentifier: chat.chatIdentifier?.trim() || null,
93
+ sendTarget: chat.sendTarget,
94
+ sessionKey: chat.sessionKey,
95
+ isGroup: chat.isGroup,
96
+ participantHandles,
97
+ };
98
+ return {
99
+ chatGuid: base.chatGuid,
100
+ chatIdentifier: base.chatIdentifier,
101
+ sendTarget: base.sendTarget,
102
+ sessionKey: base.sessionKey,
103
+ isGroup: base.isGroup,
104
+ participantHandlesHash: hash(participantHandles),
105
+ routeHash: hash(base),
106
+ rawParticipantHandlesStored: false,
107
+ };
108
+ }
109
+ function buildBlueBubblesAttachmentProof(input) {
110
+ const proof = {
111
+ endpointOrigin: endpointOrigin(input.serverUrl),
112
+ accountId: input.accountId?.trim() || null,
113
+ };
114
+ return {
115
+ ...proof,
116
+ identityHash: hash(proof),
117
+ secretStored: false,
118
+ };
119
+ }
120
+ function buildRecord(input) {
121
+ const createdAt = nowIso(input.now);
122
+ const idempotencyKey = input.idempotencyKey.trim();
123
+ const text = normalizeText(input.text);
124
+ return {
125
+ schemaVersion: 1,
126
+ policyVersion: exports.BLUEBUBBLES_OUTBOUND_STATE_POLICY_VERSION,
127
+ recordId: recordIdFor(idempotencyKey),
128
+ idempotencyKey,
129
+ idempotencyHash: hash(idempotencyKey),
130
+ status: "reserved",
131
+ createdAt,
132
+ updatedAt: createdAt,
133
+ tempGuid: input.tempGuid.trim(),
134
+ routeProof: buildBlueBubblesRouteProof(input.chat),
135
+ attachmentProof: buildBlueBubblesAttachmentProof(input.attachment),
136
+ textHash: hash(text),
137
+ textLength: text.length,
138
+ ...(input.replyToMessageGuid?.trim() ? { replyToMessageGuidHash: hash(input.replyToMessageGuid.trim()) } : {}),
139
+ contentStored: false,
140
+ };
141
+ }
142
+ function writeJsonAtomic(filePath, value) {
143
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
144
+ const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
145
+ fs.writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
146
+ fs.renameSync(tmp, filePath);
147
+ }
148
+ function readJson(filePath) {
149
+ if (!fs.existsSync(filePath))
150
+ return null;
151
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
152
+ }
153
+ function isOutboundRecord(value) {
154
+ const row = value;
155
+ return !!row
156
+ && row.schemaVersion === 1
157
+ && row.policyVersion === exports.BLUEBUBBLES_OUTBOUND_STATE_POLICY_VERSION
158
+ && typeof row.recordId === "string"
159
+ && typeof row.idempotencyKey === "string"
160
+ && typeof row.idempotencyHash === "string"
161
+ && typeof row.status === "string"
162
+ && typeof row.createdAt === "string"
163
+ && typeof row.updatedAt === "string"
164
+ && typeof row.tempGuid === "string"
165
+ && typeof row.textHash === "string"
166
+ && typeof row.textLength === "number"
167
+ && row.contentStored === false;
168
+ }
169
+ function readBlueBubblesOutboundRecord(agentRoot, recordId) {
170
+ try {
171
+ const parsed = readJson(blueBubblesOutboundRecordPath(agentRoot, recordId));
172
+ return isOutboundRecord(parsed) ? parsed : null;
173
+ }
174
+ catch {
175
+ return null;
176
+ }
177
+ }
178
+ function readBlueBubblesOutboundRecordByIdempotencyKey(agentRoot, idempotencyKey) {
179
+ return readBlueBubblesOutboundRecord(agentRoot, recordIdFor(idempotencyKey.trim()));
180
+ }
181
+ function writeBlueBubblesOutboundRecord(agentRoot, record) {
182
+ writeJsonAtomic(blueBubblesOutboundRecordPath(agentRoot, record.recordId), record);
183
+ return record;
184
+ }
185
+ function identityMatches(left, right) {
186
+ return left.routeProof.routeHash === right.routeProof.routeHash
187
+ && left.attachmentProof.identityHash === right.attachmentProof.identityHash
188
+ && left.textHash === right.textHash
189
+ && left.replyToMessageGuidHash === right.replyToMessageGuidHash;
190
+ }
191
+ function emitDuplicate(record) {
192
+ (0, runtime_1.emitNervesEvent)({
193
+ level: "warn",
194
+ component: "senses",
195
+ event: "senses.bluebubbles_outbound_duplicate",
196
+ message: "duplicate bluebubbles outbound reservation suppressed",
197
+ meta: { recordId: record.recordId, status: record.status },
198
+ });
199
+ }
200
+ function markPendingManualVerification(agentRoot, record, decidedAt, reason) {
201
+ const updated = writeBlueBubblesOutboundRecord(agentRoot, {
202
+ ...record,
203
+ status: "pending-manual-verification",
204
+ updatedAt: decidedAt,
205
+ manualVerificationReason: reason,
206
+ });
207
+ (0, runtime_1.emitNervesEvent)({
208
+ level: "warn",
209
+ component: "senses",
210
+ event: "senses.bluebubbles_outbound_pending_manual_verification",
211
+ message: "bluebubbles outbound requires manual verification",
212
+ meta: { recordId: updated.recordId, reason },
213
+ });
214
+ return updated;
215
+ }
216
+ function reserveBlueBubblesOutbound(input) {
217
+ const record = buildRecord(input);
218
+ const filePath = blueBubblesOutboundRecordPath(input.agentRoot, record.recordId);
219
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
220
+ try {
221
+ const fd = fs.openSync(filePath, "wx");
222
+ try {
223
+ fs.writeFileSync(fd, `${JSON.stringify(record, null, 2)}\n`, "utf-8");
224
+ }
225
+ finally {
226
+ fs.closeSync(fd);
227
+ }
228
+ (0, runtime_1.emitNervesEvent)({
229
+ component: "senses",
230
+ event: "senses.bluebubbles_outbound_reserved",
231
+ message: "reserved bluebubbles outbound idempotency key",
232
+ meta: { recordId: record.recordId, textLength: record.textLength },
233
+ });
234
+ return { status: "reserved", record };
235
+ }
236
+ catch (error) {
237
+ /* v8 ignore next -- non-EEXIST filesystem failures are rethrown fail-closed; hard to trigger portably after mkdir succeeds @preserve */
238
+ if (!isNodeFileExistsError(error))
239
+ throw error;
240
+ const existing = readBlueBubblesOutboundRecord(input.agentRoot, record.recordId);
241
+ if (!existing)
242
+ throw new Error(`bluebubbles outbound reservation is unreadable: ${record.recordId}`);
243
+ if (identityMatches(existing, record)) {
244
+ emitDuplicate(existing);
245
+ return { status: "duplicate", record: existing };
246
+ }
247
+ const updated = markPendingManualVerification(input.agentRoot, existing, nowIso(input.now), "identity-proof-mismatch");
248
+ return { status: "pending-manual-verification", reason: "identity-proof-mismatch", record: updated };
249
+ }
250
+ }
251
+ function isNodeFileExistsError(error) {
252
+ return typeof error === "object" && error !== null && error.code === "EEXIST";
253
+ }
254
+ function updateStatus(agentRoot, recordId, status, updatedAt, patch) {
255
+ const existing = readBlueBubblesOutboundRecord(agentRoot, recordId);
256
+ if (!existing)
257
+ throw new Error(`bluebubbles outbound record not found: ${recordId}`);
258
+ const updated = writeBlueBubblesOutboundRecord(agentRoot, {
259
+ ...existing,
260
+ ...patch,
261
+ status,
262
+ updatedAt,
263
+ });
264
+ (0, runtime_1.emitNervesEvent)({
265
+ component: "senses",
266
+ event: "senses.bluebubbles_outbound_state_changed",
267
+ message: "bluebubbles outbound state changed",
268
+ meta: { recordId, status },
269
+ });
270
+ return updated;
271
+ }
272
+ function markBlueBubblesOutboundAccepted(input) {
273
+ return updateStatus(input.agentRoot, input.recordId, "accepted", input.acceptedAt, {
274
+ acceptedAt: input.acceptedAt,
275
+ ...(input.messageGuid?.trim() ? { messageGuid: input.messageGuid.trim() } : {}),
276
+ });
277
+ }
278
+ function markBlueBubblesOutboundEnqueued(input) {
279
+ return updateStatus(input.agentRoot, input.recordId, "enqueued", input.enqueuedAt, {
280
+ enqueuedAt: input.enqueuedAt,
281
+ messageGuid: input.messageGuid.trim(),
282
+ });
283
+ }
284
+ function markBlueBubblesOutboundLocalVisible(input) {
285
+ return updateStatus(input.agentRoot, input.recordId, "local-visible", input.visibleAt, {
286
+ localVisibleAt: input.visibleAt,
287
+ messageGuid: input.messageGuid.trim(),
288
+ ...(input.tempGuid?.trim() ? { tempGuid: input.tempGuid.trim() } : {}),
289
+ });
290
+ }
291
+ function markBlueBubblesOutboundDelivered(input) {
292
+ return updateStatus(input.agentRoot, input.recordId, "delivered", input.deliveredAt, {
293
+ deliveredAt: input.deliveredAt,
294
+ ...(input.messageGuid?.trim() ? { messageGuid: input.messageGuid.trim() } : {}),
295
+ });
296
+ }
297
+ function markBlueBubblesOutboundFailed(input) {
298
+ return updateStatus(input.agentRoot, input.recordId, "failed", input.failedAt, {
299
+ failedAt: input.failedAt,
300
+ failureReason: input.reason.slice(0, 500),
301
+ });
302
+ }
303
+ function markBlueBubblesOutboundPendingManualVerification(input) {
304
+ const existing = readBlueBubblesOutboundRecord(input.agentRoot, input.recordId);
305
+ if (!existing)
306
+ throw new Error(`bluebubbles outbound record not found: ${input.recordId}`);
307
+ return markPendingManualVerification(input.agentRoot, existing, input.decidedAt, input.reason);
308
+ }