@spinabot/brigade 1.7.0 → 1.8.0

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 (214) hide show
  1. package/dist/agents/agent-loop.d.ts +13 -0
  2. package/dist/agents/agent-loop.d.ts.map +1 -1
  3. package/dist/agents/agent-loop.js +5 -0
  4. package/dist/agents/agent-loop.js.map +1 -1
  5. package/dist/agents/channels/access-control/group-tool-policy.d.ts +73 -0
  6. package/dist/agents/channels/access-control/group-tool-policy.d.ts.map +1 -0
  7. package/dist/agents/channels/access-control/group-tool-policy.js +193 -0
  8. package/dist/agents/channels/access-control/group-tool-policy.js.map +1 -0
  9. package/dist/agents/channels/access-control/index.d.ts +1 -0
  10. package/dist/agents/channels/access-control/index.d.ts.map +1 -1
  11. package/dist/agents/channels/access-control/index.js +1 -0
  12. package/dist/agents/channels/access-control/index.js.map +1 -1
  13. package/dist/agents/channels/bluebubbles/account-config.d.ts +253 -0
  14. package/dist/agents/channels/bluebubbles/account-config.d.ts.map +1 -0
  15. package/dist/agents/channels/bluebubbles/account-config.js +486 -0
  16. package/dist/agents/channels/bluebubbles/account-config.js.map +1 -0
  17. package/dist/agents/channels/bluebubbles/account-registry.d.ts +33 -0
  18. package/dist/agents/channels/bluebubbles/account-registry.d.ts.map +1 -0
  19. package/dist/agents/channels/bluebubbles/account-registry.js +46 -0
  20. package/dist/agents/channels/bluebubbles/account-registry.js.map +1 -0
  21. package/dist/agents/channels/bluebubbles/adapter.d.ts +45 -0
  22. package/dist/agents/channels/bluebubbles/adapter.d.ts.map +1 -0
  23. package/dist/agents/channels/bluebubbles/adapter.js +366 -0
  24. package/dist/agents/channels/bluebubbles/adapter.js.map +1 -0
  25. package/dist/agents/channels/bluebubbles/catchup-cursor.d.ts +52 -0
  26. package/dist/agents/channels/bluebubbles/catchup-cursor.d.ts.map +1 -0
  27. package/dist/agents/channels/bluebubbles/catchup-cursor.js +118 -0
  28. package/dist/agents/channels/bluebubbles/catchup-cursor.js.map +1 -0
  29. package/dist/agents/channels/bluebubbles/catchup.d.ts +114 -0
  30. package/dist/agents/channels/bluebubbles/catchup.d.ts.map +1 -0
  31. package/dist/agents/channels/bluebubbles/catchup.js +220 -0
  32. package/dist/agents/channels/bluebubbles/catchup.js.map +1 -0
  33. package/dist/agents/channels/bluebubbles/chat.d.ts +75 -0
  34. package/dist/agents/channels/bluebubbles/chat.d.ts.map +1 -0
  35. package/dist/agents/channels/bluebubbles/chat.js +182 -0
  36. package/dist/agents/channels/bluebubbles/chat.js.map +1 -0
  37. package/dist/agents/channels/bluebubbles/connection.d.ts +95 -0
  38. package/dist/agents/channels/bluebubbles/connection.d.ts.map +1 -0
  39. package/dist/agents/channels/bluebubbles/connection.js +413 -0
  40. package/dist/agents/channels/bluebubbles/connection.js.map +1 -0
  41. package/dist/agents/channels/bluebubbles/contact-names.d.ts +79 -0
  42. package/dist/agents/channels/bluebubbles/contact-names.d.ts.map +1 -0
  43. package/dist/agents/channels/bluebubbles/contact-names.js +188 -0
  44. package/dist/agents/channels/bluebubbles/contact-names.js.map +1 -0
  45. package/dist/agents/channels/bluebubbles/debounce.d.ts +78 -0
  46. package/dist/agents/channels/bluebubbles/debounce.d.ts.map +1 -0
  47. package/dist/agents/channels/bluebubbles/debounce.js +173 -0
  48. package/dist/agents/channels/bluebubbles/debounce.js.map +1 -0
  49. package/dist/agents/channels/bluebubbles/dedupe.d.ts +25 -0
  50. package/dist/agents/channels/bluebubbles/dedupe.d.ts.map +1 -0
  51. package/dist/agents/channels/bluebubbles/dedupe.js +35 -0
  52. package/dist/agents/channels/bluebubbles/dedupe.js.map +1 -0
  53. package/dist/agents/channels/bluebubbles/effects.d.ts +17 -0
  54. package/dist/agents/channels/bluebubbles/effects.d.ts.map +1 -0
  55. package/dist/agents/channels/bluebubbles/effects.js +57 -0
  56. package/dist/agents/channels/bluebubbles/effects.js.map +1 -0
  57. package/dist/agents/channels/bluebubbles/history.d.ts +56 -0
  58. package/dist/agents/channels/bluebubbles/history.d.ts.map +1 -0
  59. package/dist/agents/channels/bluebubbles/history.js +140 -0
  60. package/dist/agents/channels/bluebubbles/history.js.map +1 -0
  61. package/dist/agents/channels/bluebubbles/index.d.ts +18 -0
  62. package/dist/agents/channels/bluebubbles/index.d.ts.map +1 -0
  63. package/dist/agents/channels/bluebubbles/index.js +18 -0
  64. package/dist/agents/channels/bluebubbles/index.js.map +1 -0
  65. package/dist/agents/channels/bluebubbles/media.d.ts +104 -0
  66. package/dist/agents/channels/bluebubbles/media.d.ts.map +1 -0
  67. package/dist/agents/channels/bluebubbles/media.js +222 -0
  68. package/dist/agents/channels/bluebubbles/media.js.map +1 -0
  69. package/dist/agents/channels/bluebubbles/messaging.d.ts +13 -0
  70. package/dist/agents/channels/bluebubbles/messaging.d.ts.map +1 -0
  71. package/dist/agents/channels/bluebubbles/messaging.js +36 -0
  72. package/dist/agents/channels/bluebubbles/messaging.js.map +1 -0
  73. package/dist/agents/channels/bluebubbles/module.d.ts +24 -0
  74. package/dist/agents/channels/bluebubbles/module.d.ts.map +1 -0
  75. package/dist/agents/channels/bluebubbles/module.js +52 -0
  76. package/dist/agents/channels/bluebubbles/module.js.map +1 -0
  77. package/dist/agents/channels/bluebubbles/normalize.d.ts +111 -0
  78. package/dist/agents/channels/bluebubbles/normalize.d.ts.map +1 -0
  79. package/dist/agents/channels/bluebubbles/normalize.js +239 -0
  80. package/dist/agents/channels/bluebubbles/normalize.js.map +1 -0
  81. package/dist/agents/channels/bluebubbles/plugin.d.ts +46 -0
  82. package/dist/agents/channels/bluebubbles/plugin.d.ts.map +1 -0
  83. package/dist/agents/channels/bluebubbles/plugin.js +242 -0
  84. package/dist/agents/channels/bluebubbles/plugin.js.map +1 -0
  85. package/dist/agents/channels/bluebubbles/probe.d.ts +79 -0
  86. package/dist/agents/channels/bluebubbles/probe.d.ts.map +1 -0
  87. package/dist/agents/channels/bluebubbles/probe.js +138 -0
  88. package/dist/agents/channels/bluebubbles/probe.js.map +1 -0
  89. package/dist/agents/channels/bluebubbles/reactions.d.ts +46 -0
  90. package/dist/agents/channels/bluebubbles/reactions.d.ts.map +1 -0
  91. package/dist/agents/channels/bluebubbles/reactions.js +207 -0
  92. package/dist/agents/channels/bluebubbles/reactions.js.map +1 -0
  93. package/dist/agents/channels/bluebubbles/send.d.ts +132 -0
  94. package/dist/agents/channels/bluebubbles/send.d.ts.map +1 -0
  95. package/dist/agents/channels/bluebubbles/send.js +327 -0
  96. package/dist/agents/channels/bluebubbles/send.js.map +1 -0
  97. package/dist/agents/channels/bluebubbles/status-issues.d.ts +57 -0
  98. package/dist/agents/channels/bluebubbles/status-issues.d.ts.map +1 -0
  99. package/dist/agents/channels/bluebubbles/status-issues.js +93 -0
  100. package/dist/agents/channels/bluebubbles/status-issues.js.map +1 -0
  101. package/dist/agents/channels/bluebubbles/types.d.ts +69 -0
  102. package/dist/agents/channels/bluebubbles/types.d.ts.map +1 -0
  103. package/dist/agents/channels/bluebubbles/types.js +118 -0
  104. package/dist/agents/channels/bluebubbles/types.js.map +1 -0
  105. package/dist/agents/channels/bluebubbles/webhook.d.ts +97 -0
  106. package/dist/agents/channels/bluebubbles/webhook.d.ts.map +1 -0
  107. package/dist/agents/channels/bluebubbles/webhook.js +249 -0
  108. package/dist/agents/channels/bluebubbles/webhook.js.map +1 -0
  109. package/dist/agents/channels/bundled-channel-metas.d.ts +13 -0
  110. package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
  111. package/dist/agents/channels/bundled-channel-metas.js +33 -0
  112. package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
  113. package/dist/agents/channels/imessage/account-config.d.ts +178 -0
  114. package/dist/agents/channels/imessage/account-config.d.ts.map +1 -0
  115. package/dist/agents/channels/imessage/account-config.js +371 -0
  116. package/dist/agents/channels/imessage/account-config.js.map +1 -0
  117. package/dist/agents/channels/imessage/adapter.d.ts +36 -0
  118. package/dist/agents/channels/imessage/adapter.d.ts.map +1 -0
  119. package/dist/agents/channels/imessage/adapter.js +286 -0
  120. package/dist/agents/channels/imessage/adapter.js.map +1 -0
  121. package/dist/agents/channels/imessage/client.d.ts +99 -0
  122. package/dist/agents/channels/imessage/client.d.ts.map +1 -0
  123. package/dist/agents/channels/imessage/client.js +231 -0
  124. package/dist/agents/channels/imessage/client.js.map +1 -0
  125. package/dist/agents/channels/imessage/connection.d.ts +101 -0
  126. package/dist/agents/channels/imessage/connection.d.ts.map +1 -0
  127. package/dist/agents/channels/imessage/connection.js +367 -0
  128. package/dist/agents/channels/imessage/connection.js.map +1 -0
  129. package/dist/agents/channels/imessage/format.d.ts +45 -0
  130. package/dist/agents/channels/imessage/format.d.ts.map +1 -0
  131. package/dist/agents/channels/imessage/format.js +170 -0
  132. package/dist/agents/channels/imessage/format.js.map +1 -0
  133. package/dist/agents/channels/imessage/history.d.ts +49 -0
  134. package/dist/agents/channels/imessage/history.d.ts.map +1 -0
  135. package/dist/agents/channels/imessage/history.js +74 -0
  136. package/dist/agents/channels/imessage/history.js.map +1 -0
  137. package/dist/agents/channels/imessage/index.d.ts +25 -0
  138. package/dist/agents/channels/imessage/index.d.ts.map +1 -0
  139. package/dist/agents/channels/imessage/index.js +25 -0
  140. package/dist/agents/channels/imessage/index.js.map +1 -0
  141. package/dist/agents/channels/imessage/media.d.ts +92 -0
  142. package/dist/agents/channels/imessage/media.d.ts.map +1 -0
  143. package/dist/agents/channels/imessage/media.js +196 -0
  144. package/dist/agents/channels/imessage/media.js.map +1 -0
  145. package/dist/agents/channels/imessage/messaging.d.ts +14 -0
  146. package/dist/agents/channels/imessage/messaging.d.ts.map +1 -0
  147. package/dist/agents/channels/imessage/messaging.js +37 -0
  148. package/dist/agents/channels/imessage/messaging.js.map +1 -0
  149. package/dist/agents/channels/imessage/module.d.ts +16 -0
  150. package/dist/agents/channels/imessage/module.d.ts.map +1 -0
  151. package/dist/agents/channels/imessage/module.js +23 -0
  152. package/dist/agents/channels/imessage/module.js.map +1 -0
  153. package/dist/agents/channels/imessage/monitor.d.ts +207 -0
  154. package/dist/agents/channels/imessage/monitor.d.ts.map +1 -0
  155. package/dist/agents/channels/imessage/monitor.js +504 -0
  156. package/dist/agents/channels/imessage/monitor.js.map +1 -0
  157. package/dist/agents/channels/imessage/plugin.d.ts +53 -0
  158. package/dist/agents/channels/imessage/plugin.d.ts.map +1 -0
  159. package/dist/agents/channels/imessage/plugin.js +215 -0
  160. package/dist/agents/channels/imessage/plugin.js.map +1 -0
  161. package/dist/agents/channels/imessage/probe.d.ts +68 -0
  162. package/dist/agents/channels/imessage/probe.d.ts.map +1 -0
  163. package/dist/agents/channels/imessage/probe.js +134 -0
  164. package/dist/agents/channels/imessage/probe.js.map +1 -0
  165. package/dist/agents/channels/imessage/remote-attachments.d.ts +61 -0
  166. package/dist/agents/channels/imessage/remote-attachments.d.ts.map +1 -0
  167. package/dist/agents/channels/imessage/remote-attachments.js +131 -0
  168. package/dist/agents/channels/imessage/remote-attachments.js.map +1 -0
  169. package/dist/agents/channels/imessage/send.d.ts +61 -0
  170. package/dist/agents/channels/imessage/send.d.ts.map +1 -0
  171. package/dist/agents/channels/imessage/send.js +108 -0
  172. package/dist/agents/channels/imessage/send.js.map +1 -0
  173. package/dist/agents/channels/imessage/targets.d.ts +91 -0
  174. package/dist/agents/channels/imessage/targets.d.ts.map +1 -0
  175. package/dist/agents/channels/imessage/targets.js +245 -0
  176. package/dist/agents/channels/imessage/targets.js.map +1 -0
  177. package/dist/agents/channels/imessage/watch-error.d.ts +23 -0
  178. package/dist/agents/channels/imessage/watch-error.d.ts.map +1 -0
  179. package/dist/agents/channels/imessage/watch-error.js +69 -0
  180. package/dist/agents/channels/imessage/watch-error.js.map +1 -0
  181. package/dist/agents/channels/inbound-pipeline.d.ts +11 -0
  182. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  183. package/dist/agents/channels/inbound-pipeline.js +20 -1
  184. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  185. package/dist/agents/channels/manager.d.ts +9 -0
  186. package/dist/agents/channels/manager.d.ts.map +1 -1
  187. package/dist/agents/channels/manager.js.map +1 -1
  188. package/dist/agents/channels/sdk.d.ts +4 -0
  189. package/dist/agents/channels/sdk.d.ts.map +1 -1
  190. package/dist/agents/channels/sdk.js +4 -0
  191. package/dist/agents/channels/sdk.js.map +1 -1
  192. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  193. package/dist/agents/extensions/modules/index.js +12 -0
  194. package/dist/agents/extensions/modules/index.js.map +1 -1
  195. package/dist/agents/session-wiring.d.ts +31 -0
  196. package/dist/agents/session-wiring.d.ts.map +1 -1
  197. package/dist/agents/session-wiring.js +45 -2
  198. package/dist/agents/session-wiring.js.map +1 -1
  199. package/dist/agents/tools/bluebubbles-action-tool.d.ts +66 -0
  200. package/dist/agents/tools/bluebubbles-action-tool.d.ts.map +1 -0
  201. package/dist/agents/tools/bluebubbles-action-tool.js +234 -0
  202. package/dist/agents/tools/bluebubbles-action-tool.js.map +1 -0
  203. package/dist/agents/tools/registry.d.ts.map +1 -1
  204. package/dist/agents/tools/registry.js +18 -0
  205. package/dist/agents/tools/registry.js.map +1 -1
  206. package/dist/buildstamp.json +1 -1
  207. package/dist/core/server.d.ts.map +1 -1
  208. package/dist/core/server.js +48 -2
  209. package/dist/core/server.js.map +1 -1
  210. package/dist/infra/net/fetch-guard.d.ts +24 -2
  211. package/dist/infra/net/fetch-guard.d.ts.map +1 -1
  212. package/dist/infra/net/fetch-guard.js +78 -31
  213. package/dist/infra/net/fetch-guard.js.map +1 -1
  214. package/package.json +1 -1
@@ -0,0 +1,56 @@
1
+ /**
2
+ * BlueBubbles rolling-history context fetch.
3
+ *
4
+ * When an untagged GROUP message arrives, the agent has no idea what the group
5
+ * was just talking about — iMessage delivers one webhook per message with no
6
+ * thread context. This module fetches the last N messages for the chat and
7
+ * returns them as compact `{ sender, body }` entries the connection prepends to
8
+ * the inbound as a fenced context block, so the agent replies INTO the
9
+ * conversation rather than at a single stray line.
10
+ *
11
+ * BlueBubbles' message-listing endpoint shape varies by server version, so this
12
+ * tries several known paths in order and accepts the first that returns a
13
+ * recognised response (array / `data[]` / `messages[]`). `fetch` is INJECTABLE
14
+ * (the test seam); never throws — a failure returns `{ entries: [], resolved:false }`
15
+ * and the caller simply attaches no context.
16
+ */
17
+ import { type FetchLike } from "./types.js";
18
+ /** One compact history line. */
19
+ export interface BlueBubblesHistoryEntry {
20
+ /** Display name / handle of the speaker (or "me" for the bot's own past messages). */
21
+ sender: string;
22
+ /** Message text (truncated). */
23
+ body: string;
24
+ /** When it was sent (epoch ms), when known. */
25
+ timestamp?: number;
26
+ /** The message GUID, when known. */
27
+ messageId?: string;
28
+ }
29
+ /** The result of a history fetch. `resolved` is false when every path failed. */
30
+ export interface BlueBubblesHistoryFetchResult {
31
+ entries: BlueBubblesHistoryEntry[];
32
+ resolved: boolean;
33
+ }
34
+ /** Args for a history fetch. */
35
+ export interface FetchBlueBubblesHistoryArgs {
36
+ serverUrl: string;
37
+ password: string;
38
+ timeoutMs?: number;
39
+ /** TEST SEAM — inject a mock fetch. */
40
+ fetchImpl?: FetchLike;
41
+ /** Allow private/LAN/loopback hosts through the SSRF guard (default TRUE for BlueBubbles). */
42
+ allowPrivateNetwork?: boolean;
43
+ }
44
+ /**
45
+ * Fetch recent message history for a chat. Tries several known endpoint shapes;
46
+ * the first recognised response wins. Returns entries oldest-first (so a reader
47
+ * sees the conversation in order), capped to `limit`. Never throws.
48
+ */
49
+ export declare function fetchBlueBubblesHistory(chatIdentifier: string, limit: number, args: FetchBlueBubblesHistoryArgs): Promise<BlueBubblesHistoryFetchResult>;
50
+ /**
51
+ * Render history entries as a clearly-fenced context block to PREPEND to the
52
+ * inbound body. Returns "" when there are no entries. The block is delimited so
53
+ * the agent can tell prior context from the current message.
54
+ */
55
+ export declare function renderBlueBubblesHistoryBlock(entries: BlueBubblesHistoryEntry[]): string;
56
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAuD,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjG,gCAAgC;AAChC,MAAM,WAAW,uBAAuB;IACvC,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,iFAAiF;AACjF,MAAM,WAAW,6BAA6B;IAC7C,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnC,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,gCAAgC;AAChC,MAAM,WAAW,2BAA2B;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,8FAA8F;IAC9F,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAwDD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC5C,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,2BAA2B,GAC/B,OAAO,CAAC,6BAA6B,CAAC,CAoDxC;AAaD;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,MAAM,CAIxF"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * BlueBubbles rolling-history context fetch.
3
+ *
4
+ * When an untagged GROUP message arrives, the agent has no idea what the group
5
+ * was just talking about — iMessage delivers one webhook per message with no
6
+ * thread context. This module fetches the last N messages for the chat and
7
+ * returns them as compact `{ sender, body }` entries the connection prepends to
8
+ * the inbound as a fenced context block, so the agent replies INTO the
9
+ * conversation rather than at a single stray line.
10
+ *
11
+ * BlueBubbles' message-listing endpoint shape varies by server version, so this
12
+ * tries several known paths in order and accepts the first that returns a
13
+ * recognised response (array / `data[]` / `messages[]`). `fetch` is INJECTABLE
14
+ * (the test seam); never throws — a failure returns `{ entries: [], resolved:false }`
15
+ * and the caller simply attaches no context.
16
+ */
17
+ import { blueBubblesFetchWithTimeout, buildBlueBubblesApiUrl } from "./types.js";
18
+ /** Hard ceiling on a single history fetch. */
19
+ const MAX_HISTORY_FETCH_LIMIT = 100;
20
+ /** How many records to scan looking for `limit` text-bearing ones. */
21
+ const HISTORY_SCAN_MULTIPLIER = 8;
22
+ const MAX_HISTORY_SCAN_MESSAGES = 500;
23
+ /** Cap on a single history line's length (keeps the context block bounded). */
24
+ const MAX_HISTORY_BODY_CHARS = 2_000;
25
+ /** Clamp the requested limit into `[0, MAX]`. */
26
+ function clampHistoryLimit(limit) {
27
+ if (!Number.isFinite(limit))
28
+ return 0;
29
+ const n = Math.floor(limit);
30
+ if (n <= 0)
31
+ return 0;
32
+ return Math.min(n, MAX_HISTORY_FETCH_LIMIT);
33
+ }
34
+ /** Truncate a history line body, marking the cut. */
35
+ function truncateBody(text) {
36
+ if (text.length <= MAX_HISTORY_BODY_CHARS)
37
+ return text;
38
+ return `${text.slice(0, MAX_HISTORY_BODY_CHARS).trimEnd()}...`;
39
+ }
40
+ /** Resolve a display label for a message's sender. */
41
+ function resolveSender(msg) {
42
+ if (msg.is_from_me === true || msg.isFromMe === true)
43
+ return "me";
44
+ const handleObj = typeof msg.handle === "object" && msg.handle ? msg.handle : undefined;
45
+ return (msg.sender?.display_name ||
46
+ msg.sender?.displayName ||
47
+ msg.sender?.address ||
48
+ handleObj?.display_name ||
49
+ handleObj?.displayName ||
50
+ handleObj?.address ||
51
+ (typeof msg.handle === "string" ? msg.handle : undefined) ||
52
+ msg.handle_id ||
53
+ "Unknown");
54
+ }
55
+ /**
56
+ * Fetch recent message history for a chat. Tries several known endpoint shapes;
57
+ * the first recognised response wins. Returns entries oldest-first (so a reader
58
+ * sees the conversation in order), capped to `limit`. Never throws.
59
+ */
60
+ export async function fetchBlueBubblesHistory(chatIdentifier, limit, args) {
61
+ const effectiveLimit = clampHistoryLimit(limit);
62
+ if (!chatIdentifier.trim() || effectiveLimit <= 0)
63
+ return { entries: [], resolved: true };
64
+ const fetchOpts = {
65
+ ...(args.timeoutMs !== undefined ? { timeoutMs: args.timeoutMs } : {}),
66
+ ...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}),
67
+ ...(args.allowPrivateNetwork === false ? { allowPrivateNetwork: false } : {}),
68
+ };
69
+ const encoded = encodeURIComponent(chatIdentifier);
70
+ // Known listing shapes, in order — the first that returns a recognised body wins.
71
+ const paths = [
72
+ { path: `chat/${encoded}/message`, query: { limit: effectiveLimit, sort: "DESC" } },
73
+ { path: `chat/${encoded}/messages`, query: { limit: effectiveLimit } },
74
+ { path: "messages", query: { chatGuid: chatIdentifier, limit: effectiveLimit } },
75
+ ];
76
+ for (const { path, query } of paths) {
77
+ try {
78
+ const url = buildBlueBubblesApiUrl({ serverUrl: args.serverUrl, path, password: args.password, ...(query ? { query } : {}) });
79
+ const res = await blueBubblesFetchWithTimeout(url, { method: "GET" }, fetchOpts);
80
+ if (!res.ok)
81
+ continue;
82
+ const text = await res.text();
83
+ const body = text ? JSON.parse(text) : null;
84
+ if (!body)
85
+ continue;
86
+ const messages = extractMessageArray(body);
87
+ if (!messages)
88
+ continue;
89
+ const entries = [];
90
+ const maxScan = Math.min(Math.max(effectiveLimit * HISTORY_SCAN_MULTIPLIER, effectiveLimit), MAX_HISTORY_SCAN_MESSAGES);
91
+ for (let i = 0; i < messages.length && i < maxScan; i++) {
92
+ const msg = messages[i];
93
+ if (!msg || typeof msg !== "object")
94
+ continue;
95
+ const t = (msg.text ?? "").trim();
96
+ if (!t)
97
+ continue;
98
+ const timestamp = msg.date_created ?? msg.dateCreated ?? msg.date_delivered;
99
+ entries.push({
100
+ sender: resolveSender(msg),
101
+ body: truncateBody(t),
102
+ ...(typeof timestamp === "number" ? { timestamp } : {}),
103
+ ...(typeof msg.guid === "string" ? { messageId: msg.guid } : {}),
104
+ });
105
+ }
106
+ // Oldest-first so the agent reads the conversation in order.
107
+ entries.sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
108
+ return { entries: entries.slice(0, effectiveLimit), resolved: true };
109
+ }
110
+ catch {
111
+ continue;
112
+ }
113
+ }
114
+ return { entries: [], resolved: false };
115
+ }
116
+ /** Pull a message array out of the various response shapes (array / data[] / messages[]). */
117
+ function extractMessageArray(body) {
118
+ if (Array.isArray(body))
119
+ return body;
120
+ if (body && typeof body === "object") {
121
+ const rec = body;
122
+ if (Array.isArray(rec.data))
123
+ return rec.data;
124
+ if (Array.isArray(rec.messages))
125
+ return rec.messages;
126
+ }
127
+ return null;
128
+ }
129
+ /**
130
+ * Render history entries as a clearly-fenced context block to PREPEND to the
131
+ * inbound body. Returns "" when there are no entries. The block is delimited so
132
+ * the agent can tell prior context from the current message.
133
+ */
134
+ export function renderBlueBubblesHistoryBlock(entries) {
135
+ if (!entries || entries.length === 0)
136
+ return "";
137
+ const lines = entries.map((e) => `${e.sender}: ${e.body}`);
138
+ return ["[recent conversation context]", ...lines, "[end context]"].join("\n");
139
+ }
140
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * BlueBubbles channel — public barrel.
3
+ *
4
+ * Re-exports the channel's public surface (adapter, plugin, config resolvers,
5
+ * probe, webhook builders, the module) so the gateway boot + central registries
6
+ * import from one place.
7
+ */
8
+ export { bluebubblesChannelEnabled, listBlueBubblesAccountIds, resolveBlueBubblesAccount, resolveBlueBubblesServerUrl, resolveBlueBubblesPassword, resolveBlueBubblesWebhookPath, resolveBlueBubblesProbeTimeoutMs, resolveBlueBubblesActions, resolveBlueBubblesCatchup, bluebubblesThreadIdleTtlMs, normalizeBlueBubblesServerUrl, BLUEBUBBLES_CHANNEL_ID, BLUEBUBBLES_DEFAULT_ACCOUNT_ID, BLUEBUBBLES_DEFAULT_WEBHOOK_PATH, type ResolvedBlueBubblesAccount, type BlueBubblesActionFlags, } from "./account-config.js";
9
+ export { createBlueBubblesAdapter, type BlueBubblesAdapter } from "./adapter.js";
10
+ export { createBlueBubblesPlugin, type BlueBubblesPluginHandle, type BlueBubblesPluginDeps } from "./plugin.js";
11
+ export { probeBlueBubbles, type BlueBubblesProbeResult } from "./probe.js";
12
+ export { buildBlueBubblesWebhookRoute, verifyBlueBubblesWebhook, parseBlueBubblesBody, safeEqualToken, type BlueBubblesWebhookSink, } from "./webhook.js";
13
+ export { bluebubblesMessagingAdapter } from "./messaging.js";
14
+ export { bluebubblesModule } from "./module.js";
15
+ export { sendBlueBubblesTyping, markBlueBubblesChatRead, renameBlueBubblesChat, addBlueBubblesParticipant, removeBlueBubblesParticipant, leaveBlueBubblesChat, setBlueBubblesGroupIcon, } from "./chat.js";
16
+ export { resolveBlueBubblesContactName, clearBlueBubblesContactCache, type ResolveContactNameArgs, } from "./contact-names.js";
17
+ export { runBlueBubblesCatchup, type BlueBubblesCatchupConfig, type BlueBubblesCatchupSummary, } from "./catchup.js";
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,6BAA6B,EAC7B,gCAAgC,EAChC,yBAAyB,EACzB,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,sBAAsB,EACtB,8BAA8B,EAC9B,gCAAgC,EAChC,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,KAAK,uBAAuB,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAChH,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EACN,4BAA4B,EAC5B,wBAAwB,EACxB,oBAAoB,EACpB,cAAc,EACd,KAAK,sBAAsB,GAC3B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,uBAAuB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EACN,6BAA6B,EAC7B,4BAA4B,EAC5B,KAAK,sBAAsB,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,qBAAqB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,GAC9B,MAAM,cAAc,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * BlueBubbles channel — public barrel.
3
+ *
4
+ * Re-exports the channel's public surface (adapter, plugin, config resolvers,
5
+ * probe, webhook builders, the module) so the gateway boot + central registries
6
+ * import from one place.
7
+ */
8
+ export { bluebubblesChannelEnabled, listBlueBubblesAccountIds, resolveBlueBubblesAccount, resolveBlueBubblesServerUrl, resolveBlueBubblesPassword, resolveBlueBubblesWebhookPath, resolveBlueBubblesProbeTimeoutMs, resolveBlueBubblesActions, resolveBlueBubblesCatchup, bluebubblesThreadIdleTtlMs, normalizeBlueBubblesServerUrl, BLUEBUBBLES_CHANNEL_ID, BLUEBUBBLES_DEFAULT_ACCOUNT_ID, BLUEBUBBLES_DEFAULT_WEBHOOK_PATH, } from "./account-config.js";
9
+ export { createBlueBubblesAdapter } from "./adapter.js";
10
+ export { createBlueBubblesPlugin } from "./plugin.js";
11
+ export { probeBlueBubbles } from "./probe.js";
12
+ export { buildBlueBubblesWebhookRoute, verifyBlueBubblesWebhook, parseBlueBubblesBody, safeEqualToken, } from "./webhook.js";
13
+ export { bluebubblesMessagingAdapter } from "./messaging.js";
14
+ export { bluebubblesModule } from "./module.js";
15
+ export { sendBlueBubblesTyping, markBlueBubblesChatRead, renameBlueBubblesChat, addBlueBubblesParticipant, removeBlueBubblesParticipant, leaveBlueBubblesChat, setBlueBubblesGroupIcon, } from "./chat.js";
16
+ export { resolveBlueBubblesContactName, clearBlueBubblesContactCache, } from "./contact-names.js";
17
+ export { runBlueBubblesCatchup, } from "./catchup.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,6BAA6B,EAC7B,gCAAgC,EAChC,yBAAyB,EACzB,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,sBAAsB,EACtB,8BAA8B,EAC9B,gCAAgC,GAGhC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAA2B,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAA4D,MAAM,aAAa,CAAC;AAChH,OAAO,EAAE,gBAAgB,EAA+B,MAAM,YAAY,CAAC;AAC3E,OAAO,EACN,4BAA4B,EAC5B,wBAAwB,EACxB,oBAAoB,EACpB,cAAc,GAEd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,uBAAuB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EACN,6BAA6B,EAC7B,4BAA4B,GAE5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,qBAAqB,GAGrB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * BlueBubbles media helpers — inbound download + cache, outbound resolution.
3
+ *
4
+ * Unlike the native `imessage` channel (where the `imsg` bridge has already
5
+ * saved inbound bytes to local disk), BlueBubbles serves attachments over HTTP:
6
+ * `GET /api/v1/attachment/{guid}/download`. So this module DOWNLOADS each inbound
7
+ * attachment to a per-account cache dir under the OS cache (outside `~/.brigade`),
8
+ * applying a small extension-normalisation map (HEIC→jpg, caf→mp3) so the agent's
9
+ * `read` tool + downstream tools see a friendlier extension.
10
+ *
11
+ * OUTBOUND resolution reuses the iMessage exfil guard + kind classifiers so a
12
+ * prompt-injected "send ~/.ssh/id_rsa" can't attach a secret.
13
+ */
14
+ import { kindFromExt, kindFromMime, resolveOutboundAttachment, inferOutboundMediaKind } from "../imessage/media.js";
15
+ import { type FetchLike } from "./types.js";
16
+ import type { InboundMediaAttachment } from "../sdk.js";
17
+ export { kindFromExt, kindFromMime, resolveOutboundAttachment, inferOutboundMediaKind };
18
+ /** Apply the inbound extension map to a filename (`photo.heic` → `photo.jpg`). */
19
+ export declare function mapInboundExtension(fileName: string): string;
20
+ /** The result of classifying a candidate voice attachment. */
21
+ export interface BlueBubblesVoiceInfo {
22
+ /** True when the file looks like audio at all. */
23
+ isAudio: boolean;
24
+ /** True when it is mp3 (by extension or mime). */
25
+ isMp3: boolean;
26
+ /** True when it is caf (by extension or mime). */
27
+ isCaf: boolean;
28
+ }
29
+ /**
30
+ * Classify a candidate voice attachment by extension + (optional) MIME type. A
31
+ * BlueBubbles voice memo must be mp3 or caf — the server converts mp3 → caf when
32
+ * `isAudioMessage` is set.
33
+ */
34
+ export declare function resolveVoiceInfo(filename: string, contentType?: string): BlueBubblesVoiceInfo;
35
+ /**
36
+ * Ensure a filename ends with `extension` (e.g. `.mp3`), swapping any existing
37
+ * extension. `fallbackBase` is used when the input has no stem.
38
+ */
39
+ export declare function ensureExtension(filename: string, extension: string, fallbackBase: string): string;
40
+ /** The outcome of the outbound voice pre-flight. */
41
+ export interface ResolvedVoiceAttachment {
42
+ /** The (possibly extension-coerced) filename to send. */
43
+ filename: string;
44
+ /** The (possibly defaulted) content type to send. */
45
+ contentType: string | undefined;
46
+ }
47
+ /**
48
+ * Pre-flight an outbound VOICE attachment: validate it is mp3/caf, coerce the
49
+ * filename's extension to match, and default the MIME type when absent. Throws a
50
+ * clear operator-facing error when the file is not mp3/caf audio so the send
51
+ * fails fast (rather than the server silently rejecting / mis-handling it).
52
+ */
53
+ export declare function resolveOutboundVoiceAttachment(filename: string, contentType?: string): ResolvedVoiceAttachment;
54
+ /** One raw inbound attachment as the BlueBubbles webhook reports it. */
55
+ export interface RawBlueBubblesAttachment {
56
+ guid?: string;
57
+ transferName?: string;
58
+ mimeType?: string;
59
+ totalBytes?: number;
60
+ }
61
+ /** Args for downloading + caching inbound attachments. */
62
+ export interface DownloadInboundArgs {
63
+ serverUrl: string;
64
+ password: string;
65
+ /** Per-account cache dir the bytes are written under. */
66
+ cacheDir: string;
67
+ /** Max bytes to accept per attachment (skips oversize ones). */
68
+ maxBytes: number;
69
+ timeoutMs?: number;
70
+ /** TEST SEAM — inject a mock fetch. */
71
+ fetchImpl?: FetchLike;
72
+ /** Allow private/LAN/loopback hosts through the SSRF guard (default TRUE for BlueBubbles). */
73
+ allowPrivateNetwork?: boolean;
74
+ }
75
+ /**
76
+ * Download + cache a single inbound attachment by GUID, returning the saved
77
+ * `InboundMediaAttachment` (or null when it has no GUID / is oversize / fails).
78
+ * The saved filename runs through `mapInboundExtension`.
79
+ */
80
+ export declare function downloadBlueBubblesAttachment(att: RawBlueBubblesAttachment, args: DownloadInboundArgs): Promise<InboundMediaAttachment | null>;
81
+ /**
82
+ * Download all inbound attachments for a message, dropping any that fail / are
83
+ * oversize. Returns [] when none resolve.
84
+ */
85
+ export declare function downloadInboundAttachments(raw: RawBlueBubblesAttachment[] | null | undefined, args: DownloadInboundArgs): Promise<InboundMediaAttachment[]>;
86
+ /** Args for the late-index attachment re-fetch. */
87
+ export interface FetchMessageAttachmentsArgs {
88
+ serverUrl: string;
89
+ password: string;
90
+ timeoutMs?: number;
91
+ fetchImpl?: FetchLike;
92
+ allowPrivateNetwork?: boolean;
93
+ }
94
+ /**
95
+ * Re-fetch a message's attachment descriptors by GUID
96
+ * (`GET /api/v1/message/{guid}?with=attachment`).
97
+ *
98
+ * BlueBubbles can fire the `new-message` webhook BEFORE attachment indexing
99
+ * finishes, so the webhook's `attachments` arrives empty for a message that
100
+ * actually has media. A short delay + this single re-fetch recovers the media
101
+ * that would otherwise be silently lost. Returns [] on any failure (never throws).
102
+ */
103
+ export declare function fetchBlueBubblesMessageAttachments(messageGuid: string, args: FetchMessageAttachmentsArgs): Promise<RawBlueBubblesAttachment[]>;
104
+ //# sourceMappingURL=media.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACpH,OAAO,EAGN,KAAK,SAAS,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,CAAC;AAexF,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM5D;AASD,8DAA8D;AAC9D,MAAM,WAAW,oBAAoB;IACpC,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,KAAK,EAAE,OAAO,CAAC;IACf,kDAAkD;IAClD,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,oBAAoB,CAO7F;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAKjG;AAED,oDAAoD;AACpD,MAAM,WAAW,uBAAuB;IACvC,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,uBAAuB,CAc9G;AAED,wEAAwE;AACxE,MAAM,WAAW,wBAAwB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,8FAA8F;IAC9F,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CAClD,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,mBAAmB,GACvB,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CA0CxC;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC/C,GAAG,EAAE,wBAAwB,EAAE,GAAG,IAAI,GAAG,SAAS,EAClD,IAAI,EAAE,mBAAmB,GACvB,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAQnC;AAmCD,mDAAmD;AACnD,MAAM,WAAW,2BAA2B;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAsB,kCAAkC,CACvD,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,2BAA2B,GAC/B,OAAO,CAAC,wBAAwB,EAAE,CAAC,CA0BrC"}
@@ -0,0 +1,222 @@
1
+ /**
2
+ * BlueBubbles media helpers — inbound download + cache, outbound resolution.
3
+ *
4
+ * Unlike the native `imessage` channel (where the `imsg` bridge has already
5
+ * saved inbound bytes to local disk), BlueBubbles serves attachments over HTTP:
6
+ * `GET /api/v1/attachment/{guid}/download`. So this module DOWNLOADS each inbound
7
+ * attachment to a per-account cache dir under the OS cache (outside `~/.brigade`),
8
+ * applying a small extension-normalisation map (HEIC→jpg, caf→mp3) so the agent's
9
+ * `read` tool + downstream tools see a friendlier extension.
10
+ *
11
+ * OUTBOUND resolution reuses the iMessage exfil guard + kind classifiers so a
12
+ * prompt-injected "send ~/.ssh/id_rsa" can't attach a secret.
13
+ */
14
+ import { mkdir, writeFile } from "node:fs/promises";
15
+ import path from "node:path";
16
+ import { kindFromExt, kindFromMime, resolveOutboundAttachment, inferOutboundMediaKind } from "../imessage/media.js";
17
+ import { blueBubblesFetchWithTimeout, buildBlueBubblesApiUrl, } from "./types.js";
18
+ // Re-export the shared classifiers so callers import them from one place.
19
+ export { kindFromExt, kindFromMime, resolveOutboundAttachment, inferOutboundMediaKind };
20
+ /**
21
+ * Inbound extension-normalisation map. iMessage delivers Apple-native container
22
+ * formats that most tools can't open; map them to a friendlier extension on
23
+ * download. The bytes are NOT transcoded — only the on-disk extension is changed
24
+ * (a HEIC renamed `.jpg` is still HEIC bytes, but the friendlier extension keeps
25
+ * downstream readers from choking on the `.heic` suffix).
26
+ */
27
+ const EXTENSION_MAP = {
28
+ heic: "jpg",
29
+ heif: "jpg",
30
+ caf: "mp3",
31
+ };
32
+ /** Apply the inbound extension map to a filename (`photo.heic` → `photo.jpg`). */
33
+ export function mapInboundExtension(fileName) {
34
+ const ext = path.extname(fileName).toLowerCase().replace(/^\./, "");
35
+ const mapped = EXTENSION_MAP[ext];
36
+ if (!mapped)
37
+ return fileName;
38
+ const stem = fileName.slice(0, fileName.length - (ext.length + 1));
39
+ return `${stem || "attachment"}.${mapped}`;
40
+ }
41
+ /* ───────────────────────── outbound voice pre-flight ───────────────────────── */
42
+ /** MIME types BlueBubbles accepts as an mp3 voice memo. */
43
+ const VOICE_MIME_MP3 = new Set(["audio/mpeg", "audio/mp3"]);
44
+ /** MIME types BlueBubbles accepts as a caf voice memo. */
45
+ const VOICE_MIME_CAF = new Set(["audio/x-caf", "audio/caf"]);
46
+ /**
47
+ * Classify a candidate voice attachment by extension + (optional) MIME type. A
48
+ * BlueBubbles voice memo must be mp3 or caf — the server converts mp3 → caf when
49
+ * `isAudioMessage` is set.
50
+ */
51
+ export function resolveVoiceInfo(filename, contentType) {
52
+ const type = (contentType ?? "").trim().toLowerCase() || undefined;
53
+ const ext = path.extname(filename).toLowerCase();
54
+ const isMp3 = ext === ".mp3" || (type ? VOICE_MIME_MP3.has(type) : false);
55
+ const isCaf = ext === ".caf" || (type ? VOICE_MIME_CAF.has(type) : false);
56
+ const isAudio = isMp3 || isCaf || Boolean(type?.startsWith("audio/"));
57
+ return { isAudio, isMp3, isCaf };
58
+ }
59
+ /**
60
+ * Ensure a filename ends with `extension` (e.g. `.mp3`), swapping any existing
61
+ * extension. `fallbackBase` is used when the input has no stem.
62
+ */
63
+ export function ensureExtension(filename, extension, fallbackBase) {
64
+ const current = path.extname(filename);
65
+ if (current.toLowerCase() === extension)
66
+ return filename;
67
+ const base = current ? filename.slice(0, -current.length) : filename;
68
+ return `${base || fallbackBase}${extension}`;
69
+ }
70
+ /**
71
+ * Pre-flight an outbound VOICE attachment: validate it is mp3/caf, coerce the
72
+ * filename's extension to match, and default the MIME type when absent. Throws a
73
+ * clear operator-facing error when the file is not mp3/caf audio so the send
74
+ * fails fast (rather than the server silently rejecting / mis-handling it).
75
+ */
76
+ export function resolveOutboundVoiceAttachment(filename, contentType) {
77
+ const fallbackBase = "Audio Message";
78
+ const info = resolveVoiceInfo(filename, contentType);
79
+ if (!info.isAudio) {
80
+ throw new Error("BlueBubbles voice messages require audio media (mp3 or caf).");
81
+ }
82
+ if (info.isMp3) {
83
+ return { filename: ensureExtension(filename, ".mp3", fallbackBase), contentType: contentType ?? "audio/mpeg" };
84
+ }
85
+ if (info.isCaf) {
86
+ return { filename: ensureExtension(filename, ".caf", fallbackBase), contentType: contentType ?? "audio/x-caf" };
87
+ }
88
+ // Audio, but not mp3/caf (e.g. wav/m4a) — BlueBubbles can't send it as a voice memo.
89
+ throw new Error("BlueBubbles voice messages require mp3 or caf audio (convert before sending).");
90
+ }
91
+ /**
92
+ * Download + cache a single inbound attachment by GUID, returning the saved
93
+ * `InboundMediaAttachment` (or null when it has no GUID / is oversize / fails).
94
+ * The saved filename runs through `mapInboundExtension`.
95
+ */
96
+ export async function downloadBlueBubblesAttachment(att, args) {
97
+ const guid = (att.guid ?? "").trim();
98
+ if (!guid)
99
+ return null;
100
+ if (args.maxBytes > 0 && typeof att.totalBytes === "number" && att.totalBytes > args.maxBytes)
101
+ return null;
102
+ const url = buildBlueBubblesApiUrl({
103
+ serverUrl: args.serverUrl,
104
+ path: `attachment/${encodeURIComponent(guid)}/download`,
105
+ password: args.password,
106
+ });
107
+ let bytes;
108
+ let contentType;
109
+ try {
110
+ const res = await blueBubblesFetchWithTimeout(url, { method: "GET" }, { timeoutMs: args.timeoutMs ?? 30_000, ...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}), ...(args.allowPrivateNetwork === false ? { allowPrivateNetwork: false } : {}) });
111
+ if (!res.ok)
112
+ return null;
113
+ const buf = await res.arrayBuffer();
114
+ bytes = new Uint8Array(buf);
115
+ if (args.maxBytes > 0 && bytes.byteLength > args.maxBytes)
116
+ return null;
117
+ const ct = res.headers.get("content-type");
118
+ contentType = ct ? ct.split(";")[0]?.trim() || undefined : undefined;
119
+ }
120
+ catch {
121
+ return null;
122
+ }
123
+ const rawName = (att.transferName ?? "").trim() || `${guid}`;
124
+ const fileName = mapInboundExtension(rawName);
125
+ const dest = path.join(args.cacheDir, `${guid}-${fileName}`);
126
+ try {
127
+ await mkdir(args.cacheDir, { recursive: true });
128
+ await writeFile(dest, bytes);
129
+ }
130
+ catch {
131
+ return null;
132
+ }
133
+ const mimeType = (att.mimeType ?? contentType ?? "").trim() || undefined;
134
+ return {
135
+ kind: mimeType ? kindFromMime(mimeType) : kindFromExt(fileName),
136
+ path: dest,
137
+ ...(mimeType ? { mimeType } : {}),
138
+ fileName,
139
+ };
140
+ }
141
+ /**
142
+ * Download all inbound attachments for a message, dropping any that fail / are
143
+ * oversize. Returns [] when none resolve.
144
+ */
145
+ export async function downloadInboundAttachments(raw, args) {
146
+ if (!Array.isArray(raw) || raw.length === 0)
147
+ return [];
148
+ const out = [];
149
+ for (const att of raw) {
150
+ const resolved = await downloadBlueBubblesAttachment(att, args);
151
+ if (resolved)
152
+ out.push(resolved);
153
+ }
154
+ return out;
155
+ }
156
+ /** Pull the raw attachment descriptors out of a `message/{guid}` response record. */
157
+ function extractAttachmentsFromMessage(data) {
158
+ const rec = data && typeof data === "object" ? data : null;
159
+ const raw = rec?.attachments;
160
+ if (!Array.isArray(raw))
161
+ return [];
162
+ const out = [];
163
+ for (const a of raw) {
164
+ const r = a && typeof a === "object" ? a : null;
165
+ const guid = typeof r?.guid === "string" ? r.guid.trim() : "";
166
+ if (!guid)
167
+ continue;
168
+ const transferName = (typeof r?.transferName === "string" && r.transferName) ||
169
+ (typeof r?.transfer_name === "string" && r.transfer_name) ||
170
+ undefined;
171
+ const mimeType = (typeof r?.mimeType === "string" && r.mimeType) ||
172
+ (typeof r?.mime_type === "string" && r.mime_type) ||
173
+ (typeof r?.uti === "string" && r.uti) ||
174
+ undefined;
175
+ const totalBytes = (typeof r?.totalBytes === "number" && r.totalBytes) ||
176
+ (typeof r?.total_bytes === "number" && r.total_bytes) ||
177
+ undefined;
178
+ out.push({
179
+ guid,
180
+ ...(transferName ? { transferName } : {}),
181
+ ...(mimeType ? { mimeType } : {}),
182
+ ...(totalBytes !== undefined ? { totalBytes } : {}),
183
+ });
184
+ }
185
+ return out;
186
+ }
187
+ /**
188
+ * Re-fetch a message's attachment descriptors by GUID
189
+ * (`GET /api/v1/message/{guid}?with=attachment`).
190
+ *
191
+ * BlueBubbles can fire the `new-message` webhook BEFORE attachment indexing
192
+ * finishes, so the webhook's `attachments` arrives empty for a message that
193
+ * actually has media. A short delay + this single re-fetch recovers the media
194
+ * that would otherwise be silently lost. Returns [] on any failure (never throws).
195
+ */
196
+ export async function fetchBlueBubblesMessageAttachments(messageGuid, args) {
197
+ const guid = (messageGuid ?? "").trim();
198
+ if (!guid)
199
+ return [];
200
+ const url = buildBlueBubblesApiUrl({
201
+ serverUrl: args.serverUrl,
202
+ path: `message/${encodeURIComponent(guid)}`,
203
+ password: args.password,
204
+ query: { with: "attachment" },
205
+ });
206
+ try {
207
+ const res = await blueBubblesFetchWithTimeout(url, { method: "GET" }, {
208
+ timeoutMs: args.timeoutMs ?? 10_000,
209
+ ...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}),
210
+ ...(args.allowPrivateNetwork === false ? { allowPrivateNetwork: false } : {}),
211
+ });
212
+ if (!res.ok)
213
+ return [];
214
+ const text = await res.text();
215
+ const body = text ? JSON.parse(text) : {};
216
+ return extractAttachmentsFromMessage(body.data);
217
+ }
218
+ catch {
219
+ return [];
220
+ }
221
+ }
222
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/media.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * BlueBubbles outbound-addressing adapter (the `ChannelPlugin.messaging` slot).
3
+ *
4
+ * Turns the loose `to` the agent hands `send_message` ("+1 555 123 4567",
5
+ * "bluebubbles:user@example.com", "chat_guid:…") into a concrete target the
6
+ * runtime `sendText` understands. BlueBubbles shares iMessage's target grammar,
7
+ * so this reuses the iMessage target primitives (chat_guid / chat_id / handle)
8
+ * and only swaps the channel-name prefix to `bluebubbles:`.
9
+ */
10
+ import type { ChannelMessagingAdapter } from "../sdk.js";
11
+ /** The BlueBubbles messaging adapter. */
12
+ export declare const bluebubblesMessagingAdapter: ChannelMessagingAdapter;
13
+ //# sourceMappingURL=messaging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/messaging.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAwB,MAAM,WAAW,CAAC;AAO/E,yCAAyC;AACzC,eAAO,MAAM,2BAA2B,EAAE,uBAmBzC,CAAC"}