@llblab/pi-kit 0.35.0 → 0.35.2

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 (68) hide show
  1. package/BACKLOG.md +2 -0
  2. package/CHANGELOG.md +11 -0
  3. package/README.md +1 -1
  4. package/node_modules/@llblab/pi-telegram/AGENTS.md +3 -2
  5. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -6
  6. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +18 -0
  7. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +3 -2
  8. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +11 -3
  9. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +2 -2
  10. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +22 -0
  11. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +75 -16
  12. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +1 -1
  13. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +11 -1
  14. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +30 -19
  15. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +2 -0
  16. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +21 -8
  17. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +61 -46
  18. package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +7 -0
  19. package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +80 -0
  20. package/node_modules/@llblab/pi-telegram/dist/lib/logging.d.ts +36 -0
  21. package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +80 -0
  22. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +12 -0
  23. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +33 -3
  24. package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +2 -1
  25. package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +18 -3
  26. package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +13 -0
  27. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +33 -12
  28. package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +6 -2
  29. package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +46 -4
  30. package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +5 -1
  31. package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +2 -2
  32. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +2 -0
  33. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +137 -13
  34. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +11 -0
  35. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.js +31 -8
  36. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +12 -5
  37. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +21 -3
  38. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +5 -1
  39. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +5 -1
  40. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +26 -13
  41. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +6 -2
  42. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +57 -12
  43. package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
  44. package/node_modules/@llblab/pi-telegram/docs/architecture.md +5 -1
  45. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +6 -2
  46. package/node_modules/@llblab/pi-telegram/docs/outbound.md +4 -2
  47. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +13 -2
  48. package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +2 -1
  49. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +111 -15
  50. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +15 -0
  51. package/node_modules/@llblab/pi-telegram/lib/bus.ts +30 -21
  52. package/node_modules/@llblab/pi-telegram/lib/commands.ts +21 -8
  53. package/node_modules/@llblab/pi-telegram/lib/extension.ts +64 -56
  54. package/node_modules/@llblab/pi-telegram/lib/journal.ts +80 -0
  55. package/node_modules/@llblab/pi-telegram/lib/logging.ts +122 -0
  56. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +36 -3
  57. package/node_modules/@llblab/pi-telegram/lib/paths.ts +22 -3
  58. package/node_modules/@llblab/pi-telegram/lib/polling.ts +44 -10
  59. package/node_modules/@llblab/pi-telegram/lib/queue.ts +43 -4
  60. package/node_modules/@llblab/pi-telegram/lib/replies.ts +3 -2
  61. package/node_modules/@llblab/pi-telegram/lib/routing.ts +140 -18
  62. package/node_modules/@llblab/pi-telegram/lib/runtime.ts +40 -7
  63. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +30 -10
  64. package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +6 -1
  65. package/node_modules/@llblab/pi-telegram/lib/threads.ts +37 -20
  66. package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +69 -17
  67. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  68. package/package.json +2 -2
@@ -146,6 +146,8 @@ export function captureTelegramWorkspaceJournalProtectionSources(input: {
146
146
  path: string,
147
147
  ) => () => TelegramWorkspaceJournalReader | undefined;
148
148
  };
149
+ /** Snapshot-scoped reuse of binding-independent (shared/discovered) source reads. */
150
+ sharedSourceReads?: Map<string, TelegramWorkspaceJournalProtectionSource>;
149
151
  }): TelegramWorkspaceJournalProtectionCapture {
150
152
  const sources: TelegramWorkspaceJournalProtectionSource[] = [];
151
153
  let complete =
@@ -155,26 +157,43 @@ export function captureTelegramWorkspaceJournalProtectionSources(input: {
155
157
  scope: TelegramWorkspaceJournalProtectionSource["scope"],
156
158
  resolve: () => TelegramWorkspaceJournalReader | undefined,
157
159
  ): void => {
160
+ const sharedKey =
161
+ scope.kind === "shared"
162
+ ? "shared"
163
+ : scope.kind === "discovered"
164
+ ? `discovered:${scope.path}`
165
+ : undefined;
166
+ let source =
167
+ sharedKey === undefined
168
+ ? undefined
169
+ : input.sharedSourceReads?.get(sharedKey);
170
+ if (!source) {
171
+ source = readSource(scope, resolve);
172
+ if (sharedKey !== undefined)
173
+ input.sharedSourceReads?.set(sharedKey, source);
174
+ }
175
+ if (source.kind === "unknown") complete = false;
176
+ sources.push(source);
177
+ };
178
+ const readSource = (
179
+ scope: TelegramWorkspaceJournalProtectionSource["scope"],
180
+ resolve: () => TelegramWorkspaceJournalReader | undefined,
181
+ ): TelegramWorkspaceJournalProtectionSource => {
158
182
  try {
159
183
  const binding = resolve();
160
- if (!binding) {
161
- complete = false;
162
- sources.push({ kind: "unknown", scope });
163
- return;
164
- }
184
+ if (!binding) return { kind: "unknown", scope };
165
185
  const read = binding.readForProtection ?? binding.journal.read;
166
186
  const snapshot = input.withJournalReference
167
187
  ? input.withJournalReference(binding, read)
168
188
  : read();
169
- sources.push({
189
+ return {
170
190
  kind: "available",
171
191
  scope,
172
192
  entries: snapshot.entries,
173
193
  ...(snapshot.exists === undefined ? {} : { exists: snapshot.exists }),
174
- });
194
+ };
175
195
  } catch {
176
- complete = false;
177
- sources.push({ kind: "unknown", scope });
196
+ return { kind: "unknown", scope };
178
197
  }
179
198
  };
180
199
  capture({ kind: "shared" }, input.resolveLeader);
@@ -586,10 +605,12 @@ interface TelegramWorkspaceProtectionObserverDeps {
586
605
  }
587
606
 
588
607
  export interface TelegramWorkspaceProtectionObserver {
589
- capture: (
608
+ capture: ((
590
609
  binding: TelegramWorkspaceThreadBinding,
591
610
  options?: { requireBindingProvenance?: boolean },
592
- ) => TelegramWorkspaceExternalProtectionEvidence;
611
+ ) => TelegramWorkspaceExternalProtectionEvidence) & {
612
+ withSnapshot?: <T>(capture: () => T) => T;
613
+ };
593
614
  captureJournalSources: (
594
615
  binding: TelegramWorkspaceThreadBinding,
595
616
  ) => TelegramWorkspaceJournalProtectionCapture;
@@ -602,9 +623,39 @@ export interface TelegramWorkspaceProtectionObserver {
602
623
  export function createTelegramWorkspaceProtectionObserver(
603
624
  deps: TelegramWorkspaceProtectionObserverDeps,
604
625
  ): TelegramWorkspaceProtectionObserver {
626
+ // One occupancy snapshot probes every binding synchronously; namespace and shared/discovered
627
+ // journal reads are binding-independent, so read them once per snapshot instead of per binding.
628
+ // Never widen this beyond one synchronous capture: post-fence rechecks need fresh evidence.
629
+ let snapshot:
630
+ | {
631
+ namespace?: { value?: TelegramJournalNamespaceInspection; error?: unknown };
632
+ reads: Map<string, TelegramWorkspaceJournalProtectionSource>;
633
+ }
634
+ | undefined;
635
+ const inspectNamespace = (): TelegramJournalNamespaceInspection | undefined => {
636
+ if (!snapshot) return deps.inspectJournalNamespace?.();
637
+ if (!snapshot.namespace) {
638
+ try {
639
+ snapshot.namespace = { value: deps.inspectJournalNamespace?.() };
640
+ } catch (error) {
641
+ snapshot.namespace = { error };
642
+ }
643
+ }
644
+ if ("error" in snapshot.namespace) throw snapshot.namespace.error;
645
+ return snapshot.namespace.value;
646
+ };
647
+ const withSnapshot = <T>(run: () => T): T => {
648
+ if (snapshot) return run();
649
+ snapshot = { reads: new Map() };
650
+ try {
651
+ return run();
652
+ } finally {
653
+ snapshot = undefined;
654
+ }
655
+ };
605
656
  const captureJournalSources: TelegramWorkspaceProtectionObserver["captureJournalSources"] =
606
657
  (candidate) => {
607
- const namespace = deps.inspectJournalNamespace?.();
658
+ const namespace = inspectNamespace();
608
659
  if (
609
660
  deps.inspectJournalNamespace &&
610
661
  (!namespace ||
@@ -658,12 +709,13 @@ export function createTelegramWorkspaceProtectionObserver(
658
709
  },
659
710
  }
660
711
  : {}),
712
+ ...(snapshot ? { sharedSourceReads: snapshot.reads } : {}),
661
713
  });
662
714
  };
663
- const capture: TelegramWorkspaceProtectionObserver["capture"] = function (
664
- binding,
665
- options,
666
- ) {
715
+ const captureOne = function (
716
+ binding: TelegramWorkspaceThreadBinding,
717
+ options?: { requireBindingProvenance?: boolean },
718
+ ): TelegramWorkspaceExternalProtectionEvidence {
667
719
  return captureTelegramWorkspaceExternalProtection({
668
720
  binding,
669
721
  requireBindingProvenance: options?.requireBindingProvenance,
@@ -714,7 +766,7 @@ export function createTelegramWorkspaceProtectionObserver(
714
766
  });
715
767
  };
716
768
  return {
717
- capture,
769
+ capture: Object.assign(captureOne, { withSnapshot }),
718
770
  captureJournalSources,
719
771
  getJournalWriterProtection:
720
772
  deps.getJournalWriterProtection ?? (() => "unknown"),
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-telegram",
3
- "version": "0.57.0",
3
+ "version": "0.57.2",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-kit",
3
- "version": "0.35.0",
3
+ "version": "0.35.2",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -47,7 +47,7 @@
47
47
  "@llblab/pi-codex-usage": "0.13.1",
48
48
  "@llblab/pi-grow-loop": "0.9.0",
49
49
  "@llblab/pi-state-flow": "0.26.4",
50
- "@llblab/pi-telegram": "0.57.0",
50
+ "@llblab/pi-telegram": "0.57.2",
51
51
  "@llblab/skills": "1.15.0"
52
52
  },
53
53
  "bundledDependencies": [