@llblab/pi-telegram 0.51.6 → 0.52.1

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 (178) hide show
  1. package/AGENTS.md +15 -12
  2. package/BACKLOG.md +16 -9
  3. package/CHANGELOG.md +19 -0
  4. package/LICENSE +21 -0
  5. package/README.md +17 -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 +5 -1
  9. package/dist/lib/bindings.js +7 -1
  10. package/dist/lib/bus-api.js +8 -5
  11. package/dist/lib/bus-follower.d.ts +54 -56
  12. package/dist/lib/bus-follower.js +206 -139
  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 +0 -23
  24. package/dist/lib/commands.js +15 -15
  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 +258 -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 +183 -16
  34. package/dist/lib/journal.js +1175 -248
  35. package/dist/lib/keyboard.d.ts +0 -2
  36. package/dist/lib/keyboard.js +2 -2
  37. package/dist/lib/lifecycle.js +1 -1
  38. package/dist/lib/locks.d.ts +100 -12
  39. package/dist/lib/locks.js +380 -14
  40. package/dist/lib/logging.d.ts +30 -12
  41. package/dist/lib/logging.js +129 -72
  42. package/dist/lib/media.d.ts +28 -5
  43. package/dist/lib/media.js +26 -8
  44. package/dist/lib/menu-model.d.ts +0 -11
  45. package/dist/lib/menu-model.js +8 -8
  46. package/dist/lib/menu-settings.d.ts +0 -18
  47. package/dist/lib/menu-settings.js +18 -18
  48. package/dist/lib/menu-status.d.ts +4 -4
  49. package/dist/lib/menu-status.js +12 -7
  50. package/dist/lib/menu-thinking.d.ts +1 -1
  51. package/dist/lib/menu-thinking.js +1 -1
  52. package/dist/lib/menu.d.ts +1 -0
  53. package/dist/lib/menu.js +4 -3
  54. package/dist/lib/outbound-attachments.d.ts +0 -1
  55. package/dist/lib/outbound-attachments.js +1 -1
  56. package/dist/lib/outbound-buttons.js +1 -8
  57. package/dist/lib/outbound-markup.d.ts +1 -6
  58. package/dist/lib/outbound-markup.js +4 -21
  59. package/dist/lib/outbound.d.ts +0 -8
  60. package/dist/lib/outbound.js +5 -5
  61. package/dist/lib/paths.d.ts +50 -7
  62. package/dist/lib/paths.js +155 -17
  63. package/dist/lib/pi.d.ts +1 -0
  64. package/dist/lib/pi.js +2 -1
  65. package/dist/lib/polling.d.ts +0 -5
  66. package/dist/lib/polling.js +5 -5
  67. package/dist/lib/preview.d.ts +0 -3
  68. package/dist/lib/preview.js +3 -3
  69. package/dist/lib/prompt-templates.d.ts +0 -1
  70. package/dist/lib/prompt-templates.js +1 -1
  71. package/dist/lib/queue.d.ts +5 -15
  72. package/dist/lib/queue.js +94 -11
  73. package/dist/lib/recovery.d.ts +29 -9
  74. package/dist/lib/recovery.js +104 -33
  75. package/dist/lib/replies.d.ts +0 -4
  76. package/dist/lib/replies.js +1 -1
  77. package/dist/lib/routing.d.ts +74 -8
  78. package/dist/lib/routing.js +2280 -307
  79. package/dist/lib/sections.d.ts +0 -2
  80. package/dist/lib/sections.js +1 -1
  81. package/dist/lib/status.d.ts +44 -9
  82. package/dist/lib/status.js +149 -27
  83. package/dist/lib/sync.d.ts +0 -5
  84. package/dist/lib/sync.js +5 -4
  85. package/dist/lib/telegram-api.d.ts +13 -3
  86. package/dist/lib/telegram-api.js +38 -23
  87. package/dist/lib/thread-cleanup-manager.d.ts +1 -0
  88. package/dist/lib/thread-cleanup-manager.js +18 -21
  89. package/dist/lib/thread-naming.d.ts +32 -5
  90. package/dist/lib/thread-naming.js +191 -7
  91. package/dist/lib/thread-reconciler.d.ts +2 -0
  92. package/dist/lib/thread-reconciler.js +1 -1
  93. package/dist/lib/threads.d.ts +293 -59
  94. package/dist/lib/threads.js +1689 -369
  95. package/dist/lib/turns.d.ts +0 -1
  96. package/dist/lib/turns.js +1 -1
  97. package/dist/lib/updates.d.ts +191 -28
  98. package/dist/lib/updates.js +1048 -114
  99. package/dist/lib/wire.d.ts +12 -0
  100. package/dist/lib/wire.js +21 -0
  101. package/dist/lib/workspace-admission.d.ts +25 -17
  102. package/dist/lib/workspace-admission.js +95 -20
  103. package/dist/lib/workspace-identity.d.ts +20 -0
  104. package/dist/lib/workspace-identity.js +103 -0
  105. package/dist/lib/workspace-retirement.d.ts +43 -8
  106. package/dist/lib/workspace-retirement.js +148 -52
  107. package/dist/package.json +6 -6
  108. package/dist/skills/generated-control-surface/SKILL.md +3 -3
  109. package/dist/skills/telegram-bridge/references/diagnosis.md +3 -3
  110. package/docs/README.md +1 -1
  111. package/docs/activity.md +1 -1
  112. package/docs/architecture.md +156 -36
  113. package/docs/callback-namespaces.md +1 -1
  114. package/docs/delivery.md +1 -1
  115. package/docs/generative-apps.md +2 -2
  116. package/docs/inbound.md +1 -1
  117. package/docs/multi-instance-bus.md +125 -19
  118. package/docs/public-api.md +3 -1
  119. package/docs/ui-style.md +23 -9
  120. package/docs/updates.md +1 -1
  121. package/lib/activity-verbosity.ts +5 -9
  122. package/lib/bindings.ts +7 -0
  123. package/lib/bus-api.ts +9 -4
  124. package/lib/bus-follower.ts +243 -224
  125. package/lib/bus-leader.ts +178 -31
  126. package/lib/bus-transport.ts +30 -8
  127. package/lib/bus.ts +110 -334
  128. package/lib/channel-posts.ts +29 -29
  129. package/lib/command-templates.ts +5 -5
  130. package/lib/commands.ts +15 -15
  131. package/lib/config.ts +12 -17
  132. package/lib/delivery.ts +2 -8
  133. package/lib/extension.ts +261 -72
  134. package/lib/generative-apps.ts +0 -22
  135. package/lib/inbound.ts +2 -2
  136. package/lib/journal.ts +1250 -325
  137. package/lib/keyboard.ts +2 -2
  138. package/lib/lifecycle.ts +1 -1
  139. package/lib/locks.ts +402 -23
  140. package/lib/logging.ts +151 -101
  141. package/lib/media.ts +51 -9
  142. package/lib/menu-model.ts +8 -8
  143. package/lib/menu-settings.ts +18 -18
  144. package/lib/menu-status.ts +11 -0
  145. package/lib/menu-thinking.ts +2 -2
  146. package/lib/menu.ts +5 -1
  147. package/lib/outbound-attachments.ts +1 -1
  148. package/lib/outbound-buttons.ts +1 -10
  149. package/lib/outbound-markup.ts +5 -24
  150. package/lib/outbound.ts +5 -5
  151. package/lib/paths.ts +177 -17
  152. package/lib/pi.ts +5 -2
  153. package/lib/polling.ts +5 -5
  154. package/lib/preview.ts +3 -3
  155. package/lib/prompt-templates.ts +1 -1
  156. package/lib/queue.ts +93 -12
  157. package/lib/recovery.ts +104 -44
  158. package/lib/replies.ts +1 -1
  159. package/lib/routing.ts +2010 -375
  160. package/lib/sections.ts +1 -1
  161. package/lib/status.ts +156 -36
  162. package/lib/sync.ts +4 -4
  163. package/lib/telegram-api.ts +53 -33
  164. package/lib/thread-cleanup-manager.ts +24 -21
  165. package/lib/thread-naming.ts +267 -9
  166. package/lib/thread-reconciler.ts +3 -1
  167. package/lib/threads.ts +1736 -488
  168. package/lib/turns.ts +1 -1
  169. package/lib/updates.ts +1094 -151
  170. package/lib/wire.ts +28 -0
  171. package/lib/workspace-admission.ts +97 -47
  172. package/lib/workspace-identity.ts +147 -0
  173. package/lib/workspace-retirement.ts +188 -89
  174. package/package.json +6 -6
  175. package/scripts/audit-exports.mjs +100 -0
  176. package/scripts/check-downgrade.mjs +80 -43
  177. package/skills/generated-control-surface/SKILL.md +3 -3
  178. package/skills/telegram-bridge/references/diagnosis.md +3 -3
package/lib/extension.ts CHANGED
@@ -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,66 @@ 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
+ inspectRoutingInputGroupExpiry(input) {
1150
+ return telegramJournalReferenceRegistry.withReference({ referenceClass: "operator-disposition", recoveryKey: input.journalBindingKey },
1151
+ function () { return telegramJournalBindingRuntime.inspectSourceGroupExpiry(input.journalBindingKey, input.updateIds); });
1152
+ },
1153
+ inspectTemporaryThreadSources(_target, requiredJournalBindingKeys) {
1154
+ const binding = resolveTelegramUpdateJournalBinding();
1155
+ const botToken = configStore.getBotToken();
1156
+ if (!binding || !botToken) return undefined;
1157
+ const profile = configStore.getActiveProfileName() ?? "default";
1158
+ const botIdentity = Journal.createTelegramUpdateJournalBotIdentity({ botToken, botId: getTelegramBotId() });
1159
+ return configStore.withSourceSerialization(function () {
1160
+ return Journal.isTelegramThreadCleanupJournalNamespaceClear({
1161
+ directory: Paths.resolveTelegramTempDir(), profile, botIdentity,
1162
+ pollingPath: telegramLeaderJournalPath.resolve(configStore.getActiveProfileName()),
1163
+ requiredJournalBindingKeys: [binding.recoveryKey, ...requiredJournalBindingKeys],
1164
+ limits: { maxDirectoryEntries: 10_000, maxFiles: 4096, maxBytes: 64 * 1024 * 1024,
1165
+ maxEntries: 10_000, maxWork: 100_000 },
1166
+ withSourceReference(path, operation) {
1167
+ return telegramJournalReferenceRegistry.withReference({ referenceClass: "operator-disposition",
1168
+ recoveryKey: Journal.createTelegramUpdateJournalBindingKey({ path, profileName: profile, botIdentity }) }, operation);
1169
+ },
1170
+ }) ? [] : undefined;
1171
+ });
1172
+ },
1173
+ hasWorkspaceRestoreAuthority() {
1174
+ return lockRuntime.owns() && Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE);
1175
+ },
1176
+ getSessionGeneration: telegramSessionContextStore.getGeneration,
1061
1177
  bridgeRuntime,
1062
1178
  requestNewSession(source) {
1063
1179
  const updateId = Updates.getTelegramUpdateExecutionFence(source)?.updateId;
@@ -1131,7 +1247,7 @@ export default function (pi: Pi.ExtensionAPI) {
1131
1247
  sendTextReply,
1132
1248
  setMyCommands,
1133
1249
  validateThreadName(threadName) {
1134
- return Threads.getTelegramManualThreadDisplayNameValidationError(
1250
+ return ThreadNaming.getTelegramManualThreadDisplayNameValidationError(
1135
1251
  threadName,
1136
1252
  );
1137
1253
  },
@@ -1197,10 +1313,43 @@ export default function (pi: Pi.ExtensionAPI) {
1197
1313
  dispatchNext: dispatchNextQueuedTelegramTurn,
1198
1314
  requestQueueHandoffReconciliation:
1199
1315
  queueHandoffReconciliationBinding.request,
1200
- afterUpdateCompleted: sessionActionsRuntime.onUpdateCompleted,
1316
+ afterQueueReceiptCommitted: inboundRouteRuntime.onQueueReceiptCommitted,
1317
+ afterUpdateCompleted(updateId, ctx, journalBindingKey) {
1318
+ sessionActionsRuntime.onUpdateCompleted(updateId);
1319
+ inboundRouteRuntime.onUpdateCompleted(updateId, ctx, journalBindingKey);
1320
+ },
1201
1321
  },
1202
1322
  worker: {
1323
+ expireRoutingInput: inboundRouteRuntime.expireRoutingInput,
1324
+ beforeQueueReceiptPublished: inboundRouteRuntime.beforeQueueReceiptPublished,
1325
+ onQueueReceiptCompleted: inboundRouteRuntime.onQueueReceiptCompleted,
1203
1326
  defaultHandle: inboundRouteRuntime.handleUpdate,
1327
+ async shouldReviewHistoricalInput(entry, ctx, signal) {
1328
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1329
+ throw new Error("Workspace Restore source generation ended.");
1330
+ }
1331
+ const verdict = await inboundRouteRuntime.shouldReviewHistoricalInput(entry, ctx, signal);
1332
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1333
+ throw new Error("Workspace Restore source generation ended.");
1334
+ }
1335
+ if (verdict === "retain") return verdict;
1336
+ const journalBindingKey = getTelegramQueueJournalBinding();
1337
+ if (journalBindingKey && resolveWorkspaceRestoreStore()?.list().some(function (intent) {
1338
+ return intent.request.source.journalBindingKey === journalBindingKey &&
1339
+ intent.request.source.updateIds.includes(entry.updateId);
1340
+ })) return true;
1341
+ return verdict;
1342
+ },
1343
+ spendHistoricalInput: true,
1344
+ onHeldSourcesPrepared(input): Promise<void> {
1345
+ return inboundRouteRuntime.forgetPreviousWorld(input, lockedPollingRuntime.captureTransportAuthority).then(function () {});
1346
+ },
1347
+ async shouldHoldPendingInput(entry, ctx, signal) {
1348
+ if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
1349
+ throw new Error("Temporary Thread source generation ended.");
1350
+ }
1351
+ return inboundRouteRuntime.shouldHoldPendingInput(entry, ctx, signal);
1352
+ },
1204
1353
  onStateChange: runtimeDiagnostics.scheduleSnapshotPersist,
1205
1354
  settleTerminalExecutionFailure(error) {
1206
1355
  return Sync.settleStaleTelegramTopicExecutionFailure(
@@ -1217,6 +1366,11 @@ export default function (pi: Pi.ExtensionAPI) {
1217
1366
  resolveBinding: resolveTelegramFollowerJournalBinding,
1218
1367
  isRegistered: telegramBusFollowerRegistrationState.isRegistered,
1219
1368
  getGeneration: telegramBusFollowerRegistrationState.getGeneration,
1369
+ prepareBinding(binding) {
1370
+ telegramJournalBindingRuntime.prepareActiveFollowerSuccession(function isCurrent() {
1371
+ return binding.hasAuthority?.() === true;
1372
+ });
1373
+ },
1220
1374
  prepareUpdateForExecution(update) {
1221
1375
  return BusFollower.prepareTelegramBusFollowerJournaledUpdateForExecution(
1222
1376
  update,
@@ -1296,6 +1450,32 @@ export default function (pi: Pi.ExtensionAPI) {
1296
1450
  local: agentMessageRuntime,
1297
1451
  follower: telegramBusFollowerClients.agentMessages,
1298
1452
  });
1453
+ const followerWorkspaceRestore = BusFollower.createTelegramBusFollowerWorkspaceRestoreHandler({
1454
+ instanceId: telegramInstanceId,
1455
+ getContextAuthority: BusFollower.createTelegramBusFollowerRestoreContextGetter({
1456
+ isContextCurrent: telegramSessionContextStore.isCurrent,
1457
+ getSessionId: Pi.getExtensionContextSessionId,
1458
+ getCwd: Pi.getExtensionContextCwd,
1459
+ getGeneration: telegramSessionContextStore.getGeneration,
1460
+ getProfileBindingKey() {
1461
+ return workspaceAdmissionRuntime.resolve()?.getProfileKey();
1462
+ },
1463
+ getOperatorUserId: configStore.getAllowedUserId,
1464
+ getLeaderState: lockRuntime.getState,
1465
+ getAuthenticatedSecret: telegramBusFollowerControlState.getActiveAuthSecret,
1466
+ getLeaderProtocol: telegramBusFollowerRegistrationState.getLeaderProtocol,
1467
+ }),
1468
+ readRestoreIntent(operationId, profileBindingKey) {
1469
+ if (profileBindingKey !== workspaceAdmissionRuntime.resolve()?.getProfileKey()) return undefined;
1470
+ return resolveWorkspaceRestoreStore()?.list().find(function (intent) {
1471
+ return intent.request.operationId === operationId;
1472
+ });
1473
+ },
1474
+ topicTargetStore: threadStore,
1475
+ registrationState: telegramBusFollowerRegistrationState,
1476
+ getWorkspaceAdmission: workspaceAdmissionRuntime.resolve,
1477
+ recordRuntimeEvent,
1478
+ });
1299
1479
  const telegramBusFollowerAssembly: BusFollower.TelegramBusFollowerRuntimeAssembly<Pi.ExtensionContext> =
1300
1480
  BusFollower.createTelegramBusFollowerRuntimeAssembly<Pi.ExtensionContext>({
1301
1481
  instanceId: telegramInstanceId,
@@ -1308,15 +1488,11 @@ export default function (pi: Pi.ExtensionAPI) {
1308
1488
  getRecipientBindingKey: getTelegramManualFollowerProfileKey,
1309
1489
  durableAdmission: followerDurableAdmissionRuntime,
1310
1490
  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,
1491
+ handleWorkspaceRestore: followerWorkspaceRestore,
1492
+ isWorkspaceRestoreEnabled() {
1493
+ return Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) &&
1494
+ Bus.hasTelegramBusCapability(telegramBusFollowerRegistrationState.getLeaderProtocol(), Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE);
1495
+ },
1320
1496
  },
1321
1497
  recovery: {
1322
1498
  getLeaderState: lockRuntime.getState,
@@ -1424,6 +1600,17 @@ export default function (pi: Pi.ExtensionAPI) {
1424
1600
  const authorizeFollowerApiCall = Bus.createTelegramFollowerApiCallAuthorizer({
1425
1601
  isMessageOwned: messageOwnershipRuntime.isOwnedByFollower,
1426
1602
  });
1603
+ const telegramSessionFolderSweeper = Recovery.createTelegramSessionFolderSweeper({
1604
+ getSessionsDir: Paths.resolveTelegramSessionsDir,
1605
+ getProfileName: configStore.getActiveProfileName,
1606
+ getKeptSessionIds() {
1607
+ return [
1608
+ ...threadStore.listWorkspaceBindings().map(function bindingSession(binding) { return binding.sessionId; }),
1609
+ ...telegramBusFollowerRegistry.list().map(function followerSession(follower) { return follower.sessionId; }),
1610
+ Pi.getExtensionContextSessionId(telegramSessionContextStore.get()),
1611
+ ];
1612
+ },
1613
+ });
1427
1614
  const telegramBusLeaderRuntime =
1428
1615
  BusLeader.createTelegramBusLeaderRuntimeAssembly<Pi.ExtensionContext>({
1429
1616
  runtime: {
@@ -1448,11 +1635,15 @@ export default function (pi: Pi.ExtensionAPI) {
1448
1635
  });
1449
1636
  },
1450
1637
  isFollowerProcessAlive: Locks.isProcessAlive,
1638
+ afterFollowerPrune() { telegramSessionFolderSweeper.sweep(); },
1451
1639
  shouldCleanupConfirmedDeadFollower:
1452
1640
  configControls.resolveAutomaticThreadCleanupEnabled,
1453
1641
  recordFollowerMessageOwnership(record) {
1454
1642
  messageOwnershipRuntime.recordFollower(record);
1455
1643
  },
1644
+ onWorkspaceRestoreRecipientObserved(follower, isCurrent) {
1645
+ return inboundRouteRuntime.onWorkspaceRestoreRecipientObserved(follower, isCurrent, telegramSessionContextStore.get());
1646
+ },
1456
1647
  },
1457
1648
  getAllowedUserId: configStore.getAllowedUserId,
1458
1649
  instanceId: telegramInstanceId,
@@ -1481,6 +1672,7 @@ export default function (pi: Pi.ExtensionAPI) {
1481
1672
  getAdmission: workspaceAdmissionRuntime.resolve,
1482
1673
  runExclusive: telegramWorkspaceOperationRuntime.runExclusive,
1483
1674
  deleteThread: directTelegramApiRuntime.deleteWorkspaceThread,
1675
+ pruneJournalEvidence: pruneWorkspaceJournalEvidence,
1484
1676
  reclaimDeadOwnerQueuedWork(binding, isCurrent) {
1485
1677
  return telegramWorkspaceOperationRuntime.run({
1486
1678
  operationId: WorkspaceAdmission.createTelegramWorkspaceAdmissionOperationId(),
@@ -1583,6 +1775,12 @@ export default function (pi: Pi.ExtensionAPI) {
1583
1775
  const threadAwarePollingPorts = telegramThreadCapabilityRuntime.pollingPorts;
1584
1776
  const lockedPollingRuntime = Locks.createTelegramLockedPollingRuntime({
1585
1777
  lock: lockRuntime,
1778
+ resetDamagedState() {
1779
+ return Locks.resetDamagedTelegramRuntimeState(Paths.resolveTelegramStatePath(), function (profile, sections) {
1780
+ Threads.parseTelegramWorkspaceStateSection(sections.workspace, profile);
1781
+ WorkspaceAdmission.assertTelegramConsolidatedAdmissionSection(sections.admission, profile);
1782
+ });
1783
+ },
1586
1784
  transportMonitor: telegramThreadCapabilityMonitor,
1587
1785
  hasBotToken: configStore.hasBotToken,
1588
1786
  getBotTokenDiagnostic: configStore.getBotTokenDiagnostic,
@@ -1666,7 +1864,10 @@ export default function (pi: Pi.ExtensionAPI) {
1666
1864
  syncCounters: queue.syncCounters,
1667
1865
  syncFlags: lifecycle.syncFlags,
1668
1866
  bindDeferredDispatchContext: deferredQueueDispatchRuntime.bind,
1669
- prepareTempDir,
1867
+ prepareTempDir() {
1868
+ Recovery.removeTelegramLegacyRecoveryStorage(Paths.resolveTelegramTempDir());
1869
+ return prepareTempDir();
1870
+ },
1670
1871
  updateStatus,
1671
1872
  unbindDeferredDispatchContext: deferredQueueDispatchRuntime.unbind,
1672
1873
  discardQueuedItems: queueMutationRuntime.clear,
@@ -1824,20 +2025,7 @@ export default function (pi: Pi.ExtensionAPI) {
1824
2025
  activeTurnRuntime,
1825
2026
  lockedPollingRuntime,
1826
2027
  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
- }),
2028
+ // Consolidated envelope failures remain protective; legacy whole-file recovery cannot reset sibling authority.
1841
2029
  getDisconnectThreadName() {
1842
2030
  const record = findCurrentThreadRecord();
1843
2031
  if (!record?.target.threadId) return undefined;
@@ -1862,7 +2050,7 @@ export default function (pi: Pi.ExtensionAPI) {
1862
2050
  const botToken = configStore.getBotToken();
1863
2051
  if (!botToken) throw new Error("Telegram channel delivery requires an active bot token.");
1864
2052
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1865
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
2053
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1866
2054
  profileName,
1867
2055
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1868
2056
  });
@@ -1893,7 +2081,7 @@ export default function (pi: Pi.ExtensionAPI) {
1893
2081
  const caption = Replies.renderTelegramMarkdownToHtmlDraft(markdown);
1894
2082
  ChannelPosts.assertTelegramChannelPostCaptionWithinLimit(caption);
1895
2083
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1896
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
2084
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1897
2085
  profileName,
1898
2086
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1899
2087
  });
@@ -1922,7 +2110,7 @@ export default function (pi: Pi.ExtensionAPI) {
1922
2110
  const botToken = configStore.getBotToken();
1923
2111
  if (!botToken) throw new Error("Telegram channel posts require an active bot token.");
1924
2112
  return ChannelPosts.createTelegramChannelPostJournalStore({
1925
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
2113
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1926
2114
  profileName,
1927
2115
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1928
2116
  }).list(input);
@@ -1933,7 +2121,7 @@ export default function (pi: Pi.ExtensionAPI) {
1933
2121
  const botToken = configStore.getBotToken();
1934
2122
  if (!botToken) throw new Error("Telegram channel post mutation requires an active bot token.");
1935
2123
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1936
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName), profileName,
2124
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName), profileName,
1937
2125
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1938
2126
  });
1939
2127
  if (input.action === "edit") {
@@ -1995,6 +2183,7 @@ export default function (pi: Pi.ExtensionAPI) {
1995
2183
  },
1996
2184
  activityRuntime,
1997
2185
  activityVerbosityRuntime,
2186
+ diagnostics: runtimeDiagnostics,
1998
2187
  assistantOutputRuntime,
1999
2188
  publicationRuntime,
2000
2189
  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;