@spinabot/brigade 1.7.0 → 1.9.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 (257) hide show
  1. package/README.md +19 -0
  2. package/dist/agents/agent-loop.d.ts +13 -0
  3. package/dist/agents/agent-loop.d.ts.map +1 -1
  4. package/dist/agents/agent-loop.js +5 -0
  5. package/dist/agents/agent-loop.js.map +1 -1
  6. package/dist/agents/channels/access-control/group-tool-policy.d.ts +73 -0
  7. package/dist/agents/channels/access-control/group-tool-policy.d.ts.map +1 -0
  8. package/dist/agents/channels/access-control/group-tool-policy.js +193 -0
  9. package/dist/agents/channels/access-control/group-tool-policy.js.map +1 -0
  10. package/dist/agents/channels/access-control/index.d.ts +1 -0
  11. package/dist/agents/channels/access-control/index.d.ts.map +1 -1
  12. package/dist/agents/channels/access-control/index.js +1 -0
  13. package/dist/agents/channels/access-control/index.js.map +1 -1
  14. package/dist/agents/channels/bluebubbles/account-config.d.ts +253 -0
  15. package/dist/agents/channels/bluebubbles/account-config.d.ts.map +1 -0
  16. package/dist/agents/channels/bluebubbles/account-config.js +486 -0
  17. package/dist/agents/channels/bluebubbles/account-config.js.map +1 -0
  18. package/dist/agents/channels/bluebubbles/account-registry.d.ts +33 -0
  19. package/dist/agents/channels/bluebubbles/account-registry.d.ts.map +1 -0
  20. package/dist/agents/channels/bluebubbles/account-registry.js +46 -0
  21. package/dist/agents/channels/bluebubbles/account-registry.js.map +1 -0
  22. package/dist/agents/channels/bluebubbles/adapter.d.ts +45 -0
  23. package/dist/agents/channels/bluebubbles/adapter.d.ts.map +1 -0
  24. package/dist/agents/channels/bluebubbles/adapter.js +366 -0
  25. package/dist/agents/channels/bluebubbles/adapter.js.map +1 -0
  26. package/dist/agents/channels/bluebubbles/catchup-cursor.d.ts +52 -0
  27. package/dist/agents/channels/bluebubbles/catchup-cursor.d.ts.map +1 -0
  28. package/dist/agents/channels/bluebubbles/catchup-cursor.js +118 -0
  29. package/dist/agents/channels/bluebubbles/catchup-cursor.js.map +1 -0
  30. package/dist/agents/channels/bluebubbles/catchup.d.ts +114 -0
  31. package/dist/agents/channels/bluebubbles/catchup.d.ts.map +1 -0
  32. package/dist/agents/channels/bluebubbles/catchup.js +220 -0
  33. package/dist/agents/channels/bluebubbles/catchup.js.map +1 -0
  34. package/dist/agents/channels/bluebubbles/chat.d.ts +75 -0
  35. package/dist/agents/channels/bluebubbles/chat.d.ts.map +1 -0
  36. package/dist/agents/channels/bluebubbles/chat.js +182 -0
  37. package/dist/agents/channels/bluebubbles/chat.js.map +1 -0
  38. package/dist/agents/channels/bluebubbles/connection.d.ts +95 -0
  39. package/dist/agents/channels/bluebubbles/connection.d.ts.map +1 -0
  40. package/dist/agents/channels/bluebubbles/connection.js +413 -0
  41. package/dist/agents/channels/bluebubbles/connection.js.map +1 -0
  42. package/dist/agents/channels/bluebubbles/contact-names.d.ts +79 -0
  43. package/dist/agents/channels/bluebubbles/contact-names.d.ts.map +1 -0
  44. package/dist/agents/channels/bluebubbles/contact-names.js +188 -0
  45. package/dist/agents/channels/bluebubbles/contact-names.js.map +1 -0
  46. package/dist/agents/channels/bluebubbles/debounce.d.ts +78 -0
  47. package/dist/agents/channels/bluebubbles/debounce.d.ts.map +1 -0
  48. package/dist/agents/channels/bluebubbles/debounce.js +173 -0
  49. package/dist/agents/channels/bluebubbles/debounce.js.map +1 -0
  50. package/dist/agents/channels/bluebubbles/dedupe.d.ts +25 -0
  51. package/dist/agents/channels/bluebubbles/dedupe.d.ts.map +1 -0
  52. package/dist/agents/channels/bluebubbles/dedupe.js +35 -0
  53. package/dist/agents/channels/bluebubbles/dedupe.js.map +1 -0
  54. package/dist/agents/channels/bluebubbles/effects.d.ts +17 -0
  55. package/dist/agents/channels/bluebubbles/effects.d.ts.map +1 -0
  56. package/dist/agents/channels/bluebubbles/effects.js +57 -0
  57. package/dist/agents/channels/bluebubbles/effects.js.map +1 -0
  58. package/dist/agents/channels/bluebubbles/history.d.ts +56 -0
  59. package/dist/agents/channels/bluebubbles/history.d.ts.map +1 -0
  60. package/dist/agents/channels/bluebubbles/history.js +140 -0
  61. package/dist/agents/channels/bluebubbles/history.js.map +1 -0
  62. package/dist/agents/channels/bluebubbles/index.d.ts +18 -0
  63. package/dist/agents/channels/bluebubbles/index.d.ts.map +1 -0
  64. package/dist/agents/channels/bluebubbles/index.js +18 -0
  65. package/dist/agents/channels/bluebubbles/index.js.map +1 -0
  66. package/dist/agents/channels/bluebubbles/media.d.ts +104 -0
  67. package/dist/agents/channels/bluebubbles/media.d.ts.map +1 -0
  68. package/dist/agents/channels/bluebubbles/media.js +222 -0
  69. package/dist/agents/channels/bluebubbles/media.js.map +1 -0
  70. package/dist/agents/channels/bluebubbles/messaging.d.ts +13 -0
  71. package/dist/agents/channels/bluebubbles/messaging.d.ts.map +1 -0
  72. package/dist/agents/channels/bluebubbles/messaging.js +36 -0
  73. package/dist/agents/channels/bluebubbles/messaging.js.map +1 -0
  74. package/dist/agents/channels/bluebubbles/module.d.ts +24 -0
  75. package/dist/agents/channels/bluebubbles/module.d.ts.map +1 -0
  76. package/dist/agents/channels/bluebubbles/module.js +52 -0
  77. package/dist/agents/channels/bluebubbles/module.js.map +1 -0
  78. package/dist/agents/channels/bluebubbles/normalize.d.ts +111 -0
  79. package/dist/agents/channels/bluebubbles/normalize.d.ts.map +1 -0
  80. package/dist/agents/channels/bluebubbles/normalize.js +239 -0
  81. package/dist/agents/channels/bluebubbles/normalize.js.map +1 -0
  82. package/dist/agents/channels/bluebubbles/plugin.d.ts +46 -0
  83. package/dist/agents/channels/bluebubbles/plugin.d.ts.map +1 -0
  84. package/dist/agents/channels/bluebubbles/plugin.js +242 -0
  85. package/dist/agents/channels/bluebubbles/plugin.js.map +1 -0
  86. package/dist/agents/channels/bluebubbles/probe.d.ts +79 -0
  87. package/dist/agents/channels/bluebubbles/probe.d.ts.map +1 -0
  88. package/dist/agents/channels/bluebubbles/probe.js +138 -0
  89. package/dist/agents/channels/bluebubbles/probe.js.map +1 -0
  90. package/dist/agents/channels/bluebubbles/reactions.d.ts +46 -0
  91. package/dist/agents/channels/bluebubbles/reactions.d.ts.map +1 -0
  92. package/dist/agents/channels/bluebubbles/reactions.js +207 -0
  93. package/dist/agents/channels/bluebubbles/reactions.js.map +1 -0
  94. package/dist/agents/channels/bluebubbles/send.d.ts +132 -0
  95. package/dist/agents/channels/bluebubbles/send.d.ts.map +1 -0
  96. package/dist/agents/channels/bluebubbles/send.js +327 -0
  97. package/dist/agents/channels/bluebubbles/send.js.map +1 -0
  98. package/dist/agents/channels/bluebubbles/status-issues.d.ts +57 -0
  99. package/dist/agents/channels/bluebubbles/status-issues.d.ts.map +1 -0
  100. package/dist/agents/channels/bluebubbles/status-issues.js +93 -0
  101. package/dist/agents/channels/bluebubbles/status-issues.js.map +1 -0
  102. package/dist/agents/channels/bluebubbles/types.d.ts +69 -0
  103. package/dist/agents/channels/bluebubbles/types.d.ts.map +1 -0
  104. package/dist/agents/channels/bluebubbles/types.js +118 -0
  105. package/dist/agents/channels/bluebubbles/types.js.map +1 -0
  106. package/dist/agents/channels/bluebubbles/webhook.d.ts +97 -0
  107. package/dist/agents/channels/bluebubbles/webhook.d.ts.map +1 -0
  108. package/dist/agents/channels/bluebubbles/webhook.js +249 -0
  109. package/dist/agents/channels/bluebubbles/webhook.js.map +1 -0
  110. package/dist/agents/channels/bundled-channel-metas.d.ts +13 -0
  111. package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
  112. package/dist/agents/channels/bundled-channel-metas.js +33 -0
  113. package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
  114. package/dist/agents/channels/imessage/account-config.d.ts +178 -0
  115. package/dist/agents/channels/imessage/account-config.d.ts.map +1 -0
  116. package/dist/agents/channels/imessage/account-config.js +371 -0
  117. package/dist/agents/channels/imessage/account-config.js.map +1 -0
  118. package/dist/agents/channels/imessage/adapter.d.ts +36 -0
  119. package/dist/agents/channels/imessage/adapter.d.ts.map +1 -0
  120. package/dist/agents/channels/imessage/adapter.js +286 -0
  121. package/dist/agents/channels/imessage/adapter.js.map +1 -0
  122. package/dist/agents/channels/imessage/client.d.ts +99 -0
  123. package/dist/agents/channels/imessage/client.d.ts.map +1 -0
  124. package/dist/agents/channels/imessage/client.js +231 -0
  125. package/dist/agents/channels/imessage/client.js.map +1 -0
  126. package/dist/agents/channels/imessage/connection.d.ts +101 -0
  127. package/dist/agents/channels/imessage/connection.d.ts.map +1 -0
  128. package/dist/agents/channels/imessage/connection.js +367 -0
  129. package/dist/agents/channels/imessage/connection.js.map +1 -0
  130. package/dist/agents/channels/imessage/format.d.ts +45 -0
  131. package/dist/agents/channels/imessage/format.d.ts.map +1 -0
  132. package/dist/agents/channels/imessage/format.js +170 -0
  133. package/dist/agents/channels/imessage/format.js.map +1 -0
  134. package/dist/agents/channels/imessage/history.d.ts +49 -0
  135. package/dist/agents/channels/imessage/history.d.ts.map +1 -0
  136. package/dist/agents/channels/imessage/history.js +74 -0
  137. package/dist/agents/channels/imessage/history.js.map +1 -0
  138. package/dist/agents/channels/imessage/index.d.ts +25 -0
  139. package/dist/agents/channels/imessage/index.d.ts.map +1 -0
  140. package/dist/agents/channels/imessage/index.js +25 -0
  141. package/dist/agents/channels/imessage/index.js.map +1 -0
  142. package/dist/agents/channels/imessage/media.d.ts +92 -0
  143. package/dist/agents/channels/imessage/media.d.ts.map +1 -0
  144. package/dist/agents/channels/imessage/media.js +196 -0
  145. package/dist/agents/channels/imessage/media.js.map +1 -0
  146. package/dist/agents/channels/imessage/messaging.d.ts +14 -0
  147. package/dist/agents/channels/imessage/messaging.d.ts.map +1 -0
  148. package/dist/agents/channels/imessage/messaging.js +37 -0
  149. package/dist/agents/channels/imessage/messaging.js.map +1 -0
  150. package/dist/agents/channels/imessage/module.d.ts +16 -0
  151. package/dist/agents/channels/imessage/module.d.ts.map +1 -0
  152. package/dist/agents/channels/imessage/module.js +23 -0
  153. package/dist/agents/channels/imessage/module.js.map +1 -0
  154. package/dist/agents/channels/imessage/monitor.d.ts +207 -0
  155. package/dist/agents/channels/imessage/monitor.d.ts.map +1 -0
  156. package/dist/agents/channels/imessage/monitor.js +504 -0
  157. package/dist/agents/channels/imessage/monitor.js.map +1 -0
  158. package/dist/agents/channels/imessage/plugin.d.ts +53 -0
  159. package/dist/agents/channels/imessage/plugin.d.ts.map +1 -0
  160. package/dist/agents/channels/imessage/plugin.js +215 -0
  161. package/dist/agents/channels/imessage/plugin.js.map +1 -0
  162. package/dist/agents/channels/imessage/probe.d.ts +68 -0
  163. package/dist/agents/channels/imessage/probe.d.ts.map +1 -0
  164. package/dist/agents/channels/imessage/probe.js +134 -0
  165. package/dist/agents/channels/imessage/probe.js.map +1 -0
  166. package/dist/agents/channels/imessage/remote-attachments.d.ts +61 -0
  167. package/dist/agents/channels/imessage/remote-attachments.d.ts.map +1 -0
  168. package/dist/agents/channels/imessage/remote-attachments.js +131 -0
  169. package/dist/agents/channels/imessage/remote-attachments.js.map +1 -0
  170. package/dist/agents/channels/imessage/send.d.ts +61 -0
  171. package/dist/agents/channels/imessage/send.d.ts.map +1 -0
  172. package/dist/agents/channels/imessage/send.js +108 -0
  173. package/dist/agents/channels/imessage/send.js.map +1 -0
  174. package/dist/agents/channels/imessage/targets.d.ts +91 -0
  175. package/dist/agents/channels/imessage/targets.d.ts.map +1 -0
  176. package/dist/agents/channels/imessage/targets.js +245 -0
  177. package/dist/agents/channels/imessage/targets.js.map +1 -0
  178. package/dist/agents/channels/imessage/watch-error.d.ts +23 -0
  179. package/dist/agents/channels/imessage/watch-error.d.ts.map +1 -0
  180. package/dist/agents/channels/imessage/watch-error.js +69 -0
  181. package/dist/agents/channels/imessage/watch-error.js.map +1 -0
  182. package/dist/agents/channels/inbound-pipeline.d.ts +11 -0
  183. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  184. package/dist/agents/channels/inbound-pipeline.js +20 -1
  185. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  186. package/dist/agents/channels/manager.d.ts +9 -0
  187. package/dist/agents/channels/manager.d.ts.map +1 -1
  188. package/dist/agents/channels/manager.js.map +1 -1
  189. package/dist/agents/channels/sdk.d.ts +4 -0
  190. package/dist/agents/channels/sdk.d.ts.map +1 -1
  191. package/dist/agents/channels/sdk.js +4 -0
  192. package/dist/agents/channels/sdk.js.map +1 -1
  193. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  194. package/dist/agents/extensions/modules/index.js +12 -0
  195. package/dist/agents/extensions/modules/index.js.map +1 -1
  196. package/dist/agents/session-wiring.d.ts +31 -0
  197. package/dist/agents/session-wiring.d.ts.map +1 -1
  198. package/dist/agents/session-wiring.js +45 -2
  199. package/dist/agents/session-wiring.js.map +1 -1
  200. package/dist/agents/tools/bluebubbles-action-tool.d.ts +66 -0
  201. package/dist/agents/tools/bluebubbles-action-tool.d.ts.map +1 -0
  202. package/dist/agents/tools/bluebubbles-action-tool.js +234 -0
  203. package/dist/agents/tools/bluebubbles-action-tool.js.map +1 -0
  204. package/dist/agents/tools/registry.d.ts.map +1 -1
  205. package/dist/agents/tools/registry.js +18 -0
  206. package/dist/agents/tools/registry.js.map +1 -1
  207. package/dist/buildstamp.json +1 -1
  208. package/dist/cli/commands/expose.d.ts +40 -0
  209. package/dist/cli/commands/expose.d.ts.map +1 -0
  210. package/dist/cli/commands/expose.js +200 -0
  211. package/dist/cli/commands/expose.js.map +1 -0
  212. package/dist/cli/program/build-program.d.ts.map +1 -1
  213. package/dist/cli/program/build-program.js +61 -0
  214. package/dist/cli/program/build-program.js.map +1 -1
  215. package/dist/config/io.d.ts +41 -0
  216. package/dist/config/io.d.ts.map +1 -1
  217. package/dist/config/io.js.map +1 -1
  218. package/dist/core/server.d.ts.map +1 -1
  219. package/dist/core/server.js +48 -2
  220. package/dist/core/server.js.map +1 -1
  221. package/dist/core/tunnel/auth-proxy.d.ts +55 -0
  222. package/dist/core/tunnel/auth-proxy.d.ts.map +1 -0
  223. package/dist/core/tunnel/auth-proxy.js +179 -0
  224. package/dist/core/tunnel/auth-proxy.js.map +1 -0
  225. package/dist/core/tunnel/manager.d.ts +42 -0
  226. package/dist/core/tunnel/manager.d.ts.map +1 -0
  227. package/dist/core/tunnel/manager.js +102 -0
  228. package/dist/core/tunnel/manager.js.map +1 -0
  229. package/dist/core/tunnel/providers/bore.d.ts +18 -0
  230. package/dist/core/tunnel/providers/bore.d.ts.map +1 -0
  231. package/dist/core/tunnel/providers/bore.js +117 -0
  232. package/dist/core/tunnel/providers/bore.js.map +1 -0
  233. package/dist/core/tunnel/providers/cloudflared.d.ts +24 -0
  234. package/dist/core/tunnel/providers/cloudflared.d.ts.map +1 -0
  235. package/dist/core/tunnel/providers/cloudflared.js +179 -0
  236. package/dist/core/tunnel/providers/cloudflared.js.map +1 -0
  237. package/dist/core/tunnel/providers/custom.d.ts +21 -0
  238. package/dist/core/tunnel/providers/custom.d.ts.map +1 -0
  239. package/dist/core/tunnel/providers/custom.js +124 -0
  240. package/dist/core/tunnel/providers/custom.js.map +1 -0
  241. package/dist/core/tunnel/registry.d.ts +15 -0
  242. package/dist/core/tunnel/registry.d.ts.map +1 -0
  243. package/dist/core/tunnel/registry.js +26 -0
  244. package/dist/core/tunnel/registry.js.map +1 -0
  245. package/dist/core/tunnel/state.d.ts +39 -0
  246. package/dist/core/tunnel/state.d.ts.map +1 -0
  247. package/dist/core/tunnel/state.js +57 -0
  248. package/dist/core/tunnel/state.js.map +1 -0
  249. package/dist/core/tunnel/types.d.ts +61 -0
  250. package/dist/core/tunnel/types.d.ts.map +1 -0
  251. package/dist/core/tunnel/types.js +20 -0
  252. package/dist/core/tunnel/types.js.map +1 -0
  253. package/dist/infra/net/fetch-guard.d.ts +24 -2
  254. package/dist/infra/net/fetch-guard.d.ts.map +1 -1
  255. package/dist/infra/net/fetch-guard.js +78 -31
  256. package/dist/infra/net/fetch-guard.js.map +1 -1
  257. package/package.json +5 -1
@@ -0,0 +1,249 @@
1
+ /**
2
+ * BlueBubbles inbound gateway route.
3
+ *
4
+ * BlueBubbles POSTs each event to a Brigade gateway HTTP route. Because a
5
+ * BlueBubbles webhook CANNOT send custom headers, the server PASSWORD is embedded
6
+ * in the registered webhook URL's QUERY STRING (`?password=…` / `?guid=…`) and
7
+ * verified on each inbound POST. (Some BlueBubbles versions also send the token
8
+ * as a header — those are accepted too.) Verification happens FIRST, before the
9
+ * body is parsed / routed, so a forged event can't reach the agent.
10
+ *
11
+ * Mirrors `slack/webhook.ts` (the webhook-ingress blueprint): build an
12
+ * `HttpRoute`, register it via `b.httpRoute(...)` from the module, resolve the
13
+ * started adapter (`resolveSink`) at REQUEST time (late binding — the route is
14
+ * registered before the plugin starts accounts), always reply 200 so BlueBubbles
15
+ * doesn't retry-storm.
16
+ */
17
+ import { timingSafeEqual } from "node:crypto";
18
+ /** Cap on the webhook body (a BlueBubbles event is small; 4 MiB is generous). */
19
+ const WEBHOOK_MAX_BODY_BYTES = 4 * 1024 * 1024;
20
+ /** Default fixed-window rate-limit: max authenticated requests per window. */
21
+ export const WEBHOOK_RATE_LIMIT_MAX = 240;
22
+ /** Default fixed-window length (ms). 240 req / 10s ≈ 24 rps sustained per account. */
23
+ export const WEBHOOK_RATE_LIMIT_WINDOW_MS = 10_000;
24
+ /** Default bound on concurrently in-flight handler bodies (normalize/dedupe/dispatch). */
25
+ export const WEBHOOK_MAX_IN_FLIGHT = 32;
26
+ /** Build a fixed-window rate limiter (`max` requests per `windowMs`). */
27
+ export function createFixedWindowRateLimiter(max, windowMs) {
28
+ const cap = Math.max(1, Math.floor(max));
29
+ const span = Math.max(1, Math.floor(windowMs));
30
+ let windowStart = 0;
31
+ let count = 0;
32
+ return {
33
+ hit(nowMs = Date.now()) {
34
+ if (nowMs - windowStart >= span) {
35
+ windowStart = nowMs;
36
+ count = 0;
37
+ }
38
+ count++;
39
+ return count <= cap;
40
+ },
41
+ };
42
+ }
43
+ /** Build an in-flight concurrency limiter capped at `max` simultaneous holders. */
44
+ export function createInFlightLimiter(max) {
45
+ const cap = Math.max(1, Math.floor(max));
46
+ let active = 0;
47
+ return {
48
+ tryAcquire() {
49
+ if (active >= cap)
50
+ return null;
51
+ active++;
52
+ let released = false;
53
+ return () => {
54
+ if (released)
55
+ return;
56
+ released = true;
57
+ active--;
58
+ };
59
+ },
60
+ inFlight: () => active,
61
+ };
62
+ }
63
+ /** Constant-time compare of two strings — avoids leaking via timing. */
64
+ export function safeEqualToken(a, b) {
65
+ if (a.length !== b.length)
66
+ return false;
67
+ try {
68
+ return timingSafeEqual(Buffer.from(a, "utf8"), Buffer.from(b, "utf8"));
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ /**
75
+ * Verify a BlueBubbles webhook request's password. The supplied token comes from
76
+ * the URL query (`password` / `guid`) or, when present, a header. When
77
+ * `expectedPassword` is empty the check is SKIPPED (returns true) — the operator
78
+ * opted out (not recommended). Returns false when a password is configured but
79
+ * the supplied one is missing / wrong.
80
+ */
81
+ export function verifyBlueBubblesWebhook(args) {
82
+ if (!args.expectedPassword)
83
+ return true; // no password configured → skip
84
+ const supplied = (args.suppliedToken ?? "").trim();
85
+ if (!supplied)
86
+ return false;
87
+ return safeEqualToken(supplied, args.expectedPassword);
88
+ }
89
+ /** Pull the auth token from the request URL query or a header. */
90
+ function extractSuppliedToken(req) {
91
+ // URL query (BlueBubbles can't set custom headers, so this is the primary path).
92
+ const rawUrl = req.url ?? "";
93
+ const qIdx = rawUrl.indexOf("?");
94
+ if (qIdx >= 0) {
95
+ const params = new URLSearchParams(rawUrl.slice(qIdx + 1));
96
+ const fromQuery = params.get("password") ?? params.get("guid");
97
+ if (fromQuery)
98
+ return fromQuery;
99
+ }
100
+ // Header fallbacks (some BB proxy setups inject them).
101
+ const header = (name) => {
102
+ const v = req.headers[name];
103
+ const s = Array.isArray(v) ? v[0] : v;
104
+ return s ? s.replace(/^Bearer\s+/i, "").trim() : undefined;
105
+ };
106
+ return header("x-password") ?? header("x-guid") ?? header("x-bluebubbles-guid") ?? header("authorization");
107
+ }
108
+ /** Read a request body up to `maxBytes`, rejecting (→ null) when it overflows. */
109
+ function readBody(req, maxBytes) {
110
+ return new Promise((resolve) => {
111
+ const chunks = [];
112
+ let size = 0;
113
+ let overflowed = false;
114
+ req.on("data", (chunk) => {
115
+ if (overflowed)
116
+ return;
117
+ size += chunk.length;
118
+ if (size > maxBytes) {
119
+ overflowed = true;
120
+ resolve(null);
121
+ return;
122
+ }
123
+ chunks.push(chunk);
124
+ });
125
+ req.on("end", () => {
126
+ if (overflowed)
127
+ return;
128
+ resolve(Buffer.concat(chunks).toString("utf8"));
129
+ });
130
+ req.on("error", () => resolve(null));
131
+ });
132
+ }
133
+ /**
134
+ * Parse the request body. BlueBubbles delivers JSON; a form-encoded fallback
135
+ * (some proxy setups) carries the JSON under a `payload`/`data` field.
136
+ */
137
+ export function parseBlueBubblesBody(rawBody, contentType) {
138
+ const ct = (contentType ?? "").toLowerCase();
139
+ const tryJson = (s) => {
140
+ try {
141
+ const v = JSON.parse(s);
142
+ return v && typeof v === "object" ? v : null;
143
+ }
144
+ catch {
145
+ return null;
146
+ }
147
+ };
148
+ let body = null;
149
+ if (ct.includes("application/x-www-form-urlencoded")) {
150
+ const params = new URLSearchParams(rawBody);
151
+ const inner = params.get("payload") ?? params.get("data") ?? params.get("message");
152
+ if (inner)
153
+ body = tryJson(inner);
154
+ }
155
+ if (!body)
156
+ body = tryJson(rawBody);
157
+ if (!body)
158
+ return null;
159
+ const type = typeof body.type === "string" ? body.type : undefined;
160
+ return { ...(type ? { type } : {}), payload: body };
161
+ }
162
+ /**
163
+ * Build the Brigade `HttpRoute` for the BlueBubbles webhook. Register it via
164
+ * `b.httpRoute(...)` from the module.
165
+ */
166
+ export function buildBlueBubblesWebhookRoute(args) {
167
+ // Per-route limiters (one route = one account). Built once and closed over so
168
+ // the window/in-flight counters persist across requests.
169
+ const rateLimiter = createFixedWindowRateLimiter(args.rateLimitMax ?? WEBHOOK_RATE_LIMIT_MAX, args.rateLimitWindowMs ?? WEBHOOK_RATE_LIMIT_WINDOW_MS);
170
+ const inFlight = createInFlightLimiter(args.maxInFlight ?? WEBHOOK_MAX_IN_FLIGHT);
171
+ const handler = async (req, res) => {
172
+ const reply = (status, body) => {
173
+ res.statusCode = status;
174
+ res.setHeader("content-type", "application/json");
175
+ res.end(typeof body === "string" ? body : JSON.stringify(body));
176
+ };
177
+ if ((req.method ?? "").toUpperCase() !== "POST") {
178
+ reply(405, { ok: false, error: "method not allowed" });
179
+ return;
180
+ }
181
+ // Auth FIRST — verify the password before reading / parsing the body.
182
+ const supplied = extractSuppliedToken(req);
183
+ if (!verifyBlueBubblesWebhook({ expectedPassword: args.password, suppliedToken: supplied })) {
184
+ args.log?.("bluebubbles webhook rejected — bad password");
185
+ reply(401, { ok: false, error: "unauthorized" });
186
+ return;
187
+ }
188
+ // Rate-limit the authenticated stream — a replay-storm / hostile sender that
189
+ // has the password must not run the normalize/dedupe/dispatch path
190
+ // unbounded. Over-limit requests are dropped with 429 BEFORE the body is
191
+ // read, so the cost of an abusive burst is bounded.
192
+ if (!rateLimiter.hit(args.now?.())) {
193
+ args.log?.("bluebubbles webhook throttled — over rate limit");
194
+ reply(429, { ok: false, error: "rate limited" });
195
+ return;
196
+ }
197
+ // Bound concurrent in-flight handler bodies. When the cap is reached, shed
198
+ // load with 429 rather than letting unbounded parses/dispatches pile up.
199
+ const release = inFlight.tryAcquire();
200
+ if (!release) {
201
+ args.log?.("bluebubbles webhook throttled — in-flight cap reached");
202
+ reply(429, { ok: false, error: "busy" });
203
+ return;
204
+ }
205
+ try {
206
+ // The gateway dispatcher has ALREADY drained + buffered the body onto
207
+ // `req.body`. Read that first; only stream when exercised outside the gateway.
208
+ const pre = req.body;
209
+ const raw = pre ? pre.toString("utf8") : await readBody(req, WEBHOOK_MAX_BODY_BYTES);
210
+ if (raw === null) {
211
+ reply(413, { ok: false, error: "payload too large" });
212
+ return;
213
+ }
214
+ const contentType = (() => {
215
+ const c = req.headers["content-type"];
216
+ return Array.isArray(c) ? (c[0] ?? "") : (c ?? "");
217
+ })();
218
+ const parsed = parseBlueBubblesBody(raw, contentType);
219
+ if (!parsed) {
220
+ reply(400, { ok: false, error: "invalid body" });
221
+ return;
222
+ }
223
+ const sink = args.resolveSink();
224
+ if (sink) {
225
+ try {
226
+ sink.feedWebhookEvent(parsed.type, parsed.payload);
227
+ }
228
+ catch (err) {
229
+ args.log?.("bluebubbles webhook dispatch threw", { error: err instanceof Error ? err.message : String(err) });
230
+ }
231
+ }
232
+ // Always 200 so BlueBubbles doesn't retry-storm.
233
+ reply(200, { ok: true });
234
+ }
235
+ finally {
236
+ release();
237
+ }
238
+ };
239
+ return {
240
+ method: "POST",
241
+ path: args.path,
242
+ auth: "none", // BlueBubbles can't present operator-auth; the password query IS the auth.
243
+ match: "exact",
244
+ maxBodyBytes: WEBHOOK_MAX_BODY_BYTES,
245
+ skipSessionGuard: true,
246
+ handler,
247
+ };
248
+ }
249
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/webhook.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,19 @@ export declare const TELEGRAM_CHANNEL_META: ChannelMeta;
25
25
  export declare const SLACK_CHANNEL_META: ChannelMeta;
26
26
  /** Discord channel metadata (markdown-capable; visible everywhere by default). */
27
27
  export declare const DISCORD_CHANNEL_META: ChannelMeta;
28
+ /**
29
+ * iMessage channel metadata. iMessage has NO rich markup (plain text only), so
30
+ * it is NOT markdown-capable — the assembler's markdown gate strips formatting
31
+ * for this channel. Driven by the `imsg` CLI as a JSON-RPC subprocess.
32
+ */
33
+ export declare const IMESSAGE_CHANNEL_META: ChannelMeta;
34
+ /**
35
+ * BlueBubbles channel metadata. Like iMessage, BlueBubbles has NO rich markup
36
+ * (plain text only), so it is NOT markdown-capable — the assembler's markdown
37
+ * gate strips formatting for this channel. Driven by the BlueBubbles macOS server
38
+ * over REST (outbound) + a webhook (inbound).
39
+ */
40
+ export declare const BLUEBUBBLES_CHANNEL_META: ChannelMeta;
28
41
  /** Every bundled channel meta, in declaration order. The registry seeds from this. */
29
42
  export declare const BUNDLED_CHANNEL_METAS: readonly ChannelMeta[];
30
43
  //# sourceMappingURL=bundled-channel-metas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundled-channel-metas.d.ts","sourceRoot":"","sources":["../../../src/agents/channels/bundled-channel-metas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,mFAAmF;AACnF,eAAO,MAAM,qBAAqB,EAAE,WAQnC,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,qBAAqB,EAAE,WAQnC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,EAAE,WAQhC,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,EAAE,WAQlC,CAAC;AAEF,sFAAsF;AACtF,eAAO,MAAM,qBAAqB,EAAE,SAAS,WAAW,EAKvD,CAAC"}
1
+ {"version":3,"file":"bundled-channel-metas.d.ts","sourceRoot":"","sources":["../../../src/agents/channels/bundled-channel-metas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,mFAAmF;AACnF,eAAO,MAAM,qBAAqB,EAAE,WAQnC,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,qBAAqB,EAAE,WAQnC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,EAAE,WAQhC,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,EAAE,WAQlC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,WASnC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAStC,CAAC;AAEF,sFAAsF;AACtF,eAAO,MAAM,qBAAqB,EAAE,SAAS,WAAW,EAOvD,CAAC"}
@@ -56,11 +56,44 @@ export const DISCORD_CHANNEL_META = {
56
56
  order: 40,
57
57
  markdownCapable: true,
58
58
  };
59
+ /**
60
+ * iMessage channel metadata. iMessage has NO rich markup (plain text only), so
61
+ * it is NOT markdown-capable — the assembler's markdown gate strips formatting
62
+ * for this channel. Driven by the `imsg` CLI as a JSON-RPC subprocess.
63
+ */
64
+ export const IMESSAGE_CHANNEL_META = {
65
+ id: "imessage",
66
+ label: "iMessage",
67
+ selectionLabel: "iMessage",
68
+ docsPath: "channels/imessage",
69
+ blurb: "Drive native iMessage via the imsg CLI; DM/group chat over Messages.app.",
70
+ order: 50,
71
+ aliases: ["imsg"],
72
+ markdownCapable: false,
73
+ };
74
+ /**
75
+ * BlueBubbles channel metadata. Like iMessage, BlueBubbles has NO rich markup
76
+ * (plain text only), so it is NOT markdown-capable — the assembler's markdown
77
+ * gate strips formatting for this channel. Driven by the BlueBubbles macOS server
78
+ * over REST (outbound) + a webhook (inbound).
79
+ */
80
+ export const BLUEBUBBLES_CHANNEL_META = {
81
+ id: "bluebubbles",
82
+ label: "BlueBubbles",
83
+ selectionLabel: "BlueBubbles (iMessage)",
84
+ docsPath: "channels/bluebubbles",
85
+ blurb: "Drive native iMessage via a BlueBubbles macOS server; REST-out + webhook-in, reactions/edit/unsend.",
86
+ order: 55,
87
+ aliases: ["bb"],
88
+ markdownCapable: false,
89
+ };
59
90
  /** Every bundled channel meta, in declaration order. The registry seeds from this. */
60
91
  export const BUNDLED_CHANNEL_METAS = [
61
92
  WHATSAPP_CHANNEL_META,
62
93
  TELEGRAM_CHANNEL_META,
63
94
  SLACK_CHANNEL_META,
64
95
  DISCORD_CHANNEL_META,
96
+ IMESSAGE_CHANNEL_META,
97
+ BLUEBUBBLES_CHANNEL_META,
65
98
  ];
66
99
  //# sourceMappingURL=bundled-channel-metas.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundled-channel-metas.js","sourceRoot":"","sources":["../../../src/agents/channels/bundled-channel-metas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,cAAc,EAAE,UAAU;IAC1B,QAAQ,EAAE,mBAAmB;IAC7B,KAAK,EAAE,mDAAmD;IAC1D,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,cAAc,EAAE,UAAU;IAC1B,QAAQ,EAAE,mBAAmB;IAC7B,KAAK,EAAE,8DAA8D;IACrE,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,kBAAkB,GAAgB;IAC9C,EAAE,EAAE,OAAO;IACX,KAAK,EAAE,OAAO;IACd,cAAc,EAAE,OAAO;IACvB,QAAQ,EAAE,gBAAgB;IAC1B,KAAK,EAAE,mEAAmE;IAC1E,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAChD,EAAE,EAAE,SAAS;IACb,KAAK,EAAE,SAAS;IAChB,cAAc,EAAE,SAAS;IACzB,QAAQ,EAAE,kBAAkB;IAC5B,KAAK,EAAE,8DAA8D;IACrE,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC5D,qBAAqB;IACrB,qBAAqB;IACrB,kBAAkB;IAClB,oBAAoB;CACpB,CAAC"}
1
+ {"version":3,"file":"bundled-channel-metas.js","sourceRoot":"","sources":["../../../src/agents/channels/bundled-channel-metas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,cAAc,EAAE,UAAU;IAC1B,QAAQ,EAAE,mBAAmB;IAC7B,KAAK,EAAE,mDAAmD;IAC1D,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,cAAc,EAAE,UAAU;IAC1B,QAAQ,EAAE,mBAAmB;IAC7B,KAAK,EAAE,8DAA8D;IACrE,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,kBAAkB,GAAgB;IAC9C,EAAE,EAAE,OAAO;IACX,KAAK,EAAE,OAAO;IACd,cAAc,EAAE,OAAO;IACvB,QAAQ,EAAE,gBAAgB;IAC1B,KAAK,EAAE,mEAAmE;IAC1E,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAChD,EAAE,EAAE,SAAS;IACb,KAAK,EAAE,SAAS;IAChB,cAAc,EAAE,SAAS;IACzB,QAAQ,EAAE,kBAAkB;IAC5B,KAAK,EAAE,8DAA8D;IACrE,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,cAAc,EAAE,UAAU;IAC1B,QAAQ,EAAE,mBAAmB;IAC7B,KAAK,EAAE,0EAA0E;IACjF,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,eAAe,EAAE,KAAK;CACtB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAgB;IACpD,EAAE,EAAE,aAAa;IACjB,KAAK,EAAE,aAAa;IACpB,cAAc,EAAE,wBAAwB;IACxC,QAAQ,EAAE,sBAAsB;IAChC,KAAK,EAAE,qGAAqG;IAC5G,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,eAAe,EAAE,KAAK;CACtB,CAAC;AAEF,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC5D,qBAAqB;IACrB,qBAAqB;IACrB,kBAAkB;IAClB,oBAAoB;IACpB,qBAAqB;IACrB,wBAAwB;CACxB,CAAC"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * iMessage config-shape helpers (multi-ACCOUNT aware; mirrors Discord's
3
+ * `account-config.ts`).
4
+ *
5
+ * iMessage is driven through the third-party `imsg` CLI run as a long-lived
6
+ * JSON-RPC subprocess (`imsg rpc`). Unlike a token-based channel there is NO
7
+ * secret to seal — the auth surface is "the machine running the gateway is
8
+ * already signed into Messages.app". So instead of a bot token this module
9
+ * resolves the local-runtime knobs the transport needs:
10
+ *
11
+ * - `cliPath` path to the `imsg` binary (default `"imsg"`, found on PATH).
12
+ * - `dbPath` optional override for the chat.db the binary reads.
13
+ * - `service` default send service: `"imessage"` | `"sms"` | `"auto"`.
14
+ * - `region` default phone-number region for E.164 normalisation (US).
15
+ * - `mediaMaxMb` cap on an outbound attachment's size (MB).
16
+ * - `probeTimeoutMs` RPC round-trip timeout for the doctor/probe call.
17
+ * - `attachmentRoots` allow-list of dirs inbound media may be read from.
18
+ *
19
+ * Two config shapes are recognised so the surface lines up with the other
20
+ * channels:
21
+ *
22
+ * Legacy (single-account):
23
+ * channels.imessage = { enabled: true, cliPath: "imsg", service: "auto" }
24
+ *
25
+ * Multi-account:
26
+ * channels.imessage = {
27
+ * enabled: true,
28
+ * accounts: [
29
+ * { id: "personal", dbPath: "~/Library/Messages/chat.db" },
30
+ * { id: "work", cliPath: "/opt/imsg/bin/imsg" },
31
+ * ],
32
+ * }
33
+ *
34
+ * A legacy config with no `accounts[]` reads as `[{ id: "default" }]`.
35
+ */
36
+ import type { BrigadeConfig } from "../../../config/io.js";
37
+ /** Canonical channel id + default account id. */
38
+ declare const CHANNEL_ID = "imessage";
39
+ declare const DEFAULT_ACCOUNT_ID = "default";
40
+ /** Default `imsg` binary name — resolved on PATH when no explicit path is set. */
41
+ declare const DEFAULT_CLI_PATH = "imsg";
42
+ /** Default RPC probe / request timeout (ms). */
43
+ export declare const DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS = 10000;
44
+ /** Default per-message outbound text chunk size (chars). iMessage's practical limit. */
45
+ export declare const DEFAULT_IMESSAGE_TEXT_CHUNK_LIMIT = 4000;
46
+ /**
47
+ * Default rolling-history depth for an untagged GROUP message (0 = off). iMessage
48
+ * delivers one notification per message with no thread context, so the monitor
49
+ * keeps the last N seen group messages and prepends them as context.
50
+ */
51
+ export declare const DEFAULT_IMESSAGE_HISTORY_LIMIT = 0;
52
+ /** Default macOS Messages attachment root inbound media may be read from. */
53
+ export declare const DEFAULT_IMESSAGE_ATTACHMENT_ROOTS: readonly string[];
54
+ /** Per-knob env var consulted as a last-resort fallback for the binary path. */
55
+ declare const CLI_PATH_ENV_VAR = "IMSG_CLI_PATH";
56
+ /** Outbound send service. `auto` lets the bridge pick iMessage vs SMS. */
57
+ export type IMessageService = "imessage" | "sms" | "auto";
58
+ /** Outbound chunk strategy. `length` = pack to the char limit (default); `newline` = prefer line breaks. */
59
+ export type IMessageChunkMode = "length" | "newline";
60
+ /** Resolved per-account info — what the adapter runtime reads. */
61
+ export interface ResolvedIMessageAccount {
62
+ accountId: string;
63
+ enabled: boolean;
64
+ /** `imsg` binary path (default `"imsg"`). */
65
+ cliPath: string;
66
+ /** Optional chat.db override (`~`-expansion done by the client). */
67
+ dbPath: string;
68
+ /** Default send service for this account. */
69
+ service: IMessageService;
70
+ /** Default phone-number region (E.164 normalisation). */
71
+ region: string;
72
+ /** Outbound media size cap (bytes). */
73
+ mediaMaxBytes: number;
74
+ /** RPC probe / request timeout (ms). */
75
+ probeTimeoutMs: number;
76
+ /**
77
+ * The bot's OWN iMessage handle (normalised — digits for a phone, lower-case
78
+ * for an email). When set, a group message whose text names this handle gets a
79
+ * populated `mentions[]` so the central pipeline's group requireMention gate
80
+ * can fire. Empty when unset (group mention-gating then can't match the bot).
81
+ */
82
+ selfHandle: string;
83
+ /**
84
+ * Remote host (`user@host` / `host`) when the `imsg` bridge runs on a DIFFERENT
85
+ * machine than the gateway. When set, inbound attachments are SCP-copied from
86
+ * the remote root to a local temp before resolution. Empty for a same-host setup.
87
+ */
88
+ remoteHost: string;
89
+ /** When false, skip inbound media resolution entirely (text-only ingest). Default true. */
90
+ includeAttachments: boolean;
91
+ /** Default outbound recipient when a send omits an explicit target. Empty when unset. */
92
+ defaultTo: string;
93
+ /** Rolling-history depth for an untagged GROUP message (0 = off). */
94
+ historyLimit: number;
95
+ /** Rolling-history depth for an untagged DM (0 = off). */
96
+ dmHistoryLimit: number;
97
+ /** Per-message outbound text chunk size (chars). */
98
+ textChunkLimit: number;
99
+ /** Outbound chunk strategy. */
100
+ chunkMode: IMessageChunkMode;
101
+ verbose: boolean;
102
+ }
103
+ /** Coerce a loose `service` string to the typed union (defaults to `auto`). */
104
+ export declare function coerceIMessageService(raw: unknown, fallback?: IMessageService): IMessageService;
105
+ /** Is the iMessage channel switched on at all (any shape)? */
106
+ export declare function imessageChannelEnabled(cfg: BrigadeConfig): boolean;
107
+ /** List configured account ids. Legacy single-account configs surface `["default"]`. */
108
+ export declare function listIMessageAccountIds(cfg: BrigadeConfig): string[];
109
+ /**
110
+ * Resolve the `imsg` binary path for an account. Precedence: per-account config
111
+ * `${VAR}`/literal → top-level config → `IMSG_CLI_PATH` env → the default
112
+ * `"imsg"` (found on PATH).
113
+ */
114
+ export declare function resolveIMessageCliPath(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
115
+ /**
116
+ * Resolve the optional chat.db override for an account. Per-account → top-level
117
+ * → "" (the binary uses its own default location). `~`-expansion is the client's
118
+ * job — this returns the raw path.
119
+ */
120
+ export declare function resolveIMessageDbPath(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
121
+ /**
122
+ * Resolve the inbound attachment roots iMessage media may be read from
123
+ * (account-specific → channel-global → the macOS Messages Attachments floor).
124
+ */
125
+ export declare function resolveIMessageAttachmentRoots(cfg: BrigadeConfig, accountId?: string | null): string[];
126
+ /**
127
+ * Resolve the REMOTE inbound attachment roots (when the `imsg` bridge runs on a
128
+ * different host than the gateway). Falls back through the local roots so a
129
+ * same-host setup is unchanged.
130
+ */
131
+ export declare function resolveIMessageRemoteAttachmentRoots(cfg: BrigadeConfig, accountId?: string | null): string[];
132
+ /** Resolve the RPC probe / request timeout (ms) for an account. */
133
+ export declare function resolveIMessageProbeTimeoutMs(cfg: BrigadeConfig, accountId?: string | null): number;
134
+ /**
135
+ * Normalise a handle for self/mention matching: an email lower-cases; a phone
136
+ * keeps only its digits (so `+1 (555) 123-4567` and `15551234567` compare equal).
137
+ * Returns "" for an empty input. Mirrors BlueBubbles' `normalizeBlueBubblesSelfHandle`.
138
+ */
139
+ export declare function normalizeIMessageSelfHandle(raw: string | undefined): string;
140
+ /**
141
+ * Resolve the bot's own handle for an account (per-account `selfHandle` wins over
142
+ * the top-level slot), normalised. Empty when unset.
143
+ */
144
+ export declare function resolveIMessageSelfHandle(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
145
+ /**
146
+ * Resolve the REMOTE host (`user@host` / `host`) for an account when the `imsg`
147
+ * bridge runs on a different machine. Per-account → top-level → "". Returns the
148
+ * raw configured value; the SCP layer safety-validates it.
149
+ */
150
+ export declare function resolveIMessageRemoteHost(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
151
+ /**
152
+ * Resolve whether inbound media should be resolved at all. Per-account →
153
+ * top-level → DEFAULT TRUE (resolve media). Setting `includeAttachments:false`
154
+ * opts a noisy / privacy-sensitive account out of inbound media resolution.
155
+ */
156
+ export declare function resolveIMessageIncludeAttachments(cfg: BrigadeConfig, accountId?: string | null): boolean;
157
+ /** Resolve the default outbound recipient (per-account → top-level → ""). */
158
+ export declare function resolveIMessageDefaultTo(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
159
+ /** Resolve the rolling-history depth for an untagged GROUP message (0 = off). */
160
+ export declare function resolveIMessageHistoryLimit(cfg: BrigadeConfig, accountId?: string | null): number;
161
+ /** Resolve the rolling-history depth for an untagged DM (0 = off). */
162
+ export declare function resolveIMessageDmHistoryLimit(cfg: BrigadeConfig, accountId?: string | null): number;
163
+ /** Resolve the per-message outbound text chunk size (chars). */
164
+ export declare function resolveIMessageTextChunkLimit(cfg: BrigadeConfig, accountId?: string | null): number;
165
+ /** Coerce a loose `chunkMode` string to the typed union (defaults to `length`). */
166
+ export declare function coerceIMessageChunkMode(raw: unknown): IMessageChunkMode;
167
+ /** Resolve the outbound chunk strategy (per-account → top-level → `length`). */
168
+ export declare function resolveIMessageChunkMode(cfg: BrigadeConfig, accountId?: string | null): IMessageChunkMode;
169
+ /** Resolve a per-account view of the config (defaults filled in). */
170
+ export declare function resolveIMessageAccount(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): ResolvedIMessageAccount;
171
+ /**
172
+ * Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
173
+ * Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
174
+ * session-reaper uses this to age out idle iMessage group sessions.
175
+ */
176
+ export declare function imessageThreadIdleTtlMs(cfg: BrigadeConfig): number | null;
177
+ export { CHANNEL_ID as IMESSAGE_CHANNEL_ID, DEFAULT_ACCOUNT_ID as IMESSAGE_DEFAULT_ACCOUNT_ID, CLI_PATH_ENV_VAR as IMESSAGE_CLI_PATH_ENV_VAR, DEFAULT_CLI_PATH as IMESSAGE_DEFAULT_CLI_PATH, };
178
+ //# sourceMappingURL=account-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-config.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/imessage/account-config.ts"],"names":[],"mappings":"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"}