@llblab/pi-telegram 0.51.4 → 0.51.6
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.
- package/AGENTS.md +1 -1
- package/BACKLOG.md +1 -0
- package/CHANGELOG.md +15 -0
- package/README.md +1 -1
- package/dist/lib/bindings.d.ts +4 -1
- package/dist/lib/bindings.js +16 -12
- package/dist/lib/bus-follower.d.ts +3 -1
- package/dist/lib/bus-follower.js +62 -3
- package/dist/lib/bus-leader.d.ts +21 -0
- package/dist/lib/bus-leader.js +144 -1
- package/dist/lib/bus.d.ts +9 -0
- package/dist/lib/bus.js +19 -0
- package/dist/lib/commands.d.ts +25 -3
- package/dist/lib/commands.js +166 -89
- package/dist/lib/extension.js +42 -0
- package/dist/lib/lifecycle.d.ts +57 -2
- package/dist/lib/lifecycle.js +109 -4
- package/dist/lib/locks.js +5 -1
- package/dist/lib/model.js +2 -4
- package/dist/lib/polling.js +6 -2
- package/dist/lib/status.d.ts +3 -1
- package/dist/lib/status.js +31 -1
- package/dist/lib/sync.js +4 -4
- package/dist/lib/threads.d.ts +8 -0
- package/dist/lib/threads.js +30 -9
- package/dist/lib/workspace-retirement.d.ts +2 -2
- package/dist/lib/workspace-retirement.js +48 -12
- package/dist/package.json +1 -1
- package/docs/architecture.md +6 -5
- package/docs/multi-instance-bus.md +4 -2
- package/docs/public-api.md +3 -3
- package/docs/ui-style.md +4 -0
- package/lib/bindings.ts +17 -10
- package/lib/bus-follower.ts +87 -3
- package/lib/bus-leader.ts +197 -0
- package/lib/bus.ts +33 -0
- package/lib/commands.ts +173 -103
- package/lib/extension.ts +40 -0
- package/lib/lifecycle.ts +140 -4
- package/lib/locks.ts +6 -1
- package/lib/model.ts +2 -4
- package/lib/polling.ts +10 -2
- package/lib/status.ts +30 -1
- package/lib/sync.ts +4 -4
- package/lib/threads.ts +40 -8
- package/lib/workspace-retirement.ts +46 -13
- package/package.json +1 -1
package/lib/polling.ts
CHANGED
|
@@ -1180,8 +1180,16 @@ export function createTelegramThreadAwarePollingPorts<TContext, TOwner>(
|
|
|
1180
1180
|
ctx: TContext,
|
|
1181
1181
|
owner: TOwner,
|
|
1182
1182
|
): Promise<boolean | undefined> => {
|
|
1183
|
-
if (!(await refreshFollowerState()))
|
|
1184
|
-
|
|
1183
|
+
if (!(await refreshFollowerState())) {
|
|
1184
|
+
deps.recordEvent("bus", "Telegram follower auto-connect skipped: Threaded Mode is not enabled.",
|
|
1185
|
+
{ phase: "follower-auto-connect-skip", reason: "thread-mode-unavailable" });
|
|
1186
|
+
return undefined;
|
|
1187
|
+
}
|
|
1188
|
+
if (!deps.hasRememberedWorkspaceBinding?.(ctx)) {
|
|
1189
|
+
deps.recordEvent("bus", "Telegram follower auto-connect skipped: no binding for this session.",
|
|
1190
|
+
{ phase: "follower-auto-connect-skip", reason: "session-binding-unavailable" });
|
|
1191
|
+
return undefined;
|
|
1192
|
+
}
|
|
1185
1193
|
return deps.restoreFollowerWithLeader?.(ctx, owner);
|
|
1186
1194
|
};
|
|
1187
1195
|
return {
|
package/lib/status.ts
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Telegram status rendering helpers
|
|
3
3
|
* Zones: telegram ui, pi agent diagnostics, tui
|
|
4
|
-
*
|
|
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";
|
package/lib/sync.ts
CHANGED
|
@@ -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
|
-
//
|
|
889
|
-
//
|
|
890
|
-
|
|
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",
|
package/lib/threads.ts
CHANGED
|
@@ -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;
|
|
@@ -371,6 +372,12 @@ export interface TelegramSessionReplacementIntent {
|
|
|
371
372
|
threadName?: string;
|
|
372
373
|
createdAtMs: number;
|
|
373
374
|
expiresAtMs: number;
|
|
375
|
+
/**
|
|
376
|
+
* Present only when the leader published the intent for a registered
|
|
377
|
+
* follower. Successor re-key and settlement must come from this exact
|
|
378
|
+
* follower runtime or its authenticated same-process session handoff.
|
|
379
|
+
*/
|
|
380
|
+
sourceInstanceId?: string;
|
|
374
381
|
}
|
|
375
382
|
|
|
376
383
|
export interface TelegramTopicTargetFile {
|
|
@@ -1329,7 +1336,7 @@ function cloneSessionReplacementIntent(
|
|
|
1329
1336
|
return { ...intent, target: { ...intent.target } };
|
|
1330
1337
|
}
|
|
1331
1338
|
|
|
1332
|
-
function
|
|
1339
|
+
export function normalizeTelegramSessionReplacementIntent(
|
|
1333
1340
|
value: unknown,
|
|
1334
1341
|
): TelegramSessionReplacementIntent | undefined {
|
|
1335
1342
|
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
@@ -1346,7 +1353,10 @@ function normalizeSessionReplacementIntent(
|
|
|
1346
1353
|
typeof record.messageId !== "number" || !Number.isSafeInteger(record.messageId) ||
|
|
1347
1354
|
typeof record.createdAtMs !== "number" || !Number.isSafeInteger(record.createdAtMs) ||
|
|
1348
1355
|
typeof record.expiresAtMs !== "number" || !Number.isSafeInteger(record.expiresAtMs) ||
|
|
1349
|
-
record.expiresAtMs <= record.createdAtMs
|
|
1356
|
+
record.expiresAtMs <= record.createdAtMs ||
|
|
1357
|
+
(record.sourceInstanceId !== undefined &&
|
|
1358
|
+
(typeof record.sourceInstanceId !== "string" || !record.sourceInstanceId ||
|
|
1359
|
+
record.sourceInstanceId.length > 256))
|
|
1350
1360
|
) return undefined;
|
|
1351
1361
|
const continuity = record.continuity === "workspace-thread" ||
|
|
1352
1362
|
record.continuity === "classic-chat"
|
|
@@ -1370,6 +1380,8 @@ function normalizeSessionReplacementIntent(
|
|
|
1370
1380
|
...(typeof record.threadName === "string" ? { threadName: record.threadName } : {}),
|
|
1371
1381
|
createdAtMs: record.createdAtMs,
|
|
1372
1382
|
expiresAtMs: record.expiresAtMs,
|
|
1383
|
+
...(typeof record.sourceInstanceId === "string"
|
|
1384
|
+
? { sourceInstanceId: record.sourceInstanceId } : {}),
|
|
1373
1385
|
};
|
|
1374
1386
|
}
|
|
1375
1387
|
|
|
@@ -1517,6 +1529,9 @@ function normalizePendingProvision(
|
|
|
1517
1529
|
...(record.status === "in-flight" || record.status === "ambiguous"
|
|
1518
1530
|
? { status: record.status }
|
|
1519
1531
|
: {}),
|
|
1532
|
+
...(typeof record.workspaceBindingKey === "string"
|
|
1533
|
+
? { workspaceBindingKey: record.workspaceBindingKey }
|
|
1534
|
+
: {}),
|
|
1520
1535
|
...(typeof record.threadName === "string"
|
|
1521
1536
|
? { threadName: record.threadName }
|
|
1522
1537
|
: {}),
|
|
@@ -1680,7 +1695,7 @@ function parseTopicTargetFile(value: unknown): TelegramTopicTargetFile {
|
|
|
1680
1695
|
return normalized ? [normalized] : [];
|
|
1681
1696
|
})
|
|
1682
1697
|
: [],
|
|
1683
|
-
sessionReplacement:
|
|
1698
|
+
sessionReplacement: normalizeTelegramSessionReplacementIntent(file.sessionReplacement),
|
|
1684
1699
|
reservations: Array.isArray(file.reservations)
|
|
1685
1700
|
? file.reservations.flatMap((reservation) => {
|
|
1686
1701
|
const normalized = normalizeReservation(reservation);
|
|
@@ -2510,7 +2525,7 @@ export function createTelegramTopicTargetStore(
|
|
|
2510
2525
|
: undefined;
|
|
2511
2526
|
},
|
|
2512
2527
|
async commitSessionReplacementIntent(intent, isCurrent) {
|
|
2513
|
-
const next =
|
|
2528
|
+
const next = normalizeTelegramSessionReplacementIntent(intent);
|
|
2514
2529
|
if (!next || !isCurrent()) return false;
|
|
2515
2530
|
await loadFromDisk();
|
|
2516
2531
|
if (!isCurrent()) return false;
|
|
@@ -2925,7 +2940,10 @@ export function createTelegramTopicTargetStore(
|
|
|
2925
2940
|
replacement.expiresAtMs > getNowMs() &&
|
|
2926
2941
|
replacement.profileName === (getTelegramProfile() ?? "default") &&
|
|
2927
2942
|
replacement.cwd === normalizedCwd &&
|
|
2928
|
-
replacement.sourceSessionId !== normalizedSessionId
|
|
2943
|
+
replacement.sourceSessionId !== normalizedSessionId &&
|
|
2944
|
+
(replacement.sourceInstanceId === undefined ||
|
|
2945
|
+
replacement.sourceInstanceId === instanceId ||
|
|
2946
|
+
replacement.sourceInstanceId === previousInstanceId)
|
|
2929
2947
|
) {
|
|
2930
2948
|
const sourceEntry = Array.from(workspaceBindings.entries()).find(([, binding]) =>
|
|
2931
2949
|
binding.cwd === normalizedCwd &&
|
|
@@ -4905,6 +4923,13 @@ export function createTelegramTopicTargetProvisioner(
|
|
|
4905
4923
|
pending.profileKey === request.profileKey ||
|
|
4906
4924
|
pending.instanceId === request.instanceId,
|
|
4907
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
|
+
}
|
|
4908
4933
|
if (pendingForRequest?.target) {
|
|
4909
4934
|
const target = pendingForRequest.target;
|
|
4910
4935
|
const observation = deps.store.listSyncObservations().find((entry) =>
|
|
@@ -4919,8 +4944,13 @@ export function createTelegramTopicTargetProvisioner(
|
|
|
4919
4944
|
pendingForRequest = undefined;
|
|
4920
4945
|
}
|
|
4921
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));
|
|
4922
4952
|
const existing = deps.store.getByProfileKey(request.profileKey);
|
|
4923
|
-
if (existing && isCurrentThreadRecord(existing)) {
|
|
4953
|
+
if (existing && isCurrentThreadRecord(existing) && matchesWorkspace(existing.target)) {
|
|
4924
4954
|
const slot = existing.slot ?? deps.store.allocateSlot(request.profileKey);
|
|
4925
4955
|
if (!slot) {
|
|
4926
4956
|
throw new TelegramWorkspaceSlotUnavailableError();
|
|
@@ -5003,7 +5033,7 @@ export function createTelegramTopicTargetProvisioner(
|
|
|
5003
5033
|
const activeForInstance = deps.store.getActiveByInstanceId(
|
|
5004
5034
|
request.instanceId,
|
|
5005
5035
|
);
|
|
5006
|
-
if (activeForInstance) {
|
|
5036
|
+
if (activeForInstance && matchesWorkspace(activeForInstance.target)) {
|
|
5007
5037
|
if (!activeForInstance.slot) {
|
|
5008
5038
|
throw new Error("Telegram Workspace slot reservation is unavailable.");
|
|
5009
5039
|
}
|
|
@@ -5041,7 +5071,7 @@ export function createTelegramTopicTargetProvisioner(
|
|
|
5041
5071
|
getNextTelegramThreadNamePaletteSlot(deps.store.list(), undefined) ??
|
|
5042
5072
|
request.preferredSlot;
|
|
5043
5073
|
const slot =
|
|
5044
|
-
existing
|
|
5074
|
+
(existing && matchesWorkspace(existing.target) ? existing.slot : undefined) ??
|
|
5045
5075
|
deps.store.allocateSlot(
|
|
5046
5076
|
request.profileKey,
|
|
5047
5077
|
isManualFollowerRequest
|
|
@@ -5050,6 +5080,7 @@ export function createTelegramTopicTargetProvisioner(
|
|
|
5050
5080
|
(candidateThreadName ? undefined : identity?.slot) ??
|
|
5051
5081
|
preferredNameSlot),
|
|
5052
5082
|
request.workspaceBindingKey,
|
|
5083
|
+
{ excludeCurrentRecord: !!existing && !matchesWorkspace(existing.target) },
|
|
5053
5084
|
);
|
|
5054
5085
|
if (!slot) {
|
|
5055
5086
|
throw new TelegramWorkspaceSlotUnavailableError();
|
|
@@ -5093,6 +5124,7 @@ export function createTelegramTopicTargetProvisioner(
|
|
|
5093
5124
|
owner: pendingOwner,
|
|
5094
5125
|
instanceId: request.instanceId,
|
|
5095
5126
|
profileKey: request.profileKey,
|
|
5127
|
+
...(request.workspaceBindingKey ? { workspaceBindingKey: request.workspaceBindingKey } : {}),
|
|
5096
5128
|
threadName: requestThreadName,
|
|
5097
5129
|
...(displayTitle ? { displayTitle } : {}),
|
|
5098
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
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
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
|
{
|