@llblab/pi-kit 0.25.0 → 0.27.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 (169) hide show
  1. package/BACKLOG.md +5 -1
  2. package/CHANGELOG.md +11 -0
  3. package/README.md +10 -8
  4. package/node_modules/@llblab/pi-actors/AGENTS.md +2 -0
  5. package/node_modules/@llblab/pi-actors/CHANGELOG.md +4 -1
  6. package/node_modules/@llblab/pi-actors/LICENSE +21 -0
  7. package/node_modules/@llblab/pi-actors/README.md +1 -1
  8. package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +1 -1
  9. package/node_modules/@llblab/pi-actors/package.json +4 -3
  10. package/node_modules/@llblab/pi-claude-usage/AGENTS.md +6 -3
  11. package/node_modules/@llblab/pi-claude-usage/BACKLOG.md +2 -1
  12. package/node_modules/@llblab/pi-claude-usage/CHANGELOG.md +8 -0
  13. package/node_modules/@llblab/pi-claude-usage/README.md +48 -3
  14. package/node_modules/@llblab/pi-claude-usage/index.ts +8 -1159
  15. package/node_modules/@llblab/pi-claude-usage/lib/extension.ts +30 -0
  16. package/node_modules/@llblab/pi-claude-usage/lib/fast.ts +24 -0
  17. package/node_modules/@llblab/pi-claude-usage/lib/query.ts +146 -0
  18. package/node_modules/@llblab/pi-claude-usage/lib/status-format.ts +297 -0
  19. package/node_modules/@llblab/pi-claude-usage/lib/status.ts +366 -0
  20. package/node_modules/@llblab/pi-claude-usage/lib/telegram.ts +44 -0
  21. package/node_modules/@llblab/pi-claude-usage/lib/usage-store.ts +221 -0
  22. package/node_modules/@llblab/pi-claude-usage/lib/usage.ts +128 -0
  23. package/node_modules/@llblab/pi-claude-usage/package.json +9 -5
  24. package/node_modules/@llblab/pi-clean-room/AGENTS.md +1 -0
  25. package/node_modules/@llblab/pi-clean-room/CHANGELOG.md +5 -0
  26. package/node_modules/@llblab/pi-clean-room/LICENSE +21 -0
  27. package/node_modules/@llblab/pi-clean-room/README.md +1 -1
  28. package/node_modules/@llblab/pi-clean-room/package.json +3 -2
  29. package/node_modules/@llblab/pi-codex-usage/AGENTS.md +9 -6
  30. package/node_modules/@llblab/pi-codex-usage/BACKLOG.md +2 -1
  31. package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +17 -0
  32. package/node_modules/@llblab/pi-codex-usage/README.md +75 -17
  33. package/node_modules/@llblab/pi-codex-usage/index.ts +8 -1602
  34. package/node_modules/@llblab/pi-codex-usage/lib/extension.ts +25 -0
  35. package/node_modules/@llblab/pi-codex-usage/lib/fast.ts +23 -0
  36. package/node_modules/@llblab/pi-codex-usage/lib/query.ts +368 -0
  37. package/node_modules/@llblab/pi-codex-usage/lib/status-format.ts +347 -0
  38. package/node_modules/@llblab/pi-codex-usage/lib/status.ts +435 -0
  39. package/node_modules/@llblab/pi-codex-usage/lib/telegram.ts +45 -0
  40. package/node_modules/@llblab/pi-codex-usage/lib/usage-store.ts +229 -0
  41. package/node_modules/@llblab/pi-codex-usage/lib/usage.ts +425 -0
  42. package/node_modules/@llblab/pi-codex-usage/package.json +11 -6
  43. package/node_modules/@llblab/pi-command-fast/AGENTS.md +7 -0
  44. package/node_modules/@llblab/pi-command-fast/BACKLOG.md +9 -0
  45. package/node_modules/@llblab/pi-command-fast/CHANGELOG.md +7 -0
  46. package/node_modules/@llblab/pi-command-fast/LICENSE +21 -0
  47. package/node_modules/@llblab/pi-command-fast/README.md +42 -0
  48. package/node_modules/@llblab/pi-command-fast/dist/command.d.ts +8 -0
  49. package/node_modules/@llblab/pi-command-fast/dist/command.js +52 -0
  50. package/node_modules/@llblab/pi-command-fast/dist/index.d.ts +3 -0
  51. package/node_modules/@llblab/pi-command-fast/dist/index.js +3 -0
  52. package/node_modules/@llblab/pi-command-fast/dist/models-json.d.ts +10 -0
  53. package/node_modules/@llblab/pi-command-fast/dist/models-json.js +81 -0
  54. package/node_modules/@llblab/pi-command-fast/package.json +49 -0
  55. package/node_modules/@llblab/pi-grow-loop/AGENTS.md +1 -0
  56. package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +4 -1
  57. package/node_modules/@llblab/pi-grow-loop/LICENSE +21 -0
  58. package/node_modules/@llblab/pi-grow-loop/README.md +1 -1
  59. package/node_modules/@llblab/pi-grow-loop/package.json +3 -2
  60. package/node_modules/@llblab/pi-state-flow/AGENTS.md +7 -6
  61. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +13 -5
  62. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +16 -1
  63. package/node_modules/@llblab/pi-state-flow/LICENSE +21 -0
  64. package/node_modules/@llblab/pi-state-flow/README.md +117 -35
  65. package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.d.ts +24 -1
  66. package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.js +80 -1
  67. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.d.ts +18 -1
  68. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.js +41 -1
  69. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +346 -303
  70. package/node_modules/@llblab/pi-state-flow/dist/lib/git.d.ts +31 -2
  71. package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +74 -5
  72. package/node_modules/@llblab/pi-state-flow/dist/lib/operation.d.ts +37 -0
  73. package/node_modules/@llblab/pi-state-flow/dist/lib/operation.js +59 -0
  74. package/node_modules/@llblab/pi-state-flow/dist/lib/ownership.d.ts +31 -0
  75. package/node_modules/@llblab/pi-state-flow/dist/lib/ownership.js +117 -0
  76. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +7 -7
  77. package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +1 -1
  78. package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +10 -1
  79. package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +60 -1
  80. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +6 -0
  81. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +8 -5
  82. package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +2 -0
  83. package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +28 -0
  84. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +6 -1
  85. package/node_modules/@llblab/pi-state-flow/dist/package.json +10 -9
  86. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-guide/SKILL.md +14 -6
  87. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +2 -2
  88. package/node_modules/@llblab/pi-state-flow/docs/README.md +19 -9
  89. package/node_modules/@llblab/pi-state-flow/docs/agent-contract-relocation.md +4 -4
  90. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +646 -89
  91. package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +116 -37
  92. package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +118 -21
  93. package/node_modules/@llblab/pi-state-flow/docs/fork-contract.md +70 -8
  94. package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +88 -14
  95. package/node_modules/@llblab/pi-state-flow/docs/performance.md +83 -66
  96. package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +391 -62
  97. package/node_modules/@llblab/pi-state-flow/docs/usage.md +317 -61
  98. package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +85 -1
  99. package/node_modules/@llblab/pi-state-flow/lib/compaction.ts +49 -2
  100. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +342 -301
  101. package/node_modules/@llblab/pi-state-flow/lib/git.ts +77 -5
  102. package/node_modules/@llblab/pi-state-flow/lib/operation.ts +75 -0
  103. package/node_modules/@llblab/pi-state-flow/lib/ownership.ts +120 -0
  104. package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +7 -8
  105. package/node_modules/@llblab/pi-state-flow/lib/query.ts +1 -1
  106. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +1 -1
  107. package/node_modules/@llblab/pi-state-flow/lib/session.ts +52 -1
  108. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +8 -7
  109. package/node_modules/@llblab/pi-state-flow/lib/status.ts +29 -0
  110. package/node_modules/@llblab/pi-state-flow/lib/transition.ts +5 -1
  111. package/node_modules/@llblab/pi-state-flow/package.json +10 -9
  112. package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +14 -6
  113. package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +2 -2
  114. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -0
  115. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +10 -0
  116. package/node_modules/@llblab/pi-telegram/README.md +1 -1
  117. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +4 -1
  118. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +16 -12
  119. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +1 -1
  120. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +7 -1
  121. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +12 -3
  122. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +137 -83
  123. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +26 -0
  124. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +57 -2
  125. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +109 -4
  126. package/node_modules/@llblab/pi-telegram/dist/lib/model.js +2 -4
  127. package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +3 -1
  128. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +31 -1
  129. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +4 -4
  130. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +1 -0
  131. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +17 -4
  132. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +2 -2
  133. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +48 -12
  134. package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
  135. package/node_modules/@llblab/pi-telegram/docs/architecture.md +6 -5
  136. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +2 -0
  137. package/node_modules/@llblab/pi-telegram/docs/public-api.md +2 -2
  138. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +4 -0
  139. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +17 -10
  140. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +8 -2
  141. package/node_modules/@llblab/pi-telegram/lib/commands.ts +135 -97
  142. package/node_modules/@llblab/pi-telegram/lib/extension.ts +25 -0
  143. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +140 -4
  144. package/node_modules/@llblab/pi-telegram/lib/model.ts +2 -4
  145. package/node_modules/@llblab/pi-telegram/lib/status.ts +30 -1
  146. package/node_modules/@llblab/pi-telegram/lib/sync.ts +4 -4
  147. package/node_modules/@llblab/pi-telegram/lib/threads.ts +21 -3
  148. package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +46 -13
  149. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  150. package/node_modules/jsonc-parser/CHANGELOG.md +76 -0
  151. package/node_modules/jsonc-parser/LICENSE.md +21 -0
  152. package/node_modules/jsonc-parser/README.md +364 -0
  153. package/node_modules/jsonc-parser/SECURITY.md +41 -0
  154. package/node_modules/jsonc-parser/lib/esm/impl/edit.js +185 -0
  155. package/node_modules/jsonc-parser/lib/esm/impl/format.js +261 -0
  156. package/node_modules/jsonc-parser/lib/esm/impl/parser.js +659 -0
  157. package/node_modules/jsonc-parser/lib/esm/impl/scanner.js +443 -0
  158. package/node_modules/jsonc-parser/lib/esm/impl/string-intern.js +29 -0
  159. package/node_modules/jsonc-parser/lib/esm/main.d.ts +351 -0
  160. package/node_modules/jsonc-parser/lib/esm/main.js +178 -0
  161. package/node_modules/jsonc-parser/lib/umd/impl/edit.js +201 -0
  162. package/node_modules/jsonc-parser/lib/umd/impl/format.js +275 -0
  163. package/node_modules/jsonc-parser/lib/umd/impl/parser.js +682 -0
  164. package/node_modules/jsonc-parser/lib/umd/impl/scanner.js +456 -0
  165. package/node_modules/jsonc-parser/lib/umd/impl/string-intern.js +42 -0
  166. package/node_modules/jsonc-parser/lib/umd/main.d.ts +351 -0
  167. package/node_modules/jsonc-parser/lib/umd/main.js +194 -0
  168. package/node_modules/jsonc-parser/package.json +37 -0
  169. package/package.json +8 -8
@@ -1,9 +1,38 @@
1
1
  /**
2
2
  * Telegram status rendering helpers
3
3
  * Zones: telegram ui, pi agent diagnostics, tui
4
- * Builds usage, cost, and context summaries for the interactive Telegram status view
4
+ * Owns status summaries, redacted runtime diagnostics, and compact connection-failure copy
5
5
  */
6
6
 
7
+ /** UI copy is allowlisted; raw exception text belongs only in redacted diagnostics. */
8
+ export function formatTelegramConnectionFailure(error: unknown): string {
9
+ const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
10
+ const status = error && typeof error === "object" && "status" in error ? error.status : undefined;
11
+ const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
12
+ if (status === 401) return "Telegram token rejected. Run /telegram-setup.";
13
+ if (status === 403) return "Telegram access denied. Check /telegram-status --debug.";
14
+ if ((typeof code === "string" && ["ECONNREFUSED", "ETIMEDOUT", "ENOTFOUND", "ECONNRESET"].includes(code)) ||
15
+ /network unavailable|fetch failed/i.test(message)) {
16
+ return "Telegram network unavailable. Retry /telegram-connect.";
17
+ }
18
+ if (/Workspace slots?.*(?:unavailable|exhausted)|no free.*slot/i.test(message)) {
19
+ return "No Telegram slot available. Check /telegram-status --debug.";
20
+ }
21
+ if (code === "incompatible-protocol" || /protocol.*(?:incompatible|mismatch)|incompatible.*protocol/i.test(message)) {
22
+ return "Telegram instances are incompatible. Update them together.";
23
+ }
24
+ if (/unsupported.*(?:journal|version)|(?:journal|version).*unsupported/i.test(message)) {
25
+ return "Telegram state version unsupported. Use a compatible runtime.";
26
+ }
27
+ if (/follower registration failed|active in another Pi instance/i.test(message)) {
28
+ return "Telegram leader is active but unavailable. Check /telegram-status --debug.";
29
+ }
30
+ if (/unfinished Thread creation does not match/i.test(message)) {
31
+ return "Telegram Thread creation is unresolved. Check /telegram-status --debug.";
32
+ }
33
+ return "Telegram connection failed. Check /telegram-status --debug.";
34
+ }
35
+
7
36
  const TELEGRAM_STATUS_DEFAULT_PROFILE_NAME = "default";
8
37
 
9
38
  export type TelegramStatusQueueLane = "control" | "priority" | "default";
@@ -773,6 +773,7 @@ export async function ensureTelegramLeaderThreadBinding(
773
773
  : undefined;
774
774
  const legacyWorkspaceBinding =
775
775
  workspaceIdentity?.instanceSlot === "a" &&
776
+ deps.sessionId === undefined &&
776
777
  !persistedWorkspaceBinding &&
777
778
  typeof legacyLeaderRecord?.target.threadId === "number"
778
779
  ? {
@@ -885,10 +886,9 @@ export async function ensureTelegramLeaderThreadBinding(
885
886
  (record.status === "active" || record.status === "starting")
886
887
  );
887
888
  });
888
- // Short-circuit: when the instance already has an active thread and we are not
889
- // force-freshing, reuse it without re-provisioning. A thread belongs to the
890
- // live instance binding, not to one transient Pi session lifecycle.
891
- if (!deps.forceFreshUnnamed && priorTargets.length > 0) {
889
+ // Legacy callers without session identity may reuse the active instance target.
890
+ // Session-aware callers must resolve their exact Workspace binding instead.
891
+ if (deps.sessionId === undefined && !deps.forceFreshUnnamed && priorTargets.length > 0) {
892
892
  const record = priorTargets[0];
893
893
  deps.recordEvent(
894
894
  "telegram",
@@ -229,6 +229,7 @@ export interface TelegramThreadPendingProvision {
229
229
  owner: "leader" | "manual-follower";
230
230
  instanceId: string;
231
231
  profileKey?: string;
232
+ workspaceBindingKey?: string;
232
233
  status?: "in-flight" | "ambiguous";
233
234
  threadName?: string;
234
235
  displayTitle?: string;
@@ -1528,6 +1529,9 @@ function normalizePendingProvision(
1528
1529
  ...(record.status === "in-flight" || record.status === "ambiguous"
1529
1530
  ? { status: record.status }
1530
1531
  : {}),
1532
+ ...(typeof record.workspaceBindingKey === "string"
1533
+ ? { workspaceBindingKey: record.workspaceBindingKey }
1534
+ : {}),
1531
1535
  ...(typeof record.threadName === "string"
1532
1536
  ? { threadName: record.threadName }
1533
1537
  : {}),
@@ -4919,6 +4923,13 @@ export function createTelegramTopicTargetProvisioner(
4919
4923
  pending.profileKey === request.profileKey ||
4920
4924
  pending.instanceId === request.instanceId,
4921
4925
  );
4926
+ const pendingTarget = pendingForRequest?.target;
4927
+ if (pendingForRequest && request.workspaceBindingKey &&
4928
+ pendingForRequest.workspaceBindingKey !== request.workspaceBindingKey &&
4929
+ !(pendingTarget && deps.store.listWorkspaceBindings().some((binding) =>
4930
+ binding.bindingKey === request.workspaceBindingKey && targetMatches(binding.target, pendingTarget)))) {
4931
+ throw new Error("Telegram unfinished Thread creation does not match this session binding.");
4932
+ }
4922
4933
  if (pendingForRequest?.target) {
4923
4934
  const target = pendingForRequest.target;
4924
4935
  const observation = deps.store.listSyncObservations().find((entry) =>
@@ -4933,8 +4944,13 @@ export function createTelegramTopicTargetProvisioner(
4933
4944
  pendingForRequest = undefined;
4934
4945
  }
4935
4946
  }
4947
+ const matchesWorkspace = (target: TelegramTarget): boolean =>
4948
+ !request.workspaceBindingKey ||
4949
+ deps.store.listWorkspaceBindings().some((binding) =>
4950
+ binding.bindingKey === request.workspaceBindingKey && targetMatches(binding.target, target)) ||
4951
+ (!!pendingForRequest?.target && targetMatches(pendingForRequest.target, target));
4936
4952
  const existing = deps.store.getByProfileKey(request.profileKey);
4937
- if (existing && isCurrentThreadRecord(existing)) {
4953
+ if (existing && isCurrentThreadRecord(existing) && matchesWorkspace(existing.target)) {
4938
4954
  const slot = existing.slot ?? deps.store.allocateSlot(request.profileKey);
4939
4955
  if (!slot) {
4940
4956
  throw new TelegramWorkspaceSlotUnavailableError();
@@ -5017,7 +5033,7 @@ export function createTelegramTopicTargetProvisioner(
5017
5033
  const activeForInstance = deps.store.getActiveByInstanceId(
5018
5034
  request.instanceId,
5019
5035
  );
5020
- if (activeForInstance) {
5036
+ if (activeForInstance && matchesWorkspace(activeForInstance.target)) {
5021
5037
  if (!activeForInstance.slot) {
5022
5038
  throw new Error("Telegram Workspace slot reservation is unavailable.");
5023
5039
  }
@@ -5055,7 +5071,7 @@ export function createTelegramTopicTargetProvisioner(
5055
5071
  getNextTelegramThreadNamePaletteSlot(deps.store.list(), undefined) ??
5056
5072
  request.preferredSlot;
5057
5073
  const slot =
5058
- existing?.slot ??
5074
+ (existing && matchesWorkspace(existing.target) ? existing.slot : undefined) ??
5059
5075
  deps.store.allocateSlot(
5060
5076
  request.profileKey,
5061
5077
  isManualFollowerRequest
@@ -5064,6 +5080,7 @@ export function createTelegramTopicTargetProvisioner(
5064
5080
  (candidateThreadName ? undefined : identity?.slot) ??
5065
5081
  preferredNameSlot),
5066
5082
  request.workspaceBindingKey,
5083
+ { excludeCurrentRecord: !!existing && !matchesWorkspace(existing.target) },
5067
5084
  );
5068
5085
  if (!slot) {
5069
5086
  throw new TelegramWorkspaceSlotUnavailableError();
@@ -5107,6 +5124,7 @@ export function createTelegramTopicTargetProvisioner(
5107
5124
  owner: pendingOwner,
5108
5125
  instanceId: request.instanceId,
5109
5126
  profileKey: request.profileKey,
5127
+ ...(request.workspaceBindingKey ? { workspaceBindingKey: request.workspaceBindingKey } : {}),
5110
5128
  threadName: requestThreadName,
5111
5129
  ...(displayTitle ? { displayTitle } : {}),
5112
5130
  slot,
@@ -884,6 +884,7 @@ export async function executeTelegramWorkspaceRetirement(input: {
884
884
  | "listWorkspaceRetirementIntents"
885
885
  | "commitWorkspaceRetirement"
886
886
  | "removeWorkspaceRetirementIntent"
887
+ | "markStaleByTarget"
887
888
  | "persist"
888
889
  >;
889
890
  admission: Pick<
@@ -971,6 +972,12 @@ export async function executeTelegramWorkspaceRetirement(input: {
971
972
  }
972
973
  return { kind: "retained", reason: "stale-intent" };
973
974
  }
975
+ if (fence?.phase === "commit-ready") {
976
+ // Exact confirmed absence retires any same-target routing record that
977
+ // survived the deletion attempt. The fence prevents replacement target
978
+ // publication while this stale local projection is removed.
979
+ input.store.markStaleByTarget(binding.target, "deleted");
980
+ }
974
981
  const eligible = () => input.store.captureWorkspaceSlotOccupancy(
975
982
  input.getExternalProtection,
976
983
  { expectedRetirement: input.intent },
@@ -1040,6 +1047,9 @@ export async function executeTelegramWorkspaceRetirement(input: {
1040
1047
  fence = input.admission.confirmRetirementAbsence(fence);
1041
1048
  }
1042
1049
  if (!isCurrent()) return { kind: "retained", reason: "authority-changed" };
1050
+ if (fence.phase === "commit-ready") {
1051
+ input.store.markStaleByTarget(binding.target, "deleted");
1052
+ }
1043
1053
  if (!eligible()) return { kind: "retained", reason: "protection-changed" };
1044
1054
  if (!await input.store.commitWorkspaceRetirement(input.intent, isCurrent)) {
1045
1055
  return { kind: "retained", reason: "commit-rejected" };
@@ -1212,7 +1222,7 @@ export type TelegramWorkspaceRetirementLifecycleResult =
1212
1222
  export async function runTelegramWorkspaceRetirementLifecycle(input: {
1213
1223
  store: TelegramWorkspaceRetirementPreparationDeps["store"] & Pick<
1214
1224
  TelegramTopicTargetStore,
1215
- "replaceWorkspaceRetirementIntent" | "commitWorkspaceRetirement"
1225
+ "replaceWorkspaceRetirementIntent" | "commitWorkspaceRetirement" | "markStaleByTarget"
1216
1226
  >;
1217
1227
  getExternalProtection: (
1218
1228
  binding: TelegramWorkspaceThreadBinding,
@@ -1257,19 +1267,42 @@ export async function runTelegramWorkspaceRetirementLifecycle(input: {
1257
1267
  });
1258
1268
  }
1259
1269
  if (intent) {
1260
- const adoption = await adoptTelegramWorkspaceRetirementIntent({
1261
- store: input.store,
1262
- intent,
1263
- getExternalProtection: input.getExternalProtection,
1264
- getLeaderEpoch: input.getLeaderEpoch,
1265
- getProfileKey: input.getProfileKey,
1266
- isCurrent: input.isCurrent,
1267
- runExclusive: input.runExclusive,
1268
- });
1269
- if (adoption.kind !== "adopted") {
1270
- return { kind: "blocked", stage: "adoption", reason: adoption.reason };
1270
+ if (retainedFence && isTelegramWorkspaceRetirementFence(retainedFence) &&
1271
+ retainedFence.phase === "commit-ready" &&
1272
+ matchesTelegramWorkspaceRetirementFence(retainedFence, intent)) {
1273
+ const resumed = await input.runExclusive(async () => {
1274
+ const epoch = input.getLeaderEpoch();
1275
+ const profileKey = input.getProfileKey();
1276
+ const isCurrent = () => epoch !== undefined && input.getLeaderEpoch() === epoch &&
1277
+ input.getProfileKey() === profileKey && input.isCurrent?.() !== false;
1278
+ if (!isCurrent() || intent!.profileKey !== profileKey) return undefined;
1279
+ const intents = input.store.listWorkspaceRetirementIntents();
1280
+ const binding = input.store.listWorkspaceBindings().find(candidate =>
1281
+ candidate.bindingKey === intent!.binding.bindingKey);
1282
+ if (intents.length !== 1 || !isDeepStrictEqual(intents[0], intent) ||
1283
+ !binding || !isDeepStrictEqual(binding, intent.binding)) return undefined;
1284
+ if (intent!.leaderEpoch === epoch) return intent;
1285
+ const replacement = { ...intent!, leaderEpoch: epoch! };
1286
+ return await input.store.replaceWorkspaceRetirementIntent(intent!, replacement, isCurrent)
1287
+ ? replacement : undefined;
1288
+ });
1289
+ if (!resumed) return { kind: "blocked", stage: "adoption", reason: "commit-rejected" };
1290
+ intent = resumed;
1291
+ } else {
1292
+ const adoption = await adoptTelegramWorkspaceRetirementIntent({
1293
+ store: input.store,
1294
+ intent,
1295
+ getExternalProtection: input.getExternalProtection,
1296
+ getLeaderEpoch: input.getLeaderEpoch,
1297
+ getProfileKey: input.getProfileKey,
1298
+ isCurrent: input.isCurrent,
1299
+ runExclusive: input.runExclusive,
1300
+ });
1301
+ if (adoption.kind !== "adopted") {
1302
+ return { kind: "blocked", stage: "adoption", reason: adoption.reason };
1303
+ }
1304
+ intent = adoption.intent;
1271
1305
  }
1272
- intent = adoption.intent;
1273
1306
  } else {
1274
1307
  const preparation = await prepareTelegramWorkspaceRetirement(
1275
1308
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-telegram",
3
- "version": "0.51.5",
3
+ "version": "0.51.6",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -0,0 +1,76 @@
1
+ 3.3.0 2022-06-24
2
+ =================
3
+ - `JSONVisitor.onObjectBegin` and `JSONVisitor.onArrayBegin` can now return `false` to instruct the visitor that no children should be visited.
4
+
5
+
6
+ 3.2.0 2022-08-30
7
+ =================
8
+ - update the version of the bundled Javascript files to `es2020`.
9
+ - include all `const enum` values in the bundled JavaScript files (`ScanError`, `SyntaxKind`, `ParseErrorCode`).
10
+
11
+ 3.1.0 2022-07-07
12
+ ==================
13
+ * added new API `FormattingOptions.keepLines` : It leaves the initial line positions in the formatting.
14
+
15
+ 3.0.0 2020-11-13
16
+ ==================
17
+ * fixed API spec for `parseTree`. Can return `undefine` for empty input.
18
+ * added new API `FormattingOptions.insertFinalNewline`.
19
+
20
+
21
+ 2.3.0 2020-07-03
22
+ ==================
23
+ * new API `ModificationOptions.isArrayInsertion`: If `JSONPath` refers to an index of an array and `isArrayInsertion` is `true`, then `modify` will insert a new item at that location instead of overwriting its contents.
24
+ * `ModificationOptions.formattingOptions` is now optional. If not set, newly inserted content will not be formatted.
25
+
26
+
27
+ 2.2.0 2019-10-25
28
+ ==================
29
+ * added `ParseOptions.allowEmptyContent`. Default is `false`.
30
+ * new API `getNodeType`: Returns the type of a value returned by parse.
31
+ * `parse`: Fix issue with empty property name
32
+
33
+ 2.1.0 2019-03-29
34
+ ==================
35
+ * `JSONScanner` and `JSONVisitor` return lineNumber / character.
36
+
37
+ 2.0.0 2018-04-12
38
+ ==================
39
+ * renamed `Node.columnOffset` to `Node.colonOffset`
40
+ * new API `getNodePath`: Gets the JSON path of the given JSON DOM node
41
+ * new API `findNodeAtOffset`: Finds the most inner node at the given offset. If `includeRightBound` is set, also finds nodes that end at the given offset.
42
+
43
+ 1.0.3 2018-03-07
44
+ ==================
45
+ * provide ems modules
46
+
47
+ 1.0.2 2018-03-05
48
+ ==================
49
+ * added the `visit.onComment` API, reported when comments are allowed.
50
+ * added the `ParseErrorCode.InvalidCommentToken` enum value, reported when comments are disallowed.
51
+
52
+ 1.0.1
53
+ ==================
54
+ * added the `format` API: computes edits to format a JSON document.
55
+ * added the `modify` API: computes edits to insert, remove or replace a property or value in a JSON document.
56
+ * added the `allyEdits` API: applies edits to a document
57
+
58
+ 1.0.0
59
+ ==================
60
+ * remove nls dependency (remove `getParseErrorMessage`)
61
+
62
+ 0.4.2 / 2017-05-05
63
+ ==================
64
+ * added `ParseError.offset` & `ParseError.length`
65
+
66
+ 0.4.1 / 2017-04-02
67
+ ==================
68
+ * added `ParseOptions.allowTrailingComma`
69
+
70
+ 0.4.0 / 2017-02-23
71
+ ==================
72
+ * fix for `getLocation`. Now `getLocation` inside an object will always return a property from inside that property. Can be empty string if the object has no properties or if the offset is before a actual property `{ "a": { | }} will return location ['a', ' ']`
73
+
74
+ 0.3.0 / 2017-01-17
75
+ ==================
76
+ * Updating to typescript 2.0
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) Microsoft
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.