@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
@@ -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,
@@ -1394,7 +1594,10 @@ export default function (pi) {
1394
1594
  syncCounters: queue.syncCounters,
1395
1595
  syncFlags: lifecycle.syncFlags,
1396
1596
  bindDeferredDispatchContext: deferredQueueDispatchRuntime.bind,
1397
- prepareTempDir,
1597
+ prepareTempDir() {
1598
+ Recovery.removeTelegramLegacyRecoveryStorage(Paths.resolveTelegramTempDir());
1599
+ return prepareTempDir();
1600
+ },
1398
1601
  updateStatus,
1399
1602
  unbindDeferredDispatchContext: deferredQueueDispatchRuntime.unbind,
1400
1603
  discardQueuedItems: queueMutationRuntime.clear,
@@ -1536,17 +1739,7 @@ export default function (pi) {
1536
1739
  activeTurnRuntime,
1537
1740
  lockedPollingRuntime,
1538
1741
  stopPolling: disconnectTelegramAndDeleteCurrentThread,
1539
- recoverPollingStart: Recovery.createTelegramPollingStartRecoveryHandler({
1540
- getOwnersPath: Paths.resolveTelegramOwnersPath,
1541
- getStatePaths() {
1542
- return [
1543
- Threads.getTelegramTopicTargetsPath(undefined, configStore.getActiveProfileName()),
1544
- ];
1545
- },
1546
- suspendPolling: lockedPollingRuntime.suspend,
1547
- releaseOwnership: lockRuntime.release,
1548
- recordRuntimeEvent,
1549
- }),
1742
+ // Consolidated envelope failures remain protective; legacy whole-file recovery cannot reset sibling authority.
1550
1743
  getDisconnectThreadName() {
1551
1744
  const record = findCurrentThreadRecord();
1552
1745
  if (!record?.target.threadId)
@@ -1573,7 +1766,7 @@ export default function (pi) {
1573
1766
  if (!botToken)
1574
1767
  throw new Error("Telegram channel delivery requires an active bot token.");
1575
1768
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1576
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
1769
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1577
1770
  profileName,
1578
1771
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1579
1772
  });
@@ -1603,7 +1796,7 @@ export default function (pi) {
1603
1796
  const caption = Replies.renderTelegramMarkdownToHtmlDraft(markdown);
1604
1797
  ChannelPosts.assertTelegramChannelPostCaptionWithinLimit(caption);
1605
1798
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1606
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
1799
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1607
1800
  profileName,
1608
1801
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1609
1802
  });
@@ -1631,7 +1824,7 @@ export default function (pi) {
1631
1824
  if (!botToken)
1632
1825
  throw new Error("Telegram channel posts require an active bot token.");
1633
1826
  return ChannelPosts.createTelegramChannelPostJournalStore({
1634
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName),
1827
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
1635
1828
  profileName,
1636
1829
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1637
1830
  }).list(input);
@@ -1644,7 +1837,7 @@ export default function (pi) {
1644
1837
  if (!botToken)
1645
1838
  throw new Error("Telegram channel post mutation requires an active bot token.");
1646
1839
  const store = ChannelPosts.createTelegramChannelPostJournalStore({
1647
- path: Paths.resolveTelegramChannelPostJournalPath(undefined, profileName), profileName,
1840
+ ...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName), profileName,
1648
1841
  tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({ botToken }).tokenSha256,
1649
1842
  });
1650
1843
  if (input.action === "edit") {
@@ -1710,6 +1903,7 @@ export default function (pi) {
1710
1903
  },
1711
1904
  activityRuntime,
1712
1905
  activityVerbosityRuntime,
1906
+ diagnostics: runtimeDiagnostics,
1713
1907
  assistantOutputRuntime,
1714
1908
  publicationRuntime,
1715
1909
  configStore,
@@ -9,25 +9,6 @@ export declare const GENERATIVE_APP_MAX_REFRESH_AFTER_MS: number;
9
9
  export type GenerativeAppJsonValue = null | boolean | number | string | GenerativeAppJsonValue[] | {
10
10
  [key: string]: GenerativeAppJsonValue;
11
11
  };
12
- export interface GenerativeAppProcessInput {
13
- command: string;
14
- args?: string[];
15
- cwd: string;
16
- timeoutMs?: number;
17
- }
18
- export interface GenerativeAppProcessResult {
19
- code: number;
20
- killed: boolean;
21
- stderr: string;
22
- stdout: string;
23
- }
24
- export interface GenerativeAppMethodContext {
25
- argument?: GenerativeAppJsonValue;
26
- revision: number;
27
- run: (input: GenerativeAppProcessInput) => Promise<GenerativeAppProcessResult>;
28
- signal: AbortSignal;
29
- state?: GenerativeAppJsonValue;
30
- }
31
12
  export interface GenerativeAppMethodResult {
32
13
  output: string;
33
14
  refreshAfterMs?: number;
@@ -74,10 +74,8 @@ interface InboundHandlerInvocation {
74
74
  args: string[];
75
75
  }
76
76
  export declare function registerTelegramInboundHandler(kind: string, handler: TelegramInboundProgrammaticHandler): () => void;
77
- export declare function getTelegramInboundProgrammaticHandlers(kind: string): TelegramInboundProgrammaticHandler[];
78
77
  export declare function clearTelegramInboundHandlers(): void;
79
78
  export declare function telegramInboundHandlerMatchesFile(handler: TelegramInboundHandlerConfig, file: TelegramInboundHandlerFile): boolean;
80
- export declare function findTelegramInboundHandlers(handlers: TelegramInboundHandlerConfig[] | undefined, file: TelegramInboundHandlerFile): TelegramInboundHandlerConfig[];
81
79
  export declare function buildTelegramInboundHandlerInvocation(handler: CommandTemplateConfig, file: TelegramInboundHandlerFile, cwd: string, appendFileIfMissing?: boolean): InboundHandlerInvocation;
82
80
  export declare function processTelegramInboundHandlers<TFile extends TelegramInboundHandlerFile>(options: {
83
81
  files: TFile[];
@@ -43,7 +43,7 @@ export function registerTelegramInboundHandler(kind, handler) {
43
43
  }
44
44
  };
45
45
  }
46
- export function getTelegramInboundProgrammaticHandlers(kind) {
46
+ function getTelegramInboundProgrammaticHandlers(kind) {
47
47
  const registry = getOrCreateInboundHandlerRegistry();
48
48
  return [
49
49
  ...(registry.handlers.get(kind) ?? []),
@@ -117,7 +117,7 @@ export function telegramInboundHandlerMatchesFile(handler, file) {
117
117
  return true;
118
118
  return matchesAnyPattern(matchPatterns, file.kind);
119
119
  }
120
- export function findTelegramInboundHandlers(handlers, file) {
120
+ function findTelegramInboundHandlers(handlers, file) {
121
121
  if (!Array.isArray(handlers))
122
122
  return [];
123
123
  return handlers.filter((handler) => !!handler &&