@llblab/pi-telegram 0.51.5 → 0.52.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 (181) hide show
  1. package/AGENTS.md +10 -8
  2. package/BACKLOG.md +1 -8
  3. package/CHANGELOG.md +23 -0
  4. package/LICENSE +21 -0
  5. package/README.md +16 -6
  6. package/dist/lib/activity-verbosity.d.ts +1 -5
  7. package/dist/lib/activity-verbosity.js +5 -7
  8. package/dist/lib/bindings.d.ts +9 -2
  9. package/dist/lib/bindings.js +22 -13
  10. package/dist/lib/bus-api.js +4 -2
  11. package/dist/lib/bus-follower.d.ts +55 -57
  12. package/dist/lib/bus-follower.js +213 -140
  13. package/dist/lib/bus-leader.d.ts +21 -2
  14. package/dist/lib/bus-leader.js +181 -25
  15. package/dist/lib/bus-transport.d.ts +4 -1
  16. package/dist/lib/bus-transport.js +28 -4
  17. package/dist/lib/bus.d.ts +52 -56
  18. package/dist/lib/bus.js +78 -246
  19. package/dist/lib/channel-posts.d.ts +1 -3
  20. package/dist/lib/channel-posts.js +23 -26
  21. package/dist/lib/command-templates.d.ts +0 -5
  22. package/dist/lib/command-templates.js +5 -5
  23. package/dist/lib/commands.d.ts +12 -26
  24. package/dist/lib/commands.js +152 -98
  25. package/dist/lib/config.d.ts +0 -17
  26. package/dist/lib/config.js +12 -14
  27. package/dist/lib/delivery.d.ts +0 -4
  28. package/dist/lib/delivery.js +2 -5
  29. package/dist/lib/extension.js +281 -61
  30. package/dist/lib/generative-apps.d.ts +0 -19
  31. package/dist/lib/inbound.d.ts +0 -2
  32. package/dist/lib/inbound.js +2 -2
  33. package/dist/lib/journal.d.ts +177 -16
  34. package/dist/lib/journal.js +1115 -249
  35. package/dist/lib/keyboard.d.ts +0 -2
  36. package/dist/lib/keyboard.js +2 -2
  37. package/dist/lib/lifecycle.d.ts +57 -2
  38. package/dist/lib/lifecycle.js +110 -5
  39. package/dist/lib/locks.d.ts +100 -12
  40. package/dist/lib/locks.js +380 -14
  41. package/dist/lib/logging.d.ts +30 -12
  42. package/dist/lib/logging.js +129 -72
  43. package/dist/lib/media.d.ts +28 -5
  44. package/dist/lib/media.js +26 -8
  45. package/dist/lib/menu-model.d.ts +0 -11
  46. package/dist/lib/menu-model.js +8 -8
  47. package/dist/lib/menu-settings.d.ts +0 -18
  48. package/dist/lib/menu-settings.js +18 -18
  49. package/dist/lib/menu-status.d.ts +4 -4
  50. package/dist/lib/menu-status.js +12 -7
  51. package/dist/lib/menu-thinking.d.ts +1 -1
  52. package/dist/lib/menu-thinking.js +1 -1
  53. package/dist/lib/menu.d.ts +1 -0
  54. package/dist/lib/menu.js +4 -3
  55. package/dist/lib/model.js +2 -4
  56. package/dist/lib/outbound-attachments.d.ts +0 -1
  57. package/dist/lib/outbound-attachments.js +1 -1
  58. package/dist/lib/outbound-buttons.js +1 -8
  59. package/dist/lib/outbound-markup.d.ts +1 -6
  60. package/dist/lib/outbound-markup.js +4 -21
  61. package/dist/lib/outbound.d.ts +0 -8
  62. package/dist/lib/outbound.js +5 -5
  63. package/dist/lib/paths.d.ts +50 -7
  64. package/dist/lib/paths.js +155 -17
  65. package/dist/lib/pi.d.ts +1 -0
  66. package/dist/lib/pi.js +2 -1
  67. package/dist/lib/polling.d.ts +0 -5
  68. package/dist/lib/polling.js +5 -5
  69. package/dist/lib/preview.d.ts +0 -3
  70. package/dist/lib/preview.js +3 -3
  71. package/dist/lib/prompt-templates.d.ts +0 -1
  72. package/dist/lib/prompt-templates.js +1 -1
  73. package/dist/lib/queue.d.ts +3 -15
  74. package/dist/lib/queue.js +69 -8
  75. package/dist/lib/recovery.d.ts +29 -9
  76. package/dist/lib/recovery.js +104 -33
  77. package/dist/lib/replies.d.ts +0 -4
  78. package/dist/lib/replies.js +1 -1
  79. package/dist/lib/routing.d.ts +73 -8
  80. package/dist/lib/routing.js +2206 -307
  81. package/dist/lib/sections.d.ts +0 -2
  82. package/dist/lib/sections.js +1 -1
  83. package/dist/lib/status.d.ts +46 -9
  84. package/dist/lib/status.js +179 -27
  85. package/dist/lib/sync.d.ts +0 -5
  86. package/dist/lib/sync.js +9 -8
  87. package/dist/lib/telegram-api.d.ts +11 -3
  88. package/dist/lib/telegram-api.js +34 -23
  89. package/dist/lib/thread-cleanup-manager.d.ts +1 -0
  90. package/dist/lib/thread-cleanup-manager.js +18 -21
  91. package/dist/lib/thread-naming.d.ts +32 -5
  92. package/dist/lib/thread-naming.js +191 -7
  93. package/dist/lib/thread-reconciler.d.ts +2 -0
  94. package/dist/lib/thread-reconciler.js +1 -1
  95. package/dist/lib/threads.d.ts +292 -59
  96. package/dist/lib/threads.js +1664 -373
  97. package/dist/lib/turns.d.ts +0 -1
  98. package/dist/lib/turns.js +1 -1
  99. package/dist/lib/updates.d.ts +184 -28
  100. package/dist/lib/updates.js +1032 -114
  101. package/dist/lib/wire.d.ts +12 -0
  102. package/dist/lib/wire.js +21 -0
  103. package/dist/lib/workspace-admission.d.ts +25 -17
  104. package/dist/lib/workspace-admission.js +95 -20
  105. package/dist/lib/workspace-identity.d.ts +20 -0
  106. package/dist/lib/workspace-identity.js +103 -0
  107. package/dist/lib/workspace-retirement.d.ts +45 -10
  108. package/dist/lib/workspace-retirement.js +196 -64
  109. package/dist/package.json +6 -6
  110. package/dist/skills/generated-control-surface/SKILL.md +3 -3
  111. package/dist/skills/telegram-bridge/references/diagnosis.md +3 -3
  112. package/docs/README.md +1 -1
  113. package/docs/activity.md +1 -1
  114. package/docs/architecture.md +158 -39
  115. package/docs/callback-namespaces.md +1 -1
  116. package/docs/delivery.md +1 -1
  117. package/docs/generative-apps.md +2 -2
  118. package/docs/inbound.md +1 -1
  119. package/docs/multi-instance-bus.md +127 -19
  120. package/docs/public-api.md +5 -3
  121. package/docs/ui-style.md +26 -8
  122. package/docs/updates.md +1 -1
  123. package/lib/activity-verbosity.ts +5 -9
  124. package/lib/bindings.ts +23 -10
  125. package/lib/bus-api.ts +5 -2
  126. package/lib/bus-follower.ts +251 -226
  127. package/lib/bus-leader.ts +178 -31
  128. package/lib/bus-transport.ts +30 -8
  129. package/lib/bus.ts +110 -334
  130. package/lib/channel-posts.ts +29 -29
  131. package/lib/command-templates.ts +5 -5
  132. package/lib/commands.ts +150 -112
  133. package/lib/config.ts +12 -17
  134. package/lib/delivery.ts +2 -8
  135. package/lib/extension.ts +282 -72
  136. package/lib/generative-apps.ts +0 -22
  137. package/lib/inbound.ts +2 -2
  138. package/lib/journal.ts +1182 -326
  139. package/lib/keyboard.ts +2 -2
  140. package/lib/lifecycle.ts +141 -5
  141. package/lib/locks.ts +402 -23
  142. package/lib/logging.ts +151 -101
  143. package/lib/media.ts +51 -9
  144. package/lib/menu-model.ts +8 -8
  145. package/lib/menu-settings.ts +18 -18
  146. package/lib/menu-status.ts +11 -0
  147. package/lib/menu-thinking.ts +2 -2
  148. package/lib/menu.ts +5 -1
  149. package/lib/model.ts +2 -4
  150. package/lib/outbound-attachments.ts +1 -1
  151. package/lib/outbound-buttons.ts +1 -10
  152. package/lib/outbound-markup.ts +5 -24
  153. package/lib/outbound.ts +5 -5
  154. package/lib/paths.ts +177 -17
  155. package/lib/pi.ts +5 -2
  156. package/lib/polling.ts +5 -5
  157. package/lib/preview.ts +3 -3
  158. package/lib/prompt-templates.ts +1 -1
  159. package/lib/queue.ts +67 -9
  160. package/lib/recovery.ts +104 -44
  161. package/lib/replies.ts +1 -1
  162. package/lib/routing.ts +1955 -375
  163. package/lib/sections.ts +1 -1
  164. package/lib/status.ts +185 -36
  165. package/lib/sync.ts +8 -8
  166. package/lib/telegram-api.ts +48 -33
  167. package/lib/thread-cleanup-manager.ts +24 -21
  168. package/lib/thread-naming.ts +267 -9
  169. package/lib/thread-reconciler.ts +3 -1
  170. package/lib/threads.ts +1718 -491
  171. package/lib/turns.ts +1 -1
  172. package/lib/updates.ts +1072 -151
  173. package/lib/wire.ts +28 -0
  174. package/lib/workspace-admission.ts +97 -47
  175. package/lib/workspace-identity.ts +147 -0
  176. package/lib/workspace-retirement.ts +234 -102
  177. package/package.json +6 -6
  178. package/scripts/audit-exports.mjs +100 -0
  179. package/scripts/check-downgrade.mjs +80 -43
  180. package/skills/generated-control-surface/SKILL.md +3 -3
  181. package/skills/telegram-bridge/references/diagnosis.md +3 -3
@@ -46,7 +46,9 @@ import * as Sync from "./sync.js";
46
46
  import * as TelegramApi from "./telegram-api.js";
47
47
  import * as TextGroups from "./text-groups.js";
48
48
  import * as ThreadReconciler from "./thread-reconciler.js";
49
+ import * as Targets from "./target.js";
49
50
  import * as ThreadDisplay from "./thread-display.js";
51
+ import * as ThreadNaming from "./thread-naming.js";
50
52
  import * as Threads from "./threads.js";
51
53
  import * as TimeInjection from "./time-injection.js";
52
54
  import * as Updates from "./updates.js";
@@ -61,6 +63,7 @@ const telegramBusProtocolIdentity = Bus.createTelegramCurrentBusProtocolIdentity
61
63
  Bus.TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
62
64
  Bus.TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
63
65
  Bus.TELEGRAM_BUS_CAPABILITY_SESSION_REPLACEMENT_INTENT,
66
+ Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE,
64
67
  ]);
65
68
  // --- Extension Runtime ---
66
69
  export default function (pi) {
@@ -68,19 +71,20 @@ export default function (pi) {
68
71
  const piRuntime = Pi.createExtensionApiRuntimePorts(pi);
69
72
  const { getActiveTools, getCommands, getThinkingLevel, sendUserMessage, registerCommand, setActiveTools, setModel, setThinkingLevel, } = piRuntime;
70
73
  const bridgeRuntime = Runtime.createTelegramBridgeRuntime();
71
- const runtimeDiagnostics = Logging.createTelegramRuntimeDiagnosticsRuntime();
74
+ const runtimeDiagnostics = Logging.createTelegramRuntimeDiagnosticsRuntime({ sharedFile: true });
72
75
  const runtimeEvents = runtimeDiagnostics.events;
73
76
  const recordRuntimeEvent = runtimeDiagnostics.recordRuntimeEvent;
74
77
  const configStore = Config.createTelegramConfigStore({ recordRuntimeEvent });
75
78
  const busProcessRuntime = Bus.createCurrentTelegramBusProcessRuntime({
76
79
  getActiveProfileName: configStore.getActiveProfileName,
80
+ endpointLayout: "consolidated",
77
81
  });
78
82
  const { instanceId: telegramInstanceId, processId: telegramProcessId, processBirthId: telegramQueueProcessBirthId, manualFollowerOwnerId: telegramManualFollowerOwnerId, getLeaderSocketPath: getTelegramBusSocketPath, getFollowerSocketPath: getTelegramBusFollowerSocketPath, } = busProcessRuntime;
79
83
  const getTelegramBotId = Config.createTelegramConfigBotIdGetter(configStore);
80
84
  const workspaceAdmissionRuntime = WorkspaceAdmission.createTelegramWorkspaceAdmissionRuntimeBinding({
81
85
  getProfileName: configStore.getActiveProfileName,
82
86
  getBotToken: configStore.getBotToken,
83
- getPath: Paths.resolveTelegramWorkspaceAdmissionPathForProfile,
87
+ getStatePath: Paths.resolveTelegramStatePath,
84
88
  owner: {
85
89
  processId: telegramProcessId,
86
90
  processBirthId: telegramQueueProcessBirthId,
@@ -121,20 +125,26 @@ export default function (pi) {
121
125
  getBotToken: configStore.getBotToken,
122
126
  getBotId: getTelegramBotId,
123
127
  });
128
+ const telegramLeaderJournalPath = Locks.createTelegramLeaderJournalPathResolver({
129
+ getNamedJournalPath() { return lockRuntime.getJournalPath(); },
130
+ getSessionId() { return Pi.getExtensionContextSessionId(telegramSessionContextStore.get()); },
131
+ getProfileName: configStore.getActiveProfileName,
132
+ });
124
133
  const telegramJournalBindingRuntime = Journal.createTelegramUpdateJournalBindingRuntime({
125
134
  base: {
126
135
  getProfileName: configStore.getActiveProfileName,
127
136
  getBotToken: configStore.getBotToken,
128
137
  getBotId: getTelegramBotId,
138
+ withSourceSerialization: configStore.withSourceSerialization,
129
139
  onRecovery(event) {
130
140
  recordRuntimeEvent("recovery", event.kind === "repaired"
131
141
  ? "Telegram update journal was repaired automatically."
132
- : "Telegram update journal was reset after its damaged files were quarantined.", {
142
+ : "Telegram update journal was reset after its damaged files were deleted.", {
133
143
  phase: "journal-auto-recovery",
134
144
  recoveryKind: event.kind,
135
145
  journalPath: event.path,
136
146
  revision: event.revision,
137
- quarantinePath: event.quarantinePath,
147
+ deletedPaths: event.deletedPaths,
138
148
  reason: event.reason,
139
149
  });
140
150
  },
@@ -147,11 +157,17 @@ export default function (pi) {
147
157
  },
148
158
  getWorkspaceAdmission: workspaceAdmissionRuntime.resolve,
149
159
  },
150
- getLeaderJournalPath: Paths.resolveTelegramUpdateJournalPathForProfile,
151
- getFollowerJournalPath(bindingKey, profileName) {
160
+ getLeaderJournalPath: telegramLeaderJournalPath.resolve,
161
+ getRuntimeDir: Paths.resolveTelegramTempDir,
162
+ getFollowerJournalPath(bindingKey, profileName, sessionId) {
163
+ if (sessionId !== undefined)
164
+ return Paths.resolveTelegramSessionJournalPath(sessionId, bindingKey, undefined, profileName);
152
165
  return Paths.resolveTelegramFollowerJournalPath(bindingKey, undefined, profileName);
153
166
  },
154
167
  getActiveFollowerBindingKey: getTelegramManualFollowerProfileKey,
168
+ getActiveFollowerSessionId() {
169
+ return telegramBusFollowerRegistrationState.getSessionId(Pi.getExtensionContextSessionId(telegramSessionContextStore.get()));
170
+ },
155
171
  isFollowerRegistered: telegramBusFollowerRegistrationState.isRegistered,
156
172
  });
157
173
  const telegramJournalReferenceRegistry = Journal.createTelegramUpdateJournalReferenceRegistry();
@@ -163,28 +179,44 @@ export default function (pi) {
163
179
  const configControls = Config.createTelegramConfigControls(configStore);
164
180
  const lockRuntime = Locks.createTelegramLockRuntime({
165
181
  key: Locks.createTelegramLockKeyResolver(configStore),
182
+ statePath: Paths.resolveTelegramStatePath(),
166
183
  instanceId: telegramInstanceId,
167
184
  busSecret: telegramBusAuthSecret,
168
185
  staleHeartbeatMs: Locks.TELEGRAM_BUS_LEADER_STALE_HEARTBEAT_MS,
186
+ legacyLocksPath: Paths.resolveLegacyTelegramOwnersPath(),
187
+ createJournalPath() { return telegramLeaderJournalPath.createJournalPath(); },
169
188
  });
170
- const threadStore = Threads.createTelegramTopicTargetStore({
171
- path: function () {
172
- return Threads.getTelegramTopicTargetsPath(undefined, configStore.getActiveProfileName());
189
+ const telegramSessionContextStore = Lifecycle.createTelegramSessionContextStore({
190
+ getIdentity(ctx) {
191
+ return ctx.sessionManager ?? ctx.cwd;
173
192
  },
193
+ });
194
+ const captureTelegramStateAuthority = Locks.createTelegramOwnedStateAuthorityCapture(lockRuntime, telegramSessionContextStore);
195
+ const threadStore = Threads.createTelegramTopicTargetStore({
196
+ path: Paths.resolveTelegramStatePath,
174
197
  telegramProfile: function () {
175
198
  return configStore.getActiveProfileName();
176
199
  },
177
200
  canPersist: lockRuntime.owns,
178
- commitPersist: lockRuntime.commitIfOwned,
201
+ consolidated: {
202
+ captureAuthority: captureTelegramStateAuthority,
203
+ publishIfOwned: lockRuntime.publishStateSectionIfOwned,
204
+ },
179
205
  getExternalReservedSlots: function () {
180
206
  return workspaceAdmissionRuntime.resolve()?.listReservedSlots() ?? [];
181
207
  },
182
208
  });
209
+ const resolveWorkspaceRestoreStore = Threads.createTelegramWorkspaceRestoreResolver({
210
+ getProfileName: configStore.getActiveProfileName,
211
+ getBotToken: configStore.getBotToken,
212
+ threadStore,
213
+ });
183
214
  runtimeDiagnostics.bindStorage({
184
215
  getBotToken: configStore.getBotToken,
185
216
  getProfileName: configStore.getActiveProfileName,
186
217
  canReset: lockRuntime.owns,
187
218
  commitReset: lockRuntime.commitIfOwned,
219
+ captureAuthority: captureTelegramStateAuthority,
188
220
  });
189
221
  const sessionActionAssembly = Commands.createTelegramSessionActionAssembly({
190
222
  registerCommand,
@@ -220,11 +252,6 @@ export default function (pi) {
220
252
  const sessionActionsRuntime = sessionActionAssembly.action;
221
253
  const lockOwnershipGuard = Locks.createTelegramLockOwnershipGuard(lockRuntime);
222
254
  const getCurrentLeaderEpoch = lockRuntime.getOwnedLeaderEpoch;
223
- const telegramSessionContextStore = Lifecycle.createTelegramSessionContextStore({
224
- getIdentity(ctx) {
225
- return ctx.sessionManager ?? ctx.cwd;
226
- },
227
- });
228
255
  const ownsTelegramDirectDelivery = Locks.createTelegramDirectDeliveryOwnershipChecker({
229
256
  lock: lockRuntime,
230
257
  contextStore: telegramSessionContextStore,
@@ -275,12 +302,13 @@ export default function (pi) {
275
302
  });
276
303
  const telegramQueueStore = Queue.createTelegramTransportStampedQueueStore(rawTelegramQueueStore, telegramTransportStampRuntime.getStamp);
277
304
  const telegramApiTargetActivityRuntime = TelegramApi.createTelegramApiTargetActivityRuntime();
278
- const captureWorkspaceExternalProtection = WorkspaceRetirement.createTelegramWorkspaceExternalProtectionCapture({
305
+ const workspaceProtectionObserver = WorkspaceRetirement.createTelegramWorkspaceProtectionObserver({
279
306
  listFollowers: telegramBusFollowerRegistry.list,
280
307
  getActiveTurnTarget: activeTurnRuntime.getTarget,
281
308
  getQueuedItems: telegramQueueStore.getQueuedItems,
282
309
  resolveLeaderJournal: resolveTelegramUpdateJournalBinding,
283
- createFollowerJournalResolver: telegramJournalBindingRuntime.createRecipientResolver,
310
+ createFollowerJournalResolver: telegramJournalBindingRuntime.createLegacyRecipientResolver,
311
+ createSessionJournalResolver: telegramJournalBindingRuntime.createRecipientResolver,
284
312
  withJournalReference(binding, operation) {
285
313
  if (!binding.recoveryKey)
286
314
  throw new Error("Telegram workspace journal reference identity is unavailable.");
@@ -290,12 +318,25 @@ export default function (pi) {
290
318
  }, operation);
291
319
  },
292
320
  discoverFollowerJournals() {
293
- return Journal.discoverTelegramFollowerJournalPaths({
321
+ return Journal.discoverTelegramRecipientJournalPaths({
294
322
  directory: Paths.resolveTelegramTempDir(),
295
323
  profileName: configStore.getActiveProfileName(),
296
324
  });
297
325
  },
298
326
  createJournalPathResolver: telegramJournalBindingRuntime.createPathResolver,
327
+ inspectJournalNamespace() {
328
+ const botToken = configStore.getBotToken();
329
+ if (!botToken)
330
+ throw new Error("Telegram namespace inspection requires current bot identity.");
331
+ return Journal.inspectTelegramSessionJournalNamespace({
332
+ directory: Paths.resolveTelegramTempDir(),
333
+ profile: configStore.getActiveProfileName() ?? "default",
334
+ pollingPath: telegramLeaderJournalPath.resolve(configStore.getActiveProfileName()),
335
+ botIdentity: Journal.createTelegramUpdateJournalBotIdentity({ botToken, botId: getTelegramBotId() }),
336
+ limits: { maxDirectoryEntries: 10_000, maxFiles: 4096, maxBytes: 64 * 1024 * 1024,
337
+ maxEntries: 10_000, maxWork: 100_000 },
338
+ });
339
+ },
299
340
  getJournalWriterProtection(journalBindingKey) {
300
341
  const owner = Threads.getTelegramThreadOwnerFromProfileKey(journalBindingKey);
301
342
  if (owner.kind !== "manual-follower")
@@ -306,19 +347,33 @@ export default function (pi) {
306
347
  : liveness === "dead" ? "clear" : "unknown";
307
348
  },
308
349
  getDeliveryAuthorityProtection(binding) {
309
- return telegramApiTargetActivityRuntime.hasPendingTarget(binding.target)
350
+ const retainedRestore = resolveWorkspaceRestoreStore()?.list().some(function (intent) {
351
+ return intent.request.binding.bindingKey === binding.bindingKey ||
352
+ Targets.areTelegramTargetsEqual(intent.request.binding.target, binding.target) ||
353
+ Targets.areTelegramTargetsEqual(intent.request.target, binding.target);
354
+ });
355
+ return retainedRestore || telegramApiTargetActivityRuntime.hasPendingTarget(binding.target)
310
356
  ? "protected"
311
357
  : "clear";
312
358
  },
313
359
  });
360
+ const captureWorkspaceExternalProtection = workspaceProtectionObserver.capture;
361
+ const pruneWorkspaceJournalEvidence = WorkspaceRetirement.createTelegramWorkspaceJournalEvidencePruner({
362
+ store: threadStore,
363
+ getAdmission: workspaceAdmissionRuntime.resolve,
364
+ getLeaderEpoch: getCurrentLeaderEpoch,
365
+ runExclusive: telegramWorkspaceOperationRuntime.runExclusive,
366
+ protection: workspaceProtectionObserver,
367
+ });
314
368
  const reclaimTelegramWorkspaceDeadOwnerQueue = WorkspaceRetirement.createTelegramWorkspaceDeadOwnerQueueReclaimer({
315
369
  getExternalProtection: captureWorkspaceExternalProtection,
316
370
  getActiveTurnTarget: activeTurnRuntime.getTarget,
317
371
  getQueuedItems: telegramQueueStore.getQueuedItems,
318
372
  resolveLeaderJournal: resolveTelegramUpdateJournalBinding,
319
- createFollowerJournalResolver: telegramJournalBindingRuntime.createRecipientResolver,
373
+ createFollowerJournalResolver: telegramJournalBindingRuntime.createLegacyRecipientResolver,
374
+ createSessionJournalResolver: telegramJournalBindingRuntime.createRecipientResolver,
320
375
  discoverFollowerJournals() {
321
- return Journal.discoverTelegramFollowerJournalPaths({
376
+ return Journal.discoverTelegramRecipientJournalPaths({
322
377
  directory: Paths.resolveTelegramTempDir(),
323
378
  profileName: configStore.getActiveProfileName(),
324
379
  });
@@ -363,7 +418,7 @@ export default function (pi) {
363
418
  if (!botToken)
364
419
  throw new Error("Telegram Thread cleanup review requires an active bot token.");
365
420
  return ThreadCleanupManager.createTelegramThreadCleanupWorkStore({
366
- path: Paths.resolveTelegramThreadCleanupWorkPath(undefined, profileName),
421
+ ...Paths.resolveTelegramServiceJournalStorage("thread-cleanup", undefined, profileName),
367
422
  profileName,
368
423
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
369
424
  });
@@ -460,9 +515,10 @@ export default function (pi) {
460
515
  instanceId: telegramInstanceId,
461
516
  updateStatus: statusRuntime.updateStatus,
462
517
  getStatusState: statusRuntime.getStatusState,
518
+ session: telegramSessionContextStore,
463
519
  async persistSnapshot(snapshot) {
464
520
  threadStore.setStatusSnapshot(snapshot);
465
- await threadStore.persist();
521
+ await threadStore.persistStatus();
466
522
  },
467
523
  });
468
524
  const updateStatus = runtimeDiagnostics.updateStatus;
@@ -476,6 +532,10 @@ export default function (pi) {
476
532
  // --- Telegram API ---
477
533
  const directTelegramApiRuntime = TelegramApi.createDefaultTelegramBridgeApiRuntime({
478
534
  getBotToken: configStore.getBotToken,
535
+ getBotScope() {
536
+ const config = configStore.get();
537
+ return config.botUsername ?? (config.botId === undefined ? undefined : String(config.botId));
538
+ },
479
539
  recordRuntimeEvent,
480
540
  targetActivity: telegramApiTargetActivityRuntime,
481
541
  workspaceAdmission: workspaceAdmissionRuntime.resolve,
@@ -708,6 +768,10 @@ export default function (pi) {
708
768
  getActiveModel: currentModelRuntime.get,
709
769
  getThinkingLevel,
710
770
  getQueueItemCount,
771
+ getPendingCancellationCount() {
772
+ return getCurrentLeaderEpoch() === undefined ? 0 :
773
+ updateAdmissionRuntimeBinding.getActive()?.getState()?.abandoningClaimCount ?? 0;
774
+ },
711
775
  buildStatusHtml: Commands.createTelegramAppMenuHtmlBuilder({
712
776
  buildStatusHtml: Status.createTelegramStatusHtmlBuilder({
713
777
  getActiveModel: currentModelRuntime.get,
@@ -792,16 +856,11 @@ export default function (pi) {
792
856
  }, sectionRegistry);
793
857
  // --- Polling ---
794
858
  const foreignOwnedUpdateForwarder = telegramBusFollowerClients.foreignOwnedUpdateForwarder;
795
- const followerTargetController = telegramBusFollowerClients.targetController;
796
- const restoreFollowerThreadTarget = Bus.createTelegramBusFollowerThreadRestoreHandler({
797
- followerRegistry: telegramBusFollowerRegistry,
798
- followerTargetController,
799
- onRestored() {
800
- telegramSyncStateRuntime.markSliceFresh(Sync.TELEGRAM_SYNC_SLICE_TARGET_BINDINGS, {
801
- nowMs: Date.now(),
802
- action: "follower-thread-restore",
803
- });
804
- },
859
+ const workspaceRestoreFollowerController = Bus.createTelegramBusWorkspaceRestoreController({
860
+ getFollower: telegramBusFollowerRegistry.get,
861
+ localProtocolIdentity: telegramBusProtocolIdentity,
862
+ createRequestId: telegramBusFollowerClients.createRequestId,
863
+ getAuthSecret() { return telegramBusAuthSecret; },
805
864
  });
806
865
  const observedThreadTargetBinding = Polling.createTelegramThreadTargetObservationBinding();
807
866
  const topicLifecycleSync = Sync.createTelegramObservedTopicLifecycleSyncHandler({
@@ -852,7 +911,63 @@ export default function (pi) {
852
911
  return observedThreadTargetBinding.handle(ctx);
853
912
  },
854
913
  foreignOwnedUpdateForwarder,
855
- replaceFollowerThreadTarget: restoreFollowerThreadTarget,
914
+ workspaceRestoreRecipient: {
915
+ getSessionId: Pi.getExtensionContextSessionId,
916
+ getCwd: Pi.getExtensionContextCwd,
917
+ getLeaderIdentity: telegramBusLeaderState.getIdentity,
918
+ followerRegistry: telegramBusFollowerRegistry,
919
+ runFollower: workspaceRestoreFollowerController,
920
+ },
921
+ getWorkspaceRestoreStore: resolveWorkspaceRestoreStore,
922
+ captureWorkspaceExternalProtection,
923
+ inspectRestoreSourceCompletion(expected) {
924
+ return telegramJournalReferenceRegistry.withReference({ referenceClass: "operator-disposition",
925
+ recoveryKey: expected.journalBindingKey }, function () {
926
+ const observed = telegramJournalBindingRuntime.inspectSourceCompletion(expected.journalBindingKey, { updateId: expected.updateId,
927
+ sourceSha256: expected.sourceSha256, completionSha256: expected.completionSha256 });
928
+ return observed && { journalBindingKey: expected.journalBindingKey, ...observed };
929
+ });
930
+ },
931
+ inspectRestoreQueuedReceipt(expected) {
932
+ return telegramJournalReferenceRegistry.withReference({ referenceClass: "operator-disposition",
933
+ recoveryKey: expected.journalBindingKey }, function () {
934
+ return telegramJournalBindingRuntime.inspectQueuedReceipt(expected.journalBindingKey, { queueKind: expected.queueKind, receiptId: expected.receiptId,
935
+ sourceUpdateIds: [...expected.sourceUpdateIds], queueOwner: { ...expected.queueOwner } });
936
+ });
937
+ },
938
+ inspectRestoreSourceAbandonment(updateId, journalBindingKey) {
939
+ return telegramJournalReferenceRegistry.withReference({
940
+ referenceClass: "operator-disposition",
941
+ recoveryKey: journalBindingKey,
942
+ }, function () {
943
+ return telegramJournalBindingRuntime.inspectSourceAbandonment(journalBindingKey, updateId);
944
+ });
945
+ },
946
+ inspectTemporaryThreadSources(_target, requiredJournalBindingKeys) {
947
+ const binding = resolveTelegramUpdateJournalBinding();
948
+ const botToken = configStore.getBotToken();
949
+ if (!binding || !botToken)
950
+ return undefined;
951
+ const profile = configStore.getActiveProfileName() ?? "default";
952
+ const botIdentity = Journal.createTelegramUpdateJournalBotIdentity({ botToken, botId: getTelegramBotId() });
953
+ return configStore.withSourceSerialization(function () {
954
+ return Journal.isTelegramThreadCleanupJournalNamespaceClear({
955
+ directory: Paths.resolveTelegramTempDir(), profile, botIdentity,
956
+ pollingPath: telegramLeaderJournalPath.resolve(configStore.getActiveProfileName()),
957
+ requiredJournalBindingKeys: [binding.recoveryKey, ...requiredJournalBindingKeys],
958
+ limits: { maxDirectoryEntries: 10_000, maxFiles: 4096, maxBytes: 64 * 1024 * 1024,
959
+ maxEntries: 10_000, maxWork: 100_000 },
960
+ withSourceReference(path, operation) {
961
+ return telegramJournalReferenceRegistry.withReference({ referenceClass: "operator-disposition",
962
+ recoveryKey: Journal.createTelegramUpdateJournalBindingKey({ path, profileName: profile, botIdentity }) }, operation);
963
+ },
964
+ }) ? [] : undefined;
965
+ });
966
+ },
967
+ hasWorkspaceRestoreAuthority() {
968
+ return lockRuntime.owns() && Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE);
969
+ },
970
+ getSessionGeneration: telegramSessionContextStore.getGeneration,
856
971
  bridgeRuntime,
857
972
  requestNewSession(source) {
858
973
  const updateId = Updates.getTelegramUpdateExecutionFence(source)?.updateId;
@@ -921,7 +1036,7 @@ export default function (pi) {
921
1036
  sendTextReply,
922
1037
  setMyCommands,
923
1038
  validateThreadName(threadName) {
924
- return Threads.getTelegramManualThreadDisplayNameValidationError(threadName);
1039
+ return ThreadNaming.getTelegramManualThreadDisplayNameValidationError(threadName);
925
1040
  },
926
1041
  renameCurrentThread: telegramThreadDisplayNameRenameBinding.rename,
927
1042
  resetCurrentThreadName: telegramThreadDisplayNameResetBinding.reset,
@@ -970,10 +1085,45 @@ export default function (pi) {
970
1085
  isContextCurrent: telegramSessionContextStore.isCurrent,
971
1086
  dispatchNext: dispatchNextQueuedTelegramTurn,
972
1087
  requestQueueHandoffReconciliation: queueHandoffReconciliationBinding.request,
973
- afterUpdateCompleted: sessionActionsRuntime.onUpdateCompleted,
1088
+ afterQueueReceiptCommitted: inboundRouteRuntime.onQueueReceiptCommitted,
1089
+ afterUpdateCompleted(updateId, ctx, journalBindingKey) {
1090
+ sessionActionsRuntime.onUpdateCompleted(updateId);
1091
+ inboundRouteRuntime.onUpdateCompleted(updateId, ctx, journalBindingKey);
1092
+ },
974
1093
  },
975
1094
  worker: {
1095
+ expireRoutingInput: inboundRouteRuntime.expireRoutingInput,
1096
+ beforeQueueReceiptPublished: inboundRouteRuntime.beforeQueueReceiptPublished,
1097
+ onQueueReceiptCompleted: inboundRouteRuntime.onQueueReceiptCompleted,
976
1098
  defaultHandle: inboundRouteRuntime.handleUpdate,
1099
+ async shouldReviewHistoricalInput(entry, ctx, signal) {
1100
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1101
+ throw new Error("Workspace Restore source generation ended.");
1102
+ }
1103
+ const verdict = await inboundRouteRuntime.shouldReviewHistoricalInput(entry, ctx, signal);
1104
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1105
+ throw new Error("Workspace Restore source generation ended.");
1106
+ }
1107
+ if (verdict === "retain")
1108
+ return verdict;
1109
+ const journalBindingKey = getTelegramQueueJournalBinding();
1110
+ if (journalBindingKey && resolveWorkspaceRestoreStore()?.list().some(function (intent) {
1111
+ return intent.request.source.journalBindingKey === journalBindingKey &&
1112
+ intent.request.source.updateIds.includes(entry.updateId);
1113
+ }))
1114
+ return true;
1115
+ return verdict;
1116
+ },
1117
+ spendHistoricalInput: true,
1118
+ onHeldSourcesPrepared(input) {
1119
+ return inboundRouteRuntime.forgetPreviousWorld(input, lockedPollingRuntime.captureTransportAuthority).then(function () { });
1120
+ },
1121
+ async shouldHoldPendingInput(entry, ctx, signal) {
1122
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1123
+ throw new Error("Temporary Thread source generation ended.");
1124
+ }
1125
+ return inboundRouteRuntime.shouldHoldPendingInput(entry, ctx, signal);
1126
+ },
977
1127
  onStateChange: runtimeDiagnostics.scheduleSnapshotPersist,
978
1128
  settleTerminalExecutionFailure(error) {
979
1129
  return Sync.settleStaleTelegramTopicExecutionFailure(error, staleTopicApiErrorRecoveryDeps);
@@ -987,6 +1137,11 @@ export default function (pi) {
987
1137
  resolveBinding: resolveTelegramFollowerJournalBinding,
988
1138
  isRegistered: telegramBusFollowerRegistrationState.isRegistered,
989
1139
  getGeneration: telegramBusFollowerRegistrationState.getGeneration,
1140
+ prepareBinding(binding) {
1141
+ telegramJournalBindingRuntime.prepareActiveFollowerSuccession(function isCurrent() {
1142
+ return binding.hasAuthority?.() === true;
1143
+ });
1144
+ },
990
1145
  prepareUpdateForExecution(update) {
991
1146
  return BusFollower.prepareTelegramBusFollowerJournaledUpdateForExecution(update, textGroupRuntime.prepareForwardedMessage);
992
1147
  },
@@ -1056,6 +1211,33 @@ export default function (pi) {
1056
1211
  local: agentMessageRuntime,
1057
1212
  follower: telegramBusFollowerClients.agentMessages,
1058
1213
  });
1214
+ const followerWorkspaceRestore = BusFollower.createTelegramBusFollowerWorkspaceRestoreHandler({
1215
+ instanceId: telegramInstanceId,
1216
+ getContextAuthority: BusFollower.createTelegramBusFollowerRestoreContextGetter({
1217
+ isContextCurrent: telegramSessionContextStore.isCurrent,
1218
+ getSessionId: Pi.getExtensionContextSessionId,
1219
+ getCwd: Pi.getExtensionContextCwd,
1220
+ getGeneration: telegramSessionContextStore.getGeneration,
1221
+ getProfileBindingKey() {
1222
+ return workspaceAdmissionRuntime.resolve()?.getProfileKey();
1223
+ },
1224
+ getOperatorUserId: configStore.getAllowedUserId,
1225
+ getLeaderState: lockRuntime.getState,
1226
+ getAuthenticatedSecret: telegramBusFollowerControlState.getActiveAuthSecret,
1227
+ getLeaderProtocol: telegramBusFollowerRegistrationState.getLeaderProtocol,
1228
+ }),
1229
+ readRestoreIntent(operationId, profileBindingKey) {
1230
+ if (profileBindingKey !== workspaceAdmissionRuntime.resolve()?.getProfileKey())
1231
+ return undefined;
1232
+ return resolveWorkspaceRestoreStore()?.list().find(function (intent) {
1233
+ return intent.request.operationId === operationId;
1234
+ });
1235
+ },
1236
+ topicTargetStore: threadStore,
1237
+ registrationState: telegramBusFollowerRegistrationState,
1238
+ getWorkspaceAdmission: workspaceAdmissionRuntime.resolve,
1239
+ recordRuntimeEvent,
1240
+ });
1059
1241
  const telegramBusFollowerAssembly = BusFollower.createTelegramBusFollowerRuntimeAssembly({
1060
1242
  instanceId: telegramInstanceId,
1061
1243
  registrationState: telegramBusFollowerRegistrationState,
@@ -1067,15 +1249,11 @@ export default function (pi) {
1067
1249
  getRecipientBindingKey: getTelegramManualFollowerProfileKey,
1068
1250
  durableAdmission: followerDurableAdmissionRuntime,
1069
1251
  handleQueueHandoff: acceptStagedQueueHandoff,
1070
- },
1071
- targetReplacement: {
1072
- topicTargetStore: threadStore,
1073
- getManualFollowerProfileKey: getTelegramManualFollowerProfileKey,
1074
- manualFollowerOwnerId: telegramManualFollowerOwnerId,
1075
- getWorkspaceAdmission: workspaceAdmissionRuntime.resolve,
1076
- getSyncState: telegramSyncStateRuntime.getState,
1077
- setSyncState: telegramSyncStateRuntime.setState,
1078
- updateStatus,
1252
+ handleWorkspaceRestore: followerWorkspaceRestore,
1253
+ isWorkspaceRestoreEnabled() {
1254
+ return Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) &&
1255
+ Bus.hasTelegramBusCapability(telegramBusFollowerRegistrationState.getLeaderProtocol(), Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE);
1256
+ },
1079
1257
  },
1080
1258
  recovery: {
1081
1259
  getLeaderState: lockRuntime.getState,
@@ -1177,6 +1355,17 @@ export default function (pi) {
1177
1355
  const authorizeFollowerApiCall = Bus.createTelegramFollowerApiCallAuthorizer({
1178
1356
  isMessageOwned: messageOwnershipRuntime.isOwnedByFollower,
1179
1357
  });
1358
+ const telegramSessionFolderSweeper = Recovery.createTelegramSessionFolderSweeper({
1359
+ getSessionsDir: Paths.resolveTelegramSessionsDir,
1360
+ getProfileName: configStore.getActiveProfileName,
1361
+ getKeptSessionIds() {
1362
+ return [
1363
+ ...threadStore.listWorkspaceBindings().map(function bindingSession(binding) { return binding.sessionId; }),
1364
+ ...telegramBusFollowerRegistry.list().map(function followerSession(follower) { return follower.sessionId; }),
1365
+ Pi.getExtensionContextSessionId(telegramSessionContextStore.get()),
1366
+ ];
1367
+ },
1368
+ });
1180
1369
  const telegramBusLeaderRuntime = BusLeader.createTelegramBusLeaderRuntimeAssembly({
1181
1370
  runtime: {
1182
1371
  socketPath: getTelegramBusSocketPath,
@@ -1200,10 +1389,14 @@ export default function (pi) {
1200
1389
  });
1201
1390
  },
1202
1391
  isFollowerProcessAlive: Locks.isProcessAlive,
1392
+ afterFollowerPrune() { telegramSessionFolderSweeper.sweep(); },
1203
1393
  shouldCleanupConfirmedDeadFollower: configControls.resolveAutomaticThreadCleanupEnabled,
1204
1394
  recordFollowerMessageOwnership(record) {
1205
1395
  messageOwnershipRuntime.recordFollower(record);
1206
1396
  },
1397
+ onWorkspaceRestoreRecipientObserved(follower, isCurrent) {
1398
+ return inboundRouteRuntime.onWorkspaceRestoreRecipientObserved(follower, isCurrent, telegramSessionContextStore.get());
1399
+ },
1207
1400
  },
1208
1401
  getAllowedUserId: configStore.getAllowedUserId,
1209
1402
  instanceId: telegramInstanceId,
@@ -1231,6 +1424,7 @@ export default function (pi) {
1231
1424
  getAdmission: workspaceAdmissionRuntime.resolve,
1232
1425
  runExclusive: telegramWorkspaceOperationRuntime.runExclusive,
1233
1426
  deleteThread: directTelegramApiRuntime.deleteWorkspaceThread,
1427
+ pruneJournalEvidence: pruneWorkspaceJournalEvidence,
1234
1428
  reclaimDeadOwnerQueuedWork(binding, isCurrent) {
1235
1429
  return telegramWorkspaceOperationRuntime.run({
1236
1430
  operationId: WorkspaceAdmission.createTelegramWorkspaceAdmissionOperationId(),
@@ -1316,6 +1510,12 @@ export default function (pi) {
1316
1510
  const threadAwarePollingPorts = telegramThreadCapabilityRuntime.pollingPorts;
1317
1511
  const lockedPollingRuntime = Locks.createTelegramLockedPollingRuntime({
1318
1512
  lock: lockRuntime,
1513
+ resetDamagedState() {
1514
+ return Locks.resetDamagedTelegramRuntimeState(Paths.resolveTelegramStatePath(), function (profile, sections) {
1515
+ Threads.parseTelegramWorkspaceStateSection(sections.workspace, profile);
1516
+ WorkspaceAdmission.assertTelegramConsolidatedAdmissionSection(sections.admission, profile);
1517
+ });
1518
+ },
1319
1519
  transportMonitor: telegramThreadCapabilityMonitor,
1320
1520
  hasBotToken: configStore.hasBotToken,
1321
1521
  getBotTokenDiagnostic: configStore.getBotTokenDiagnostic,
@@ -1361,6 +1561,28 @@ export default function (pi) {
1361
1561
  resolveAutomaticThreadCleanupEnabled: configControls.resolveAutomaticThreadCleanupEnabled,
1362
1562
  runWorkspaceOperation: telegramWorkspaceOperationRuntime.run,
1363
1563
  });
1564
+ const connectionIntent = Lifecycle.createTelegramConnectionIntentRuntime();
1565
+ const connectionLifecycle = Lifecycle.createTelegramConnectionLifecycle({
1566
+ intent: connectionIntent,
1567
+ getGeneration: telegramSessionContextStore.getGeneration,
1568
+ isCurrent: telegramSessionContextStore.isCurrent,
1569
+ getProfileName: configStore.getActiveProfileName,
1570
+ isConnected() {
1571
+ return lockRuntime.owns() || telegramBusFollowerRegistrationState.isRegistered();
1572
+ },
1573
+ async activateProfile(profileName, isCurrent) {
1574
+ await configStore.load();
1575
+ if (!isCurrent())
1576
+ return false;
1577
+ return configStore.activateProfile(profileName) && configStore.hasBotToken();
1578
+ },
1579
+ start(ctx) {
1580
+ return lockedPollingRuntime.start(ctx);
1581
+ },
1582
+ recordError(error) {
1583
+ recordRuntimeEvent("connection", error, { phase: "resume-connect" });
1584
+ },
1585
+ });
1364
1586
  const telegramBridgeSessionLifecycleDeps = Lifecycle.createTelegramBridgeSessionLifecycleDeps({
1365
1587
  contextStore: telegramSessionContextStore,
1366
1588
  queue: {
@@ -1372,7 +1594,10 @@ export default function (pi) {
1372
1594
  syncCounters: queue.syncCounters,
1373
1595
  syncFlags: lifecycle.syncFlags,
1374
1596
  bindDeferredDispatchContext: deferredQueueDispatchRuntime.bind,
1375
- prepareTempDir,
1597
+ prepareTempDir() {
1598
+ Recovery.removeTelegramLegacyRecoveryStorage(Paths.resolveTelegramTempDir());
1599
+ return prepareTempDir();
1600
+ },
1376
1601
  updateStatus,
1377
1602
  unbindDeferredDispatchContext: deferredQueueDispatchRuntime.unbind,
1378
1603
  discardQueuedItems: queueMutationRuntime.clear,
@@ -1408,6 +1633,7 @@ export default function (pi) {
1408
1633
  },
1409
1634
  delivery: deliveryLifecycleRuntime,
1410
1635
  polling: lockedPollingRuntime,
1636
+ connection: connectionLifecycle,
1411
1637
  inboundWorker: {
1412
1638
  onSessionShutdown: updateAdmissionRuntimeBinding.onSessionShutdown,
1413
1639
  },
@@ -1513,17 +1739,7 @@ export default function (pi) {
1513
1739
  activeTurnRuntime,
1514
1740
  lockedPollingRuntime,
1515
1741
  stopPolling: disconnectTelegramAndDeleteCurrentThread,
1516
- recoverPollingStart: Recovery.createTelegramPollingStartRecoveryHandler({
1517
- getOwnersPath: Paths.resolveTelegramOwnersPath,
1518
- getStatePaths() {
1519
- return [
1520
- Threads.getTelegramTopicTargetsPath(undefined, configStore.getActiveProfileName()),
1521
- ];
1522
- },
1523
- suspendPolling: lockedPollingRuntime.suspend,
1524
- releaseOwnership: lockRuntime.release,
1525
- recordRuntimeEvent,
1526
- }),
1742
+ // Consolidated envelope failures remain protective; legacy whole-file recovery cannot reset sibling authority.
1527
1743
  getDisconnectThreadName() {
1528
1744
  const record = findCurrentThreadRecord();
1529
1745
  if (!record?.target.threadId)
@@ -1536,6 +1752,9 @@ export default function (pi) {
1536
1752
  modelContextAvailabilityRuntime.reconcile();
1537
1753
  },
1538
1754
  getStatusLines,
1755
+ isContextCurrent: telegramSessionContextStore.isCurrent,
1756
+ getSessionGeneration: telegramSessionContextStore.getGeneration,
1757
+ connectionIntent,
1539
1758
  buttonActionStore,
1540
1759
  sendMarkdownReply,
1541
1760
  async sendChannelMarkdownMessage(channel, markdown, options) {
@@ -1547,7 +1766,7 @@ export default function (pi) {
1547
1766
  if (!botToken)
1548
1767
  throw new Error("Telegram channel delivery requires an active bot token.");
1549
1768
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1550
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
1769
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1551
1770
  profileName,
1552
1771
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1553
1772
  });
@@ -1577,7 +1796,7 @@ export default function (pi) {
1577
1796
  const caption = Replies.renderTelegramMarkdownToHtmlDraft(markdown);
1578
1797
  ChannelPosts.assertTelegramChannelPostCaptionWithinLimit(caption);
1579
1798
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1580
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
1799
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1581
1800
  profileName,
1582
1801
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1583
1802
  });
@@ -1605,7 +1824,7 @@ export default function (pi) {
1605
1824
  if (!botToken)
1606
1825
  throw new Error("Telegram channel posts require an active bot token.");
1607
1826
  return ChannelPosts.createTelegramChannelPostJournalStore({
1608
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
1827
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1609
1828
  profileName,
1610
1829
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1611
1830
  }).list(input);
@@ -1618,7 +1837,7 @@ export default function (pi) {
1618
1837
  if (!botToken)
1619
1838
  throw new Error("Telegram channel post mutation requires an active bot token.");
1620
1839
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1621
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName), profileName,
1840
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName), profileName,
1622
1841
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1623
1842
  });
1624
1843
  if (input.action === "edit") {
@@ -1684,6 +1903,7 @@ export default function (pi) {
1684
1903
  },
1685
1904
  activityRuntime,
1686
1905
  activityVerbosityRuntime,
1906
+ diagnostics: runtimeDiagnostics,
1687
1907
  assistantOutputRuntime,
1688
1908
  publicationRuntime,
1689
1909
  configStore,