@llblab/pi-telegram 0.52.2 → 0.53.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 (204) hide show
  1. package/AGENTS.md +9 -7
  2. package/BACKLOG.md +1 -18
  3. package/CHANGELOG.md +11 -0
  4. package/README.md +7 -11
  5. package/api/commands.ts +3 -0
  6. package/dist/api/commands.d.ts +1 -1
  7. package/dist/lib/activity-verbosity.d.ts +1 -5
  8. package/dist/lib/activity-verbosity.js +15 -42
  9. package/dist/lib/activity.d.ts +9 -0
  10. package/dist/lib/activity.js +39 -10
  11. package/dist/lib/agent-messages.js +7 -3
  12. package/dist/lib/bindings.d.ts +43 -5
  13. package/dist/lib/bindings.js +163 -20
  14. package/dist/lib/bus-api.d.ts +12 -0
  15. package/dist/lib/bus-api.js +182 -79
  16. package/dist/lib/bus-follower.d.ts +111 -31
  17. package/dist/lib/bus-follower.js +1324 -359
  18. package/dist/lib/bus-leader.d.ts +41 -91
  19. package/dist/lib/bus-leader.js +969 -637
  20. package/dist/lib/bus-transport.js +16 -9
  21. package/dist/lib/bus.d.ts +215 -18
  22. package/dist/lib/bus.js +1048 -327
  23. package/dist/lib/channel-posts.d.ts +5 -0
  24. package/dist/lib/channel-posts.js +434 -261
  25. package/dist/lib/command-templates.d.ts +26 -5
  26. package/dist/lib/command-templates.js +92 -176
  27. package/dist/lib/commands.d.ts +168 -82
  28. package/dist/lib/commands.js +1409 -291
  29. package/dist/lib/config.d.ts +1 -8
  30. package/dist/lib/config.js +34 -76
  31. package/dist/lib/delivery.d.ts +2 -2
  32. package/dist/lib/delivery.js +16 -16
  33. package/dist/lib/extension.js +639 -171
  34. package/dist/lib/generative-app-worker.mjs +19 -7
  35. package/dist/lib/generative-apps.d.ts +0 -5
  36. package/dist/lib/generative-apps.js +61 -49
  37. package/dist/lib/inbound.d.ts +5 -0
  38. package/dist/lib/inbound.js +35 -59
  39. package/dist/lib/journal.d.ts +33 -3
  40. package/dist/lib/journal.js +2063 -782
  41. package/dist/lib/lifecycle.d.ts +2 -6
  42. package/dist/lib/lifecycle.js +75 -58
  43. package/dist/lib/locks.d.ts +29 -3
  44. package/dist/lib/locks.js +289 -108
  45. package/dist/lib/logging.js +50 -14
  46. package/dist/lib/media.d.ts +22 -1
  47. package/dist/lib/media.js +46 -28
  48. package/dist/lib/menu-model.d.ts +19 -5
  49. package/dist/lib/menu-model.js +53 -11
  50. package/dist/lib/menu-queue.d.ts +5 -4
  51. package/dist/lib/menu-queue.js +45 -63
  52. package/dist/lib/menu-settings.d.ts +5 -4
  53. package/dist/lib/menu-settings.js +114 -78
  54. package/dist/lib/menu-status.d.ts +1 -1
  55. package/dist/lib/menu-status.js +8 -25
  56. package/dist/lib/menu-thinking.d.ts +6 -1
  57. package/dist/lib/menu-thinking.js +14 -21
  58. package/dist/lib/menu.d.ts +8 -61
  59. package/dist/lib/menu.js +92 -164
  60. package/dist/lib/model.d.ts +1 -1
  61. package/dist/lib/model.js +2 -16
  62. package/dist/lib/outbound-attachments.d.ts +6 -27
  63. package/dist/lib/outbound-attachments.js +45 -38
  64. package/dist/lib/outbound-buttons.js +22 -16
  65. package/dist/lib/outbound-markup.d.ts +0 -2
  66. package/dist/lib/outbound-markup.js +51 -64
  67. package/dist/lib/outbound-voice.js +6 -3
  68. package/dist/lib/outbound.d.ts +6 -6
  69. package/dist/lib/outbound.js +61 -51
  70. package/dist/lib/ownership.js +6 -2
  71. package/dist/lib/paths.d.ts +5 -0
  72. package/dist/lib/paths.js +37 -21
  73. package/dist/lib/pi.d.ts +2 -0
  74. package/dist/lib/pi.js +8 -1
  75. package/dist/lib/polling.d.ts +21 -37
  76. package/dist/lib/polling.js +59 -50
  77. package/dist/lib/preview.js +39 -19
  78. package/dist/lib/process-identity.d.ts +24 -0
  79. package/dist/lib/process-identity.js +133 -0
  80. package/dist/lib/prompts.js +2 -7
  81. package/dist/lib/queue.d.ts +14 -16
  82. package/dist/lib/queue.js +249 -126
  83. package/dist/lib/recovery.d.ts +2 -83
  84. package/dist/lib/recovery.js +20 -274
  85. package/dist/lib/replies.d.ts +16 -24
  86. package/dist/lib/replies.js +99 -116
  87. package/dist/lib/routing.d.ts +120 -7
  88. package/dist/lib/routing.js +4667 -1152
  89. package/dist/lib/runtime.d.ts +1 -11
  90. package/dist/lib/sections.d.ts +4 -29
  91. package/dist/lib/sections.js +7 -20
  92. package/dist/lib/skills.js +4 -3
  93. package/dist/lib/status.js +86 -57
  94. package/dist/lib/sync.d.ts +1 -3
  95. package/dist/lib/sync.js +67 -43
  96. package/dist/lib/target.d.ts +4 -0
  97. package/dist/lib/target.js +18 -0
  98. package/dist/lib/telegram-api.d.ts +18 -13
  99. package/dist/lib/telegram-api.js +148 -53
  100. package/dist/lib/text-groups.js +4 -39
  101. package/dist/lib/thread-cleanup-manager.d.ts +6 -27
  102. package/dist/lib/thread-cleanup-manager.js +369 -186
  103. package/dist/lib/thread-display.d.ts +1 -2
  104. package/dist/lib/thread-display.js +58 -38
  105. package/dist/lib/thread-naming.d.ts +28 -8
  106. package/dist/lib/thread-naming.js +175 -66
  107. package/dist/lib/thread-reconciler.d.ts +42 -16
  108. package/dist/lib/thread-reconciler.js +90 -50
  109. package/dist/lib/threads.d.ts +82 -20
  110. package/dist/lib/threads.js +2247 -855
  111. package/dist/lib/time-injection.js +1 -2
  112. package/dist/lib/turns.js +1 -19
  113. package/dist/lib/updates.d.ts +169 -80
  114. package/dist/lib/updates.js +2418 -641
  115. package/dist/lib/voice.d.ts +7 -22
  116. package/dist/lib/voice.js +7 -22
  117. package/dist/lib/wire.js +1 -1
  118. package/dist/lib/workspace-admission.d.ts +3 -1
  119. package/dist/lib/workspace-admission.js +425 -211
  120. package/dist/lib/workspace-identity.js +8 -13
  121. package/dist/lib/workspace-retirement.d.ts +1 -1
  122. package/dist/lib/workspace-retirement.js +328 -140
  123. package/dist/lib/workspace-slots.js +8 -4
  124. package/dist/package.json +1 -1
  125. package/docs/architecture.md +31 -29
  126. package/docs/inbound.md +1 -1
  127. package/docs/multi-instance-bus.md +15 -3
  128. package/docs/outbound.md +1 -1
  129. package/docs/public-api.md +29 -1
  130. package/docs/ui-style.md +25 -8
  131. package/lib/activity-verbosity.ts +59 -82
  132. package/lib/activity.ts +146 -102
  133. package/lib/agent-messages.ts +12 -5
  134. package/lib/bindings.ts +389 -82
  135. package/lib/bus-api.ts +263 -102
  136. package/lib/bus-follower.ts +2440 -601
  137. package/lib/bus-leader.ts +2209 -1290
  138. package/lib/bus-transport.ts +46 -12
  139. package/lib/bus.ts +1673 -444
  140. package/lib/channel-posts.ts +848 -327
  141. package/lib/command-templates.ts +152 -265
  142. package/lib/commands.ts +2398 -555
  143. package/lib/config.ts +177 -170
  144. package/lib/delivery.ts +41 -29
  145. package/lib/extension.ts +1206 -433
  146. package/lib/generative-app-worker.mjs +19 -7
  147. package/lib/generative-apps.ts +324 -211
  148. package/lib/inbound.ts +95 -97
  149. package/lib/journal.ts +5311 -1763
  150. package/lib/keyboard.ts +1 -3
  151. package/lib/lifecycle.ts +128 -78
  152. package/lib/locks.ts +677 -203
  153. package/lib/logging.ts +147 -58
  154. package/lib/media.ts +82 -43
  155. package/lib/menu-model.ts +85 -18
  156. package/lib/menu-queue.ts +88 -129
  157. package/lib/menu-settings.ts +260 -155
  158. package/lib/menu-status.ts +20 -60
  159. package/lib/menu-thinking.ts +41 -56
  160. package/lib/menu.ts +112 -285
  161. package/lib/model.ts +8 -22
  162. package/lib/outbound-attachments.ts +156 -125
  163. package/lib/outbound-buttons.ts +76 -49
  164. package/lib/outbound-markup.ts +96 -94
  165. package/lib/outbound-voice.ts +33 -27
  166. package/lib/outbound.ts +125 -125
  167. package/lib/ownership.ts +19 -10
  168. package/lib/paths.ts +148 -49
  169. package/lib/pi.ts +35 -15
  170. package/lib/polling.ts +144 -147
  171. package/lib/preview.ts +93 -40
  172. package/lib/process-identity.ts +164 -0
  173. package/lib/prompts.ts +4 -11
  174. package/lib/queue.ts +511 -300
  175. package/lib/recovery.ts +50 -454
  176. package/lib/rendering.ts +1 -3
  177. package/lib/replies.ts +248 -209
  178. package/lib/routing.ts +8509 -2186
  179. package/lib/runtime.ts +1 -12
  180. package/lib/sections.ts +24 -89
  181. package/lib/setup.ts +1 -3
  182. package/lib/skills.ts +9 -4
  183. package/lib/status.ts +215 -110
  184. package/lib/sync.ts +448 -361
  185. package/lib/target.ts +22 -3
  186. package/lib/telegram-api.ts +302 -127
  187. package/lib/text-groups.ts +5 -39
  188. package/lib/thread-cleanup-manager.ts +833 -331
  189. package/lib/thread-display.ts +213 -97
  190. package/lib/thread-naming.ts +232 -87
  191. package/lib/thread-reconciler.ts +155 -72
  192. package/lib/threads.ts +5318 -1845
  193. package/lib/time-injection.ts +1 -4
  194. package/lib/turns.ts +15 -28
  195. package/lib/updates.ts +5184 -1612
  196. package/lib/voice.ts +7 -35
  197. package/lib/wire.ts +1 -1
  198. package/lib/workspace-admission.ts +996 -416
  199. package/lib/workspace-identity.ts +14 -17
  200. package/lib/workspace-retirement.ts +878 -376
  201. package/lib/workspace-slots.ts +22 -13
  202. package/package.json +1 -1
  203. package/scripts/check-downgrade.mjs +0 -472
  204. package/scripts/measure-workspace.mjs +0 -108
@@ -3,16 +3,61 @@
3
3
  * Zones: telegram controls, pi agent commands, queue controls
4
4
  * Owns Telegram slash-command normalization, bot command metadata, pi-side command registration, and command-initiated session replacement orchestration behind runtime ports
5
5
  */
6
+ import type { TelegramActivityPublicationWork } from "./activity.ts";
6
7
  import { type TelegramConfigStore } from "./config.ts";
7
8
  import type * as Pi from "./pi.ts";
8
9
  import type { ExtensionAPI, ExtensionCommandContext } from "./pi.ts";
10
+ import type { TelegramPromptTemplateCommand } from "./prompt-templates.ts";
11
+ import { createTelegramControlItemBuilder, type PendingTelegramControlItem, type TelegramControlQueueController, type TelegramControlQueueControllerDeps, type TelegramQueueAdmissionReceipt } from "./queue.ts";
9
12
  import { type TelegramBridgeStatusLineOptions } from "./status.ts";
13
+ import { type TelegramApiCallOptions } from "./telegram-api.ts";
10
14
  import type { TelegramSessionReplacementIntent } from "./threads.ts";
11
- import { type PendingTelegramControlItem, type TelegramQueueAdmissionReceipt } from "./queue.ts";
15
+ import { type TelegramDeferredSourceEvidence, type TelegramLiveSourceCompletionReadiness, type TelegramQueueAdmissionReceiptLike } from "./updates.ts";
16
+ export type TelegramHeldCommandName = "status" | "abort" | "stop" | "next" | "continue";
17
+ /** Commands-owned no-fold admission over the ordinary recipient queue; source reporting stays separate from removal. */
18
+ export interface TelegramHeldTurnAdmission {
19
+ assertCurrent(): void;
20
+ report(receipts: readonly TelegramQueueAdmissionReceiptLike[]): void;
21
+ }
22
+ export interface TelegramPreparedHeldCommand {
23
+ readonly source: TelegramDeferredSourceEvidence;
24
+ readonly command: ParsedTelegramCommand;
25
+ bindCarrier(value: unknown): boolean;
26
+ execute(): Promise<boolean>;
27
+ /** Source disposal only, independent of detached delivery and ended source-execution/chooser callbacks. */
28
+ inspectCompletion(): TelegramDeferredSourceEvidence | undefined;
29
+ }
30
+ /** Saved-original admission for a held follower plan: fixed target plus independent source and recipient lifetimes. */
31
+ export interface TelegramHeldCommandAdmission {
32
+ target: {
33
+ chatId: number;
34
+ threadId: number;
35
+ };
36
+ assertSourceCurrent(): void;
37
+ assertRecipientCurrent(): void;
38
+ }
39
+ /** Recipient-scoped reply sender; the plan never falls back to ordinary follower API delivery. */
40
+ export interface TelegramHeldCommandReply {
41
+ sendTextReply(chatId: number, replyToMessageId: number, text: string, options: {
42
+ parseMode?: "HTML";
43
+ target: {
44
+ chatId: number;
45
+ threadId: number;
46
+ };
47
+ assertAuthority: () => void;
48
+ }): Promise<unknown>;
49
+ }
50
+ /** Captured recipient effects; a supplied but unavailable effect never falls back to ordinary dispatch. */
51
+ export type TelegramHeldCommandEffects<TContext> = Partial<TelegramHeldCommandReply & Pick<TelegramCommandHandlerTargetRuntimeDeps<TelegramCommandRuntimeMessage, TContext>, "showStatus">>;
12
52
  export interface ParsedTelegramCommand {
13
53
  name: string;
14
54
  args: string;
15
55
  }
56
+ /** Exact singleton operator-private text command original eligible for a held follower plan. */
57
+ export declare function isTelegramSelectedHeldOriginal(update: unknown, target: {
58
+ chatId: number;
59
+ threadId: number;
60
+ }, operator: number | undefined, name: string): boolean;
16
61
  export interface TelegramBotCommandDefinition {
17
62
  command: string;
18
63
  description: string;
@@ -27,6 +72,25 @@ export interface TelegramExtensionCommandContext {
27
72
  reply: (text: string) => Promise<void>;
28
73
  enqueuePrompt: (prompt: string) => Promise<void>;
29
74
  }
75
+ export interface SelectedPreparationInput {
76
+ readonly name: string;
77
+ readonly args: string;
78
+ }
79
+ export interface SelectedCommandExecution {
80
+ /** Recheck before producer mutations and after awaits; this is a trusted contract, not a sandbox. */
81
+ assertCurrent(): void;
82
+ /** Acceptance of semantic completion only, never a source-removal ACK or delivery/cleanup proof. */
83
+ reportCompleted(): boolean;
84
+ /** Queue detached recipient text without waiting for delivery as semantic completion. */
85
+ reply(text: string): void;
86
+ }
87
+ export type PreparedSelectedCommand = {
88
+ kind: "command-only";
89
+ execute(ctx: SelectedCommandExecution): void | Promise<void>;
90
+ } | {
91
+ kind: "generated-prompt";
92
+ prompt: string;
93
+ };
30
94
  export interface TelegramExtensionCommandRegistration {
31
95
  name: string;
32
96
  description?: string;
@@ -34,6 +98,10 @@ export interface TelegramExtensionCommandRegistration {
34
98
  showInMenu?: boolean;
35
99
  emoji?: string;
36
100
  handler: (ctx: TelegramExtensionCommandContext) => Promise<void> | void;
101
+ /** Trusted side-effect-free plan preparation for single-message leader selection; ordinary dispatch still uses handler. */
102
+ selected?: {
103
+ prepare(input: SelectedPreparationInput): PreparedSelectedCommand | undefined | Promise<PreparedSelectedCommand | undefined>;
104
+ };
37
105
  }
38
106
  interface RegisteredTelegramExtensionCommand {
39
107
  name: string;
@@ -42,9 +110,18 @@ interface RegisteredTelegramExtensionCommand {
42
110
  showInMenu: boolean;
43
111
  emoji?: string;
44
112
  handler: TelegramExtensionCommandRegistration["handler"];
113
+ selected?: Readonly<TelegramExtensionCommandRegistration["selected"]>;
45
114
  }
46
115
  export declare function registerTelegramCommand(registration: TelegramExtensionCommandRegistration): () => void;
47
116
  export declare function findTelegramExtensionCommand(name: string | undefined): RegisteredTelegramExtensionCommand | undefined;
117
+ /** Preparation only: no execution, admission, source freeze or binding effects. Routing owns those later. */
118
+ export declare function prepareTelegramSelectedExtensionCommand(command: ParsedTelegramCommand, authority: {
119
+ assertSourceCurrent(): void;
120
+ assertRecipientCurrent(): void;
121
+ }): Promise<{
122
+ plan: Readonly<PreparedSelectedCommand>;
123
+ assertRegistrationCurrent(): void;
124
+ } | undefined>;
48
125
  export declare function clearTelegramExtensionCommands(): void;
49
126
  export declare const TELEGRAM_COMMAND_EMOJI: {
50
127
  readonly start: "🟢";
@@ -73,10 +150,10 @@ export declare const TELEGRAM_COMPACTION_COMPLETED_MARKDOWN = "**\u2705 Compacti
73
150
  export declare const TELEGRAM_BOT_COMMANDS: readonly TelegramBotCommandDefinition[];
74
151
  export declare function getTelegramReservedCommandNames(): string[];
75
152
  export interface TelegramBotCommandRegistrationDeps {
76
- setMyCommands: (commands: readonly TelegramBotCommandDefinition[]) => Promise<unknown>;
153
+ setMyCommands: (commands: readonly TelegramBotCommandDefinition[], options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<unknown>;
77
154
  }
78
- export declare function registerTelegramBotCommands(deps: TelegramBotCommandRegistrationDeps): Promise<void>;
79
- export declare function createTelegramBotCommandRegistrar(deps: TelegramBotCommandRegistrationDeps): () => Promise<void>;
155
+ export declare function registerTelegramBotCommands(deps: TelegramBotCommandRegistrationDeps, options?: Pick<TelegramApiCallOptions, "assertAuthority">): Promise<void>;
156
+ export declare function createTelegramBotCommandRegistrar(deps: TelegramBotCommandRegistrationDeps): (options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
80
157
  export interface TelegramBridgeCommandStartPollingOptions {
81
158
  force?: boolean;
82
159
  forceFreshLeaderThread?: boolean;
@@ -87,15 +164,6 @@ export interface TelegramBridgeCommandStartPollingResult {
87
164
  canTakeover?: boolean;
88
165
  owner?: string;
89
166
  }
90
- export type TelegramPollingStartRecoveryResult = {
91
- kind: "unhandled";
92
- } | {
93
- kind: "retry";
94
- message: string;
95
- } | {
96
- kind: "blocked";
97
- message: string;
98
- };
99
167
  export interface TelegramBridgeCommandRegistrationDeps {
100
168
  promptForConfig: (ctx: ExtensionCommandContext, profileName?: string) => Promise<void>;
101
169
  getStatusLines: (options?: TelegramBridgeStatusLineOptions) => string[];
@@ -104,7 +172,6 @@ export interface TelegramBridgeCommandRegistrationDeps {
104
172
  getBotTokenDiagnostic?: () => string | undefined;
105
173
  startPolling: (ctx: ExtensionCommandContext, options?: TelegramBridgeCommandStartPollingOptions) => void | Promise<void | TelegramBridgeCommandStartPollingResult> | TelegramBridgeCommandStartPollingResult;
106
174
  stopPolling: () => Promise<void | string>;
107
- recoverPollingStart?: (error: unknown) => Promise<TelegramPollingStartRecoveryResult>;
108
175
  recordConnectionEvent?: (error: unknown, phase: string) => void;
109
176
  getDisconnectThreadName?: () => string | undefined;
110
177
  queueAgentConnectionContext?: (connected: boolean) => void;
@@ -121,18 +188,20 @@ export interface TelegramBridgeCommandRegistrationDeps {
121
188
  activateDefaultProfileConfig?: (ctx: ExtensionCommandContext, isCurrent: () => boolean) => Promise<void>;
122
189
  activateProfileConfig?: (ctx: ExtensionCommandContext, profileName: string, isCurrent: () => boolean) => Promise<boolean>;
123
190
  }
191
+ /** Bound adapters must carry the optional recipient guard through their own effect/publication awaits. */
124
192
  export type TelegramThreadDisplayNameRenamePort = (target: {
125
193
  chatId: number;
126
194
  threadId?: number;
127
- }, threadName: string) => Promise<{
195
+ }, threadName: string, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<{
128
196
  ok: boolean;
129
197
  threadName?: string;
130
198
  message?: string;
131
199
  }>;
200
+ /** Reset adapters must preserve the same optional recipient lifetime as manual rename adapters. */
132
201
  export type TelegramThreadDisplayNameResetPort = (target: {
133
202
  chatId: number;
134
203
  threadId?: number;
135
- }) => Promise<{
204
+ }, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<{
136
205
  ok: boolean;
137
206
  threadName?: string;
138
207
  message?: string;
@@ -193,7 +262,6 @@ export type TelegramCommandAction = {
193
262
  commandName: "help" | "start";
194
263
  executionMode: "immediate";
195
264
  };
196
- export type TelegramCommandExecutionMode = "ignored" | "immediate";
197
265
  export interface TelegramCommandActionDeps<TMessage, TContext> {
198
266
  handleStop: (message: TMessage, ctx: TContext) => Promise<void>;
199
267
  handleName: (message: TMessage, ctx: TContext, name: string) => Promise<void>;
@@ -230,13 +298,16 @@ export interface TelegramCompactConfirmationReplyMarkup {
230
298
  callback_data: string;
231
299
  }[][];
232
300
  }
233
- export interface TelegramCompactCommandDeps extends TelegramRuntimeEventRecorderPort {
301
+ /** Pi or Telegram work that must drain before a session-level command may replace or compact the session. */
302
+ export interface TelegramSessionBusyPorts {
234
303
  isIdle: () => boolean;
235
304
  hasPendingMessages: () => boolean;
236
305
  hasActiveTelegramTurn: () => boolean;
237
306
  hasDispatchPending: () => boolean;
238
307
  hasQueuedTelegramItems: () => boolean;
239
308
  isCompactionInProgress: () => boolean;
309
+ }
310
+ export interface TelegramCompactCommandDeps extends TelegramRuntimeEventRecorderPort, TelegramSessionBusyPorts {
240
311
  setCompactionInProgress: (inProgress: boolean) => void;
241
312
  updateStatus: () => void;
242
313
  dispatchNextQueuedTelegramTurn: () => void;
@@ -258,6 +329,7 @@ export interface TelegramCompactConfirmationDeps {
258
329
  chatId: number;
259
330
  threadId?: number;
260
331
  };
332
+ assertAuthority?: TelegramApiCallOptions["assertAuthority"];
261
333
  }) => Promise<number | undefined>;
262
334
  }
263
335
  export interface TelegramCompactConfirmationCallbackQuery {
@@ -298,6 +370,7 @@ export interface TelegramCommandRuntimeMessage {
298
370
  message_thread_id?: number;
299
371
  from?: {
300
372
  id?: number;
373
+ is_bot?: boolean;
301
374
  };
302
375
  pi_telegram_source_update_id?: number;
303
376
  }
@@ -311,63 +384,39 @@ export interface TelegramCommandTargetRuntimeDeps<TContext> {
311
384
  getAdmissionScope?: () => string | undefined;
312
385
  getAdmissionJournalBinding?: () => string | undefined;
313
386
  onControlQueued?: (message: TelegramCommandRuntimeMessage, receipt: TelegramQueueAdmissionReceipt) => void;
314
- showStatus: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number) => Promise<void>;
315
- openModelMenu: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number) => Promise<void>;
316
- openSettingsMenu?: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number) => Promise<void>;
387
+ showStatus: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
388
+ openModelMenu: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
389
+ openSettingsMenu?: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
317
390
  sendTextReply: (chatId: number, replyToMessageId: number, text: string, options?: {
318
391
  parseMode?: "HTML";
319
392
  target?: {
320
393
  chatId: number;
321
394
  threadId?: number;
322
395
  };
396
+ assertAuthority?: TelegramApiCallOptions["assertAuthority"];
323
397
  }) => Promise<unknown>;
324
398
  }
325
399
  export interface TelegramCommandTargetRuntime<TMessage extends TelegramCommandRuntimeMessage, TContext> {
326
400
  enqueueControlItem: (message: TMessage, ctx: TContext, controlType: TelegramControlCommandType, statusSummary: string, execute: (ctx: TContext) => Promise<void>) => void;
327
- showStatus: (message: TMessage, ctx: TContext) => Promise<void>;
328
- openModelMenu: (message: TMessage, ctx: TContext) => Promise<void>;
329
- openSettingsMenu: (message: TMessage, ctx: TContext) => Promise<void>;
401
+ showStatus: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
402
+ openModelMenu: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
403
+ openSettingsMenu: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
330
404
  sendTextReply: (message: TMessage, text: string, options?: {
331
405
  parseMode?: "HTML";
406
+ assertAuthority?: TelegramApiCallOptions["assertAuthority"];
332
407
  }) => Promise<void>;
333
408
  }
334
409
  export declare function getTelegramCommandMessageTarget(message: TelegramCommandRuntimeMessage): TelegramCommandMessageTarget;
335
- export interface TelegramCommandControlQueueRuntimeDeps<TContext> {
336
- createControlItem: (options: {
337
- chatId: number;
338
- target?: {
339
- chatId: number;
340
- threadId?: number;
341
- };
342
- replyToMessageId: number;
343
- controlType: TelegramControlCommandType;
344
- statusSummary: string;
345
- admissionReceipts?: TelegramQueueAdmissionReceipt[];
346
- execute: (ctx: TContext) => Promise<void>;
347
- }) => PendingTelegramControlItem<TContext>;
348
- appendControlItem: (item: PendingTelegramControlItem<TContext>, ctx: TContext) => void;
349
- dispatchNextQueuedTelegramTurn: (ctx: TContext) => void;
350
- }
351
- export declare function createTelegramCommandControlQueueRuntime<TContext>(deps: TelegramCommandControlQueueRuntimeDeps<TContext>): TelegramCommandTargetRuntimeDeps<TContext>["enqueueControlItem"];
352
410
  export declare function createTelegramCommandControlEnqueueAdapter<TContext>(deps: {
353
- createControlItem: (options: {
354
- chatId: number;
355
- target?: {
356
- chatId: number;
357
- threadId?: number;
358
- };
359
- replyToMessageId: number;
360
- controlType: TelegramControlCommandType;
361
- statusSummary: string;
362
- admissionReceipts?: TelegramQueueAdmissionReceipt[];
363
- execute: (ctx: TContext) => Promise<void>;
364
- }) => PendingTelegramControlItem<TContext>;
365
- enqueueControlItem: (item: PendingTelegramControlItem<TContext>, ctx: TContext, onQueued?: (item: PendingTelegramControlItem<TContext>) => void) => void;
411
+ createControlItem: ReturnType<typeof createTelegramControlItemBuilder<TContext>>;
412
+ enqueueControlItem: TelegramControlQueueController<TContext>["enqueue"];
366
413
  }): TelegramCommandTargetRuntimeDeps<TContext>["enqueueControlItem"];
367
- export type TelegramCommandTargetQueueRuntimeDeps<TContext> = TelegramCommandControlQueueRuntimeDeps<TContext> & Omit<TelegramCommandTargetRuntimeDeps<TContext>, "enqueueControlItem">;
414
+ export type TelegramCommandTargetQueueRuntimeDeps<TContext> = TelegramControlQueueControllerDeps<TContext> & {
415
+ createControlItem: ReturnType<typeof createTelegramControlItemBuilder<TContext>>;
416
+ } & Omit<TelegramCommandTargetRuntimeDeps<TContext>, "enqueueControlItem">;
368
417
  export declare function createTelegramCommandTargetQueueRuntime<TMessage extends TelegramCommandRuntimeMessage, TContext>(deps: TelegramCommandTargetQueueRuntimeDeps<TContext>): TelegramCommandTargetRuntime<TMessage, TContext>;
369
418
  export declare function createTelegramCommandTargetRuntime<TMessage extends TelegramCommandRuntimeMessage, TContext>(deps: TelegramCommandTargetRuntimeDeps<TContext>): TelegramCommandTargetRuntime<TMessage, TContext>;
370
- export interface TelegramCommandOrPromptRuntimeDeps<TMessage, TContext> {
419
+ export interface TelegramCommandOrPromptDispatcherDeps<TMessage, TContext> {
371
420
  extractRawText: (messages: TMessage[]) => string;
372
421
  shouldIgnoreMessages?: (messages: TMessage[]) => boolean;
373
422
  consumeThreadNameInput?: (messages: TMessage[], ctx: TContext) => Promise<boolean>;
@@ -378,7 +427,10 @@ export interface TelegramCommandOrPromptRuntimeDeps<TMessage, TContext> {
378
427
  enqueueTurn: (messages: TMessage[], ctx: TContext) => Promise<void>;
379
428
  assertExecutionCurrent?: (message: TMessage) => void;
380
429
  }
381
- export interface TelegramCommandRuntimeDeps<TMessage extends TelegramCommandRuntimeMessage, TContext> extends TelegramRuntimeEventRecorderPort {
430
+ interface TelegramCommandEffectWorkPort {
431
+ beginCommandEffectWork?: () => TelegramActivityPublicationWork;
432
+ }
433
+ export interface TelegramCommandRuntimeDeps<TMessage extends TelegramCommandRuntimeMessage, TContext> extends TelegramRuntimeEventRecorderPort, TelegramCommandEffectWorkPort {
382
434
  hasAbortHandler: () => boolean;
383
435
  clearPendingModelSwitch: () => void;
384
436
  hasQueuedTelegramItems: () => boolean;
@@ -406,28 +458,42 @@ export interface TelegramCommandRuntimeDeps<TMessage extends TelegramCommandRunt
406
458
  }) => void;
407
459
  stopTypingLoop?: () => void;
408
460
  enqueueContinueTurn: (message: TMessage, ctx: TContext) => Promise<void>;
461
+ heldTurn?: {
462
+ enqueue(message: TMessage, ctx: TContext, kind: "continue" | "prompt", admission: TelegramHeldTurnAdmission): Promise<void>;
463
+ templates?: {
464
+ getCommands(): readonly TelegramPromptTemplateCommand[];
465
+ expand(name: string, args: string): string | undefined;
466
+ };
467
+ };
409
468
  requestNewSession?: (message: TMessage) => void;
410
469
  compact: (ctx: TContext, callbacks: {
411
470
  onComplete: () => void;
412
471
  onError: (error: unknown) => void;
413
472
  }) => void;
414
473
  enqueueControlItem: (message: TMessage, ctx: TContext, controlType: TelegramControlCommandType, statusSummary: string, execute: (ctx: TContext) => Promise<void>) => void;
415
- showStatus: (message: TMessage, ctx: TContext) => Promise<void>;
416
- handleForumBootstrap?: (message: TMessage, ctx: TContext) => Promise<string | undefined>;
417
- openModelMenu: (message: TMessage, ctx: TContext) => Promise<void>;
418
- openThinkingMenu: (message: TMessage, ctx: TContext) => Promise<void>;
419
- openQueueMenu: (message: TMessage, ctx: TContext) => Promise<void>;
420
- openSettingsMenu?: (message: TMessage, ctx: TContext) => Promise<void>;
474
+ showStatus: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
475
+ /** Supplied adapters must forward recipient authority into issuance and recheck it after awaits. */
476
+ handleForumBootstrap?: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<string | undefined>;
477
+ openModelMenu: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
478
+ openThinkingMenu: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
479
+ openQueueMenu: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
480
+ openSettingsMenu?: (message: TMessage, ctx: TContext, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
421
481
  validateThreadName?: (threadName: string) => string | undefined;
422
482
  renameCurrentThread?: TelegramThreadDisplayNameRenamePort;
423
483
  resetCurrentThreadName?: TelegramThreadDisplayNameResetPort;
424
- openThreadNameDialog?: (message: TMessage, ctx: TContext) => Promise<void>;
484
+ openThreadNameDialog?: (message: TMessage, ctx: TContext, admission?: {
485
+ assertSemanticCurrent(): void;
486
+ assertRecipientCurrent(): void;
487
+ }) => Promise<void | {
488
+ assertPublished(): void;
489
+ }>;
425
490
  getAllowedUserId: () => number | undefined;
426
491
  persistAllowedUserId: TelegramConfigStore["persistAllowedUserId"];
427
- registerBotCommands: () => Promise<void>;
492
+ registerBotCommands: (options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
428
493
  getPromptTemplateCommands?: () => readonly TelegramPromptTemplateMenuCommand[];
429
494
  sendTextReply: (message: TMessage, text: string, options?: {
430
495
  parseMode?: "HTML";
496
+ assertAuthority?: TelegramApiCallOptions["assertAuthority"];
431
497
  }) => Promise<void>;
432
498
  getActiveTurnReply?: () => ((text: string, options?: {
433
499
  parseMode?: "HTML";
@@ -503,7 +569,6 @@ export declare const TELEGRAM_COMMAND_ACTIONS: {
503
569
  };
504
570
  };
505
571
  export declare function buildTelegramCommandAction(commandName: string | undefined): TelegramCommandAction;
506
- export declare function getTelegramCommandExecutionMode(action: TelegramCommandAction): TelegramCommandExecutionMode;
507
572
  export declare function handleTelegramStopCommand(deps: TelegramStopCommandDeps): Promise<void>;
508
573
  export declare function handleTelegramAbortCommand(deps: {
509
574
  hasAbortHandler: () => boolean;
@@ -535,16 +600,10 @@ export declare function handleTelegramNextCommand(deps: {
535
600
  parseMode?: "HTML";
536
601
  }) => Promise<void>) | undefined;
537
602
  }): Promise<void>;
538
- export declare function openTelegramNewConfirmation(target: TelegramCommandMessageTarget, deps: TelegramCompactConfirmationDeps): Promise<void>;
603
+ export declare function openTelegramNewConfirmation(target: TelegramCommandMessageTarget, deps: TelegramCompactConfirmationDeps, assertAuthority?: TelegramApiCallOptions["assertAuthority"]): Promise<void>;
539
604
  export declare function handleTelegramNewConfirmationCallback<TContext>(query: TelegramCompactConfirmationCallbackQuery, deps: TelegramNewConfirmationCallbackDeps<TContext>): Promise<boolean>;
540
605
  export declare function handleTelegramCompactConfirmationCallback<TContext>(query: TelegramCompactConfirmationCallbackQuery, deps: TelegramCompactConfirmationCallbackDeps<TContext>): Promise<boolean>;
541
- export interface TelegramNewCommandDeps extends TelegramRuntimeEventRecorderPort {
542
- isIdle: () => boolean;
543
- hasPendingMessages: () => boolean;
544
- hasActiveTelegramTurn: () => boolean;
545
- hasDispatchPending: () => boolean;
546
- hasQueuedTelegramItems: () => boolean;
547
- isCompactionInProgress: () => boolean;
606
+ export interface TelegramNewCommandDeps extends TelegramRuntimeEventRecorderPort, TelegramSessionBusyPorts {
548
607
  requestNewSession?: () => void;
549
608
  sendTextReply: (text: string, options?: {
550
609
  parseMode?: "HTML";
@@ -552,10 +611,6 @@ export interface TelegramNewCommandDeps extends TelegramRuntimeEventRecorderPort
552
611
  }
553
612
  export declare function handleTelegramNewCommand(deps: TelegramNewCommandDeps): Promise<void>;
554
613
  export declare function handleTelegramCompactCommand(deps: TelegramCompactCommandDeps): Promise<void>;
555
- export declare function handleTelegramStatusCommand<TContext>(deps: {
556
- ctx: TContext;
557
- showStatus: (ctx: TContext) => Promise<void>;
558
- }): Promise<void>;
559
614
  export declare function handleTelegramModelCommand<TContext>(deps: {
560
615
  ctx: TContext;
561
616
  openModelMenu: (ctx: TContext) => Promise<void>;
@@ -565,11 +620,42 @@ export interface TelegramCommandHandlerTargetRuntimeDeps<TMessage extends Telegr
565
620
  allocateItemOrder: () => number;
566
621
  allocateControlOrder: () => number;
567
622
  }
568
- export declare function createTelegramCommandHandlerTargetRuntime<TMessage extends TelegramCommandRuntimeMessage, TContext>(deps: TelegramCommandHandlerTargetRuntimeDeps<TMessage, TContext>): (commandName: string | undefined, message: TMessage, ctx: TContext, commandArgs?: string) => Promise<boolean>;
569
- export declare function createTelegramCommandHandler<TMessage extends TelegramCommandRuntimeMessage, TContext>(deps: TelegramCommandRuntimeDeps<TMessage, TContext>): (commandName: string | undefined, message: TMessage, ctx: TContext, commandArgs?: string) => Promise<boolean>;
570
- export declare function createTelegramCommandOrPromptRuntime<TMessage, TContext>(deps: TelegramCommandOrPromptRuntimeDeps<TMessage, TContext>): {
571
- dispatchMessages: (messages: TMessage[], ctx: TContext) => Promise<void>;
623
+ export declare function createTelegramCommandHandlerTargetRuntime<TMessage extends TelegramCommandRuntimeMessage, TContext>(deps: TelegramCommandHandlerTargetRuntimeDeps<TMessage, TContext>): ReturnType<typeof createTelegramCommandHandler<TMessage, TContext>>;
624
+ /** Released exact-source admission for one selected command: source/recipient lifetimes and one completion report. */
625
+ export interface TelegramSelectedCommandAdmission {
626
+ assertSourceCurrent(): void;
627
+ /** Independent exact recipient/target lifetime, including inside captured menu transport adapters. */
628
+ assertRecipientCurrent(): void;
629
+ reportCompleted(): boolean;
630
+ }
631
+ export declare function createTelegramCommandHandler<TMessage extends TelegramCommandRuntimeMessage, TContext>(deps: TelegramCommandRuntimeDeps<TMessage, TContext>): ((commandName: string | undefined, message: TMessage, ctx: TContext, commandArgs?: string) => Promise<boolean>) & {
632
+ /** Command-only producer execution; Routing must supply the captured plan and released exact-source authority. */
633
+ prepareSelectedExtensionCommand(prepared: NonNullable<Awaited<ReturnType<typeof prepareTelegramSelectedExtensionCommand>>>, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission): (() => Promise<void>) | undefined;
634
+ /** Selected help/start require the existing authenticated owner; cold pairing remains ordinary first contact. */
635
+ prepareSelectedStartCommand: (command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission) => (() => Promise<boolean>) | undefined;
636
+ prepareSelectedHelpCommand: (command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission) => (() => Promise<boolean>) | undefined;
637
+ /** Selected new handles only confirmation; the later authenticated callback owns replacement admission. */
638
+ prepareSelectedNewCommand: (command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission) => (() => Promise<boolean>) | undefined;
639
+ /** Selected compaction handles only confirmation; the later authenticated callback owns actual compaction. */
640
+ prepareSelectedCompactCommand: (command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission) => (() => Promise<boolean>) | undefined;
641
+ /** Bare naming completes only after the exact dialog owner confirms current publication, not delivery alone. */
642
+ prepareSelectedNameDialogCommand(command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission): (() => Promise<boolean>) | undefined;
643
+ /** Explicit naming retains source authority until its owner result; bare dialogs use their own publication leaf. */
644
+ prepareSelectedNameCommand(command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission): (() => Promise<boolean>) | undefined;
645
+ /** Genuine leader originals capture their warm queue owner before release; no hold copy or semantic-completion report. */
646
+ prepareSelectedQueueCommand(command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramHeldCommandAdmission): Omit<TelegramPreparedHeldCommand, "bindCarrier"> | undefined;
647
+ /** Selected leaders reuse registry semantics; native source/recipient admission and inline transport remain role-owned. */
648
+ prepareSelectedCommand: (command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission) => (() => Promise<boolean>) | undefined;
649
+ /** Existing native publication boundary; unrelated/legacy receipts keep their ordinary owner. */
650
+ prepareHeldQueueReceipt: (receipt: TelegramQueueAdmissionReceipt, queueOwner: import("./journal.ts").TelegramUpdateJournalQueueOwner, context: TContext, isWorkerCurrent: () => boolean) => import("./updates.ts").TelegramQueueSourceCompletion[] | undefined;
651
+ /** Pure registry/effect availability; never reads a source or activates future recipient authority. */
652
+ canPrepareHeldCommand(name: string, effects?: TelegramHeldCommandEffects<TContext>): boolean;
653
+ /** Compile one registry plan from a saved original; no admission, recipient activation or update-handler replay. */
654
+ prepareHeldCommand(name: string, readiness: TelegramLiveSourceCompletionReadiness, ctx: TContext, admission: TelegramHeldCommandAdmission, effects?: TelegramHeldCommandEffects<TContext>): TelegramPreparedHeldCommand | undefined;
655
+ /** Warm menu-only issuance; completion reporting is not a receipt or a durable removal ACK. */
656
+ prepareSelectedMenuCommand(command: ParsedTelegramCommand, messages: readonly TMessage[], ctx: TContext, admission: TelegramSelectedCommandAdmission): (() => Promise<boolean>) | undefined;
572
657
  };
658
+ export declare function createTelegramCommandOrPromptDispatcher<TMessage, TContext>(deps: TelegramCommandOrPromptDispatcherDeps<TMessage, TContext>): (messages: TMessage[], ctx: TContext) => Promise<void>;
573
659
  export declare const TELEGRAM_INTERNAL_COMMAND_NAME = "telegram-internal";
574
660
  export declare const TELEGRAM_INTERNAL_COMMAND_DESCRIPTION = "Internal Telegram command cannot be run manually";
575
661
  export declare const TELEGRAM_INTERNAL_MANUAL_USE_MESSAGE = "This internal Telegram command cannot be run manually.";