@s0nderlabs/anima-plugin-telegram 0.24.11 → 0.24.13

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@s0nderlabs/anima-plugin-telegram",
3
- "version": "0.24.11",
3
+ "version": "0.24.13",
4
4
  "type": "module",
5
5
  "description": "Telegram gateway plugin for anima — long-poll bot, debounced dispatch, reactions, allowlist",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "test": "bun test"
40
40
  },
41
41
  "dependencies": {
42
- "@s0nderlabs/anima-core": "0.24.11",
42
+ "@s0nderlabs/anima-core": "0.24.13",
43
43
  "grammy": "^1.42.0",
44
44
  "zod": "^3.23.8"
45
45
  }
package/src/listener.ts CHANGED
@@ -237,6 +237,14 @@ export class TelegramListener {
237
237
  this.installCallbackHandler(handler)
238
238
  }
239
239
 
240
+ // v0.24.12: operator-notifier slot. Gateway fills it with brain clarify
241
+ // questions on autonomous market wakes; we broadcast to every allowed
242
+ // chat so the operator sees the question on their phone when no TUI is
243
+ // attached.
244
+ if (this.opts.operatorNotifier) {
245
+ this.opts.operatorNotifier.current = text => this.notifyOperators(text)
246
+ }
247
+
240
248
  await clearWebhookBeforePolling(this.bot)
241
249
 
242
250
  // v0.20.0: register the bot command menu so Telegram clients show
@@ -279,6 +287,7 @@ export class TelegramListener {
279
287
  clearTimeout(this.retryTimer)
280
288
  this.retryTimer = null
281
289
  }
290
+ if (this.opts.operatorNotifier) this.opts.operatorNotifier.current = null
282
291
  if (!this.running) {
283
292
  this.releaseLock()
284
293
  return
@@ -298,6 +307,30 @@ export class TelegramListener {
298
307
  this.releaseLock()
299
308
  }
300
309
 
310
+ /**
311
+ * v0.24.12: broadcast a short text to every allowed operator chat. Used
312
+ * by the gateway to forward unsolicited brain prompts (clarify on
313
+ * autonomous market wakes) when no TUI is connected. Best-effort: per-chat
314
+ * failures are logged but don't stop the broadcast.
315
+ */
316
+ private async notifyOperators(text: string): Promise<void> {
317
+ if (!this.running) return
318
+ const trimmed = text.trim()
319
+ if (trimmed.length === 0) return
320
+ const body = trimmed.length > 3500 ? `${trimmed.slice(0, 3500)}\n[truncated]` : trimmed
321
+ await Promise.allSettled(
322
+ this.opts.allowedUserIds.map(async chatId => {
323
+ try {
324
+ await this.bot.api.sendMessage(chatId, body)
325
+ } catch (err) {
326
+ console.warn(
327
+ `[telegram] notifyOperators chat=${chatId} failed: ${(err as Error).message?.slice(0, 200) ?? 'unknown'}`,
328
+ )
329
+ }
330
+ }),
331
+ )
332
+ }
333
+
301
334
  private scheduleStartRetry(): void {
302
335
  if (this.stopped) return
303
336
  if (this.retryAttempts >= MAX_LOCK_RETRY_ATTEMPTS) {
package/src/types.ts CHANGED
@@ -50,6 +50,19 @@ export interface TelegramRuntimeContext {
50
50
  * modal handles all approvals as before.
51
51
  */
52
52
  approvalBridge?: TelegramApprovalBridge
53
+ /**
54
+ * v0.24.12: outbound slot the listener fills on `start()` with a method
55
+ * that broadcasts a short text to every allowed operator chat. The
56
+ * gateway uses it to forward unsolicited brain prompts (clarify on
57
+ * autonomous market wakes) when no TUI is connected. When absent, the
58
+ * gateway logs the question to activity-log only.
59
+ */
60
+ operatorNotifier?: OperatorNotifierSlot
61
+ }
62
+
63
+ /** Mutable slot the listener fills on start so the gateway can broadcast clarify questions. */
64
+ export interface OperatorNotifierSlot {
65
+ current: ((text: string) => Promise<void>) | null
53
66
  }
54
67
 
55
68
  export type ApprovalChoiceKind = 'once' | 'session' | 'always' | 'deny'