@llblab/pi-kit 0.27.5 → 0.28.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 (194) hide show
  1. package/BACKLOG.md +3 -1
  2. package/CHANGELOG.md +9 -0
  3. package/README.md +4 -4
  4. package/node_modules/@llblab/pi-state-flow/AGENTS.md +1 -1
  5. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +6 -2
  6. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +4 -1
  7. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.js +4 -3
  8. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +26 -13
  9. package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
  10. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +3 -1
  11. package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +2 -2
  12. package/node_modules/@llblab/pi-state-flow/docs/usage.md +2 -1
  13. package/node_modules/@llblab/pi-state-flow/lib/compaction.ts +4 -3
  14. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +25 -12
  15. package/node_modules/@llblab/pi-state-flow/package.json +1 -1
  16. package/node_modules/@llblab/pi-telegram/AGENTS.md +10 -8
  17. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -9
  18. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +13 -0
  19. package/node_modules/@llblab/pi-telegram/LICENSE +21 -0
  20. package/node_modules/@llblab/pi-telegram/README.md +15 -5
  21. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +1 -5
  22. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +5 -7
  23. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +5 -1
  24. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +6 -1
  25. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +4 -2
  26. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +54 -56
  27. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +206 -139
  28. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +21 -2
  29. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +181 -25
  30. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.d.ts +4 -1
  31. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +28 -4
  32. package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +52 -56
  33. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +78 -246
  34. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +1 -3
  35. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +23 -26
  36. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +0 -5
  37. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +5 -5
  38. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +0 -23
  39. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +15 -15
  40. package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +0 -17
  41. package/node_modules/@llblab/pi-telegram/dist/lib/config.js +12 -14
  42. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +0 -4
  43. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +2 -5
  44. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +255 -61
  45. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +0 -19
  46. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +0 -2
  47. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +2 -2
  48. package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +177 -16
  49. package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +1115 -249
  50. package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.d.ts +0 -2
  51. package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.js +2 -2
  52. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +1 -1
  53. package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +100 -12
  54. package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +380 -14
  55. package/node_modules/@llblab/pi-telegram/dist/lib/logging.d.ts +30 -12
  56. package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +129 -72
  57. package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +28 -5
  58. package/node_modules/@llblab/pi-telegram/dist/lib/media.js +26 -8
  59. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +0 -11
  60. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +8 -8
  61. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +0 -18
  62. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +18 -18
  63. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +4 -4
  64. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +12 -7
  65. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +1 -1
  66. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +1 -1
  67. package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +1 -0
  68. package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +4 -3
  69. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +0 -1
  70. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +1 -1
  71. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +1 -8
  72. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +1 -6
  73. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +4 -21
  74. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +0 -8
  75. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +5 -5
  76. package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +50 -7
  77. package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +155 -17
  78. package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +1 -0
  79. package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +2 -1
  80. package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +0 -5
  81. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +5 -5
  82. package/node_modules/@llblab/pi-telegram/dist/lib/preview.d.ts +0 -3
  83. package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +3 -3
  84. package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.d.ts +0 -1
  85. package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.js +1 -1
  86. package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +3 -15
  87. package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +69 -8
  88. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +29 -9
  89. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +104 -33
  90. package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +0 -4
  91. package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +1 -1
  92. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +73 -8
  93. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +2206 -307
  94. package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +0 -2
  95. package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +1 -1
  96. package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +44 -9
  97. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +149 -27
  98. package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +0 -5
  99. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +5 -4
  100. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +11 -3
  101. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +34 -23
  102. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +1 -0
  103. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +18 -21
  104. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +32 -5
  105. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +191 -7
  106. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +2 -0
  107. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +1 -1
  108. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +291 -59
  109. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +1647 -369
  110. package/node_modules/@llblab/pi-telegram/dist/lib/turns.d.ts +0 -1
  111. package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +1 -1
  112. package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +184 -28
  113. package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +1032 -114
  114. package/node_modules/@llblab/pi-telegram/dist/lib/wire.d.ts +12 -0
  115. package/node_modules/@llblab/pi-telegram/dist/lib/wire.js +21 -0
  116. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +25 -17
  117. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +95 -20
  118. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.d.ts +20 -0
  119. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.js +103 -0
  120. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +43 -8
  121. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +148 -52
  122. package/node_modules/@llblab/pi-telegram/dist/package.json +6 -6
  123. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/SKILL.md +3 -3
  124. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/diagnosis.md +3 -3
  125. package/node_modules/@llblab/pi-telegram/docs/README.md +1 -1
  126. package/node_modules/@llblab/pi-telegram/docs/activity.md +1 -1
  127. package/node_modules/@llblab/pi-telegram/docs/architecture.md +152 -34
  128. package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +1 -1
  129. package/node_modules/@llblab/pi-telegram/docs/delivery.md +1 -1
  130. package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +2 -2
  131. package/node_modules/@llblab/pi-telegram/docs/inbound.md +1 -1
  132. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +125 -19
  133. package/node_modules/@llblab/pi-telegram/docs/public-api.md +3 -1
  134. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +22 -8
  135. package/node_modules/@llblab/pi-telegram/docs/updates.md +1 -1
  136. package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +5 -9
  137. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +6 -0
  138. package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +5 -2
  139. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +243 -224
  140. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +178 -31
  141. package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +30 -8
  142. package/node_modules/@llblab/pi-telegram/lib/bus.ts +110 -334
  143. package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +29 -29
  144. package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +5 -5
  145. package/node_modules/@llblab/pi-telegram/lib/commands.ts +15 -15
  146. package/node_modules/@llblab/pi-telegram/lib/config.ts +12 -17
  147. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +2 -8
  148. package/node_modules/@llblab/pi-telegram/lib/extension.ts +257 -72
  149. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +0 -22
  150. package/node_modules/@llblab/pi-telegram/lib/inbound.ts +2 -2
  151. package/node_modules/@llblab/pi-telegram/lib/journal.ts +1182 -326
  152. package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +2 -2
  153. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +1 -1
  154. package/node_modules/@llblab/pi-telegram/lib/locks.ts +402 -23
  155. package/node_modules/@llblab/pi-telegram/lib/logging.ts +151 -101
  156. package/node_modules/@llblab/pi-telegram/lib/media.ts +51 -9
  157. package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +8 -8
  158. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +18 -18
  159. package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +11 -0
  160. package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +2 -2
  161. package/node_modules/@llblab/pi-telegram/lib/menu.ts +5 -1
  162. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +1 -1
  163. package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +1 -10
  164. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +5 -24
  165. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +5 -5
  166. package/node_modules/@llblab/pi-telegram/lib/paths.ts +177 -17
  167. package/node_modules/@llblab/pi-telegram/lib/pi.ts +5 -2
  168. package/node_modules/@llblab/pi-telegram/lib/polling.ts +5 -5
  169. package/node_modules/@llblab/pi-telegram/lib/preview.ts +3 -3
  170. package/node_modules/@llblab/pi-telegram/lib/prompt-templates.ts +1 -1
  171. package/node_modules/@llblab/pi-telegram/lib/queue.ts +67 -9
  172. package/node_modules/@llblab/pi-telegram/lib/recovery.ts +104 -44
  173. package/node_modules/@llblab/pi-telegram/lib/replies.ts +1 -1
  174. package/node_modules/@llblab/pi-telegram/lib/routing.ts +1955 -375
  175. package/node_modules/@llblab/pi-telegram/lib/sections.ts +1 -1
  176. package/node_modules/@llblab/pi-telegram/lib/status.ts +156 -36
  177. package/node_modules/@llblab/pi-telegram/lib/sync.ts +4 -4
  178. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +48 -33
  179. package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +24 -21
  180. package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +267 -9
  181. package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +3 -1
  182. package/node_modules/@llblab/pi-telegram/lib/threads.ts +1697 -488
  183. package/node_modules/@llblab/pi-telegram/lib/turns.ts +1 -1
  184. package/node_modules/@llblab/pi-telegram/lib/updates.ts +1072 -151
  185. package/node_modules/@llblab/pi-telegram/lib/wire.ts +28 -0
  186. package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +97 -47
  187. package/node_modules/@llblab/pi-telegram/lib/workspace-identity.ts +147 -0
  188. package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +188 -89
  189. package/node_modules/@llblab/pi-telegram/package.json +6 -6
  190. package/node_modules/@llblab/pi-telegram/scripts/audit-exports.mjs +100 -0
  191. package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +80 -43
  192. package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/SKILL.md +3 -3
  193. package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/diagnosis.md +3 -3
  194. package/package.json +3 -3
@@ -47,7 +47,9 @@ import * as Sync from "./sync.ts";
47
47
  import * as TelegramApi from "./telegram-api.ts";
48
48
  import * as TextGroups from "./text-groups.ts";
49
49
  import * as ThreadReconciler from "./thread-reconciler.ts";
50
+ import * as Targets from "./target.ts";
50
51
  import * as ThreadDisplay from "./thread-display.ts";
52
+ import * as ThreadNaming from "./thread-naming.ts";
51
53
  import * as Threads from "./threads.ts";
52
54
  import * as TimeInjection from "./time-injection.ts";
53
55
  import * as Updates from "./updates.ts";
@@ -66,6 +68,7 @@ const telegramBusProtocolIdentity =
66
68
  Bus.TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
67
69
  Bus.TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
68
70
  Bus.TELEGRAM_BUS_CAPABILITY_SESSION_REPLACEMENT_INTENT,
71
+ Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE,
69
72
  ]);
70
73
 
71
74
  // --- Extension Runtime ---
@@ -85,12 +88,13 @@ export default function (pi: Pi.ExtensionAPI) {
85
88
  } = piRuntime;
86
89
  const bridgeRuntime = Runtime.createTelegramBridgeRuntime();
87
90
  const runtimeDiagnostics =
88
- Logging.createTelegramRuntimeDiagnosticsRuntime<Pi.ExtensionContext>();
91
+ Logging.createTelegramRuntimeDiagnosticsRuntime<Pi.ExtensionContext>({ sharedFile: true });
89
92
  const runtimeEvents = runtimeDiagnostics.events;
90
93
  const recordRuntimeEvent = runtimeDiagnostics.recordRuntimeEvent;
91
94
  const configStore = Config.createTelegramConfigStore({ recordRuntimeEvent });
92
95
  const busProcessRuntime = Bus.createCurrentTelegramBusProcessRuntime({
93
96
  getActiveProfileName: configStore.getActiveProfileName,
97
+ endpointLayout: "consolidated",
94
98
  });
95
99
  const {
96
100
  instanceId: telegramInstanceId,
@@ -105,7 +109,7 @@ export default function (pi: Pi.ExtensionAPI) {
105
109
  WorkspaceAdmission.createTelegramWorkspaceAdmissionRuntimeBinding({
106
110
  getProfileName: configStore.getActiveProfileName,
107
111
  getBotToken: configStore.getBotToken,
108
- getPath: Paths.resolveTelegramWorkspaceAdmissionPathForProfile,
112
+ getStatePath: Paths.resolveTelegramStatePath,
109
113
  owner: {
110
114
  processId: telegramProcessId,
111
115
  processBirthId: telegramQueueProcessBirthId,
@@ -157,24 +161,30 @@ export default function (pi: Pi.ExtensionAPI) {
157
161
  getBotToken: configStore.getBotToken,
158
162
  getBotId: getTelegramBotId,
159
163
  });
164
+ const telegramLeaderJournalPath = Locks.createTelegramLeaderJournalPathResolver({
165
+ getNamedJournalPath() { return lockRuntime.getJournalPath(); },
166
+ getSessionId() { return Pi.getExtensionContextSessionId(telegramSessionContextStore.get()); },
167
+ getProfileName: configStore.getActiveProfileName,
168
+ });
160
169
  const telegramJournalBindingRuntime =
161
170
  Journal.createTelegramUpdateJournalBindingRuntime({
162
171
  base: {
163
172
  getProfileName: configStore.getActiveProfileName,
164
173
  getBotToken: configStore.getBotToken,
165
174
  getBotId: getTelegramBotId,
175
+ withSourceSerialization: configStore.withSourceSerialization,
166
176
  onRecovery(event) {
167
177
  recordRuntimeEvent(
168
178
  "recovery",
169
179
  event.kind === "repaired"
170
180
  ? "Telegram update journal was repaired automatically."
171
- : "Telegram update journal was reset after its damaged files were quarantined.",
181
+ : "Telegram update journal was reset after its damaged files were deleted.",
172
182
  {
173
183
  phase: "journal-auto-recovery",
174
184
  recoveryKind: event.kind,
175
185
  journalPath: event.path,
176
186
  revision: event.revision,
177
- quarantinePath: event.quarantinePath,
187
+ deletedPaths: event.deletedPaths,
178
188
  reason: event.reason,
179
189
  },
180
190
  );
@@ -188,8 +198,12 @@ export default function (pi: Pi.ExtensionAPI) {
188
198
  },
189
199
  getWorkspaceAdmission: workspaceAdmissionRuntime.resolve,
190
200
  },
191
- getLeaderJournalPath: Paths.resolveTelegramUpdateJournalPathForProfile,
192
- getFollowerJournalPath(bindingKey, profileName) {
201
+ getLeaderJournalPath: telegramLeaderJournalPath.resolve,
202
+ getRuntimeDir: Paths.resolveTelegramTempDir,
203
+ getFollowerJournalPath(bindingKey, profileName, sessionId) {
204
+ if (sessionId !== undefined) return Paths.resolveTelegramSessionJournalPath(
205
+ sessionId, bindingKey, undefined, profileName,
206
+ );
193
207
  return Paths.resolveTelegramFollowerJournalPath(
194
208
  bindingKey,
195
209
  undefined,
@@ -197,6 +211,11 @@ export default function (pi: Pi.ExtensionAPI) {
197
211
  );
198
212
  },
199
213
  getActiveFollowerBindingKey: getTelegramManualFollowerProfileKey,
214
+ getActiveFollowerSessionId() {
215
+ return telegramBusFollowerRegistrationState.getSessionId(
216
+ Pi.getExtensionContextSessionId(telegramSessionContextStore.get()),
217
+ );
218
+ },
200
219
  isFollowerRegistered: telegramBusFollowerRegistrationState.isRegistered,
201
220
  });
202
221
  const telegramJournalReferenceRegistry =
@@ -213,31 +232,46 @@ export default function (pi: Pi.ExtensionAPI) {
213
232
  const configControls = Config.createTelegramConfigControls(configStore);
214
233
  const lockRuntime = Locks.createTelegramLockRuntime<Pi.ExtensionContext>({
215
234
  key: Locks.createTelegramLockKeyResolver(configStore),
235
+ statePath: Paths.resolveTelegramStatePath(),
216
236
  instanceId: telegramInstanceId,
217
237
  busSecret: telegramBusAuthSecret,
218
238
  staleHeartbeatMs: Locks.TELEGRAM_BUS_LEADER_STALE_HEARTBEAT_MS,
239
+ legacyLocksPath: Paths.resolveLegacyTelegramOwnersPath(),
240
+ createJournalPath() { return telegramLeaderJournalPath.createJournalPath(); },
219
241
  });
242
+ const telegramSessionContextStore =
243
+ Lifecycle.createTelegramSessionContextStore<Pi.ExtensionContext>({
244
+ getIdentity(ctx) {
245
+ return ctx.sessionManager ?? ctx.cwd;
246
+ },
247
+ });
248
+ const captureTelegramStateAuthority = Locks.createTelegramOwnedStateAuthorityCapture(
249
+ lockRuntime, telegramSessionContextStore);
220
250
  const threadStore = Threads.createTelegramTopicTargetStore({
221
- path: function () {
222
- return Threads.getTelegramTopicTargetsPath(
223
- undefined,
224
- configStore.getActiveProfileName(),
225
- );
226
- },
251
+ path: Paths.resolveTelegramStatePath,
227
252
  telegramProfile: function () {
228
253
  return configStore.getActiveProfileName();
229
254
  },
230
255
  canPersist: lockRuntime.owns,
231
- commitPersist: lockRuntime.commitIfOwned,
256
+ consolidated: {
257
+ captureAuthority: captureTelegramStateAuthority,
258
+ publishIfOwned: lockRuntime.publishStateSectionIfOwned!,
259
+ },
232
260
  getExternalReservedSlots: function () {
233
261
  return workspaceAdmissionRuntime.resolve()?.listReservedSlots() ?? [];
234
262
  },
235
263
  });
264
+ const resolveWorkspaceRestoreStore = Threads.createTelegramWorkspaceRestoreResolver({
265
+ getProfileName: configStore.getActiveProfileName,
266
+ getBotToken: configStore.getBotToken,
267
+ threadStore,
268
+ });
236
269
  runtimeDiagnostics.bindStorage({
237
270
  getBotToken: configStore.getBotToken,
238
271
  getProfileName: configStore.getActiveProfileName,
239
272
  canReset: lockRuntime.owns,
240
273
  commitReset: lockRuntime.commitIfOwned,
274
+ captureAuthority: captureTelegramStateAuthority,
241
275
  });
242
276
  const sessionActionAssembly = Commands.createTelegramSessionActionAssembly({
243
277
  registerCommand,
@@ -276,12 +310,6 @@ export default function (pi: Pi.ExtensionAPI) {
276
310
  const lockOwnershipGuard =
277
311
  Locks.createTelegramLockOwnershipGuard(lockRuntime);
278
312
  const getCurrentLeaderEpoch = lockRuntime.getOwnedLeaderEpoch;
279
- const telegramSessionContextStore =
280
- Lifecycle.createTelegramSessionContextStore<Pi.ExtensionContext>({
281
- getIdentity(ctx) {
282
- return ctx.sessionManager ?? ctx.cwd;
283
- },
284
- });
285
313
  const ownsTelegramDirectDelivery =
286
314
  Locks.createTelegramDirectDeliveryOwnershipChecker({
287
315
  lock: lockRuntime,
@@ -360,13 +388,15 @@ export default function (pi: Pi.ExtensionAPI) {
360
388
  );
361
389
  const telegramApiTargetActivityRuntime =
362
390
  TelegramApi.createTelegramApiTargetActivityRuntime();
363
- const captureWorkspaceExternalProtection =
364
- WorkspaceRetirement.createTelegramWorkspaceExternalProtectionCapture({
391
+ const workspaceProtectionObserver =
392
+ WorkspaceRetirement.createTelegramWorkspaceProtectionObserver({
365
393
  listFollowers: telegramBusFollowerRegistry.list,
366
394
  getActiveTurnTarget: activeTurnRuntime.getTarget,
367
395
  getQueuedItems: telegramQueueStore.getQueuedItems,
368
396
  resolveLeaderJournal: resolveTelegramUpdateJournalBinding,
369
397
  createFollowerJournalResolver:
398
+ telegramJournalBindingRuntime.createLegacyRecipientResolver,
399
+ createSessionJournalResolver:
370
400
  telegramJournalBindingRuntime.createRecipientResolver,
371
401
  withJournalReference(binding, operation) {
372
402
  if (!binding.recoveryKey) throw new Error(
@@ -378,12 +408,24 @@ export default function (pi: Pi.ExtensionAPI) {
378
408
  }, operation);
379
409
  },
380
410
  discoverFollowerJournals() {
381
- return Journal.discoverTelegramFollowerJournalPaths({
411
+ return Journal.discoverTelegramRecipientJournalPaths({
382
412
  directory: Paths.resolveTelegramTempDir(),
383
413
  profileName: configStore.getActiveProfileName(),
384
414
  });
385
415
  },
386
416
  createJournalPathResolver: telegramJournalBindingRuntime.createPathResolver,
417
+ inspectJournalNamespace() {
418
+ const botToken = configStore.getBotToken();
419
+ if (!botToken) throw new Error("Telegram namespace inspection requires current bot identity.");
420
+ return Journal.inspectTelegramSessionJournalNamespace({
421
+ directory: Paths.resolveTelegramTempDir(),
422
+ profile: configStore.getActiveProfileName() ?? "default",
423
+ pollingPath: telegramLeaderJournalPath.resolve(configStore.getActiveProfileName()),
424
+ botIdentity: Journal.createTelegramUpdateJournalBotIdentity({ botToken, botId: getTelegramBotId() }),
425
+ limits: { maxDirectoryEntries: 10_000, maxFiles: 4096, maxBytes: 64 * 1024 * 1024,
426
+ maxEntries: 10_000, maxWork: 100_000 },
427
+ });
428
+ },
387
429
  getJournalWriterProtection(journalBindingKey) {
388
430
  const owner = Threads.getTelegramThreadOwnerFromProfileKey(
389
431
  journalBindingKey,
@@ -397,11 +439,24 @@ export default function (pi: Pi.ExtensionAPI) {
397
439
  : liveness === "dead" ? "clear" : "unknown";
398
440
  },
399
441
  getDeliveryAuthorityProtection(binding) {
400
- return telegramApiTargetActivityRuntime.hasPendingTarget(binding.target)
442
+ const retainedRestore = resolveWorkspaceRestoreStore()?.list().some(function (intent) {
443
+ return intent.request.binding.bindingKey === binding.bindingKey ||
444
+ Targets.areTelegramTargetsEqual(intent.request.binding.target, binding.target) ||
445
+ Targets.areTelegramTargetsEqual(intent.request.target, binding.target);
446
+ });
447
+ return retainedRestore || telegramApiTargetActivityRuntime.hasPendingTarget(binding.target)
401
448
  ? "protected"
402
449
  : "clear";
403
450
  },
404
451
  });
452
+ const captureWorkspaceExternalProtection = workspaceProtectionObserver.capture;
453
+ const pruneWorkspaceJournalEvidence = WorkspaceRetirement.createTelegramWorkspaceJournalEvidencePruner({
454
+ store: threadStore,
455
+ getAdmission: workspaceAdmissionRuntime.resolve,
456
+ getLeaderEpoch: getCurrentLeaderEpoch,
457
+ runExclusive: telegramWorkspaceOperationRuntime.runExclusive,
458
+ protection: workspaceProtectionObserver,
459
+ });
405
460
  const reclaimTelegramWorkspaceDeadOwnerQueue =
406
461
  WorkspaceRetirement.createTelegramWorkspaceDeadOwnerQueueReclaimer({
407
462
  getExternalProtection: captureWorkspaceExternalProtection,
@@ -409,9 +464,11 @@ export default function (pi: Pi.ExtensionAPI) {
409
464
  getQueuedItems: telegramQueueStore.getQueuedItems,
410
465
  resolveLeaderJournal: resolveTelegramUpdateJournalBinding,
411
466
  createFollowerJournalResolver:
467
+ telegramJournalBindingRuntime.createLegacyRecipientResolver,
468
+ createSessionJournalResolver:
412
469
  telegramJournalBindingRuntime.createRecipientResolver,
413
470
  discoverFollowerJournals() {
414
- return Journal.discoverTelegramFollowerJournalPaths({
471
+ return Journal.discoverTelegramRecipientJournalPaths({
415
472
  directory: Paths.resolveTelegramTempDir(),
416
473
  profileName: configStore.getActiveProfileName(),
417
474
  });
@@ -460,7 +517,7 @@ export default function (pi: Pi.ExtensionAPI) {
460
517
  const botToken = configStore.getBotToken();
461
518
  if (!botToken) throw new Error("Telegram Thread cleanup review requires an active bot token.");
462
519
  return ThreadCleanupManager.createTelegramThreadCleanupWorkStore({
463
- path: Paths.resolveTelegramThreadCleanupWorkPath(undefined, profileName),
520
+ ...Paths.resolveTelegramServiceJournalStorage("thread-cleanup", undefined, profileName),
464
521
  profileName,
465
522
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
466
523
  });
@@ -573,9 +630,10 @@ export default function (pi: Pi.ExtensionAPI) {
573
630
  instanceId: telegramInstanceId,
574
631
  updateStatus: statusRuntime.updateStatus,
575
632
  getStatusState: statusRuntime.getStatusState,
633
+ session: telegramSessionContextStore,
576
634
  async persistSnapshot(snapshot) {
577
635
  threadStore.setStatusSnapshot(snapshot);
578
- await threadStore.persist();
636
+ await threadStore.persistStatus();
579
637
  },
580
638
  });
581
639
  const updateStatus = runtimeDiagnostics.updateStatus;
@@ -592,6 +650,10 @@ export default function (pi: Pi.ExtensionAPI) {
592
650
  const directTelegramApiRuntime =
593
651
  TelegramApi.createDefaultTelegramBridgeApiRuntime({
594
652
  getBotToken: configStore.getBotToken,
653
+ getBotScope() {
654
+ const config = configStore.get();
655
+ return config.botUsername ?? (config.botId === undefined ? undefined : String(config.botId));
656
+ },
595
657
  recordRuntimeEvent,
596
658
  targetActivity: telegramApiTargetActivityRuntime,
597
659
  workspaceAdmission: workspaceAdmissionRuntime.resolve,
@@ -896,6 +958,10 @@ export default function (pi: Pi.ExtensionAPI) {
896
958
  getActiveModel: currentModelRuntime.get,
897
959
  getThinkingLevel,
898
960
  getQueueItemCount,
961
+ getPendingCancellationCount() {
962
+ return getCurrentLeaderEpoch() === undefined ? 0 :
963
+ updateAdmissionRuntimeBinding.getActive()?.getState()?.abandoningClaimCount ?? 0;
964
+ },
899
965
  buildStatusHtml: Commands.createTelegramAppMenuHtmlBuilder({
900
966
  buildStatusHtml: Status.createTelegramStatusHtmlBuilder({
901
967
  getActiveModel: currentModelRuntime.get,
@@ -988,21 +1054,12 @@ export default function (pi: Pi.ExtensionAPI) {
988
1054
 
989
1055
  const foreignOwnedUpdateForwarder =
990
1056
  telegramBusFollowerClients.foreignOwnedUpdateForwarder;
991
- const followerTargetController = telegramBusFollowerClients.targetController;
992
- const restoreFollowerThreadTarget =
993
- Bus.createTelegramBusFollowerThreadRestoreHandler({
994
- followerRegistry: telegramBusFollowerRegistry,
995
- followerTargetController,
996
- onRestored() {
997
- telegramSyncStateRuntime.markSliceFresh(
998
- Sync.TELEGRAM_SYNC_SLICE_TARGET_BINDINGS,
999
- {
1000
- nowMs: Date.now(),
1001
- action: "follower-thread-restore",
1002
- },
1003
- );
1004
- },
1005
- });
1057
+ const workspaceRestoreFollowerController = Bus.createTelegramBusWorkspaceRestoreController({
1058
+ getFollower: telegramBusFollowerRegistry.get,
1059
+ localProtocolIdentity: telegramBusProtocolIdentity,
1060
+ createRequestId: telegramBusFollowerClients.createRequestId,
1061
+ getAuthSecret() { return telegramBusAuthSecret; },
1062
+ });
1006
1063
  const observedThreadTargetBinding =
1007
1064
  Polling.createTelegramThreadTargetObservationBinding<Pi.ExtensionContext>();
1008
1065
  const topicLifecycleSync =
@@ -1057,7 +1114,62 @@ export default function (pi: Pi.ExtensionAPI) {
1057
1114
  return observedThreadTargetBinding.handle(ctx);
1058
1115
  },
1059
1116
  foreignOwnedUpdateForwarder,
1060
- replaceFollowerThreadTarget: restoreFollowerThreadTarget,
1117
+ workspaceRestoreRecipient: {
1118
+ getSessionId: Pi.getExtensionContextSessionId,
1119
+ getCwd: Pi.getExtensionContextCwd,
1120
+ getLeaderIdentity: telegramBusLeaderState.getIdentity,
1121
+ followerRegistry: telegramBusFollowerRegistry,
1122
+ runFollower: workspaceRestoreFollowerController,
1123
+ },
1124
+ getWorkspaceRestoreStore: resolveWorkspaceRestoreStore,
1125
+ captureWorkspaceExternalProtection,
1126
+ inspectRestoreSourceCompletion(expected) {
1127
+ return telegramJournalReferenceRegistry.withReference({ referenceClass: "operator-disposition",
1128
+ recoveryKey: expected.journalBindingKey }, function () {
1129
+ const observed = telegramJournalBindingRuntime.inspectSourceCompletion(expected.journalBindingKey, { updateId: expected.updateId,
1130
+ sourceSha256: expected.sourceSha256, completionSha256: expected.completionSha256 });
1131
+ return observed && { journalBindingKey: expected.journalBindingKey, ...observed };
1132
+ });
1133
+ },
1134
+ inspectRestoreQueuedReceipt(expected) {
1135
+ return telegramJournalReferenceRegistry.withReference({ referenceClass: "operator-disposition",
1136
+ recoveryKey: expected.journalBindingKey }, function () {
1137
+ return telegramJournalBindingRuntime.inspectQueuedReceipt(expected.journalBindingKey, { queueKind: expected.queueKind, receiptId: expected.receiptId,
1138
+ sourceUpdateIds: [...expected.sourceUpdateIds], queueOwner: { ...expected.queueOwner } });
1139
+ });
1140
+ },
1141
+ inspectRestoreSourceAbandonment(updateId, journalBindingKey) {
1142
+ return telegramJournalReferenceRegistry.withReference({
1143
+ referenceClass: "operator-disposition",
1144
+ recoveryKey: journalBindingKey,
1145
+ }, function () {
1146
+ return telegramJournalBindingRuntime.inspectSourceAbandonment(journalBindingKey, updateId);
1147
+ });
1148
+ },
1149
+ inspectTemporaryThreadSources(_target, requiredJournalBindingKeys) {
1150
+ const binding = resolveTelegramUpdateJournalBinding();
1151
+ const botToken = configStore.getBotToken();
1152
+ if (!binding || !botToken) return undefined;
1153
+ const profile = configStore.getActiveProfileName() ?? "default";
1154
+ const botIdentity = Journal.createTelegramUpdateJournalBotIdentity({ botToken, botId: getTelegramBotId() });
1155
+ return configStore.withSourceSerialization(function () {
1156
+ return Journal.isTelegramThreadCleanupJournalNamespaceClear({
1157
+ directory: Paths.resolveTelegramTempDir(), profile, botIdentity,
1158
+ pollingPath: telegramLeaderJournalPath.resolve(configStore.getActiveProfileName()),
1159
+ requiredJournalBindingKeys: [binding.recoveryKey, ...requiredJournalBindingKeys],
1160
+ limits: { maxDirectoryEntries: 10_000, maxFiles: 4096, maxBytes: 64 * 1024 * 1024,
1161
+ maxEntries: 10_000, maxWork: 100_000 },
1162
+ withSourceReference(path, operation) {
1163
+ return telegramJournalReferenceRegistry.withReference({ referenceClass: "operator-disposition",
1164
+ recoveryKey: Journal.createTelegramUpdateJournalBindingKey({ path, profileName: profile, botIdentity }) }, operation);
1165
+ },
1166
+ }) ? [] : undefined;
1167
+ });
1168
+ },
1169
+ hasWorkspaceRestoreAuthority() {
1170
+ return lockRuntime.owns() && Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE);
1171
+ },
1172
+ getSessionGeneration: telegramSessionContextStore.getGeneration,
1061
1173
  bridgeRuntime,
1062
1174
  requestNewSession(source) {
1063
1175
  const updateId = Updates.getTelegramUpdateExecutionFence(source)?.updateId;
@@ -1131,7 +1243,7 @@ export default function (pi: Pi.ExtensionAPI) {
1131
1243
  sendTextReply,
1132
1244
  setMyCommands,
1133
1245
  validateThreadName(threadName) {
1134
- return Threads.getTelegramManualThreadDisplayNameValidationError(
1246
+ return ThreadNaming.getTelegramManualThreadDisplayNameValidationError(
1135
1247
  threadName,
1136
1248
  );
1137
1249
  },
@@ -1197,10 +1309,43 @@ export default function (pi: Pi.ExtensionAPI) {
1197
1309
  dispatchNext: dispatchNextQueuedTelegramTurn,
1198
1310
  requestQueueHandoffReconciliation:
1199
1311
  queueHandoffReconciliationBinding.request,
1200
- afterUpdateCompleted: sessionActionsRuntime.onUpdateCompleted,
1312
+ afterQueueReceiptCommitted: inboundRouteRuntime.onQueueReceiptCommitted,
1313
+ afterUpdateCompleted(updateId, ctx, journalBindingKey) {
1314
+ sessionActionsRuntime.onUpdateCompleted(updateId);
1315
+ inboundRouteRuntime.onUpdateCompleted(updateId, ctx, journalBindingKey);
1316
+ },
1201
1317
  },
1202
1318
  worker: {
1319
+ expireRoutingInput: inboundRouteRuntime.expireRoutingInput,
1320
+ beforeQueueReceiptPublished: inboundRouteRuntime.beforeQueueReceiptPublished,
1321
+ onQueueReceiptCompleted: inboundRouteRuntime.onQueueReceiptCompleted,
1203
1322
  defaultHandle: inboundRouteRuntime.handleUpdate,
1323
+ async shouldReviewHistoricalInput(entry, ctx, signal) {
1324
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1325
+ throw new Error("Workspace Restore source generation ended.");
1326
+ }
1327
+ const verdict = await inboundRouteRuntime.shouldReviewHistoricalInput(entry, ctx, signal);
1328
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1329
+ throw new Error("Workspace Restore source generation ended.");
1330
+ }
1331
+ if (verdict === "retain") return verdict;
1332
+ const journalBindingKey = getTelegramQueueJournalBinding();
1333
+ if (journalBindingKey && resolveWorkspaceRestoreStore()?.list().some(function (intent) {
1334
+ return intent.request.source.journalBindingKey === journalBindingKey &&
1335
+ intent.request.source.updateIds.includes(entry.updateId);
1336
+ })) return true;
1337
+ return verdict;
1338
+ },
1339
+ spendHistoricalInput: true,
1340
+ onHeldSourcesPrepared(input): Promise<void> {
1341
+ return inboundRouteRuntime.forgetPreviousWorld(input, lockedPollingRuntime.captureTransportAuthority).then(function () {});
1342
+ },
1343
+ async shouldHoldPendingInput(entry, ctx, signal) {
1344
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1345
+ throw new Error("Temporary Thread source generation ended.");
1346
+ }
1347
+ return inboundRouteRuntime.shouldHoldPendingInput(entry, ctx, signal);
1348
+ },
1204
1349
  onStateChange: runtimeDiagnostics.scheduleSnapshotPersist,
1205
1350
  settleTerminalExecutionFailure(error) {
1206
1351
  return Sync.settleStaleTelegramTopicExecutionFailure(
@@ -1217,6 +1362,11 @@ export default function (pi: Pi.ExtensionAPI) {
1217
1362
  resolveBinding: resolveTelegramFollowerJournalBinding,
1218
1363
  isRegistered: telegramBusFollowerRegistrationState.isRegistered,
1219
1364
  getGeneration: telegramBusFollowerRegistrationState.getGeneration,
1365
+ prepareBinding(binding) {
1366
+ telegramJournalBindingRuntime.prepareActiveFollowerSuccession(function isCurrent() {
1367
+ return binding.hasAuthority?.() === true;
1368
+ });
1369
+ },
1220
1370
  prepareUpdateForExecution(update) {
1221
1371
  return BusFollower.prepareTelegramBusFollowerJournaledUpdateForExecution(
1222
1372
  update,
@@ -1296,6 +1446,32 @@ export default function (pi: Pi.ExtensionAPI) {
1296
1446
  local: agentMessageRuntime,
1297
1447
  follower: telegramBusFollowerClients.agentMessages,
1298
1448
  });
1449
+ const followerWorkspaceRestore = BusFollower.createTelegramBusFollowerWorkspaceRestoreHandler({
1450
+ instanceId: telegramInstanceId,
1451
+ getContextAuthority: BusFollower.createTelegramBusFollowerRestoreContextGetter({
1452
+ isContextCurrent: telegramSessionContextStore.isCurrent,
1453
+ getSessionId: Pi.getExtensionContextSessionId,
1454
+ getCwd: Pi.getExtensionContextCwd,
1455
+ getGeneration: telegramSessionContextStore.getGeneration,
1456
+ getProfileBindingKey() {
1457
+ return workspaceAdmissionRuntime.resolve()?.getProfileKey();
1458
+ },
1459
+ getOperatorUserId: configStore.getAllowedUserId,
1460
+ getLeaderState: lockRuntime.getState,
1461
+ getAuthenticatedSecret: telegramBusFollowerControlState.getActiveAuthSecret,
1462
+ getLeaderProtocol: telegramBusFollowerRegistrationState.getLeaderProtocol,
1463
+ }),
1464
+ readRestoreIntent(operationId, profileBindingKey) {
1465
+ if (profileBindingKey !== workspaceAdmissionRuntime.resolve()?.getProfileKey()) return undefined;
1466
+ return resolveWorkspaceRestoreStore()?.list().find(function (intent) {
1467
+ return intent.request.operationId === operationId;
1468
+ });
1469
+ },
1470
+ topicTargetStore: threadStore,
1471
+ registrationState: telegramBusFollowerRegistrationState,
1472
+ getWorkspaceAdmission: workspaceAdmissionRuntime.resolve,
1473
+ recordRuntimeEvent,
1474
+ });
1299
1475
  const telegramBusFollowerAssembly: BusFollower.TelegramBusFollowerRuntimeAssembly<Pi.ExtensionContext> =
1300
1476
  BusFollower.createTelegramBusFollowerRuntimeAssembly<Pi.ExtensionContext>({
1301
1477
  instanceId: telegramInstanceId,
@@ -1308,15 +1484,11 @@ export default function (pi: Pi.ExtensionAPI) {
1308
1484
  getRecipientBindingKey: getTelegramManualFollowerProfileKey,
1309
1485
  durableAdmission: followerDurableAdmissionRuntime,
1310
1486
  handleQueueHandoff: acceptStagedQueueHandoff,
1311
- },
1312
- targetReplacement: {
1313
- topicTargetStore: threadStore,
1314
- getManualFollowerProfileKey: getTelegramManualFollowerProfileKey,
1315
- manualFollowerOwnerId: telegramManualFollowerOwnerId,
1316
- getWorkspaceAdmission: workspaceAdmissionRuntime.resolve,
1317
- getSyncState: telegramSyncStateRuntime.getState,
1318
- setSyncState: telegramSyncStateRuntime.setState,
1319
- updateStatus,
1487
+ handleWorkspaceRestore: followerWorkspaceRestore,
1488
+ isWorkspaceRestoreEnabled() {
1489
+ return Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) &&
1490
+ Bus.hasTelegramBusCapability(telegramBusFollowerRegistrationState.getLeaderProtocol(), Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE);
1491
+ },
1320
1492
  },
1321
1493
  recovery: {
1322
1494
  getLeaderState: lockRuntime.getState,
@@ -1424,6 +1596,17 @@ export default function (pi: Pi.ExtensionAPI) {
1424
1596
  const authorizeFollowerApiCall = Bus.createTelegramFollowerApiCallAuthorizer({
1425
1597
  isMessageOwned: messageOwnershipRuntime.isOwnedByFollower,
1426
1598
  });
1599
+ const telegramSessionFolderSweeper = Recovery.createTelegramSessionFolderSweeper({
1600
+ getSessionsDir: Paths.resolveTelegramSessionsDir,
1601
+ getProfileName: configStore.getActiveProfileName,
1602
+ getKeptSessionIds() {
1603
+ return [
1604
+ ...threadStore.listWorkspaceBindings().map(function bindingSession(binding) { return binding.sessionId; }),
1605
+ ...telegramBusFollowerRegistry.list().map(function followerSession(follower) { return follower.sessionId; }),
1606
+ Pi.getExtensionContextSessionId(telegramSessionContextStore.get()),
1607
+ ];
1608
+ },
1609
+ });
1427
1610
  const telegramBusLeaderRuntime =
1428
1611
  BusLeader.createTelegramBusLeaderRuntimeAssembly<Pi.ExtensionContext>({
1429
1612
  runtime: {
@@ -1448,11 +1631,15 @@ export default function (pi: Pi.ExtensionAPI) {
1448
1631
  });
1449
1632
  },
1450
1633
  isFollowerProcessAlive: Locks.isProcessAlive,
1634
+ afterFollowerPrune() { telegramSessionFolderSweeper.sweep(); },
1451
1635
  shouldCleanupConfirmedDeadFollower:
1452
1636
  configControls.resolveAutomaticThreadCleanupEnabled,
1453
1637
  recordFollowerMessageOwnership(record) {
1454
1638
  messageOwnershipRuntime.recordFollower(record);
1455
1639
  },
1640
+ onWorkspaceRestoreRecipientObserved(follower, isCurrent) {
1641
+ return inboundRouteRuntime.onWorkspaceRestoreRecipientObserved(follower, isCurrent, telegramSessionContextStore.get());
1642
+ },
1456
1643
  },
1457
1644
  getAllowedUserId: configStore.getAllowedUserId,
1458
1645
  instanceId: telegramInstanceId,
@@ -1481,6 +1668,7 @@ export default function (pi: Pi.ExtensionAPI) {
1481
1668
  getAdmission: workspaceAdmissionRuntime.resolve,
1482
1669
  runExclusive: telegramWorkspaceOperationRuntime.runExclusive,
1483
1670
  deleteThread: directTelegramApiRuntime.deleteWorkspaceThread,
1671
+ pruneJournalEvidence: pruneWorkspaceJournalEvidence,
1484
1672
  reclaimDeadOwnerQueuedWork(binding, isCurrent) {
1485
1673
  return telegramWorkspaceOperationRuntime.run({
1486
1674
  operationId: WorkspaceAdmission.createTelegramWorkspaceAdmissionOperationId(),
@@ -1583,6 +1771,12 @@ export default function (pi: Pi.ExtensionAPI) {
1583
1771
  const threadAwarePollingPorts = telegramThreadCapabilityRuntime.pollingPorts;
1584
1772
  const lockedPollingRuntime = Locks.createTelegramLockedPollingRuntime({
1585
1773
  lock: lockRuntime,
1774
+ resetDamagedState() {
1775
+ return Locks.resetDamagedTelegramRuntimeState(Paths.resolveTelegramStatePath(), function (profile, sections) {
1776
+ Threads.parseTelegramWorkspaceStateSection(sections.workspace, profile);
1777
+ WorkspaceAdmission.assertTelegramConsolidatedAdmissionSection(sections.admission, profile);
1778
+ });
1779
+ },
1586
1780
  transportMonitor: telegramThreadCapabilityMonitor,
1587
1781
  hasBotToken: configStore.hasBotToken,
1588
1782
  getBotTokenDiagnostic: configStore.getBotTokenDiagnostic,
@@ -1666,7 +1860,10 @@ export default function (pi: Pi.ExtensionAPI) {
1666
1860
  syncCounters: queue.syncCounters,
1667
1861
  syncFlags: lifecycle.syncFlags,
1668
1862
  bindDeferredDispatchContext: deferredQueueDispatchRuntime.bind,
1669
- prepareTempDir,
1863
+ prepareTempDir() {
1864
+ Recovery.removeTelegramLegacyRecoveryStorage(Paths.resolveTelegramTempDir());
1865
+ return prepareTempDir();
1866
+ },
1670
1867
  updateStatus,
1671
1868
  unbindDeferredDispatchContext: deferredQueueDispatchRuntime.unbind,
1672
1869
  discardQueuedItems: queueMutationRuntime.clear,
@@ -1824,20 +2021,7 @@ export default function (pi: Pi.ExtensionAPI) {
1824
2021
  activeTurnRuntime,
1825
2022
  lockedPollingRuntime,
1826
2023
  stopPolling: disconnectTelegramAndDeleteCurrentThread,
1827
- recoverPollingStart: Recovery.createTelegramPollingStartRecoveryHandler({
1828
- getOwnersPath: Paths.resolveTelegramOwnersPath,
1829
- getStatePaths() {
1830
- return [
1831
- Threads.getTelegramTopicTargetsPath(
1832
- undefined,
1833
- configStore.getActiveProfileName(),
1834
- ),
1835
- ];
1836
- },
1837
- suspendPolling: lockedPollingRuntime.suspend,
1838
- releaseOwnership: lockRuntime.release,
1839
- recordRuntimeEvent,
1840
- }),
2024
+ // Consolidated envelope failures remain protective; legacy whole-file recovery cannot reset sibling authority.
1841
2025
  getDisconnectThreadName() {
1842
2026
  const record = findCurrentThreadRecord();
1843
2027
  if (!record?.target.threadId) return undefined;
@@ -1862,7 +2046,7 @@ export default function (pi: Pi.ExtensionAPI) {
1862
2046
  const botToken = configStore.getBotToken();
1863
2047
  if (!botToken) throw new Error("Telegram channel delivery requires an active bot token.");
1864
2048
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1865
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
2049
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1866
2050
  profileName,
1867
2051
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1868
2052
  });
@@ -1893,7 +2077,7 @@ export default function (pi: Pi.ExtensionAPI) {
1893
2077
  const caption = Replies.renderTelegramMarkdownToHtmlDraft(markdown);
1894
2078
  ChannelPosts.assertTelegramChannelPostCaptionWithinLimit(caption);
1895
2079
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1896
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
2080
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1897
2081
  profileName,
1898
2082
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1899
2083
  });
@@ -1922,7 +2106,7 @@ export default function (pi: Pi.ExtensionAPI) {
1922
2106
  const botToken = configStore.getBotToken();
1923
2107
  if (!botToken) throw new Error("Telegram channel posts require an active bot token.");
1924
2108
  return ChannelPosts.createTelegramChannelPostJournalStore({
1925
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
2109
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1926
2110
  profileName,
1927
2111
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1928
2112
  }).list(input);
@@ -1933,7 +2117,7 @@ export default function (pi: Pi.ExtensionAPI) {
1933
2117
  const botToken = configStore.getBotToken();
1934
2118
  if (!botToken) throw new Error("Telegram channel post mutation requires an active bot token.");
1935
2119
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1936
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName), profileName,
2120
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName), profileName,
1937
2121
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1938
2122
  });
1939
2123
  if (input.action === "edit") {
@@ -1995,6 +2179,7 @@ export default function (pi: Pi.ExtensionAPI) {
1995
2179
  },
1996
2180
  activityRuntime,
1997
2181
  activityVerbosityRuntime,
2182
+ diagnostics: runtimeDiagnostics,
1998
2183
  assistantOutputRuntime,
1999
2184
  publicationRuntime,
2000
2185
  configStore,
@@ -44,28 +44,6 @@ export type GenerativeAppJsonValue =
44
44
  | GenerativeAppJsonValue[]
45
45
  | { [key: string]: GenerativeAppJsonValue };
46
46
 
47
- export interface GenerativeAppProcessInput {
48
- command: string;
49
- args?: string[];
50
- cwd: string;
51
- timeoutMs?: number;
52
- }
53
-
54
- export interface GenerativeAppProcessResult {
55
- code: number;
56
- killed: boolean;
57
- stderr: string;
58
- stdout: string;
59
- }
60
-
61
- export interface GenerativeAppMethodContext {
62
- argument?: GenerativeAppJsonValue;
63
- revision: number;
64
- run: (input: GenerativeAppProcessInput) => Promise<GenerativeAppProcessResult>;
65
- signal: AbortSignal;
66
- state?: GenerativeAppJsonValue;
67
- }
68
-
69
47
  export interface GenerativeAppMethodResult {
70
48
  output: string;
71
49
  refreshAfterMs?: number;
@@ -162,7 +162,7 @@ export function registerTelegramInboundHandler(
162
162
  };
163
163
  }
164
164
 
165
- export function getTelegramInboundProgrammaticHandlers(
165
+ function getTelegramInboundProgrammaticHandlers(
166
166
  kind: string,
167
167
  ): TelegramInboundProgrammaticHandler[] {
168
168
  const registry = getOrCreateInboundHandlerRegistry();
@@ -255,7 +255,7 @@ export function telegramInboundHandlerMatchesFile(
255
255
  return matchesAnyPattern(matchPatterns, file.kind);
256
256
  }
257
257
 
258
- export function findTelegramInboundHandlers(
258
+ function findTelegramInboundHandlers(
259
259
  handlers: TelegramInboundHandlerConfig[] | undefined,
260
260
  file: TelegramInboundHandlerFile,
261
261
  ): TelegramInboundHandlerConfig[] {