@llblab/pi-kit 0.27.6 → 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 +2 -5
- package/CHANGELOG.md +5 -0
- package/README.md +2 -2
- 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 +2 -2
|
@@ -11,9 +11,10 @@ import { createConnection, createServer, } from "node:net";
|
|
|
11
11
|
import { createRequire } from "node:module";
|
|
12
12
|
import { platform as getPlatform, tmpdir } from "node:os";
|
|
13
13
|
import { basename, dirname, join } from "node:path";
|
|
14
|
-
import { classifyTelegramBusTransportError, createTelegramBusTransportTimeoutError, delayTelegramBusTransportRetry, getTelegramBusEndpointDiagnostics, getTelegramBusFollowerEndpoint, getTelegramBusLeaderEndpoint, getTelegramBusPipePath, getTelegramBusTransportRetryPolicy, isTelegramBusPipePath, isRetryableTelegramBusTransportError, probeTelegramBusEndpoint, } from "./bus-transport.js";
|
|
15
|
-
import {
|
|
14
|
+
import { classifyTelegramBusTransportError, createTelegramBusTransportTimeoutError, delayTelegramBusTransportRetry, getTelegramBusEndpointDiagnostics, getTelegramBusFollowerEndpoint, getTelegramBusLeaderEndpoint, getTelegramBusPipePath, getTelegramBusTransportRetryPolicy, TELEGRAM_BUS_MAX_DIRECT_UNIX_ENDPOINT_BYTES, isTelegramBusPipePath, isRetryableTelegramBusTransportError, probeTelegramBusEndpoint, } from "./bus-transport.js";
|
|
15
|
+
import { parseTelegramQueueHandoffPayload, TELEGRAM_QUEUE_HANDOFF_PAYLOAD_MAX_BYTES, } from "./queue.js";
|
|
16
16
|
import { isProcessAlive } from "./locks.js";
|
|
17
|
+
import { isWireRecord as isRecord } from "./wire.js";
|
|
17
18
|
import { resolveAgentDir } from "./paths.js";
|
|
18
19
|
import { normalizeTelegramSessionReplacementIntent, } from "./threads.js";
|
|
19
20
|
function readDarwinProcessStart(pid) {
|
|
@@ -22,7 +23,7 @@ function readDarwinProcessStart(pid) {
|
|
|
22
23
|
stdio: ["ignore", "pipe", "ignore"],
|
|
23
24
|
}).trim();
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
+
function getTelegramProcessBirthProof(pid, options = {}) {
|
|
26
27
|
if (pid <= 0)
|
|
27
28
|
return { status: "unverifiable" };
|
|
28
29
|
const platform = options.platform ?? getPlatform();
|
|
@@ -95,12 +96,14 @@ export function getTelegramProcessBirthIdentityLiveness(processBirthId, options
|
|
|
95
96
|
export function createCurrentTelegramBusProcessRuntime(input) {
|
|
96
97
|
return createTelegramBusProcessRuntime({
|
|
97
98
|
getActiveProfileName: input.getActiveProfileName,
|
|
99
|
+
endpointLayout: input.endpointLayout,
|
|
98
100
|
pid: input.pid ?? process.pid,
|
|
99
101
|
parentPid: input.parentPid ?? process.ppid,
|
|
100
102
|
createdAtMs: input.createdAtMs ?? Date.now(),
|
|
101
103
|
});
|
|
102
104
|
}
|
|
103
105
|
export function createTelegramBusProcessRuntime(input) {
|
|
106
|
+
const getActiveProfileName = input.getActiveProfileName, endpointLayout = input.endpointLayout;
|
|
104
107
|
const instanceId = `${input.pid}:${input.createdAtMs}`;
|
|
105
108
|
const ownerPid = input.parentPid || input.pid;
|
|
106
109
|
const manualFollowerOwnerId = input.parentProcessIdentity ??
|
|
@@ -110,14 +113,14 @@ export function createTelegramBusProcessRuntime(input) {
|
|
|
110
113
|
processId: input.pid,
|
|
111
114
|
processBirthId: getTelegramProcessBirthIdentity(input.pid, instanceId),
|
|
112
115
|
manualFollowerOwnerId,
|
|
113
|
-
getLeaderSocketPath: () => getTelegramBusSocketPath(undefined, undefined,
|
|
114
|
-
getFollowerSocketPath: () => getTelegramBusFollowerSocketPath(instanceId, undefined, undefined,
|
|
116
|
+
getLeaderSocketPath: () => getTelegramBusSocketPath(undefined, undefined, getActiveProfileName(), endpointLayout),
|
|
117
|
+
getFollowerSocketPath: () => getTelegramBusFollowerSocketPath(instanceId, undefined, undefined, getActiveProfileName(), endpointLayout),
|
|
115
118
|
};
|
|
116
119
|
}
|
|
117
120
|
export function createTelegramBusAuthSecret() {
|
|
118
121
|
return randomBytes(32).toString("base64url");
|
|
119
122
|
}
|
|
120
|
-
|
|
123
|
+
const TELEGRAM_BUS_PROTOCOL_VERSION = 2;
|
|
121
124
|
export const TELEGRAM_BUS_CAPABILITY_DURABLE_FOLLOWER_ADMISSION = "durable-follower-admission-v1";
|
|
122
125
|
export const TELEGRAM_BUS_CAPABILITY_QUEUE_HANDOFF = "queue-handoff-v1";
|
|
123
126
|
export const TELEGRAM_BUS_CAPABILITY_INPUT_CUSTODY_REFERENCE = "input-custody-reference-v1";
|
|
@@ -126,6 +129,7 @@ export const TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE = "thread-display-mode-
|
|
|
126
129
|
export const TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT = "directory-display-format-v1";
|
|
127
130
|
export const TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT = "workspace-follower-auto-connect-v1";
|
|
128
131
|
export const TELEGRAM_BUS_CAPABILITY_SESSION_REPLACEMENT_INTENT = "session-replacement-intent-v1";
|
|
132
|
+
export const TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE = "workspace-restore-v1";
|
|
129
133
|
export function createTelegramBusProtocolIdentity(input) {
|
|
130
134
|
const runtimeBuild = input.runtimeBuild.trim();
|
|
131
135
|
if (!runtimeBuild || runtimeBuild.length > 128) {
|
|
@@ -191,15 +195,16 @@ export function getTelegramBusProtocolCompatibility(input) {
|
|
|
191
195
|
}
|
|
192
196
|
: { compatible: true, missingCapabilities: [] };
|
|
193
197
|
}
|
|
194
|
-
export function getTelegramBusSocketPath(agentDir = resolveAgentDir(), platform = getPlatform(), profileName) {
|
|
195
|
-
return getTelegramBusLeaderEndpoint({ agentDir, platform, profileName });
|
|
198
|
+
export function getTelegramBusSocketPath(agentDir = resolveAgentDir(), platform = getPlatform(), profileName, layout) {
|
|
199
|
+
return getTelegramBusLeaderEndpoint({ agentDir, platform, profileName, layout });
|
|
196
200
|
}
|
|
197
|
-
export function getTelegramBusFollowerSocketPath(instanceId, agentDir = resolveAgentDir(), platform = getPlatform(), profileName) {
|
|
201
|
+
export function getTelegramBusFollowerSocketPath(instanceId, agentDir = resolveAgentDir(), platform = getPlatform(), profileName, layout) {
|
|
198
202
|
return getTelegramBusFollowerEndpoint({
|
|
199
203
|
agentDir,
|
|
200
204
|
platform,
|
|
201
205
|
instanceId,
|
|
202
206
|
profileName,
|
|
207
|
+
layout,
|
|
203
208
|
});
|
|
204
209
|
}
|
|
205
210
|
export function getTelegramFollowerTargetOwnership(input) {
|
|
@@ -229,7 +234,7 @@ export function markTelegramBusAggregateDelivery(body) {
|
|
|
229
234
|
[TELEGRAM_BUS_AGGREGATE_DELIVERY_FIELD]: true,
|
|
230
235
|
};
|
|
231
236
|
}
|
|
232
|
-
|
|
237
|
+
function isTelegramBusAggregateDelivery(body) {
|
|
233
238
|
return Boolean(body &&
|
|
234
239
|
typeof body === "object" &&
|
|
235
240
|
!Array.isArray(body) &&
|
|
@@ -242,7 +247,7 @@ export function markTelegramBusCrossTargetDelivery(body) {
|
|
|
242
247
|
[TELEGRAM_BUS_CROSS_TARGET_DELIVERY_FIELD]: true,
|
|
243
248
|
};
|
|
244
249
|
}
|
|
245
|
-
|
|
250
|
+
function isTelegramBusCrossTargetDelivery(body) {
|
|
246
251
|
return Boolean(body &&
|
|
247
252
|
typeof body === "object" &&
|
|
248
253
|
!Array.isArray(body) &&
|
|
@@ -542,8 +547,16 @@ export function parseTelegramBusEnvelope(line) {
|
|
|
542
547
|
case "leader.forwardEditedMessage":
|
|
543
548
|
envelope = parseForwardMessageEnvelope(value, requestId, "leader.forwardEditedMessage");
|
|
544
549
|
break;
|
|
545
|
-
case "leader.
|
|
546
|
-
|
|
550
|
+
case "leader.workspaceRestore":
|
|
551
|
+
if (typeof value.recipientInstanceId === "string" && value.recipientInstanceId &&
|
|
552
|
+
typeof value.recipientRegistrationGeneration === "string" && value.recipientRegistrationGeneration &&
|
|
553
|
+
typeof value.operationId === "string" && value.operationId.length > 0 && value.operationId.length <= 128 &&
|
|
554
|
+
(value.mode === "apply" || value.mode === "inspect") &&
|
|
555
|
+
typeof value.sentAtMs === "number" && Number.isFinite(value.sentAtMs)) {
|
|
556
|
+
envelope = { kind: "leader.workspaceRestore", requestId, recipientInstanceId: value.recipientInstanceId,
|
|
557
|
+
recipientRegistrationGeneration: value.recipientRegistrationGeneration, operationId: value.operationId,
|
|
558
|
+
mode: value.mode, sentAtMs: value.sentAtMs };
|
|
559
|
+
}
|
|
547
560
|
break;
|
|
548
561
|
case "leader.offerQueueHandoff":
|
|
549
562
|
envelope = parseQueueHandoffEnvelope(value, requestId, "leader.offerQueueHandoff");
|
|
@@ -576,7 +589,6 @@ function getActiveTelegramBusLocalServers() {
|
|
|
576
589
|
const root = globalThis;
|
|
577
590
|
return (root[TELEGRAM_ACTIVE_LOCAL_SERVERS] ??= new Map());
|
|
578
591
|
}
|
|
579
|
-
const TELEGRAM_BUS_MAX_DIRECT_UNIX_ENDPOINT_BYTES = 80;
|
|
580
592
|
export function resolveTelegramBusSocketPath(source, platform = getPlatform()) {
|
|
581
593
|
const endpoint = typeof source === "function" ? source() : source;
|
|
582
594
|
if (platform === "win32") {
|
|
@@ -892,67 +904,56 @@ export function listTelegramBusLiveThreadTargets(input) {
|
|
|
892
904
|
}
|
|
893
905
|
return targets;
|
|
894
906
|
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
return {
|
|
898
|
-
|
|
899
|
-
|
|
907
|
+
/** Caller owns the durable one-shot apply grant. Inspections never grant another apply. */
|
|
908
|
+
export function createTelegramBusWorkspaceRestoreController(deps) {
|
|
909
|
+
return async (input) => {
|
|
910
|
+
const isCurrent = input.isCurrent.bind(input);
|
|
911
|
+
if (!isCurrent())
|
|
912
|
+
return undefined;
|
|
913
|
+
const follower = deps.getFollower(input.instanceId);
|
|
914
|
+
const secret = deps.getAuthSecret();
|
|
915
|
+
if (!secret || !follower?.registrationGeneration || !follower.busSocketPath ||
|
|
916
|
+
follower.sessionId !== input.sessionId || follower.slot !== input.slot ||
|
|
917
|
+
!hasTelegramBusCapability(deps.localProtocolIdentity, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) ||
|
|
918
|
+
!hasTelegramBusCapability(follower.protocol, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) ||
|
|
919
|
+
!getTelegramBusProtocolCompatibility({ local: deps.localProtocolIdentity, remote: follower.protocol }).compatible)
|
|
920
|
+
return undefined;
|
|
921
|
+
const captured = structuredClone(follower);
|
|
922
|
+
const expected = { operationId: input.operationId, sessionId: input.sessionId, slot: input.slot,
|
|
923
|
+
target: { ...input.target }, oldTarget: { ...input.oldTarget }, mode: input.mode };
|
|
924
|
+
const current = () => {
|
|
925
|
+
if (!isCurrent() || deps.getAuthSecret() !== secret ||
|
|
926
|
+
!hasTelegramBusCapability(deps.localProtocolIdentity, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE))
|
|
900
927
|
return false;
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
return false;
|
|
931
|
-
const follower = deps.followerRegistry.get(record.instanceId);
|
|
932
|
-
if (!follower?.registrationGeneration || !oldTarget ||
|
|
933
|
-
follower.target?.chatId !== oldTarget.chatId ||
|
|
934
|
-
follower.target.threadId !== oldTarget.threadId ||
|
|
935
|
-
target.chatId !== oldTarget.chatId || target.threadId === oldTarget.threadId)
|
|
936
|
-
return false;
|
|
937
|
-
const replaced = await deps.followerTargetController.replaceTarget({
|
|
938
|
-
follower,
|
|
939
|
-
target,
|
|
940
|
-
oldTarget,
|
|
941
|
-
reason: "thread-restore",
|
|
942
|
-
});
|
|
943
|
-
const current = deps.followerRegistry.get(record.instanceId);
|
|
944
|
-
if (!replaced || !current ||
|
|
945
|
-
current.registrationGeneration !== follower.registrationGeneration ||
|
|
946
|
-
current.target?.chatId !== oldTarget.chatId ||
|
|
947
|
-
current.target.threadId !== oldTarget.threadId)
|
|
948
|
-
return false;
|
|
949
|
-
deps.followerRegistry.register({
|
|
950
|
-
...current,
|
|
951
|
-
target,
|
|
952
|
-
connectedAtMs: current.connectedAtMs,
|
|
953
|
-
});
|
|
954
|
-
deps.onRestored?.();
|
|
955
|
-
return true;
|
|
928
|
+
const live = deps.getFollower(captured.instanceId);
|
|
929
|
+
return !!live && live.registrationGeneration === captured.registrationGeneration &&
|
|
930
|
+
live.sessionId === captured.sessionId && live.cwd === captured.cwd && live.slot === captured.slot &&
|
|
931
|
+
live.busSocketPath === captured.busSocketPath && live.target?.chatId === captured.target?.chatId &&
|
|
932
|
+
live.target?.threadId === captured.target?.threadId &&
|
|
933
|
+
hasTelegramBusCapability(live.protocol, TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) &&
|
|
934
|
+
getTelegramBusProtocolCompatibility({ local: deps.localProtocolIdentity, remote: live.protocol }).compatible;
|
|
935
|
+
};
|
|
936
|
+
if (!current())
|
|
937
|
+
return undefined;
|
|
938
|
+
const requestId = deps.createRequestId();
|
|
939
|
+
const response = await sendTelegramBusLocalEnvelope({ socketPath: captured.busSocketPath, timeoutMs: deps.timeoutMs,
|
|
940
|
+
retry: { attempts: 1, delayMs: 0 }, envelope: { kind: "leader.workspaceRestore", requestId,
|
|
941
|
+
recipientInstanceId: captured.instanceId, recipientRegistrationGeneration: captured.registrationGeneration,
|
|
942
|
+
operationId: expected.operationId, mode: expected.mode, auth: secret, sentAtMs: Date.now() } });
|
|
943
|
+
if (!current() || response?.kind !== "bus.ack" || response.requestId !== requestId || response.ok !== true ||
|
|
944
|
+
!response.result || typeof response.result !== "object")
|
|
945
|
+
return undefined;
|
|
946
|
+
const result = response.result;
|
|
947
|
+
const recipient = result.recipient;
|
|
948
|
+
const target = parseThreadTarget(result.target);
|
|
949
|
+
const wanted = result.ready === true ? expected.target : expected.oldTarget;
|
|
950
|
+
if (result.operationId !== expected.operationId || typeof result.ready !== "boolean" || result.slot !== expected.slot ||
|
|
951
|
+
!target || target.chatId !== wanted.chatId || target.threadId !== wanted.threadId ||
|
|
952
|
+
recipient?.kind !== "follower" || recipient.instanceId !== captured.instanceId ||
|
|
953
|
+
recipient.sessionId !== expected.sessionId || recipient.generation !== captured.registrationGeneration)
|
|
954
|
+
return undefined;
|
|
955
|
+
return { operationId: expected.operationId, recipient: { kind: "follower", instanceId: captured.instanceId,
|
|
956
|
+
sessionId: expected.sessionId, generation: captured.registrationGeneration }, target, slot: expected.slot, ready: result.ready };
|
|
956
957
|
};
|
|
957
958
|
}
|
|
958
959
|
export function isTelegramBusEnvelopeAuthorized(envelope, secret) {
|
|
@@ -1021,11 +1022,8 @@ export function createTelegramBusLocalServer(deps) {
|
|
|
1021
1022
|
result: Promise.resolve().then(() => deps.handleEnvelope(envelope)),
|
|
1022
1023
|
};
|
|
1023
1024
|
requestLedger.set(key, entry);
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
}, () => {
|
|
1027
|
-
entry.settled = true;
|
|
1028
|
-
});
|
|
1025
|
+
const settled = () => { entry.settled = true; };
|
|
1026
|
+
void entry.result.then(settled, settled);
|
|
1029
1027
|
return entry.result;
|
|
1030
1028
|
};
|
|
1031
1029
|
let server;
|
|
@@ -1652,169 +1650,6 @@ function parseWakeInputCustodyEnvelope(value, requestId) {
|
|
|
1652
1650
|
delivery, sentAtMs: value.sentAtMs }
|
|
1653
1651
|
: undefined;
|
|
1654
1652
|
}
|
|
1655
|
-
function parseReplaceFollowerTargetEnvelope(value, requestId) {
|
|
1656
|
-
const target = parseThreadTarget(value.target);
|
|
1657
|
-
const oldTarget = parseThreadTarget(value.oldTarget);
|
|
1658
|
-
if (typeof value.recipientInstanceId !== "string" ||
|
|
1659
|
-
!target ||
|
|
1660
|
-
(value.oldTarget !== undefined && !oldTarget) ||
|
|
1661
|
-
value.reason !== "thread-restore" ||
|
|
1662
|
-
typeof value.sentAtMs !== "number") {
|
|
1663
|
-
return undefined;
|
|
1664
|
-
}
|
|
1665
|
-
return {
|
|
1666
|
-
kind: "leader.replaceFollowerTarget",
|
|
1667
|
-
requestId,
|
|
1668
|
-
recipientInstanceId: value.recipientInstanceId,
|
|
1669
|
-
...(typeof value.recipientRegistrationGeneration === "string"
|
|
1670
|
-
? {
|
|
1671
|
-
recipientRegistrationGeneration: value.recipientRegistrationGeneration,
|
|
1672
|
-
}
|
|
1673
|
-
: {}),
|
|
1674
|
-
target,
|
|
1675
|
-
...(oldTarget ? { oldTarget } : {}),
|
|
1676
|
-
reason: value.reason,
|
|
1677
|
-
sentAtMs: value.sentAtMs,
|
|
1678
|
-
};
|
|
1679
|
-
}
|
|
1680
|
-
function parseQueueAdmissionReceipt(value, queueKind) {
|
|
1681
|
-
if (!isRecord(value) || value.queueKind !== queueKind)
|
|
1682
|
-
return undefined;
|
|
1683
|
-
const sourceUpdateIds = Array.isArray(value.sourceUpdateIds)
|
|
1684
|
-
? value.sourceUpdateIds
|
|
1685
|
-
: undefined;
|
|
1686
|
-
if (typeof value.receiptId !== "string" ||
|
|
1687
|
-
!value.receiptId ||
|
|
1688
|
-
(value.journalBindingKey !== undefined &&
|
|
1689
|
-
(typeof value.journalBindingKey !== "string" ||
|
|
1690
|
-
!value.journalBindingKey.trim())) ||
|
|
1691
|
-
!sourceUpdateIds ||
|
|
1692
|
-
sourceUpdateIds.length === 0 ||
|
|
1693
|
-
sourceUpdateIds.some((updateId, index) => !Number.isSafeInteger(updateId) ||
|
|
1694
|
-
updateId < 0 ||
|
|
1695
|
-
(index > 0 &&
|
|
1696
|
-
updateId <=
|
|
1697
|
-
sourceUpdateIds[index - 1]))) {
|
|
1698
|
-
return undefined;
|
|
1699
|
-
}
|
|
1700
|
-
return {
|
|
1701
|
-
queueKind,
|
|
1702
|
-
receiptId: value.receiptId,
|
|
1703
|
-
sourceUpdateIds: sourceUpdateIds,
|
|
1704
|
-
...(typeof value.journalBindingKey === "string"
|
|
1705
|
-
? { journalBindingKey: value.journalBindingKey }
|
|
1706
|
-
: {}),
|
|
1707
|
-
};
|
|
1708
|
-
}
|
|
1709
|
-
function parseQueueHandoffPayload(value) {
|
|
1710
|
-
if (!isRecord(value) || (value.kind !== "prompt" && value.kind !== "control")) {
|
|
1711
|
-
return undefined;
|
|
1712
|
-
}
|
|
1713
|
-
const queueKind = value.kind;
|
|
1714
|
-
const target = parseTarget(value.target);
|
|
1715
|
-
const transportStamp = isRecord(value.transportStamp) &&
|
|
1716
|
-
typeof value.transportStamp.profile === "string" &&
|
|
1717
|
-
typeof value.transportStamp.generation === "string"
|
|
1718
|
-
? {
|
|
1719
|
-
profile: value.transportStamp.profile,
|
|
1720
|
-
generation: value.transportStamp.generation,
|
|
1721
|
-
}
|
|
1722
|
-
: undefined;
|
|
1723
|
-
if (!Number.isSafeInteger(value.chatId) ||
|
|
1724
|
-
(value.target !== undefined && !target) ||
|
|
1725
|
-
(value.transportStamp !== undefined && !transportStamp) ||
|
|
1726
|
-
!Number.isSafeInteger(value.replyToMessageId) ||
|
|
1727
|
-
(value.guestQueryId !== undefined &&
|
|
1728
|
-
typeof value.guestQueryId !== "string") ||
|
|
1729
|
-
(value.guestInlineMessageId !== undefined &&
|
|
1730
|
-
typeof value.guestInlineMessageId !== "string") ||
|
|
1731
|
-
!Number.isSafeInteger(value.queueOrder) ||
|
|
1732
|
-
(value.queueLane !== "control" &&
|
|
1733
|
-
value.queueLane !== "priority" &&
|
|
1734
|
-
value.queueLane !== "default") ||
|
|
1735
|
-
!Number.isSafeInteger(value.laneOrder) ||
|
|
1736
|
-
typeof value.statusSummary !== "string" ||
|
|
1737
|
-
!Array.isArray(value.admissionReceipts)) {
|
|
1738
|
-
return undefined;
|
|
1739
|
-
}
|
|
1740
|
-
const admissionReceipts = value.admissionReceipts.map((receipt) => parseQueueAdmissionReceipt(receipt, queueKind));
|
|
1741
|
-
if (admissionReceipts.length === 0 ||
|
|
1742
|
-
admissionReceipts.length > TELEGRAM_QUEUE_HANDOFF_MAX_RECEIPTS ||
|
|
1743
|
-
admissionReceipts.some((receipt) => receipt === undefined)) {
|
|
1744
|
-
return undefined;
|
|
1745
|
-
}
|
|
1746
|
-
const queueLane = value.queueLane;
|
|
1747
|
-
const base = {
|
|
1748
|
-
chatId: value.chatId,
|
|
1749
|
-
...(target ? { target } : {}),
|
|
1750
|
-
...(transportStamp ? { transportStamp } : {}),
|
|
1751
|
-
replyToMessageId: value.replyToMessageId,
|
|
1752
|
-
...(typeof value.guestQueryId === "string"
|
|
1753
|
-
? { guestQueryId: value.guestQueryId }
|
|
1754
|
-
: {}),
|
|
1755
|
-
...(typeof value.guestInlineMessageId === "string"
|
|
1756
|
-
? { guestInlineMessageId: value.guestInlineMessageId }
|
|
1757
|
-
: {}),
|
|
1758
|
-
queueOrder: value.queueOrder,
|
|
1759
|
-
queueLane,
|
|
1760
|
-
laneOrder: value.laneOrder,
|
|
1761
|
-
statusSummary: value.statusSummary,
|
|
1762
|
-
admissionReceipts: admissionReceipts,
|
|
1763
|
-
};
|
|
1764
|
-
if (queueKind === "control") {
|
|
1765
|
-
if (value.queueLane !== "control" ||
|
|
1766
|
-
(value.controlType !== "status" && value.controlType !== "model")) {
|
|
1767
|
-
return undefined;
|
|
1768
|
-
}
|
|
1769
|
-
return { kind: "control", controlType: value.controlType, ...base };
|
|
1770
|
-
}
|
|
1771
|
-
if (value.queueLane === "control" ||
|
|
1772
|
-
!Array.isArray(value.sourceMessageIds) ||
|
|
1773
|
-
value.sourceMessageIds.some((id) => !Number.isSafeInteger(id)) ||
|
|
1774
|
-
!Array.isArray(value.queuedAttachments) ||
|
|
1775
|
-
value.queuedAttachments.some((attachment) => !isRecord(attachment) ||
|
|
1776
|
-
typeof attachment.path !== "string" ||
|
|
1777
|
-
typeof attachment.fileName !== "string") ||
|
|
1778
|
-
!Array.isArray(value.content) ||
|
|
1779
|
-
value.content.some((content) => !isRecord(content) ||
|
|
1780
|
-
(content.type === "text"
|
|
1781
|
-
? typeof content.text !== "string"
|
|
1782
|
-
: content.type === "image"
|
|
1783
|
-
? typeof content.data !== "string" ||
|
|
1784
|
-
typeof content.mimeType !== "string"
|
|
1785
|
-
: true)) ||
|
|
1786
|
-
typeof value.historyText !== "string" ||
|
|
1787
|
-
(value.priorityEmoji !== undefined &&
|
|
1788
|
-
typeof value.priorityEmoji !== "string") ||
|
|
1789
|
-
(value.reactionSuppressionEmoji !== undefined &&
|
|
1790
|
-
typeof value.reactionSuppressionEmoji !== "string") ||
|
|
1791
|
-
(value.voiceReplyPreferred !== undefined &&
|
|
1792
|
-
typeof value.voiceReplyPreferred !== "boolean") ||
|
|
1793
|
-
(value.voiceReplyRequired !== undefined &&
|
|
1794
|
-
typeof value.voiceReplyRequired !== "boolean")) {
|
|
1795
|
-
return undefined;
|
|
1796
|
-
}
|
|
1797
|
-
return {
|
|
1798
|
-
kind: "prompt",
|
|
1799
|
-
...base,
|
|
1800
|
-
sourceMessageIds: value.sourceMessageIds,
|
|
1801
|
-
queuedAttachments: value.queuedAttachments,
|
|
1802
|
-
content: value.content,
|
|
1803
|
-
historyText: value.historyText,
|
|
1804
|
-
...(typeof value.priorityEmoji === "string"
|
|
1805
|
-
? { priorityEmoji: value.priorityEmoji }
|
|
1806
|
-
: {}),
|
|
1807
|
-
...(typeof value.reactionSuppressionEmoji === "string"
|
|
1808
|
-
? { reactionSuppressionEmoji: value.reactionSuppressionEmoji }
|
|
1809
|
-
: {}),
|
|
1810
|
-
...(typeof value.voiceReplyPreferred === "boolean"
|
|
1811
|
-
? { voiceReplyPreferred: value.voiceReplyPreferred }
|
|
1812
|
-
: {}),
|
|
1813
|
-
...(typeof value.voiceReplyRequired === "boolean"
|
|
1814
|
-
? { voiceReplyRequired: value.voiceReplyRequired }
|
|
1815
|
-
: {}),
|
|
1816
|
-
};
|
|
1817
|
-
}
|
|
1818
1653
|
function parseQueueHandoffEnvelope(value, requestId, kind) {
|
|
1819
1654
|
let serializedPayloadBytes;
|
|
1820
1655
|
try {
|
|
@@ -1826,7 +1661,7 @@ function parseQueueHandoffEnvelope(value, requestId, kind) {
|
|
|
1826
1661
|
if (serializedPayloadBytes > TELEGRAM_QUEUE_HANDOFF_PAYLOAD_MAX_BYTES) {
|
|
1827
1662
|
return undefined;
|
|
1828
1663
|
}
|
|
1829
|
-
const payload =
|
|
1664
|
+
const payload = parseTelegramQueueHandoffPayload(value.payload);
|
|
1830
1665
|
if (!payload ||
|
|
1831
1666
|
typeof value.recipientInstanceId !== "string" ||
|
|
1832
1667
|
typeof value.recipientRegistrationGeneration !== "string" ||
|
|
@@ -2096,6 +1931,3 @@ function parseThreadTarget(value) {
|
|
|
2096
1931
|
? { chatId: target.chatId, threadId: target.threadId }
|
|
2097
1932
|
: undefined;
|
|
2098
1933
|
}
|
|
2099
|
-
function isRecord(value) {
|
|
2100
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2101
|
-
}
|
|
@@ -11,9 +11,6 @@ export interface TelegramChannelPostMediaIntent {
|
|
|
11
11
|
sizeBytes: number;
|
|
12
12
|
sha256: string;
|
|
13
13
|
}
|
|
14
|
-
export declare const TELEGRAM_CHANNEL_POST_MEDIA_MAX_BYTES: Record<TelegramChannelPostMediaKind, number>;
|
|
15
|
-
export declare const TELEGRAM_CHANNEL_POST_CAPTION_MAX_LENGTH = 1024;
|
|
16
|
-
export declare const TELEGRAM_CHANNEL_POST_MEDIA_FILE_NAME_MAX_LENGTH = 255;
|
|
17
14
|
/** Safe, content-free local validation failure for channel media publication intent. */
|
|
18
15
|
export declare class TelegramChannelPostValidationError extends Error {
|
|
19
16
|
constructor(message: string);
|
|
@@ -70,6 +67,7 @@ export type TelegramChannelPostRecord = TelegramChannelPostRecordBase & ({
|
|
|
70
67
|
} & TelegramPublishedChannelPostIdentity));
|
|
71
68
|
export interface TelegramChannelPostJournalStoreOptions {
|
|
72
69
|
path: string;
|
|
70
|
+
runtimeDir?: string;
|
|
73
71
|
profileName: string;
|
|
74
72
|
tokenSha256: string;
|
|
75
73
|
maxRecords?: number;
|
|
@@ -6,21 +6,23 @@
|
|
|
6
6
|
import { chmodSync, closeSync, constants, createReadStream, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { lstat } from "node:fs/promises";
|
|
8
8
|
import { basename, dirname } from "node:path";
|
|
9
|
+
import { getTelegramJournalPublicationPaths } from "./paths.js";
|
|
9
10
|
import { createHash, randomUUID } from "node:crypto";
|
|
10
11
|
import { Type } from "@sinclair/typebox";
|
|
11
12
|
import { renameTelegramPathWithRetry, withTelegramFileTransaction } from "./locks.js";
|
|
13
|
+
import { isWireRecord as isRecord, hasOnlyWireKeys as hasOnlyKeys, isNonNegativeWireInteger as isSafeTime, } from "./wire.js";
|
|
12
14
|
const CHANNEL_POST_JOURNAL_VERSION = 1;
|
|
13
15
|
const DEFAULT_MAX_RECORDS = 256;
|
|
14
16
|
const DEFAULT_MAX_BYTES = 4 * 1024 * 1024;
|
|
15
17
|
const MAX_ID_LENGTH = 256;
|
|
16
18
|
const MAX_MARKDOWN_LENGTH = 100_000;
|
|
17
19
|
const MAX_CHANNEL_TITLE_LENGTH = 255;
|
|
18
|
-
|
|
20
|
+
const TELEGRAM_CHANNEL_POST_MEDIA_MAX_BYTES = {
|
|
19
21
|
photo: 10 * 1024 * 1024,
|
|
20
22
|
video: 50 * 1024 * 1024,
|
|
21
23
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
const TELEGRAM_CHANNEL_POST_CAPTION_MAX_LENGTH = 1024;
|
|
25
|
+
const TELEGRAM_CHANNEL_POST_MEDIA_FILE_NAME_MAX_LENGTH = 255;
|
|
24
26
|
/** Safe, content-free local validation failure for channel media publication intent. */
|
|
25
27
|
export class TelegramChannelPostValidationError extends Error {
|
|
26
28
|
constructor(message) {
|
|
@@ -195,16 +197,6 @@ export function registerTelegramChannelPostListTool(pi, deps) {
|
|
|
195
197
|
},
|
|
196
198
|
});
|
|
197
199
|
}
|
|
198
|
-
function isRecord(value) {
|
|
199
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
200
|
-
}
|
|
201
|
-
function hasOnlyKeys(value, keys) {
|
|
202
|
-
const allowed = new Set(keys);
|
|
203
|
-
return Object.keys(value).every(key => allowed.has(key));
|
|
204
|
-
}
|
|
205
|
-
function isSafeTime(value) {
|
|
206
|
-
return Number.isSafeInteger(value) && value >= 0;
|
|
207
|
-
}
|
|
208
200
|
function normalizeChannel(value) {
|
|
209
201
|
if (Number.isSafeInteger(value) && value < 0)
|
|
210
202
|
return value;
|
|
@@ -312,7 +304,21 @@ function validateRecord(value) {
|
|
|
312
304
|
}
|
|
313
305
|
throw new TelegramChannelPostJournalError("invalid", "Telegram channel post journal contains an invalid state.");
|
|
314
306
|
}
|
|
307
|
+
function parseTelegramChannelPostJournalFile(value, profileName, tokenSha256) {
|
|
308
|
+
if (!isRecord(value) || !hasOnlyKeys(value, ["version", "profile", "tokenSha256", "records"]) ||
|
|
309
|
+
value.version !== CHANNEL_POST_JOURNAL_VERSION || value.profile !== profileName ||
|
|
310
|
+
value.tokenSha256 !== tokenSha256 || !Array.isArray(value.records)) {
|
|
311
|
+
throw new TelegramChannelPostJournalError("conflict", "Telegram channel post journal identity or schema does not match.");
|
|
312
|
+
}
|
|
313
|
+
const records = value.records.map(validateRecord);
|
|
314
|
+
if (new Set(records.map(record => record.operationId)).size !== records.length) {
|
|
315
|
+
throw new TelegramChannelPostJournalError("invalid", "Telegram channel post journal contains duplicate operation IDs.");
|
|
316
|
+
}
|
|
317
|
+
return { version: CHANNEL_POST_JOURNAL_VERSION, profile: profileName, tokenSha256, records };
|
|
318
|
+
}
|
|
315
319
|
export function createTelegramChannelPostJournalStore(options) {
|
|
320
|
+
options = { ...options };
|
|
321
|
+
const publicationPaths = getTelegramJournalPublicationPaths(options.path, options.runtimeDir);
|
|
316
322
|
const maxRecords = options.maxRecords ?? DEFAULT_MAX_RECORDS;
|
|
317
323
|
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
318
324
|
const now = options.getNowMs ?? Date.now;
|
|
@@ -348,17 +354,7 @@ export function createTelegramChannelPostJournalStore(options) {
|
|
|
348
354
|
throw new TelegramChannelPostJournalError("conflict", "Telegram channel post journal changed during inspection.");
|
|
349
355
|
}
|
|
350
356
|
const value = JSON.parse(readFileSync(fd, "utf8"));
|
|
351
|
-
|
|
352
|
-
value.version !== CHANNEL_POST_JOURNAL_VERSION || value.profile !== options.profileName ||
|
|
353
|
-
value.tokenSha256 !== options.tokenSha256 || !Array.isArray(value.records)) {
|
|
354
|
-
throw new TelegramChannelPostJournalError("conflict", "Telegram channel post journal identity or schema does not match.");
|
|
355
|
-
}
|
|
356
|
-
const records = value.records.map(validateRecord);
|
|
357
|
-
if (new Set(records.map(record => record.operationId)).size !== records.length) {
|
|
358
|
-
throw new TelegramChannelPostJournalError("invalid", "Telegram channel post journal contains duplicate operation IDs.");
|
|
359
|
-
}
|
|
360
|
-
return { version: CHANNEL_POST_JOURNAL_VERSION, profile: options.profileName,
|
|
361
|
-
tokenSha256: options.tokenSha256, records };
|
|
357
|
+
return parseTelegramChannelPostJournalFile(value, options.profileName, options.tokenSha256);
|
|
362
358
|
}
|
|
363
359
|
catch (error) {
|
|
364
360
|
if (error instanceof TelegramChannelPostJournalError)
|
|
@@ -378,8 +374,9 @@ export function createTelegramChannelPostJournalStore(options) {
|
|
|
378
374
|
if (Buffer.byteLength(serialized) > maxBytes) {
|
|
379
375
|
throw new TelegramChannelPostJournalError("capacity", "Telegram channel post journal byte limit reached.");
|
|
380
376
|
}
|
|
381
|
-
const temporaryPath = `${
|
|
377
|
+
const temporaryPath = `${publicationPaths.temporaryBasePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
382
378
|
mkdirSync(dirname(options.path), { recursive: true, mode: 0o700 });
|
|
379
|
+
mkdirSync(dirname(temporaryPath), { recursive: true, mode: 0o700 });
|
|
383
380
|
try {
|
|
384
381
|
writeFileSync(temporaryPath, serialized, { encoding: "utf8", mode: 0o600 });
|
|
385
382
|
chmodSync(temporaryPath, 0o600);
|
|
@@ -397,7 +394,7 @@ export function createTelegramChannelPostJournalStore(options) {
|
|
|
397
394
|
};
|
|
398
395
|
const mutate = (operation) => {
|
|
399
396
|
try {
|
|
400
|
-
return withTelegramFileTransaction(
|
|
397
|
+
return withTelegramFileTransaction(publicationPaths.transactionPath, () => operation(read()));
|
|
401
398
|
}
|
|
402
399
|
catch (error) {
|
|
403
400
|
if (error instanceof TelegramChannelPostJournalError)
|
|
@@ -52,15 +52,10 @@ export interface CommandTemplateExecResult {
|
|
|
52
52
|
}
|
|
53
53
|
export type CommandTemplateRiskLabel = "risk.shell" | "risk.eval" | "risk.broad_fs_write" | "risk.destructive_fs" | "risk.network" | "risk.external_side_effect" | "risk.long_running" | "risk.platform_specific" | "risk.secret_touching";
|
|
54
54
|
export declare function normalizeCommandTemplateConfig(config: CommandTemplateConfig): CommandTemplateObjectConfig;
|
|
55
|
-
export declare function resolveInheritedDefaultReferences(ownDefaults: Record<string, unknown> | undefined, inheritedDefaults: Record<string, unknown> | undefined, runtimeValues?: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
56
|
-
export declare function resolveCommandTemplateRepeat(value: number | string | undefined, values?: Record<string, unknown>): number | undefined;
|
|
57
|
-
export declare function getCommandTemplateRepeatDefaults(index: number, repeat: number): Record<string, string>;
|
|
58
55
|
export declare function expandCommandTemplateConfigs(config: CommandTemplateConfig, inherited?: Pick<CommandTemplateObjectConfig, "args" | "defaults">): CommandTemplateLeafConfig[];
|
|
59
56
|
export declare function getCommandTemplateWarnings(config: CommandTemplateConfig): string[];
|
|
60
57
|
export declare function getCommandTemplateRiskLabels(config: CommandTemplateConfig): CommandTemplateRiskLabel[];
|
|
61
|
-
export declare function getCommandTemplateDefaults(config: CommandTemplateConfig | undefined): Record<string, string>;
|
|
62
58
|
export declare function splitCommandTemplate(input: string): string[];
|
|
63
|
-
export declare function expandCommandTemplateExecutable(command: string, cwd: string): string;
|
|
64
59
|
export declare function shouldRunCommandTemplateNode(value: boolean | string | undefined, values: Record<string, unknown>): boolean;
|
|
65
60
|
export declare function substituteCommandTemplateToken(token: string, values: Record<string, unknown>, missingLabel?: string, depth?: number): string;
|
|
66
61
|
export declare function execCommandTemplate(command: string, args: string[], options?: CommandTemplateExecOptions): Promise<CommandTemplateExecResult>;
|
|
@@ -43,7 +43,7 @@ function normalizeCommandTemplateDefaults(defaults) {
|
|
|
43
43
|
}
|
|
44
44
|
return normalized;
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
function resolveInheritedDefaultReferences(ownDefaults, inheritedDefaults, runtimeValues = {}) {
|
|
47
47
|
if (!ownDefaults || !inheritedDefaults)
|
|
48
48
|
return ownDefaults;
|
|
49
49
|
const resolved = { ...ownDefaults };
|
|
@@ -59,7 +59,7 @@ export function resolveInheritedDefaultReferences(ownDefaults, inheritedDefaults
|
|
|
59
59
|
}
|
|
60
60
|
return resolved;
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
function resolveCommandTemplateRepeat(value, values = {}) {
|
|
63
63
|
if (value === undefined)
|
|
64
64
|
return undefined;
|
|
65
65
|
if (typeof value === "number") {
|
|
@@ -228,7 +228,7 @@ function getLeafCommandTemplateWarnings(config) {
|
|
|
228
228
|
function pad(value, width) {
|
|
229
229
|
return String(value).padStart(width, "0");
|
|
230
230
|
}
|
|
231
|
-
|
|
231
|
+
function getCommandTemplateRepeatDefaults(index, repeat) {
|
|
232
232
|
const prev = (index - 1 + repeat) % repeat;
|
|
233
233
|
const next = (index + 1) % repeat;
|
|
234
234
|
const values = {
|
|
@@ -329,7 +329,7 @@ function parseCommandTemplatePlaceholderContent(content) {
|
|
|
329
329
|
...(match[2] !== undefined ? { inlineDefault: match[2] } : {}),
|
|
330
330
|
};
|
|
331
331
|
}
|
|
332
|
-
|
|
332
|
+
function getCommandTemplateDefaults(config) {
|
|
333
333
|
const normalizedConfig = config
|
|
334
334
|
? normalizeCommandTemplateConfig(config)
|
|
335
335
|
: undefined;
|
|
@@ -406,7 +406,7 @@ export function splitCommandTemplate(input) {
|
|
|
406
406
|
words.push(current);
|
|
407
407
|
return words;
|
|
408
408
|
}
|
|
409
|
-
|
|
409
|
+
function expandCommandTemplateExecutable(command, cwd) {
|
|
410
410
|
if (command === "~")
|
|
411
411
|
return homedir();
|
|
412
412
|
if (command.startsWith("~/"))
|