@llblab/pi-kit 0.5.0 → 0.5.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 (27) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +1 -1
  3. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -0
  4. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +21 -0
  5. package/node_modules/@llblab/pi-telegram/README.md +2 -0
  6. package/node_modules/@llblab/pi-telegram/docs/architecture.md +6 -4
  7. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +5 -1
  8. package/node_modules/@llblab/pi-telegram/docs/outbound.md +19 -3
  9. package/node_modules/@llblab/pi-telegram/index.ts +10 -0
  10. package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +43 -25
  11. package/node_modules/@llblab/pi-telegram/lib/activity.ts +60 -1
  12. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +101 -90
  13. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +7 -2
  14. package/node_modules/@llblab/pi-telegram/lib/locks.ts +99 -16
  15. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +18 -7
  16. package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +11 -0
  17. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +10 -3
  18. package/node_modules/@llblab/pi-telegram/lib/polling.ts +142 -30
  19. package/node_modules/@llblab/pi-telegram/lib/preview.ts +19 -3
  20. package/node_modules/@llblab/pi-telegram/lib/prompts.ts +8 -6
  21. package/node_modules/@llblab/pi-telegram/lib/queue.ts +101 -66
  22. package/node_modules/@llblab/pi-telegram/lib/routing.ts +192 -58
  23. package/node_modules/@llblab/pi-telegram/lib/status.ts +4 -0
  24. package/node_modules/@llblab/pi-telegram/lib/updates.ts +33 -35
  25. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  26. package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/diagnosis.md +2 -0
  27. package/package.json +2 -2
@@ -291,6 +291,7 @@ export interface TelegramStatusBarTheme {
291
291
  export interface TelegramStatusBarState {
292
292
  hasBotToken: boolean;
293
293
  pollingActive: boolean;
294
+ pollingStopReason?: string;
294
295
  paired: boolean;
295
296
  busRole?: TelegramBridgeBusRole;
296
297
  busLifecyclePhase?: TelegramBridgeBusLifecyclePhase;
@@ -699,6 +700,7 @@ export function createTelegramBridgeStatusRuntime<
699
700
  queuedItems: queuedItemCount,
700
701
  }),
701
702
  queuedStatus: deps.formatQueuedStatus(queuedItems),
703
+ pollingStopReason: deps.getPollingState?.().stopReason,
702
704
  error,
703
705
  };
704
706
  },
@@ -889,6 +891,8 @@ export function buildTelegramStatusBarText(
889
891
  : "";
890
892
  if (!state.hasBotToken)
891
893
  return `${label} ${theme.fg("muted", "not configured")}${queued}`;
894
+ if (state.pollingStopReason === "persistent-conflict" && state.busRole !== "follower")
895
+ return `${label} ${theme.fg("error", "error")}`;
892
896
  if (!state.paired)
893
897
  return `${label} ${theme.fg("warning", "awaiting pairing")}${queued}`;
894
898
  if (state.busLifecyclePhase === "electing")
@@ -481,12 +481,7 @@ const TELEGRAM_UPDATE_ADMISSION_BINDING = Symbol(
481
481
 
482
482
  interface TelegramUpdateAdmissionBinding {
483
483
  sourceUpdateId: number;
484
- report: (
485
- outcome: Extract<
486
- TelegramUpdateAdmissionOutcome,
487
- { kind: "deferred" | "queued" }
488
- >,
489
- ) => void;
484
+ report: (outcome: TelegramUpdateAdmissionOutcome) => void;
490
485
  }
491
486
 
492
487
  export type TelegramQueueAdmissionReceiptLike = TelegramQueueAdmissionReceipt;
@@ -589,6 +584,16 @@ export function collectTelegramAdmissionSourceUpdateIds(
589
584
  return [...sourceUpdateIds].sort((left, right) => left - right);
590
585
  }
591
586
 
587
+ /** Report source completion; true means reported, not a durable settlement acknowledgement. */
588
+ export function reportTelegramUpdateCompleted(value: unknown): boolean {
589
+ const binding = getTelegramUpdateAdmissionBinding(value);
590
+ if (!binding) return false;
591
+ const execution = getTelegramUpdateExecutionFence(value);
592
+ if (execution && !execution.isCurrent()) return false;
593
+ binding.report({ kind: "complete" });
594
+ return true;
595
+ }
596
+
592
597
  export function reportTelegramUpdateDeferred(value: unknown): boolean {
593
598
  const binding = getTelegramUpdateAdmissionBinding(value);
594
599
  if (!binding) return false;
@@ -1810,10 +1815,7 @@ export interface TelegramUpdateWorkerRuntime<TContext> {
1810
1815
  signal: () => void;
1811
1816
  settleDeferred: (input: {
1812
1817
  updateId: number;
1813
- outcome: Extract<
1814
- TelegramUpdateAdmissionOutcome,
1815
- { kind: "deferred" | "queued" }
1816
- >;
1818
+ outcome: TelegramUpdateAdmissionOutcome;
1817
1819
  signal: AbortSignal;
1818
1820
  }) => void;
1819
1821
  isQueueReceiptCommitted: (
@@ -2160,6 +2162,7 @@ export function createTelegramUpdateWorkerRuntime<TContext>(
2160
2162
  failurePhase: string,
2161
2163
  error: unknown,
2162
2164
  currentUpdateId?: number,
2165
+ extraDetails?: Record<string, unknown>,
2163
2166
  ): "blocked" => {
2164
2167
  blocked = true;
2165
2168
  state.lastFailureAtMs = getNowMs();
@@ -2168,6 +2171,7 @@ export function createTelegramUpdateWorkerRuntime<TContext>(
2168
2171
  phase: failurePhase,
2169
2172
  generation: owner?.generation,
2170
2173
  ...(currentUpdateId !== undefined ? { updateId: currentUpdateId } : {}),
2174
+ ...extraDetails,
2171
2175
  });
2172
2176
  transition("blocked", currentUpdateId, blockedReason);
2173
2177
  return "blocked";
@@ -2553,6 +2557,10 @@ export function createTelegramUpdateWorkerRuntime<TContext>(
2553
2557
  `Telegram queue receipt ${normalized.receiptId} conflicts with committed authority.`,
2554
2558
  ),
2555
2559
  currentUpdateId,
2560
+ {
2561
+ receiptId: normalized.receiptId,
2562
+ sourceUpdateIds: normalized.sourceUpdateIds,
2563
+ },
2556
2564
  );
2557
2565
  }
2558
2566
  return "duplicate";
@@ -3012,6 +3020,13 @@ export function createTelegramUpdateWorkerRuntime<TContext>(
3012
3020
  return;
3013
3021
  }
3014
3022
  const claim = claims.get(input.updateId);
3023
+ if (input.outcome.kind === "complete") {
3024
+ // Expiry may retire only a still-deferred source, never accepted queue work.
3025
+ if (claim !== "deferred") return;
3026
+ const result = commitCompletedBatch(expectedOwner, [input.updateId]);
3027
+ if (!result) transition("idle", input.updateId);
3028
+ return;
3029
+ }
3015
3030
  if (input.outcome.kind === "deferred") {
3016
3031
  if (claim === "queued") return;
3017
3032
  if (claim !== "deferred") {
@@ -3447,10 +3462,7 @@ export interface TelegramUpdateAdmissionHandleDeps<
3447
3462
  ) => Promise<void>;
3448
3463
  registry?: TelegramUpdateHandlerRegistry;
3449
3464
  onLateOutcome?: (
3450
- outcome: Extract<
3451
- TelegramUpdateAdmissionOutcome,
3452
- { kind: "deferred" | "queued" }
3453
- >,
3465
+ outcome: TelegramUpdateAdmissionOutcome,
3454
3466
  details: {
3455
3467
  updateId: number;
3456
3468
  ctx: TContext;
@@ -3461,24 +3473,15 @@ export interface TelegramUpdateAdmissionHandleDeps<
3461
3473
  }
3462
3474
 
3463
3475
  function mergeTelegramReportedAdmissionOutcome(
3464
- current:
3465
- | Extract<
3466
- TelegramUpdateAdmissionOutcome,
3467
- { kind: "deferred" | "queued" }
3468
- >
3469
- | undefined,
3470
- next: Extract<
3471
- TelegramUpdateAdmissionOutcome,
3472
- { kind: "deferred" | "queued" }
3473
- >,
3476
+ current: TelegramUpdateAdmissionOutcome | undefined,
3477
+ next: TelegramUpdateAdmissionOutcome,
3474
3478
  updateId: number,
3475
- ): Extract<
3476
- TelegramUpdateAdmissionOutcome,
3477
- { kind: "deferred" | "queued" }
3478
- > {
3479
+ ): TelegramUpdateAdmissionOutcome {
3479
3480
  if (!current || current.kind === "deferred") return next;
3480
3481
  if (next.kind === "deferred") return current;
3481
- if (areTelegramQueueAdmissionReceiptsEqual(current, next)) return current;
3482
+ if (current.kind === "complete" && next.kind === "complete") return current;
3483
+ if (current.kind === "queued" && next.kind === "queued" &&
3484
+ areTelegramQueueAdmissionReceiptsEqual(current, next)) return current;
3482
3485
  throw new TelegramUpdateAdmissionOutcomeError(
3483
3486
  `Telegram update ${updateId} reported conflicting queue outcomes.`,
3484
3487
  );
@@ -3523,12 +3526,7 @@ export function createTelegramUpdateAdmissionHandle<
3523
3526
  execution.assertCurrent();
3524
3527
  if (verdict === "consume") return { kind: "complete" };
3525
3528
  let immediate = true;
3526
- let outcome:
3527
- | Extract<
3528
- TelegramUpdateAdmissionOutcome,
3529
- { kind: "deferred" | "queued" }
3530
- >
3531
- | undefined;
3529
+ let outcome: TelegramUpdateAdmissionOutcome | undefined;
3532
3530
  const boundUpdate = bindTelegramUpdateExecutionFence(
3533
3531
  bindTelegramUpdateAdmissionSource(update, (next) => {
3534
3532
  if (immediate) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-telegram",
3
- "version": "0.43.0",
3
+ "version": "0.43.2",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -13,4 +13,6 @@ These slash commands are registered Pi commands, not shell executables or agent
13
13
 
14
14
  When `PI_CODING_AGENT_DIR` selects another compatible runtime, resolve its equivalent `tmp/telegram` directory.
15
15
 
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
+
16
18
  Do not mutate ownership files, bridge state, journals, bindings, or locks to force recovery. Use supported commands and preserve exact profile, target, transport, and session authority. Never claim successful delivery without transport evidence.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-kit",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -45,7 +45,7 @@
45
45
  "@llblab/pi-codex-usage": "0.9.4",
46
46
  "@llblab/pi-grow-loop": "0.7.4",
47
47
  "@llblab/pi-state-flow": "0.3.0",
48
- "@llblab/pi-telegram": "0.43.0",
48
+ "@llblab/pi-telegram": "0.43.2",
49
49
  "@llblab/skills": "1.14.0"
50
50
  },
51
51
  "bundledDependencies": [