@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,242 @@
1
+ /**
2
+ * BlueBubbles `ChannelPlugin` — the multi-ACCOUNT contract surface.
3
+ *
4
+ * Mirrors `slack/plugin.ts` (webhook-in + REST-out, multi-account): wraps
5
+ * `createBlueBubblesAdapter()` once per configured account, partitions per-account
6
+ * runtime in a `Map<accountId, AccountRuntime>`, and drives each account's inbound
7
+ * through the shared `runChannelInboundPipeline` so every account carries the
8
+ * identical ACL + debounce + abort surface.
9
+ *
10
+ * The webhook bridge: each module-registered route resolves its account's STARTED
11
+ * adapter via the per-account registry (`account-registry.ts`). This plugin
12
+ * populates that registry on `startAccount` (so a webhook POST for THIS account's
13
+ * path reaches THIS adapter) and clears it on `stopAccount` (so a torn-down
14
+ * account's route can't feed a dead adapter).
15
+ *
16
+ * The legacy single-account `createBlueBubblesAdapter` STEPS ASIDE when >1 account
17
+ * is configured (its `isConfigured` returns false for the default account).
18
+ */
19
+ import { buildBundledCommands, createInboundPipelineContext, createSubsystemLogger, runChannelInboundPipeline, BLUEBUBBLES_CHANNEL_META, } from "../sdk.js";
20
+ import { listBlueBubblesAccountIds, resolveBlueBubblesAccount, resolveBlueBubblesPassword, resolveBlueBubblesProbeTimeoutMs, resolveBlueBubblesServerUrl, BLUEBUBBLES_CHANNEL_ID, BLUEBUBBLES_DEFAULT_ACCOUNT_ID, } from "./account-config.js";
21
+ import { registerBlueBubblesAccountSink, removeBlueBubblesAccountSink } from "./account-registry.js";
22
+ import { createBlueBubblesAdapter } from "./adapter.js";
23
+ import { bluebubblesMessagingAdapter } from "./messaging.js";
24
+ import { probeBlueBubbles } from "./probe.js";
25
+ import { collectBlueBubblesStatusIssues, statusAccountFromSnapshot, toChannelStatusIssues } from "./status-issues.js";
26
+ const log = createSubsystemLogger("channels/bluebubbles/plugin");
27
+ const BLUEBUBBLES_META = BLUEBUBBLES_CHANNEL_META;
28
+ /** BlueBubbles capabilities baseline (rich actions are gated at runtime by Private-API status). */
29
+ const BLUEBUBBLES_BASE_CAPABILITIES = {
30
+ chatTypes: ["direct", "group"],
31
+ media: true,
32
+ reply: true,
33
+ reactions: true,
34
+ edit: true,
35
+ unsend: true,
36
+ };
37
+ /** Construct the plugin instance, capturing per-account runtime state in closure. */
38
+ export function createBlueBubblesPlugin(deps) {
39
+ const accountRuntimes = new Map();
40
+ const startAccount = async (ctx) => {
41
+ const accountId = ctx.accountId || BLUEBUBBLES_DEFAULT_ACCOUNT_ID;
42
+ const existing = accountRuntimes.get(accountId);
43
+ if (existing) {
44
+ try {
45
+ await existing.adapter.stop();
46
+ }
47
+ catch {
48
+ /* best-effort */
49
+ }
50
+ try {
51
+ existing.abort.abort("restart");
52
+ }
53
+ catch {
54
+ /* best-effort */
55
+ }
56
+ removeBlueBubblesAccountSink(accountId);
57
+ accountRuntimes.delete(accountId);
58
+ }
59
+ const cfg = deps.loadConfig();
60
+ const factory = deps.adapterFactory ?? defaultBlueBubblesAdapterFactory;
61
+ const adapter = factory({ accountId });
62
+ const accountAbort = new AbortController();
63
+ const parent = ctx.signal;
64
+ if (parent) {
65
+ if (parent.aborted)
66
+ accountAbort.abort();
67
+ else
68
+ parent.addEventListener("abort", () => accountAbort.abort(), { once: true });
69
+ }
70
+ const pipelineRunTurn = (turn) => deps.runTurn(turn);
71
+ const commandMap = new Map();
72
+ for (const c of buildBundledCommands(adapter))
73
+ commandMap.set(c.name.toLowerCase(), c);
74
+ const pipeline = createInboundPipelineContext({
75
+ adapter,
76
+ config: cfg,
77
+ agentId: deps.defaultAgentId,
78
+ runTurn: pipelineRunTurn,
79
+ commandMap,
80
+ parentAbort: accountAbort.signal,
81
+ });
82
+ const startCtx = {
83
+ signal: accountAbort.signal,
84
+ log: (msg, meta) => log.info(`[${accountId}] ${msg}`, meta),
85
+ onInbound: async (msg) => {
86
+ pipeline.config = deps.loadConfig();
87
+ const stamped = msg.accountId ? msg : { ...msg, accountId };
88
+ await runChannelInboundPipeline(pipeline, stamped);
89
+ },
90
+ };
91
+ try {
92
+ await adapter.start(startCtx);
93
+ accountRuntimes.set(accountId, { adapter, pipeline, abort: accountAbort });
94
+ // Bridge this started adapter to its webhook route via the registry.
95
+ registerBlueBubblesAccountSink(accountId, {
96
+ feedWebhookEvent: (eventType, payload) => adapter.feedWebhookEvent(eventType, payload),
97
+ });
98
+ log.info("bluebubbles account started", { accountId });
99
+ }
100
+ catch (err) {
101
+ log.warn("bluebubbles account failed to start", {
102
+ accountId,
103
+ error: err instanceof Error ? err.message : String(err),
104
+ });
105
+ throw err;
106
+ }
107
+ };
108
+ const stopAccount = async (ctx) => {
109
+ const runtime = accountRuntimes.get(ctx.accountId);
110
+ // Drop the sink BEFORE teardown so a late in-flight POST can't drive a dead adapter.
111
+ removeBlueBubblesAccountSink(ctx.accountId);
112
+ if (!runtime)
113
+ return;
114
+ accountRuntimes.delete(ctx.accountId);
115
+ try {
116
+ runtime.abort.abort("stop-requested");
117
+ }
118
+ catch {
119
+ /* best-effort */
120
+ }
121
+ for (const slot of runtime.pipeline.pendingDispatches.values())
122
+ clearTimeout(slot.timer);
123
+ runtime.pipeline.pendingDispatches.clear();
124
+ try {
125
+ await runtime.adapter.stop();
126
+ }
127
+ catch (err) {
128
+ log.warn("bluebubbles account stop threw", {
129
+ accountId: ctx.accountId,
130
+ error: err instanceof Error ? err.message : String(err),
131
+ });
132
+ }
133
+ };
134
+ const logoutAccount = async (ctx) => {
135
+ try {
136
+ await stopAccount(ctx);
137
+ return { ok: true };
138
+ }
139
+ catch (err) {
140
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
141
+ }
142
+ };
143
+ return {
144
+ id: BLUEBUBBLES_CHANNEL_ID,
145
+ meta: BLUEBUBBLES_META,
146
+ capabilities: BLUEBUBBLES_BASE_CAPABILITIES,
147
+ startedAccountIds: () => [...accountRuntimes.keys()],
148
+ getAdapter: (accountId) => accountRuntimes.get(accountId)?.adapter,
149
+ probeAccount: async (accountId, cfg) => {
150
+ return probeBlueBubbles({
151
+ serverUrl: resolveBlueBubblesServerUrl(cfg, accountId),
152
+ password: resolveBlueBubblesPassword(cfg, accountId),
153
+ timeoutMs: resolveBlueBubblesProbeTimeoutMs(cfg, accountId),
154
+ });
155
+ },
156
+ config: {
157
+ listAccountIds: (cfg) => listBlueBubblesAccountIds(cfg),
158
+ resolveAccount: (cfg, accountId) => resolveBlueBubblesAccount(cfg, accountId ?? undefined),
159
+ defaultAccountId: () => BLUEBUBBLES_DEFAULT_ACCOUNT_ID,
160
+ isEnabled: (account) => account.enabled,
161
+ },
162
+ gateway: {
163
+ startAccount,
164
+ stopAccount,
165
+ logoutAccount,
166
+ },
167
+ status: {
168
+ // Stamp probe-derived diagnostics onto the open-shaped snapshot so
169
+ // `collectStatusIssues` can derive structured issues without re-probing.
170
+ buildAccountSnapshot: async ({ account, cfg, runtime }) => {
171
+ const base = { ...(runtime ?? {}), id: account.accountId };
172
+ const configured = Boolean(account.serverUrl) && Boolean(account.password);
173
+ base.configured = configured;
174
+ if (configured) {
175
+ try {
176
+ const probe = await probeBlueBubbles({
177
+ serverUrl: resolveBlueBubblesServerUrl(cfg, account.accountId),
178
+ password: resolveBlueBubblesPassword(cfg, account.accountId),
179
+ timeoutMs: resolveBlueBubblesProbeTimeoutMs(cfg, account.accountId),
180
+ });
181
+ base.reachable = probe.ok;
182
+ base.privateApi = probe.privateApi;
183
+ }
184
+ catch {
185
+ base.reachable = false;
186
+ }
187
+ }
188
+ return base;
189
+ },
190
+ collectStatusIssues: (accounts) => toChannelStatusIssues(collectBlueBubblesStatusIssues((accounts ?? []).map((s) => statusAccountFromSnapshot(s)))),
191
+ },
192
+ outbound: {
193
+ sendText: async (params) => {
194
+ const accountId = params.target.accountId || BLUEBUBBLES_DEFAULT_ACCOUNT_ID;
195
+ const runtime = accountRuntimes.get(accountId);
196
+ if (!runtime)
197
+ return { ok: false, error: `bluebubbles account "${accountId}" is not running` };
198
+ try {
199
+ const sent = await runtime.adapter.sendText(params.target.to, params.text, { accountId });
200
+ return {
201
+ ok: true,
202
+ ...(sent && typeof sent === "object" && sent.messageId !== undefined ? { messageId: sent.messageId } : {}),
203
+ };
204
+ }
205
+ catch (err) {
206
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
207
+ }
208
+ },
209
+ sendMedia: async (params) => {
210
+ const accountId = params.target.accountId || BLUEBUBBLES_DEFAULT_ACCOUNT_ID;
211
+ const runtime = accountRuntimes.get(accountId);
212
+ if (!runtime || !runtime.adapter.sendMedia) {
213
+ return { ok: false, error: `bluebubbles account "${accountId}" cannot send media right now` };
214
+ }
215
+ try {
216
+ await runtime.adapter.sendMedia(params.target.to, {
217
+ kind: params.mediaType ?? "document",
218
+ path: params.mediaUrl,
219
+ ...(params.caption !== undefined ? { caption: params.caption } : {}),
220
+ });
221
+ return { ok: true };
222
+ }
223
+ catch (err) {
224
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
225
+ }
226
+ },
227
+ },
228
+ messaging: bluebubblesMessagingAdapter,
229
+ secrets: {
230
+ // The server password is a sealable secret-ref target.
231
+ secretTargetRegistryEntries: [
232
+ { path: "channels.bluebubbles.password", description: "BlueBubbles server password (single-account)" },
233
+ { path: "channels.bluebubbles.accounts.*.password", description: "BlueBubbles server password (per account)" },
234
+ ],
235
+ },
236
+ };
237
+ }
238
+ /** Default adapter factory — threads the per-account scope. */
239
+ function defaultBlueBubblesAdapterFactory(args) {
240
+ return createBlueBubblesAdapter({ accountId: args.accountId });
241
+ }
242
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * BlueBubbles probe / doctor.
3
+ *
4
+ * `probeBlueBubbles` does a `GET /api/v1/server/info` round-trip. It NEVER throws
5
+ * — it returns `{ ok, error?, fatal?, serverInfo?, privateApi, elapsedMs }` so
6
+ * `brigade channels status` / `doctor` can render a verdict and the adapter can
7
+ * gate rich actions on the detected Private-API status (and advertise
8
+ * capabilities honestly). `fetch` is injectable (the test seam).
9
+ *
10
+ * - `ok: false` + `fatal: true` → server unreachable / auth rejected (config error).
11
+ * - `ok: true` + `privateApi` → tri-state: true (rich actions live), false
12
+ * (text-only), or null (unknown — server info
13
+ * didn't report it).
14
+ */
15
+ import { type BlueBubblesServerInfo, type FetchLike } from "./types.js";
16
+ /** Result of a BlueBubbles probe — never throws; this is the verdict. */
17
+ export interface BlueBubblesProbeResult {
18
+ ok: boolean;
19
+ /** Operator-facing failure reason (when `ok: false`). */
20
+ error?: string;
21
+ /** True when the failure is a config error (bad URL / password), not transient. */
22
+ fatal?: boolean;
23
+ /** The parsed server/info payload (when reachable). */
24
+ serverInfo?: BlueBubblesServerInfo;
25
+ /** Private-API status — true / false / null (unknown). Gates rich actions. */
26
+ privateApi: boolean | null;
27
+ /**
28
+ * The macOS MAJOR version of the BlueBubbles host (e.g. 14, 15, 26), parsed
29
+ * from `serverInfo.os_version`. null when unknown. macOS 26+ removed iMessage
30
+ * EDIT, so the adapter refuses `edit` cleanly when this is ≥ 26.
31
+ */
32
+ macOSMajor: number | null;
33
+ /** Round-trip time in ms. */
34
+ elapsedMs: number;
35
+ }
36
+ /** The macOS major version at/after which iMessage message EDIT is unsupported (Apple removed it). */
37
+ export declare const BLUEBUBBLES_EDIT_UNSUPPORTED_MACOS_MAJOR = 26;
38
+ /** True when the probed macOS major version no longer supports message edit (≥ 26). */
39
+ export declare function isMacOSEditUnsupported(macOSMajor: number | null | undefined): boolean;
40
+ export interface ProbeBlueBubblesArgs {
41
+ serverUrl: string;
42
+ password: string;
43
+ timeoutMs?: number;
44
+ /** TEST SEAM — inject a mock fetch. */
45
+ fetchImpl?: FetchLike;
46
+ /** Allow private/LAN/loopback hosts through the SSRF guard (default TRUE for BlueBubbles). */
47
+ allowPrivateNetwork?: boolean;
48
+ }
49
+ /** Probe a BlueBubbles server's `server/info`. Never throws. */
50
+ export declare function probeBlueBubbles(args: ProbeBlueBubblesArgs): Promise<BlueBubblesProbeResult>;
51
+ /** Default TTL for a cached probe result (10 min) — long enough to spare repeated sends a round-trip. */
52
+ export declare const BLUEBUBBLES_SERVER_INFO_CACHE_TTL_MS: number;
53
+ /** Cap on the number of distinct accounts held in the cache (LRU-ish; oldest evicted). */
54
+ export declare const BLUEBUBBLES_SERVER_INFO_CACHE_MAX = 64;
55
+ /** Read a non-expired cached probe for an account, or null. */
56
+ export declare function getCachedBlueBubblesProbe(accountId: string, nowMs?: number): BlueBubblesProbeResult | null;
57
+ /** Store a probe result for an account (refreshes its position for the LRU-ish cap). */
58
+ export declare function setCachedBlueBubblesProbe(accountId: string, result: BlueBubblesProbeResult, ttlMs?: number, nowMs?: number): void;
59
+ /** Clear the cache (tests + key rotation). */
60
+ export declare function clearBlueBubblesProbeCache(): void;
61
+ /** Args for a cached probe — a probe plus the account-scope key + TTL/clock seams. */
62
+ export interface ProbeBlueBubblesCachedArgs extends ProbeBlueBubblesArgs {
63
+ /** Cache key — the account id this probe is scoped to. */
64
+ accountId: string;
65
+ /** Override the cache TTL (ms). */
66
+ cacheTtlMs?: number;
67
+ /** Clock seam (tests). */
68
+ now?: () => number;
69
+ }
70
+ /**
71
+ * Probe a BlueBubbles server, served from a per-account TTL cache when fresh.
72
+ * Repeated sends/actions within the TTL reuse the last probe (no extra
73
+ * round-trip). Only a SUCCESSFUL probe (`ok: true`) is cached — a transient
74
+ * failure isn't, so the next call retries the server. Never throws.
75
+ */
76
+ export declare function probeBlueBubblesCached(args: ProbeBlueBubblesCachedArgs): Promise<BlueBubblesProbeResult>;
77
+ /** Parse the macOS major version from a server/info `os_version` (e.g. `"26.1"` → 26). */
78
+ export declare function parseMacOSMajorVersion(osVersion: string | undefined): number | null;
79
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAGN,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACd,MAAM,YAAY,CAAC;AAEpB,yEAAyE;AACzE,MAAM,WAAW,sBAAsB;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uDAAuD;IACvD,UAAU,CAAC,EAAE,qBAAqB,CAAC;IACnC,8EAA8E;IAC9E,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,sGAAsG;AACtG,eAAO,MAAM,wCAAwC,KAAK,CAAC;AAE3D,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAErF;AAED,MAAM,WAAW,oBAAoB;IACpC,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;AAED,gEAAgE;AAChE,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAsDlG;AAID,yGAAyG;AACzG,eAAO,MAAM,oCAAoC,QAAiB,CAAC;AACnE,0FAA0F;AAC1F,eAAO,MAAM,iCAAiC,KAAK,CAAC;AAmBpD,+DAA+D;AAC/D,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAmB,GAAG,sBAAsB,GAAG,IAAI,CAQtH;AAED,wFAAwF;AACxF,wBAAgB,yBAAyB,CACxC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,sBAAsB,EAC9B,KAAK,GAAE,MAA6C,EACpD,KAAK,GAAE,MAAmB,GACxB,IAAI,CAIN;AAED,8CAA8C;AAC9C,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,sFAAsF;AACtF,MAAM,WAAW,0BAA2B,SAAQ,oBAAoB;IACvE,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,0BAA0B,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAO9G;AAED,0FAA0F;AAC1F,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAKnF"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * BlueBubbles probe / doctor.
3
+ *
4
+ * `probeBlueBubbles` does a `GET /api/v1/server/info` round-trip. It NEVER throws
5
+ * — it returns `{ ok, error?, fatal?, serverInfo?, privateApi, elapsedMs }` so
6
+ * `brigade channels status` / `doctor` can render a verdict and the adapter can
7
+ * gate rich actions on the detected Private-API status (and advertise
8
+ * capabilities honestly). `fetch` is injectable (the test seam).
9
+ *
10
+ * - `ok: false` + `fatal: true` → server unreachable / auth rejected (config error).
11
+ * - `ok: true` + `privateApi` → tri-state: true (rich actions live), false
12
+ * (text-only), or null (unknown — server info
13
+ * didn't report it).
14
+ */
15
+ import { blueBubblesFetchWithTimeout, buildBlueBubblesApiUrl, } from "./types.js";
16
+ /** The macOS major version at/after which iMessage message EDIT is unsupported (Apple removed it). */
17
+ export const BLUEBUBBLES_EDIT_UNSUPPORTED_MACOS_MAJOR = 26;
18
+ /** True when the probed macOS major version no longer supports message edit (≥ 26). */
19
+ export function isMacOSEditUnsupported(macOSMajor) {
20
+ return typeof macOSMajor === "number" && macOSMajor >= BLUEBUBBLES_EDIT_UNSUPPORTED_MACOS_MAJOR;
21
+ }
22
+ /** Probe a BlueBubbles server's `server/info`. Never throws. */
23
+ export async function probeBlueBubbles(args) {
24
+ const start = Date.now();
25
+ if (!args.serverUrl.trim()) {
26
+ return { ok: false, error: "BlueBubbles serverUrl is not configured", fatal: true, privateApi: null, macOSMajor: null, elapsedMs: 0 };
27
+ }
28
+ let url;
29
+ try {
30
+ url = buildBlueBubblesApiUrl({ serverUrl: args.serverUrl, path: "server/info", password: args.password });
31
+ }
32
+ catch (err) {
33
+ return {
34
+ ok: false,
35
+ error: err instanceof Error ? err.message : String(err),
36
+ fatal: true,
37
+ privateApi: null,
38
+ macOSMajor: null,
39
+ elapsedMs: Date.now() - start,
40
+ };
41
+ }
42
+ try {
43
+ const res = await blueBubblesFetchWithTimeout(url, { method: "GET" }, { ...(args.timeoutMs !== undefined ? { timeoutMs: args.timeoutMs } : {}), ...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}), ...(args.allowPrivateNetwork === false ? { allowPrivateNetwork: false } : {}) });
44
+ const elapsedMs = Date.now() - start;
45
+ if (res.status === 401 || res.status === 403) {
46
+ return { ok: false, error: "BlueBubbles rejected the password (401/403)", fatal: true, privateApi: null, macOSMajor: null, elapsedMs };
47
+ }
48
+ if (!res.ok) {
49
+ return { ok: false, error: `BlueBubbles server/info returned HTTP ${res.status}`, fatal: false, privateApi: null, macOSMajor: null, elapsedMs };
50
+ }
51
+ let serverInfo;
52
+ try {
53
+ const text = await res.text();
54
+ const body = text ? JSON.parse(text) : {};
55
+ const data = body.data;
56
+ if (data && typeof data === "object")
57
+ serverInfo = data;
58
+ }
59
+ catch {
60
+ serverInfo = undefined;
61
+ }
62
+ const privateApi = serverInfo && typeof serverInfo.private_api === "boolean" ? serverInfo.private_api : null;
63
+ const macOSMajor = parseMacOSMajorVersion(serverInfo?.os_version);
64
+ return { ok: true, ...(serverInfo ? { serverInfo } : {}), privateApi, macOSMajor, elapsedMs };
65
+ }
66
+ catch (err) {
67
+ return {
68
+ ok: false,
69
+ error: err instanceof Error ? err.message : String(err),
70
+ fatal: false,
71
+ privateApi: null,
72
+ macOSMajor: null,
73
+ elapsedMs: Date.now() - start,
74
+ };
75
+ }
76
+ }
77
+ /* ───────────────────────── server-info cache ───────────────────────── */
78
+ /** Default TTL for a cached probe result (10 min) — long enough to spare repeated sends a round-trip. */
79
+ export const BLUEBUBBLES_SERVER_INFO_CACHE_TTL_MS = 10 * 60 * 1000;
80
+ /** Cap on the number of distinct accounts held in the cache (LRU-ish; oldest evicted). */
81
+ export const BLUEBUBBLES_SERVER_INFO_CACHE_MAX = 64;
82
+ /** Module-level per-account cache of the last successful probe. */
83
+ const serverInfoCache = new Map();
84
+ /** Evict the oldest entry when over the cap (Map preserves insertion order). */
85
+ function evictIfOver() {
86
+ while (serverInfoCache.size > BLUEBUBBLES_SERVER_INFO_CACHE_MAX) {
87
+ const oldest = serverInfoCache.keys().next().value;
88
+ if (oldest === undefined)
89
+ break;
90
+ serverInfoCache.delete(oldest);
91
+ }
92
+ }
93
+ /** Read a non-expired cached probe for an account, or null. */
94
+ export function getCachedBlueBubblesProbe(accountId, nowMs = Date.now()) {
95
+ const hit = serverInfoCache.get(accountId);
96
+ if (!hit)
97
+ return null;
98
+ if (hit.expiresAt <= nowMs) {
99
+ serverInfoCache.delete(accountId);
100
+ return null;
101
+ }
102
+ return hit.result;
103
+ }
104
+ /** Store a probe result for an account (refreshes its position for the LRU-ish cap). */
105
+ export function setCachedBlueBubblesProbe(accountId, result, ttlMs = BLUEBUBBLES_SERVER_INFO_CACHE_TTL_MS, nowMs = Date.now()) {
106
+ serverInfoCache.delete(accountId); // refresh insertion order
107
+ serverInfoCache.set(accountId, { result, expiresAt: nowMs + ttlMs });
108
+ evictIfOver();
109
+ }
110
+ /** Clear the cache (tests + key rotation). */
111
+ export function clearBlueBubblesProbeCache() {
112
+ serverInfoCache.clear();
113
+ }
114
+ /**
115
+ * Probe a BlueBubbles server, served from a per-account TTL cache when fresh.
116
+ * Repeated sends/actions within the TTL reuse the last probe (no extra
117
+ * round-trip). Only a SUCCESSFUL probe (`ok: true`) is cached — a transient
118
+ * failure isn't, so the next call retries the server. Never throws.
119
+ */
120
+ export async function probeBlueBubblesCached(args) {
121
+ const nowMs = (args.now ?? Date.now)();
122
+ const cached = getCachedBlueBubblesProbe(args.accountId, nowMs);
123
+ if (cached)
124
+ return cached;
125
+ const result = await probeBlueBubbles(args);
126
+ if (result.ok)
127
+ setCachedBlueBubblesProbe(args.accountId, result, args.cacheTtlMs ?? BLUEBUBBLES_SERVER_INFO_CACHE_TTL_MS, nowMs);
128
+ return result;
129
+ }
130
+ /** Parse the macOS major version from a server/info `os_version` (e.g. `"26.1"` → 26). */
131
+ export function parseMacOSMajorVersion(osVersion) {
132
+ const m = /^(\d+)/.exec((osVersion ?? "").trim());
133
+ if (!m || !m[1])
134
+ return null;
135
+ const n = Number.parseInt(m[1], 10);
136
+ return Number.isFinite(n) ? n : null;
137
+ }
138
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/probe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * BlueBubbles tapback / reaction maps.
3
+ *
4
+ * iMessage "tapbacks" are the six canonical reactions. They cross the wire two
5
+ * different ways:
6
+ *
7
+ * OUTBOUND — the Private-API `message/react` endpoint takes a TYPE NAME string
8
+ * (`"love"`, `"like"`, …), with a leading `-` to REMOVE
9
+ * (`"-love"`). `normalizeBlueBubblesReaction` resolves any input — a type name,
10
+ * a common alias, or an emoji glyph — to that wire string.
11
+ *
12
+ * INBOUND — a tapback arrives as a MESSAGE whose `associatedMessageType` is a
13
+ * numeric code: `2000-2005` = ADD, `3000-3005` = REMOVE, in the canonical order
14
+ * love/like/dislike/laugh/emphasize/question. `decodeTapbackType` maps that
15
+ * code to `{ emoji, action }` so the inbound path can DROP the tapback as a
16
+ * normal message and (optionally) surface it as a reaction note.
17
+ */
18
+ /** The six canonical iMessage tapback types. */
19
+ export type BlueBubblesReactionType = "love" | "like" | "dislike" | "laugh" | "emphasize" | "question";
20
+ /**
21
+ * Resolve any reaction input to the BlueBubbles wire string for `message/react`.
22
+ * A leading `-` (e.g. `"-love"`) or the words `remove`/`removed` mark a REMOVAL.
23
+ * Returns null when the input doesn't map to a known tapback.
24
+ */
25
+ export declare function normalizeBlueBubblesReaction(raw: string): string | null;
26
+ /** Resolve a name/alias/emoji to a canonical reaction type (null when unknown). */
27
+ export declare function resolveReactionType(raw: string): BlueBubblesReactionType | null;
28
+ /** The decoded inbound tapback: which emoji, and add vs remove. */
29
+ export interface DecodedTapback {
30
+ type: BlueBubblesReactionType;
31
+ emoji: string;
32
+ action: "added" | "removed";
33
+ }
34
+ /**
35
+ * Decode an inbound `associatedMessageType` numeric code into a tapback. Codes
36
+ * `2000-2005` are ADD; `3000-3005` are REMOVE; the low digit selects the type in
37
+ * canonical order. Returns null for any non-tapback type.
38
+ */
39
+ export declare function decodeTapbackType(associatedMessageType: number | undefined): DecodedTapback | null;
40
+ /**
41
+ * True iff an `associatedMessageType` is in the tapback range at all (2000-3999).
42
+ * Used to DROP a tapback-as-message so it isn't replied to as normal text and so
43
+ * a reaction-association isn't mistaken for a reply target.
44
+ */
45
+ export declare function isTapbackAssociatedType(associatedMessageType: number | undefined): boolean;
46
+ //# sourceMappingURL=reactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactions.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/reactions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,gDAAgD;AAChD,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;AAsHvG;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiBvE;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAS/E;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,uBAAuB,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,qBAAqB,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,IAAI,CAgBlG;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,qBAAqB,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAO1F"}