@ouro.bot/cli 0.1.0-alpha.51 → 0.1.0-alpha.510

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 (372) hide show
  1. package/README.md +133 -19
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  5. package/changelog.json +3245 -0
  6. package/dist/arc/attention-types.js +8 -0
  7. package/dist/arc/cares.js +140 -0
  8. package/dist/arc/episodes.js +117 -0
  9. package/dist/arc/intentions.js +133 -0
  10. package/dist/arc/json-store.js +117 -0
  11. package/dist/arc/obligations.js +237 -0
  12. package/dist/arc/packets.js +193 -0
  13. package/dist/arc/presence.js +185 -0
  14. package/dist/arc/task-lifecycle.js +65 -0
  15. package/dist/heart/active-work.js +867 -35
  16. package/dist/heart/agent-entry.js +58 -3
  17. package/dist/heart/attachments/image-normalize.js +194 -0
  18. package/dist/heart/attachments/materialize.js +97 -0
  19. package/dist/heart/attachments/originals.js +88 -0
  20. package/dist/heart/attachments/render.js +29 -0
  21. package/dist/heart/attachments/sources/adapter.js +2 -0
  22. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  23. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  24. package/dist/heart/attachments/sources/index.js +16 -0
  25. package/dist/heart/attachments/store.js +103 -0
  26. package/dist/heart/attachments/types.js +93 -0
  27. package/dist/heart/auth/auth-flow.js +426 -0
  28. package/dist/heart/background-operations.js +281 -0
  29. package/dist/heart/bundle-state.js +168 -0
  30. package/dist/heart/commitments.js +111 -0
  31. package/dist/heart/config-registry.js +304 -0
  32. package/dist/heart/config.js +119 -129
  33. package/dist/heart/core.js +878 -244
  34. package/dist/heart/cross-chat-delivery.js +131 -0
  35. package/dist/heart/daemon/agent-config-check.js +490 -0
  36. package/dist/heart/daemon/agent-discovery.js +79 -3
  37. package/dist/heart/daemon/agent-service.js +360 -0
  38. package/dist/heart/daemon/agentic-repair.js +216 -0
  39. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  40. package/dist/heart/daemon/cadence.js +70 -0
  41. package/dist/heart/daemon/cli-defaults.js +640 -0
  42. package/dist/heart/daemon/cli-exec.js +7239 -0
  43. package/dist/heart/daemon/cli-help.js +493 -0
  44. package/dist/heart/daemon/cli-parse.js +1533 -0
  45. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  46. package/dist/heart/daemon/cli-render.js +561 -0
  47. package/dist/heart/daemon/cli-types.js +8 -0
  48. package/dist/heart/daemon/connect-bay.js +323 -0
  49. package/dist/heart/daemon/daemon-cli.js +29 -1631
  50. package/dist/heart/daemon/daemon-entry.js +345 -3
  51. package/dist/heart/daemon/daemon-health.js +141 -0
  52. package/dist/heart/daemon/daemon-runtime-sync.js +190 -12
  53. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  54. package/dist/heart/daemon/daemon.js +677 -58
  55. package/dist/heart/daemon/dns-workflow.js +394 -0
  56. package/dist/heart/daemon/doctor-types.js +8 -0
  57. package/dist/heart/daemon/doctor.js +750 -0
  58. package/dist/heart/daemon/health-monitor.js +92 -1
  59. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  60. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  61. package/dist/heart/daemon/http-health-probe.js +80 -0
  62. package/dist/heart/daemon/human-command-screens.js +234 -0
  63. package/dist/heart/daemon/human-readiness.js +114 -0
  64. package/dist/heart/daemon/inner-status.js +89 -0
  65. package/dist/heart/daemon/interactive-repair.js +394 -0
  66. package/dist/heart/daemon/launchd.js +25 -5
  67. package/dist/heart/daemon/log-tailer.js +82 -12
  68. package/dist/heart/daemon/logs-prune.js +110 -0
  69. package/dist/heart/daemon/message-router.js +2 -2
  70. package/dist/heart/daemon/os-cron-deps.js +134 -0
  71. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  72. package/dist/heart/daemon/ouro-entry.js +3 -1
  73. package/dist/heart/daemon/process-manager.js +214 -0
  74. package/dist/heart/daemon/provider-discovery.js +137 -0
  75. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  76. package/dist/heart/daemon/pulse.js +475 -0
  77. package/dist/heart/daemon/readiness-repair.js +365 -0
  78. package/dist/heart/daemon/run-hooks.js +2 -0
  79. package/dist/heart/daemon/runtime-logging.js +67 -16
  80. package/dist/heart/daemon/runtime-metadata.js +73 -0
  81. package/dist/heart/daemon/runtime-mode.js +67 -0
  82. package/dist/heart/daemon/safe-mode.js +161 -0
  83. package/dist/heart/daemon/sense-manager.js +178 -37
  84. package/dist/heart/daemon/session-id-resolver.js +131 -0
  85. package/dist/heart/daemon/skill-management-installer.js +94 -0
  86. package/dist/heart/daemon/socket-client.js +109 -4
  87. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  88. package/dist/heart/daemon/startup-tui.js +264 -0
  89. package/dist/heart/daemon/task-scheduler.js +3 -25
  90. package/dist/heart/daemon/terminal-ui.js +499 -0
  91. package/dist/heart/daemon/thoughts.js +162 -17
  92. package/dist/heart/daemon/up-progress.js +366 -0
  93. package/dist/heart/daemon/vault-items.js +56 -0
  94. package/dist/heart/delegation.js +1 -1
  95. package/dist/heart/habits/habit-migration.js +189 -0
  96. package/dist/heart/habits/habit-parser.js +140 -0
  97. package/dist/heart/habits/habit-runtime-state.js +100 -0
  98. package/dist/heart/habits/habit-scheduler.js +372 -0
  99. package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
  100. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  101. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  102. package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
  103. package/dist/heart/identity.js +205 -66
  104. package/dist/heart/kept-notes.js +357 -0
  105. package/dist/heart/kicks.js +1 -1
  106. package/dist/heart/machine-identity.js +161 -0
  107. package/dist/heart/mail-import-discovery.js +353 -0
  108. package/dist/heart/mcp/mcp-server.js +653 -0
  109. package/dist/heart/migrate-config.js +100 -0
  110. package/dist/heart/model-capabilities.js +19 -0
  111. package/dist/heart/outlook/outlook-http-hooks.js +66 -0
  112. package/dist/heart/outlook/outlook-http-response.js +7 -0
  113. package/dist/heart/outlook/outlook-http-routes.js +244 -0
  114. package/dist/heart/outlook/outlook-http-static.js +103 -0
  115. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  116. package/dist/heart/outlook/outlook-http.js +99 -0
  117. package/dist/heart/outlook/outlook-read.js +31 -0
  118. package/dist/heart/outlook/outlook-types.js +27 -0
  119. package/dist/heart/outlook/outlook-view.js +195 -0
  120. package/dist/heart/outlook/readers/agent-machine.js +382 -0
  121. package/dist/heart/outlook/readers/continuity-readers.js +336 -0
  122. package/dist/heart/outlook/readers/mail.js +362 -0
  123. package/dist/heart/outlook/readers/runtime-readers.js +644 -0
  124. package/dist/heart/outlook/readers/sessions.js +232 -0
  125. package/dist/heart/outlook/readers/shared.js +111 -0
  126. package/dist/heart/platform.js +81 -0
  127. package/dist/heart/provider-attempt.js +134 -0
  128. package/dist/heart/provider-binding-resolver.js +255 -0
  129. package/dist/heart/provider-credentials.js +424 -0
  130. package/dist/heart/provider-failover.js +301 -0
  131. package/dist/heart/provider-models.js +81 -0
  132. package/dist/heart/provider-ping.js +262 -0
  133. package/dist/heart/provider-state.js +216 -0
  134. package/dist/heart/provider-visibility.js +188 -0
  135. package/dist/heart/providers/anthropic-token.js +131 -0
  136. package/dist/heart/providers/anthropic.js +139 -52
  137. package/dist/heart/providers/azure.js +97 -13
  138. package/dist/heart/providers/error-classification.js +127 -0
  139. package/dist/heart/providers/github-copilot.js +145 -0
  140. package/dist/heart/providers/minimax-vlm.js +189 -0
  141. package/dist/heart/providers/minimax.js +26 -8
  142. package/dist/heart/providers/openai-codex.js +55 -40
  143. package/dist/heart/runtime-capability-check.js +170 -0
  144. package/dist/heart/runtime-credentials.js +260 -0
  145. package/dist/heart/sense-truth.js +11 -4
  146. package/dist/heart/session-activity.js +43 -22
  147. package/dist/heart/session-events.js +1150 -0
  148. package/dist/heart/session-playback-cli-main.js +5 -0
  149. package/dist/heart/session-playback-cli.js +36 -0
  150. package/dist/heart/session-playback.js +231 -0
  151. package/dist/heart/session-stats-cli-main.js +5 -0
  152. package/dist/heart/session-stats.js +182 -0
  153. package/dist/heart/session-transcript.js +167 -0
  154. package/dist/heart/start-of-turn-packet.js +345 -0
  155. package/dist/heart/streaming.js +44 -27
  156. package/dist/heart/sync.js +332 -0
  157. package/dist/heart/target-resolution.js +127 -0
  158. package/dist/heart/tempo.js +93 -0
  159. package/dist/heart/temporal-view.js +41 -0
  160. package/dist/heart/tool-activity-callbacks.js +36 -0
  161. package/dist/heart/tool-description.js +135 -0
  162. package/dist/heart/tool-friction.js +55 -0
  163. package/dist/heart/tool-loop.js +200 -0
  164. package/dist/heart/turn-context.js +372 -0
  165. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  166. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  167. package/dist/heart/versioning/ouro-path-installer.js +425 -0
  168. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  169. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  170. package/dist/heart/{daemon → versioning}/update-checker.js +5 -1
  171. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  172. package/dist/mailroom/attention.js +167 -0
  173. package/dist/mailroom/autonomy.js +209 -0
  174. package/dist/mailroom/blob-store.js +606 -0
  175. package/dist/mailroom/body-cache.js +61 -0
  176. package/dist/mailroom/core.js +672 -0
  177. package/dist/mailroom/entry.js +160 -0
  178. package/dist/mailroom/file-store.js +426 -0
  179. package/dist/mailroom/mbox-import.js +382 -0
  180. package/dist/mailroom/outbound.js +380 -0
  181. package/dist/mailroom/policy.js +263 -0
  182. package/dist/mailroom/reader.js +219 -0
  183. package/dist/mailroom/search-cache.js +182 -0
  184. package/dist/mailroom/search-relevance.js +319 -0
  185. package/dist/mailroom/smtp-ingress.js +176 -0
  186. package/dist/mailroom/source-state.js +176 -0
  187. package/dist/mailroom/thread.js +109 -0
  188. package/dist/mailroom/travel-extract.js +89 -0
  189. package/dist/mind/bundle-manifest.js +7 -1
  190. package/dist/mind/context.js +165 -101
  191. package/dist/mind/diary-integrity.js +60 -0
  192. package/dist/mind/{memory.js → diary.js} +74 -93
  193. package/dist/mind/embedding-provider.js +60 -0
  194. package/dist/mind/file-state.js +179 -0
  195. package/dist/mind/friends/channel.js +30 -0
  196. package/dist/mind/friends/group-context.js +144 -0
  197. package/dist/mind/friends/resolver.js +54 -2
  198. package/dist/mind/friends/store-file.js +39 -3
  199. package/dist/mind/friends/trust-explanation.js +74 -0
  200. package/dist/mind/friends/types.js +2 -2
  201. package/dist/mind/journal-index.js +161 -0
  202. package/dist/mind/note-search.js +268 -0
  203. package/dist/mind/obligation-steering.js +221 -0
  204. package/dist/mind/pending.js +4 -0
  205. package/dist/mind/prompt-refresh.js +3 -2
  206. package/dist/mind/prompt.js +940 -111
  207. package/dist/mind/provenance-trust.js +26 -0
  208. package/dist/mind/scrutiny.js +173 -0
  209. package/dist/nerves/cli-logging.js +7 -1
  210. package/dist/nerves/coverage/audit-rules.js +15 -6
  211. package/dist/nerves/coverage/audit.js +28 -2
  212. package/dist/nerves/coverage/cli.js +1 -1
  213. package/dist/nerves/coverage/contract.js +5 -5
  214. package/dist/nerves/coverage/file-completeness.js +114 -5
  215. package/dist/nerves/coverage/run-artifacts.js +1 -1
  216. package/dist/nerves/event-buffer.js +111 -0
  217. package/dist/nerves/index.js +224 -4
  218. package/dist/nerves/observation.js +20 -0
  219. package/dist/nerves/redact.js +79 -0
  220. package/dist/nerves/review/cli-main.js +5 -0
  221. package/dist/nerves/review/cli.js +156 -0
  222. package/dist/nerves/review/core.js +152 -0
  223. package/dist/nerves/runtime.js +5 -1
  224. package/dist/outlook-ui/assets/index-BPr5vNuM.css +1 -0
  225. package/dist/outlook-ui/assets/index-Cm51CY9W.js +61 -0
  226. package/dist/outlook-ui/index.html +15 -0
  227. package/dist/repertoire/ado-client.js +15 -56
  228. package/dist/repertoire/ado-semantic.js +11 -10
  229. package/dist/repertoire/api-client.js +97 -0
  230. package/dist/repertoire/bitwarden-store.js +774 -0
  231. package/dist/repertoire/bundle-templates.js +72 -0
  232. package/dist/repertoire/bw-installer.js +180 -0
  233. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  234. package/dist/repertoire/coding/context-pack.js +330 -0
  235. package/dist/repertoire/coding/feedback.js +197 -30
  236. package/dist/repertoire/coding/manager.js +158 -9
  237. package/dist/repertoire/coding/spawner.js +55 -9
  238. package/dist/repertoire/coding/tools.js +170 -7
  239. package/dist/repertoire/commerce-errors.js +109 -0
  240. package/dist/repertoire/commerce-self-test.js +156 -0
  241. package/dist/repertoire/credential-access.js +111 -0
  242. package/dist/repertoire/duffel-client.js +185 -0
  243. package/dist/repertoire/github-client.js +14 -55
  244. package/dist/repertoire/graph-client.js +11 -52
  245. package/dist/repertoire/guardrails.js +396 -0
  246. package/dist/repertoire/mcp-client.js +255 -0
  247. package/dist/repertoire/mcp-manager.js +305 -0
  248. package/dist/repertoire/mcp-tools.js +63 -0
  249. package/dist/repertoire/shell-sessions.js +133 -0
  250. package/dist/repertoire/skills.js +15 -24
  251. package/dist/repertoire/stripe-client.js +131 -0
  252. package/dist/repertoire/tasks/board.js +31 -5
  253. package/dist/repertoire/tasks/fix.js +182 -0
  254. package/dist/repertoire/tasks/index.js +16 -4
  255. package/dist/repertoire/tasks/lifecycle.js +2 -2
  256. package/dist/repertoire/tasks/parser.js +3 -2
  257. package/dist/repertoire/tasks/scanner.js +194 -37
  258. package/dist/repertoire/tasks/transitions.js +16 -78
  259. package/dist/repertoire/tool-results.js +29 -0
  260. package/dist/repertoire/tools-attachments.js +317 -0
  261. package/dist/repertoire/tools-base.js +46 -955
  262. package/dist/repertoire/tools-bluebubbles.js +1 -0
  263. package/dist/repertoire/tools-bridge.js +141 -0
  264. package/dist/repertoire/tools-bundle.js +984 -0
  265. package/dist/repertoire/tools-config.js +185 -0
  266. package/dist/repertoire/tools-continuity.js +248 -0
  267. package/dist/repertoire/tools-credential.js +381 -0
  268. package/dist/repertoire/tools-files.js +342 -0
  269. package/dist/repertoire/tools-flight.js +224 -0
  270. package/dist/repertoire/tools-flow.js +105 -0
  271. package/dist/repertoire/tools-github.js +1 -7
  272. package/dist/repertoire/tools-mail.js +1477 -0
  273. package/dist/repertoire/tools-notes.js +376 -0
  274. package/dist/repertoire/tools-session.js +749 -0
  275. package/dist/repertoire/tools-shell.js +120 -0
  276. package/dist/repertoire/tools-stripe.js +180 -0
  277. package/dist/repertoire/tools-surface.js +243 -0
  278. package/dist/repertoire/tools-teams.js +9 -39
  279. package/dist/repertoire/tools-travel.js +125 -0
  280. package/dist/repertoire/tools-trip.js +422 -0
  281. package/dist/repertoire/tools-user-profile.js +144 -0
  282. package/dist/repertoire/tools-vault.js +40 -0
  283. package/dist/repertoire/tools.js +107 -100
  284. package/dist/repertoire/travel-api-client.js +360 -0
  285. package/dist/repertoire/user-profile.js +131 -0
  286. package/dist/repertoire/vault-setup.js +246 -0
  287. package/dist/repertoire/vault-unlock.js +561 -0
  288. package/dist/scripts/claude-code-hook.js +41 -0
  289. package/dist/scripts/claude-code-stop-hook.js +47 -0
  290. package/dist/senses/attention-queue.js +116 -0
  291. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  292. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  293. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  294. package/dist/senses/bluebubbles/entry.js +73 -0
  295. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  296. package/dist/senses/bluebubbles/index.js +1881 -0
  297. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  298. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  299. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  300. package/dist/senses/bluebubbles/processed-log.js +111 -0
  301. package/dist/senses/bluebubbles/replay.js +129 -0
  302. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +2 -2
  303. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  304. package/dist/senses/cli/bracketed-paste.js +82 -0
  305. package/dist/senses/cli/image-paste.js +287 -0
  306. package/dist/senses/cli/image-ref-navigation.js +75 -0
  307. package/dist/senses/cli/ink-app.js +156 -0
  308. package/dist/senses/cli/inline-diff.js +64 -0
  309. package/dist/senses/cli/input-keys.js +174 -0
  310. package/dist/senses/cli/kill-ring.js +86 -0
  311. package/dist/senses/cli/message-list.js +51 -0
  312. package/dist/senses/cli/ouro-tui.js +605 -0
  313. package/dist/senses/cli/spinner-imperative.js +135 -0
  314. package/dist/senses/cli/spinner.js +101 -0
  315. package/dist/senses/cli/status-line.js +60 -0
  316. package/dist/senses/cli/streaming-markdown.js +526 -0
  317. package/dist/senses/cli/tool-display.js +83 -0
  318. package/dist/senses/cli/tool-render.js +85 -0
  319. package/dist/senses/cli/tui-store.js +240 -0
  320. package/dist/senses/cli/virtual-list.js +35 -0
  321. package/dist/senses/cli-entry.js +60 -8
  322. package/dist/senses/cli-layout.js +187 -0
  323. package/dist/senses/cli.js +511 -209
  324. package/dist/senses/commands.js +66 -3
  325. package/dist/senses/habit-turn-message.js +108 -0
  326. package/dist/senses/inner-dialog-worker.js +175 -21
  327. package/dist/senses/inner-dialog.js +330 -27
  328. package/dist/senses/mail-entry.js +66 -0
  329. package/dist/senses/mail.js +379 -0
  330. package/dist/senses/pipeline.js +573 -164
  331. package/dist/senses/proactive-content-guard.js +51 -0
  332. package/dist/senses/shared-turn.js +248 -0
  333. package/dist/senses/surface-tool.js +68 -0
  334. package/dist/senses/teams-entry.js +60 -8
  335. package/dist/senses/teams.js +405 -170
  336. package/dist/senses/trust-gate.js +100 -5
  337. package/dist/trips/core.js +138 -0
  338. package/dist/trips/store.js +146 -0
  339. package/package.json +37 -7
  340. package/skills/agent-commerce.md +106 -0
  341. package/skills/browser-navigation.md +117 -0
  342. package/skills/commerce-setup-guide.md +116 -0
  343. package/skills/commerce-setup.md +84 -0
  344. package/skills/configure-dev-tools.md +101 -0
  345. package/skills/travel-planning.md +138 -0
  346. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  347. package/dist/heart/daemon/subagent-installer.js +0 -166
  348. package/dist/heart/session-recall.js +0 -116
  349. package/dist/mind/associative-recall.js +0 -209
  350. package/dist/senses/bluebubbles-entry.js +0 -13
  351. package/dist/senses/bluebubbles.js +0 -1142
  352. package/dist/senses/debug-activity.js +0 -148
  353. package/subagents/README.md +0 -86
  354. package/subagents/work-doer.md +0 -237
  355. package/subagents/work-merger.md +0 -618
  356. package/subagents/work-planner.md +0 -390
  357. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  358. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  359. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  360. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  361. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  362. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  363. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  364. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  365. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  366. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  367. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  368. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  369. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  370. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  371. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  372. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAttentionQueue = buildAttentionQueue;
4
+ exports.dequeueAttentionItem = dequeueAttentionItem;
5
+ exports.attentionQueueEmpty = attentionQueueEmpty;
6
+ exports.buildAttentionQueueSummary = buildAttentionQueueSummary;
7
+ const runtime_1 = require("../nerves/runtime");
8
+ // ── Queue construction ───────────────────────────────────────────
9
+ function generateItemId() {
10
+ return Math.random().toString(36).slice(2, 10);
11
+ }
12
+ function originKey(friendId, channel, key) {
13
+ return `${friendId}/${channel}/${key}`;
14
+ }
15
+ function buildAttentionQueue(input) {
16
+ const { drainedPending, outstandingObligations, friendNameResolver, packetResolver } = input;
17
+ const seen = new Set();
18
+ const items = [];
19
+ const enrichPacket = (packetId) => {
20
+ if (!packetId || !packetResolver)
21
+ return {};
22
+ const packet = packetResolver(packetId);
23
+ if (!packet)
24
+ return { packetId };
25
+ return {
26
+ packetId,
27
+ packetKind: packet.kind,
28
+ packetObjective: packet.objective,
29
+ packetSummary: packet.summary,
30
+ };
31
+ };
32
+ // Source 1: drained pending messages with delegatedFrom (current-turn delegations)
33
+ for (const msg of drainedPending) {
34
+ if (!msg.delegatedFrom)
35
+ continue;
36
+ const { friendId, channel, key, bridgeId } = msg.delegatedFrom;
37
+ const oKey = originKey(friendId, channel, key);
38
+ seen.add(oKey);
39
+ const resolvedName = friendNameResolver(friendId);
40
+ items.push({
41
+ id: msg.obligationId ?? generateItemId(),
42
+ friendId,
43
+ friendName: resolvedName ?? friendId,
44
+ channel,
45
+ key,
46
+ ...(bridgeId ? { bridgeId } : {}),
47
+ delegatedContent: msg.content,
48
+ ...(msg.obligationId ? { obligationId: msg.obligationId } : {}),
49
+ ...enrichPacket(msg.packetId),
50
+ source: "drained",
51
+ timestamp: msg.timestamp,
52
+ });
53
+ }
54
+ // Source 2: outstanding obligations (crash recovery)
55
+ for (const obligation of outstandingObligations) {
56
+ const { friendId, channel, key, bridgeId } = obligation.origin;
57
+ const oKey = originKey(friendId, channel, key);
58
+ if (seen.has(oKey))
59
+ continue; // deduplicate: prefer drained version
60
+ seen.add(oKey);
61
+ const resolvedName = friendNameResolver(friendId);
62
+ items.push({
63
+ id: obligation.id,
64
+ friendId,
65
+ friendName: resolvedName ?? friendId,
66
+ channel,
67
+ key,
68
+ ...(bridgeId ? { bridgeId } : {}),
69
+ delegatedContent: obligation.delegatedContent,
70
+ obligationId: obligation.id,
71
+ ...enrichPacket(obligation.packetId),
72
+ source: "obligation-recovery",
73
+ timestamp: obligation.createdAt,
74
+ });
75
+ }
76
+ // Sort FIFO (oldest first)
77
+ items.sort((a, b) => a.timestamp - b.timestamp);
78
+ (0, runtime_1.emitNervesEvent)({
79
+ event: "senses.attention_queue_built",
80
+ component: "senses",
81
+ message: `attention queue built with ${items.length} item(s)`,
82
+ meta: {
83
+ drainedCount: items.filter((i) => i.source === "drained").length,
84
+ recoveredCount: items.filter((i) => i.source === "obligation-recovery").length,
85
+ },
86
+ });
87
+ return items;
88
+ }
89
+ // ── Queue operations ─────────────────────────────────────────────
90
+ function dequeueAttentionItem(queue, id) {
91
+ const index = queue.findIndex((item) => item.id === id);
92
+ if (index === -1)
93
+ return null;
94
+ return queue.splice(index, 1)[0];
95
+ }
96
+ function attentionQueueEmpty(queue) {
97
+ return queue.length === 0;
98
+ }
99
+ // ── Queue visibility ─────────────────────────────────────────────
100
+ const CONTENT_PREVIEW_MAX = 80;
101
+ function buildAttentionQueueSummary(queue) {
102
+ if (queue.length === 0)
103
+ return "";
104
+ const lines = ["[internal: held work items — not messages to send]"];
105
+ for (const item of queue) {
106
+ if (item.packetKind && item.packetObjective) {
107
+ lines.push(`- [${item.id}] ${item.friendName} -> ${item.packetKind}: ${item.packetObjective}`);
108
+ continue;
109
+ }
110
+ const preview = item.delegatedContent.length > CONTENT_PREVIEW_MAX
111
+ ? `${item.delegatedContent.slice(0, CONTENT_PREVIEW_MAX - 3)}...`
112
+ : item.delegatedContent;
113
+ lines.push(`- [${item.id}] ${item.friendName} asked: "${preview}"`);
114
+ }
115
+ return lines.join("\n");
116
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cacheBlueBubblesAttachment = cacheBlueBubblesAttachment;
4
+ exports.lookupBlueBubblesAttachment = lookupBlueBubblesAttachment;
5
+ exports.resetBlueBubblesAttachmentCache = resetBlueBubblesAttachmentCache;
6
+ const runtime_1 = require("../../nerves/runtime");
7
+ /**
8
+ * Bounded process-local cache of recently-seen BlueBubbles attachment summaries.
9
+ *
10
+ * Populated at attachment-hydration time so the `describe_image` tool can
11
+ * look up a guid → summary later in the same turn (or a few turns later)
12
+ * and re-download the bytes on demand. Intentionally NOT persisted — per
13
+ * planning doc D4, session storage holds only the VLM description text,
14
+ * never the raw image bytes. The cache is cleared on daemon restart, which
15
+ * matches the product expectation that "describe_image works on recent
16
+ * messages in this session".
17
+ *
18
+ * Bounded at MAX_CACHED_ATTACHMENTS entries; oldest entries evict first
19
+ * when the limit is hit.
20
+ */
21
+ const MAX_CACHED_ATTACHMENTS = 50;
22
+ const cache = new Map();
23
+ function cacheBlueBubblesAttachment(summary) {
24
+ const guid = summary.guid?.trim();
25
+ if (!guid)
26
+ return;
27
+ // Re-insert to move to end (LRU behavior via Map insertion order).
28
+ if (cache.has(guid))
29
+ cache.delete(guid);
30
+ cache.set(guid, { ...summary });
31
+ while (cache.size > MAX_CACHED_ATTACHMENTS) {
32
+ // cache.size > 0 here, so keys().next().value is always defined.
33
+ const oldestKey = cache.keys().next().value;
34
+ cache.delete(oldestKey);
35
+ }
36
+ }
37
+ function lookupBlueBubblesAttachment(guid) {
38
+ const trimmed = guid?.trim();
39
+ if (!trimmed)
40
+ return undefined;
41
+ return cache.get(trimmed);
42
+ }
43
+ function resetBlueBubblesAttachmentCache() {
44
+ cache.clear();
45
+ }
46
+ /* v8 ignore start — module-level observability event */
47
+ (0, runtime_1.emitNervesEvent)({
48
+ component: "senses",
49
+ event: "senses.bluebubbles_attachment_cache_loaded",
50
+ message: "bluebubbles attachment cache module loaded",
51
+ meta: { maxEntries: MAX_CACHED_ATTACHMENTS },
52
+ });
53
+ /* v8 ignore stop */
@@ -0,0 +1,137 @@
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.isBlueBubblesImageAttachment = isBlueBubblesImageAttachment;
37
+ exports.downloadBlueBubblesAttachment = downloadBlueBubblesAttachment;
38
+ const path = __importStar(require("node:path"));
39
+ const image_normalize_1 = require("../../heart/attachments/image-normalize");
40
+ const runtime_1 = require("../../nerves/runtime");
41
+ const MAX_NON_IMAGE_ATTACHMENT_BYTES = 8 * 1024 * 1024;
42
+ const IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".heic", ".heif", ".tif", ".tiff", ".bmp"]);
43
+ function buildBlueBubblesApiUrl(baseUrl, endpoint, password) {
44
+ const root = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
45
+ const url = new URL(endpoint.replace(/^\//, ""), root);
46
+ url.searchParams.set("password", password);
47
+ return url.toString();
48
+ }
49
+ function inferContentType(attachment, responseType) {
50
+ const normalizedResponseType = responseType?.split(";")[0]?.trim().toLowerCase();
51
+ if (normalizedResponseType) {
52
+ return normalizedResponseType;
53
+ }
54
+ return attachment.mimeType?.trim().toLowerCase() || undefined;
55
+ }
56
+ function isBlueBubblesImageAttachment(attachment, contentType) {
57
+ if (contentType?.startsWith("image/"))
58
+ return true;
59
+ const normalizedMime = attachment.mimeType?.trim().toLowerCase();
60
+ if (normalizedMime?.startsWith("image/"))
61
+ return true;
62
+ const extension = path.extname(attachment.transferName ?? "").toLowerCase();
63
+ return IMAGE_EXTENSIONS.has(extension);
64
+ }
65
+ function maxDownloadBytesForAttachment(attachment, contentType) {
66
+ return isBlueBubblesImageAttachment(attachment, contentType)
67
+ ? image_normalize_1.MAX_ATTACHMENT_DOWNLOAD_BYTES_IMAGE
68
+ : MAX_NON_IMAGE_ATTACHMENT_BYTES;
69
+ }
70
+ async function downloadBlueBubblesAttachment(attachment, config, channelConfig, fetchImpl = fetch) {
71
+ const guid = attachment.guid?.trim();
72
+ if (!guid) {
73
+ (0, runtime_1.emitNervesEvent)({
74
+ level: "warn",
75
+ component: "senses",
76
+ event: "senses.bluebubbles_attachment_download_error",
77
+ message: "bluebubbles attachment download failed",
78
+ meta: { reason: "missing_guid" },
79
+ });
80
+ throw new Error("attachment guid missing");
81
+ }
82
+ const advertisedLimit = maxDownloadBytesForAttachment(attachment);
83
+ if (typeof attachment.totalBytes === "number" && attachment.totalBytes > advertisedLimit) {
84
+ (0, runtime_1.emitNervesEvent)({
85
+ level: "warn",
86
+ component: "senses",
87
+ event: "senses.bluebubbles_attachment_download_error",
88
+ message: "bluebubbles attachment download failed",
89
+ meta: { attachmentGuid: guid, reason: "advertised_limit_exceeded", advertisedLimit, totalBytes: attachment.totalBytes },
90
+ });
91
+ throw new Error(`attachment exceeds ${advertisedLimit} byte limit`);
92
+ }
93
+ const url = buildBlueBubblesApiUrl(config.serverUrl, `/api/v1/attachment/${encodeURIComponent(guid)}/download`, config.password);
94
+ (0, runtime_1.emitNervesEvent)({
95
+ component: "senses",
96
+ event: "senses.bluebubbles_attachment_download_start",
97
+ message: "bluebubbles attachment download started",
98
+ meta: { attachmentGuid: guid, advertisedLimit },
99
+ });
100
+ const response = await fetchImpl(url, {
101
+ method: "GET",
102
+ signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
103
+ });
104
+ if (!response.ok) {
105
+ (0, runtime_1.emitNervesEvent)({
106
+ level: "warn",
107
+ component: "senses",
108
+ event: "senses.bluebubbles_attachment_download_error",
109
+ message: "bluebubbles attachment download failed",
110
+ meta: { attachmentGuid: guid, reason: "http_error", status: response.status },
111
+ });
112
+ throw new Error(`HTTP ${response.status}`);
113
+ }
114
+ const contentType = inferContentType(attachment, response.headers.get("content-type"));
115
+ const buffer = Buffer.from(await response.arrayBuffer());
116
+ const actualLimit = maxDownloadBytesForAttachment(attachment, contentType);
117
+ if (buffer.length > actualLimit) {
118
+ (0, runtime_1.emitNervesEvent)({
119
+ level: "warn",
120
+ component: "senses",
121
+ event: "senses.bluebubbles_attachment_download_error",
122
+ message: "bluebubbles attachment download failed",
123
+ meta: { attachmentGuid: guid, reason: "actual_limit_exceeded", actualLimit, byteCount: buffer.length, contentType: contentType ?? null },
124
+ });
125
+ throw new Error(`attachment exceeds ${actualLimit} byte limit`);
126
+ }
127
+ (0, runtime_1.emitNervesEvent)({
128
+ component: "senses",
129
+ event: "senses.bluebubbles_attachment_download_end",
130
+ message: "bluebubbles attachment download completed",
131
+ meta: { attachmentGuid: guid, byteCount: buffer.length, contentType: contentType ?? null },
132
+ });
133
+ return {
134
+ buffer,
135
+ contentType,
136
+ };
137
+ }
@@ -1,12 +1,48 @@
1
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
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.createBlueBubblesClient = createBlueBubblesClient;
4
37
  const node_crypto_1 = require("node:crypto");
5
- const config_1 = require("../heart/config");
6
- const identity_1 = require("../heart/identity");
7
- const runtime_1 = require("../nerves/runtime");
8
- const bluebubbles_model_1 = require("./bluebubbles-model");
9
- const bluebubbles_media_1 = require("./bluebubbles-media");
38
+ const config_1 = require("../../heart/config");
39
+ const identity_1 = require("../../heart/identity");
40
+ const bluebubbles_health_diagnostics_1 = require("../../heart/daemon/bluebubbles-health-diagnostics");
41
+ const runtime_1 = require("../../nerves/runtime");
42
+ const minimax_1 = require("../../heart/providers/minimax");
43
+ const minimax_vlm_1 = require("../../heart/providers/minimax-vlm");
44
+ const model_1 = require("./model");
45
+ const media_1 = require("./media");
10
46
  function buildBlueBubblesApiUrl(baseUrl, endpoint, password) {
11
47
  const root = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
12
48
  const url = new URL(endpoint.replace(/^\//, ""), root);
@@ -55,6 +91,9 @@ async function parseJsonBody(response) {
55
91
  return null;
56
92
  }
57
93
  }
94
+ function describeCaughtValue(error) {
95
+ return error instanceof Error ? error.message : String(error);
96
+ }
58
97
  function buildRepairUrl(baseUrl, messageGuid, password) {
59
98
  const url = buildBlueBubblesApiUrl(baseUrl, `/api/v1/message/${encodeURIComponent(messageGuid)}`, password);
60
99
  const parsed = new URL(url);
@@ -99,6 +138,17 @@ function extractChatQueryRows(payload) {
99
138
  }
100
139
  return data.map((entry) => asRecord(entry)).filter((entry) => entry !== null);
101
140
  }
141
+ function extractMessageQueryRows(payload) {
142
+ const record = asRecord(payload);
143
+ const data = asRecord(record?.data);
144
+ const rows = Array.isArray(record?.data) ? record.data
145
+ : Array.isArray(data?.messages) ? data.messages
146
+ : Array.isArray(data?.results) ? data.results
147
+ : Array.isArray(record?.messages) ? record.messages
148
+ : Array.isArray(payload) ? payload
149
+ : [];
150
+ return rows.map((entry) => asRecord(entry)).filter((entry) => entry !== null);
151
+ }
102
152
  async function resolveChatGuidForIdentifier(config, channelConfig, chatIdentifier) {
103
153
  const trimmedIdentifier = chatIdentifier.trim();
104
154
  if (!trimmedIdentifier)
@@ -330,19 +380,19 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
330
380
  }
331
381
  },
332
382
  async checkHealth() {
333
- const url = buildBlueBubblesApiUrl(config.serverUrl, "/api/v1/message/count", config.password);
334
383
  (0, runtime_1.emitNervesEvent)({
335
384
  component: "senses",
336
385
  event: "senses.bluebubbles_healthcheck_start",
337
386
  message: "probing bluebubbles upstream health",
338
387
  meta: { serverUrl: config.serverUrl },
339
388
  });
340
- const response = await fetch(url, {
341
- method: "GET",
342
- signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
389
+ const result = await (0, bluebubbles_health_diagnostics_1.probeBlueBubblesHealth)({
390
+ serverUrl: config.serverUrl,
391
+ password: config.password,
392
+ requestTimeoutMs: channelConfig.requestTimeoutMs,
393
+ fetchImpl: fetch,
343
394
  });
344
- if (!response.ok) {
345
- const errorText = await response.text().catch(() => "");
395
+ if (!result.ok) {
346
396
  (0, runtime_1.emitNervesEvent)({
347
397
  level: "warn",
348
398
  component: "senses",
@@ -350,11 +400,13 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
350
400
  message: "bluebubbles upstream health probe failed",
351
401
  meta: {
352
402
  serverUrl: config.serverUrl,
353
- status: response.status,
354
- reason: errorText || "unknown",
403
+ status: result.status,
404
+ reason: result.reason,
405
+ classification: result.classification,
406
+ detail: (0, bluebubbles_health_diagnostics_1.redactBlueBubblesHealthDetailForNerves)(result.detail),
355
407
  },
356
408
  });
357
- throw new Error(`BlueBubbles upstream health check failed (${response.status}): ${errorText || "unknown"}`);
409
+ throw new Error(result.detail);
358
410
  }
359
411
  (0, runtime_1.emitNervesEvent)({
360
412
  component: "senses",
@@ -363,6 +415,71 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
363
415
  meta: { serverUrl: config.serverUrl },
364
416
  });
365
417
  },
418
+ async listRecentMessages(params = {}) {
419
+ const limit = Math.max(1, Math.min(100, Math.floor(params.limit ?? 50)));
420
+ const offset = Math.max(0, Math.floor(params.offset ?? 0));
421
+ const url = buildBlueBubblesApiUrl(config.serverUrl, "/api/v1/message/query", config.password);
422
+ (0, runtime_1.emitNervesEvent)({
423
+ component: "senses",
424
+ event: "senses.bluebubbles_query_recent_start",
425
+ message: "querying recent bluebubbles messages",
426
+ meta: { limit, offset },
427
+ });
428
+ const response = await fetch(url, {
429
+ method: "POST",
430
+ headers: { "Content-Type": "application/json" },
431
+ body: JSON.stringify({
432
+ limit,
433
+ offset,
434
+ sort: "DESC",
435
+ with: ["chats", "attachments", "payloadData", "messageSummaryInfo"],
436
+ }),
437
+ signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
438
+ });
439
+ if (!response.ok) {
440
+ const errorText = await response.text().catch(() => "");
441
+ (0, runtime_1.emitNervesEvent)({
442
+ level: "warn",
443
+ component: "senses",
444
+ event: "senses.bluebubbles_query_recent_error",
445
+ message: "bluebubbles recent message query failed",
446
+ meta: {
447
+ status: response.status,
448
+ reason: errorText || "unknown",
449
+ },
450
+ });
451
+ throw new Error(`BlueBubbles recent message query failed (${response.status}): ${errorText || "unknown"}`);
452
+ }
453
+ const payload = await parseJsonBody(response);
454
+ const rows = extractMessageQueryRows(payload);
455
+ const messages = [];
456
+ for (const row of rows) {
457
+ try {
458
+ messages.push((0, model_1.normalizeBlueBubblesEvent)({ type: "new-message", data: row }));
459
+ }
460
+ catch (error) {
461
+ (0, runtime_1.emitNervesEvent)({
462
+ level: "warn",
463
+ component: "senses",
464
+ event: "senses.bluebubbles_query_recent_skip",
465
+ message: "skipped unusable bluebubbles recent message row",
466
+ meta: {
467
+ reason: describeCaughtValue(error),
468
+ },
469
+ });
470
+ }
471
+ }
472
+ (0, runtime_1.emitNervesEvent)({
473
+ component: "senses",
474
+ event: "senses.bluebubbles_query_recent_end",
475
+ message: "queried recent bluebubbles messages",
476
+ meta: {
477
+ rows: rows.length,
478
+ normalized: messages.length,
479
+ },
480
+ });
481
+ return messages;
482
+ },
366
483
  async repairEvent(event) {
367
484
  if (!event.requiresRepair) {
368
485
  (0, runtime_1.emitNervesEvent)({
@@ -377,6 +494,7 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
377
494
  return event;
378
495
  }
379
496
  (0, runtime_1.emitNervesEvent)({
497
+ level: "warn",
380
498
  component: "senses",
381
499
  event: "senses.bluebubbles_repair_start",
382
500
  message: "repairing bluebubbles event by guid",
@@ -423,13 +541,13 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
423
541
  });
424
542
  return repaired;
425
543
  }
426
- const normalized = (0, bluebubbles_model_1.normalizeBlueBubblesEvent)({
544
+ const normalized = (0, model_1.normalizeBlueBubblesEvent)({
427
545
  type: event.eventType,
428
546
  data,
429
547
  });
430
548
  const recoveredMessage = event.kind === "mutation"
431
549
  && !event.shouldNotifyAgent
432
- ? (0, bluebubbles_model_1.normalizeBlueBubblesEvent)({
550
+ ? (0, model_1.normalizeBlueBubblesEvent)({
433
551
  type: "new-message",
434
552
  data,
435
553
  })
@@ -440,8 +558,42 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
440
558
  if (hydrated.kind === "message" &&
441
559
  hydrated.balloonBundleId !== "com.apple.messages.URLBalloonProvider" &&
442
560
  hydrated.attachments.length > 0) {
443
- const media = await (0, bluebubbles_media_1.hydrateBlueBubblesAttachments)(hydrated.attachments, config, channelConfig, {
444
- preferAudioInput: providerSupportsAudioInput((0, identity_1.loadAgentConfig)().provider),
561
+ const agentConfig = (0, identity_1.loadAgentConfig)();
562
+ const chatModel = agentConfig.humanFacing.model;
563
+ const chatProvider = agentConfig.humanFacing.provider;
564
+ const vlmDescribe = async (params) => {
565
+ if (chatProvider !== "minimax") {
566
+ throw new Error("VLM fallback requires a minimax credential for this agent — " +
567
+ "configure one or switch to a vision-capable chat model");
568
+ }
569
+ const { readProviderCredentialRecord } = await Promise.resolve().then(() => __importStar(require("../../heart/provider-credentials")));
570
+ const credential = await readProviderCredentialRecord((0, identity_1.getAgentName)(), "minimax");
571
+ const apiKey = credential.ok ? credential.record.credentials.apiKey : undefined;
572
+ if (!apiKey) {
573
+ throw new Error("VLM fallback: minimax API key not found in the agent vault — " +
574
+ "run `ouro auth --agent <agent> --provider minimax`");
575
+ }
576
+ return (0, minimax_vlm_1.minimaxVlmDescribe)({
577
+ apiKey: String(apiKey),
578
+ prompt: params.prompt,
579
+ imageDataUrl: params.imageDataUrl,
580
+ baseURL: minimax_1.MINIMAX_PROVIDER_BASE_URL,
581
+ attachmentGuid: params.attachmentGuid,
582
+ mimeType: params.mimeType,
583
+ chatModel: params.chatModel,
584
+ });
585
+ };
586
+ // VLM prompt context wants the user's raw inbound text — NOT
587
+ // the agent-facing rendering, which now carries the attachment
588
+ // marker after the B2 fix. Pull it from the source payload.
589
+ const rawUserText = typeof data.text === "string"
590
+ ? (data.text).trim()
591
+ : "";
592
+ const media = await (0, media_1.hydrateBlueBubblesAttachments)(hydrated.attachments, config, channelConfig, {
593
+ preferAudioInput: providerSupportsAudioInput(chatProvider),
594
+ chatModel,
595
+ vlmDescribe,
596
+ userText: rawUserText,
445
597
  });
446
598
  const transcriptSuffix = media.transcriptAdditions.map((entry) => `[${entry}]`).join("\n");
447
599
  const noticeSuffix = media.notices.map((entry) => `[${entry}]`).join("\n");
@@ -453,6 +605,7 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
453
605
  };
454
606
  }
455
607
  (0, runtime_1.emitNervesEvent)({
608
+ level: "warn",
456
609
  component: "senses",
457
610
  event: "senses.bluebubbles_repair_end",
458
611
  message: "bluebubbles event repaired",
@@ -480,5 +633,53 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
480
633
  return applyRepairNotice(event, `BlueBubbles repair failed: ${reason}`);
481
634
  }
482
635
  },
636
+ async getMessageText(messageGuid) {
637
+ const url = buildRepairUrl(config.serverUrl, messageGuid, config.password);
638
+ try {
639
+ const response = await fetch(url, {
640
+ method: "GET",
641
+ signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
642
+ });
643
+ if (!response.ok) {
644
+ (0, runtime_1.emitNervesEvent)({
645
+ level: "warn",
646
+ component: "senses",
647
+ event: "senses.bluebubbles_get_message_text_error",
648
+ message: "failed to fetch message text",
649
+ meta: { messageGuid, status: response.status },
650
+ });
651
+ return null;
652
+ }
653
+ const payload = await parseJsonBody(response);
654
+ const data = extractRepairData(payload);
655
+ if (!data || typeof data.text !== "string") {
656
+ (0, runtime_1.emitNervesEvent)({
657
+ level: "warn",
658
+ component: "senses",
659
+ event: "senses.bluebubbles_get_message_text_error",
660
+ message: "message payload missing text field",
661
+ meta: { messageGuid, hasData: !!data, textType: data ? typeof data.text : "n/a" },
662
+ });
663
+ return null;
664
+ }
665
+ (0, runtime_1.emitNervesEvent)({
666
+ component: "senses",
667
+ event: "senses.bluebubbles_get_message_text",
668
+ message: "fetched message text by guid",
669
+ meta: { messageGuid },
670
+ });
671
+ return data.text.trim() || null;
672
+ }
673
+ catch (error) {
674
+ (0, runtime_1.emitNervesEvent)({
675
+ level: "warn",
676
+ component: "senses",
677
+ event: "senses.bluebubbles_get_message_text_error",
678
+ message: "exception fetching message text",
679
+ meta: { messageGuid, reason: error instanceof Error ? error.message : String(error) },
680
+ });
681
+ return null;
682
+ }
683
+ },
483
684
  };
484
685
  }