@llblab/pi-telegram 0.11.2 → 0.13.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 (53) hide show
  1. package/AGENTS.md +20 -15
  2. package/BACKLOG.md +1 -11
  3. package/CHANGELOG.md +41 -1
  4. package/README.md +15 -41
  5. package/api/inbound.ts +14 -0
  6. package/api/keyboard.ts +10 -0
  7. package/api/outbound.ts +11 -0
  8. package/api/sections.ts +17 -0
  9. package/api/updates.ts +11 -0
  10. package/api/voice.ts +24 -0
  11. package/docs/README.md +7 -5
  12. package/docs/architecture.md +162 -226
  13. package/docs/callback-namespaces.md +3 -3
  14. package/docs/command-templates.md +18 -16
  15. package/docs/{inbound-handlers.md → inbound.md} +14 -11
  16. package/docs/locks.md +3 -3
  17. package/docs/{outbound-handlers.md → outbound.md} +14 -11
  18. package/docs/public-api.md +420 -0
  19. package/docs/{extension-sections.md → sections.md} +34 -30
  20. package/docs/ui-style.md +165 -0
  21. package/docs/{external-handlers.md → updates.md} +33 -31
  22. package/docs/voice.md +27 -19
  23. package/index.ts +88 -242
  24. package/lib/bindings.ts +299 -0
  25. package/lib/command-templates.ts +249 -60
  26. package/lib/commands.ts +114 -1
  27. package/lib/config.ts +44 -4
  28. package/lib/{inbound-handlers.ts → inbound.ts} +31 -21
  29. package/lib/lifecycle.ts +41 -6
  30. package/lib/locks.ts +4 -1
  31. package/lib/menu-model.ts +3 -3
  32. package/lib/menu-queue.ts +1 -1
  33. package/lib/menu-settings.ts +21 -10
  34. package/lib/menu-status.ts +1 -1
  35. package/lib/menu.ts +1 -1
  36. package/lib/outbound-buttons.ts +226 -0
  37. package/lib/outbound-markup.ts +357 -0
  38. package/lib/outbound-voice.ts +263 -0
  39. package/lib/outbound.ts +908 -0
  40. package/lib/polling.ts +4 -3
  41. package/lib/preview.ts +2 -2
  42. package/lib/queue.ts +3 -0
  43. package/lib/replies.ts +4 -1
  44. package/lib/routing.ts +44 -3
  45. package/lib/{extension-sections.ts → sections.ts} +37 -8
  46. package/lib/status.ts +13 -0
  47. package/lib/{api.ts → telegram-api.ts} +4 -4
  48. package/lib/text-groups.ts +3 -2
  49. package/lib/updates.ts +121 -1
  50. package/lib/voice.ts +67 -21
  51. package/package.json +13 -3
  52. package/lib/external-handlers.ts +0 -166
  53. package/lib/outbound-handlers.ts +0 -1663
package/lib/config.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Telegram bridge config and pairing helpers
3
3
  * Zones: telegram config, pairing, filesystem
4
- * Owns persisted bot/session pairing state, local config storage, authorization policy, and first-user pairing side effects
4
+ * Owns persisted bot/session pairing state, local config storage, live config controls, authorization policy, and first-user pairing side effects
5
5
  */
6
6
 
7
7
  import { existsSync } from "node:fs";
@@ -9,7 +9,7 @@ import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
9
9
  import { homedir } from "node:os";
10
10
  import { join, resolve } from "node:path";
11
11
 
12
- import type { TelegramInboundHandlerConfig } from "./inbound-handlers.ts";
12
+ import type { TelegramInboundHandlerConfig } from "./inbound.ts";
13
13
  import type { CommandTemplateObjectConfig } from "./command-templates.ts";
14
14
 
15
15
  const CONFIG_RUNTIME_KEY = "__piTelegramConfigRuntime__";
@@ -30,9 +30,8 @@ export type TelegramOutboundCommandTemplateConfig =
30
30
  export interface TelegramOutboundHandlerConfig extends CommandTemplateObjectConfig {
31
31
  type?: string;
32
32
  match?: string | string[];
33
- pipe?: TelegramOutboundCommandTemplateConfig[];
34
33
  output?: string;
35
- timeout?: number;
34
+ timeout?: number | string;
36
35
  }
37
36
 
38
37
  export type TelegramTimeMode = "hidden" | "always" | "interval";
@@ -110,6 +109,22 @@ export function updateTelegramVoiceConfig(
110
109
  return true;
111
110
  }
112
111
 
112
+ export function bindGlobalTelegramConfigRuntime(
113
+ configStore: Pick<TelegramConfigStore, "get" | "set" | "persist">,
114
+ ): void {
115
+ setGlobalTelegramConfigRuntime({
116
+ updateVoiceConfig(voice) {
117
+ const current = configStore.get();
118
+ const next = {
119
+ ...current,
120
+ voice: { ...(current.voice ?? {}), ...voice },
121
+ };
122
+ configStore.set(next);
123
+ void configStore.persist(next);
124
+ },
125
+ });
126
+ }
127
+
113
128
  export async function readTelegramConfig(
114
129
  configPath: string,
115
130
  ): Promise<TelegramConfig> {
@@ -266,6 +281,16 @@ export function createTelegramTimeInjectionModeSetter(
266
281
  ): (injectionMode: TelegramTimeMode) => Promise<void> {
267
282
  return async (injectionMode) => {
268
283
  const current = configStore.get();
284
+ if (injectionMode === "hidden") {
285
+ const { injectionMode: _injectionMode, ...remainingTime } =
286
+ current.time ?? {};
287
+ const next = { ...current };
288
+ if (Object.keys(remainingTime).length > 0) next.time = remainingTime;
289
+ else delete next.time;
290
+ configStore.set(next);
291
+ await configStore.persist(next);
292
+ return;
293
+ }
269
294
  const next = {
270
295
  ...current,
271
296
  time: { ...(current.time ?? {}), injectionMode },
@@ -282,6 +307,21 @@ export function createTelegramProactivePushChatIdGetter(deps: {
282
307
  return () => deps.getActiveTurnChatId() ?? deps.getAllowedUserId();
283
308
  }
284
309
 
310
+ export function createTelegramConfigControls(
311
+ configStore: Pick<TelegramConfigStore, "get" | "set" | "persist">,
312
+ ) {
313
+ return {
314
+ isProactivePushEnabled: createTelegramProactivePushChecker(configStore),
315
+ setProactivePushEnabled: createTelegramProactivePushSetter(configStore),
316
+ getVoiceReplyMode: createTelegramVoiceReplyModeGetter(configStore),
317
+ isVoiceReplyModeConfigured:
318
+ createTelegramVoiceReplyModeConfiguredChecker(configStore),
319
+ setVoiceReplyMode: createTelegramVoiceReplyModeSetter(configStore),
320
+ getTimeInjectionMode: createTelegramTimeInjectionModeGetter(configStore),
321
+ setTimeInjectionMode: createTelegramTimeInjectionModeSetter(configStore),
322
+ };
323
+ }
324
+
285
325
  export type TelegramAuthorizationState =
286
326
  | { kind: "pair"; userId: number }
287
327
  | { kind: "allow" }
@@ -11,6 +11,7 @@ import {
11
11
  buildCommandTemplateInvocation,
12
12
  expandCommandTemplateConfigs,
13
13
  normalizeCommandTemplateConfig,
14
+ substituteCommandTemplateToken,
14
15
  type CommandTemplateConfig,
15
16
  type CommandTemplateObjectConfig,
16
17
  } from "./command-templates.ts";
@@ -28,10 +29,9 @@ export interface TelegramInboundHandlerConfig {
28
29
  mime?: string | string[];
29
30
  type?: string | string[];
30
31
  template?: string | TelegramInboundCommandTemplateConfig[];
31
- pipe?: TelegramInboundCommandTemplateConfig[];
32
32
  args?: string[];
33
33
  defaults?: Record<string, unknown>;
34
- timeout?: number;
34
+ timeout?: number | string;
35
35
  }
36
36
 
37
37
  export interface TelegramInboundHandlerFile {
@@ -62,6 +62,7 @@ export interface TelegramInboundHandlerExecOptions {
62
62
  timeout?: number;
63
63
  signal?: AbortSignal;
64
64
  stdin?: string;
65
+ retry?: number;
65
66
  }
66
67
 
67
68
  export interface TelegramInboundHandlerExecResult {
@@ -216,9 +217,7 @@ function matchesWildcard(pattern: string, value: string | undefined): boolean {
216
217
  return new RegExp(`^${escaped}$`).test(normalizedValue);
217
218
  }
218
219
 
219
- function handlerHasSelectors(
220
- handler: TelegramInboundHandlerConfig,
221
- ): boolean {
220
+ function handlerHasSelectors(handler: TelegramInboundHandlerConfig): boolean {
222
221
  return (
223
222
  normalizeStringList(handler.match).length > 0 ||
224
223
  normalizeStringList(handler.mime).length > 0 ||
@@ -324,13 +323,28 @@ export function buildTelegramInboundHandlerInvocation(
324
323
  );
325
324
  }
326
325
 
326
+ function resolveTelegramInboundNumericControlField(
327
+ value: number | string | undefined,
328
+ values: Record<string, unknown>,
329
+ label: string,
330
+ ): number | undefined {
331
+ if (value === undefined) return undefined;
332
+ const resolved =
333
+ typeof value === "string"
334
+ ? substituteCommandTemplateToken(value, values, label)
335
+ : value;
336
+ if (resolved === "") return undefined;
337
+ const numeric = Number(resolved);
338
+ if (!Number.isFinite(numeric) || numeric < 0)
339
+ throw new Error(`Command template ${label} must be a non-negative number.`);
340
+ return numeric;
341
+ }
342
+
327
343
  function getTelegramInboundHandlerConfiguredTimeout(
328
344
  handler: TelegramInboundCommandTemplateConfig,
329
345
  ): number | undefined {
330
346
  const timeout = typeof handler === "string" ? undefined : handler.timeout;
331
- return typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0
332
- ? timeout
333
- : undefined;
347
+ return resolveTelegramInboundNumericControlField(timeout, {}, "timeout");
334
348
  }
335
349
 
336
350
  function getTelegramInboundHandlerTimeout(
@@ -376,8 +390,7 @@ function getTelegramInboundCompositionStepTimeout(
376
390
  function getTelegramInboundHandlerKind(
377
391
  handler: TelegramInboundHandlerConfig,
378
392
  ): string {
379
- if (Array.isArray(handler.template) || handler.pipe?.length)
380
- return "composition";
393
+ if (Array.isArray(handler.template)) return "composition";
381
394
  if (handler.template) return "template";
382
395
  return "unknown";
383
396
  }
@@ -412,7 +425,7 @@ async function executeTelegramInboundHandlerInvocation(
412
425
  cwd,
413
426
  timeout,
414
427
  ...(typeof handler === "object" && handler.retry !== undefined
415
- ? { retry: handler.retry }
428
+ ? { retry: resolveTelegramInboundNumericControlField(handler.retry, {}, "retry") }
416
429
  : {}),
417
430
  ...(stdin !== undefined ? { stdin } : {}),
418
431
  });
@@ -429,12 +442,6 @@ function getTelegramInboundHandlerCompositionSteps(
429
442
  handler,
430
443
  ) as TelegramInboundCommandTemplateConfig[];
431
444
  }
432
- if (handler.pipe?.length) {
433
- return expandCommandTemplateConfigs({
434
- ...handler,
435
- template: handler.pipe,
436
- }) as TelegramInboundCommandTemplateConfig[];
437
- }
438
445
  return [];
439
446
  }
440
447
 
@@ -492,7 +499,7 @@ async function executeTelegramTextHandlerInvocation(
492
499
  timeout,
493
500
  stdin: text,
494
501
  ...(typeof handler === "object" && handler.retry !== undefined
495
- ? { retry: handler.retry }
502
+ ? { retry: resolveTelegramInboundNumericControlField(handler.retry, {}, "retry") }
496
503
  : {}),
497
504
  });
498
505
  if (result.code !== 0)
@@ -526,7 +533,7 @@ async function executeTelegramTextHandler(
526
533
  : getTelegramInboundCompositionStepTimeout(handler, step, startedAt),
527
534
  );
528
535
  } catch (error) {
529
- if (typeof step === "object" && step.critical) throw error;
536
+ if (typeof step === "object" && step.failure === "root") throw error;
530
537
  output = "";
531
538
  }
532
539
  if (index > 0 && !output) output = text;
@@ -642,7 +649,10 @@ async function readBuiltInTelegramTextAttachment(
642
649
  if (!isTelegramTextMimeType(file.mimeType)) return undefined;
643
650
  const content = await readFile(file.path, "utf8");
644
651
  const normalized = content.trim();
645
- if (!normalized || Buffer.byteLength(normalized, "utf8") > BUILT_IN_TEXT_ATTACHMENT_MAX_BYTES) {
652
+ if (
653
+ !normalized ||
654
+ Buffer.byteLength(normalized, "utf8") > BUILT_IN_TEXT_ATTACHMENT_MAX_BYTES
655
+ ) {
646
656
  return undefined;
647
657
  }
648
658
  const name = file.fileName || basename(file.path);
@@ -681,7 +691,7 @@ async function executeTelegramInboundHandler(
681
691
  index === 0 ? undefined : output,
682
692
  );
683
693
  } catch (error) {
684
- if (typeof step === "object" && step.critical) throw error;
694
+ if (typeof step === "object" && step.failure === "root") throw error;
685
695
  output = "";
686
696
  }
687
697
  }
package/lib/lifecycle.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Telegram lifecycle hook registration helpers
3
3
  * Zones: pi agent lifecycle, telegram session
4
- * Owns binding prepared Telegram lifecycle runtimes to pi extension lifecycle events
4
+ * Binds prepared Telegram lifecycle runtimes to pi extension lifecycle events
5
5
  */
6
6
 
7
7
  import type {
@@ -107,16 +107,15 @@ type TelegramLifecycleTimer = number | ReturnType<typeof setTimeout>;
107
107
  export interface TelegramCompactionObserverRuntimeDeps<TContext> {
108
108
  setCompactionInProgress: (inProgress: boolean) => void;
109
109
  updateStatus: (ctx: TContext) => void;
110
+ startTypingLoop?: (ctx: TContext) => void;
111
+ stopTypingLoop?: () => void;
110
112
  requestDeferredDispatchNextQueuedTelegramTurn: (
111
113
  dispatch: (ctx: TContext) => void,
112
114
  ) => void;
113
115
  dispatchNextQueuedTelegramTurn: (ctx: TContext) => void;
114
116
  recordRuntimeEvent?: (category: string, error: unknown) => void;
115
117
  timeoutMs?: number;
116
- setTimer?: (
117
- callback: () => void,
118
- ms: number,
119
- ) => TelegramLifecycleTimer;
118
+ setTimer?: (callback: () => void, ms: number) => TelegramLifecycleTimer;
120
119
  clearTimer?: (timer: TelegramLifecycleTimer) => void;
121
120
  }
122
121
 
@@ -149,11 +148,13 @@ export function createTelegramCompactionObserverRuntime<TContext>(
149
148
  return {
150
149
  onSessionBeforeCompact: (_event, ctx) => {
151
150
  deps.setCompactionInProgress(true);
151
+ deps.startTypingLoop?.(ctx);
152
152
  deps.updateStatus(ctx);
153
153
  clearFallbackTimer();
154
154
  fallbackTimer = setTimer(() => {
155
155
  fallbackTimer = undefined;
156
156
  deps.setCompactionInProgress(false);
157
+ deps.stopTypingLoop?.();
157
158
  deps.updateStatus(ctx);
158
159
  deps.recordRuntimeEvent?.(
159
160
  "compact",
@@ -165,10 +166,44 @@ export function createTelegramCompactionObserverRuntime<TContext>(
165
166
  onSessionCompact: (_event, ctx) => {
166
167
  clearFallbackTimer();
167
168
  deps.setCompactionInProgress(false);
169
+ deps.stopTypingLoop?.();
168
170
  deps.updateStatus(ctx);
169
171
  requestDispatch();
170
172
  },
171
- onSessionShutdown: clearFallbackTimer,
173
+ onSessionShutdown: () => {
174
+ clearFallbackTimer();
175
+ deps.stopTypingLoop?.();
176
+ },
177
+ };
178
+ }
179
+
180
+ export interface TelegramMessageActivityTypingDeps<TContext> {
181
+ hasActiveTurn: () => boolean;
182
+ startTypingLoop: (ctx: TContext) => void;
183
+ onMessageStart: TelegramLifecycleRegistrationDeps["onMessageStart"];
184
+ onMessageUpdate: TelegramLifecycleRegistrationDeps["onMessageUpdate"];
185
+ }
186
+
187
+ export function createTelegramMessageActivityTypingHooks<
188
+ TContext extends ExtensionContext,
189
+ >(
190
+ deps: TelegramMessageActivityTypingDeps<TContext>,
191
+ ): Pick<
192
+ TelegramLifecycleRegistrationDeps,
193
+ "onMessageStart" | "onMessageUpdate"
194
+ > {
195
+ const ensureTyping = (ctx: TContext): void => {
196
+ if (deps.hasActiveTurn()) deps.startTypingLoop(ctx);
197
+ };
198
+ return {
199
+ onMessageStart: async (event, ctx) => {
200
+ ensureTyping(ctx as TContext);
201
+ await deps.onMessageStart(event, ctx);
202
+ },
203
+ onMessageUpdate: async (event, ctx) => {
204
+ ensureTyping(ctx as TContext);
205
+ await deps.onMessageUpdate(event, ctx);
206
+ },
172
207
  };
173
208
  }
174
209
 
package/lib/locks.ts CHANGED
@@ -125,7 +125,10 @@ export function writeLocks(path: string, locks: Record<string, unknown>): void {
125
125
  mkdirSync(dirname(path), { recursive: true });
126
126
  const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
127
127
  try {
128
- writeFileSync(tempPath, `${JSON.stringify(locks, null, 2)}\n`, "utf8");
128
+ writeFileSync(tempPath, `${JSON.stringify(locks, null, 2)}\n`, {
129
+ encoding: "utf8",
130
+ mode: 0o600,
131
+ });
129
132
  renameSync(tempPath, path);
130
133
  } catch (error) {
131
134
  try {
package/lib/menu-model.ts CHANGED
@@ -983,7 +983,7 @@ export function buildModelMenuReplyMarkup(
983
983
  callback_data: "model:scope:scoped",
984
984
  },
985
985
  {
986
- text: state.scope === "all" ? "🟡 All" : "⚫️ All",
986
+ text: state.scope === "all" ? "🟣 All" : "⚫️ All",
987
987
  callback_data: "model:scope:all",
988
988
  },
989
989
  ]);
@@ -1050,7 +1050,7 @@ export function buildModelDetailMenuReplyMarkup(
1050
1050
  callback_data: "model:scope-enable",
1051
1051
  },
1052
1052
  {
1053
- text: scoped ? "⚫️ All" : "🟡 All",
1053
+ text: scoped ? "⚫️ All" : "🟣 All",
1054
1054
  callback_data: "model:scope-disable",
1055
1055
  },
1056
1056
  ],
@@ -1091,7 +1091,7 @@ export function buildModelPageMenuReplyMarkup(
1091
1091
  return {
1092
1092
  text:
1093
1093
  pageIndex === menuPage.page
1094
- ? `🟢 ${pageIndex + 1}`
1094
+ ? `🟣 ${pageIndex + 1}`
1095
1095
  : String(pageIndex + 1),
1096
1096
  callback_data: `model:page:${pageIndex}`,
1097
1097
  };
package/lib/menu-queue.ts CHANGED
@@ -162,7 +162,7 @@ function buildTelegramQueueItemSubmenuReplyMarkup(
162
162
  callback_data: `queue:prio-set:${chatId}:${replyToMessageId}:priority`,
163
163
  },
164
164
  {
165
- text: isPriority ? "⚫️ Normal" : "🟡 Normal",
165
+ text: isPriority ? "⚫️ Normal" : "🟣 Normal",
166
166
  callback_data: `queue:prio-set:${chatId}:${replyToMessageId}:normal`,
167
167
  },
168
168
  ],
@@ -7,7 +7,7 @@
7
7
  import {
8
8
  getTelegramExtensionSettingsRows,
9
9
  type TelegramSectionRegistry,
10
- } from "./extension-sections.ts";
10
+ } from "./sections.ts";
11
11
  import type { TelegramTimeMode } from "./config.ts";
12
12
  import type { TelegramInlineKeyboardMarkup } from "./keyboard.ts";
13
13
  import type { TelegramModelMenuState } from "./menu-model.ts";
@@ -115,7 +115,8 @@ export interface TelegramSettingsMenuRuntimeDeps<
115
115
 
116
116
  export const SETTINGS_MENU_TITLE = "<b>⚙️ Settings:</b>";
117
117
  export const PROACTIVE_PUSH_SETTINGS_TITLE = "<b>📌 Proactive push:</b>";
118
- export const TIME_INJECTION_MODE_SETTINGS_TITLE = "<b>🕒 Time injection mode:</b>";
118
+ export const TIME_INJECTION_MODE_SETTINGS_TITLE =
119
+ "<b>🕒 Time injection mode:</b>";
119
120
  export const VOICE_REPLY_MODE_SETTINGS_TITLE = "<b>👄 Voice reply mode:</b>";
120
121
 
121
122
  type TelegramVoiceReplyModeSetting = TelegramVoiceReplyMode | "hidden";
@@ -124,6 +125,10 @@ function getVoiceReplyModeLabel(mode: TelegramVoiceReplyModeSetting): string {
124
125
  return mode;
125
126
  }
126
127
 
128
+ function getTelegramSettingsStateValueLabel(value: string): string {
129
+ return value.length > 0 ? value[0]!.toUpperCase() + value.slice(1) : value;
130
+ }
131
+
127
132
  function getVoiceReplyModeSetting(
128
133
  mode: TelegramVoiceReplyMode,
129
134
  configured: boolean,
@@ -197,21 +202,23 @@ export function buildTelegramSettingsMenuReplyMarkup(
197
202
  rows.push(
198
203
  [
199
204
  {
200
- text: `👄 Voice reply: ${getVoiceReplyModeLabel(
201
- getVoiceReplyModeSetting(voiceReplyMode, voiceReplyModeConfigured),
205
+ text: `👄 Voice reply: ${getTelegramSettingsStateValueLabel(
206
+ getVoiceReplyModeLabel(
207
+ getVoiceReplyModeSetting(voiceReplyMode, voiceReplyModeConfigured),
208
+ ),
202
209
  )}`,
203
210
  callback_data: "settings:open:voice-reply",
204
211
  },
205
212
  ],
206
213
  [
207
214
  {
208
- text: `🕒 Time injection: ${timeInjectionMode}`,
215
+ text: `🕒 Time injection: ${getTelegramSettingsStateValueLabel(timeInjectionMode)}`,
209
216
  callback_data: "settings:open:time-injection",
210
217
  },
211
218
  ],
212
219
  [
213
220
  {
214
- text: `📌 Proactive push: ${proactivePushEnabled ? "on" : "off"}`,
221
+ text: `📌 Proactive push: ${proactivePushEnabled ? "On" : "Off"}`,
215
222
  callback_data: "settings:open:proactive",
216
223
  },
217
224
  ],
@@ -251,11 +258,11 @@ export function buildProactivePushSettingsReplyMarkup(
251
258
  [{ text: "⬆️ Back", callback_data: "settings:list" }],
252
259
  [
253
260
  {
254
- text: proactivePushEnabled ? "🟢 on" : "⚫️ on",
261
+ text: proactivePushEnabled ? "🟢 On" : "⚫️ On",
255
262
  callback_data: "settings:set:proactive:on",
256
263
  },
257
264
  {
258
- text: proactivePushEnabled ? "⚫️ off" : "🟡 off",
265
+ text: proactivePushEnabled ? "⚫️ Off" : "🟡 Off",
259
266
  callback_data: "settings:set:proactive:off",
260
267
  },
261
268
  ],
@@ -372,7 +379,10 @@ export async function handleTelegramSettingsMenuCallbackAction(
372
379
  await deps.answerCallbackQuery(callbackQueryId);
373
380
  return true;
374
381
  }
375
- if (data === "settings:open:time-injection" || data === "settings:open:time") {
382
+ if (
383
+ data === "settings:open:time-injection" ||
384
+ data === "settings:open:time"
385
+ ) {
376
386
  await updateTimeInjectionModeSettingsMessage(deps);
377
387
  await deps.answerCallbackQuery(callbackQueryId);
378
388
  return true;
@@ -506,7 +516,8 @@ export function createTelegramSettingsMenuRuntime<
506
516
  ? query.data.slice("settings:set:time-injection:".length)
507
517
  : query.data.slice("settings:set:time:".length);
508
518
  if (
509
- (hasTimeInjectionPrefix || query.data.startsWith("settings:set:time:")) &&
519
+ (hasTimeInjectionPrefix ||
520
+ query.data.startsWith("settings:set:time:")) &&
510
521
  (timeMode === "off" ||
511
522
  timeMode === "hidden" ||
512
523
  timeMode === "always" ||
@@ -8,7 +8,7 @@ import { formatTelegramCommandEmojiPrefix } from "./commands.ts";
8
8
  import {
9
9
  getTelegramSectionMainMenuRows,
10
10
  type TelegramSectionRegistry,
11
- } from "./extension-sections.ts";
11
+ } from "./sections.ts";
12
12
  import {
13
13
  formatStatusButtonLabel,
14
14
  type TelegramMenuMessageRuntimeDeps,
package/lib/menu.ts CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  handleTelegramSectionSettingsOpen,
11
11
  parseTelegramSectionCallback,
12
12
  type TelegramSectionRegistry,
13
- } from "./extension-sections.ts";
13
+ } from "./sections.ts";
14
14
  import {
15
15
  createTelegramModelMenuStateBuilder,
16
16
  handleTelegramModelMenuCallbackAction,