@llblab/pi-kit 0.29.1 → 0.30.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.
- package/BACKLOG.md +3 -1
- package/CHANGELOG.md +10 -0
- package/README.md +4 -4
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +12 -0
- package/node_modules/@llblab/pi-state-flow/README.md +2 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +2 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +17 -8
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +7 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +2 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +3 -2
- package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +3 -3
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +3 -2
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +17 -8
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +6 -3
- package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +4 -2
- package/node_modules/@llblab/pi-state-flow/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +13 -10
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -1
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +23 -0
- package/node_modules/@llblab/pi-telegram/README.md +10 -11
- package/node_modules/@llblab/pi-telegram/api/commands.ts +3 -0
- package/node_modules/@llblab/pi-telegram/dist/api/commands.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +1 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +15 -42
- package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +9 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +39 -10
- package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.js +7 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +43 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +164 -20
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.d.ts +12 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +181 -77
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +111 -31
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +1324 -359
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +41 -91
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +969 -637
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +16 -9
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +215 -18
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +1048 -327
- package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +5 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +434 -261
- package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +26 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +92 -176
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +168 -82
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +1409 -291
- package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +1 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/config.js +34 -76
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +16 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +642 -170
- package/node_modules/@llblab/pi-telegram/dist/lib/generative-app-worker.mjs +19 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +0 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.js +61 -49
- package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +5 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +35 -59
- package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +40 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +2102 -760
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +2 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +75 -58
- package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +34 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +318 -119
- package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +50 -14
- package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +22 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/media.js +46 -28
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +19 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +53 -11
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.d.ts +5 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.js +45 -63
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +5 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +114 -78
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +8 -25
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +6 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +14 -21
- package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +8 -61
- package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +92 -164
- package/node_modules/@llblab/pi-telegram/dist/lib/model.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/model.js +2 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +6 -27
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +45 -38
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +22 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +0 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +51 -64
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.js +6 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +6 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +61 -51
- package/node_modules/@llblab/pi-telegram/dist/lib/ownership.js +6 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +5 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +37 -21
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +8 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +23 -37
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +71 -52
- package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +39 -19
- package/node_modules/@llblab/pi-telegram/dist/lib/process-identity.d.ts +24 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/process-identity.js +133 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/prompts.js +2 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +16 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +261 -116
- package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +2 -83
- package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +20 -274
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +16 -24
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +99 -116
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +121 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +4750 -1161
- package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +1 -11
- package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +4 -29
- package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +7 -20
- package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +4 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/status.js +86 -57
- package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +6 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +112 -45
- package/node_modules/@llblab/pi-telegram/dist/lib/target.d.ts +4 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/target.js +18 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +18 -11
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +165 -49
- package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.js +4 -39
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +6 -27
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +369 -186
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +1 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +58 -38
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +28 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +175 -66
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +42 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +90 -50
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +88 -24
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +2276 -842
- package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.js +1 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +1 -19
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +178 -82
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +2438 -645
- package/node_modules/@llblab/pi-telegram/dist/lib/voice.d.ts +7 -22
- package/node_modules/@llblab/pi-telegram/dist/lib/voice.js +7 -22
- package/node_modules/@llblab/pi-telegram/dist/lib/wire.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +3 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +425 -211
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.js +8 -13
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +328 -140
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.js +8 -4
- package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +43 -35
- package/node_modules/@llblab/pi-telegram/docs/inbound.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +15 -3
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +29 -1
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +25 -8
- package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +59 -82
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +146 -102
- package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +12 -5
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +390 -82
- package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +262 -99
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +2440 -601
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +2209 -1290
- package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +46 -12
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +1673 -444
- package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +848 -327
- package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +152 -265
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +2398 -555
- package/node_modules/@llblab/pi-telegram/lib/config.ts +177 -170
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +41 -29
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +1209 -431
- package/node_modules/@llblab/pi-telegram/lib/generative-app-worker.mjs +19 -7
- package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +324 -211
- package/node_modules/@llblab/pi-telegram/lib/inbound.ts +95 -97
- package/node_modules/@llblab/pi-telegram/lib/journal.ts +5329 -1712
- package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +1 -3
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +128 -78
- package/node_modules/@llblab/pi-telegram/lib/locks.ts +703 -212
- package/node_modules/@llblab/pi-telegram/lib/logging.ts +147 -58
- package/node_modules/@llblab/pi-telegram/lib/media.ts +82 -43
- package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +85 -18
- package/node_modules/@llblab/pi-telegram/lib/menu-queue.ts +88 -129
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +260 -155
- package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +20 -60
- package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +41 -56
- package/node_modules/@llblab/pi-telegram/lib/menu.ts +112 -285
- package/node_modules/@llblab/pi-telegram/lib/model.ts +8 -22
- package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +156 -125
- package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +76 -49
- package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +96 -94
- package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +33 -27
- package/node_modules/@llblab/pi-telegram/lib/outbound.ts +125 -125
- package/node_modules/@llblab/pi-telegram/lib/ownership.ts +19 -10
- package/node_modules/@llblab/pi-telegram/lib/paths.ts +148 -49
- package/node_modules/@llblab/pi-telegram/lib/pi.ts +35 -15
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +165 -149
- package/node_modules/@llblab/pi-telegram/lib/preview.ts +93 -40
- package/node_modules/@llblab/pi-telegram/lib/process-identity.ts +164 -0
- package/node_modules/@llblab/pi-telegram/lib/prompts.ts +4 -11
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +523 -289
- package/node_modules/@llblab/pi-telegram/lib/recovery.ts +50 -454
- package/node_modules/@llblab/pi-telegram/lib/rendering.ts +1 -3
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +248 -209
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +8527 -2149
- package/node_modules/@llblab/pi-telegram/lib/runtime.ts +1 -12
- package/node_modules/@llblab/pi-telegram/lib/sections.ts +24 -89
- package/node_modules/@llblab/pi-telegram/lib/setup.ts +1 -3
- package/node_modules/@llblab/pi-telegram/lib/skills.ts +9 -4
- package/node_modules/@llblab/pi-telegram/lib/status.ts +215 -110
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +488 -359
- package/node_modules/@llblab/pi-telegram/lib/target.ts +22 -3
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +322 -122
- package/node_modules/@llblab/pi-telegram/lib/text-groups.ts +5 -39
- package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +833 -331
- package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +213 -97
- package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +232 -87
- package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +155 -72
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +5329 -1817
- package/node_modules/@llblab/pi-telegram/lib/time-injection.ts +1 -4
- package/node_modules/@llblab/pi-telegram/lib/turns.ts +15 -28
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +5194 -1600
- package/node_modules/@llblab/pi-telegram/lib/voice.ts +7 -35
- package/node_modules/@llblab/pi-telegram/lib/wire.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +996 -416
- package/node_modules/@llblab/pi-telegram/lib/workspace-identity.ts +14 -17
- package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +878 -376
- package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +22 -13
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/package.json +3 -3
- package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +0 -472
- package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +0 -108
|
@@ -8,7 +8,8 @@ const DEFAULT_FRESH_CREATION_GRACE_MS = 30_000;
|
|
|
8
8
|
function targetKey(target) {
|
|
9
9
|
return `${target.chatId}:${target.threadId}`;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
/** A Thread record still claims its slot/target while active, starting or pending. */
|
|
12
|
+
export function isCurrentThreadRecord(record) {
|
|
12
13
|
return (record.status === "active" ||
|
|
13
14
|
record.status === "starting" ||
|
|
14
15
|
record.status === "pending");
|
|
@@ -50,13 +51,12 @@ function isCleanupAction(action) {
|
|
|
50
51
|
action.kind === "close-stale-replaced-topic" ||
|
|
51
52
|
action.kind === "close-delete-replaced-follower-topic" ||
|
|
52
53
|
action.kind === "close-delete-previous-leader-topic" ||
|
|
53
|
-
action.kind === "close-delete-disconnected-instance-topic" ||
|
|
54
54
|
action.kind === "close-delete-graceful-shutdown-topic" ||
|
|
55
55
|
action.kind === "cancel-superseded-graceful-shutdown-cleanup" ||
|
|
56
56
|
action.kind === "close-delete-expired-pending-provision-topic");
|
|
57
57
|
}
|
|
58
58
|
function isSyncAction(action) {
|
|
59
|
-
return action.kind === "mark-topic-active" || action.kind === "mark-topic-stale";
|
|
59
|
+
return (action.kind === "mark-topic-active" || action.kind === "mark-topic-stale");
|
|
60
60
|
}
|
|
61
61
|
function createThreadReconciliationMachineState(input, actions) {
|
|
62
62
|
const pendingProvisionCount = (input.pendingProvisions ?? []).filter((provision) => isPendingProvisionAlive(provision, input.nowMs, input.currentLeaderEpoch)).length;
|
|
@@ -101,26 +101,34 @@ function createThreadReconciliationTransition(previous, current) {
|
|
|
101
101
|
function getActionLeaderEpoch(action) {
|
|
102
102
|
return "leaderEpoch" in action ? action.leaderEpoch : undefined;
|
|
103
103
|
}
|
|
104
|
+
/** Pure Bot API vocabulary for a deleted/missing Thread; callers own their HTTP-status policy. */
|
|
105
|
+
export function isTelegramTopicDeletedErrorMessage(message) {
|
|
106
|
+
const text = message.toLowerCase();
|
|
107
|
+
return [
|
|
108
|
+
"topic_id_invalid",
|
|
109
|
+
"message thread not found",
|
|
110
|
+
"thread not found",
|
|
111
|
+
"topic not found",
|
|
112
|
+
"topic deleted",
|
|
113
|
+
].some((fragment) => text.includes(fragment));
|
|
114
|
+
}
|
|
115
|
+
/** Pure Bot API vocabulary for a closed Thread; closure is not deletion evidence. */
|
|
116
|
+
export function isTelegramTopicClosedErrorMessage(message) {
|
|
117
|
+
const text = message.toLowerCase();
|
|
118
|
+
return [
|
|
119
|
+
"topic closed",
|
|
120
|
+
"thread closed",
|
|
121
|
+
"forum topic closed",
|
|
122
|
+
"message thread closed",
|
|
123
|
+
].some((fragment) => text.includes(fragment));
|
|
124
|
+
}
|
|
104
125
|
function isTelegramTopicTargetDeletedOrMissingError(error) {
|
|
105
|
-
|
|
106
|
-
return false;
|
|
107
|
-
const message = error.message.toLowerCase();
|
|
108
|
-
return (message.includes("topic_id_invalid") ||
|
|
109
|
-
message.includes("message thread not found") ||
|
|
110
|
-
message.includes("thread not found") ||
|
|
111
|
-
message.includes("topic not found") ||
|
|
112
|
-
message.includes("topic deleted"));
|
|
126
|
+
return (error instanceof Error && isTelegramTopicDeletedErrorMessage(error.message));
|
|
113
127
|
}
|
|
114
128
|
function isTelegramTopicTargetGoneError(error) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return false;
|
|
119
|
-
const message = error.message.toLowerCase();
|
|
120
|
-
return (message.includes("topic closed") ||
|
|
121
|
-
message.includes("thread closed") ||
|
|
122
|
-
message.includes("forum topic closed") ||
|
|
123
|
-
message.includes("message thread closed"));
|
|
129
|
+
return (error instanceof Error &&
|
|
130
|
+
(isTelegramTopicDeletedErrorMessage(error.message) ||
|
|
131
|
+
isTelegramTopicClosedErrorMessage(error.message)));
|
|
124
132
|
}
|
|
125
133
|
function shouldSkipForStaleLeaderEpoch(action, ports) {
|
|
126
134
|
const actionLeaderEpoch = getActionLeaderEpoch(action);
|
|
@@ -178,21 +186,58 @@ export function createThreadReconciliationRuntime(deps) {
|
|
|
178
186
|
},
|
|
179
187
|
};
|
|
180
188
|
}
|
|
181
|
-
export function
|
|
189
|
+
export function prepareLiveRebindThreadCleanup(input) {
|
|
190
|
+
const { operationId, oldTarget, recipientTarget, leaderEpoch, work } = input;
|
|
191
|
+
const validTarget = (target) => Number.isSafeInteger(target?.chatId) &&
|
|
192
|
+
target.chatId !== 0 &&
|
|
193
|
+
Number.isSafeInteger(target.threadId) &&
|
|
194
|
+
target.threadId > 0;
|
|
195
|
+
if (!operationId?.trim() ||
|
|
196
|
+
!leaderEpoch?.trim() ||
|
|
197
|
+
!validTarget(oldTarget) ||
|
|
198
|
+
!validTarget(recipientTarget) ||
|
|
199
|
+
oldTarget.chatId !== recipientTarget.chatId ||
|
|
200
|
+
oldTarget.threadId === recipientTarget.threadId ||
|
|
201
|
+
input.targetProtected !== false ||
|
|
202
|
+
work?.sessionBusy !== false ||
|
|
203
|
+
work.targetWork !== false ||
|
|
204
|
+
work.deliveryPending !== false ||
|
|
205
|
+
work.unknown !== false)
|
|
206
|
+
return undefined;
|
|
182
207
|
return {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
instanceId: input.instanceId,
|
|
189
|
-
...(input.leaderEpoch !== undefined
|
|
190
|
-
? { leaderEpoch: input.leaderEpoch }
|
|
191
|
-
: {}),
|
|
192
|
-
},
|
|
193
|
-
],
|
|
208
|
+
status: "prepared",
|
|
209
|
+
operationId,
|
|
210
|
+
target: { ...oldTarget },
|
|
211
|
+
recipientTarget: { ...recipientTarget },
|
|
212
|
+
leaderEpoch,
|
|
194
213
|
};
|
|
195
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* One unretried deletion for an already issued live-rebind cleanup grant. Success or confirmed absence is `confirmed`;
|
|
217
|
+
* protection or authority loss before the request and a definite request rejection are `failed`; every other outcome is
|
|
218
|
+
* `unknown`. The caller owns the durable issue marker and terminal record; this never repeats or rolls back.
|
|
219
|
+
*/
|
|
220
|
+
export async function issueLiveRebindThreadCleanup(prepared, ports) {
|
|
221
|
+
const target = { ...prepared.target };
|
|
222
|
+
try {
|
|
223
|
+
ports.assertCurrent();
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return "failed";
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
await ports.deleteTopic(target);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
const failure = ports.classifyFailure(error);
|
|
233
|
+
return failure === "absent"
|
|
234
|
+
? "confirmed"
|
|
235
|
+
: failure === "rejected"
|
|
236
|
+
? "failed"
|
|
237
|
+
: "unknown";
|
|
238
|
+
}
|
|
239
|
+
return "confirmed";
|
|
240
|
+
}
|
|
196
241
|
export async function applyThreadReconciliationPlan(plan, ports) {
|
|
197
242
|
let shouldPersist = false;
|
|
198
243
|
const persistFences = [];
|
|
@@ -276,7 +321,6 @@ export async function applyThreadReconciliationPlan(plan, ports) {
|
|
|
276
321
|
action.kind === "close-delete-reserved-topic" ||
|
|
277
322
|
action.kind === "close-delete-replaced-follower-topic" ||
|
|
278
323
|
action.kind === "close-delete-previous-leader-topic" ||
|
|
279
|
-
action.kind === "close-delete-disconnected-instance-topic" ||
|
|
280
324
|
action.kind === "close-delete-graceful-shutdown-topic" ||
|
|
281
325
|
action.kind === "close-delete-expired-pending-provision-topic") {
|
|
282
326
|
if (shouldSkipForStaleLeaderEpoch(action, ports)) {
|
|
@@ -295,7 +339,9 @@ export async function applyThreadReconciliationPlan(plan, ports) {
|
|
|
295
339
|
}
|
|
296
340
|
let deleteConfirmed = false;
|
|
297
341
|
let superseded = false;
|
|
298
|
-
for (const method of ports.skipCloseBeforeDelete
|
|
342
|
+
for (const method of ports.skipCloseBeforeDelete
|
|
343
|
+
? ["deleteForumTopic"]
|
|
344
|
+
: ["closeForumTopic", "deleteForumTopic"]) {
|
|
299
345
|
if (ports.isCleanupTargetProtected?.(action.target, action)) {
|
|
300
346
|
superseded = true;
|
|
301
347
|
break;
|
|
@@ -331,7 +377,8 @@ export async function applyThreadReconciliationPlan(plan, ports) {
|
|
|
331
377
|
incompleteActions.push(action);
|
|
332
378
|
continue;
|
|
333
379
|
}
|
|
334
|
-
if (superseded ||
|
|
380
|
+
if (superseded ||
|
|
381
|
+
ports.isCleanupTargetProtected?.(action.target, action)) {
|
|
335
382
|
ports.recordRuntimeEvent?.("telegram", "Cancelled cleanup of a protected Telegram target", {
|
|
336
383
|
phase: "thread-reconciler-cleanup-target-reused",
|
|
337
384
|
action: action.kind,
|
|
@@ -356,7 +403,6 @@ export async function applyThreadReconciliationPlan(plan, ports) {
|
|
|
356
403
|
continue;
|
|
357
404
|
if (action.kind !== "close-delete-previous-leader-topic" &&
|
|
358
405
|
action.kind !== "close-delete-replaced-follower-topic" &&
|
|
359
|
-
action.kind !== "close-delete-disconnected-instance-topic" &&
|
|
360
406
|
action.kind !== "close-delete-expired-pending-provision-topic") {
|
|
361
407
|
const changed = ports.markStaleByTarget?.(action.target, "deleted") ?? false;
|
|
362
408
|
if (changed)
|
|
@@ -371,11 +417,9 @@ export async function applyThreadReconciliationPlan(plan, ports) {
|
|
|
371
417
|
? "Replaced follower Telegram topic deleted"
|
|
372
418
|
: action.kind === "close-delete-previous-leader-topic"
|
|
373
419
|
? "Previous leader Telegram topic deleted"
|
|
374
|
-
: action.kind === "close-delete-
|
|
375
|
-
? "
|
|
376
|
-
:
|
|
377
|
-
? "Graceful shutdown Telegram topic deleted"
|
|
378
|
-
: "Expired pending provision Telegram topic deleted", {
|
|
420
|
+
: action.kind === "close-delete-graceful-shutdown-topic"
|
|
421
|
+
? "Graceful shutdown Telegram topic deleted"
|
|
422
|
+
: "Expired pending provision Telegram topic deleted", {
|
|
379
423
|
phase: action.kind === "close-delete-unbound-topic"
|
|
380
424
|
? "thread-reconciler-unbound-topic-delete"
|
|
381
425
|
: action.kind === "close-delete-reserved-topic"
|
|
@@ -384,13 +428,9 @@ export async function applyThreadReconciliationPlan(plan, ports) {
|
|
|
384
428
|
? "thread-reconciler-replaced-follower-topic-delete"
|
|
385
429
|
: action.kind === "close-delete-previous-leader-topic"
|
|
386
430
|
? "thread-reconciler-previous-leader-topic-delete"
|
|
387
|
-
: action.kind ===
|
|
388
|
-
"
|
|
389
|
-
|
|
390
|
-
: action.kind ===
|
|
391
|
-
"close-delete-graceful-shutdown-topic"
|
|
392
|
-
? "thread-reconciler-graceful-shutdown-topic-delete"
|
|
393
|
-
: "thread-reconciler-expired-pending-provision-topic-delete",
|
|
431
|
+
: action.kind === "close-delete-graceful-shutdown-topic"
|
|
432
|
+
? "thread-reconciler-graceful-shutdown-topic-delete"
|
|
433
|
+
: "thread-reconciler-expired-pending-provision-topic-delete",
|
|
394
434
|
chatId: action.target.chatId,
|
|
395
435
|
threadId: action.target.threadId,
|
|
396
436
|
...("messageId" in action ? { messageId: action.messageId } : {}),
|
|
@@ -436,7 +476,7 @@ export function planThreadReconciliation(input) {
|
|
|
436
476
|
const graceMs = input.freshCreationGraceMs ?? DEFAULT_FRESH_CREATION_GRACE_MS;
|
|
437
477
|
const knownTargets = new Set(input.records.map((record) => targetKey(record.target)));
|
|
438
478
|
const currentTargets = new Set(input.records
|
|
439
|
-
.filter(
|
|
479
|
+
.filter(isCurrentThreadRecord)
|
|
440
480
|
.map((record) => targetKey(record.target)));
|
|
441
481
|
const reservedTargets = new Set((input.reservations ?? [])
|
|
442
482
|
.filter((reservation) => isReservationAlive(reservation, input.nowMs))
|
|
@@ -449,7 +489,7 @@ export function planThreadReconciliation(input) {
|
|
|
449
489
|
.map((observation) => targetKey(observation.target)));
|
|
450
490
|
const actions = [];
|
|
451
491
|
for (const cleanup of input.pendingCleanups ?? []) {
|
|
452
|
-
const superseded = input.records.some((record) =>
|
|
492
|
+
const superseded = input.records.some((record) => isCurrentThreadRecord(record) &&
|
|
453
493
|
targetKey(record.target) === targetKey(cleanup.target) &&
|
|
454
494
|
record.instanceId !== cleanup.instanceId);
|
|
455
495
|
const common = {
|
|
@@ -3,15 +3,13 @@
|
|
|
3
3
|
* Zones: multi-instance bus, Telegram UI threads, durable Workspace state
|
|
4
4
|
* Owns live mappings, Workspace bindings and guarded Restore transitions; routing and transport effects stay outside.
|
|
5
5
|
*/
|
|
6
|
-
import { type TelegramApiCallOptions } from "./telegram-api.ts";
|
|
7
6
|
import { type TelegramTarget } from "./target.ts";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import { type TelegramWorkspaceBindingIdentity } from "./workspace-identity.ts";
|
|
11
|
-
export { createTelegramWorkspaceBindingIdentity, createTelegramWorkspaceDirectoryKey, normalizeTelegramSessionId, normalizeTelegramWorkspacePath, type TelegramWorkspaceBindingIdentity, } from "./workspace-identity.ts";
|
|
12
|
-
import { type TelegramLockRuntime, type TelegramLockContext, type TelegramRuntimeStateMutation, type TelegramOwnedStatePublicationOptions, type TelegramOwnedStatePublicationResult } from "./locks.ts";
|
|
7
|
+
import { type TelegramApiCallOptions } from "./telegram-api.ts";
|
|
8
|
+
import { type TelegramLockContext, type TelegramLockRuntime, type TelegramOwnedStatePublicationOptions, type TelegramOwnedStatePublicationResult, type TelegramRuntimeStateMutation } from "./locks.ts";
|
|
13
9
|
import * as ThreadReconciler from "./thread-reconciler.ts";
|
|
10
|
+
import { type TelegramWorkspaceBindingIdentity } from "./workspace-identity.ts";
|
|
14
11
|
import { type TelegramWorkspaceSlotOccupancy } from "./workspace-slots.ts";
|
|
12
|
+
export { createTelegramWorkspaceBindingIdentity, createTelegramWorkspaceDirectoryKey, normalizeTelegramSessionId, normalizeTelegramWorkspacePath, type TelegramWorkspaceBindingIdentity, } from "./workspace-identity.ts";
|
|
15
13
|
export type TelegramTopicTargetStatus = "active" | "offline" | "stale" | "pending" | "starting" | "probe-required" | "failed";
|
|
16
14
|
export type TelegramTopicSyncStatus = "open" | "closed" | "deleted" | "unknown";
|
|
17
15
|
export type TelegramThreadOwner = {
|
|
@@ -247,12 +245,26 @@ export interface TelegramWorkspaceRestoreIntent {
|
|
|
247
245
|
cleanup?: "issued" | "completed" | "not-issued";
|
|
248
246
|
};
|
|
249
247
|
}
|
|
248
|
+
/** Live same-session metadata, never a legacy scoped ACK or permission to dispatch/delete. */
|
|
249
|
+
export type TelegramWorkspaceLiveRebindIntent = Pick<TelegramWorkspaceRestoreIntent, "request" | "operatorUserId" | "executor" | "revision" | "createdAtMs" | "updatedAtMs"> & {
|
|
250
|
+
kind: "live-rebind";
|
|
251
|
+
recipient: TelegramWorkspaceRestoreRecipient;
|
|
252
|
+
} & ({
|
|
253
|
+
phase: "rebound";
|
|
254
|
+
cleanup?: never;
|
|
255
|
+
} | {
|
|
256
|
+
phase: "released";
|
|
257
|
+
cleanup?: "issued";
|
|
258
|
+
} | {
|
|
259
|
+
phase: "finished";
|
|
260
|
+
cleanup: "confirmed" | "failed" | "unknown" | "not-issued";
|
|
261
|
+
});
|
|
250
262
|
/** Immutable source membership, not readiness, cancellation, or proof of complete Thread coverage. */
|
|
251
263
|
export interface TelegramTemporaryThreadInput {
|
|
252
264
|
journalBindingKey: string;
|
|
253
265
|
updateIds: number[];
|
|
254
266
|
}
|
|
255
|
-
/**
|
|
267
|
+
/** Journal-owned donor discard evidence: retained manual cancellation or body-free chooser expiry, never recipient cancellation. */
|
|
256
268
|
export interface TelegramTemporaryThreadCancellationEvidence {
|
|
257
269
|
journalBindingKey: string;
|
|
258
270
|
updateId: number;
|
|
@@ -266,7 +278,7 @@ export interface TelegramTemporaryThreadEntry {
|
|
|
266
278
|
};
|
|
267
279
|
/** Append-only known source groups. Missing legacy metadata never proves that the creation source was alone. */
|
|
268
280
|
inputs?: TelegramTemporaryThreadInput[];
|
|
269
|
-
/** Whole known groups with positively observed cancellation; never
|
|
281
|
+
/** Whole known groups with positively observed donor cancellation or expiry; never recipient cancellation or deletion authority. */
|
|
270
282
|
cancelledInputs?: TelegramTemporaryThreadInput[];
|
|
271
283
|
/** Whole known groups whose Forward was positively completed by the journal owner; never deletion authority alone. */
|
|
272
284
|
completedInputs?: TelegramTemporaryThreadInput[];
|
|
@@ -304,11 +316,19 @@ interface TelegramWorkspaceRestoreSnapshot {
|
|
|
304
316
|
tokenSha256: string;
|
|
305
317
|
revision: number;
|
|
306
318
|
operations: TelegramWorkspaceRestoreIntent[];
|
|
319
|
+
liveRebindings?: TelegramWorkspaceLiveRebindIntent[];
|
|
307
320
|
temporaryThreads?: TelegramTemporaryThreadEntry[];
|
|
308
321
|
}
|
|
309
322
|
/** Scope-bound Workspace operations; raw snapshot mutation is private to the store. */
|
|
310
323
|
export interface TelegramWorkspaceRestore {
|
|
311
324
|
list(): TelegramWorkspaceRestoreIntent[];
|
|
325
|
+
listLiveRebindings(): TelegramWorkspaceLiveRebindIntent[];
|
|
326
|
+
/** Caller has saved and held the selected input; this publishes the binding, not dispatch readiness. */
|
|
327
|
+
commitLiveRebind(request: TelegramWorkspaceRestoreRequest, recipient: TelegramWorkspaceRestoreRecipient, authority: TelegramWorkspaceRestoreAuthority): Promise<TelegramWorkspaceLiveRebindIntent | undefined>;
|
|
328
|
+
/** Caller proves local apply for release or current live clearance for cleanup; unknown issuance never repeats. */
|
|
329
|
+
advanceLiveRebind(expected: TelegramWorkspaceLiveRebindIntent, step: "release" | "issue-cleanup" | Extract<TelegramWorkspaceLiveRebindIntent, {
|
|
330
|
+
phase: "finished";
|
|
331
|
+
}>["cleanup"], authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceLiveRebindIntent | undefined;
|
|
312
332
|
commit(request: TelegramWorkspaceRestoreRequest, authority: TelegramWorkspaceRestoreAuthority): Promise<TelegramWorkspaceRestoreIntent | undefined>;
|
|
313
333
|
adopt(expected: TelegramWorkspaceRestoreIntent, authority: TelegramWorkspaceRestoreAuthority): TelegramWorkspaceRestoreIntent | undefined;
|
|
314
334
|
issueRecipient(expected: TelegramWorkspaceRestoreIntent, recipient: TelegramWorkspaceRestoreRecipient, authority: TelegramWorkspaceRestoreAuthority): {
|
|
@@ -361,6 +381,8 @@ export interface TelegramWorkspaceRestore {
|
|
|
361
381
|
recordTemporaryThreadForwardIssued(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
|
|
362
382
|
recordTemporaryThreadInputCompletion(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority): TelegramTemporaryThreadEntry | undefined;
|
|
363
383
|
recordTemporaryThreadInputCancellation(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority, inspect: (updateId: number) => TelegramTemporaryThreadCancellationEvidence | undefined): TelegramTemporaryThreadEntry | undefined;
|
|
384
|
+
/** Body-free chooser expiry may terminate an uncertain donor Forward/Restore, never accepted recipient work or a bound target. */
|
|
385
|
+
recordTemporaryThreadInputExpiry(expected: TelegramTemporaryThreadEntry, input: TelegramTemporaryThreadInput, authority: TelegramWorkspaceRestoreAuthority, inspect: (updateId: number) => TelegramTemporaryThreadCancellationEvidence | undefined): TelegramTemporaryThreadEntry | undefined;
|
|
364
386
|
/** Caller holds profile admission and proves fresh source/protection clearance; publication grants one attempt, never retry. */
|
|
365
387
|
issueTemporaryThreadCleanup(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority): {
|
|
366
388
|
issued: true;
|
|
@@ -370,10 +392,11 @@ export interface TelegramWorkspaceRestore {
|
|
|
370
392
|
/** `completed` names one newly completed group; every other known group must already be cancelled or completed. */
|
|
371
393
|
retireTemporaryThread(expected: TelegramTemporaryThreadEntry, authority: TelegramWorkspaceRestoreAuthority, completed?: TelegramTemporaryThreadInput): TelegramTemporaryThreadEntry | undefined;
|
|
372
394
|
/** New-world restart: atomically forgets this operator's Restore intents and temporary entries from previous runtime instances.
|
|
373
|
-
* Committed bindings stay; nothing is rolled back, replayed or deleted here. */
|
|
374
|
-
forgetPreviousWorld(authority: TelegramWorkspaceRestoreAuthority): {
|
|
395
|
+
* Caller may preserve exact unbound temporary tokens for clock-bearing sources. Committed bindings stay; nothing is rolled back, replayed or deleted here. */
|
|
396
|
+
forgetPreviousWorld(authority: TelegramWorkspaceRestoreAuthority, preserveTemporaryTokens?: readonly string[]): {
|
|
375
397
|
operations: TelegramWorkspaceRestoreIntent[];
|
|
376
398
|
temporaryThreads: TelegramTemporaryThreadEntry[];
|
|
399
|
+
liveRebindings?: TelegramWorkspaceLiveRebindIntent[];
|
|
377
400
|
} | undefined;
|
|
378
401
|
}
|
|
379
402
|
export interface TelegramWorkspaceRestoreOptions {
|
|
@@ -424,7 +447,8 @@ export interface TelegramTopicTargetStore {
|
|
|
424
447
|
load: () => Promise<void>;
|
|
425
448
|
/** Discard process-local projections and reload owner-published state. */
|
|
426
449
|
refresh?: () => Promise<void>;
|
|
427
|
-
|
|
450
|
+
/** Optional caller fence supplements, never replaces, captured publication authority. */
|
|
451
|
+
persist: (isCurrent?: () => boolean) => Promise<void>;
|
|
428
452
|
invalidateTarget: (target: TelegramTarget, isCurrent: () => boolean, lastSyncError: string) => Promise<boolean>;
|
|
429
453
|
/** Caller proves owner detachment; this does not assert Telegram Thread absence. */
|
|
430
454
|
detachTargetOwner: (expected: TelegramTopicTargetRecord, isCurrent: () => boolean) => Promise<boolean>;
|
|
@@ -439,7 +463,18 @@ export interface TelegramTopicTargetStore {
|
|
|
439
463
|
/** Runs synchronous live publication under the same evidence transaction; caller retains authentication/admission. */
|
|
440
464
|
commitWorkspaceRestoreRegistration: (candidate: Parameters<TelegramTopicTargetStore["assertWorkspaceRestoreRegistration"]>[0], publish: () => void) => void;
|
|
441
465
|
/** Read-only canonical observation; the callback must finish synchronously under the snapshot transaction. */
|
|
442
|
-
withWorkspaceRestoreSnapshot: (expected: TelegramWorkspaceRestoreIntent, observe: (snapshot: Readonly<Pick<TelegramTopicTargetFile, "threads" | "workspaceBindings">>) => undefined) => void;
|
|
466
|
+
withWorkspaceRestoreSnapshot: (expected: TelegramWorkspaceRestoreIntent | TelegramWorkspaceLiveRebindIntent, observe: (snapshot: Readonly<Pick<TelegramTopicTargetFile, "threads" | "workspaceBindings">>) => undefined) => void;
|
|
467
|
+
/** Exact synchronous live-operation snapshot, including a current publication frame; no mutation, lock or authority grant. */
|
|
468
|
+
withWorkspaceLiveRebindSnapshot: (expected: TelegramWorkspaceLiveRebindIntent, observe: (snapshot: Readonly<Pick<TelegramTopicTargetFile, "threads" | "workspaceBindings">>) => undefined) => void;
|
|
469
|
+
/** Current live-origin ownership veto; effect callers still require Workspace admission. False is not work/recipient/deletion authority. */
|
|
470
|
+
isWorkspaceLiveRebindCleanupTargetProtected: (expected: TelegramWorkspaceLiveRebindIntent) => boolean;
|
|
471
|
+
/** Read-only captured identity with an optional exact manual-name result fence; no transport/session/admission grant or lock. */
|
|
472
|
+
captureWorkspaceThreadRenameObservation: (binding: TelegramWorkspaceThreadBinding, owner: TelegramTopicTargetRecord) => (expectedManualThreadName?: string) => boolean;
|
|
473
|
+
/** Captured read-only identity and exact absent-manual-name/automatic-title result fences; no authority grant or lock. */
|
|
474
|
+
captureWorkspaceThreadResetObservation: (binding: TelegramWorkspaceThreadBinding, owner: TelegramTopicTargetRecord) => {
|
|
475
|
+
isCurrent: () => boolean;
|
|
476
|
+
isResultCurrent: (automaticTitle: string) => boolean;
|
|
477
|
+
};
|
|
443
478
|
/** Fresh strict disk read of acknowledged temporary-tab targets; throws rather than guessing absence. */
|
|
444
479
|
listTemporaryThreadTargets: () => TelegramTarget[];
|
|
445
480
|
list: () => TelegramTopicTargetRecord[];
|
|
@@ -524,14 +559,19 @@ export interface TelegramTopicTargetStore {
|
|
|
524
559
|
renameByTarget: (target: TelegramTarget, threadName: string, options?: {
|
|
525
560
|
updateDisplayTitle: boolean;
|
|
526
561
|
}) => TelegramTopicTargetRecord | undefined;
|
|
562
|
+
/** Publish a manual-name candidate without first retaining it in the dirty local projection. */
|
|
563
|
+
renameByTargetAndPersist: (target: TelegramTarget, threadName: string, options: {
|
|
564
|
+
updateDisplayTitle: boolean;
|
|
565
|
+
}, isCurrent: () => boolean) => Promise<TelegramTopicTargetRecord | undefined>;
|
|
527
566
|
clearManualNameByTarget: (target: TelegramTarget, automaticTitle: string) => TelegramTopicTargetRecord | undefined;
|
|
567
|
+
/** Stage exact manual-name removal and automatic display metadata in the existing publication candidate. */
|
|
568
|
+
clearManualNameByTargetAndPersist: (target: TelegramTarget, automaticTitle: string, isCurrent: () => boolean) => Promise<TelegramTopicTargetRecord | undefined>;
|
|
528
569
|
allocateSlot: (profileKey: string, preferredSlot?: string, workspaceBindingKey?: string, options?: {
|
|
529
570
|
excludeCurrentRecord?: boolean;
|
|
530
571
|
}) => string | undefined;
|
|
531
572
|
/** Claim the first reusable inactive thread for an instance, linking it to instanceId. */
|
|
532
573
|
claimReusableTarget: (instanceId: string, threadName?: string) => TelegramTopicTargetRecord | undefined;
|
|
533
574
|
}
|
|
534
|
-
export declare function reconcileTelegramFreshAllocationCursor(store: Pick<TelegramTopicTargetStore, "getBotState" | "list" | "setBotState">, nowMs?: number): boolean;
|
|
535
575
|
export declare function createTelegramCleanupTargetProtection(store: Pick<TelegramTopicTargetStore, "list"> & Partial<Pick<TelegramTopicTargetStore, "listReservations" | "listPendingProvisions" | "listPendingCleanups" | "listTemporaryThreadTargets">>, departingRecord?: TelegramTopicTargetRecord): NonNullable<ThreadReconciler.ThreadReconciliationApplyPorts["isCleanupTargetProtected"]>;
|
|
536
576
|
export interface TelegramTopicTargetStoreOptions {
|
|
537
577
|
path: string | (() => string);
|
|
@@ -554,8 +594,10 @@ export interface TelegramTopicTargetProvisionerDeps {
|
|
|
554
594
|
claimPendingTargets?: boolean;
|
|
555
595
|
}
|
|
556
596
|
export interface TelegramTopicTargetRenamerDeps {
|
|
557
|
-
store: Pick<TelegramTopicTargetStore, "
|
|
558
|
-
|
|
597
|
+
store: Pick<TelegramTopicTargetStore, "list" | "listWorkspaceBindings" | "listPendingProvisions"> & {
|
|
598
|
+
renameByTarget: (...args: Parameters<TelegramTopicTargetStore["renameByTarget"]>) => ReturnType<TelegramTopicTargetStore["renameByTarget"]> | Promise<ReturnType<TelegramTopicTargetStore["renameByTarget"]>>;
|
|
599
|
+
};
|
|
600
|
+
callApi: <TResponse>(method: string, body: Record<string, unknown>, options?: TelegramApiCallOptions) => Promise<TResponse>;
|
|
559
601
|
assertAuthority?: () => void;
|
|
560
602
|
shouldRenameDisplayedTitle?: () => boolean;
|
|
561
603
|
topicNameTemplate?: string;
|
|
@@ -595,8 +637,6 @@ export interface TelegramTopicTargetProvisionResult {
|
|
|
595
637
|
record: TelegramTopicTargetRecord;
|
|
596
638
|
displayTitle?: string;
|
|
597
639
|
}
|
|
598
|
-
export declare function getTelegramStatePath(agentDir?: string, profileName?: string): string;
|
|
599
|
-
export declare function getTelegramTopicTargetsPath(agentDir?: string, profileName?: string): string;
|
|
600
640
|
export declare const TELEGRAM_LEADER_SESSION_HANDOFF_TTL_MS = 30000;
|
|
601
641
|
export interface TelegramLeaderSessionHandoff {
|
|
602
642
|
pid: number;
|
|
@@ -703,6 +743,37 @@ export declare function resolveTelegramInstanceThreadIdentity(options: {
|
|
|
703
743
|
leader?: TelegramInstanceThreadIdentityCandidate;
|
|
704
744
|
record?: TelegramTopicTargetRecord;
|
|
705
745
|
}): TelegramInstanceThreadIdentityCandidate;
|
|
746
|
+
export interface TelegramWorkspaceThreadRenameAuthority {
|
|
747
|
+
context: unknown;
|
|
748
|
+
sessionId?: string;
|
|
749
|
+
sessionGeneration: number;
|
|
750
|
+
cwd?: string;
|
|
751
|
+
profileName?: string;
|
|
752
|
+
botToken?: string;
|
|
753
|
+
operatorUserId?: number;
|
|
754
|
+
leaderEpoch?: string | number;
|
|
755
|
+
ownsDirectDelivery: boolean;
|
|
756
|
+
followerRegistered: boolean;
|
|
757
|
+
localTarget?: TelegramTarget;
|
|
758
|
+
localSlot?: string;
|
|
759
|
+
}
|
|
760
|
+
interface TelegramWorkspaceThreadNameRecipientDeps {
|
|
761
|
+
store: TelegramTopicTargetStore;
|
|
762
|
+
instanceId: string;
|
|
763
|
+
target: TelegramTarget;
|
|
764
|
+
assertAuthority: () => void;
|
|
765
|
+
getAuthority: () => TelegramWorkspaceThreadRenameAuthority;
|
|
766
|
+
}
|
|
767
|
+
/** Prepared recipient identity/result fences; callers retain Workspace admission and transport effects. */
|
|
768
|
+
export declare function createTelegramWorkspaceThreadRenameRecipient(deps: TelegramWorkspaceThreadNameRecipientDeps): {
|
|
769
|
+
assertAuthority: () => void;
|
|
770
|
+
assertResult: (result: TelegramTopicTargetRecord) => void;
|
|
771
|
+
};
|
|
772
|
+
/** Exact automatic-title/absent-name result fences, separate from recipient identity and issued effects. */
|
|
773
|
+
export declare function createTelegramWorkspaceThreadResetRecipient(deps: TelegramWorkspaceThreadNameRecipientDeps): {
|
|
774
|
+
assertAuthority: () => void;
|
|
775
|
+
assertResult: (automaticTitle: string) => void;
|
|
776
|
+
};
|
|
706
777
|
export interface TelegramLeaderThreadStateRuntime {
|
|
707
778
|
getTarget(): TelegramTarget | undefined;
|
|
708
779
|
getIdentity(): TelegramInstanceThreadIdentityCandidate | undefined;
|
|
@@ -733,13 +804,6 @@ export declare function findCurrentTelegramInstanceThreadRecord(options: {
|
|
|
733
804
|
instanceId: string;
|
|
734
805
|
preferredTarget?: TelegramTarget;
|
|
735
806
|
}): TelegramTopicTargetRecord | undefined;
|
|
736
|
-
export declare function resolveTelegramInstanceThreadTarget(options: {
|
|
737
|
-
followerTarget?: TelegramTarget;
|
|
738
|
-
leaderTarget?: TelegramTarget;
|
|
739
|
-
currentRecord?: TelegramTopicTargetRecord;
|
|
740
|
-
}): (TelegramTarget & {
|
|
741
|
-
threadId: number;
|
|
742
|
-
}) | undefined;
|
|
743
807
|
export interface TelegramThreadStatusProjectionRuntime {
|
|
744
808
|
getBusRole(): "leader" | "follower" | undefined;
|
|
745
809
|
getBusFollowers(): ReturnType<typeof listTelegramThreadStatusFollowers>;
|