@spinabot/brigade 1.1.0 → 1.2.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 (139) hide show
  1. package/convex/channels.d.ts +5 -5
  2. package/convex/schema.d.ts +2 -2
  3. package/dist/agents/agent-loop.d.ts.map +1 -1
  4. package/dist/agents/agent-loop.js +27 -4
  5. package/dist/agents/agent-loop.js.map +1 -1
  6. package/dist/agents/channels/approval-callback-codec.d.ts +107 -0
  7. package/dist/agents/channels/approval-callback-codec.d.ts.map +1 -0
  8. package/dist/agents/channels/approval-callback-codec.js +173 -0
  9. package/dist/agents/channels/approval-callback-codec.js.map +1 -0
  10. package/dist/agents/channels/approval-router.d.ts +77 -20
  11. package/dist/agents/channels/approval-router.d.ts.map +1 -1
  12. package/dist/agents/channels/approval-router.js +163 -37
  13. package/dist/agents/channels/approval-router.js.map +1 -1
  14. package/dist/agents/channels/backoff.d.ts +55 -0
  15. package/dist/agents/channels/backoff.d.ts.map +1 -0
  16. package/dist/agents/channels/backoff.js +47 -0
  17. package/dist/agents/channels/backoff.js.map +1 -0
  18. package/dist/agents/channels/channel-secrets.d.ts +45 -0
  19. package/dist/agents/channels/channel-secrets.d.ts.map +1 -0
  20. package/dist/agents/channels/channel-secrets.js +69 -0
  21. package/dist/agents/channels/channel-secrets.js.map +1 -0
  22. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  23. package/dist/agents/channels/inbound-pipeline.js +67 -3
  24. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  25. package/dist/agents/channels/last-sent-message.d.ts +46 -0
  26. package/dist/agents/channels/last-sent-message.d.ts.map +1 -0
  27. package/dist/agents/channels/last-sent-message.js +55 -0
  28. package/dist/agents/channels/last-sent-message.js.map +1 -0
  29. package/dist/agents/channels/manager.d.ts +52 -0
  30. package/dist/agents/channels/manager.d.ts.map +1 -1
  31. package/dist/agents/channels/manager.js +141 -31
  32. package/dist/agents/channels/manager.js.map +1 -1
  33. package/dist/agents/channels/plugin-channel-manager-facade.d.ts +13 -2
  34. package/dist/agents/channels/plugin-channel-manager-facade.d.ts.map +1 -1
  35. package/dist/agents/channels/plugin-channel-manager-facade.js +21 -0
  36. package/dist/agents/channels/plugin-channel-manager-facade.js.map +1 -1
  37. package/dist/agents/channels/sdk.d.ts +426 -0
  38. package/dist/agents/channels/sdk.d.ts.map +1 -0
  39. package/dist/agents/channels/sdk.js +274 -0
  40. package/dist/agents/channels/sdk.js.map +1 -0
  41. package/dist/agents/channels/telegram/account-config.d.ts +92 -0
  42. package/dist/agents/channels/telegram/account-config.d.ts.map +1 -0
  43. package/dist/agents/channels/telegram/account-config.js +192 -0
  44. package/dist/agents/channels/telegram/account-config.js.map +1 -0
  45. package/dist/agents/channels/telegram/adapter.d.ts +79 -0
  46. package/dist/agents/channels/telegram/adapter.d.ts.map +1 -0
  47. package/dist/agents/channels/telegram/adapter.js +475 -0
  48. package/dist/agents/channels/telegram/adapter.js.map +1 -0
  49. package/dist/agents/channels/telegram/allowed-updates.d.ts +44 -0
  50. package/dist/agents/channels/telegram/allowed-updates.d.ts.map +1 -0
  51. package/dist/agents/channels/telegram/allowed-updates.js +52 -0
  52. package/dist/agents/channels/telegram/allowed-updates.js.map +1 -0
  53. package/dist/agents/channels/telegram/approval-authorize.d.ts +41 -0
  54. package/dist/agents/channels/telegram/approval-authorize.d.ts.map +1 -0
  55. package/dist/agents/channels/telegram/approval-authorize.js +69 -0
  56. package/dist/agents/channels/telegram/approval-authorize.js.map +1 -0
  57. package/dist/agents/channels/telegram/approval-native.d.ts +68 -0
  58. package/dist/agents/channels/telegram/approval-native.d.ts.map +1 -0
  59. package/dist/agents/channels/telegram/approval-native.js +94 -0
  60. package/dist/agents/channels/telegram/approval-native.js.map +1 -0
  61. package/dist/agents/channels/telegram/command-menu.d.ts +35 -0
  62. package/dist/agents/channels/telegram/command-menu.d.ts.map +1 -0
  63. package/dist/agents/channels/telegram/command-menu.js +59 -0
  64. package/dist/agents/channels/telegram/command-menu.js.map +1 -0
  65. package/dist/agents/channels/telegram/connection.d.ts +359 -0
  66. package/dist/agents/channels/telegram/connection.d.ts.map +1 -0
  67. package/dist/agents/channels/telegram/connection.js +865 -0
  68. package/dist/agents/channels/telegram/connection.js.map +1 -0
  69. package/dist/agents/channels/telegram/format.d.ts +48 -0
  70. package/dist/agents/channels/telegram/format.d.ts.map +1 -0
  71. package/dist/agents/channels/telegram/format.js +256 -0
  72. package/dist/agents/channels/telegram/format.js.map +1 -0
  73. package/dist/agents/channels/telegram/inbound-extras.d.ts +73 -0
  74. package/dist/agents/channels/telegram/inbound-extras.d.ts.map +1 -0
  75. package/dist/agents/channels/telegram/inbound-extras.js +231 -0
  76. package/dist/agents/channels/telegram/inbound-extras.js.map +1 -0
  77. package/dist/agents/channels/telegram/index.d.ts +14 -0
  78. package/dist/agents/channels/telegram/index.d.ts.map +1 -0
  79. package/dist/agents/channels/telegram/index.js +14 -0
  80. package/dist/agents/channels/telegram/index.js.map +1 -0
  81. package/dist/agents/channels/telegram/media.d.ts +68 -0
  82. package/dist/agents/channels/telegram/media.d.ts.map +1 -0
  83. package/dist/agents/channels/telegram/media.js +143 -0
  84. package/dist/agents/channels/telegram/media.js.map +1 -0
  85. package/dist/agents/channels/telegram/module.d.ts +15 -0
  86. package/dist/agents/channels/telegram/module.d.ts.map +1 -0
  87. package/dist/agents/channels/telegram/module.js +36 -0
  88. package/dist/agents/channels/telegram/module.js.map +1 -0
  89. package/dist/agents/channels/telegram/plugin.d.ts +76 -0
  90. package/dist/agents/channels/telegram/plugin.d.ts.map +1 -0
  91. package/dist/agents/channels/telegram/plugin.js +314 -0
  92. package/dist/agents/channels/telegram/plugin.js.map +1 -0
  93. package/dist/agents/channels/telegram/probe.d.ts +54 -0
  94. package/dist/agents/channels/telegram/probe.d.ts.map +1 -0
  95. package/dist/agents/channels/telegram/probe.js +95 -0
  96. package/dist/agents/channels/telegram/probe.js.map +1 -0
  97. package/dist/agents/channels/telegram/webhook.d.ts +55 -0
  98. package/dist/agents/channels/telegram/webhook.d.ts.map +1 -0
  99. package/dist/agents/channels/telegram/webhook.js +141 -0
  100. package/dist/agents/channels/telegram/webhook.js.map +1 -0
  101. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  102. package/dist/agents/extensions/modules/index.js +4 -0
  103. package/dist/agents/extensions/modules/index.js.map +1 -1
  104. package/dist/agents/extensions/types.d.ts +72 -2
  105. package/dist/agents/extensions/types.d.ts.map +1 -1
  106. package/dist/agents/extensions/types.js.map +1 -1
  107. package/dist/agents/tools/connect-channel-tool.d.ts +86 -0
  108. package/dist/agents/tools/connect-channel-tool.d.ts.map +1 -0
  109. package/dist/agents/tools/connect-channel-tool.js +398 -0
  110. package/dist/agents/tools/connect-channel-tool.js.map +1 -0
  111. package/dist/agents/tools/message-action-tool.d.ts +67 -0
  112. package/dist/agents/tools/message-action-tool.d.ts.map +1 -0
  113. package/dist/agents/tools/message-action-tool.js +216 -0
  114. package/dist/agents/tools/message-action-tool.js.map +1 -0
  115. package/dist/agents/tools/registry.d.ts.map +1 -1
  116. package/dist/agents/tools/registry.js +19 -0
  117. package/dist/agents/tools/registry.js.map +1 -1
  118. package/dist/buildstamp.json +1 -1
  119. package/dist/cli/commands/channels.d.ts.map +1 -1
  120. package/dist/cli/commands/channels.js +27 -2
  121. package/dist/cli/commands/channels.js.map +1 -1
  122. package/dist/core/server.d.ts.map +1 -1
  123. package/dist/core/server.js +77 -27
  124. package/dist/core/server.js.map +1 -1
  125. package/dist/cron/service/state.d.ts +10 -0
  126. package/dist/cron/service/state.d.ts.map +1 -1
  127. package/dist/cron/service/state.js.map +1 -1
  128. package/dist/cron/service/timer.d.ts.map +1 -1
  129. package/dist/cron/service/timer.js +43 -14
  130. package/dist/cron/service/timer.js.map +1 -1
  131. package/dist/cron/session-reaper.d.ts +27 -0
  132. package/dist/cron/session-reaper.d.ts.map +1 -1
  133. package/dist/cron/session-reaper.js +81 -0
  134. package/dist/cron/session-reaper.js.map +1 -1
  135. package/dist/system-prompt/assembler.d.ts +14 -0
  136. package/dist/system-prompt/assembler.d.ts.map +1 -1
  137. package/dist/system-prompt/assembler.js +36 -14
  138. package/dist/system-prompt/assembler.js.map +1 -1
  139. package/package.json +16 -3
@@ -0,0 +1,274 @@
1
+ /**
2
+ * ════════════════════════════════════════════════════════════════════════════
3
+ * Brigade Channel SDK — the COMPLETE surface for authoring a channel
4
+ * ════════════════════════════════════════════════════════════════════════════
5
+ *
6
+ * One import for everything a new channel adapter (Slack, Discord, iMessage, …)
7
+ * needs: the CONTRACT it implements (BOTH the single-account `ChannelAdapter`
8
+ * AND the multi-account `ChannelPlugin`), the SHARED HELPERS every channel
9
+ * reuses (the inbound pipeline, the approval router, the last-channel pin), and
10
+ * the central capabilities (inline-button approvals, message actions, the
11
+ * durable token seal, the webhook HTTP route). The goal is that the NEXT channel
12
+ * — including a multi-account + webhook + native-commands channel like Discord —
13
+ * is built ENTIRELY on this barrel: no reaching across into `whatsapp/`,
14
+ * `../types.*`, `../inbound-pipeline`, `../approval-router`, `../manager`, or
15
+ * `../../extensions/` for a stray type or helper.
16
+ *
17
+ * ──────────────────────────────────────────────────────────────────────────
18
+ * TWO AUTHORING PATHS
19
+ * ──────────────────────────────────────────────────────────────────────────
20
+ *
21
+ * A. SINGLE-ACCOUNT adapter (`ChannelAdapter`) — one live connection per
22
+ * gateway, started by the legacy `startChannels` manager. Simplest path;
23
+ * implement `start/stop/sendText/…` and register via `b.channel(adapter)`.
24
+ *
25
+ * B. MULTI-ACCOUNT plugin (`ChannelPlugin`) — run N accounts of the same
26
+ * channel at once (`channels.<id>.accounts: [{ id, … }, …]`). You implement
27
+ * the sub-adapters (`config`/`gateway`/`outbound`/`security`/`status`/
28
+ * `actions`/`secrets`/`approvalCapability`), partition per-account runtime
29
+ * state in a `Map<accountId, …>`, and drive each account's inbound through
30
+ * the SHARED `runChannelInboundPipeline` so every account carries the
31
+ * identical ACL + debounce + abort + approval surface. Telegram's
32
+ * `plugin.ts` is the reference; mirror it.
33
+ *
34
+ * Most real channels ship BOTH: the `ChannelAdapter` is the per-connection
35
+ * worker, and the `ChannelPlugin` wraps `createXAdapter()` once per account.
36
+ *
37
+ * ──────────────────────────────────────────────────────────────────────────
38
+ * HOW TO AUTHOR A CHANNEL — the 8-file skeleton
39
+ * ──────────────────────────────────────────────────────────────────────────
40
+ *
41
+ * Mirror the `telegram/` layout (the reference token-based channel):
42
+ *
43
+ * channels/<id>/
44
+ * ├─ module.ts register: `defineModule({ id, register(b){ b.channel(createXAdapter()) } })`
45
+ * ├─ adapter.ts implement `ChannelAdapter` (id/label/start/stop/sendText/…)
46
+ * ├─ plugin.ts implement `ChannelPlugin` (multi-account: config/gateway/outbound/…)
47
+ * ├─ connection.ts the live transport (lazy-import the heavy SDK here)
48
+ * ├─ account-config.ts resolve per-account config + token (see secret seal below)
49
+ * ├─ format.ts markdown → the channel's native markup
50
+ * ├─ inbound-extras.ts normalize provider payloads → `InboundMessage` fields
51
+ * ├─ command-menu.ts map `buildBundledCommands(adapter)` → native `/`-menu (optional)
52
+ * ├─ webhook.ts build the inbound `HttpRoute` for push transport (optional)
53
+ * ├─ media.ts in/out media (run `validateOutboundMediaPath` on send)
54
+ * └─ index.ts re-export the public surface
55
+ *
56
+ * plus tests alongside each (`*.test.ts`).
57
+ *
58
+ * ──────────────────────────────────────────────────────────────────────────
59
+ * REGISTRATION
60
+ * ──────────────────────────────────────────────────────────────────────────
61
+ *
62
+ * 1. `module.ts` calls `b.channel(createXAdapter())` inside `defineModule`.
63
+ * 2. Add the module to the bundled module list (`extensions/modules/index.ts`).
64
+ * 3. Account config lives under `~/.brigade/channels/<id>/<accountId>/`.
65
+ * 4. Lazy-import the heavy transport SDK inside `connection.ts` (Baileys /
66
+ * grammY style) so a non-X boot never pays for it.
67
+ * 5. Implement reconnect with `nextBackoffDelay({ attempt, initialMs, maxMs,
68
+ * factor, jitter })` (do NOT hand-roll the curve) + a capped attempt count.
69
+ * 6. Run inbound through dedupe (`createDedupeCache`) and outbound media
70
+ * through `validateOutboundMediaPath` before uploading bytes.
71
+ *
72
+ * ──────────────────────────────────────────────────────────────────────────
73
+ * MULTI-ACCOUNT PLUGIN PATH (`ChannelPlugin`)
74
+ * ──────────────────────────────────────────────────────────────────────────
75
+ *
76
+ * 1. Declare `id` / `meta` / `capabilities` / `config` (required) plus the
77
+ * sub-adapters you support (`gateway`/`outbound`/`security`/`status`/
78
+ * `actions`/`secrets`/`approvalCapability`). Omit a slot to opt out; the
79
+ * manager pre-checks `capabilities.<flag>` before calling an adapter.
80
+ * 2. `config.listAccountIds(cfg)` + `config.resolveAccount(cfg, id)` drive
81
+ * multi-account discovery. Make the legacy single-account `ChannelAdapter`
82
+ * STEP ASIDE when >1 account is configured (its `isConfigured` returns
83
+ * false for the default account) so the two paths never double-start.
84
+ * 3. In `gateway.startAccount`, build a per-account pipeline with
85
+ * `createInboundPipelineContext({ adapter, config, agentId, runTurn,
86
+ * commandMap, parentAbort })` and feed each inbound through
87
+ * `runChannelInboundPipeline(pipeline, msg)` (stamp `msg.accountId`).
88
+ * Build the command map from `buildBundledCommands(adapter)`.
89
+ * 4. Register a PER-ACCOUNT approval dispatcher with
90
+ * `registerChannelApprovalDispatcher(channelId, accountId, dispatcher)` on
91
+ * start and `removeChannelApprovalDispatcher(channelId, accountId)` on stop,
92
+ * so an exec-gate prompt raised by a turn on (channel, accountId) replies on
93
+ * that same account — not the channel default.
94
+ * 5. Take `runTurn` from the gateway via `StartChannelsArgs["runTurn"]`.
95
+ *
96
+ * ──────────────────────────────────────────────────────────────────────────
97
+ * WEBHOOK / PUSH TRANSPORT (`HttpRoute`)
98
+ * ──────────────────────────────────────────────────────────────────────────
99
+ *
100
+ * For channels that receive updates via an inbound POST (Telegram webhook
101
+ * mode, Slack Events API, …) instead of long-polling:
102
+ * • Build an `HttpRoute` (the `HttpRoute` type is re-exported here) whose
103
+ * handler verifies the provider's signature / secret header FIRST (before
104
+ * parsing the body), then feeds the parsed update into the started
105
+ * adapter's normalize+dedupe+dispatch path.
106
+ * • Register it from `module.ts` via `b.httpRoute(route)`, gated on config so
107
+ * a default polling install exposes NO inbound HTTP surface.
108
+ * • Set `auth: "none"` ONLY when the provider authenticates via a signed
109
+ * payload the handler verifies itself (the gateway can't present operator-
110
+ * auth to a third-party webhook); otherwise use `auth: "operator"`.
111
+ *
112
+ * ──────────────────────────────────────────────────────────────────────────
113
+ * NATIVE COMMAND MENU
114
+ * ──────────────────────────────────────────────────────────────────────────
115
+ *
116
+ * Brigade owns the channel command set centrally (`buildBundledCommands(adapter)`
117
+ * → `/help`, `/status`, `/allowlist`, `/agent`, `/agents`, `/whoami`, `/org`,
118
+ * plus module-registered `ChannelCommand`s). A channel with a native `/`-menu
119
+ * (Telegram `setMyCommands`, Discord application commands) maps that set onto
120
+ * the provider's shape on connect — see `telegram/command-menu.ts`. Advertise
121
+ * `capabilities.nativeCommands: true`.
122
+ *
123
+ * ──────────────────────────────────────────────────────────────────────────
124
+ * OPTING INTO CENTRAL CAPABILITIES
125
+ * ──────────────────────────────────────────────────────────────────────────
126
+ *
127
+ * • Inline-button approvals: set `adapter.approvalCapability.sendApprovalPrompt`
128
+ * (render `buildApprovalCallbackButtons(approvalId)` as native buttons whose
129
+ * `callback_data` is each button's `.data`). Deliver the press back as
130
+ * `InboundMessage.callbackQuery` — the central pipeline decodes + resolves
131
+ * it. Add `authorizeApprover` to refuse non-operator pressers.
132
+ * • Message actions (edit / delete / react / pin): implement
133
+ * `adapter.handleAction(...)` and advertise the matching `capabilities`
134
+ * flags (`edit` / `unsend` / `reactions` / `reply`). The central
135
+ * `message_action` tool pre-checks the flag before calling you.
136
+ * • Outbound id: return `{ messageId }` from `sendText`/`sendMedia` so the
137
+ * agent can reference "my last message" via `message_action`.
138
+ * • Durable token: `connect_channel` seals tokens via `sealChannelToken`;
139
+ * read yours back at start with `readSealedChannelToken("<id>")` as a token
140
+ * source (survives a gateway reboot when the live env is gone).
141
+ *
142
+ * ──────────────────────────────────────────────────────────────────────────
143
+ * ENUMERATION TESTS TO UPDATE when you add a channel-related agent tool
144
+ * ──────────────────────────────────────────────────────────────────────────
145
+ *
146
+ * • `agents/tools/registry.test.ts` — the sorted tool-name list + count
147
+ * • `agents/session-wiring.test.ts` — the brigade-tool list + counts
148
+ * • `agents/tools/owner-only.test.ts` — the customTools count + name list
149
+ *
150
+ * ──────────────────────────────────────────────────────────────────────────
151
+ * DESIGN NOTE — RE-EXPORT, never RELOCATE
152
+ * ──────────────────────────────────────────────────────────────────────────
153
+ *
154
+ * Helpers like `chunkText` physically live where they were first written
155
+ * (`whatsapp/chunk.js`) and WhatsApp imports them directly. Moving a file would
156
+ * change WhatsApp's import and risk the one channel that works perfectly, so
157
+ * this barrel RE-EXPORTS from where things already are — it has zero runtime
158
+ * behaviour of its own. The codec + the durable-seal + the backoff helper DO
159
+ * live in `channels/` (they are channel-neutral by design) and are re-exported
160
+ * here as the canonical author-facing surface.
161
+ */
162
+ /* ───────────────────────── contract: register ───────────────────────── */
163
+ export {
164
+ /** Register a channel through the extension seam: `defineModule({ id, register(b){ b.channel(adapter) } })`. */
165
+ defineModule, } from "../extensions/types.js";
166
+ /* ───────────────────────── shared helper: outbound chunking ───────────────────────── */
167
+ export {
168
+ /**
169
+ * Split a long outbound message into provider-safe chunks WITHOUT shredding
170
+ * code fences / paragraphs. Lives under `whatsapp/` for history; it is
171
+ * channel-agnostic (Telegram reuses it with `{ limit: 4096 }`). Re-exported
172
+ * here so new channels don't reach across into the WhatsApp folder.
173
+ */
174
+ chunkText, } from "./whatsapp/chunk.js";
175
+ /* ───────────────────────── shared helper: inbound dedupe ───────────────────────── */
176
+ export {
177
+ /** Build a per-channel inbound dedupe cache (claim-once, LRU + TTL). */
178
+ createDedupeCache, } from "./dedupe.js";
179
+ /* ───────────────────────── shared helper: outbound media guard ───────────────────────── */
180
+ export {
181
+ /**
182
+ * Refuse to ATTACH a local secret / system file on outbound media — the
183
+ * content-exfil guard every `sendMedia` path must run before uploading
184
+ * a local path's bytes to a conversation.
185
+ */
186
+ validateOutboundMediaPath, } from "../../security/media-path-guard.js";
187
+ /* ───────────────────────── shared helper: structured logger ───────────────────────── */
188
+ export {
189
+ /** Named JSON subsystem logger — `createSubsystemLogger("channels/<id>")`. */
190
+ createSubsystemLogger, } from "../../logging/subsystem-logger.js";
191
+ /* ───────────────────────── shared helper: reconnect backoff ───────────────────────── */
192
+ export {
193
+ /**
194
+ * Jittered exponential reconnect-delay helper shared by every channel.
195
+ * Pass the schedule ({ attempt, initialMs, maxMs, factor, jitter }); the
196
+ * arithmetic is WhatsApp's proven curve. WhatsApp + Telegram both delegate
197
+ * to it; a new channel should too instead of hand-rolling its own.
198
+ */
199
+ nextBackoffDelay, } from "./backoff.js";
200
+ /* ───────────────────────── central: inline-button approval codec ───────────────────────── */
201
+ export {
202
+ /** Encode `{ approvalId, decision }` into a <=64-byte callback payload (undefined if oversized). */
203
+ encodeApprovalCallback,
204
+ /** Decode a callback payload back to `{ approvalId, decision }` (null if not ours / malformed). */
205
+ decodeApprovalCallback,
206
+ /** True iff a string fits the universal 64-byte callback-data budget. */
207
+ fitsApprovalCallback,
208
+ /** Build the standard Allow once / Allow always / Deny buttons (label + encoded payload). */
209
+ buildApprovalCallbackButtons,
210
+ /** The universal callback-data byte ceiling (Telegram's 64). */
211
+ APPROVAL_CALLBACK_MAX_BYTES, } from "./approval-callback-codec.js";
212
+ /* ───────────────────────── central: durable channel-token seal ───────────────────────── */
213
+ export {
214
+ /** Durably seal a channel's token into the encrypted credential store (survives reboot). */
215
+ sealChannelToken,
216
+ /** Read a channel's durably-sealed token (""→ none) at start time, no agent context needed. */
217
+ readSealedChannelToken,
218
+ /** Provider key a channel's token is sealed under (`channel:<id>`). */
219
+ channelSecretProvider, } from "./channel-secrets.js";
220
+ /* ───────────────────────── pipeline: the shared inbound engine ───────────────────────── */
221
+ export {
222
+ /**
223
+ * Run ONE inbound message end-to-end through the shared pipeline (media + reply
224
+ * note synthesis → access gate → mark-read → approval-callback + approval-reply
225
+ * intercept → abort triggers → channel command → 8-tier route → last-channel pin
226
+ * → optional debounce → dispatchTurn → reply). Never throws. Both the legacy
227
+ * manager and every multi-account plugin call THIS so the safety surface is
228
+ * identical on every channel.
229
+ */
230
+ runChannelInboundPipeline,
231
+ /** Build a fresh per-channel-instance pipeline context (per account on the plugin path). */
232
+ createInboundPipelineContext,
233
+ /**
234
+ * Build the bundled built-in channel commands (`/help`, `/status`, `/allowlist`,
235
+ * `/agent`, `/agents`, `/whoami`, `/org`) an operator can DM to admin the bot.
236
+ * Feed the result into your `commandMap` AND into a native command menu.
237
+ */
238
+ buildBundledCommands,
239
+ /** Disambiguating lane key for inflight + pending maps ((adapter, account, conversation, thread)). */
240
+ laneKey, } from "./inbound-pipeline.js";
241
+ /* ───────────────────────── approvals: the channel approval router ───────────────────────── */
242
+ export {
243
+ /**
244
+ * Register a (per-account) dispatcher so an exec-gate approval prompt raised by
245
+ * a channel-routed turn lands IN that conversation. Pass `(channelId, accountId,
246
+ * dispatcher)` on the multi-account path so each account routes to itself.
247
+ */
248
+ registerChannelApprovalDispatcher,
249
+ /** Drop a channel's (per-account) dispatcher + deny its in-flight prompts on stop. */
250
+ removeChannelApprovalDispatcher,
251
+ /** Send an approval prompt via the channel + register the pending entry (called by the bridge). */
252
+ dispatchChannelApproval,
253
+ /** Intercept a yes/no TEXT reply as the answer to a pending approval for this peer. */
254
+ tryConsumeChannelApprovalReply,
255
+ /** Intercept an inline-BUTTON press (callback_query) as the answer to a pending approval. */
256
+ tryConsumeChannelApprovalCallback,
257
+ /** Cancel a pending approval by request id (e.g. on session abort). */
258
+ cancelChannelApprovalById,
259
+ /** Diagnostic — list registered dispatcher keys. */
260
+ listChannelApprovalDispatchers,
261
+ /** Diagnostic — snapshot of pending channel approvals. */
262
+ listPendingChannelApprovals, } from "./approval-router.js";
263
+ /* ───────────────────────── last-channel: the announce-target pin ───────────────────────── */
264
+ export {
265
+ /**
266
+ * Pin THIS channel as the agent's most-recently-active (called by the pipeline
267
+ * on every admitted inbound). A cron's announce-delivery reads it as the
268
+ * last-resort target when no explicit channel was set. The pipeline already
269
+ * calls this for you; a channel only calls it directly for a bespoke surface.
270
+ */
271
+ recordLastChannelForAgent,
272
+ /** Read the agent's last-recorded channel (undefined when no channel activity yet). */
273
+ getLastChannelForAgent, } from "./last-channel.js";
274
+ //# sourceMappingURL=sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../../src/agents/channels/sdk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgKG;AAEH,4EAA4E;AAE5E,OAAO;AACN,gHAAgH;AAChH,YAAY,GACZ,MAAM,wBAAwB,CAAC;AA+DhC,0FAA0F;AAE1F,OAAO;AACN;;;;;GAKG;AACH,SAAS,GACT,MAAM,qBAAqB,CAAC;AAE7B,uFAAuF;AAEvF,OAAO;AACN,wEAAwE;AACxE,iBAAiB,GACjB,MAAM,aAAa,CAAC;AAGrB,6FAA6F;AAE7F,OAAO;AACN;;;;GAIG;AACH,yBAAyB,GACzB,MAAM,oCAAoC,CAAC;AAG5C,0FAA0F;AAE1F,OAAO;AACN,8EAA8E;AAC9E,qBAAqB,GACrB,MAAM,mCAAmC,CAAC;AAG3C,0FAA0F;AAE1F,OAAO;AACN;;;;;GAKG;AACH,gBAAgB,GAChB,MAAM,cAAc,CAAC;AAGtB,+FAA+F;AAE/F,OAAO;AACN,oGAAoG;AACpG,sBAAsB;AACtB,mGAAmG;AACnG,sBAAsB;AACtB,yEAAyE;AACzE,oBAAoB;AACpB,6FAA6F;AAC7F,4BAA4B;AAC5B,gEAAgE;AAChE,2BAA2B,GAC3B,MAAM,8BAA8B,CAAC;AAQtC,6FAA6F;AAE7F,OAAO;AACN,4FAA4F;AAC5F,gBAAgB;AAChB,+FAA+F;AAC/F,sBAAsB;AACtB,uEAAuE;AACvE,qBAAqB,GACrB,MAAM,sBAAsB,CAAC;AAsF9B,6FAA6F;AAE7F,OAAO;AACN;;;;;;;GAOG;AACH,yBAAyB;AACzB,4FAA4F;AAC5F,4BAA4B;AAC5B;;;;GAIG;AACH,oBAAoB;AACpB,sGAAsG;AACtG,OAAO,GACP,MAAM,uBAAuB,CAAC;AAY/B,gGAAgG;AAEhG,OAAO;AACN;;;;GAIG;AACH,iCAAiC;AACjC,sFAAsF;AACtF,+BAA+B;AAC/B,mGAAmG;AACnG,uBAAuB;AACvB,uFAAuF;AACvF,8BAA8B;AAC9B,6FAA6F;AAC7F,iCAAiC;AACjC,uEAAuE;AACvE,yBAAyB;AACzB,oDAAoD;AACpD,8BAA8B;AAC9B,0DAA0D;AAC1D,2BAA2B,GAC3B,MAAM,sBAAsB,CAAC;AA2B9B,+FAA+F;AAE/F,OAAO;AACN;;;;;GAKG;AACH,yBAAyB;AACzB,uFAAuF;AACvF,sBAAsB,GACtB,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Telegram config-shape helpers (single-account v1; multi-account aware shape).
3
+ *
4
+ * Brigade's Telegram config is TOKEN-based (no QR/OAuth pairing — the operator
5
+ * pastes a Bot API token from @BotFather). Two shapes are recognised so the
6
+ * surface lines up with WhatsApp's `account-config.ts`:
7
+ *
8
+ * Legacy (single-account):
9
+ * channels.telegram = { enabled: true, botToken: "123:ABC", verbose?: boolean }
10
+ *
11
+ * Multi-account (later follow-up — the shape is honoured now, v1 ships one):
12
+ * channels.telegram = {
13
+ * enabled: true,
14
+ * accounts: [
15
+ * { id: "main", botToken: "111:AAA" },
16
+ * { id: "ops", botToken: "222:BBB" },
17
+ * ],
18
+ * }
19
+ *
20
+ * A legacy config with no `accounts[]` reads as `[{ id: "default" }]`.
21
+ *
22
+ * Token resolution: a value of the form `${VAR}` is resolved against
23
+ * `process.env[VAR]` (mirrors Brigade's config secret-ref convention, so a
24
+ * token never has to be committed as a literal). When no token is configured
25
+ * at all, the `TELEGRAM_BOT_TOKEN` environment variable is the last-resort
26
+ * fallback. NOTE: Brigade's config loader already resolves `${VAR}` leaves on
27
+ * read (`resolveSecretsInPlace`), so by the time the adapter reads config the
28
+ * ref is usually already expanded — the explicit resolution here is defensive
29
+ * for callers (CLI/tests) that read raw config and for the env fallback.
30
+ */
31
+ import type { BrigadeConfig } from "../../../config/io.js";
32
+ declare const CHANNEL_ID = "telegram";
33
+ declare const DEFAULT_ACCOUNT_ID = "default";
34
+ /** The env var consulted as a last-resort token fallback. */
35
+ declare const TOKEN_ENV_VAR = "TELEGRAM_BOT_TOKEN";
36
+ /** Resolved per-account info — what the adapter runtime reads. */
37
+ export interface ResolvedTelegramAccount {
38
+ accountId: string;
39
+ enabled: boolean;
40
+ /** Bot API token, fully resolved (`${VAR}` + env fallback applied), or `""` when unset. */
41
+ botToken: string;
42
+ verbose: boolean;
43
+ }
44
+ /** Is the Telegram channel switched on at all (any shape)? */
45
+ export declare function telegramChannelEnabled(cfg: BrigadeConfig): boolean;
46
+ /** List configured account ids. Legacy single-account configs surface `["default"]`. */
47
+ export declare function listTelegramAccountIds(cfg: BrigadeConfig): string[];
48
+ /**
49
+ * Resolve the Bot API token for an account. Precedence:
50
+ * 1. The per-account `botToken` (multi-account shape), `${VAR}`-resolved.
51
+ * 2. The top-level `channels.telegram.botToken` (legacy shape), `${VAR}`-resolved.
52
+ * 3. The DURABLE sealed channel token (written by `connect_channel`) — this is
53
+ * the source that survives a gateway reboot, when the live env + `${VAR}`
54
+ * ref have evaporated.
55
+ * 4. The `TELEGRAM_BOT_TOKEN` env var (last-resort fallback).
56
+ * Returns `""` when no token can be resolved.
57
+ *
58
+ * Note the sealed token is consulted AFTER the config refs: an explicit config
59
+ * `${VAR}` / literal that resolves in THIS process wins (so a live env set by
60
+ * `connect_channel` is used immediately), and the durable seal is the fallback
61
+ * that keeps the channel authenticated across restarts.
62
+ */
63
+ export declare function resolveTelegramBotToken(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
64
+ /** Resolve a per-account view of the config (defaults + token resolution filled in). */
65
+ export declare function resolveTelegramAccount(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): ResolvedTelegramAccount;
66
+ /** Resolved Telegram transport config (mode + webhook details). */
67
+ export interface TelegramWebhookConfig {
68
+ /** `"polling"` (default) or `"webhook"`. */
69
+ mode: "polling" | "webhook";
70
+ /** Public base URL Telegram POSTs to (webhook mode). `""` when unset. */
71
+ url: string;
72
+ /** Gateway route path (default `/telegram/webhook`). */
73
+ path: string;
74
+ /** Secret token verified on the inbound webhook header. `""` when unset. */
75
+ secretToken: string;
76
+ }
77
+ /**
78
+ * Resolve the Telegram transport config. Defaults to `polling` (Brigade is
79
+ * local-first); `webhook` is opt-in via `channels.telegram.mode: "webhook"`.
80
+ * `${VAR}` refs in the secret token are env-resolved (it's a secret).
81
+ */
82
+ export declare function telegramWebhookConfig(cfg: BrigadeConfig, env?: NodeJS.ProcessEnv): TelegramWebhookConfig;
83
+ /** True when forum-topic auto-labeling is enabled (`channels.telegram.autoLabelTopics`). */
84
+ export declare function telegramAutoLabelTopics(cfg: BrigadeConfig): boolean;
85
+ /**
86
+ * Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
87
+ * Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
88
+ * session-reaper uses this to age out idle Telegram thread sessions.
89
+ */
90
+ export declare function telegramThreadIdleTtlMs(cfg: BrigadeConfig): number | null;
91
+ export { CHANNEL_ID as TELEGRAM_CHANNEL_ID, DEFAULT_ACCOUNT_ID as TELEGRAM_DEFAULT_ACCOUNT_ID, TOKEN_ENV_VAR as TELEGRAM_BOT_TOKEN_ENV_VAR, };
92
+ //# sourceMappingURL=account-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-config.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/telegram/account-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,QAAA,MAAM,UAAU,aAAa,CAAC;AAC9B,QAAA,MAAM,kBAAkB,YAAY,CAAC;AAErC,6DAA6D;AAC7D,QAAA,MAAM,aAAa,uBAAuB,CAAC;AAwC3C,kEAAkE;AAClE,MAAM,WAAW,uBAAuB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,2FAA2F;IAC3F,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAqBD,8DAA8D;AAC9D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAElE;AAED,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,EAAE,CAgBnE;AAeD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACtC,GAAG,EAAE,aAAa,EAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,MAAM,CAWR;AAED,wFAAwF;AACxF,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,aAAa,EAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,uBAAuB,CAWzB;AAOD,mEAAmE;AACnE,MAAM,WAAW,qBAAqB;IACrC,4CAA4C;IAC5C,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IAC5B,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACpC,GAAG,EAAE,aAAa,EAClB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,qBAAqB,CAYvB;AAED,4FAA4F;AAC5F,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAczE;AAED,OAAO,EACN,UAAU,IAAI,mBAAmB,EACjC,kBAAkB,IAAI,2BAA2B,EACjD,aAAa,IAAI,0BAA0B,GAC3C,CAAC"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Telegram config-shape helpers (single-account v1; multi-account aware shape).
3
+ *
4
+ * Brigade's Telegram config is TOKEN-based (no QR/OAuth pairing — the operator
5
+ * pastes a Bot API token from @BotFather). Two shapes are recognised so the
6
+ * surface lines up with WhatsApp's `account-config.ts`:
7
+ *
8
+ * Legacy (single-account):
9
+ * channels.telegram = { enabled: true, botToken: "123:ABC", verbose?: boolean }
10
+ *
11
+ * Multi-account (later follow-up — the shape is honoured now, v1 ships one):
12
+ * channels.telegram = {
13
+ * enabled: true,
14
+ * accounts: [
15
+ * { id: "main", botToken: "111:AAA" },
16
+ * { id: "ops", botToken: "222:BBB" },
17
+ * ],
18
+ * }
19
+ *
20
+ * A legacy config with no `accounts[]` reads as `[{ id: "default" }]`.
21
+ *
22
+ * Token resolution: a value of the form `${VAR}` is resolved against
23
+ * `process.env[VAR]` (mirrors Brigade's config secret-ref convention, so a
24
+ * token never has to be committed as a literal). When no token is configured
25
+ * at all, the `TELEGRAM_BOT_TOKEN` environment variable is the last-resort
26
+ * fallback. NOTE: Brigade's config loader already resolves `${VAR}` leaves on
27
+ * read (`resolveSecretsInPlace`), so by the time the adapter reads config the
28
+ * ref is usually already expanded — the explicit resolution here is defensive
29
+ * for callers (CLI/tests) that read raw config and for the env fallback.
30
+ */
31
+ import { readSealedChannelToken } from "../channel-secrets.js";
32
+ const CHANNEL_ID = "telegram";
33
+ const DEFAULT_ACCOUNT_ID = "default";
34
+ /** The env var consulted as a last-resort token fallback. */
35
+ const TOKEN_ENV_VAR = "TELEGRAM_BOT_TOKEN";
36
+ /** `${VAR}` secret-ref form — identical to `config/io.ts`'s SECRET_REF_PATTERN. */
37
+ const SECRET_REF_PATTERN = /^\$\{([A-Z_][A-Z0-9_]*)\}$/;
38
+ /** Read `channels.telegram` loosely (schema keeps it open). */
39
+ function telegramChannelConfig(cfg) {
40
+ return cfg.channels?.[CHANNEL_ID];
41
+ }
42
+ /**
43
+ * Resolve a single token-ish string: a `${VAR}` ref expands against
44
+ * `process.env`; any other non-empty string passes through verbatim; empty /
45
+ * missing returns "".
46
+ */
47
+ function resolveTokenRef(raw, env) {
48
+ if (typeof raw !== "string")
49
+ return "";
50
+ const trimmed = raw.trim();
51
+ if (!trimmed)
52
+ return "";
53
+ const m = SECRET_REF_PATTERN.exec(trimmed);
54
+ if (m && m[1])
55
+ return (env[m[1]] ?? "").trim();
56
+ return trimmed;
57
+ }
58
+ /** Is the Telegram channel switched on at all (any shape)? */
59
+ export function telegramChannelEnabled(cfg) {
60
+ return telegramChannelConfig(cfg)?.enabled === true;
61
+ }
62
+ /** List configured account ids. Legacy single-account configs surface `["default"]`. */
63
+ export function listTelegramAccountIds(cfg) {
64
+ const slot = telegramChannelConfig(cfg);
65
+ if (!slot || slot.enabled !== true)
66
+ return [];
67
+ const accounts = Array.isArray(slot.accounts) ? slot.accounts : undefined;
68
+ if (!accounts || accounts.length === 0)
69
+ return [DEFAULT_ACCOUNT_ID];
70
+ const ids = [];
71
+ const seen = new Set();
72
+ for (const entry of accounts) {
73
+ const id = typeof entry?.id === "string" ? entry.id.trim() : "";
74
+ if (!id || seen.has(id))
75
+ continue;
76
+ seen.add(id);
77
+ ids.push(id);
78
+ }
79
+ // A half-typed `accounts:[]` still degrades to the default account so the
80
+ // channel isn't silently disabled.
81
+ return ids.length === 0 ? [DEFAULT_ACCOUNT_ID] : ids;
82
+ }
83
+ /** Look up the raw account entry from config (or null when missing). */
84
+ function findAccountEntry(cfg, accountId) {
85
+ const slot = telegramChannelConfig(cfg);
86
+ if (!slot)
87
+ return null;
88
+ const accounts = Array.isArray(slot.accounts) ? slot.accounts : undefined;
89
+ if (!accounts)
90
+ return null;
91
+ for (const entry of accounts) {
92
+ const id = typeof entry?.id === "string" ? entry.id.trim() : "";
93
+ if (id === accountId)
94
+ return entry;
95
+ }
96
+ return null;
97
+ }
98
+ /**
99
+ * Resolve the Bot API token for an account. Precedence:
100
+ * 1. The per-account `botToken` (multi-account shape), `${VAR}`-resolved.
101
+ * 2. The top-level `channels.telegram.botToken` (legacy shape), `${VAR}`-resolved.
102
+ * 3. The DURABLE sealed channel token (written by `connect_channel`) — this is
103
+ * the source that survives a gateway reboot, when the live env + `${VAR}`
104
+ * ref have evaporated.
105
+ * 4. The `TELEGRAM_BOT_TOKEN` env var (last-resort fallback).
106
+ * Returns `""` when no token can be resolved.
107
+ *
108
+ * Note the sealed token is consulted AFTER the config refs: an explicit config
109
+ * `${VAR}` / literal that resolves in THIS process wins (so a live env set by
110
+ * `connect_channel` is used immediately), and the durable seal is the fallback
111
+ * that keeps the channel authenticated across restarts.
112
+ */
113
+ export function resolveTelegramBotToken(cfg, accountId, env = process.env) {
114
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
115
+ const slot = telegramChannelConfig(cfg);
116
+ const entry = findAccountEntry(cfg, id);
117
+ const perAccount = resolveTokenRef(entry?.botToken, env);
118
+ if (perAccount)
119
+ return perAccount;
120
+ const topLevel = resolveTokenRef(slot?.botToken, env);
121
+ if (topLevel)
122
+ return topLevel;
123
+ const sealed = readSealedChannelToken(CHANNEL_ID);
124
+ if (sealed)
125
+ return sealed;
126
+ return (env[TOKEN_ENV_VAR] ?? "").trim();
127
+ }
128
+ /** Resolve a per-account view of the config (defaults + token resolution filled in). */
129
+ export function resolveTelegramAccount(cfg, accountId, env = process.env) {
130
+ const slot = telegramChannelConfig(cfg);
131
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
132
+ const entry = findAccountEntry(cfg, id);
133
+ const enabled = entry?.enabled !== false && slot?.enabled === true;
134
+ return {
135
+ accountId: id,
136
+ enabled,
137
+ botToken: resolveTelegramBotToken(cfg, id, env),
138
+ verbose: slot?.verbose === true,
139
+ };
140
+ }
141
+ /* ───────────────────────── transport / lifecycle config ───────────────────────── */
142
+ /** Default gateway path the webhook transport registers + points `setWebhook` at. */
143
+ const DEFAULT_WEBHOOK_PATH = "/telegram/webhook";
144
+ /**
145
+ * Resolve the Telegram transport config. Defaults to `polling` (Brigade is
146
+ * local-first); `webhook` is opt-in via `channels.telegram.mode: "webhook"`.
147
+ * `${VAR}` refs in the secret token are env-resolved (it's a secret).
148
+ */
149
+ export function telegramWebhookConfig(cfg, env = process.env) {
150
+ const slot = telegramChannelConfig(cfg);
151
+ const rawMode = typeof slot?.mode === "string" ? slot.mode.trim().toLowerCase() : "";
152
+ const mode = rawMode === "webhook" ? "webhook" : "polling";
153
+ const wh = slot?.webhook ?? {};
154
+ const path = typeof wh.path === "string" && wh.path.trim() ? wh.path.trim() : DEFAULT_WEBHOOK_PATH;
155
+ return {
156
+ mode,
157
+ url: typeof wh.url === "string" ? wh.url.trim() : "",
158
+ path: path.startsWith("/") ? path : `/${path}`,
159
+ secretToken: resolveTokenRef(wh.secretToken, env),
160
+ };
161
+ }
162
+ /** True when forum-topic auto-labeling is enabled (`channels.telegram.autoLabelTopics`). */
163
+ export function telegramAutoLabelTopics(cfg) {
164
+ return telegramChannelConfig(cfg)?.autoLabelTopics === true;
165
+ }
166
+ /**
167
+ * Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
168
+ * Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
169
+ * session-reaper uses this to age out idle Telegram thread sessions.
170
+ */
171
+ export function telegramThreadIdleTtlMs(cfg) {
172
+ const raw = telegramChannelConfig(cfg)?.threadIdleTtlMs;
173
+ if (typeof raw === "number")
174
+ return raw > 0 ? raw : null;
175
+ if (typeof raw !== "string")
176
+ return null;
177
+ const trimmed = raw.trim();
178
+ if (!trimmed)
179
+ return null;
180
+ const m = /^(\d+)\s*(s|m|h|d|w)?$/i.exec(trimmed);
181
+ if (!m)
182
+ return null;
183
+ const n = Number(m[1]);
184
+ if (!Number.isFinite(n) || n <= 0)
185
+ return null;
186
+ const unit = (m[2] ?? "ms").toLowerCase();
187
+ const mult = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000, ms: 1 };
188
+ const factor = mult[unit] ?? 1;
189
+ return n * factor;
190
+ }
191
+ export { CHANNEL_ID as TELEGRAM_CHANNEL_ID, DEFAULT_ACCOUNT_ID as TELEGRAM_DEFAULT_ACCOUNT_ID, TOKEN_ENV_VAR as TELEGRAM_BOT_TOKEN_ENV_VAR, };
192
+ //# sourceMappingURL=account-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-config.js","sourceRoot":"","sources":["../../../../src/agents/channels/telegram/account-config.ts"],"names":[],"mappings":"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"}