@llblab/pi-kit 0.29.1 → 0.30.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 (222) hide show
  1. package/BACKLOG.md +3 -1
  2. package/CHANGELOG.md +10 -0
  3. package/README.md +4 -4
  4. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +12 -0
  5. package/node_modules/@llblab/pi-state-flow/README.md +2 -2
  6. package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +2 -2
  7. package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +17 -8
  8. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +7 -3
  9. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +2 -1
  10. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +3 -2
  11. package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
  12. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +3 -3
  13. package/node_modules/@llblab/pi-state-flow/docs/usage.md +3 -2
  14. package/node_modules/@llblab/pi-state-flow/lib/context.ts +17 -8
  15. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +6 -3
  16. package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +4 -2
  17. package/node_modules/@llblab/pi-state-flow/package.json +1 -1
  18. package/node_modules/@llblab/pi-telegram/AGENTS.md +13 -10
  19. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -1
  20. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +23 -0
  21. package/node_modules/@llblab/pi-telegram/README.md +10 -11
  22. package/node_modules/@llblab/pi-telegram/api/commands.ts +3 -0
  23. package/node_modules/@llblab/pi-telegram/dist/api/commands.d.ts +1 -1
  24. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +1 -5
  25. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +15 -42
  26. package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +9 -0
  27. package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +39 -10
  28. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.js +7 -3
  29. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +43 -5
  30. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +164 -20
  31. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.d.ts +12 -0
  32. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +181 -77
  33. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +111 -31
  34. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +1324 -359
  35. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +41 -91
  36. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +969 -637
  37. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +16 -9
  38. package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +215 -18
  39. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +1048 -327
  40. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +5 -0
  41. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +434 -261
  42. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +26 -5
  43. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +92 -176
  44. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +168 -82
  45. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +1409 -291
  46. package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +1 -8
  47. package/node_modules/@llblab/pi-telegram/dist/lib/config.js +34 -76
  48. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +2 -2
  49. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +16 -16
  50. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +642 -170
  51. package/node_modules/@llblab/pi-telegram/dist/lib/generative-app-worker.mjs +19 -7
  52. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +0 -5
  53. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.js +61 -49
  54. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +5 -0
  55. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +35 -59
  56. package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +40 -4
  57. package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +2102 -760
  58. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +2 -6
  59. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +75 -58
  60. package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +34 -3
  61. package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +318 -119
  62. package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +50 -14
  63. package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +22 -1
  64. package/node_modules/@llblab/pi-telegram/dist/lib/media.js +46 -28
  65. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +19 -5
  66. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +53 -11
  67. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.d.ts +5 -4
  68. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.js +45 -63
  69. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +5 -4
  70. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +114 -78
  71. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +1 -1
  72. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +8 -25
  73. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +6 -1
  74. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +14 -21
  75. package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +8 -61
  76. package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +92 -164
  77. package/node_modules/@llblab/pi-telegram/dist/lib/model.d.ts +1 -1
  78. package/node_modules/@llblab/pi-telegram/dist/lib/model.js +2 -16
  79. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +6 -27
  80. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +45 -38
  81. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +22 -16
  82. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +0 -2
  83. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +51 -64
  84. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.js +6 -3
  85. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +6 -6
  86. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +61 -51
  87. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.js +6 -2
  88. package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +5 -0
  89. package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +37 -21
  90. package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +2 -0
  91. package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +8 -1
  92. package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +23 -37
  93. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +71 -52
  94. package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +39 -19
  95. package/node_modules/@llblab/pi-telegram/dist/lib/process-identity.d.ts +24 -0
  96. package/node_modules/@llblab/pi-telegram/dist/lib/process-identity.js +133 -0
  97. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.js +2 -7
  98. package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +16 -16
  99. package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +261 -116
  100. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +2 -83
  101. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +20 -274
  102. package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +16 -24
  103. package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +99 -116
  104. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +121 -7
  105. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +4750 -1161
  106. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +1 -11
  107. package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +4 -29
  108. package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +7 -20
  109. package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +4 -3
  110. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +86 -57
  111. package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +6 -3
  112. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +112 -45
  113. package/node_modules/@llblab/pi-telegram/dist/lib/target.d.ts +4 -0
  114. package/node_modules/@llblab/pi-telegram/dist/lib/target.js +18 -0
  115. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +18 -11
  116. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +165 -49
  117. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.js +4 -39
  118. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +6 -27
  119. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +369 -186
  120. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +1 -2
  121. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +58 -38
  122. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +28 -8
  123. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +175 -66
  124. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +42 -16
  125. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +90 -50
  126. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +88 -24
  127. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +2276 -842
  128. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.js +1 -2
  129. package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +1 -19
  130. package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +178 -82
  131. package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +2438 -645
  132. package/node_modules/@llblab/pi-telegram/dist/lib/voice.d.ts +7 -22
  133. package/node_modules/@llblab/pi-telegram/dist/lib/voice.js +7 -22
  134. package/node_modules/@llblab/pi-telegram/dist/lib/wire.js +1 -1
  135. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +3 -1
  136. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +425 -211
  137. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.js +8 -13
  138. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +1 -1
  139. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +328 -140
  140. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.js +8 -4
  141. package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
  142. package/node_modules/@llblab/pi-telegram/docs/architecture.md +43 -35
  143. package/node_modules/@llblab/pi-telegram/docs/inbound.md +1 -1
  144. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +15 -3
  145. package/node_modules/@llblab/pi-telegram/docs/outbound.md +1 -1
  146. package/node_modules/@llblab/pi-telegram/docs/public-api.md +29 -1
  147. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +25 -8
  148. package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +59 -82
  149. package/node_modules/@llblab/pi-telegram/lib/activity.ts +146 -102
  150. package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +12 -5
  151. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +390 -82
  152. package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +262 -99
  153. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +2440 -601
  154. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +2209 -1290
  155. package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +46 -12
  156. package/node_modules/@llblab/pi-telegram/lib/bus.ts +1673 -444
  157. package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +848 -327
  158. package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +152 -265
  159. package/node_modules/@llblab/pi-telegram/lib/commands.ts +2398 -555
  160. package/node_modules/@llblab/pi-telegram/lib/config.ts +177 -170
  161. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +41 -29
  162. package/node_modules/@llblab/pi-telegram/lib/extension.ts +1209 -431
  163. package/node_modules/@llblab/pi-telegram/lib/generative-app-worker.mjs +19 -7
  164. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +324 -211
  165. package/node_modules/@llblab/pi-telegram/lib/inbound.ts +95 -97
  166. package/node_modules/@llblab/pi-telegram/lib/journal.ts +5329 -1712
  167. package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +1 -3
  168. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +128 -78
  169. package/node_modules/@llblab/pi-telegram/lib/locks.ts +703 -212
  170. package/node_modules/@llblab/pi-telegram/lib/logging.ts +147 -58
  171. package/node_modules/@llblab/pi-telegram/lib/media.ts +82 -43
  172. package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +85 -18
  173. package/node_modules/@llblab/pi-telegram/lib/menu-queue.ts +88 -129
  174. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +260 -155
  175. package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +20 -60
  176. package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +41 -56
  177. package/node_modules/@llblab/pi-telegram/lib/menu.ts +112 -285
  178. package/node_modules/@llblab/pi-telegram/lib/model.ts +8 -22
  179. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +156 -125
  180. package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +76 -49
  181. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +96 -94
  182. package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +33 -27
  183. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +125 -125
  184. package/node_modules/@llblab/pi-telegram/lib/ownership.ts +19 -10
  185. package/node_modules/@llblab/pi-telegram/lib/paths.ts +148 -49
  186. package/node_modules/@llblab/pi-telegram/lib/pi.ts +35 -15
  187. package/node_modules/@llblab/pi-telegram/lib/polling.ts +165 -149
  188. package/node_modules/@llblab/pi-telegram/lib/preview.ts +93 -40
  189. package/node_modules/@llblab/pi-telegram/lib/process-identity.ts +164 -0
  190. package/node_modules/@llblab/pi-telegram/lib/prompts.ts +4 -11
  191. package/node_modules/@llblab/pi-telegram/lib/queue.ts +523 -289
  192. package/node_modules/@llblab/pi-telegram/lib/recovery.ts +50 -454
  193. package/node_modules/@llblab/pi-telegram/lib/rendering.ts +1 -3
  194. package/node_modules/@llblab/pi-telegram/lib/replies.ts +248 -209
  195. package/node_modules/@llblab/pi-telegram/lib/routing.ts +8527 -2149
  196. package/node_modules/@llblab/pi-telegram/lib/runtime.ts +1 -12
  197. package/node_modules/@llblab/pi-telegram/lib/sections.ts +24 -89
  198. package/node_modules/@llblab/pi-telegram/lib/setup.ts +1 -3
  199. package/node_modules/@llblab/pi-telegram/lib/skills.ts +9 -4
  200. package/node_modules/@llblab/pi-telegram/lib/status.ts +215 -110
  201. package/node_modules/@llblab/pi-telegram/lib/sync.ts +488 -359
  202. package/node_modules/@llblab/pi-telegram/lib/target.ts +22 -3
  203. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +322 -122
  204. package/node_modules/@llblab/pi-telegram/lib/text-groups.ts +5 -39
  205. package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +833 -331
  206. package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +213 -97
  207. package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +232 -87
  208. package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +155 -72
  209. package/node_modules/@llblab/pi-telegram/lib/threads.ts +5329 -1817
  210. package/node_modules/@llblab/pi-telegram/lib/time-injection.ts +1 -4
  211. package/node_modules/@llblab/pi-telegram/lib/turns.ts +15 -28
  212. package/node_modules/@llblab/pi-telegram/lib/updates.ts +5194 -1600
  213. package/node_modules/@llblab/pi-telegram/lib/voice.ts +7 -35
  214. package/node_modules/@llblab/pi-telegram/lib/wire.ts +1 -1
  215. package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +996 -416
  216. package/node_modules/@llblab/pi-telegram/lib/workspace-identity.ts +14 -17
  217. package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +878 -376
  218. package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +22 -13
  219. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  220. package/package.json +3 -3
  221. package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +0 -472
  222. package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +0 -108
@@ -7,15 +7,16 @@
7
7
  */
8
8
  import { randomUUID } from "node:crypto";
9
9
  import { createWriteStream, openAsBlob } from "node:fs";
10
- import { mkdir, readdir, rename, stat, unlink, writeFile } from "node:fs/promises";
10
+ import { mkdir, readdir, rename, stat, unlink, writeFile, } from "node:fs/promises";
11
11
  import { request as requestHttps } from "node:https";
12
12
  import { join } from "node:path";
13
- import { resolveTelegramAttachmentsDir } from "./paths.js";
14
13
  import { Readable, Transform } from "node:stream";
15
14
  import { pipeline } from "node:stream/promises";
15
+ import { resolveTelegramAttachmentsDir } from "./paths.js";
16
16
  const TELEGRAM_API_BASE = "https://api.telegram.org";
17
17
  export const TELEGRAM_FILE_MAX_BYTES = 50 * 1024 * 1024;
18
- export function getTelegramInboundFileByteLimitFromEnv(env, names, defaultValue = TELEGRAM_FILE_MAX_BYTES) {
18
+ /** First positive safe-integer byte limit among ordered env names, else the caller's default. */
19
+ export function getTelegramByteLimitFromEnv(env, names, defaultValue) {
19
20
  for (const name of names) {
20
21
  const rawValue = env[name]?.trim();
21
22
  if (!rawValue)
@@ -30,8 +31,9 @@ function getTelegramApiTempDir() {
30
31
  return resolveTelegramAttachmentsDir();
31
32
  }
32
33
  const TELEGRAM_TEMP_FILE_MAX_AGE_MS = 24 * 60 * 60 * 1000;
34
+ const TELEGRAM_DOWNLOAD_RENAME_MAX_ATTEMPTS = 6;
33
35
  const activeTelegramApiWorkspaceAdmissionOperationIds = new Set();
34
- const TELEGRAM_INBOUND_FILE_MAX_BYTES = getTelegramInboundFileByteLimitFromEnv(process.env, ["PI_TELEGRAM_INBOUND_FILE_MAX_BYTES", "TELEGRAM_MAX_FILE_SIZE_BYTES"], TELEGRAM_FILE_MAX_BYTES);
36
+ const TELEGRAM_INBOUND_FILE_MAX_BYTES = getTelegramByteLimitFromEnv(process.env, ["PI_TELEGRAM_INBOUND_FILE_MAX_BYTES", "TELEGRAM_MAX_FILE_SIZE_BYTES"], TELEGRAM_FILE_MAX_BYTES);
35
37
  const TELEGRAM_NETWORK_FAMILY_ENV = "PI_TELEGRAM_NETWORK_FAMILY";
36
38
  const TELEGRAM_NETWORK_FAMILY_VALUES = new Set([
37
39
  "auto",
@@ -39,10 +41,32 @@ const TELEGRAM_NETWORK_FAMILY_VALUES = new Set([
39
41
  "ipv6",
40
42
  "ipv4-fallback",
41
43
  ]);
44
+ export class TelegramApiAuthorityError extends Error {
45
+ requestIssued;
46
+ constructor(requestIssued) {
47
+ super("Telegram API call authority is unavailable.");
48
+ this.name = "TelegramApiAuthorityError";
49
+ this.requestIssued = requestIssued;
50
+ }
51
+ }
52
+ /** Recheck caller authority, classifying refusal by whether a Bot API request was already issued. */
53
+ export function assertTelegramApiCallAuthority(assertAuthority, requestIssued) {
54
+ try {
55
+ assertAuthority?.();
56
+ }
57
+ catch {
58
+ throw new TelegramApiAuthorityError(requestIssued);
59
+ }
60
+ }
42
61
  function parseTelegramApiTargetInteger(value) {
43
- const parsed = typeof value === "number" ? value :
44
- typeof value === "string" && /^-?\d+$/u.test(value) ? Number(value) : undefined;
45
- return parsed !== undefined && Number.isSafeInteger(parsed) ? parsed : undefined;
62
+ const parsed = typeof value === "number"
63
+ ? value
64
+ : typeof value === "string" && /^-?\d+$/u.test(value)
65
+ ? Number(value)
66
+ : undefined;
67
+ return parsed !== undefined && Number.isSafeInteger(parsed)
68
+ ? parsed
69
+ : undefined;
46
70
  }
47
71
  export function createTelegramApiTargetActivityRuntime() {
48
72
  const pending = new Map();
@@ -58,8 +82,10 @@ export function createTelegramApiTargetActivityRuntime() {
58
82
  const chatId = parseTelegramApiTargetInteger(body.chat_id);
59
83
  const threadId = parseTelegramApiTargetInteger(body.message_thread_id);
60
84
  const messageId = parseTelegramApiTargetInteger(body.message_id);
61
- const chatScoped = chatId !== undefined && threadId === undefined &&
62
- messageId !== undefined && messageScopedMethods.has(method);
85
+ const chatScoped = chatId !== undefined &&
86
+ threadId === undefined &&
87
+ messageId !== undefined &&
88
+ messageScopedMethods.has(method);
63
89
  if (chatId === undefined || (threadId === undefined && !chatScoped)) {
64
90
  return () => undefined;
65
91
  }
@@ -69,7 +95,10 @@ export function createTelegramApiTargetActivityRuntime() {
69
95
  if (existing)
70
96
  existing.count += 1;
71
97
  else
72
- pending.set(key, { target: { chatId, threadId: threadId }, count: 1 });
98
+ pending.set(key, {
99
+ target: { chatId, threadId: threadId },
100
+ count: 1,
101
+ });
73
102
  }
74
103
  else {
75
104
  pendingChats.set(chatId, (pendingChats.get(chatId) ?? 0) + 1);
@@ -95,8 +124,9 @@ export function createTelegramApiTargetActivityRuntime() {
95
124
  };
96
125
  },
97
126
  hasPendingTarget(target) {
98
- return pendingChats.has(target.chatId) ||
99
- (target.threadId !== undefined && pending.has(`${target.chatId}:${target.threadId}`));
127
+ return (pendingChats.has(target.chatId) ||
128
+ (target.threadId !== undefined &&
129
+ pending.has(`${target.chatId}:${target.threadId}`)));
100
130
  },
101
131
  listPendingTargets() {
102
132
  return Array.from(pending.values(), ({ target }) => ({ ...target }));
@@ -215,14 +245,27 @@ function sanitizeFileName(name) {
215
245
  export function createTelegramAttachmentFileName(source, generatedName, botScope) {
216
246
  const chat = source.chat;
217
247
  const clean = (value) => sanitizeFileName(value.replace(/^@/u, "")).replace(/^[-.]+/u, "");
218
- const scope = source.scope ? clean(source.scope) : chat?.type === "private" || !chat
219
- ? botScope ? clean(botScope) : chat ? String(Math.abs(chat.id)) : ""
220
- : chat.username ? clean(chat.username) : String(Math.abs(chat.id));
248
+ const scope = source.scope
249
+ ? clean(source.scope)
250
+ : chat?.type === "private" || !chat
251
+ ? botScope
252
+ ? clean(botScope)
253
+ : chat
254
+ ? String(Math.abs(chat.id))
255
+ : ""
256
+ : chat.username
257
+ ? clean(chat.username)
258
+ : String(Math.abs(chat.id));
221
259
  const dot = generatedName.lastIndexOf(".");
222
260
  const extension = dot > 0 ? sanitizeFileName(generatedName.slice(dot)) : "";
223
- const tail = source.userFileName ? `-${clean(source.userFileName)}` : extension;
224
- return [sanitizeFileName(source.kind), scope, String(source.messageId)].filter(Boolean).join("-") +
225
- (source.index !== undefined ? `-${source.index}` : "") + tail;
261
+ const tail = source.userFileName
262
+ ? `-${clean(source.userFileName)}`
263
+ : extension;
264
+ return ([sanitizeFileName(source.kind), scope, String(source.messageId)]
265
+ .filter(Boolean)
266
+ .join("-") +
267
+ (source.index !== undefined ? `-${source.index}` : "") +
268
+ tail);
226
269
  }
227
270
  class TelegramApiMalformedSuccessError extends Error {
228
271
  constructor(method, detail) {
@@ -287,8 +330,9 @@ export function isTelegramStaleTargetHttpError(error) {
287
330
  }
288
331
  /** Only a parsed Telegram rejection of this method proves a request had no effect. */
289
332
  export function isTelegramApiRequestRejected(error, method) {
290
- return error instanceof TelegramApiHttpError && error.rejectedRequestMethod !== undefined &&
291
- error.rejectedRequestMethod === method;
333
+ return (error instanceof TelegramApiHttpError &&
334
+ error.rejectedRequestMethod !== undefined &&
335
+ error.rejectedRequestMethod === method);
292
336
  }
293
337
  export function isTelegramMessageNotModifiedError(error) {
294
338
  return (error instanceof Error && error.message.includes("message is not modified"));
@@ -321,13 +365,15 @@ export function isRetryableTelegramApiError(error) {
321
365
  (error.status !== undefined && error.status >= 500)));
322
366
  }
323
367
  export function getTelegramApiRetryAfterMs(error) {
324
- return error instanceof TelegramApiHttpError && error.retryAfterSeconds !== undefined
368
+ return error instanceof TelegramApiHttpError &&
369
+ error.retryAfterSeconds !== undefined
325
370
  ? Math.max(0, error.retryAfterSeconds * 1000)
326
371
  : undefined;
327
372
  }
328
373
  export function isTelegramMessageUnavailableError(error) {
329
- return error instanceof TelegramApiHttpError && error.status === 400 &&
330
- /Bad Request: (message to edit not found|message not found|message_id_invalid)/iu.test(error.message);
374
+ return (error instanceof TelegramApiHttpError &&
375
+ error.status === 400 &&
376
+ /Bad Request: (message to edit not found|message not found|message_id_invalid)/iu.test(error.message));
331
377
  }
332
378
  function getTelegramRetryDelayMs(error, attempt, baseDelayMs) {
333
379
  if (error instanceof TelegramApiHttpError &&
@@ -391,6 +437,24 @@ async function writeTelegramDownloadResponse(response, targetPath, maxFileSizeBy
391
437
  }
392
438
  await pipeline(Readable.from(response.body, { objectMode: false }), createTelegramDownloadLimitTransform(maxFileSizeBytes), createWriteStream(targetPath, { mode: 0o600 }));
393
439
  }
440
+ async function publishTelegramDownload(partPath, targetPath, signal) {
441
+ for (let attempt = 0;; attempt++) {
442
+ throwIfTelegramApiCallAborted(signal);
443
+ try {
444
+ await rename(partPath, targetPath);
445
+ return;
446
+ }
447
+ catch (error) {
448
+ const code = error?.code;
449
+ // Windows may briefly deny replacement while another publisher/scanner holds the file.
450
+ if (process.platform !== "win32" ||
451
+ (code !== "EPERM" && code !== "EACCES") ||
452
+ attempt + 1 >= TELEGRAM_DOWNLOAD_RENAME_MAX_ATTEMPTS)
453
+ throw error;
454
+ await sleepTelegramRetry(50 * 2 ** attempt, signal);
455
+ }
456
+ }
457
+ }
394
458
  async function removeTelegramPartialDownload(path) {
395
459
  try {
396
460
  await unlink(path);
@@ -421,8 +485,11 @@ async function parseTelegramApiResponse(response, method) {
421
485
  const retryAfterHeader = response.headers?.get("retry-after");
422
486
  const retryAfterSeconds = data?.parameters?.retry_after ??
423
487
  (retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : undefined);
424
- throw new TelegramApiHttpError(`Telegram API ${method} failed: ${status}${description}`, response.status, Number.isFinite(retryAfterSeconds) ? retryAfterSeconds : undefined, data?.ok === false && data.error_code === response.status &&
425
- [400, 401, 403, 404, 429].includes(response.status) ? method : undefined);
488
+ throw new TelegramApiHttpError(`Telegram API ${method} failed: ${status}${description}`, response.status, Number.isFinite(retryAfterSeconds) ? retryAfterSeconds : undefined, data?.ok === false &&
489
+ data.error_code === response.status &&
490
+ [400, 401, 403, 404, 429].includes(response.status)
491
+ ? method
492
+ : undefined);
426
493
  }
427
494
  if (!data) {
428
495
  throw new TelegramApiMalformedSuccessError(method, "returned invalid JSON");
@@ -621,6 +688,12 @@ function withTelegramTransportDiagnostics(error, details) {
621
688
  return transport ? { ...details, transport } : details;
622
689
  }
623
690
  async function callTelegramWithRetry(method, request, options) {
691
+ const assertAuthority = options?.assertAuthority;
692
+ let requestIssued = false;
693
+ const beforeRequest = () => {
694
+ assertTelegramApiCallAuthority(assertAuthority, requestIssued);
695
+ requestIssued = true;
696
+ };
624
697
  const retrySafe = options?.retrySafety === "safe" ||
625
698
  (options?.retrySafety !== "non-idempotent" &&
626
699
  isTelegramApiMethodRetrySafe(method));
@@ -648,10 +721,17 @@ async function callTelegramWithRetry(method, request, options) {
648
721
  };
649
722
  for (let attempt = 0;; attempt += 1) {
650
723
  throwIfTelegramApiCallAborted(options?.signal);
724
+ assertTelegramApiCallAuthority(assertAuthority, requestIssued);
651
725
  try {
652
- return unwrapTelegramApiResult(method, await parseTelegramApiResponse(await callTelegramTransportRequest(request, retrySafe), method));
726
+ const result = unwrapTelegramApiResult(method, await parseTelegramApiResponse(await callTelegramTransportRequest((family) => request(family, beforeRequest), retrySafe), method));
727
+ assertTelegramApiCallAuthority(assertAuthority, requestIssued);
728
+ return result;
653
729
  }
654
730
  catch (error) {
731
+ // Authority refusal is never a transport failure, retry grant or acknowledged success.
732
+ if (error instanceof TelegramApiAuthorityError)
733
+ throw error;
734
+ assertTelegramApiCallAuthority(assertAuthority, requestIssued);
655
735
  const retryable = isRetryableTelegramApiError(error) &&
656
736
  !(options?.retryRateLimit === false &&
657
737
  error instanceof TelegramApiHttpError &&
@@ -717,12 +797,16 @@ function assertTelegramBotTokenConfigured(botToken) {
717
797
  export async function callTelegram(botToken, method, body, options) {
718
798
  const configuredBotToken = assertTelegramBotTokenConfigured(botToken);
719
799
  try {
720
- return await callTelegramWithRetry(method, async (family) => telegramFetch(`${TELEGRAM_API_BASE}/bot${configuredBotToken}/${method}`, {
721
- method: "POST",
722
- headers: { "content-type": "application/json" },
723
- body: JSON.stringify(body),
724
- signal: options?.signal,
725
- }, family), options);
800
+ return await callTelegramWithRetry(method, async (family, beforeRequest) => {
801
+ const encodedBody = JSON.stringify(body);
802
+ beforeRequest();
803
+ return telegramFetch(`${TELEGRAM_API_BASE}/bot${configuredBotToken}/${method}`, {
804
+ method: "POST",
805
+ headers: { "content-type": "application/json" },
806
+ body: encodedBody,
807
+ signal: options?.signal,
808
+ }, family);
809
+ }, options);
726
810
  }
727
811
  catch (error) {
728
812
  attachTelegramApiRequestTarget(error, body);
@@ -742,11 +826,14 @@ export async function fetchTelegramBotIdentity(botToken, fetchImpl = fetch) {
742
826
  */
743
827
  export async function callTelegramMultipart(botToken, method, fields, fileField, filePath, fileName, options) {
744
828
  const configuredBotToken = assertTelegramBotTokenConfigured(botToken);
829
+ options = options && { ...options };
830
+ assertTelegramApiCallAuthority(options?.assertAuthority, false);
745
831
  const fileBlob = await openAsBlob(filePath);
746
832
  try {
747
- return await callTelegramWithRetry(method, async (family) => {
833
+ return await callTelegramWithRetry(method, async (family, beforeRequest) => {
748
834
  if (family) {
749
835
  const multipart = await buildTelegramMultipartBody(fields, fileField, fileBlob, fileName);
836
+ beforeRequest();
750
837
  return telegramFetch(`${TELEGRAM_API_BASE}/bot${configuredBotToken}/${method}`, {
751
838
  method: "POST",
752
839
  headers: { "content-type": multipart.contentType },
@@ -759,6 +846,7 @@ export async function callTelegramMultipart(botToken, method, fields, fileField,
759
846
  form.set(key, value);
760
847
  }
761
848
  form.set(fileField, fileBlob, fileName);
849
+ beforeRequest();
762
850
  return telegramFetch(`${TELEGRAM_API_BASE}/bot${configuredBotToken}/${method}`, {
763
851
  method: "POST",
764
852
  body: form,
@@ -787,7 +875,7 @@ export async function downloadTelegramFile(botToken, fileId, suggestedName, temp
787
875
  assertTelegramFileSizeWithinLimit(contentLength ? Number.parseInt(contentLength, 10) : undefined, options?.maxFileSizeBytes);
788
876
  try {
789
877
  await writeTelegramDownloadResponse(response, partPath, options?.maxFileSizeBytes);
790
- await rename(partPath, targetPath);
878
+ await publishTelegramDownload(partPath, targetPath, options?.signal);
791
879
  }
792
880
  catch (error) {
793
881
  await removeTelegramPartialDownload(partPath);
@@ -799,12 +887,16 @@ export async function answerTelegramCallbackQuery(botToken, callbackQueryId, tex
799
887
  try {
800
888
  await callTelegram(botToken, "answerCallbackQuery", text
801
889
  ? { callback_query_id: callbackQueryId, text }
802
- : { callback_query_id: callbackQueryId });
890
+ : { callback_query_id: callbackQueryId }, options.assertAuthority
891
+ ? { assertAuthority: options.assertAuthority }
892
+ : undefined);
803
893
  }
804
894
  catch (error) {
805
895
  options.recordRuntimeEvent?.("api", error, withTelegramTransportDiagnostics(error, {
806
896
  method: "answerCallbackQuery",
807
897
  }));
898
+ if (error instanceof TelegramApiAuthorityError)
899
+ throw error;
808
900
  }
809
901
  }
810
902
  export function createTelegramChatActionSender(sendChatAction, action) {
@@ -889,7 +981,8 @@ export function createDefaultTelegramBridgeApiRuntime(deps) {
889
981
  // The exclusive deletion permit replaces ordinary target admission.
890
982
  const target = authorize();
891
983
  const deleted = await client.call("deleteForumTopic", {
892
- chat_id: target.chatId, message_thread_id: target.threadId,
984
+ chat_id: target.chatId,
985
+ message_thread_id: target.threadId,
893
986
  }, { maxAttempts: 1, retrySafety: "non-idempotent" });
894
987
  if (deleted !== true)
895
988
  throw new Error("Telegram Workspace Thread deletion was not confirmed.");
@@ -902,7 +995,9 @@ export function createTelegramBridgeApiRuntime(deps) {
902
995
  await handler?.(error);
903
996
  }
904
997
  catch (recoveryError) {
905
- deps.recordRuntimeEvent("api", recoveryError, { phase: "stale-target-recovery" });
998
+ deps.recordRuntimeEvent("api", recoveryError, {
999
+ phase: "stale-target-recovery",
1000
+ });
906
1001
  }
907
1002
  };
908
1003
  const now = deps.now ?? Date.now;
@@ -1007,9 +1102,11 @@ export function createTelegramBridgeApiRuntime(deps) {
1007
1102
  }
1008
1103
  catch (error) {
1009
1104
  await recoverRequestError(recoverError, error);
1010
- if (method === "deleteMessage" && error instanceof TelegramApiHttpError &&
1011
- error.status === 400 && error.message ===
1012
- "Telegram API deleteMessage failed: HTTP 400: Bad Request: message to delete not found") {
1105
+ if (method === "deleteMessage" &&
1106
+ error instanceof TelegramApiHttpError &&
1107
+ error.status === 400 &&
1108
+ error.message ===
1109
+ "Telegram API deleteMessage failed: HTTP 400: Bad Request: message to delete not found") {
1013
1110
  return true;
1014
1111
  }
1015
1112
  deps.recordRuntimeEvent("api", error, withTelegramTransportDiagnostics(error, { method }));
@@ -1053,7 +1150,7 @@ export function createTelegramBridgeApiRuntime(deps) {
1053
1150
  },
1054
1151
  deleteWebhook: (signal) => callRecorded("deleteWebhook", { drop_pending_updates: false }, { signal }),
1055
1152
  getUpdates: (body, signal) => callRecorded("getUpdates", body, { signal }),
1056
- setMyCommands: (commands) => callRecorded("setMyCommands", { commands }),
1153
+ setMyCommands: (commands, options) => callRecorded("setMyCommands", { commands }, options),
1057
1154
  sendChatAction: (chatId, action, options) => callRecorded("sendChatAction", {
1058
1155
  chat_id: chatId,
1059
1156
  action,
@@ -1090,13 +1187,13 @@ export function createTelegramBridgeApiRuntime(deps) {
1090
1187
  body.message_thread_id = options.message_thread_id;
1091
1188
  return callRecorded("sendMessageDraft", body);
1092
1189
  },
1093
- sendMessage: (body) => callRecorded("sendMessage", body),
1094
- sendRichMessage: (body) => callRecorded("sendRichMessage", body),
1190
+ sendMessage: (body, options) => callRecorded("sendMessage", body, options),
1191
+ sendRichMessage: (body, options) => callRecorded("sendRichMessage", body, options),
1095
1192
  sendRichMessageDraft: (body) => callRecorded("sendRichMessageDraft", body),
1096
- editMessageText: async (body) => {
1193
+ editMessageText: async (body, options) => {
1097
1194
  const recoverError = deps.captureRequestErrorHandler?.(body);
1098
1195
  try {
1099
- await deps.client.call("editMessageText", body);
1196
+ await deps.client.call("editMessageText", body, options);
1100
1197
  return "edited";
1101
1198
  }
1102
1199
  catch (error) {
@@ -1116,7 +1213,19 @@ export function createTelegramBridgeApiRuntime(deps) {
1116
1213
  reply_markup: replyMarkup,
1117
1214
  });
1118
1215
  },
1119
- answerCallbackQuery: async (callbackQueryId, text) => {
1216
+ answerCallbackQuery: async (callbackQueryId, text, options) => {
1217
+ if (options?.assertAuthority) {
1218
+ try {
1219
+ await callRecorded("answerCallbackQuery", text
1220
+ ? { callback_query_id: callbackQueryId, text }
1221
+ : { callback_query_id: callbackQueryId }, { assertAuthority: options.assertAuthority });
1222
+ }
1223
+ catch (error) {
1224
+ if (error instanceof TelegramApiAuthorityError)
1225
+ throw error;
1226
+ }
1227
+ return;
1228
+ }
1120
1229
  try {
1121
1230
  await deps.client.answerCallbackQuery(callbackQueryId, text);
1122
1231
  }
@@ -1124,6 +1233,8 @@ export function createTelegramBridgeApiRuntime(deps) {
1124
1233
  deps.recordRuntimeEvent("api", error, withTelegramTransportDiagnostics(error, {
1125
1234
  method: "answerCallbackQuery",
1126
1235
  }));
1236
+ if (error instanceof TelegramApiAuthorityError)
1237
+ throw error;
1127
1238
  }
1128
1239
  },
1129
1240
  answerGuestQuery: (guestQueryId, text, options) => callRecorded("answerGuestQuery", buildTelegramAnswerGuestQueryBody(guestQueryId, text, options)),
@@ -1198,7 +1309,8 @@ export function createTelegramApiClient(getBotToken, options = {}) {
1198
1309
  }
1199
1310
  catch (error) {
1200
1311
  if (draftKey && isRetryableTelegramApiError(error)) {
1201
- draftRetryNotBeforeByTarget.set(draftKey, Math.max(draftRetryNotBeforeByTarget.get(draftKey) ?? 0, now() + getTelegramRetryDelayMs(error, 0, options?.retryBaseDelayMs ?? 500)));
1312
+ draftRetryNotBeforeByTarget.set(draftKey, Math.max(draftRetryNotBeforeByTarget.get(draftKey) ?? 0, now() +
1313
+ getTelegramRetryDelayMs(error, 0, options?.retryBaseDelayMs ?? 500)));
1202
1314
  }
1203
1315
  throw error;
1204
1316
  }
@@ -1209,8 +1321,12 @@ export function createTelegramApiClient(getBotToken, options = {}) {
1209
1321
  downloadFile: async (fileId, suggestedName, tempDir, options) => {
1210
1322
  return downloadTelegramFile(getBotToken(), fileId, suggestedName, tempDir, options);
1211
1323
  },
1212
- answerCallbackQuery: async (callbackQueryId, text) => {
1213
- await answerTelegramCallbackQuery(getBotToken(), callbackQueryId, text, options);
1324
+ answerCallbackQuery: async (callbackQueryId, text, authorityOptions) => {
1325
+ const assertAuthority = authorityOptions?.assertAuthority;
1326
+ const callbackOptions = assertAuthority
1327
+ ? { ...options, assertAuthority }
1328
+ : options;
1329
+ await answerTelegramCallbackQuery(getBotToken(), callbackQueryId, text, callbackOptions);
1214
1330
  },
1215
1331
  };
1216
1332
  }
@@ -4,7 +4,7 @@
4
4
  * Owns conservative delayed grouping for Telegram text messages that look like automatic long-message splits
5
5
  */
6
6
  import { setTimeout as waitForTimeout } from "node:timers/promises";
7
- import { extractTelegramMessageText, } from "./media.js";
7
+ import { createTelegramPendingGroupLifecycle, extractTelegramMessageText, } from "./media.js";
8
8
  const TELEGRAM_TEXT_GROUP_DEBOUNCE_MS = 1000;
9
9
  const TELEGRAM_TEXT_GROUP_MIN_SPLIT_LENGTH = 3600;
10
10
  const TELEGRAM_TEXT_GROUP_MAX_MESSAGE_ID_GAP = 12;
@@ -155,6 +155,7 @@ export function createTelegramTextGroupController(options = {}) {
155
155
  : (timer) => {
156
156
  timer.abort();
157
157
  });
158
+ const lifecycle = createTelegramPendingGroupLifecycle(groups, clearTimer);
158
159
  return {
159
160
  prepareUpdateBatch(updates) {
160
161
  for (let index = 0; index + 1 < updates.length; index += 1) {
@@ -249,45 +250,9 @@ export function createTelegramTextGroupController(options = {}) {
249
250
  : undefined,
250
251
  });
251
252
  },
252
- async flushMessage(messageId) {
253
- for (const state of groups.values()) {
254
- if (!state.messages.some((message) => message.message_id === messageId)) {
255
- continue;
256
- }
257
- if (state.flushTimer)
258
- clearTimer(state.flushTimer);
259
- state.flushTimer = undefined;
260
- await state.dispatchNow?.();
261
- if (state.messages.some((message) => message.message_id === messageId) &&
262
- !state.dispatching) {
263
- await state.dispatchNow?.();
264
- }
265
- return true;
266
- }
267
- return false;
268
- },
269
- suspend: () => {
270
- for (const state of groups.values()) {
271
- state.suspended = true;
272
- if (state.flushTimer)
273
- clearTimer(state.flushTimer);
274
- state.flushTimer = undefined;
275
- }
276
- },
277
- resume: (context) => {
278
- for (const state of groups.values()) {
279
- state.context = context;
280
- state.suspended = false;
281
- if (!state.dispatching && !state.flushTimer)
282
- state.reschedule?.();
283
- }
284
- },
253
+ ...lifecycle,
285
254
  clear: () => {
286
- for (const state of groups.values()) {
287
- if (state.flushTimer)
288
- clearTimer(state.flushTimer);
289
- }
290
- groups.clear();
255
+ lifecycle.clear();
291
256
  plannedForwardCommentStarts.clear();
292
257
  plannedForwardCommentEnds.clear();
293
258
  },
@@ -64,8 +64,8 @@ export declare function planTelegramInactiveThreadCleanup(input: {
64
64
  threadId: number;
65
65
  }[];
66
66
  }): TelegramThreadCleanupCandidate[];
67
- export declare function captureTelegramInactiveThreadCleanupEvidence<TBinding extends TelegramThreadCleanupBindingSnapshot>(input: {
68
- profileName: string;
67
+ /** Read ports for the bindings and target claims that cleanup evidence is captured from. */
68
+ export interface TelegramInactiveThreadCleanupEvidencePorts<TBinding extends TelegramThreadCleanupBindingSnapshot> {
69
69
  listBindings(): readonly TBinding[];
70
70
  getProtection(binding: TBinding): {
71
71
  liveOwner: TelegramThreadCleanupProtectionState;
@@ -90,33 +90,12 @@ export declare function captureTelegramInactiveThreadCleanupEvidence<TBinding ex
90
90
  threadId: number;
91
91
  };
92
92
  }[];
93
+ }
94
+ export declare function captureTelegramInactiveThreadCleanupEvidence<TBinding extends TelegramThreadCleanupBindingSnapshot>(input: TelegramInactiveThreadCleanupEvidencePorts<TBinding> & {
95
+ profileName: string;
93
96
  }): Parameters<typeof planTelegramInactiveThreadCleanup>[0];
94
- export declare function createTelegramInactiveThreadCleanupReviewRuntime<TBinding extends TelegramThreadCleanupBindingSnapshot>(deps: {
97
+ export declare function createTelegramInactiveThreadCleanupReviewRuntime<TBinding extends TelegramThreadCleanupBindingSnapshot>(deps: TelegramInactiveThreadCleanupEvidencePorts<TBinding> & {
95
98
  getProfileName(): string;
96
- listBindings(): readonly TBinding[];
97
- getProtection(binding: TBinding): {
98
- liveOwner: TelegramThreadCleanupProtectionState;
99
- acceptedWork: TelegramThreadCleanupProtectionState;
100
- deliveryAuthority: TelegramThreadCleanupProtectionState;
101
- };
102
- listReservations(): readonly {
103
- target: {
104
- chatId: number;
105
- threadId: number;
106
- };
107
- }[];
108
- listPendingProvisions(): readonly {
109
- target?: {
110
- chatId: number;
111
- threadId: number;
112
- };
113
- }[];
114
- listPendingCleanups(): readonly {
115
- target: {
116
- chatId: number;
117
- threadId: number;
118
- };
119
- }[];
120
99
  getWorkStore(): TelegramThreadCleanupWorkStore;
121
100
  runWorkspaceOperation<T>(input: {
122
101
  operationId: string;