@llblab/pi-kit 0.27.5 → 0.28.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 +9 -0
- package/README.md +4 -4
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +6 -2
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +4 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.js +4 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +26 -13
- package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +3 -1
- package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +2 -2
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +2 -1
- package/node_modules/@llblab/pi-state-flow/lib/compaction.ts +4 -3
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +25 -12
- package/node_modules/@llblab/pi-state-flow/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +10 -8
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -9
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +13 -0
- package/node_modules/@llblab/pi-telegram/LICENSE +21 -0
- package/node_modules/@llblab/pi-telegram/README.md +15 -5
- 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 +5 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +5 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +6 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +4 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +54 -56
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +206 -139
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +21 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +181 -25
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.d.ts +4 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +28 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +52 -56
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +78 -246
- package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +1 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +23 -26
- package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +0 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +5 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +0 -23
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +15 -15
- package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +0 -17
- package/node_modules/@llblab/pi-telegram/dist/lib/config.js +12 -14
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +0 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +2 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +255 -61
- package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +0 -19
- package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +0 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +177 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +1115 -249
- package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.d.ts +0 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.js +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +100 -12
- package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +380 -14
- package/node_modules/@llblab/pi-telegram/dist/lib/logging.d.ts +30 -12
- package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +129 -72
- package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +28 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/media.js +26 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +0 -11
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +8 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +0 -18
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +18 -18
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +4 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +12 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +4 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +0 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +1 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +1 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +4 -21
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +0 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +5 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +50 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +155 -17
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +2 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +0 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +5 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/preview.d.ts +0 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +3 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.d.ts +0 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +3 -15
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +69 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +29 -9
- package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +104 -33
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +0 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +73 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +2206 -307
- package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +0 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +44 -9
- package/node_modules/@llblab/pi-telegram/dist/lib/status.js +149 -27
- package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +0 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +5 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +11 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +34 -23
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +18 -21
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +32 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +191 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +291 -59
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +1647 -369
- package/node_modules/@llblab/pi-telegram/dist/lib/turns.d.ts +0 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +184 -28
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +1032 -114
- package/node_modules/@llblab/pi-telegram/dist/lib/wire.d.ts +12 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/wire.js +21 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +25 -17
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +95 -20
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.d.ts +20 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.js +103 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +43 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +148 -52
- package/node_modules/@llblab/pi-telegram/dist/package.json +6 -6
- package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/SKILL.md +3 -3
- package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/diagnosis.md +3 -3
- package/node_modules/@llblab/pi-telegram/docs/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/activity.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +152 -34
- package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/delivery.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/inbound.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +125 -19
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +3 -1
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +22 -8
- package/node_modules/@llblab/pi-telegram/docs/updates.md +1 -1
- package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +5 -9
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +6 -0
- package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +5 -2
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +243 -224
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +178 -31
- package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +30 -8
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +110 -334
- package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +29 -29
- package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +5 -5
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +15 -15
- package/node_modules/@llblab/pi-telegram/lib/config.ts +12 -17
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +2 -8
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +257 -72
- package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +0 -22
- package/node_modules/@llblab/pi-telegram/lib/inbound.ts +2 -2
- package/node_modules/@llblab/pi-telegram/lib/journal.ts +1182 -326
- package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +2 -2
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/locks.ts +402 -23
- package/node_modules/@llblab/pi-telegram/lib/logging.ts +151 -101
- package/node_modules/@llblab/pi-telegram/lib/media.ts +51 -9
- package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +8 -8
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +18 -18
- package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +11 -0
- package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +2 -2
- package/node_modules/@llblab/pi-telegram/lib/menu.ts +5 -1
- package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +1 -10
- package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +5 -24
- package/node_modules/@llblab/pi-telegram/lib/outbound.ts +5 -5
- package/node_modules/@llblab/pi-telegram/lib/paths.ts +177 -17
- package/node_modules/@llblab/pi-telegram/lib/pi.ts +5 -2
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +5 -5
- package/node_modules/@llblab/pi-telegram/lib/preview.ts +3 -3
- package/node_modules/@llblab/pi-telegram/lib/prompt-templates.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +67 -9
- package/node_modules/@llblab/pi-telegram/lib/recovery.ts +104 -44
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +1955 -375
- package/node_modules/@llblab/pi-telegram/lib/sections.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/status.ts +156 -36
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +4 -4
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +48 -33
- package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +24 -21
- package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +267 -9
- package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +3 -1
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +1697 -488
- package/node_modules/@llblab/pi-telegram/lib/turns.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +1072 -151
- package/node_modules/@llblab/pi-telegram/lib/wire.ts +28 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +97 -47
- package/node_modules/@llblab/pi-telegram/lib/workspace-identity.ts +147 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +188 -89
- package/node_modules/@llblab/pi-telegram/package.json +6 -6
- package/node_modules/@llblab/pi-telegram/scripts/audit-exports.mjs +100 -0
- package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +80 -43
- package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/SKILL.md +3 -3
- package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/diagnosis.md +3 -3
- package/package.json +3 -3
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
* Owns leader-only runtime orchestration: follower registration envelopes, follower API proxying,
|
|
5
5
|
* leader activation hot-switching, local bus server startup, and stale follower pruning.
|
|
6
6
|
*/
|
|
7
|
+
import { isDeepStrictEqual } from "node:util";
|
|
7
8
|
import * as Sync from "./sync.js";
|
|
8
9
|
import { createTelegramThreadDisplayReconciler, resolveTelegramInitialWorkspaceDisplayName, resolveTelegramLiveWorkspaceBindingKeys, } from "./thread-display.js";
|
|
10
|
+
import * as ThreadNaming from "./thread-naming.js";
|
|
9
11
|
import * as ThreadReconciler from "./thread-reconciler.js";
|
|
10
12
|
import { getTelegramApiErrorRequestTarget, isTelegramApiCommitUnknownError, } from "./telegram-api.js";
|
|
11
13
|
import * as Threads from "./threads.js";
|
|
12
|
-
import
|
|
14
|
+
import * as WorkspaceIdentity from "./workspace-identity.js";
|
|
15
|
+
import { createTelegramBusLocalServer, createUnauthorizedBusAck, getTelegramBusEnvelopeTrafficClass, getTelegramBusProtocolCompatibility, hasTelegramBusCapability, isTelegramBusEnvelopeAuthorized, getTelegramBusFollowerSocketPath, sendTelegramBusLocalEnvelope, stripTelegramBusApiMetadata, TELEGRAM_BUS_CAPABILITY_DURABLE_FOLLOWER_ADMISSION, TELEGRAM_BUS_CAPABILITY_QUEUE_HANDOFF, TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE, TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME, TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE, TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT, TELEGRAM_BUS_CAPABILITY_SESSION_REPLACEMENT_INTENT, } from "./bus.js";
|
|
13
16
|
import { getTelegramBusTransportRetryPolicy } from "./bus-transport.js";
|
|
14
17
|
import { createTelegramWorkspaceOperationRuntime, createTelegramWorkspaceSlotRotation, } from "./workspace-retirement.js";
|
|
15
18
|
import { createTelegramWorkspaceAdmissionOperationId, runWithTelegramWorkspaceAdmissionsAsync, } from "./workspace-admission.js";
|
|
@@ -39,10 +42,10 @@ export function createTelegramBusFollowerSessionReplacementAuthority(deps) {
|
|
|
39
42
|
const ttlMs = deps.ttlMs ?? Threads.TELEGRAM_LEADER_SESSION_HANDOFF_TTL_MS;
|
|
40
43
|
const assertCommon = (follower, intent) => {
|
|
41
44
|
const cwd = follower.cwd
|
|
42
|
-
?
|
|
45
|
+
? WorkspaceIdentity.normalizeTelegramWorkspacePath(follower.cwd)
|
|
43
46
|
: undefined;
|
|
44
47
|
const sessionId = follower.sessionId
|
|
45
|
-
?
|
|
48
|
+
? WorkspaceIdentity.normalizeTelegramSessionId(follower.sessionId)
|
|
46
49
|
: undefined;
|
|
47
50
|
const nowMs = getNowMs();
|
|
48
51
|
if (intent.continuity !== "workspace-thread" ||
|
|
@@ -324,7 +327,7 @@ export function createTelegramBusLeaderRuntimeAssembly(deps) {
|
|
|
324
327
|
slot: record.slot,
|
|
325
328
|
});
|
|
326
329
|
if (!renamed) {
|
|
327
|
-
throw new Error(
|
|
330
|
+
throw new Error(ThreadNaming.getTelegramTopicThreadNameValidationError(threadName, record.slot) ?? "Telegram Workspace Thread name is already reserved.");
|
|
328
331
|
}
|
|
329
332
|
await deps.topicTargetStore.persist();
|
|
330
333
|
return renamed;
|
|
@@ -474,7 +477,7 @@ export function createTelegramBusLeaderRuntimeAssembly(deps) {
|
|
|
474
477
|
throw new Error("Telegram Workspace Thread rename lost leader ownership.");
|
|
475
478
|
}
|
|
476
479
|
if (!renamed) {
|
|
477
|
-
throw new Error(
|
|
480
|
+
throw new Error(ThreadNaming.getTelegramTopicThreadNameValidationError(threadName, follower.slot) ?? "Telegram Workspace Thread name is already reserved.");
|
|
478
481
|
}
|
|
479
482
|
await deps.topicTargetStore.persist();
|
|
480
483
|
return { threadName: renamed.manualThreadName ?? threadName };
|
|
@@ -559,8 +562,26 @@ export function createTelegramBusLeaderRuntimeAssembly(deps) {
|
|
|
559
562
|
operationKind: "workspace.provision-follower",
|
|
560
563
|
scopes: [{ kind: "profile" }],
|
|
561
564
|
}, () => provisionFollowerTarget(registration, options)),
|
|
565
|
+
commitFollowerRegistration: (input, publish) => runWorkspaceOperation({
|
|
566
|
+
operationId: createTelegramWorkspaceAdmissionOperationId(),
|
|
567
|
+
operationKind: "workspace.publish-follower-registration", scopes: [{ kind: "profile" }],
|
|
568
|
+
}, async () => {
|
|
569
|
+
if (!input.target) {
|
|
570
|
+
publish();
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
await deps.topicTargetStore.load();
|
|
574
|
+
const binding = input.registration.cwd && input.registration.sessionId
|
|
575
|
+
? deps.topicTargetStore.getWorkspaceBindingByTarget(input.target, input.registration.sessionId) : undefined;
|
|
576
|
+
const bindingKey = binding && input.registration.cwd && binding.cwd === WorkspaceIdentity.normalizeTelegramWorkspacePath(input.registration.cwd)
|
|
577
|
+
? binding.bindingKey : undefined;
|
|
578
|
+
if (input.target.threadId !== undefined && input.registration.cwd && input.registration.sessionId && !bindingKey)
|
|
579
|
+
throw new Error("Telegram follower Workspace binding changed before registration publication.");
|
|
580
|
+
deps.topicTargetStore.commitWorkspaceRestoreRegistration({ target: input.target, slot: input.slot, bindingKey }, publish);
|
|
581
|
+
}),
|
|
562
582
|
getCurrentLeaderEpoch: deps.getCurrentLeaderEpoch,
|
|
563
583
|
getTelegramProfile: deps.getTelegramProfile,
|
|
584
|
+
getAllowedUserId: deps.getAllowedUserId,
|
|
564
585
|
runWorkspaceAdmission,
|
|
565
586
|
runWithWorkspaceCapacity,
|
|
566
587
|
callApi: createTelegramBusLeaderApiProxy({
|
|
@@ -751,10 +772,10 @@ export function createTelegramBusFollowerTargetProvisioner(deps) {
|
|
|
751
772
|
const nowMs = getNowMs();
|
|
752
773
|
const carriedThreadName = workspaceBinding?.threadName ?? registration.threadName;
|
|
753
774
|
const requestedThreadName = carriedThreadName &&
|
|
754
|
-
|
|
775
|
+
ThreadNaming.isTelegramTopicThreadNameValidForSlot(carriedThreadName, registration.slot)
|
|
755
776
|
? carriedThreadName
|
|
756
777
|
: recoveryHint?.threadName &&
|
|
757
|
-
|
|
778
|
+
ThreadNaming.isTelegramTopicThreadNameValidForSlot(recoveryHint.threadName, recoveryHint.slot)
|
|
758
779
|
? recoveryHint.threadName
|
|
759
780
|
: undefined;
|
|
760
781
|
const requestedSlot = workspaceIdentity?.slot ?? workspaceBinding?.slot ?? registration.slot ?? recoveryHint?.slot;
|
|
@@ -790,6 +811,11 @@ export function createTelegramBusFollowerTargetProvisioner(deps) {
|
|
|
790
811
|
};
|
|
791
812
|
};
|
|
792
813
|
const runRegistration = async () => {
|
|
814
|
+
if (requestedTarget)
|
|
815
|
+
deps.topicTargetStore.assertWorkspaceRestoreRegistration({
|
|
816
|
+
target: requestedTarget, bindingKey: workspaceIdentity?.bindingKey,
|
|
817
|
+
slot: workspaceIdentity?.slot ?? workspaceBinding?.slot ?? registration.slot,
|
|
818
|
+
});
|
|
793
819
|
const recoveryTarget = reconnectRecord?.target ?? recoverableTarget;
|
|
794
820
|
if (recoveryTarget) {
|
|
795
821
|
Threads.assertTelegramPendingTopicRecoveryAllowed(deps.topicTargetStore, recoveryTarget);
|
|
@@ -824,6 +850,10 @@ export function createTelegramBusFollowerTargetProvisioner(deps) {
|
|
|
824
850
|
};
|
|
825
851
|
};
|
|
826
852
|
alignResultWithWorkspaceSlot();
|
|
853
|
+
const assertRestoreRegistration = () => deps.topicTargetStore.assertWorkspaceRestoreRegistration({
|
|
854
|
+
target: result.target, slot: result.record.slot, bindingKey: workspaceIdentity?.bindingKey,
|
|
855
|
+
});
|
|
856
|
+
assertRestoreRegistration();
|
|
827
857
|
const crossSessionReuse = !!reconnectRecord &&
|
|
828
858
|
reconnectRecord.instanceId !== registration.instanceId;
|
|
829
859
|
if (reconnectRecord && !crossSessionReuse) {
|
|
@@ -864,6 +894,7 @@ export function createTelegramBusFollowerTargetProvisioner(deps) {
|
|
|
864
894
|
: undefined;
|
|
865
895
|
if (requiresVisibilityProbe && connectedAnnouncement) {
|
|
866
896
|
try {
|
|
897
|
+
assertRestoreRegistration();
|
|
867
898
|
await deps.callApi(exactSessionHandoff ? "sendChatAction" : "sendMessage", exactSessionHandoff
|
|
868
899
|
? {
|
|
869
900
|
chat_id: connectedAnnouncement.target.chatId,
|
|
@@ -876,6 +907,7 @@ export function createTelegramBusFollowerTargetProvisioner(deps) {
|
|
|
876
907
|
text: connectedAnnouncement.text,
|
|
877
908
|
parse_mode: connectedAnnouncement.parseMode,
|
|
878
909
|
});
|
|
910
|
+
assertRestoreRegistration();
|
|
879
911
|
if (recoverableTarget || probeRequiredRecord) {
|
|
880
912
|
const activatedRecord = deps.topicTargetStore.upsert({
|
|
881
913
|
...result.record,
|
|
@@ -929,6 +961,8 @@ export function createTelegramBusFollowerTargetProvisioner(deps) {
|
|
|
929
961
|
connectedAnnouncement = undefined;
|
|
930
962
|
}
|
|
931
963
|
catch (error) {
|
|
964
|
+
// Restore protection failures are not evidence that a Telegram topic is missing.
|
|
965
|
+
assertRestoreRegistration();
|
|
932
966
|
if (Threads.isTelegramTopicTargetStaleError(error)) {
|
|
933
967
|
deps.topicTargetStore.markStaleByTarget(result.target, "deleted", error instanceof Error ? error.message : String(error));
|
|
934
968
|
await deps.topicTargetStore.persist();
|
|
@@ -976,7 +1010,10 @@ export function createTelegramBusFollowerTargetProvisioner(deps) {
|
|
|
976
1010
|
? { threadName: result.record.threadName }
|
|
977
1011
|
: {}),
|
|
978
1012
|
slot: workspaceIdentity.slot,
|
|
979
|
-
|
|
1013
|
+
...(workspaceIdentity.sessionId
|
|
1014
|
+
? { journalSources: [{ sessionId: workspaceIdentity.sessionId, recipientBindingKey: followerProfileKey }],
|
|
1015
|
+
journalBindingKeys: [] }
|
|
1016
|
+
: { journalBindingKeys: [followerProfileKey] }),
|
|
980
1017
|
journalBindingsComplete: true,
|
|
981
1018
|
updatedAtMs: getNowMs(),
|
|
982
1019
|
},
|
|
@@ -990,6 +1027,7 @@ export function createTelegramBusFollowerTargetProvisioner(deps) {
|
|
|
990
1027
|
deps.topicTargetStore.markWorkspaceBindingActiveByTarget(result.target);
|
|
991
1028
|
await deps.topicTargetStore.persist();
|
|
992
1029
|
}
|
|
1030
|
+
assertRestoreRegistration();
|
|
993
1031
|
deps.setSyncState(Sync.markTelegramSyncSliceFresh(deps.getSyncState(), "target-bindings", {
|
|
994
1032
|
nowMs: getNowMs(),
|
|
995
1033
|
action: "follower-register",
|
|
@@ -1183,7 +1221,7 @@ export function createTelegramBusLeaderTargetProvisioner(deps) {
|
|
|
1183
1221
|
await deps.topicTargetStore.load();
|
|
1184
1222
|
const cwd = deps.getCwd?.(ctx);
|
|
1185
1223
|
const normalizedCwd = cwd
|
|
1186
|
-
?
|
|
1224
|
+
? WorkspaceIdentity.normalizeTelegramWorkspacePath(cwd)
|
|
1187
1225
|
: undefined;
|
|
1188
1226
|
const profileKey = Threads.getTelegramThreadOwnerKey({
|
|
1189
1227
|
kind: "leader",
|
|
@@ -1319,6 +1357,26 @@ export function createTelegramBusLeaderTargetProvisioner(deps) {
|
|
|
1319
1357
|
}
|
|
1320
1358
|
};
|
|
1321
1359
|
}
|
|
1360
|
+
/** Strict copy of a follower-supplied attachment source; anything malformed falls back to the plain generated name. */
|
|
1361
|
+
function parseTelegramBusAttachmentSource(value) {
|
|
1362
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1363
|
+
return undefined;
|
|
1364
|
+
const raw = value, chat = raw.chat;
|
|
1365
|
+
const text = (field) => typeof field === "string" && field.length > 0 && field.length <= 256;
|
|
1366
|
+
if (!text(raw.kind) || !Number.isSafeInteger(raw.messageId) ||
|
|
1367
|
+
(raw.index !== undefined && !Number.isSafeInteger(raw.index)) ||
|
|
1368
|
+
(raw.userFileName !== undefined && !text(raw.userFileName)) || (raw.scope !== undefined && !text(raw.scope)) ||
|
|
1369
|
+
(chat !== undefined && (!chat || typeof chat !== "object" || Array.isArray(chat) || !Number.isSafeInteger(chat.id) ||
|
|
1370
|
+
(chat.type !== undefined && !text(chat.type)) || (chat.username !== undefined && !text(chat.username)))))
|
|
1371
|
+
return undefined;
|
|
1372
|
+
return { kind: raw.kind, messageId: raw.messageId,
|
|
1373
|
+
...(raw.index !== undefined ? { index: raw.index } : {}),
|
|
1374
|
+
...(raw.userFileName !== undefined ? { userFileName: raw.userFileName } : {}),
|
|
1375
|
+
...(raw.scope !== undefined ? { scope: raw.scope } : {}),
|
|
1376
|
+
...(chat ? { chat: { id: chat.id,
|
|
1377
|
+
...(chat.type !== undefined ? { type: chat.type } : {}),
|
|
1378
|
+
...(chat.username !== undefined ? { username: chat.username } : {}) } } : {}) };
|
|
1379
|
+
}
|
|
1322
1380
|
export function createTelegramBusLeaderApiProxy(deps) {
|
|
1323
1381
|
return async (method, args) => {
|
|
1324
1382
|
if (method === "call") {
|
|
@@ -1342,7 +1400,9 @@ export function createTelegramBusLeaderApiProxy(deps) {
|
|
|
1342
1400
|
}
|
|
1343
1401
|
}
|
|
1344
1402
|
if (method === "downloadFile") {
|
|
1345
|
-
|
|
1403
|
+
// Follower IPC is a trust boundary: only an exact attachment-source shape reaches the file-name builder.
|
|
1404
|
+
const source = parseTelegramBusAttachmentSource(args[2]);
|
|
1405
|
+
return deps.downloadFile(args[0], args[1], ...(source ? [source] : []));
|
|
1346
1406
|
}
|
|
1347
1407
|
throw new Error(`Unsupported Telegram bus API method: ${method}`);
|
|
1348
1408
|
};
|
|
@@ -1374,6 +1434,54 @@ function createTelegramBusFollowerMutationRunner() {
|
|
|
1374
1434
|
export function createTelegramBusLeaderEnvelopeHandler(deps) {
|
|
1375
1435
|
const getNowMs = deps.getNowMs ?? Date.now;
|
|
1376
1436
|
const runFollowerMutation = deps.runFollowerMutation ?? createTelegramBusFollowerMutationRunner();
|
|
1437
|
+
const recipientObservations = new Map();
|
|
1438
|
+
const observeRestoreRecipient = (follower) => {
|
|
1439
|
+
if (!deps.authSecret || !deps.onWorkspaceRestoreRecipientObserved || !deps.getTelegramProfile ||
|
|
1440
|
+
!hasTelegramBusCapability(deps.protocolIdentity, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) ||
|
|
1441
|
+
!hasTelegramBusCapability(follower.protocol, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE))
|
|
1442
|
+
return;
|
|
1443
|
+
const instanceId = follower.instanceId;
|
|
1444
|
+
const report = (error) => {
|
|
1445
|
+
try {
|
|
1446
|
+
deps.recordRuntimeEvent?.("bus", error, { phase: "workspace-restore-recipient-observation", instanceId });
|
|
1447
|
+
}
|
|
1448
|
+
catch { /* Optional observation diagnostics must not break transport liveness. */ }
|
|
1449
|
+
};
|
|
1450
|
+
try {
|
|
1451
|
+
const epoch = deps.getCurrentLeaderEpoch?.(), operator = deps.getAllowedUserId?.();
|
|
1452
|
+
const runtimeGeneration = deps.getWorkspaceRestoreObservationGeneration?.();
|
|
1453
|
+
if (epoch === undefined || operator === undefined ||
|
|
1454
|
+
(deps.getWorkspaceRestoreObservationGeneration && runtimeGeneration === undefined))
|
|
1455
|
+
return;
|
|
1456
|
+
const snapshot = structuredClone(follower);
|
|
1457
|
+
const observed = { epoch, operator, profile: deps.getTelegramProfile(), runtimeGeneration,
|
|
1458
|
+
follower: { ...snapshot, lastHeartbeatMs: undefined, connectedAtMs: undefined, threadName: undefined } };
|
|
1459
|
+
if (isDeepStrictEqual(recipientObservations.get(instanceId), observed))
|
|
1460
|
+
return;
|
|
1461
|
+
recipientObservations.set(instanceId, observed);
|
|
1462
|
+
const isCurrent = () => {
|
|
1463
|
+
const live = deps.followerRegistry.get(instanceId);
|
|
1464
|
+
return recipientObservations.get(instanceId) === observed &&
|
|
1465
|
+
deps.getWorkspaceRestoreObservationGeneration?.() === observed.runtimeGeneration &&
|
|
1466
|
+
hasTelegramBusCapability(deps.protocolIdentity, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) &&
|
|
1467
|
+
deps.getCurrentLeaderEpoch?.() === observed.epoch && deps.getAllowedUserId?.() === observed.operator &&
|
|
1468
|
+
deps.getTelegramProfile?.() === observed.profile && !!live &&
|
|
1469
|
+
hasTelegramBusCapability(live.protocol, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) &&
|
|
1470
|
+
isDeepStrictEqual({ ...live, lastHeartbeatMs: undefined, connectedAtMs: undefined, threadName: undefined }, observed.follower);
|
|
1471
|
+
};
|
|
1472
|
+
// A heartbeat is a hint, not completion proof. Never await the listener before acknowledging it.
|
|
1473
|
+
void Promise.resolve().then(() => {
|
|
1474
|
+
if (isCurrent())
|
|
1475
|
+
return deps.onWorkspaceRestoreRecipientObserved?.(structuredClone(snapshot), isCurrent);
|
|
1476
|
+
}).catch(report).finally(() => {
|
|
1477
|
+
if (recipientObservations.get(instanceId) === observed)
|
|
1478
|
+
recipientObservations.delete(instanceId);
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
catch (error) {
|
|
1482
|
+
report(error);
|
|
1483
|
+
}
|
|
1484
|
+
};
|
|
1377
1485
|
const handleAgentRequest = async (envelope) => {
|
|
1378
1486
|
const follower = deps.followerRegistry.get(envelope.instanceId);
|
|
1379
1487
|
if (!follower) {
|
|
@@ -1636,9 +1744,16 @@ export function createTelegramBusLeaderEnvelopeHandler(deps) {
|
|
|
1636
1744
|
const registrationOperation = () => runFollowerMutation(envelope.registration, async () => {
|
|
1637
1745
|
try {
|
|
1638
1746
|
const leaderEpoch = deps.getCurrentLeaderEpoch?.();
|
|
1747
|
+
const telegramProfile = deps.getTelegramProfile?.();
|
|
1748
|
+
const operatorUserId = deps.getAllowedUserId?.();
|
|
1749
|
+
const registrationCurrent = () => (!deps.getCurrentLeaderEpoch || deps.getCurrentLeaderEpoch() === leaderEpoch) &&
|
|
1750
|
+
(!deps.getTelegramProfile || deps.getTelegramProfile() === telegramProfile) &&
|
|
1751
|
+
(!deps.getAllowedUserId || deps.getAllowedUserId() === operatorUserId);
|
|
1639
1752
|
if (deps.getCurrentLeaderEpoch && leaderEpoch === undefined) {
|
|
1640
1753
|
throw new Error("Telegram follower registration requires leader ownership.");
|
|
1641
1754
|
}
|
|
1755
|
+
if (hasTelegramBusCapability(deps.protocolIdentity, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) && !deps.commitFollowerRegistration)
|
|
1756
|
+
throw new Error("Workspace Restore registration publication protection is unavailable.");
|
|
1642
1757
|
const target = await deps.provisionFollowerTarget?.(envelope.registration, { existingWorkspaceBindingOnly: restoringWorkspace });
|
|
1643
1758
|
if (restoringWorkspace && !target) {
|
|
1644
1759
|
return {
|
|
@@ -1650,10 +1765,8 @@ export function createTelegramBusLeaderEnvelopeHandler(deps) {
|
|
|
1650
1765
|
message: "No remembered Telegram Workspace Thread is available.",
|
|
1651
1766
|
};
|
|
1652
1767
|
}
|
|
1653
|
-
if (
|
|
1654
|
-
deps.getCurrentLeaderEpoch() !== leaderEpoch) {
|
|
1768
|
+
if (!registrationCurrent())
|
|
1655
1769
|
throw new Error("Telegram follower registration lost leader ownership.");
|
|
1656
|
-
}
|
|
1657
1770
|
if (!displayCompatible()) {
|
|
1658
1771
|
throw new Error("Thread display mode changed; update or restart this follower before connecting.");
|
|
1659
1772
|
}
|
|
@@ -1664,19 +1777,50 @@ export function createTelegramBusLeaderEnvelopeHandler(deps) {
|
|
|
1664
1777
|
(!registeredSlot || !/^[A-Z]$/u.test(registeredSlot))) {
|
|
1665
1778
|
throw new Error("Telegram Thread slot authority is unavailable.");
|
|
1666
1779
|
}
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1780
|
+
let publicationOpen = true;
|
|
1781
|
+
let published;
|
|
1782
|
+
const publish = () => {
|
|
1783
|
+
if (!publicationOpen)
|
|
1784
|
+
throw new Error("Telegram follower registration publication is no longer available.");
|
|
1785
|
+
publicationOpen = false;
|
|
1786
|
+
if (!registrationCurrent())
|
|
1787
|
+
throw new Error("Telegram follower registration lost leader ownership.");
|
|
1788
|
+
if (!displayCompatible())
|
|
1789
|
+
throw new Error("Thread display mode changed; update or restart this follower before connecting.");
|
|
1790
|
+
published = deps.followerRegistry.register({
|
|
1791
|
+
...envelope.registration,
|
|
1792
|
+
connectedAtMs: getNowMs(),
|
|
1793
|
+
target: registeredTarget,
|
|
1794
|
+
...(registeredSlot ? { slot: registeredSlot } : {}),
|
|
1795
|
+
...((target?.threadName ?? envelope.registration.threadName)
|
|
1796
|
+
? { threadName: target?.threadName ?? envelope.registration.threadName } : {}),
|
|
1797
|
+
});
|
|
1798
|
+
};
|
|
1799
|
+
try {
|
|
1800
|
+
if (deps.commitFollowerRegistration)
|
|
1801
|
+
await deps.commitFollowerRegistration({
|
|
1802
|
+
registration: envelope.registration, target: registeredTarget, slot: registeredSlot,
|
|
1803
|
+
}, publish);
|
|
1804
|
+
else
|
|
1805
|
+
publish();
|
|
1806
|
+
}
|
|
1807
|
+
finally {
|
|
1808
|
+
publicationOpen = false;
|
|
1809
|
+
}
|
|
1810
|
+
if (!published)
|
|
1811
|
+
throw new Error("Telegram follower registration publication was not confirmed.");
|
|
1812
|
+
if (!registrationCurrent())
|
|
1813
|
+
throw new Error("Telegram follower registration lost leader ownership.");
|
|
1814
|
+
if (!displayCompatible())
|
|
1815
|
+
throw new Error("Thread display mode changed; update or restart this follower before connecting.");
|
|
1678
1816
|
const follower = deps.followerRegistry.get(envelope.registration.instanceId);
|
|
1679
|
-
|
|
1817
|
+
if (!follower)
|
|
1818
|
+
throw new Error("Telegram follower registration changed before acknowledgement.");
|
|
1819
|
+
const { lastHeartbeatMs: _publishedHeartbeat, connectedAtMs: _publishedAt, threadName: _publishedName, ...publishedIdentity } = published;
|
|
1820
|
+
const { lastHeartbeatMs: _heartbeat, connectedAtMs: _connectedAt, threadName: _threadName, ...identity } = follower;
|
|
1821
|
+
if (!isDeepStrictEqual(publishedIdentity, identity))
|
|
1822
|
+
throw new Error("Telegram follower registration changed before acknowledgement.");
|
|
1823
|
+
const displayTitle = deps.getFollowerDisplayTitle?.(follower);
|
|
1680
1824
|
deps.onFollowerRegistered?.();
|
|
1681
1825
|
return {
|
|
1682
1826
|
kind: "bus.ack",
|
|
@@ -1997,6 +2141,8 @@ export function createTelegramBusLeaderEnvelopeHandler(deps) {
|
|
|
1997
2141
|
};
|
|
1998
2142
|
}
|
|
1999
2143
|
const follower = deps.followerRegistry.heartbeat(envelope.instanceId, getNowMs());
|
|
2144
|
+
if (follower)
|
|
2145
|
+
observeRestoreRecipient(follower);
|
|
2000
2146
|
const displayTitle = follower ? deps.getFollowerDisplayTitle?.(follower) : undefined;
|
|
2001
2147
|
return follower
|
|
2002
2148
|
? {
|
|
@@ -2406,6 +2552,10 @@ export function createTelegramBusLeaderRuntime(deps) {
|
|
|
2406
2552
|
const expectedGeneration = pruneGeneration;
|
|
2407
2553
|
let tracked;
|
|
2408
2554
|
tracked = pruneFollowers(expectedGeneration)
|
|
2555
|
+
.then(() => {
|
|
2556
|
+
if (pruneGeneration === expectedGeneration)
|
|
2557
|
+
deps.afterFollowerPrune?.();
|
|
2558
|
+
})
|
|
2409
2559
|
.catch((error) => {
|
|
2410
2560
|
if (pruneGeneration === expectedGeneration) {
|
|
2411
2561
|
recordPruneEvent(error, { phase: "follower-prune-owner" });
|
|
@@ -2441,6 +2591,7 @@ export function createTelegramBusLeaderRuntime(deps) {
|
|
|
2441
2591
|
forgetPreservation(pendingPreservations.get(registration.instanceId));
|
|
2442
2592
|
return deps.provisionFollowerTarget(registration, options);
|
|
2443
2593
|
} : undefined,
|
|
2594
|
+
commitFollowerRegistration: deps.commitFollowerRegistration,
|
|
2444
2595
|
onFollowerDisconnected: deps.onFollowerDisconnected,
|
|
2445
2596
|
renameFollowerThread: deps.renameFollowerThread,
|
|
2446
2597
|
resetFollowerThreadName: deps.resetFollowerThreadName,
|
|
@@ -2448,9 +2599,14 @@ export function createTelegramBusLeaderRuntime(deps) {
|
|
|
2448
2599
|
settleFollowerSessionReplacement: deps.settleFollowerSessionReplacement,
|
|
2449
2600
|
getFollowerDisplayTitle: deps.getFollowerDisplayTitle,
|
|
2450
2601
|
onFollowerRegistered: deps.onFollowerRegistered,
|
|
2602
|
+
onWorkspaceRestoreRecipientObserved: deps.onWorkspaceRestoreRecipientObserved,
|
|
2603
|
+
getWorkspaceRestoreObservationGeneration: () => pruneInterval ? pruneGeneration : undefined,
|
|
2604
|
+
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
2451
2605
|
applyThreadDisplayMode: deps.applyThreadDisplayMode,
|
|
2452
2606
|
getThreadDisplayMode: deps.getThreadDisplayMode,
|
|
2453
2607
|
getCurrentLeaderEpoch: deps.getCurrentLeaderEpoch,
|
|
2608
|
+
getTelegramProfile: deps.getTelegramProfile,
|
|
2609
|
+
getAllowedUserId: deps.getAllowedUserId,
|
|
2454
2610
|
runFollowerMutation,
|
|
2455
2611
|
runWorkspaceAdmission: deps.runWorkspaceAdmission,
|
|
2456
2612
|
runWithWorkspaceCapacity: deps.runWithWorkspaceCapacity,
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Zones: multi-instance bus, IPC transport, Windows named pipes, Unix sockets
|
|
4
4
|
* Owns endpoint derivation, transport-kind detection, retry/error classification, and small timing policy.
|
|
5
5
|
*/
|
|
6
|
+
export type TelegramBusEndpointLayout = "consolidated";
|
|
7
|
+
export declare const TELEGRAM_BUS_MAX_DIRECT_UNIX_ENDPOINT_BYTES = 80;
|
|
6
8
|
export type TelegramBusTransportKind = "pipe" | "socket";
|
|
7
9
|
export type TelegramBusTransportEventRecorder = (phase: string, details: Record<string, unknown>) => void;
|
|
8
10
|
export type TelegramBusTransportEndpointDiagnostics = Record<string, unknown> & {
|
|
@@ -19,7 +21,6 @@ export interface TelegramBusTransportRetryPolicyOverrides {
|
|
|
19
21
|
}
|
|
20
22
|
export type TelegramBusTransportOperation = "registration" | "operation";
|
|
21
23
|
export declare const TELEGRAM_BUS_REGISTRATION_RETRY: TelegramBusTransportRetryPolicy;
|
|
22
|
-
export declare const TELEGRAM_BUS_OPERATION_RETRY: TelegramBusTransportRetryPolicy;
|
|
23
24
|
export declare function getTelegramBusPipePath(input: {
|
|
24
25
|
agentDir: string;
|
|
25
26
|
scope: string;
|
|
@@ -36,12 +37,14 @@ export declare function getTelegramBusLeaderEndpoint(input: {
|
|
|
36
37
|
agentDir: string;
|
|
37
38
|
platform: NodeJS.Platform | string;
|
|
38
39
|
profileName?: string;
|
|
40
|
+
layout?: TelegramBusEndpointLayout;
|
|
39
41
|
}): string;
|
|
40
42
|
export declare function getTelegramBusFollowerEndpoint(input: {
|
|
41
43
|
agentDir: string;
|
|
42
44
|
platform: NodeJS.Platform | string;
|
|
43
45
|
instanceId: string;
|
|
44
46
|
profileName?: string;
|
|
47
|
+
layout?: TelegramBusEndpointLayout;
|
|
45
48
|
}): string;
|
|
46
49
|
export interface TelegramBusTransportErrorInfo {
|
|
47
50
|
message: string;
|
|
@@ -5,12 +5,20 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
import { createConnection } from "node:net";
|
|
8
|
-
import { join, resolve } from "node:path";
|
|
8
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
9
|
+
import { resolveTelegramTempDir, resolveTelegramRuntimeDir } from "./paths.js";
|
|
10
|
+
export const TELEGRAM_BUS_MAX_DIRECT_UNIX_ENDPOINT_BYTES = 80;
|
|
11
|
+
function requireConsolidatedUnixEndpoint(path) {
|
|
12
|
+
if (!isAbsolute(path) || resolve(path) !== path)
|
|
13
|
+
throw new Error("Consolidated Telegram IPC requires an exact absolute runtime path.");
|
|
14
|
+
// Over-budget logical paths keep their identity; socket resolution applies the bounded private external fallback.
|
|
15
|
+
return path;
|
|
16
|
+
}
|
|
9
17
|
export const TELEGRAM_BUS_REGISTRATION_RETRY = {
|
|
10
18
|
attempts: 10,
|
|
11
19
|
delayMs: 150,
|
|
12
20
|
};
|
|
13
|
-
|
|
21
|
+
const TELEGRAM_BUS_OPERATION_RETRY = {
|
|
14
22
|
attempts: 3,
|
|
15
23
|
delayMs: 100,
|
|
16
24
|
};
|
|
@@ -51,6 +59,14 @@ function normalizeTelegramBusEndpointScope(value) {
|
|
|
51
59
|
return value.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 80);
|
|
52
60
|
}
|
|
53
61
|
export function getTelegramBusLeaderEndpoint(input) {
|
|
62
|
+
if (input.layout !== undefined && input.layout !== "consolidated")
|
|
63
|
+
throw new Error("Telegram IPC layout is invalid.");
|
|
64
|
+
if (input.layout === "consolidated") {
|
|
65
|
+
const scope = createHash("sha256").update(JSON.stringify([input.profileName ?? "default"])).digest("hex").slice(0, 16);
|
|
66
|
+
return input.platform === "win32"
|
|
67
|
+
? getTelegramBusPipePath({ agentDir: input.agentDir, scope: `bus-${scope}` })
|
|
68
|
+
: requireConsolidatedUnixEndpoint(join(resolveTelegramRuntimeDir(input.agentDir), `bus.${scope}.sock`));
|
|
69
|
+
}
|
|
54
70
|
const profileScope = input.profileName
|
|
55
71
|
? normalizeTelegramBusEndpointScope(input.profileName)
|
|
56
72
|
: undefined;
|
|
@@ -59,9 +75,17 @@ export function getTelegramBusLeaderEndpoint(input) {
|
|
|
59
75
|
agentDir: input.agentDir,
|
|
60
76
|
scope: profileScope ? `bus-${profileScope}` : "bus",
|
|
61
77
|
})
|
|
62
|
-
: join(input.agentDir,
|
|
78
|
+
: join(resolveTelegramTempDir(input.agentDir), profileScope ? `bus.${profileScope}.sock` : "bus.sock");
|
|
63
79
|
}
|
|
64
80
|
export function getTelegramBusFollowerEndpoint(input) {
|
|
81
|
+
if (input.layout !== undefined && input.layout !== "consolidated")
|
|
82
|
+
throw new Error("Telegram IPC layout is invalid.");
|
|
83
|
+
if (input.layout === "consolidated") {
|
|
84
|
+
const scope = createHash("sha256").update(JSON.stringify([input.profileName ?? "default", input.instanceId])).digest("hex").slice(0, 16);
|
|
85
|
+
return input.platform === "win32"
|
|
86
|
+
? getTelegramBusPipePath({ agentDir: input.agentDir, scope: `follower-${scope}` })
|
|
87
|
+
: requireConsolidatedUnixEndpoint(join(resolveTelegramRuntimeDir(input.agentDir), `f.${scope}.sock`));
|
|
88
|
+
}
|
|
65
89
|
const instanceScope = normalizeTelegramBusEndpointScope(input.instanceId);
|
|
66
90
|
const profileScope = input.profileName
|
|
67
91
|
? normalizeTelegramBusEndpointScope(input.profileName)
|
|
@@ -73,7 +97,7 @@ export function getTelegramBusFollowerEndpoint(input) {
|
|
|
73
97
|
? `follower-${profileScope}-${instanceScope}`
|
|
74
98
|
: `follower-${instanceScope}`,
|
|
75
99
|
})
|
|
76
|
-
: join(input.agentDir, "
|
|
100
|
+
: join(resolveTelegramTempDir(input.agentDir), "followers", ...(profileScope ? [profileScope] : []), `${instanceScope}.sock`);
|
|
77
101
|
}
|
|
78
102
|
export function classifyTelegramBusTransportError(error) {
|
|
79
103
|
const message = error instanceof Error ? error.message : String(error);
|