@llblab/pi-telegram 0.52.2 → 0.53.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 (204) hide show
  1. package/AGENTS.md +9 -7
  2. package/BACKLOG.md +1 -18
  3. package/CHANGELOG.md +11 -0
  4. package/README.md +7 -11
  5. package/api/commands.ts +3 -0
  6. package/dist/api/commands.d.ts +1 -1
  7. package/dist/lib/activity-verbosity.d.ts +1 -5
  8. package/dist/lib/activity-verbosity.js +15 -42
  9. package/dist/lib/activity.d.ts +9 -0
  10. package/dist/lib/activity.js +39 -10
  11. package/dist/lib/agent-messages.js +7 -3
  12. package/dist/lib/bindings.d.ts +43 -5
  13. package/dist/lib/bindings.js +163 -20
  14. package/dist/lib/bus-api.d.ts +12 -0
  15. package/dist/lib/bus-api.js +182 -79
  16. package/dist/lib/bus-follower.d.ts +111 -31
  17. package/dist/lib/bus-follower.js +1324 -359
  18. package/dist/lib/bus-leader.d.ts +41 -91
  19. package/dist/lib/bus-leader.js +969 -637
  20. package/dist/lib/bus-transport.js +16 -9
  21. package/dist/lib/bus.d.ts +215 -18
  22. package/dist/lib/bus.js +1048 -327
  23. package/dist/lib/channel-posts.d.ts +5 -0
  24. package/dist/lib/channel-posts.js +434 -261
  25. package/dist/lib/command-templates.d.ts +26 -5
  26. package/dist/lib/command-templates.js +92 -176
  27. package/dist/lib/commands.d.ts +168 -82
  28. package/dist/lib/commands.js +1409 -291
  29. package/dist/lib/config.d.ts +1 -8
  30. package/dist/lib/config.js +34 -76
  31. package/dist/lib/delivery.d.ts +2 -2
  32. package/dist/lib/delivery.js +16 -16
  33. package/dist/lib/extension.js +639 -171
  34. package/dist/lib/generative-app-worker.mjs +19 -7
  35. package/dist/lib/generative-apps.d.ts +0 -5
  36. package/dist/lib/generative-apps.js +61 -49
  37. package/dist/lib/inbound.d.ts +5 -0
  38. package/dist/lib/inbound.js +35 -59
  39. package/dist/lib/journal.d.ts +33 -3
  40. package/dist/lib/journal.js +2063 -782
  41. package/dist/lib/lifecycle.d.ts +2 -6
  42. package/dist/lib/lifecycle.js +75 -58
  43. package/dist/lib/locks.d.ts +29 -3
  44. package/dist/lib/locks.js +289 -108
  45. package/dist/lib/logging.js +50 -14
  46. package/dist/lib/media.d.ts +22 -1
  47. package/dist/lib/media.js +46 -28
  48. package/dist/lib/menu-model.d.ts +19 -5
  49. package/dist/lib/menu-model.js +53 -11
  50. package/dist/lib/menu-queue.d.ts +5 -4
  51. package/dist/lib/menu-queue.js +45 -63
  52. package/dist/lib/menu-settings.d.ts +5 -4
  53. package/dist/lib/menu-settings.js +114 -78
  54. package/dist/lib/menu-status.d.ts +1 -1
  55. package/dist/lib/menu-status.js +8 -25
  56. package/dist/lib/menu-thinking.d.ts +6 -1
  57. package/dist/lib/menu-thinking.js +14 -21
  58. package/dist/lib/menu.d.ts +8 -61
  59. package/dist/lib/menu.js +92 -164
  60. package/dist/lib/model.d.ts +1 -1
  61. package/dist/lib/model.js +2 -16
  62. package/dist/lib/outbound-attachments.d.ts +6 -27
  63. package/dist/lib/outbound-attachments.js +45 -38
  64. package/dist/lib/outbound-buttons.js +22 -16
  65. package/dist/lib/outbound-markup.d.ts +0 -2
  66. package/dist/lib/outbound-markup.js +51 -64
  67. package/dist/lib/outbound-voice.js +6 -3
  68. package/dist/lib/outbound.d.ts +6 -6
  69. package/dist/lib/outbound.js +61 -51
  70. package/dist/lib/ownership.js +6 -2
  71. package/dist/lib/paths.d.ts +5 -0
  72. package/dist/lib/paths.js +37 -21
  73. package/dist/lib/pi.d.ts +2 -0
  74. package/dist/lib/pi.js +8 -1
  75. package/dist/lib/polling.d.ts +21 -37
  76. package/dist/lib/polling.js +59 -50
  77. package/dist/lib/preview.js +39 -19
  78. package/dist/lib/process-identity.d.ts +24 -0
  79. package/dist/lib/process-identity.js +133 -0
  80. package/dist/lib/prompts.js +2 -7
  81. package/dist/lib/queue.d.ts +14 -16
  82. package/dist/lib/queue.js +249 -126
  83. package/dist/lib/recovery.d.ts +2 -83
  84. package/dist/lib/recovery.js +20 -274
  85. package/dist/lib/replies.d.ts +16 -24
  86. package/dist/lib/replies.js +99 -116
  87. package/dist/lib/routing.d.ts +120 -7
  88. package/dist/lib/routing.js +4667 -1152
  89. package/dist/lib/runtime.d.ts +1 -11
  90. package/dist/lib/sections.d.ts +4 -29
  91. package/dist/lib/sections.js +7 -20
  92. package/dist/lib/skills.js +4 -3
  93. package/dist/lib/status.js +86 -57
  94. package/dist/lib/sync.d.ts +1 -3
  95. package/dist/lib/sync.js +67 -43
  96. package/dist/lib/target.d.ts +4 -0
  97. package/dist/lib/target.js +18 -0
  98. package/dist/lib/telegram-api.d.ts +18 -13
  99. package/dist/lib/telegram-api.js +148 -53
  100. package/dist/lib/text-groups.js +4 -39
  101. package/dist/lib/thread-cleanup-manager.d.ts +6 -27
  102. package/dist/lib/thread-cleanup-manager.js +369 -186
  103. package/dist/lib/thread-display.d.ts +1 -2
  104. package/dist/lib/thread-display.js +58 -38
  105. package/dist/lib/thread-naming.d.ts +28 -8
  106. package/dist/lib/thread-naming.js +175 -66
  107. package/dist/lib/thread-reconciler.d.ts +42 -16
  108. package/dist/lib/thread-reconciler.js +90 -50
  109. package/dist/lib/threads.d.ts +82 -20
  110. package/dist/lib/threads.js +2247 -855
  111. package/dist/lib/time-injection.js +1 -2
  112. package/dist/lib/turns.js +1 -19
  113. package/dist/lib/updates.d.ts +169 -80
  114. package/dist/lib/updates.js +2418 -641
  115. package/dist/lib/voice.d.ts +7 -22
  116. package/dist/lib/voice.js +7 -22
  117. package/dist/lib/wire.js +1 -1
  118. package/dist/lib/workspace-admission.d.ts +3 -1
  119. package/dist/lib/workspace-admission.js +425 -211
  120. package/dist/lib/workspace-identity.js +8 -13
  121. package/dist/lib/workspace-retirement.d.ts +1 -1
  122. package/dist/lib/workspace-retirement.js +328 -140
  123. package/dist/lib/workspace-slots.js +8 -4
  124. package/dist/package.json +1 -1
  125. package/docs/architecture.md +31 -29
  126. package/docs/inbound.md +1 -1
  127. package/docs/multi-instance-bus.md +15 -3
  128. package/docs/outbound.md +1 -1
  129. package/docs/public-api.md +29 -1
  130. package/docs/ui-style.md +25 -8
  131. package/lib/activity-verbosity.ts +59 -82
  132. package/lib/activity.ts +146 -102
  133. package/lib/agent-messages.ts +12 -5
  134. package/lib/bindings.ts +389 -82
  135. package/lib/bus-api.ts +263 -102
  136. package/lib/bus-follower.ts +2440 -601
  137. package/lib/bus-leader.ts +2209 -1290
  138. package/lib/bus-transport.ts +46 -12
  139. package/lib/bus.ts +1673 -444
  140. package/lib/channel-posts.ts +848 -327
  141. package/lib/command-templates.ts +152 -265
  142. package/lib/commands.ts +2398 -555
  143. package/lib/config.ts +177 -170
  144. package/lib/delivery.ts +41 -29
  145. package/lib/extension.ts +1206 -433
  146. package/lib/generative-app-worker.mjs +19 -7
  147. package/lib/generative-apps.ts +324 -211
  148. package/lib/inbound.ts +95 -97
  149. package/lib/journal.ts +5311 -1763
  150. package/lib/keyboard.ts +1 -3
  151. package/lib/lifecycle.ts +128 -78
  152. package/lib/locks.ts +677 -203
  153. package/lib/logging.ts +147 -58
  154. package/lib/media.ts +82 -43
  155. package/lib/menu-model.ts +85 -18
  156. package/lib/menu-queue.ts +88 -129
  157. package/lib/menu-settings.ts +260 -155
  158. package/lib/menu-status.ts +20 -60
  159. package/lib/menu-thinking.ts +41 -56
  160. package/lib/menu.ts +112 -285
  161. package/lib/model.ts +8 -22
  162. package/lib/outbound-attachments.ts +156 -125
  163. package/lib/outbound-buttons.ts +76 -49
  164. package/lib/outbound-markup.ts +96 -94
  165. package/lib/outbound-voice.ts +33 -27
  166. package/lib/outbound.ts +125 -125
  167. package/lib/ownership.ts +19 -10
  168. package/lib/paths.ts +148 -49
  169. package/lib/pi.ts +35 -15
  170. package/lib/polling.ts +144 -147
  171. package/lib/preview.ts +93 -40
  172. package/lib/process-identity.ts +164 -0
  173. package/lib/prompts.ts +4 -11
  174. package/lib/queue.ts +511 -300
  175. package/lib/recovery.ts +50 -454
  176. package/lib/rendering.ts +1 -3
  177. package/lib/replies.ts +248 -209
  178. package/lib/routing.ts +8509 -2186
  179. package/lib/runtime.ts +1 -12
  180. package/lib/sections.ts +24 -89
  181. package/lib/setup.ts +1 -3
  182. package/lib/skills.ts +9 -4
  183. package/lib/status.ts +215 -110
  184. package/lib/sync.ts +448 -361
  185. package/lib/target.ts +22 -3
  186. package/lib/telegram-api.ts +302 -127
  187. package/lib/text-groups.ts +5 -39
  188. package/lib/thread-cleanup-manager.ts +833 -331
  189. package/lib/thread-display.ts +213 -97
  190. package/lib/thread-naming.ts +232 -87
  191. package/lib/thread-reconciler.ts +155 -72
  192. package/lib/threads.ts +5318 -1845
  193. package/lib/time-injection.ts +1 -4
  194. package/lib/turns.ts +15 -28
  195. package/lib/updates.ts +5184 -1612
  196. package/lib/voice.ts +7 -35
  197. package/lib/wire.ts +1 -1
  198. package/lib/workspace-admission.ts +996 -416
  199. package/lib/workspace-identity.ts +14 -17
  200. package/lib/workspace-retirement.ts +878 -376
  201. package/lib/workspace-slots.ts +22 -13
  202. package/package.json +1 -1
  203. package/scripts/check-downgrade.mjs +0 -472
  204. package/scripts/measure-workspace.mjs +0 -108
@@ -5,10 +5,9 @@
5
5
  * Transport authority, durable bindings, and queue custody remain with their owners.
6
6
  */
7
7
  import * as BusFollower from "./bus-follower.ts";
8
- import * as Queue from "./queue.ts";
9
8
  import type { AgentEndEvent, AgentSettledEvent, AgentStartEvent, AssistantMessageEvent, BeforeAgentStartEvent, ExtensionAPI, ExtensionContext, InputEvent, MessageEndEvent, SessionBeforeCompactEvent, SessionCompactEvent, SessionCompactFailedEvent, SessionShutdownEvent, SessionStartEvent, ToolExecutionEndEvent, ToolExecutionStartEvent, ToolExecutionUpdateEvent, UIPromptEndEvent, UIPromptStartEvent } from "./pi.ts";
10
- export declare function setResetTransportReplyDedup(fn: () => void): void;
11
- export declare function createAgentStartDedupHook(inner: (event: AgentStartEvent, ctx: ExtensionContext) => Promise<void>, schedulePublication?: (task: () => Promise<void>) => void): (event: AgentStartEvent, ctx: ExtensionContext) => Promise<void>;
9
+ import * as Queue from "./queue.ts";
10
+ export declare function createAgentStartDedupHook(inner: (event: AgentStartEvent, ctx: ExtensionContext) => Promise<void>, resetReplyDedup: () => void, schedulePublication?: (task: () => Promise<void>) => void): (event: AgentStartEvent, ctx: ExtensionContext) => Promise<void>;
12
11
  type TelegramBeforeAgentStartEvent = Omit<BeforeAgentStartEvent, "systemPrompt"> & {
13
12
  systemPrompt: string | string[];
14
13
  };
@@ -202,9 +201,6 @@ export interface TelegramMessageActivityTypingDeps<TContext> {
202
201
  recordRuntimeEvent?: (category: string, error: unknown, details?: Record<string, unknown>) => void;
203
202
  }
204
203
  export declare function createTelegramMessageActivityTypingHooks<TContext extends ExtensionContext>(deps: TelegramMessageActivityTypingDeps<TContext>): Pick<TelegramLifecycleRegistrationDeps, "onMessageStart" | "onMessageUpdate">;
205
- export declare function createDedupAgentStartHook(dedup: {
206
- reset(): void;
207
- }, inner: (event: AgentStartEvent, ctx: ExtensionContext) => Promise<void>): (event: AgentStartEvent, ctx: ExtensionContext) => Promise<void>;
208
204
  export interface TelegramExtraLifecycleHooks {
209
205
  onSessionStart?: (event: SessionStartEvent, ctx: ExtensionContext) => Promise<void>;
210
206
  onSessionShutdown?: (event: SessionShutdownEvent, ctx: ExtensionContext) => Promise<void>;
@@ -5,53 +5,58 @@
5
5
  * Transport authority, durable bindings, and queue custody remain with their owners.
6
6
  */
7
7
  import { randomUUID } from "node:crypto";
8
- import { formatTelegramConnectionFailure } from "./status.js";
9
8
  import * as BusFollower from "./bus-follower.js";
10
9
  import * as Queue from "./queue.js";
10
+ import { formatTelegramConnectionFailure } from "./status.js";
11
11
  import * as TextGroups from "./text-groups.js";
12
- let resetTransportReplyDedupFn;
13
- export function setResetTransportReplyDedup(fn) {
14
- resetTransportReplyDedupFn = fn;
15
- }
16
- export function createAgentStartDedupHook(inner, schedulePublication) {
12
+ export function createAgentStartDedupHook(inner, resetReplyDedup, schedulePublication) {
17
13
  return async (event, ctx) => {
18
- const reset = resetTransportReplyDedupFn;
19
- if (reset) {
20
- // A new turn must not erase the anchor of a final still ahead in the FIFO.
21
- if (schedulePublication)
22
- schedulePublication(async () => { reset(); });
23
- else
24
- reset();
25
- }
14
+ // A new turn must not erase the anchor of a final still ahead in the FIFO.
15
+ if (schedulePublication)
16
+ schedulePublication(async () => {
17
+ resetReplyDedup();
18
+ });
19
+ else
20
+ resetReplyDedup();
26
21
  return inner(event, ctx);
27
22
  };
28
23
  }
29
24
  const HANDOFF_KEY = Symbol.for("pi-telegram.connection-resume.v1");
30
25
  function processHandoffStore() {
31
26
  const globals = globalThis;
32
- return globals[HANDOFF_KEY] ??= {};
27
+ return (globals[HANDOFF_KEY] ??= {});
33
28
  }
34
29
  export function createTelegramConnectionLifecycle(deps) {
35
30
  return {
36
31
  onSessionShutdown(event, ctx) {
37
- deps.intent.suspend({ reason: event.reason, cwd: ctx.cwd,
38
- targetSessionFile: event.targetSessionFile, connected: deps.isConnected(),
39
- profileName: deps.getProfileName() });
32
+ deps.intent.suspend({
33
+ reason: event.reason,
34
+ cwd: ctx.cwd,
35
+ targetSessionFile: event.targetSessionFile,
36
+ connected: deps.isConnected(),
37
+ profileName: deps.getProfileName(),
38
+ });
40
39
  },
41
40
  prepare(event, ctx) {
42
- const intent = deps.intent.resume({ reason: event.reason, cwd: ctx.cwd,
43
- sessionFile: event.reason === "resume" ? ctx.sessionManager.getSessionFile() : undefined });
41
+ const intent = deps.intent.resume({
42
+ reason: event.reason,
43
+ cwd: ctx.cwd,
44
+ sessionFile: event.reason === "resume"
45
+ ? ctx.sessionManager.getSessionFile()
46
+ : undefined,
47
+ });
44
48
  if (!intent)
45
49
  return undefined;
46
50
  const generation = deps.getGeneration();
47
51
  const isCurrent = () => deps.intent.isActive(intent.id) &&
48
- generation === deps.getGeneration() && deps.isCurrent(ctx);
52
+ generation === deps.getGeneration() &&
53
+ deps.isCurrent(ctx);
49
54
  return () => {
50
55
  // Startup remains extension-owned background work; no captured command ctx crosses resume.
51
56
  void (async () => {
52
57
  if (!isCurrent())
53
58
  return;
54
- if (!await deps.activateProfile(intent.profileName, isCurrent)) {
59
+ if (!(await deps.activateProfile(intent.profileName, isCurrent))) {
55
60
  if (isCurrent())
56
61
  ctx.ui.notify("Telegram profile unavailable. Run /telegram-setup.", "warning");
57
62
  return;
@@ -65,11 +70,13 @@ export function createTelegramConnectionLifecycle(deps) {
65
70
  deps.recordError(new Error(result.message ?? "Telegram resume connection failed."));
66
71
  ctx.ui.notify(formatTelegramConnectionFailure(result.message), "warning");
67
72
  }
68
- })().catch((error) => {
73
+ })()
74
+ .catch((error) => {
69
75
  deps.recordError(error);
70
76
  if (isCurrent())
71
77
  ctx.ui.notify(formatTelegramConnectionFailure(error), "warning");
72
- }).finally(() => deps.intent.finish(intent.id));
78
+ })
79
+ .finally(() => deps.intent.finish(intent.id));
73
80
  };
74
81
  },
75
82
  };
@@ -97,23 +104,38 @@ export function createTelegramConnectionIntentRuntime(options = {}) {
97
104
  store.pending = undefined;
98
105
  },
99
106
  suspend(input) {
100
- const intent = active ?? (input.connected
101
- ? { id: randomUUID(), cwd: input.cwd, profileName: input.profileName }
102
- : undefined);
107
+ const intent = active ??
108
+ (input.connected
109
+ ? { id: randomUUID(), cwd: input.cwd, profileName: input.profileName }
110
+ : undefined);
103
111
  active = undefined;
104
- store.pending = input.reason === "resume" && input.targetSessionFile &&
105
- intent?.cwd === input.cwd
106
- ? { ...intent, pid, targetSessionFile: input.targetSessionFile, expiresAtMs: now() + 30_000 }
107
- : undefined;
112
+ store.pending =
113
+ input.reason === "resume" &&
114
+ input.targetSessionFile &&
115
+ intent?.cwd === input.cwd
116
+ ? {
117
+ ...intent,
118
+ pid,
119
+ targetSessionFile: input.targetSessionFile,
120
+ expiresAtMs: now() + 30_000,
121
+ }
122
+ : undefined;
108
123
  },
109
124
  resume(input) {
110
125
  const handoff = store.pending;
111
126
  store.pending = undefined;
112
- if (!handoff || handoff.pid !== pid || now() >= handoff.expiresAtMs ||
113
- input.reason !== "resume" || input.cwd !== handoff.cwd ||
127
+ if (!handoff ||
128
+ handoff.pid !== pid ||
129
+ now() >= handoff.expiresAtMs ||
130
+ input.reason !== "resume" ||
131
+ input.cwd !== handoff.cwd ||
114
132
  input.sessionFile !== handoff.targetSessionFile)
115
133
  return undefined;
116
- active = { id: randomUUID(), cwd: handoff.cwd, profileName: handoff.profileName };
134
+ active = {
135
+ id: randomUUID(),
136
+ cwd: handoff.cwd,
137
+ profileName: handoff.profileName,
138
+ };
117
139
  return { ...active };
118
140
  },
119
141
  };
@@ -258,10 +280,13 @@ export function createTelegramBridgeSessionLifecycleAssembly(deps) {
258
280
  let preserveThread;
259
281
  if (event.reason === "quit") {
260
282
  try {
261
- preserveThread = deps.services.prepareThreadPreservationOnQuit?.(isCurrent);
283
+ preserveThread =
284
+ deps.services.prepareThreadPreservationOnQuit?.(isCurrent);
262
285
  }
263
286
  catch (error) {
264
- deps.follower.recordRuntimeEvent("session", error, { phase: "preserve-thread-on-quit" });
287
+ deps.follower.recordRuntimeEvent("session", error, {
288
+ phase: "preserve-thread-on-quit",
289
+ });
265
290
  }
266
291
  }
267
292
  deps.services.guestPlaceholder?.stopAll();
@@ -280,7 +305,9 @@ export function createTelegramBridgeSessionLifecycleAssembly(deps) {
280
305
  await preserveThread?.();
281
306
  }
282
307
  catch (error) {
283
- deps.follower.recordRuntimeEvent("session", error, { phase: "preserve-thread-on-quit" });
308
+ deps.follower.recordRuntimeEvent("session", error, {
309
+ phase: "preserve-thread-on-quit",
310
+ });
284
311
  }
285
312
  },
286
313
  };
@@ -316,6 +343,14 @@ export function createTelegramCompactionObserverRuntime(deps) {
316
343
  clearTimer(fallbackTimer);
317
344
  fallbackTimer = undefined;
318
345
  };
346
+ // Stop only a typing loop this observer started; a pre-existing agent-owned loop is preserved.
347
+ const releaseCompactionPresence = (ctx) => {
348
+ deps.setCompactionInProgress(false);
349
+ if (typingStartedByObserver)
350
+ deps.stopTypingLoop?.();
351
+ typingStartedByObserver = false;
352
+ deps.updateStatus(ctx);
353
+ };
319
354
  const requestDispatch = () => {
320
355
  deps.requestDeferredDispatchNextQueuedTelegramTurn(deps.dispatchNextQueuedTelegramTurn);
321
356
  };
@@ -337,11 +372,7 @@ export function createTelegramCompactionObserverRuntime(deps) {
337
372
  fallbackTimer = undefined;
338
373
  if (deps.isContextActive && !deps.isContextActive(ctx))
339
374
  return;
340
- deps.setCompactionInProgress(false);
341
- if (typingStartedByObserver)
342
- deps.stopTypingLoop?.();
343
- typingStartedByObserver = false;
344
- deps.updateStatus(ctx);
375
+ releaseCompactionPresence(ctx);
345
376
  deps.recordRuntimeEvent?.("compact", new Error("Compaction observer timed out"));
346
377
  // Observer expiry releases local presence, not Pi's eventual terminal result.
347
378
  requestDispatch();
@@ -352,22 +383,14 @@ export function createTelegramCompactionObserverRuntime(deps) {
352
383
  if (deps.isContextActive && !deps.isContextActive(ctx))
353
384
  return;
354
385
  clearFallbackTimer();
355
- deps.setCompactionInProgress(false);
356
- if (typingStartedByObserver)
357
- deps.stopTypingLoop?.();
358
- typingStartedByObserver = false;
359
- deps.updateStatus(ctx);
386
+ releaseCompactionPresence(ctx);
360
387
  requestDispatch();
361
388
  },
362
389
  onSessionCompactFailed: (_event, ctx) => {
363
390
  if (deps.isContextActive && !deps.isContextActive(ctx))
364
391
  return;
365
392
  clearFallbackTimer();
366
- deps.setCompactionInProgress(false);
367
- if (typingStartedByObserver)
368
- deps.stopTypingLoop?.();
369
- typingStartedByObserver = false;
370
- deps.updateStatus(ctx);
393
+ releaseCompactionPresence(ctx);
371
394
  deps.onCompactionAbandoned?.();
372
395
  requestDispatch();
373
396
  },
@@ -402,12 +425,6 @@ export function createTelegramMessageActivityTypingHooks(deps) {
402
425
  onMessageUpdate: (event, ctx) => handleMessageActivity("update", event, ctx, deps.onMessageUpdate),
403
426
  };
404
427
  }
405
- export function createDedupAgentStartHook(dedup, inner) {
406
- return async (event, ctx) => {
407
- dedup.reset();
408
- await inner(event, ctx);
409
- };
410
- }
411
428
  export function appendTelegramLifecycleHooks(base, extra, isSessionActive) {
412
429
  return {
413
430
  onSessionStart: async (event, ctx) => {
@@ -84,7 +84,7 @@ export interface TelegramLockRuntime<TContext extends TelegramLockContext> {
84
84
  owns: (ctx?: TelegramLockContext) => boolean;
85
85
  commitIfOwned: (commit: () => void) => boolean;
86
86
  /** Consolidated-store publication; domain reducers retain their own exact payload/CAS rules. */
87
- publishStateSectionIfOwned?: <T>(section: "workspace" | "runtime", mutate: (current: unknown, observed: Readonly<TelegramRuntimeStateProfile>) => TelegramRuntimeStateMutation<T>, options: TelegramOwnedStatePublicationOptions) => TelegramOwnedStatePublicationResult<T>;
87
+ publishStateSectionIfOwned?: <T>(section: "workspace" | "runtime", mutate: TelegramRuntimeStateSectionReducer<T>, options: TelegramOwnedStatePublicationOptions) => TelegramOwnedStatePublicationResult<T>;
88
88
  refresh: (ctx?: TelegramLockContext) => boolean;
89
89
  /** The polling journal named by owners.json for this key, owned or not. */
90
90
  getJournalPath: () => string | undefined;
@@ -135,6 +135,31 @@ interface TelegramRenameRetryOptions {
135
135
  attempts?: number;
136
136
  retryDelayMs?: number;
137
137
  }
138
+ export type TelegramPrivateFileFailure = "capacity" | "unsafe" | "changed";
139
+ /** Typed private-file refusal; owners map the failure into their own error vocabulary. */
140
+ export declare class TelegramPrivateFileError extends Error {
141
+ readonly failure: TelegramPrivateFileFailure;
142
+ constructor(failure: TelegramPrivateFileFailure, message: string);
143
+ }
144
+ /**
145
+ * Read flags for private runtime files. Where the platform offers them, no-follow and non-blocking opens refuse a
146
+ * swapped link or FIFO at open time. Windows has neither flag and no FIFOs in the file namespace; there the
147
+ * lstat-before/fstat-after identity binding every strict reader performs is the guard, so a link swapped in after
148
+ * inspection opens a different file and is refused as changed.
149
+ */
150
+ export declare const TELEGRAM_STRICT_READ_FLAGS: number;
151
+ /** POSIX owner and permission bits; Windows has no uid, so its ACL-protected agent directory carries privacy. */
152
+ export declare function isTelegramOwnerPrivate(stat: {
153
+ uid: bigint;
154
+ mode: bigint;
155
+ }): boolean;
156
+ /**
157
+ * Read one owner-private, single-link, bounded regular file without following links. Absence returns undefined;
158
+ * an inode or metadata change between inspection and open refuses as `changed`.
159
+ */
160
+ export declare function readTelegramPrivateFile(path: string, maxBytes: number): string | undefined;
161
+ /** Atomically publish owner-private contents through a unique staging file; the rename consumes staging. */
162
+ export declare function publishTelegramPrivateFile(path: string, temporaryBasePath: string, contents: string, label: string, onBoundary?: (boundary: "after-write-before-rename" | "after-rename") => void): void;
138
163
  /** Rename one Telegram runtime artifact with bounded Windows sharing retries. */
139
164
  export declare function renameTelegramPathWithRetry(sourcePath: string, destinationPath: string, options?: TelegramRenameRetryOptions): boolean;
140
165
  export interface TelegramFileTransactionOptions {
@@ -162,6 +187,8 @@ export declare function readTelegramRuntimeState(path: string): TelegramRuntimeS
162
187
  * continuity. Filesystem access errors are not damage and still throw. Returns whether a reset was published.
163
188
  */
164
189
  export declare function resetDamagedTelegramRuntimeState(path: string, validateProfile?: (profile: string, sections: Readonly<TelegramRuntimeStateProfile>) => void): boolean;
190
+ /** Pure section reducer: receives the stored section and its profile, returns the next section and result. */
191
+ export type TelegramRuntimeStateSectionReducer<T> = (current: unknown, observed: Readonly<TelegramRuntimeStateProfile>) => TelegramRuntimeStateMutation<T>;
165
192
  export interface TelegramRuntimeStateMutation<T> {
166
193
  value: unknown;
167
194
  result: T;
@@ -183,10 +210,9 @@ export interface TelegramOwnedStatePublicationOptions extends TelegramRuntimeSta
183
210
  * One physical read/check/write transaction for one named section. The caller supplies domain policy; copies expose
184
211
  * current sibling facts without granting writes to them. No await, nested transaction, repair or legacy import.
185
212
  */
186
- export declare function mutateTelegramRuntimeStateSection<T>(path: string, profile: string, section: TelegramRuntimeStateSection, mutate: (current: unknown, observed: Readonly<TelegramRuntimeStateProfile>) => TelegramRuntimeStateMutation<T>, options: TelegramRuntimeStatePublicationOptions): T;
213
+ export declare function mutateTelegramRuntimeStateSection<T>(path: string, profile: string, section: TelegramRuntimeStateSection, mutate: TelegramRuntimeStateSectionReducer<T>, options: TelegramRuntimeStatePublicationOptions): T;
187
214
  export declare function writeLocks(path: string, locks: Record<string, unknown>): void;
188
215
  export declare function parseTelegramLockEntry(value: unknown): TelegramLockEntry | undefined;
189
- export declare function isProcessAlive(pid: number): boolean;
190
216
  export declare function createTelegramLockRuntime<TContext extends TelegramLockContext>(options?: TelegramLockRuntimeOptions): TelegramLockRuntime<TContext>;
191
217
  export declare function createTelegramLockOwnershipGuard<TContext extends TelegramLockContext>(lock: TelegramLockRuntime<TContext>): TelegramLockOwnershipGuard<TContext>;
192
218
  export declare function createTelegramDirectDeliveryOwnershipChecker<TContext extends TelegramLockContext>(deps: {