@llblab/pi-telegram 0.51.5 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/AGENTS.md +10 -8
  2. package/BACKLOG.md +1 -8
  3. package/CHANGELOG.md +23 -0
  4. package/LICENSE +21 -0
  5. package/README.md +16 -6
  6. package/dist/lib/activity-verbosity.d.ts +1 -5
  7. package/dist/lib/activity-verbosity.js +5 -7
  8. package/dist/lib/bindings.d.ts +9 -2
  9. package/dist/lib/bindings.js +22 -13
  10. package/dist/lib/bus-api.js +4 -2
  11. package/dist/lib/bus-follower.d.ts +55 -57
  12. package/dist/lib/bus-follower.js +213 -140
  13. package/dist/lib/bus-leader.d.ts +21 -2
  14. package/dist/lib/bus-leader.js +181 -25
  15. package/dist/lib/bus-transport.d.ts +4 -1
  16. package/dist/lib/bus-transport.js +28 -4
  17. package/dist/lib/bus.d.ts +52 -56
  18. package/dist/lib/bus.js +78 -246
  19. package/dist/lib/channel-posts.d.ts +1 -3
  20. package/dist/lib/channel-posts.js +23 -26
  21. package/dist/lib/command-templates.d.ts +0 -5
  22. package/dist/lib/command-templates.js +5 -5
  23. package/dist/lib/commands.d.ts +12 -26
  24. package/dist/lib/commands.js +152 -98
  25. package/dist/lib/config.d.ts +0 -17
  26. package/dist/lib/config.js +12 -14
  27. package/dist/lib/delivery.d.ts +0 -4
  28. package/dist/lib/delivery.js +2 -5
  29. package/dist/lib/extension.js +281 -61
  30. package/dist/lib/generative-apps.d.ts +0 -19
  31. package/dist/lib/inbound.d.ts +0 -2
  32. package/dist/lib/inbound.js +2 -2
  33. package/dist/lib/journal.d.ts +177 -16
  34. package/dist/lib/journal.js +1115 -249
  35. package/dist/lib/keyboard.d.ts +0 -2
  36. package/dist/lib/keyboard.js +2 -2
  37. package/dist/lib/lifecycle.d.ts +57 -2
  38. package/dist/lib/lifecycle.js +110 -5
  39. package/dist/lib/locks.d.ts +100 -12
  40. package/dist/lib/locks.js +380 -14
  41. package/dist/lib/logging.d.ts +30 -12
  42. package/dist/lib/logging.js +129 -72
  43. package/dist/lib/media.d.ts +28 -5
  44. package/dist/lib/media.js +26 -8
  45. package/dist/lib/menu-model.d.ts +0 -11
  46. package/dist/lib/menu-model.js +8 -8
  47. package/dist/lib/menu-settings.d.ts +0 -18
  48. package/dist/lib/menu-settings.js +18 -18
  49. package/dist/lib/menu-status.d.ts +4 -4
  50. package/dist/lib/menu-status.js +12 -7
  51. package/dist/lib/menu-thinking.d.ts +1 -1
  52. package/dist/lib/menu-thinking.js +1 -1
  53. package/dist/lib/menu.d.ts +1 -0
  54. package/dist/lib/menu.js +4 -3
  55. package/dist/lib/model.js +2 -4
  56. package/dist/lib/outbound-attachments.d.ts +0 -1
  57. package/dist/lib/outbound-attachments.js +1 -1
  58. package/dist/lib/outbound-buttons.js +1 -8
  59. package/dist/lib/outbound-markup.d.ts +1 -6
  60. package/dist/lib/outbound-markup.js +4 -21
  61. package/dist/lib/outbound.d.ts +0 -8
  62. package/dist/lib/outbound.js +5 -5
  63. package/dist/lib/paths.d.ts +50 -7
  64. package/dist/lib/paths.js +155 -17
  65. package/dist/lib/pi.d.ts +1 -0
  66. package/dist/lib/pi.js +2 -1
  67. package/dist/lib/polling.d.ts +0 -5
  68. package/dist/lib/polling.js +5 -5
  69. package/dist/lib/preview.d.ts +0 -3
  70. package/dist/lib/preview.js +3 -3
  71. package/dist/lib/prompt-templates.d.ts +0 -1
  72. package/dist/lib/prompt-templates.js +1 -1
  73. package/dist/lib/queue.d.ts +3 -15
  74. package/dist/lib/queue.js +69 -8
  75. package/dist/lib/recovery.d.ts +29 -9
  76. package/dist/lib/recovery.js +104 -33
  77. package/dist/lib/replies.d.ts +0 -4
  78. package/dist/lib/replies.js +1 -1
  79. package/dist/lib/routing.d.ts +73 -8
  80. package/dist/lib/routing.js +2206 -307
  81. package/dist/lib/sections.d.ts +0 -2
  82. package/dist/lib/sections.js +1 -1
  83. package/dist/lib/status.d.ts +46 -9
  84. package/dist/lib/status.js +179 -27
  85. package/dist/lib/sync.d.ts +0 -5
  86. package/dist/lib/sync.js +9 -8
  87. package/dist/lib/telegram-api.d.ts +11 -3
  88. package/dist/lib/telegram-api.js +34 -23
  89. package/dist/lib/thread-cleanup-manager.d.ts +1 -0
  90. package/dist/lib/thread-cleanup-manager.js +18 -21
  91. package/dist/lib/thread-naming.d.ts +32 -5
  92. package/dist/lib/thread-naming.js +191 -7
  93. package/dist/lib/thread-reconciler.d.ts +2 -0
  94. package/dist/lib/thread-reconciler.js +1 -1
  95. package/dist/lib/threads.d.ts +292 -59
  96. package/dist/lib/threads.js +1664 -373
  97. package/dist/lib/turns.d.ts +0 -1
  98. package/dist/lib/turns.js +1 -1
  99. package/dist/lib/updates.d.ts +184 -28
  100. package/dist/lib/updates.js +1032 -114
  101. package/dist/lib/wire.d.ts +12 -0
  102. package/dist/lib/wire.js +21 -0
  103. package/dist/lib/workspace-admission.d.ts +25 -17
  104. package/dist/lib/workspace-admission.js +95 -20
  105. package/dist/lib/workspace-identity.d.ts +20 -0
  106. package/dist/lib/workspace-identity.js +103 -0
  107. package/dist/lib/workspace-retirement.d.ts +45 -10
  108. package/dist/lib/workspace-retirement.js +196 -64
  109. package/dist/package.json +6 -6
  110. package/dist/skills/generated-control-surface/SKILL.md +3 -3
  111. package/dist/skills/telegram-bridge/references/diagnosis.md +3 -3
  112. package/docs/README.md +1 -1
  113. package/docs/activity.md +1 -1
  114. package/docs/architecture.md +158 -39
  115. package/docs/callback-namespaces.md +1 -1
  116. package/docs/delivery.md +1 -1
  117. package/docs/generative-apps.md +2 -2
  118. package/docs/inbound.md +1 -1
  119. package/docs/multi-instance-bus.md +127 -19
  120. package/docs/public-api.md +5 -3
  121. package/docs/ui-style.md +26 -8
  122. package/docs/updates.md +1 -1
  123. package/lib/activity-verbosity.ts +5 -9
  124. package/lib/bindings.ts +23 -10
  125. package/lib/bus-api.ts +5 -2
  126. package/lib/bus-follower.ts +251 -226
  127. package/lib/bus-leader.ts +178 -31
  128. package/lib/bus-transport.ts +30 -8
  129. package/lib/bus.ts +110 -334
  130. package/lib/channel-posts.ts +29 -29
  131. package/lib/command-templates.ts +5 -5
  132. package/lib/commands.ts +150 -112
  133. package/lib/config.ts +12 -17
  134. package/lib/delivery.ts +2 -8
  135. package/lib/extension.ts +282 -72
  136. package/lib/generative-apps.ts +0 -22
  137. package/lib/inbound.ts +2 -2
  138. package/lib/journal.ts +1182 -326
  139. package/lib/keyboard.ts +2 -2
  140. package/lib/lifecycle.ts +141 -5
  141. package/lib/locks.ts +402 -23
  142. package/lib/logging.ts +151 -101
  143. package/lib/media.ts +51 -9
  144. package/lib/menu-model.ts +8 -8
  145. package/lib/menu-settings.ts +18 -18
  146. package/lib/menu-status.ts +11 -0
  147. package/lib/menu-thinking.ts +2 -2
  148. package/lib/menu.ts +5 -1
  149. package/lib/model.ts +2 -4
  150. package/lib/outbound-attachments.ts +1 -1
  151. package/lib/outbound-buttons.ts +1 -10
  152. package/lib/outbound-markup.ts +5 -24
  153. package/lib/outbound.ts +5 -5
  154. package/lib/paths.ts +177 -17
  155. package/lib/pi.ts +5 -2
  156. package/lib/polling.ts +5 -5
  157. package/lib/preview.ts +3 -3
  158. package/lib/prompt-templates.ts +1 -1
  159. package/lib/queue.ts +67 -9
  160. package/lib/recovery.ts +104 -44
  161. package/lib/replies.ts +1 -1
  162. package/lib/routing.ts +1955 -375
  163. package/lib/sections.ts +1 -1
  164. package/lib/status.ts +185 -36
  165. package/lib/sync.ts +8 -8
  166. package/lib/telegram-api.ts +48 -33
  167. package/lib/thread-cleanup-manager.ts +24 -21
  168. package/lib/thread-naming.ts +267 -9
  169. package/lib/thread-reconciler.ts +3 -1
  170. package/lib/threads.ts +1718 -491
  171. package/lib/turns.ts +1 -1
  172. package/lib/updates.ts +1072 -151
  173. package/lib/wire.ts +28 -0
  174. package/lib/workspace-admission.ts +97 -47
  175. package/lib/workspace-identity.ts +147 -0
  176. package/lib/workspace-retirement.ts +234 -102
  177. package/package.json +6 -6
  178. package/scripts/audit-exports.mjs +100 -0
  179. package/scripts/check-downgrade.mjs +80 -43
  180. package/skills/generated-control-surface/SKILL.md +3 -3
  181. package/skills/telegram-bridge/references/diagnosis.md +3 -3
@@ -1,37 +1,17 @@
1
1
  /**
2
2
  * Telegram thread binding helpers
3
- * Zones: multi-instance bus, Telegram UI threads, volatile extension state
4
- * Owns current live instance-binding to Telegram UI thread mappings backed by Bot API ForumTopic/message_thread_id transport
3
+ * Zones: multi-instance bus, Telegram UI threads, durable Workspace state
4
+ * Owns live mappings, Workspace bindings and guarded Restore transitions; routing and transport effects stay outside.
5
5
  */
6
6
  import { type TelegramApiCallOptions } from "./telegram-api.ts";
7
- import type { TelegramTarget } from "./target.ts";
7
+ import { type TelegramTarget } from "./target.ts";
8
+ export { chooseTelegramThreadName, createTelegramThreadName, getTelegramManualThreadDisplayNameValidationError, getTelegramTopicIdentityName, getTelegramTopicThreadNameValidationError, getTelegramTopicTitleForThreadName, isTelegramTopicThreadNameValidForSlot, type TelegramThreadNameInput, } from "./thread-naming.ts";
9
+ export declare const getTelegramTopicName: (request: TelegramTopicTargetProvisionRequest, template?: string, slot?: string) => string;
10
+ import { type TelegramWorkspaceBindingIdentity } from "./workspace-identity.ts";
11
+ export { createTelegramWorkspaceBindingIdentity, createTelegramWorkspaceDirectoryKey, normalizeTelegramSessionId, normalizeTelegramWorkspacePath, type TelegramWorkspaceBindingIdentity, } from "./workspace-identity.ts";
12
+ import { type TelegramLockRuntime, type TelegramLockContext, type TelegramRuntimeStateMutation, type TelegramOwnedStatePublicationOptions, type TelegramOwnedStatePublicationResult } from "./locks.ts";
8
13
  import * as ThreadReconciler from "./thread-reconciler.ts";
9
14
  import { type TelegramWorkspaceSlotOccupancy } from "./workspace-slots.ts";
10
- export interface TelegramThreadNameInput {
11
- seed: string;
12
- cwd?: string;
13
- role?: "leader" | "follower";
14
- peers?: readonly string[];
15
- slot?: string;
16
- }
17
- export interface TelegramWorkspaceBindingIdentity {
18
- cwd: string;
19
- workspaceKey: string;
20
- /** Exact durable Pi session identity; absent only on legacy cwd-only bindings. */
21
- sessionId?: string;
22
- /** Full SHA-256 index component for session-qualified bindings. */
23
- sessionKey?: string;
24
- /** Immutable legacy binding-key component, not the displayed global letter. */
25
- instanceSlot: string;
26
- bindingKey: string;
27
- /** Profile-wide letter reserved by the transient claim. */
28
- slot?: string;
29
- }
30
- export declare function normalizeTelegramSessionId(sessionId: string): string | undefined;
31
- export declare function createTelegramSessionKey(sessionId: string): string | undefined;
32
- export declare function normalizeTelegramWorkspacePath(cwd: string): string | undefined;
33
- export declare function createTelegramWorkspaceDirectoryKey(cwd: string): string | undefined;
34
- export declare function createTelegramWorkspaceBindingIdentity(cwd: string, ordinal?: number, sessionId?: string): TelegramWorkspaceBindingIdentity | undefined;
35
15
  export type TelegramTopicTargetStatus = "active" | "offline" | "stale" | "pending" | "starting" | "probe-required" | "failed";
36
16
  export type TelegramTopicSyncStatus = "open" | "closed" | "deleted" | "unknown";
37
17
  export type TelegramThreadOwner = {
@@ -68,6 +48,7 @@ export interface TelegramThreadPendingProvision {
68
48
  owner: "leader" | "manual-follower";
69
49
  instanceId: string;
70
50
  profileKey?: string;
51
+ workspaceBindingKey?: string;
71
52
  status?: "in-flight" | "ambiguous";
72
53
  threadName?: string;
73
54
  displayTitle?: string;
@@ -80,6 +61,14 @@ export interface TelegramThreadPendingProvision {
80
61
  leaderEpoch?: number | string;
81
62
  }
82
63
  export type TelegramThreadCleanupIntent = ThreadReconciler.TelegramThreadCleanupIntent;
64
+ export type TelegramProvisionRecoveryFile = Record<string, {
65
+ instanceId: string;
66
+ profileKey?: string;
67
+ leaderEpoch?: number | string;
68
+ target: TelegramTarget & {
69
+ threadId: number;
70
+ };
71
+ }>;
83
72
  export interface TelegramTopicSyncObservation {
84
73
  target: TelegramTarget & {
85
74
  threadId: number;
@@ -120,6 +109,10 @@ export interface TelegramThreadIdentityRecord {
120
109
  slot?: string;
121
110
  updatedAtMs: number;
122
111
  }
112
+ export interface TelegramWorkspaceJournalSource {
113
+ sessionId: string;
114
+ recipientBindingKey: string;
115
+ }
123
116
  export interface TelegramWorkspaceThreadBinding {
124
117
  cwd: string;
125
118
  workspaceKey: string;
@@ -141,6 +134,8 @@ export interface TelegramWorkspaceThreadBinding {
141
134
  displayTitle?: string;
142
135
  /** Historical follower-journal routing keys that may retain accepted work. */
143
136
  journalBindingKeys?: string[];
137
+ /** Exact session-qualified journal addresses; retained across session re-key. */
138
+ journalSources?: TelegramWorkspaceJournalSource[];
144
139
  /** True only when the historical journal-key set is proven complete. */
145
140
  journalBindingsComplete?: true;
146
141
  /** Sticky once this directory has multiple retained bindings. */
@@ -175,6 +170,221 @@ export interface TelegramBotStateSnapshot {
175
170
  lastSlot?: string;
176
171
  lastReconcileAction?: string;
177
172
  }
173
+ export interface TelegramWorkspaceRelocationRequest {
174
+ operationId: string;
175
+ binding: TelegramWorkspaceThreadBinding;
176
+ owner: TelegramTopicTargetRecord;
177
+ target: TelegramTarget & {
178
+ threadId: number;
179
+ };
180
+ }
181
+ export interface TelegramWorkspaceRestoreRequest extends TelegramWorkspaceRelocationRequest {
182
+ source: {
183
+ journalBindingKey: string;
184
+ updateIds: number[];
185
+ };
186
+ }
187
+ export interface TelegramWorkspaceRestoreExecutor {
188
+ instanceId: string;
189
+ leaderEpoch: string;
190
+ }
191
+ export interface TelegramWorkspaceRestoreAuthority {
192
+ executor: TelegramWorkspaceRestoreExecutor;
193
+ operatorUserId: number;
194
+ /** Exact profile, transport, session, source and Workspace-admission authority. */
195
+ isCurrent: () => boolean;
196
+ }
197
+ export type TelegramWorkspaceRestoreRecipient = {
198
+ kind: "leader" | "follower";
199
+ instanceId: string;
200
+ sessionId: string;
201
+ generation: string;
202
+ };
203
+ /** Retained queue admission is nonterminal; queue-completed requires positive journal-owner disposition. */
204
+ export type TelegramWorkspaceRestoreSourceSettlement = {
205
+ journalBindingKey: string;
206
+ updateIds: number[];
207
+ } & ({
208
+ kind: "completed";
209
+ } | {
210
+ kind: "queued" | "queue-completed";
211
+ receiptId: string;
212
+ queueKind: "prompt" | "control";
213
+ });
214
+ /** Positive execution/recipient acceptance, retained before source disposition; never a source-removal ACK. */
215
+ export type TelegramWorkspaceRestoreSourceAcceptance = {
216
+ journalBindingKey: string;
217
+ updateId: number;
218
+ /** SHA-256 of the exact journal entry captured by its worker owner, not a routed message projection. */
219
+ sourceSha256: string;
220
+ recipient: TelegramWorkspaceRestoreRecipient;
221
+ } & ({
222
+ kind: "completed";
223
+ } | {
224
+ kind: "forwarded";
225
+ deliveryId: string;
226
+ recipientBindingKey: string;
227
+ } | {
228
+ kind: "queued";
229
+ receiptId: string;
230
+ queueKind: "prompt" | "control";
231
+ queueOwnerSha256: string;
232
+ });
233
+ export interface TelegramWorkspaceRestoreIntent {
234
+ request: TelegramWorkspaceRestoreRequest;
235
+ operatorUserId: number;
236
+ executor: TelegramWorkspaceRestoreExecutor;
237
+ revision: number;
238
+ createdAtMs: number;
239
+ updatedAtMs: number;
240
+ phase: "relocated" | "recipient-issued" | "ready";
241
+ committedAtMs: number;
242
+ recipient?: TelegramWorkspaceRestoreRecipient;
243
+ readyRecipient?: TelegramWorkspaceRestoreRecipient;
244
+ routing?: {
245
+ acceptances?: TelegramWorkspaceRestoreSourceAcceptance[];
246
+ settlements: TelegramWorkspaceRestoreSourceSettlement[];
247
+ cleanup?: "issued" | "completed" | "not-issued";
248
+ };
249
+ }
250
+ /** Immutable source membership, not readiness, cancellation, or proof of complete Thread coverage. */
251
+ export interface TelegramTemporaryThreadInput {
252
+ journalBindingKey: string;
253
+ updateIds: number[];
254
+ }
255
+ /** A strict journal observation of committed cancellation plus matching private retention. */
256
+ export interface TelegramTemporaryThreadCancellationEvidence {
257
+ journalBindingKey: string;
258
+ updateId: number;
259
+ operatorAuthorityId: string;
260
+ }
261
+ /** A bot-created routing tab with an exact creation source; it owns no Pi binding or slot. */
262
+ export interface TelegramTemporaryThreadEntry {
263
+ source: {
264
+ journalBindingKey: string;
265
+ updateId: number;
266
+ };
267
+ /** Append-only known source groups. Missing legacy metadata never proves that the creation source was alone. */
268
+ inputs?: TelegramTemporaryThreadInput[];
269
+ /** Whole known groups with positively observed cancellation; never proof that deletion may be issued. */
270
+ cancelledInputs?: TelegramTemporaryThreadInput[];
271
+ /** Whole known groups whose Forward was positively completed by the journal owner; never deletion authority alone. */
272
+ completedInputs?: TelegramTemporaryThreadInput[];
273
+ /** Whole known groups whose Forward was durably issued before local handling/queueing or follower RPC; never delivery proof or a retry grant. */
274
+ forwardedInputs?: TelegramTemporaryThreadInput[];
275
+ /** Published at creation only: every subsequent Forward path must record issuance; missing legacy coverage stays unknown. */
276
+ forwardProtocol?: "one-shot-v1";
277
+ /** Published before the sole cleanup attempt; uncertainty survives executor adoption and restart. */
278
+ cleanupIssued?: true;
279
+ operatorUserId: number;
280
+ executor: TelegramWorkspaceRestoreExecutor;
281
+ /** Unique title token; the only identity an unacknowledged creation may later be matched by. */
282
+ token: string;
283
+ /** `creating` is published before the one creation request, so after a crash its outcome is unknown. */
284
+ phase: "creating" | "created";
285
+ target?: TelegramTarget & {
286
+ threadId: number;
287
+ };
288
+ revision: number;
289
+ createdAtMs: number;
290
+ updatedAtMs: number;
291
+ }
292
+ /** Canonical target classification only; a bound target still needs live same-session readiness proof. */
293
+ export type TelegramTemporaryThreadTargetObservation = {
294
+ kind: "bound";
295
+ binding: TelegramWorkspaceThreadBinding;
296
+ } | {
297
+ kind: "temporary";
298
+ } | {
299
+ kind: "unknown";
300
+ };
301
+ interface TelegramWorkspaceRestoreSnapshot {
302
+ version: 1;
303
+ profileName: string;
304
+ tokenSha256: string;
305
+ revision: number;
306
+ operations: TelegramWorkspaceRestoreIntent[];
307
+ temporaryThreads?: TelegramTemporaryThreadEntry[];
308
+ }
309
+ /** Scope-bound Workspace operations; raw snapshot mutation is private to the store. */
310
+ export interface TelegramWorkspaceRestore {
311
+ list(): TelegramWorkspaceRestoreIntent[];
312
+ commit(request: TelegramWorkspaceRestoreRequest, authority: TelegramWorkspaceRestoreAuthority): Promise<TelegramWorkspaceRestoreIntent | undefined>;
313
+ adopt(expected: TelegramWorkspaceRestoreIntent, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
314
+ issueRecipient(expected: TelegramWorkspaceRestoreIntent, recipient: TelegramWorkspaceRestoreRecipient, authority: TelegramWorkspaceRestoreAuthority): {
315
+ issued: true;
316
+ intent: TelegramWorkspaceRestoreIntent;
317
+ } | undefined;
318
+ confirmReady(expected: TelegramWorkspaceRestoreIntent, acknowledged: TelegramWorkspaceRestoreRecipient, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
319
+ confirmInspectedReady(expected: TelegramWorkspaceRestoreIntent, observed: TelegramWorkspaceRestoreRecipient, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
320
+ issueRouting(expected: TelegramWorkspaceRestoreIntent, authority: TelegramWorkspaceRestoreAuthority): {
321
+ issued: true;
322
+ intent: TelegramWorkspaceRestoreIntent;
323
+ } | undefined;
324
+ recordSourceAcceptance(expected: TelegramWorkspaceRestoreIntent, evidence: TelegramWorkspaceRestoreSourceAcceptance, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
325
+ recordSourceSettlement(expected: TelegramWorkspaceRestoreIntent, evidence: TelegramWorkspaceRestoreSourceSettlement, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
326
+ issueCleanup(expected: TelegramWorkspaceRestoreIntent, authority: TelegramWorkspaceRestoreAuthority): {
327
+ issued: true;
328
+ intent: TelegramWorkspaceRestoreIntent;
329
+ } | undefined;
330
+ recordCleanup(expected: TelegramWorkspaceRestoreIntent, result: {
331
+ target: TelegramWorkspaceRestoreRequest["target"];
332
+ kind: "completed" | "not-issued";
333
+ }, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
334
+ retire(expected: TelegramWorkspaceRestoreIntent, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
335
+ /** Caller proves exact operator abandonment of every original; no dispatch grant may exist. */
336
+ retireAbandoned(expected: TelegramWorkspaceRestoreIntent, abandonedUpdateIds: readonly number[], authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
337
+ listTemporaryThreads(): TelegramTemporaryThreadEntry[];
338
+ /** Caller holds admission for effectful use. Fresh exact read grants no adoption, routing, disposition or deletion. */
339
+ inspectTemporaryThreadTarget(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadTargetObservation | undefined;
340
+ /** Read-only veto for an already-granted in-flight attempt; never another grant, disposable classification or deletion ACK. */
341
+ isTemporaryThreadCleanupCurrent(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority): boolean;
342
+ /** Publishes `creating` before the caller's single creation request; an existing source entry is returned, never recreated. */
343
+ reserveTemporaryThread(source: TelegramTemporaryThreadEntry["source"], token: string, authority: TelegramWorkspaceRestoreAuthority): {
344
+ reserved: boolean;
345
+ entry: TelegramTemporaryThreadEntry;
346
+ } | undefined;
347
+ /** Caller proves a fresh owner-authenticated implicit Telegram creation and exact live source under profile admission.
348
+ * Registers that observed unbound target without issuing or fabricating a Bot API creation. */
349
+ registerImplicitTemporaryThread(input: TelegramTemporaryThreadInput, target: TelegramTarget & {
350
+ threadId: number;
351
+ }, token: string, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
352
+ /** Records the exact acknowledged creation target; it never reopens a created entry. */
353
+ acknowledgeTemporaryThread(expected: TelegramTemporaryThreadEntry, target: TelegramTarget & {
354
+ threadId: number;
355
+ }, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
356
+ adoptTemporaryThread(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
357
+ /** Caller supplies exact live source/group authority; duplicate membership is read-only, never a new dispatch grant. */
358
+ recordTemporaryThreadInput(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
359
+ /** Records a positively completed Forward group; the caller proves every source of the group completed. */
360
+ /** Publishes the one-time Forward issuance fact before any RPC; a duplicate, cancelled, completed or Restore-owned group is refused. */
361
+ recordTemporaryThreadForwardIssued(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
362
+ recordTemporaryThreadInputCompletion(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
363
+ recordTemporaryThreadInputCancellation(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority, inspect: (updateId: number) => TelegramTemporaryThreadCancellationEvidence | undefined): TelegramTemporaryThreadEntry | undefined;
364
+ /** Caller holds profile admission and proves fresh source/protection clearance; publication grants one attempt, never retry. */
365
+ issueTemporaryThreadCleanup(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority): {
366
+ issued: true;
367
+ entry: TelegramTemporaryThreadEntry;
368
+ } | undefined;
369
+ /** Caller proves source settlement or cancellation and target disposition; this releases protection only. */
370
+ /** `completed` names one newly completed group; every other known group must already be cancelled or completed. */
371
+ retireTemporaryThread(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority, completed?: TelegramTemporaryThreadInput): TelegramTemporaryThreadEntry | undefined;
372
+ /** New-world restart: atomically forgets this operator's Restore intents and temporary entries from previous runtime instances.
373
+ * Committed bindings stay; nothing is rolled back, replayed or deleted here. */
374
+ forgetPreviousWorld(authority: TelegramWorkspaceRestoreAuthority): {
375
+ operations: TelegramWorkspaceRestoreIntent[];
376
+ temporaryThreads: TelegramTemporaryThreadEntry[];
377
+ } | undefined;
378
+ }
379
+ export interface TelegramWorkspaceRestoreOptions {
380
+ profileName: string;
381
+ tokenSha256: string;
382
+ isCurrentScope?: () => boolean;
383
+ maxBytes?: number;
384
+ getNowMs?: () => number;
385
+ legacyPath?: string;
386
+ onPublicationBoundary?: (boundary: "after-write-before-rename" | "after-rename") => void;
387
+ }
178
388
  export interface TelegramSessionReplacementIntent {
179
389
  continuity: "workspace-thread" | "classic-chat";
180
390
  cwd: string;
@@ -199,13 +409,11 @@ export interface TelegramTopicTargetFile {
199
409
  source: "snapshot";
200
410
  writtenAtMs: number;
201
411
  bot: TelegramBotStateSnapshot;
202
- runtime?: Record<string, unknown>;
203
- liveRoster?: Record<string, unknown>;
204
- diagnostics?: Record<string, unknown>;
205
412
  threads: TelegramTopicTargetRecord[];
206
413
  identities?: TelegramThreadIdentityRecord[];
207
414
  workspaceBindings?: TelegramWorkspaceThreadBinding[];
208
415
  workspaceRetirements?: TelegramWorkspaceRetirementIntent[];
416
+ workspaceRestore?: TelegramWorkspaceRestoreSnapshot;
209
417
  sessionReplacement?: TelegramSessionReplacementIntent;
210
418
  reservations?: TelegramThreadReservation[];
211
419
  pendingProvisions?: TelegramThreadPendingProvision[];
@@ -220,6 +428,20 @@ export interface TelegramTopicTargetStore {
220
428
  invalidateTarget: (target: TelegramTarget, isCurrent: () => boolean, lastSyncError: string) => Promise<boolean>;
221
429
  /** Caller proves owner detachment; this does not assert Telegram Thread absence. */
222
430
  detachTargetOwner: (expected: TelegramTopicTargetRecord, isCurrent: () => boolean) => Promise<boolean>;
431
+ /** Caller holds Workspace admission; publication uses this store's exact transport-owner fence. */
432
+ workspaceRestore: (options: TelegramWorkspaceRestoreOptions) => TelegramWorkspaceRestore;
433
+ /** Read-only precondition under caller-owned admission; not registration or transport authority. */
434
+ assertWorkspaceRestoreRegistration: (candidate: {
435
+ target: TelegramTarget;
436
+ bindingKey?: string;
437
+ slot?: string;
438
+ }) => void;
439
+ /** Runs synchronous live publication under the same evidence transaction; caller retains authentication/admission. */
440
+ commitWorkspaceRestoreRegistration: (candidate: Parameters<TelegramTopicTargetStore["assertWorkspaceRestoreRegistration"]>[0], publish: () => void) => void;
441
+ /** Read-only canonical observation; the callback must finish synchronously under the snapshot transaction. */
442
+ withWorkspaceRestoreSnapshot: (expected: TelegramWorkspaceRestoreIntent, observe: (snapshot: Readonly<Pick<TelegramTopicTargetFile, "threads" | "workspaceBindings">>) => undefined) => void;
443
+ /** Fresh strict disk read of acknowledged temporary-tab targets; throws rather than guessing absence. */
444
+ listTemporaryThreadTargets: () => TelegramTarget[];
223
445
  list: () => TelegramTopicTargetRecord[];
224
446
  getFollowerRecoveryHintByTarget?: (target: TelegramTarget) => {
225
447
  slot?: string;
@@ -244,6 +466,8 @@ export interface TelegramTopicTargetStore {
244
466
  liveRoster?: Record<string, unknown>;
245
467
  diagnostics?: Record<string, unknown>;
246
468
  }) => void;
469
+ /** Writes the non-canonical status projection to its own file; it never touches canonical state or grants authority. */
470
+ persistStatus: () => Promise<void>;
247
471
  getByProfileKey: (profileKey: string) => TelegramTopicTargetRecord | undefined;
248
472
  getActiveByInstanceId: (instanceId: string) => TelegramTopicTargetRecord | undefined;
249
473
  getIdentityByProfileKey: (profileKey: string) => TelegramThreadIdentityRecord | undefined;
@@ -254,7 +478,10 @@ export interface TelegramTopicTargetStore {
254
478
  commitSessionReplacementIntent: (intent: TelegramSessionReplacementIntent, isCurrent: () => boolean) => Promise<boolean>;
255
479
  removeSessionReplacementIntent: (expected: TelegramSessionReplacementIntent, isCurrent: () => boolean) => Promise<boolean>;
256
480
  listWorkspaceRetirementIntents: () => TelegramWorkspaceRetirementIntent[];
257
- commitWorkspaceJournalEvidence: (expected: TelegramWorkspaceThreadBinding, journalBindingKeys: readonly string[], complete: boolean) => TelegramWorkspaceThreadBinding | undefined;
481
+ /** Metadata subset CAS only: callers prove exact-source/writer evidence; independent snapshot roots are untouched. */
482
+ commitWorkspaceJournalEvidence: (expected: TelegramWorkspaceThreadBinding, journalBindingKeys: readonly string[], complete: boolean, journalSources?: readonly TelegramWorkspaceJournalSource[]) => TelegramWorkspaceThreadBinding | undefined;
483
+ /** Acknowledge publication of the exact current metadata frame; never roll it back after an uncertain write. */
484
+ persistWorkspaceJournalEvidence: (expected: TelegramWorkspaceThreadBinding, isCurrent: () => boolean) => Promise<boolean>;
258
485
  upsertWorkspaceRetirementIntent: (intent: TelegramWorkspaceRetirementIntent) => boolean;
259
486
  removeWorkspaceRetirementIntent: (expected: TelegramWorkspaceRetirementIntent) => boolean;
260
487
  replaceWorkspaceRetirementIntent: (expected: TelegramWorkspaceRetirementIntent, replacement: TelegramWorkspaceRetirementIntent, isCurrent: () => boolean) => Promise<boolean>;
@@ -305,13 +532,14 @@ export interface TelegramTopicTargetStore {
305
532
  claimReusableTarget: (instanceId: string, threadName?: string) => TelegramTopicTargetRecord | undefined;
306
533
  }
307
534
  export declare function reconcileTelegramFreshAllocationCursor(store: Pick<TelegramTopicTargetStore, "getBotState" | "list" | "setBotState">, nowMs?: number): boolean;
308
- export declare function createTelegramCleanupTargetProtection(store: Pick<TelegramTopicTargetStore, "list"> & Partial<Pick<TelegramTopicTargetStore, "listReservations" | "listPendingProvisions" | "listPendingCleanups">>, departingRecord?: TelegramTopicTargetRecord): NonNullable<ThreadReconciler.ThreadReconciliationApplyPorts["isCleanupTargetProtected"]>;
535
+ export declare function createTelegramCleanupTargetProtection(store: Pick<TelegramTopicTargetStore, "list"> & Partial<Pick<TelegramTopicTargetStore, "listReservations" | "listPendingProvisions" | "listPendingCleanups" | "listTemporaryThreadTargets">>, departingRecord?: TelegramTopicTargetRecord): NonNullable<ThreadReconciler.ThreadReconciliationApplyPorts["isCleanupTargetProtected"]>;
309
536
  export interface TelegramTopicTargetStoreOptions {
310
537
  path: string | (() => string);
311
538
  telegramProfile?: string | (() => string | undefined);
312
539
  getNowMs?: () => number;
313
540
  canPersist?: () => boolean;
314
541
  commitPersist?: (commit: () => void) => boolean;
542
+ consolidated?: Pick<TelegramConsolidatedWorkspaceStorageOptions, "captureAuthority" | "publishIfOwned">;
315
543
  getExternalReservedSlots?: () => readonly string[];
316
544
  }
317
545
  export interface TelegramTopicTargetProvisionerDeps {
@@ -367,7 +595,6 @@ export interface TelegramTopicTargetProvisionResult {
367
595
  record: TelegramTopicTargetRecord;
368
596
  displayTitle?: string;
369
597
  }
370
- export declare function createTelegramThreadName(input: TelegramThreadNameInput): string;
371
598
  export declare function getTelegramStatePath(agentDir?: string, profileName?: string): string;
372
599
  export declare function getTelegramTopicTargetsPath(agentDir?: string, profileName?: string): string;
373
600
  export declare const TELEGRAM_LEADER_SESSION_HANDOFF_TTL_MS = 30000;
@@ -384,35 +611,42 @@ export interface TelegramLeaderSessionHandoff {
384
611
  }
385
612
  export declare function getTelegramLeaderSessionHandoff(): TelegramLeaderSessionHandoff | undefined;
386
613
  export declare function setTelegramLeaderSessionHandoff(handoff: TelegramLeaderSessionHandoff | undefined): void;
387
- export declare function isTelegramLeaderSessionHandoffFresh(handoff: TelegramLeaderSessionHandoff | undefined, options?: {
388
- pid?: number;
389
- nowMs?: number;
390
- ttlMs?: number;
391
- }): handoff is TelegramLeaderSessionHandoff;
392
614
  export declare function getTelegramThreadOwnerKey(owner: TelegramThreadOwner): string;
393
615
  export declare function getTelegramThreadOwnerFromProfileKey(profileKey: string): TelegramThreadOwner;
394
616
  export declare function normalizeTelegramSessionReplacementIntent(value: unknown): TelegramSessionReplacementIntent | undefined;
617
+ export declare const isTelegramWorkspaceRestoreRecipient: (value: unknown) => value is TelegramWorkspaceRestoreRecipient;
618
+ export declare function isTelegramWorkspaceRestoreRequest(value: unknown): value is TelegramWorkspaceRestoreRequest;
619
+ /** Stable acceptance scope, not a removal ACK; adoption and mutable progress cannot change it. */
620
+ export declare function getTelegramWorkspaceRestoreSourceCompletionSha256(operation: TelegramWorkspaceRestoreIntent, acceptance: TelegramWorkspaceRestoreSourceAcceptance): string;
621
+ export declare function getTelegramTemporaryThreadInputs(entry: TelegramTemporaryThreadEntry): TelegramTemporaryThreadInput[];
622
+ /** Every known group is durably cancelled or Forward-completed; still not deletion authority by itself. */
623
+ export declare function isTelegramTemporaryThreadFullyResolved(entry: TelegramTemporaryThreadEntry): boolean;
624
+ /** The unified section accepts only lossless current-format Workspace evidence, never tolerant legacy repair. */
625
+ export declare function parseTelegramWorkspaceStateSection(value: unknown, profile: string): TelegramTopicTargetFile | undefined;
626
+ export declare function resolveTelegramWorkspaceProvisionRecoveryPath(statePath: string, profileName?: string, layout?: "consolidated"): string;
627
+ export interface TelegramConsolidatedWorkspaceStorageOptions {
628
+ getPath: () => string;
629
+ getProfile: () => string | undefined;
630
+ /** Exact owner/context/session grant captured before the caller's first await. */
631
+ captureAuthority: () => (() => boolean) | undefined;
632
+ publishIfOwned: NonNullable<TelegramLockRuntime<TelegramLockContext>["publishStateSectionIfOwned"]>;
633
+ }
634
+ export type TelegramWorkspaceStatePublication = <T>(mutate: (current: unknown) => TelegramRuntimeStateMutation<T>, publication?: Partial<Pick<TelegramOwnedStatePublicationOptions, "onPublicationBoundary" | "publishRename" | "isCurrent">>) => TelegramOwnedStatePublicationResult<T>;
635
+ /** Prepared Workspace IO adapter; transition/CAS policy remains with the existing Threads owner. */
636
+ export declare function createTelegramConsolidatedWorkspaceStorage(options: TelegramConsolidatedWorkspaceStorageOptions): {
637
+ readRaw: () => unknown;
638
+ read: () => TelegramTopicTargetFile | undefined;
639
+ capturePublication(): TelegramWorkspaceStatePublication | undefined;
640
+ };
395
641
  export declare function isSameTelegramProcessInstance(left: string | undefined, right: string | undefined): boolean;
642
+ /** Resolving selects a scope-bound view of the existing Workspace owner; it creates no files. */
643
+ export declare function createTelegramWorkspaceRestoreResolver(deps: {
644
+ getProfileName: () => string | undefined;
645
+ getBotToken: () => string | undefined;
646
+ threadStore: Pick<TelegramTopicTargetStore, "workspaceRestore">;
647
+ agentDir?: string;
648
+ }): () => TelegramWorkspaceRestore | undefined;
396
649
  export declare function createTelegramTopicTargetStore(options: TelegramTopicTargetStoreOptions): TelegramTopicTargetStore;
397
- export declare function normalizeTelegramTopicTargetThreadName(threadName: string): string;
398
- export declare function getTelegramTopicIdentityName(threadName: string): string;
399
- export declare function listOccupiedTelegramThreadIdentities(input: {
400
- records: readonly TelegramTopicTargetRecord[];
401
- workspaceBindings?: readonly TelegramWorkspaceThreadBinding[];
402
- pendingProvisions?: readonly TelegramThreadPendingProvision[];
403
- exceptTarget?: TelegramTarget;
404
- exceptWorkspaceBindingKey?: string;
405
- }): string[];
406
- export declare function chooseTelegramThreadName(input: {
407
- slot: string | undefined;
408
- entropy?: number | string;
409
- getRandom?: () => number;
410
- occupied?: readonly string[];
411
- }): string | undefined;
412
- export declare function getTelegramTopicThreadNameValidationError(threadName: string, _slot: string | undefined): string | undefined;
413
- export declare function getTelegramManualThreadDisplayNameValidationError(threadName: string): string | undefined;
414
- export declare function isTelegramTopicThreadNameValidForSlot(threadName: string, slot: string | undefined): boolean;
415
- export declare function getTelegramTopicName(request: TelegramTopicTargetProvisionRequest, template?: string, slot?: string): string;
416
650
  export interface TelegramPromoteFollowerBindingToLeaderDeps {
417
651
  store: TelegramTopicTargetStore;
418
652
  instanceId: string;
@@ -643,6 +877,5 @@ export declare function getTelegramTargetFromApiBody(body: unknown): (TelegramTa
643
877
  }) | undefined;
644
878
  export declare function isTelegramTopicTargetStaleError(error: unknown): boolean;
645
879
  export declare function isTelegramTopicModeUnavailableError(error: unknown): boolean;
646
- export declare function getTelegramTopicTitleForThreadName(threadName: string, slot: string, template?: string): string;
647
880
  export declare function createTelegramTopicTargetRenamer(deps: TelegramTopicTargetRenamerDeps): (request: TelegramTopicTargetRenameRequest) => Promise<TelegramTopicTargetRecord | undefined>;
648
881
  export declare function createTelegramTopicTargetProvisioner(deps: TelegramTopicTargetProvisionerDeps): (request: TelegramTopicTargetProvisionRequest) => Promise<TelegramTopicTargetProvisionResult>;