@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
@@ -8,7 +8,8 @@ const DEFAULT_FRESH_CREATION_GRACE_MS = 30_000;
8
8
  function targetKey(target) {
9
9
  return `${target.chatId}:${target.threadId}`;
10
10
  }
11
- function isCurrentRecord(record) {
11
+ /** A Thread record still claims its slot/target while active, starting or pending. */
12
+ export function isCurrentThreadRecord(record) {
12
13
  return (record.status === "active" ||
13
14
  record.status === "starting" ||
14
15
  record.status === "pending");
@@ -50,13 +51,12 @@ function isCleanupAction(action) {
50
51
  action.kind === "close-stale-replaced-topic" ||
51
52
  action.kind === "close-delete-replaced-follower-topic" ||
52
53
  action.kind === "close-delete-previous-leader-topic" ||
53
- action.kind === "close-delete-disconnected-instance-topic" ||
54
54
  action.kind === "close-delete-graceful-shutdown-topic" ||
55
55
  action.kind === "cancel-superseded-graceful-shutdown-cleanup" ||
56
56
  action.kind === "close-delete-expired-pending-provision-topic");
57
57
  }
58
58
  function isSyncAction(action) {
59
- return action.kind === "mark-topic-active" || action.kind === "mark-topic-stale";
59
+ return (action.kind === "mark-topic-active" || action.kind === "mark-topic-stale");
60
60
  }
61
61
  function createThreadReconciliationMachineState(input, actions) {
62
62
  const pendingProvisionCount = (input.pendingProvisions ?? []).filter((provision) => isPendingProvisionAlive(provision, input.nowMs, input.currentLeaderEpoch)).length;
@@ -101,26 +101,34 @@ function createThreadReconciliationTransition(previous, current) {
101
101
  function getActionLeaderEpoch(action) {
102
102
  return "leaderEpoch" in action ? action.leaderEpoch : undefined;
103
103
  }
104
+ /** Pure Bot API vocabulary for a deleted/missing Thread; callers own their HTTP-status policy. */
105
+ export function isTelegramTopicDeletedErrorMessage(message) {
106
+ const text = message.toLowerCase();
107
+ return [
108
+ "topic_id_invalid",
109
+ "message thread not found",
110
+ "thread not found",
111
+ "topic not found",
112
+ "topic deleted",
113
+ ].some((fragment) => text.includes(fragment));
114
+ }
115
+ /** Pure Bot API vocabulary for a closed Thread; closure is not deletion evidence. */
116
+ export function isTelegramTopicClosedErrorMessage(message) {
117
+ const text = message.toLowerCase();
118
+ return [
119
+ "topic closed",
120
+ "thread closed",
121
+ "forum topic closed",
122
+ "message thread closed",
123
+ ].some((fragment) => text.includes(fragment));
124
+ }
104
125
  function isTelegramTopicTargetDeletedOrMissingError(error) {
105
- if (!(error instanceof Error))
106
- return false;
107
- const message = error.message.toLowerCase();
108
- return (message.includes("topic_id_invalid") ||
109
- message.includes("message thread not found") ||
110
- message.includes("thread not found") ||
111
- message.includes("topic not found") ||
112
- message.includes("topic deleted"));
126
+ return (error instanceof Error && isTelegramTopicDeletedErrorMessage(error.message));
113
127
  }
114
128
  function isTelegramTopicTargetGoneError(error) {
115
- if (isTelegramTopicTargetDeletedOrMissingError(error))
116
- return true;
117
- if (!(error instanceof Error))
118
- return false;
119
- const message = error.message.toLowerCase();
120
- return (message.includes("topic closed") ||
121
- message.includes("thread closed") ||
122
- message.includes("forum topic closed") ||
123
- message.includes("message thread closed"));
129
+ return (error instanceof Error &&
130
+ (isTelegramTopicDeletedErrorMessage(error.message) ||
131
+ isTelegramTopicClosedErrorMessage(error.message)));
124
132
  }
125
133
  function shouldSkipForStaleLeaderEpoch(action, ports) {
126
134
  const actionLeaderEpoch = getActionLeaderEpoch(action);
@@ -178,21 +186,58 @@ export function createThreadReconciliationRuntime(deps) {
178
186
  },
179
187
  };
180
188
  }
181
- export function planDisconnectedInstanceThreadCleanup(input) {
189
+ export function prepareLiveRebindThreadCleanup(input) {
190
+ const { operationId, oldTarget, recipientTarget, leaderEpoch, work } = input;
191
+ const validTarget = (target) => Number.isSafeInteger(target?.chatId) &&
192
+ target.chatId !== 0 &&
193
+ Number.isSafeInteger(target.threadId) &&
194
+ target.threadId > 0;
195
+ if (!operationId?.trim() ||
196
+ !leaderEpoch?.trim() ||
197
+ !validTarget(oldTarget) ||
198
+ !validTarget(recipientTarget) ||
199
+ oldTarget.chatId !== recipientTarget.chatId ||
200
+ oldTarget.threadId === recipientTarget.threadId ||
201
+ input.targetProtected !== false ||
202
+ work?.sessionBusy !== false ||
203
+ work.targetWork !== false ||
204
+ work.deliveryPending !== false ||
205
+ work.unknown !== false)
206
+ return undefined;
182
207
  return {
183
- actions: [
184
- {
185
- kind: "close-delete-disconnected-instance-topic",
186
- target: input.target,
187
- reason: "manual-disconnect",
188
- instanceId: input.instanceId,
189
- ...(input.leaderEpoch !== undefined
190
- ? { leaderEpoch: input.leaderEpoch }
191
- : {}),
192
- },
193
- ],
208
+ status: "prepared",
209
+ operationId,
210
+ target: { ...oldTarget },
211
+ recipientTarget: { ...recipientTarget },
212
+ leaderEpoch,
194
213
  };
195
214
  }
215
+ /**
216
+ * One unretried deletion for an already issued live-rebind cleanup grant. Success or confirmed absence is `confirmed`;
217
+ * protection or authority loss before the request and a definite request rejection are `failed`; every other outcome is
218
+ * `unknown`. The caller owns the durable issue marker and terminal record; this never repeats or rolls back.
219
+ */
220
+ export async function issueLiveRebindThreadCleanup(prepared, ports) {
221
+ const target = { ...prepared.target };
222
+ try {
223
+ ports.assertCurrent();
224
+ }
225
+ catch {
226
+ return "failed";
227
+ }
228
+ try {
229
+ await ports.deleteTopic(target);
230
+ }
231
+ catch (error) {
232
+ const failure = ports.classifyFailure(error);
233
+ return failure === "absent"
234
+ ? "confirmed"
235
+ : failure === "rejected"
236
+ ? "failed"
237
+ : "unknown";
238
+ }
239
+ return "confirmed";
240
+ }
196
241
  export async function applyThreadReconciliationPlan(plan, ports) {
197
242
  let shouldPersist = false;
198
243
  const persistFences = [];
@@ -276,7 +321,6 @@ export async function applyThreadReconciliationPlan(plan, ports) {
276
321
  action.kind === "close-delete-reserved-topic" ||
277
322
  action.kind === "close-delete-replaced-follower-topic" ||
278
323
  action.kind === "close-delete-previous-leader-topic" ||
279
- action.kind === "close-delete-disconnected-instance-topic" ||
280
324
  action.kind === "close-delete-graceful-shutdown-topic" ||
281
325
  action.kind === "close-delete-expired-pending-provision-topic") {
282
326
  if (shouldSkipForStaleLeaderEpoch(action, ports)) {
@@ -295,7 +339,9 @@ export async function applyThreadReconciliationPlan(plan, ports) {
295
339
  }
296
340
  let deleteConfirmed = false;
297
341
  let superseded = false;
298
- for (const method of ports.skipCloseBeforeDelete ? ["deleteForumTopic"] : ["closeForumTopic", "deleteForumTopic"]) {
342
+ for (const method of ports.skipCloseBeforeDelete
343
+ ? ["deleteForumTopic"]
344
+ : ["closeForumTopic", "deleteForumTopic"]) {
299
345
  if (ports.isCleanupTargetProtected?.(action.target, action)) {
300
346
  superseded = true;
301
347
  break;
@@ -331,7 +377,8 @@ export async function applyThreadReconciliationPlan(plan, ports) {
331
377
  incompleteActions.push(action);
332
378
  continue;
333
379
  }
334
- if (superseded || ports.isCleanupTargetProtected?.(action.target, action)) {
380
+ if (superseded ||
381
+ ports.isCleanupTargetProtected?.(action.target, action)) {
335
382
  ports.recordRuntimeEvent?.("telegram", "Cancelled cleanup of a protected Telegram target", {
336
383
  phase: "thread-reconciler-cleanup-target-reused",
337
384
  action: action.kind,
@@ -356,7 +403,6 @@ export async function applyThreadReconciliationPlan(plan, ports) {
356
403
  continue;
357
404
  if (action.kind !== "close-delete-previous-leader-topic" &&
358
405
  action.kind !== "close-delete-replaced-follower-topic" &&
359
- action.kind !== "close-delete-disconnected-instance-topic" &&
360
406
  action.kind !== "close-delete-expired-pending-provision-topic") {
361
407
  const changed = ports.markStaleByTarget?.(action.target, "deleted") ?? false;
362
408
  if (changed)
@@ -371,11 +417,9 @@ export async function applyThreadReconciliationPlan(plan, ports) {
371
417
  ? "Replaced follower Telegram topic deleted"
372
418
  : action.kind === "close-delete-previous-leader-topic"
373
419
  ? "Previous leader Telegram topic deleted"
374
- : action.kind === "close-delete-disconnected-instance-topic"
375
- ? "Disconnected instance Telegram topic deleted"
376
- : action.kind === "close-delete-graceful-shutdown-topic"
377
- ? "Graceful shutdown Telegram topic deleted"
378
- : "Expired pending provision Telegram topic deleted", {
420
+ : action.kind === "close-delete-graceful-shutdown-topic"
421
+ ? "Graceful shutdown Telegram topic deleted"
422
+ : "Expired pending provision Telegram topic deleted", {
379
423
  phase: action.kind === "close-delete-unbound-topic"
380
424
  ? "thread-reconciler-unbound-topic-delete"
381
425
  : action.kind === "close-delete-reserved-topic"
@@ -384,13 +428,9 @@ export async function applyThreadReconciliationPlan(plan, ports) {
384
428
  ? "thread-reconciler-replaced-follower-topic-delete"
385
429
  : action.kind === "close-delete-previous-leader-topic"
386
430
  ? "thread-reconciler-previous-leader-topic-delete"
387
- : action.kind ===
388
- "close-delete-disconnected-instance-topic"
389
- ? "thread-reconciler-disconnected-instance-topic-delete"
390
- : action.kind ===
391
- "close-delete-graceful-shutdown-topic"
392
- ? "thread-reconciler-graceful-shutdown-topic-delete"
393
- : "thread-reconciler-expired-pending-provision-topic-delete",
431
+ : action.kind === "close-delete-graceful-shutdown-topic"
432
+ ? "thread-reconciler-graceful-shutdown-topic-delete"
433
+ : "thread-reconciler-expired-pending-provision-topic-delete",
394
434
  chatId: action.target.chatId,
395
435
  threadId: action.target.threadId,
396
436
  ...("messageId" in action ? { messageId: action.messageId } : {}),
@@ -436,7 +476,7 @@ export function planThreadReconciliation(input) {
436
476
  const graceMs = input.freshCreationGraceMs ?? DEFAULT_FRESH_CREATION_GRACE_MS;
437
477
  const knownTargets = new Set(input.records.map((record) => targetKey(record.target)));
438
478
  const currentTargets = new Set(input.records
439
- .filter(isCurrentRecord)
479
+ .filter(isCurrentThreadRecord)
440
480
  .map((record) => targetKey(record.target)));
441
481
  const reservedTargets = new Set((input.reservations ?? [])
442
482
  .filter((reservation) => isReservationAlive(reservation, input.nowMs))
@@ -449,7 +489,7 @@ export function planThreadReconciliation(input) {
449
489
  .map((observation) => targetKey(observation.target)));
450
490
  const actions = [];
451
491
  for (const cleanup of input.pendingCleanups ?? []) {
452
- const superseded = input.records.some((record) => isCurrentRecord(record) &&
492
+ const superseded = input.records.some((record) => isCurrentThreadRecord(record) &&
453
493
  targetKey(record.target) === targetKey(cleanup.target) &&
454
494
  record.instanceId !== cleanup.instanceId);
455
495
  const common = {
@@ -3,15 +3,13 @@
3
3
  * Zones: multi-instance bus, Telegram UI threads, durable Workspace state
4
4
  * Owns live mappings, Workspace bindings and guarded Restore transitions; routing and transport effects stay outside.
5
5
  */
6
- import { type TelegramApiCallOptions } from "./telegram-api.ts";
7
6
  import { type TelegramTarget } from "./target.ts";
8
- export { chooseTelegramThreadName, createTelegramThreadName, getTelegramManualThreadDisplayNameValidationError, getTelegramTopicIdentityName, getTelegramTopicThreadNameValidationError, getTelegramTopicTitleForThreadName, isTelegramTopicThreadNameValidForSlot, type TelegramThreadNameInput, } from "./thread-naming.ts";
9
- export declare const getTelegramTopicName: (request: TelegramTopicTargetProvisionRequest, template?: string, slot?: string) => string;
10
- import { type TelegramWorkspaceBindingIdentity } from "./workspace-identity.ts";
11
- export { createTelegramWorkspaceBindingIdentity, createTelegramWorkspaceDirectoryKey, normalizeTelegramSessionId, normalizeTelegramWorkspacePath, type TelegramWorkspaceBindingIdentity, } from "./workspace-identity.ts";
12
- import { type TelegramLockRuntime, type TelegramLockContext, type TelegramRuntimeStateMutation, type TelegramOwnedStatePublicationOptions, type TelegramOwnedStatePublicationResult } from "./locks.ts";
7
+ import { type TelegramApiCallOptions } from "./telegram-api.ts";
8
+ import { type TelegramLockContext, type TelegramLockRuntime, type TelegramOwnedStatePublicationOptions, type TelegramOwnedStatePublicationResult, type TelegramRuntimeStateMutation } from "./locks.ts";
13
9
  import * as ThreadReconciler from "./thread-reconciler.ts";
10
+ import { type TelegramWorkspaceBindingIdentity } from "./workspace-identity.ts";
14
11
  import { type TelegramWorkspaceSlotOccupancy } from "./workspace-slots.ts";
12
+ export { createTelegramWorkspaceBindingIdentity, createTelegramWorkspaceDirectoryKey, normalizeTelegramSessionId, normalizeTelegramWorkspacePath, type TelegramWorkspaceBindingIdentity, } from "./workspace-identity.ts";
15
13
  export type TelegramTopicTargetStatus = "active" | "offline" | "stale" | "pending" | "starting" | "probe-required" | "failed";
16
14
  export type TelegramTopicSyncStatus = "open" | "closed" | "deleted" | "unknown";
17
15
  export type TelegramThreadOwner = {
@@ -247,12 +245,26 @@ export interface TelegramWorkspaceRestoreIntent {
247
245
  cleanup?: "issued" | "completed" | "not-issued";
248
246
  };
249
247
  }
248
+ /** Live same-session metadata, never a legacy scoped ACK or permission to dispatch/delete. */
249
+ export type TelegramWorkspaceLiveRebindIntent = Pick<TelegramWorkspaceRestoreIntent, "request" | "operatorUserId" | "executor" | "revision" | "createdAtMs" | "updatedAtMs"> & {
250
+ kind: "live-rebind";
251
+ recipient: TelegramWorkspaceRestoreRecipient;
252
+ } & ({
253
+ phase: "rebound";
254
+ cleanup?: never;
255
+ } | {
256
+ phase: "released";
257
+ cleanup?: "issued";
258
+ } | {
259
+ phase: "finished";
260
+ cleanup: "confirmed" | "failed" | "unknown" | "not-issued";
261
+ });
250
262
  /** Immutable source membership, not readiness, cancellation, or proof of complete Thread coverage. */
251
263
  export interface TelegramTemporaryThreadInput {
252
264
  journalBindingKey: string;
253
265
  updateIds: number[];
254
266
  }
255
- /** A strict journal observation of committed cancellation plus matching private retention. */
267
+ /** Journal-owned donor discard evidence: retained manual cancellation or body-free chooser expiry, never recipient cancellation. */
256
268
  export interface TelegramTemporaryThreadCancellationEvidence {
257
269
  journalBindingKey: string;
258
270
  updateId: number;
@@ -266,7 +278,7 @@ export interface TelegramTemporaryThreadEntry {
266
278
  };
267
279
  /** Append-only known source groups. Missing legacy metadata never proves that the creation source was alone. */
268
280
  inputs?: TelegramTemporaryThreadInput[];
269
- /** Whole known groups with positively observed cancellation; never proof that deletion may be issued. */
281
+ /** Whole known groups with positively observed donor cancellation or expiry; never recipient cancellation or deletion authority. */
270
282
  cancelledInputs?: TelegramTemporaryThreadInput[];
271
283
  /** Whole known groups whose Forward was positively completed by the journal owner; never deletion authority alone. */
272
284
  completedInputs?: TelegramTemporaryThreadInput[];
@@ -304,11 +316,19 @@ interface TelegramWorkspaceRestoreSnapshot {
304
316
  tokenSha256: string;
305
317
  revision: number;
306
318
  operations: TelegramWorkspaceRestoreIntent[];
319
+ liveRebindings?: TelegramWorkspaceLiveRebindIntent[];
307
320
  temporaryThreads?: TelegramTemporaryThreadEntry[];
308
321
  }
309
322
  /** Scope-bound Workspace operations; raw snapshot mutation is private to the store. */
310
323
  export interface TelegramWorkspaceRestore {
311
324
  list(): TelegramWorkspaceRestoreIntent[];
325
+ listLiveRebindings(): TelegramWorkspaceLiveRebindIntent[];
326
+ /** Caller has saved and held the selected input; this publishes the binding, not dispatch readiness. */
327
+ commitLiveRebind(request: TelegramWorkspaceRestoreRequest, recipient: TelegramWorkspaceRestoreRecipient, authority: TelegramWorkspaceRestoreAuthority): Promise<TelegramWorkspaceLiveRebindIntent | undefined>;
328
+ /** Caller proves local apply for release or current live clearance for cleanup; unknown issuance never repeats. */
329
+ advanceLiveRebind(expected: TelegramWorkspaceLiveRebindIntent, step: "release" | "issue-cleanup" | Extract<TelegramWorkspaceLiveRebindIntent, {
330
+ phase: "finished";
331
+ }>["cleanup"], authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceLiveRebindIntent | undefined;
312
332
  commit(request: TelegramWorkspaceRestoreRequest, authority: TelegramWorkspaceRestoreAuthority): Promise<TelegramWorkspaceRestoreIntent | undefined>;
313
333
  adopt(expected: TelegramWorkspaceRestoreIntent, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
314
334
  issueRecipient(expected: TelegramWorkspaceRestoreIntent, recipient: TelegramWorkspaceRestoreRecipient, authority: TelegramWorkspaceRestoreAuthority): {
@@ -361,6 +381,8 @@ export interface TelegramWorkspaceRestore {
361
381
  recordTemporaryThreadForwardIssued(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
362
382
  recordTemporaryThreadInputCompletion(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
363
383
  recordTemporaryThreadInputCancellation(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority, inspect: (updateId: number) => TelegramTemporaryThreadCancellationEvidence | undefined): TelegramTemporaryThreadEntry | undefined;
384
+ /** Body-free chooser expiry may terminate an uncertain donor Forward/Restore, never accepted recipient work or a bound target. */
385
+ recordTemporaryThreadInputExpiry(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority, inspect: (updateId: number) => TelegramTemporaryThreadCancellationEvidence | undefined): TelegramTemporaryThreadEntry | undefined;
364
386
  /** Caller holds profile admission and proves fresh source/protection clearance; publication grants one attempt, never retry. */
365
387
  issueTemporaryThreadCleanup(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority): {
366
388
  issued: true;
@@ -370,10 +392,11 @@ export interface TelegramWorkspaceRestore {
370
392
  /** `completed` names one newly completed group; every other known group must already be cancelled or completed. */
371
393
  retireTemporaryThread(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority, completed?: TelegramTemporaryThreadInput): TelegramTemporaryThreadEntry | undefined;
372
394
  /** New-world restart: atomically forgets this operator's Restore intents and temporary entries from previous runtime instances.
373
- * Committed bindings stay; nothing is rolled back, replayed or deleted here. */
374
- forgetPreviousWorld(authority: TelegramWorkspaceRestoreAuthority): {
395
+ * Caller may preserve exact unbound temporary tokens for clock-bearing sources. Committed bindings stay; nothing is rolled back, replayed or deleted here. */
396
+ forgetPreviousWorld(authority: TelegramWorkspaceRestoreAuthority, preserveTemporaryTokens?: readonly string[]): {
375
397
  operations: TelegramWorkspaceRestoreIntent[];
376
398
  temporaryThreads: TelegramTemporaryThreadEntry[];
399
+ liveRebindings?: TelegramWorkspaceLiveRebindIntent[];
377
400
  } | undefined;
378
401
  }
379
402
  export interface TelegramWorkspaceRestoreOptions {
@@ -424,7 +447,8 @@ export interface TelegramTopicTargetStore {
424
447
  load: () => Promise<void>;
425
448
  /** Discard process-local projections and reload owner-published state. */
426
449
  refresh?: () => Promise<void>;
427
- persist: () => Promise<void>;
450
+ /** Optional caller fence supplements, never replaces, captured publication authority. */
451
+ persist: (isCurrent?: () => boolean) => Promise<void>;
428
452
  invalidateTarget: (target: TelegramTarget, isCurrent: () => boolean, lastSyncError: string) => Promise<boolean>;
429
453
  /** Caller proves owner detachment; this does not assert Telegram Thread absence. */
430
454
  detachTargetOwner: (expected: TelegramTopicTargetRecord, isCurrent: () => boolean) => Promise<boolean>;
@@ -439,7 +463,18 @@ export interface TelegramTopicTargetStore {
439
463
  /** Runs synchronous live publication under the same evidence transaction; caller retains authentication/admission. */
440
464
  commitWorkspaceRestoreRegistration: (candidate: Parameters<TelegramTopicTargetStore["assertWorkspaceRestoreRegistration"]>[0], publish: () => void) => void;
441
465
  /** Read-only canonical observation; the callback must finish synchronously under the snapshot transaction. */
442
- withWorkspaceRestoreSnapshot: (expected: TelegramWorkspaceRestoreIntent, observe: (snapshot: Readonly<Pick<TelegramTopicTargetFile, "threads" | "workspaceBindings">>) => undefined) => void;
466
+ withWorkspaceRestoreSnapshot: (expected: TelegramWorkspaceRestoreIntent | TelegramWorkspaceLiveRebindIntent, observe: (snapshot: Readonly<Pick<TelegramTopicTargetFile, "threads" | "workspaceBindings">>) => undefined) => void;
467
+ /** Exact synchronous live-operation snapshot, including a current publication frame; no mutation, lock or authority grant. */
468
+ withWorkspaceLiveRebindSnapshot: (expected: TelegramWorkspaceLiveRebindIntent, observe: (snapshot: Readonly<Pick<TelegramTopicTargetFile, "threads" | "workspaceBindings">>) => undefined) => void;
469
+ /** Current live-origin ownership veto; effect callers still require Workspace admission. False is not work/recipient/deletion authority. */
470
+ isWorkspaceLiveRebindCleanupTargetProtected: (expected: TelegramWorkspaceLiveRebindIntent) => boolean;
471
+ /** Read-only captured identity with an optional exact manual-name result fence; no transport/session/admission grant or lock. */
472
+ captureWorkspaceThreadRenameObservation: (binding: TelegramWorkspaceThreadBinding, owner: TelegramTopicTargetRecord) => (expectedManualThreadName?: string) => boolean;
473
+ /** Captured read-only identity and exact absent-manual-name/automatic-title result fences; no authority grant or lock. */
474
+ captureWorkspaceThreadResetObservation: (binding: TelegramWorkspaceThreadBinding, owner: TelegramTopicTargetRecord) => {
475
+ isCurrent: () => boolean;
476
+ isResultCurrent: (automaticTitle: string) => boolean;
477
+ };
443
478
  /** Fresh strict disk read of acknowledged temporary-tab targets; throws rather than guessing absence. */
444
479
  listTemporaryThreadTargets: () => TelegramTarget[];
445
480
  list: () => TelegramTopicTargetRecord[];
@@ -524,14 +559,19 @@ export interface TelegramTopicTargetStore {
524
559
  renameByTarget: (target: TelegramTarget, threadName: string, options?: {
525
560
  updateDisplayTitle: boolean;
526
561
  }) => TelegramTopicTargetRecord | undefined;
562
+ /** Publish a manual-name candidate without first retaining it in the dirty local projection. */
563
+ renameByTargetAndPersist: (target: TelegramTarget, threadName: string, options: {
564
+ updateDisplayTitle: boolean;
565
+ }, isCurrent: () => boolean) => Promise<TelegramTopicTargetRecord | undefined>;
527
566
  clearManualNameByTarget: (target: TelegramTarget, automaticTitle: string) => TelegramTopicTargetRecord | undefined;
567
+ /** Stage exact manual-name removal and automatic display metadata in the existing publication candidate. */
568
+ clearManualNameByTargetAndPersist: (target: TelegramTarget, automaticTitle: string, isCurrent: () => boolean) => Promise<TelegramTopicTargetRecord | undefined>;
528
569
  allocateSlot: (profileKey: string, preferredSlot?: string, workspaceBindingKey?: string, options?: {
529
570
  excludeCurrentRecord?: boolean;
530
571
  }) => string | undefined;
531
572
  /** Claim the first reusable inactive thread for an instance, linking it to instanceId. */
532
573
  claimReusableTarget: (instanceId: string, threadName?: string) => TelegramTopicTargetRecord | undefined;
533
574
  }
534
- export declare function reconcileTelegramFreshAllocationCursor(store: Pick<TelegramTopicTargetStore, "getBotState" | "list" | "setBotState">, nowMs?: number): boolean;
535
575
  export declare function createTelegramCleanupTargetProtection(store: Pick<TelegramTopicTargetStore, "list"> & Partial<Pick<TelegramTopicTargetStore, "listReservations" | "listPendingProvisions" | "listPendingCleanups" | "listTemporaryThreadTargets">>, departingRecord?: TelegramTopicTargetRecord): NonNullable<ThreadReconciler.ThreadReconciliationApplyPorts["isCleanupTargetProtected"]>;
536
576
  export interface TelegramTopicTargetStoreOptions {
537
577
  path: string | (() => string);
@@ -554,8 +594,10 @@ export interface TelegramTopicTargetProvisionerDeps {
554
594
  claimPendingTargets?: boolean;
555
595
  }
556
596
  export interface TelegramTopicTargetRenamerDeps {
557
- store: Pick<TelegramTopicTargetStore, "renameByTarget" | "list" | "listWorkspaceBindings" | "listPendingProvisions">;
558
- callApi: <TResponse>(method: string, body: Record<string, unknown>) => Promise<TResponse>;
597
+ store: Pick<TelegramTopicTargetStore, "list" | "listWorkspaceBindings" | "listPendingProvisions"> & {
598
+ renameByTarget: (...args: Parameters<TelegramTopicTargetStore["renameByTarget"]>) => ReturnType<TelegramTopicTargetStore["renameByTarget"]> | Promise<ReturnType<TelegramTopicTargetStore["renameByTarget"]>>;
599
+ };
600
+ callApi: <TResponse>(method: string, body: Record<string, unknown>, options?: TelegramApiCallOptions) => Promise<TResponse>;
559
601
  assertAuthority?: () => void;
560
602
  shouldRenameDisplayedTitle?: () => boolean;
561
603
  topicNameTemplate?: string;
@@ -595,8 +637,6 @@ export interface TelegramTopicTargetProvisionResult {
595
637
  record: TelegramTopicTargetRecord;
596
638
  displayTitle?: string;
597
639
  }
598
- export declare function getTelegramStatePath(agentDir?: string, profileName?: string): string;
599
- export declare function getTelegramTopicTargetsPath(agentDir?: string, profileName?: string): string;
600
640
  export declare const TELEGRAM_LEADER_SESSION_HANDOFF_TTL_MS = 30000;
601
641
  export interface TelegramLeaderSessionHandoff {
602
642
  pid: number;
@@ -703,6 +743,37 @@ export declare function resolveTelegramInstanceThreadIdentity(options: {
703
743
  leader?: TelegramInstanceThreadIdentityCandidate;
704
744
  record?: TelegramTopicTargetRecord;
705
745
  }): TelegramInstanceThreadIdentityCandidate;
746
+ export interface TelegramWorkspaceThreadRenameAuthority {
747
+ context: unknown;
748
+ sessionId?: string;
749
+ sessionGeneration: number;
750
+ cwd?: string;
751
+ profileName?: string;
752
+ botToken?: string;
753
+ operatorUserId?: number;
754
+ leaderEpoch?: string | number;
755
+ ownsDirectDelivery: boolean;
756
+ followerRegistered: boolean;
757
+ localTarget?: TelegramTarget;
758
+ localSlot?: string;
759
+ }
760
+ interface TelegramWorkspaceThreadNameRecipientDeps {
761
+ store: TelegramTopicTargetStore;
762
+ instanceId: string;
763
+ target: TelegramTarget;
764
+ assertAuthority: () => void;
765
+ getAuthority: () => TelegramWorkspaceThreadRenameAuthority;
766
+ }
767
+ /** Prepared recipient identity/result fences; callers retain Workspace admission and transport effects. */
768
+ export declare function createTelegramWorkspaceThreadRenameRecipient(deps: TelegramWorkspaceThreadNameRecipientDeps): {
769
+ assertAuthority: () => void;
770
+ assertResult: (result: TelegramTopicTargetRecord) => void;
771
+ };
772
+ /** Exact automatic-title/absent-name result fences, separate from recipient identity and issued effects. */
773
+ export declare function createTelegramWorkspaceThreadResetRecipient(deps: TelegramWorkspaceThreadNameRecipientDeps): {
774
+ assertAuthority: () => void;
775
+ assertResult: (automaticTitle: string) => void;
776
+ };
706
777
  export interface TelegramLeaderThreadStateRuntime {
707
778
  getTarget(): TelegramTarget | undefined;
708
779
  getIdentity(): TelegramInstanceThreadIdentityCandidate | undefined;
@@ -733,13 +804,6 @@ export declare function findCurrentTelegramInstanceThreadRecord(options: {
733
804
  instanceId: string;
734
805
  preferredTarget?: TelegramTarget;
735
806
  }): TelegramTopicTargetRecord | undefined;
736
- export declare function resolveTelegramInstanceThreadTarget(options: {
737
- followerTarget?: TelegramTarget;
738
- leaderTarget?: TelegramTarget;
739
- currentRecord?: TelegramTopicTargetRecord;
740
- }): (TelegramTarget & {
741
- threadId: number;
742
- }) | undefined;
743
807
  export interface TelegramThreadStatusProjectionRuntime {
744
808
  getBusRole(): "leader" | "follower" | undefined;
745
809
  getBusFollowers(): ReturnType<typeof listTelegramThreadStatusFollowers>;