@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
@@ -22,14 +22,21 @@
22
22
  */
23
23
 
24
24
  import {
25
- existsSync,
26
25
  lstatSync,
27
26
  readFileSync,
28
- readdirSync,
27
+ opendirSync,
29
28
  } from "node:fs";
30
29
  import { homedir } from "node:os";
31
30
  import { basename, join, resolve } from "node:path";
31
+ import { decodeTelegramSessionDirectoryName, resolveTelegramTempDir } from "../dist/lib/paths.js";
32
32
 
33
+ const MAX_DIRECTORY_ENTRIES = 10_000;
34
+ const MAX_FILES = 4_096;
35
+ const MAX_BYTES = 64 * 1024 * 1024;
36
+ let remainingEntries = MAX_DIRECTORY_ENTRIES;
37
+ let remainingFiles = MAX_FILES;
38
+ let remainingBytes = MAX_BYTES;
39
+ const SESSION_SNAPSHOT_PATTERN = /^(?:journal\.[a-f0-9]{16}|inbox)(?:\.[a-zA-Z0-9._-]+)?\.json$/u;
33
40
  const SNAPSHOT_PATTERN = /^(?:inbox|follower-inbox-[a-f0-9]{16})(?:\.[a-zA-Z0-9._-]+)?\.json$/u;
34
41
  const SEGMENT_NAME_PATTERN = /^\d{16}\.json$/u;
35
42
  const AUTHORITY_STATES = new Set(["pending", "retry-wait", "queued", "failed"]);
@@ -114,8 +121,24 @@ function isNonNegativeInteger(value) {
114
121
  return Number.isSafeInteger(value) && value >= 0;
115
122
  }
116
123
 
117
- function readJson(path) {
124
+ function listDirectory(path) {
125
+ const directory = opendirSync(path);
126
+ const names = [];
118
127
  try {
128
+ for (;;) {
129
+ const entry = directory.readSync();
130
+ if (!entry) return names.sort();
131
+ if (--remainingEntries < 0) throw new Error("journal directory listing limit exhausted");
132
+ names.push(entry.name);
133
+ }
134
+ } finally { directory.closeSync(); }
135
+ }
136
+
137
+ function readJson(path, stat) {
138
+ try {
139
+ if (--remainingFiles < 0 || stat.size > remainingBytes)
140
+ throw new Error("journal file/byte inspection limit exhausted");
141
+ remainingBytes -= stat.size;
119
142
  return JSON.parse(readFileSync(path, "utf8"));
120
143
  } catch (error) {
121
144
  block(
@@ -306,46 +329,56 @@ function validateSegment(value) {
306
329
  }
307
330
 
308
331
  const agentDir = resolveAgentDir();
309
- const runtimeDir = join(agentDir, "tmp", "telegram");
310
- if (!existsSync(runtimeDir)) {
311
- console.log("SAFE: no Telegram runtime directory exists.");
312
- process.exit(0);
313
- }
314
-
332
+ const runtimeDir = resolveTelegramTempDir(agentDir);
315
333
  let runtimeNames;
334
+ let observedRuntime = false;
316
335
  try {
317
- runtimeNames = readdirSync(runtimeDir);
336
+ if (!lstatSync(runtimeDir).isDirectory()) throw new Error("non-directory Telegram runtime or link");
337
+ observedRuntime = true;
338
+ runtimeNames = listDirectory(runtimeDir);
318
339
  } catch (error) {
319
- block(
320
- `cannot verify Telegram runtime directory ${runtimeDir}: ${error instanceof Error ? error.message : String(error)}`,
321
- );
340
+ if (error?.code === "ENOENT" && !observedRuntime) {
341
+ console.log("SAFE: no Telegram runtime directory exists.");
342
+ process.exit(0);
343
+ }
344
+ block(`cannot verify Telegram runtime directory ${runtimeDir}: ${error instanceof Error ? error.message : String(error)}`);
322
345
  process.exit(1);
323
346
  }
324
347
 
325
- const snapshotNames = runtimeNames.filter((name) => SNAPSHOT_PATTERN.test(name));
326
- const snapshotSet = new Set(snapshotNames);
327
- for (const name of runtimeNames) {
328
- const snapshotName = name.endsWith(".segments")
329
- ? name.slice(0, -".segments".length)
330
- : undefined;
331
- if (snapshotName && SNAPSHOT_PATTERN.test(snapshotName)) {
332
- if (!snapshotSet.has(snapshotName)) {
333
- block(
334
- `cannot verify orphan journal segments without ${join(runtimeDir, snapshotName)}`,
335
- );
348
+ function collectSnapshots(directory, names, pattern, strict = false) {
349
+ const snapshots = names.filter(name => pattern.test(name));
350
+ const snapshotSet = new Set(snapshots);
351
+ for (const name of names) {
352
+ // Legacy recovery folders hold no journal authority; current releases delete them.
353
+ if (name.toLowerCase() === "recovery") continue;
354
+ const snapshotName = name.endsWith(".segments") ? name.slice(0, -".segments".length) : undefined;
355
+ if (snapshotName && pattern.test(snapshotName)) {
356
+ if (!snapshotSet.has(snapshotName)) block(`cannot verify orphan journal segments without ${join(directory, snapshotName)}`);
357
+ continue;
336
358
  }
337
- continue;
338
- }
339
- if (
340
- (name.startsWith("inbox") || name.startsWith("follower-inbox")) &&
341
- !SNAPSHOT_PATTERN.test(name)
342
- ) {
343
- block(`cannot verify unrecognized journal-like artifact ${join(runtimeDir, name)}`);
359
+ if (!pattern.test(name) && (strict || /^(?:inbox|follower-inbox|journal\.)/iu.test(name)))
360
+ block(`cannot verify unrecognized journal-like artifact ${join(directory, name)}`);
344
361
  }
362
+ return snapshots.map(name => join(directory, name));
345
363
  }
346
364
 
347
- for (const name of snapshotNames) {
348
- const path = join(runtimeDir, name);
365
+ const snapshotPaths = collectSnapshots(runtimeDir, runtimeNames, SNAPSHOT_PATTERN);
366
+ for (const name of runtimeNames.filter(name => name.toLowerCase() === "sessions")) {
367
+ const root = join(runtimeDir, name);
368
+ try {
369
+ if (name !== "sessions" || !lstatSync(root).isDirectory()) throw new Error("noncanonical session root or link/type");
370
+ for (const sessionName of listDirectory(root)) {
371
+ const directory = join(root, sessionName);
372
+ if (decodeTelegramSessionDirectoryName(sessionName) === undefined || !lstatSync(directory).isDirectory()) {
373
+ block(`cannot verify session folder ${directory}`);
374
+ continue;
375
+ }
376
+ snapshotPaths.push(...collectSnapshots(directory, listDirectory(directory), SESSION_SNAPSHOT_PATTERN, true));
377
+ }
378
+ } catch (error) { block(`cannot verify session journals ${root}: ${String(error)}`); }
379
+ }
380
+
381
+ for (const path of snapshotPaths) {
349
382
  let pathStat;
350
383
  try {
351
384
  pathStat = lstatSync(path);
@@ -357,7 +390,7 @@ for (const name of snapshotNames) {
357
390
  block(`cannot verify non-file journal snapshot ${path}`);
358
391
  continue;
359
392
  }
360
- const snapshot = validateSnapshot(readJson(path));
393
+ const snapshot = validateSnapshot(readJson(path, pathStat));
361
394
  if (!snapshot) {
362
395
  block(`cannot verify malformed journal snapshot ${path}`);
363
396
  continue;
@@ -367,14 +400,19 @@ for (const name of snapshotNames) {
367
400
  let botIdentity = snapshot.botIdentity;
368
401
  const entries = snapshot.entries;
369
402
  const segmentDir = `${path}.segments`;
370
- if (existsSync(segmentDir)) {
403
+ let segmentDirectoryStat;
404
+ try { segmentDirectoryStat = lstatSync(segmentDir); }
405
+ catch (error) {
406
+ if (error?.code !== "ENOENT") block(`cannot verify journal segments ${segmentDir}: ${String(error)}`);
407
+ }
408
+ if (segmentDirectoryStat) {
371
409
  let segmentNames;
372
410
  try {
373
- if (!lstatSync(segmentDir).isDirectory()) {
411
+ if (!segmentDirectoryStat.isDirectory()) {
374
412
  block(`cannot verify non-directory journal segments ${segmentDir}`);
375
413
  continue;
376
414
  }
377
- segmentNames = readdirSync(segmentDir);
415
+ segmentNames = listDirectory(segmentDir);
378
416
  } catch (error) {
379
417
  block(`cannot verify journal segments ${segmentDir}: ${String(error)}`);
380
418
  continue;
@@ -389,7 +427,6 @@ for (const name of snapshotNames) {
389
427
  SEGMENT_NAME_PATTERN.test(candidate),
390
428
  ).sort()) {
391
429
  const nameRevision = Number(segmentName.slice(0, 16));
392
- if (nameRevision <= revision) continue;
393
430
  const segmentPath = join(segmentDir, segmentName);
394
431
  let segmentStat;
395
432
  try {
@@ -398,9 +435,9 @@ for (const name of snapshotNames) {
398
435
  block(`cannot verify journal segment ${segmentPath}: ${String(error)}`);
399
436
  break;
400
437
  }
401
- const segment = segmentStat.isFile()
402
- ? validateSegment(readJson(segmentPath))
403
- : undefined;
438
+ if (!segmentStat.isFile()) { block(`cannot verify non-file journal segment ${segmentPath}`); break; }
439
+ if (nameRevision <= revision) continue;
440
+ const segment = validateSegment(readJson(segmentPath, segmentStat));
404
441
  if (
405
442
  !segment ||
406
443
  segment.revision !== nameRevision ||
@@ -426,10 +463,10 @@ for (const name of snapshotNames) {
426
463
  }
427
464
  if (entries.size > 0) {
428
465
  block(
429
- `${path} retains ${entries.size} unresolved update(s); drain with 0.28.x before downgrade.`,
466
+ `${path} retains ${entries.size} unresolved update(s); drain with a compatible runtime before downgrade.`,
430
467
  );
431
468
  }
432
469
  }
433
470
 
434
471
  if (process.exitCode) process.exit(1);
435
- console.log(`SAFE: ${snapshotNames.length} Telegram journal(s) contain no unresolved updates.`);
472
+ console.log(`SAFE: ${snapshotPaths.length} Telegram journal(s) contain no unresolved updates.`);
@@ -46,7 +46,7 @@ A disabled control is not an action: it needs no prompt or selected style and mu
46
46
 
47
47
  Prompts must name any target, operation, constraint, or freshness identity whose omission could change the action. Reuse visible context only when it remains unambiguous under delayed or reordered clicks. Never encode volatile output that should be freshly inspected.
48
48
 
49
- Every generated human-readable action label must use `emoji + space + text`; emoji-free text labels are invalid. Choose the emoji by action semantics, keep its meaning consistent, and never rely on emoji or color alone. Coordinates, established symbolic controls, and intentionally spatial glyphs already satisfy the marker role through their domain grammar. If prompt buttons are unavailable, preserve the same choices as a numbered list.
49
+ Every generated human-readable action label must use `emoji + space + text`; emoji-free text labels are invalid. Choose the emoji by action semantics, keep its meaning consistent, and never rely on emoji or color alone. State/value controls follow their UI-kit grammar; unmarked inactive list items are not action labels. Coordinates, established symbolic controls, and intentionally spatial glyphs already satisfy the marker role through their domain grammar. If prompt buttons are unavailable, preserve the same choices as a numbered list.
50
50
 
51
51
  ## Layout Kernel
52
52
 
@@ -97,10 +97,10 @@ Show concise failure evidence and emit valid recovery controls such as diagnose,
97
97
  Before sending:
98
98
 
99
99
  - At least one useful button is present whenever the transport supports prompt buttons.
100
- - Every human-readable button label begins with a semantic emoji and one ASCII space.
100
+ - Every human-readable action label begins with a semantic emoji and one ASCII space; state/value controls follow their owning documented grammar.
101
101
  - State, actions, owner, and target agree.
102
102
  - Live claims are fresh; adaptation and incompleteness are explicit.
103
- - Every prompt is sufficient and every label follows its semantic emoji rule.
103
+ - Every prompt is sufficient; labels follow their control grammar.
104
104
  - Row grouping reflects real hierarchy or peer relationships.
105
105
  - High-impact actions require confirmation.
106
106
  - No secret or hidden reasoning appears.
@@ -6,12 +6,12 @@ Inspect in this order:
6
6
 
7
7
  1. `/telegram-status` for compact health in the Pi TUI.
8
8
  2. `/telegram-status --debug` for bounded human-readable diagnostics in the Pi TUI.
9
- 3. `~/.pi/agent/tmp/telegram/state.json` and `logs.jsonl` for default-profile redacted evidence.
10
- 4. `state.<profile>.json` and `logs.<profile>.jsonl` for a named profile.
9
+ 3. `~/.pi/agent/tmp/pi-telegram/state.json` (per-profile `transport`, `workspace` canonical bindings and `runtime` roster/diagnostics sections) and `logs.jsonl` (profile-labelled redacted evidence); rotated history is `logs/logs._prev.jsonl`.
10
+ 4. For a named profile, read its `profiles.<name>` entry and filter log records by `profile`; service journals are `journals/<kind>.<profile sha256>.json`.
11
11
 
12
12
  These slash commands are registered Pi commands, not shell executables or agent tools. If the agent cannot invoke them through a supported Pi surface, read the diagnostic files directly; do not run them in Bash or inject terminal input.
13
13
 
14
- When `PI_CODING_AGENT_DIR` selects another compatible runtime, resolve its equivalent `tmp/telegram` directory.
14
+ When `PI_CODING_AGENT_DIR` selects another compatible runtime, resolve its equivalent `tmp/pi-telegram` directory.
15
15
 
16
16
  A `persistent-conflict` polling stop means the bounded competing-`getUpdates` threshold triggered full transport stand-down, not cancellation of accepted local Pi work. The terminal diagnostic distinguishes lost local ownership from a competing client despite an apparently owned lock. Check other profiles, agent directories, installations, or non-Pi clients sharing the bot; after removing the competition, reconnect through the supported Pi command. Do not restart repeatedly or alter lock files to compete for the stream.
17
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-kit",
3
- "version": "0.27.5",
3
+ "version": "0.28.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -46,8 +46,8 @@
46
46
  "@llblab/pi-clean-room": "0.3.0",
47
47
  "@llblab/pi-codex-usage": "0.12.1",
48
48
  "@llblab/pi-grow-loop": "0.9.0",
49
- "@llblab/pi-state-flow": "0.25.4",
50
- "@llblab/pi-telegram": "0.51.6",
49
+ "@llblab/pi-state-flow": "0.25.5",
50
+ "@llblab/pi-telegram": "0.52.0",
51
51
  "@llblab/skills": "1.15.0"
52
52
  },
53
53
  "bundledDependencies": [