@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
|
@@ -8,12 +8,18 @@ import { chmodSync, closeSync, constants, createReadStream, fstatSync, lstatSync
|
|
|
8
8
|
readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
9
9
|
import { lstat } from "node:fs/promises";
|
|
10
10
|
import { basename, dirname } from "node:path";
|
|
11
|
+
import { getTelegramJournalPublicationPaths } from "./paths.ts";
|
|
11
12
|
import { createHash, randomUUID } from "node:crypto";
|
|
12
13
|
|
|
13
14
|
import { Type } from "@sinclair/typebox";
|
|
14
15
|
|
|
15
16
|
import { renameTelegramPathWithRetry, withTelegramFileTransaction } from "./locks.ts";
|
|
16
17
|
import type { ExtensionAPI } from "./pi.ts";
|
|
18
|
+
import {
|
|
19
|
+
isWireRecord as isRecord,
|
|
20
|
+
hasOnlyWireKeys as hasOnlyKeys,
|
|
21
|
+
isNonNegativeWireInteger as isSafeTime,
|
|
22
|
+
} from "./wire.ts";
|
|
17
23
|
|
|
18
24
|
const CHANNEL_POST_JOURNAL_VERSION = 1;
|
|
19
25
|
const DEFAULT_MAX_RECORDS = 256;
|
|
@@ -31,12 +37,12 @@ export interface TelegramChannelPostMediaIntent {
|
|
|
31
37
|
sha256: string;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
const TELEGRAM_CHANNEL_POST_MEDIA_MAX_BYTES: Record<TelegramChannelPostMediaKind, number> = {
|
|
35
41
|
photo: 10 * 1024 * 1024,
|
|
36
42
|
video: 50 * 1024 * 1024,
|
|
37
43
|
};
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
const TELEGRAM_CHANNEL_POST_CAPTION_MAX_LENGTH = 1024;
|
|
45
|
+
const TELEGRAM_CHANNEL_POST_MEDIA_FILE_NAME_MAX_LENGTH = 255;
|
|
40
46
|
|
|
41
47
|
/** Safe, content-free local validation failure for channel media publication intent. */
|
|
42
48
|
export class TelegramChannelPostValidationError extends Error {
|
|
@@ -195,6 +201,7 @@ interface TelegramChannelPostJournalFile {
|
|
|
195
201
|
|
|
196
202
|
export interface TelegramChannelPostJournalStoreOptions {
|
|
197
203
|
path: string;
|
|
204
|
+
runtimeDir?: string;
|
|
198
205
|
profileName: string;
|
|
199
206
|
tokenSha256: string;
|
|
200
207
|
maxRecords?: number;
|
|
@@ -329,19 +336,6 @@ export function registerTelegramChannelPostListTool(
|
|
|
329
336
|
});
|
|
330
337
|
}
|
|
331
338
|
|
|
332
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
333
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function hasOnlyKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {
|
|
337
|
-
const allowed = new Set(keys);
|
|
338
|
-
return Object.keys(value).every(key => allowed.has(key));
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function isSafeTime(value: unknown): value is number {
|
|
342
|
-
return Number.isSafeInteger(value) && (value as number) >= 0;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
339
|
function normalizeChannel(value: unknown): TelegramChannelPostAddress {
|
|
346
340
|
if (Number.isSafeInteger(value) && (value as number) < 0) return value as number;
|
|
347
341
|
if (typeof value === "string" && /^@[A-Za-z0-9_]{5,32}$/u.test(value)) {
|
|
@@ -454,9 +448,24 @@ function validateRecord(value: unknown): TelegramChannelPostRecord {
|
|
|
454
448
|
throw new TelegramChannelPostJournalError("invalid", "Telegram channel post journal contains an invalid state.");
|
|
455
449
|
}
|
|
456
450
|
|
|
451
|
+
function parseTelegramChannelPostJournalFile(value: unknown, profileName: string, tokenSha256: string): TelegramChannelPostJournalFile {
|
|
452
|
+
if (!isRecord(value) || !hasOnlyKeys(value, ["version", "profile", "tokenSha256", "records"]) ||
|
|
453
|
+
value.version !== CHANNEL_POST_JOURNAL_VERSION || value.profile !== profileName ||
|
|
454
|
+
value.tokenSha256 !== tokenSha256 || !Array.isArray(value.records)) {
|
|
455
|
+
throw new TelegramChannelPostJournalError("conflict", "Telegram channel post journal identity or schema does not match.");
|
|
456
|
+
}
|
|
457
|
+
const records = value.records.map(validateRecord);
|
|
458
|
+
if (new Set(records.map(record => record.operationId)).size !== records.length) {
|
|
459
|
+
throw new TelegramChannelPostJournalError("invalid", "Telegram channel post journal contains duplicate operation IDs.");
|
|
460
|
+
}
|
|
461
|
+
return { version: CHANNEL_POST_JOURNAL_VERSION, profile: profileName, tokenSha256, records };
|
|
462
|
+
}
|
|
463
|
+
|
|
457
464
|
export function createTelegramChannelPostJournalStore(
|
|
458
465
|
options: TelegramChannelPostJournalStoreOptions,
|
|
459
466
|
): TelegramChannelPostJournalStore {
|
|
467
|
+
options = { ...options };
|
|
468
|
+
const publicationPaths = getTelegramJournalPublicationPaths(options.path, options.runtimeDir);
|
|
460
469
|
const maxRecords = options.maxRecords ?? DEFAULT_MAX_RECORDS;
|
|
461
470
|
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
462
471
|
const now = options.getNowMs ?? Date.now;
|
|
@@ -491,17 +500,7 @@ export function createTelegramChannelPostJournalStore(
|
|
|
491
500
|
throw new TelegramChannelPostJournalError("conflict", "Telegram channel post journal changed during inspection.");
|
|
492
501
|
}
|
|
493
502
|
const value = JSON.parse(readFileSync(fd, "utf8")) as unknown;
|
|
494
|
-
|
|
495
|
-
value.version !== CHANNEL_POST_JOURNAL_VERSION || value.profile !== options.profileName ||
|
|
496
|
-
value.tokenSha256 !== options.tokenSha256 || !Array.isArray(value.records)) {
|
|
497
|
-
throw new TelegramChannelPostJournalError("conflict", "Telegram channel post journal identity or schema does not match.");
|
|
498
|
-
}
|
|
499
|
-
const records = value.records.map(validateRecord);
|
|
500
|
-
if (new Set(records.map(record => record.operationId)).size !== records.length) {
|
|
501
|
-
throw new TelegramChannelPostJournalError("invalid", "Telegram channel post journal contains duplicate operation IDs.");
|
|
502
|
-
}
|
|
503
|
-
return { version: CHANNEL_POST_JOURNAL_VERSION, profile: options.profileName,
|
|
504
|
-
tokenSha256: options.tokenSha256, records };
|
|
503
|
+
return parseTelegramChannelPostJournalFile(value, options.profileName, options.tokenSha256);
|
|
505
504
|
} catch (error) {
|
|
506
505
|
if (error instanceof TelegramChannelPostJournalError) throw error;
|
|
507
506
|
throw new TelegramChannelPostJournalError("io", "Could not read Telegram channel post journal.", error);
|
|
@@ -517,8 +516,9 @@ export function createTelegramChannelPostJournalStore(
|
|
|
517
516
|
if (Buffer.byteLength(serialized) > maxBytes) {
|
|
518
517
|
throw new TelegramChannelPostJournalError("capacity", "Telegram channel post journal byte limit reached.");
|
|
519
518
|
}
|
|
520
|
-
const temporaryPath = `${
|
|
519
|
+
const temporaryPath = `${publicationPaths.temporaryBasePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
521
520
|
mkdirSync(dirname(options.path), { recursive: true, mode: 0o700 });
|
|
521
|
+
mkdirSync(dirname(temporaryPath), { recursive: true, mode: 0o700 });
|
|
522
522
|
try {
|
|
523
523
|
writeFileSync(temporaryPath, serialized, { encoding: "utf8", mode: 0o600 });
|
|
524
524
|
chmodSync(temporaryPath, 0o600);
|
|
@@ -532,7 +532,7 @@ export function createTelegramChannelPostJournalStore(
|
|
|
532
532
|
};
|
|
533
533
|
const mutate = <T>(operation: (file: TelegramChannelPostJournalFile) => T): T => {
|
|
534
534
|
try {
|
|
535
|
-
return withTelegramFileTransaction(
|
|
535
|
+
return withTelegramFileTransaction(publicationPaths.transactionPath, () => operation(read()));
|
|
536
536
|
} catch (error) {
|
|
537
537
|
if (error instanceof TelegramChannelPostJournalError) throw error;
|
|
538
538
|
throw new TelegramChannelPostJournalError("io", "Telegram channel post journal mutation failed.", error);
|
|
@@ -121,7 +121,7 @@ function normalizeCommandTemplateDefaults(
|
|
|
121
121
|
return normalized;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
function resolveInheritedDefaultReferences(
|
|
125
125
|
ownDefaults: Record<string, unknown> | undefined,
|
|
126
126
|
inheritedDefaults: Record<string, unknown> | undefined,
|
|
127
127
|
runtimeValues: Record<string, unknown> = {},
|
|
@@ -142,7 +142,7 @@ export function resolveInheritedDefaultReferences(
|
|
|
142
142
|
return resolved;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
function resolveCommandTemplateRepeat(
|
|
146
146
|
value: number | string | undefined,
|
|
147
147
|
values: Record<string, unknown> = {},
|
|
148
148
|
): number | undefined {
|
|
@@ -367,7 +367,7 @@ function pad(value: number, width: number): string {
|
|
|
367
367
|
return String(value).padStart(width, "0");
|
|
368
368
|
}
|
|
369
369
|
|
|
370
|
-
|
|
370
|
+
function getCommandTemplateRepeatDefaults(
|
|
371
371
|
index: number,
|
|
372
372
|
repeat: number,
|
|
373
373
|
): Record<string, string> {
|
|
@@ -516,7 +516,7 @@ function parseCommandTemplatePlaceholderContent(
|
|
|
516
516
|
};
|
|
517
517
|
}
|
|
518
518
|
|
|
519
|
-
|
|
519
|
+
function getCommandTemplateDefaults(
|
|
520
520
|
config: CommandTemplateConfig | undefined,
|
|
521
521
|
): Record<string, string> {
|
|
522
522
|
const normalizedConfig = config
|
|
@@ -588,7 +588,7 @@ export function splitCommandTemplate(input: string): string[] {
|
|
|
588
588
|
return words;
|
|
589
589
|
}
|
|
590
590
|
|
|
591
|
-
|
|
591
|
+
function expandCommandTemplateExecutable(
|
|
592
592
|
command: string,
|
|
593
593
|
cwd: string,
|
|
594
594
|
): string {
|
|
@@ -91,11 +91,11 @@ function getOrCreateTelegramCommandRegistry(): TelegramExtensionCommandRegistry
|
|
|
91
91
|
return registry;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
function normalizeTelegramExtensionCommandName(name: string): string {
|
|
95
95
|
return name.trim().replace(/^\/+/, "").toLowerCase();
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
function isTelegramExtensionCommandName(name: string): boolean {
|
|
99
99
|
return TELEGRAM_BOT_COMMAND_NAME_PATTERN.test(name);
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -144,7 +144,7 @@ export function registerTelegramCommand(
|
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
function getTelegramExtensionCommands(): RegisteredTelegramExtensionCommand[] {
|
|
148
148
|
return Array.from(
|
|
149
149
|
getOrCreateTelegramCommandRegistry().commands.values(),
|
|
150
150
|
).sort((a, b) => a.order - b.order || a.name.localeCompare(b.name));
|
|
@@ -181,7 +181,7 @@ export const TELEGRAM_COMMAND_EMOJI = {
|
|
|
181
181
|
|
|
182
182
|
export type TelegramCommandEmojiName = keyof typeof TELEGRAM_COMMAND_EMOJI;
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
function getTelegramCommandEmoji(
|
|
185
185
|
command: TelegramCommandEmojiName,
|
|
186
186
|
): string {
|
|
187
187
|
return TELEGRAM_COMMAND_EMOJI[command];
|
|
@@ -235,12 +235,12 @@ export function formatTelegramAutomaticThreadDisplayNameRestoredHeading(
|
|
|
235
235
|
return `<b>✅ Automatic Thread display name restored as <i>${escapeHtml(name)}</i>.</b>`;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
const TELEGRAM_COMPACTION_STARTED_TEXT =
|
|
239
239
|
formatTelegramInformationHeading(
|
|
240
240
|
getTelegramCommandEmoji("compact"),
|
|
241
241
|
"Compaction started.",
|
|
242
242
|
);
|
|
243
|
-
|
|
243
|
+
const TELEGRAM_COMPACTION_COMPLETED_TEXT =
|
|
244
244
|
formatTelegramInformationHeading("✅", "Compaction completed.");
|
|
245
245
|
export const TELEGRAM_COMPACTION_STARTED_MARKDOWN =
|
|
246
246
|
`**${formatTelegramCommandEmojiPrefix("compact")}Compaction started.**`;
|
|
@@ -254,7 +254,7 @@ function formatTelegramBotCommandDescription(
|
|
|
254
254
|
return `${formatTelegramCommandEmojiPrefix(command)}${description}`;
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
|
|
257
|
+
const TELEGRAM_BUILTIN_BOT_COMMANDS: readonly TelegramBotCommandDefinition[] =
|
|
258
258
|
[
|
|
259
259
|
{
|
|
260
260
|
command: "start",
|
|
@@ -1504,7 +1504,7 @@ export async function handleTelegramNextCommand(deps: {
|
|
|
1504
1504
|
deps.updateStatus();
|
|
1505
1505
|
}
|
|
1506
1506
|
|
|
1507
|
-
|
|
1507
|
+
async function handleTelegramContinueCommand<TMessage, TContext>(
|
|
1508
1508
|
message: TMessage,
|
|
1509
1509
|
ctx: TContext,
|
|
1510
1510
|
deps: {
|
|
@@ -1530,7 +1530,7 @@ function dispatchNextQueuedTelegramTurnAfterCompact(
|
|
|
1530
1530
|
deps.dispatchNextQueuedTelegramTurn();
|
|
1531
1531
|
}
|
|
1532
1532
|
|
|
1533
|
-
|
|
1533
|
+
function buildTelegramNewConfirmationReplyMarkup(): TelegramCompactConfirmationReplyMarkup {
|
|
1534
1534
|
return {
|
|
1535
1535
|
inline_keyboard: [
|
|
1536
1536
|
[
|
|
@@ -1541,7 +1541,7 @@ export function buildTelegramNewConfirmationReplyMarkup(): TelegramCompactConfir
|
|
|
1541
1541
|
};
|
|
1542
1542
|
}
|
|
1543
1543
|
|
|
1544
|
-
|
|
1544
|
+
function getTelegramNewConfirmationHtml(): string {
|
|
1545
1545
|
return "<b>Start a new session?</b>";
|
|
1546
1546
|
}
|
|
1547
1547
|
|
|
@@ -1588,7 +1588,7 @@ export async function handleTelegramNewConfirmationCallback<TContext>(
|
|
|
1588
1588
|
return true;
|
|
1589
1589
|
}
|
|
1590
1590
|
|
|
1591
|
-
|
|
1591
|
+
function buildTelegramCompactConfirmationReplyMarkup(): TelegramCompactConfirmationReplyMarkup {
|
|
1592
1592
|
return {
|
|
1593
1593
|
inline_keyboard: [
|
|
1594
1594
|
[
|
|
@@ -1599,11 +1599,11 @@ export function buildTelegramCompactConfirmationReplyMarkup(): TelegramCompactCo
|
|
|
1599
1599
|
};
|
|
1600
1600
|
}
|
|
1601
1601
|
|
|
1602
|
-
|
|
1602
|
+
function getTelegramCompactConfirmationHtml(): string {
|
|
1603
1603
|
return "<b>Compact session?</b>";
|
|
1604
1604
|
}
|
|
1605
1605
|
|
|
1606
|
-
|
|
1606
|
+
async function openTelegramCompactConfirmation(
|
|
1607
1607
|
target: TelegramCommandMessageTarget,
|
|
1608
1608
|
deps: TelegramCompactConfirmationDeps,
|
|
1609
1609
|
): Promise<void> {
|
|
@@ -2373,7 +2373,7 @@ export const TELEGRAM_INTERNAL_COMMAND_DESCRIPTION =
|
|
|
2373
2373
|
export const TELEGRAM_INTERNAL_MANUAL_USE_MESSAGE =
|
|
2374
2374
|
"This internal Telegram command cannot be run manually.";
|
|
2375
2375
|
|
|
2376
|
-
|
|
2376
|
+
function delayTelegramSessionAction(delayMs: number): Promise<void> {
|
|
2377
2377
|
return new Promise<void>((resolve) => setTimeout(resolve, delayMs));
|
|
2378
2378
|
}
|
|
2379
2379
|
|
|
@@ -2433,7 +2433,7 @@ export async function settleTelegramSessionReplacement(
|
|
|
2433
2433
|
return "stale";
|
|
2434
2434
|
}
|
|
2435
2435
|
|
|
2436
|
-
|
|
2436
|
+
function createTelegramSessionReplacementSettlementRuntime<TContext>(deps: {
|
|
2437
2437
|
resolve: (ctx: TContext) => TelegramSessionReplacementSettlementDeps | undefined;
|
|
2438
2438
|
onResult?: (result: "none" | "settled" | "expired" | "failed" | "stale") => void;
|
|
2439
2439
|
onError?: (error: unknown) => void;
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
export { TELEGRAM_DEFAULT_PROFILE_NAME } from "./paths.ts";
|
|
25
25
|
|
|
26
26
|
import type { CommandTemplateObjectConfig } from "./command-templates.ts";
|
|
27
|
+
import { isWireRecord as isPlainConfigRecord } from "./wire.ts";
|
|
27
28
|
import type { TelegramInboundHandlerConfig } from "./inbound.ts";
|
|
28
29
|
import { withTelegramFileTransaction } from "./locks.ts";
|
|
29
30
|
|
|
@@ -75,7 +76,7 @@ export type TelegramBotTokenReference =
|
|
|
75
76
|
* environment-variable references. Any other `$`-prefixed value is malformed
|
|
76
77
|
* rather than a literal secret so a broken reference fails closed.
|
|
77
78
|
*/
|
|
78
|
-
|
|
79
|
+
function getTelegramBotTokenReference(
|
|
79
80
|
value: string | undefined,
|
|
80
81
|
): TelegramBotTokenReference | undefined {
|
|
81
82
|
const trimmed = value?.trim();
|
|
@@ -115,8 +116,6 @@ export function getTelegramBotTokenDiagnostic(
|
|
|
115
116
|
return `Telegram bot token environment variable ${reference.variable} is not set.`;
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
export type TelegramOutboundCommandTemplateConfig =
|
|
119
|
-
string | CommandTemplateObjectConfig;
|
|
120
119
|
export interface TelegramOutboundHandlerConfig extends CommandTemplateObjectConfig {
|
|
121
120
|
type?: string;
|
|
122
121
|
match?: string | string[];
|
|
@@ -465,10 +464,6 @@ export async function writeTelegramConfig(
|
|
|
465
464
|
await chmod(configPath, 0o600);
|
|
466
465
|
}
|
|
467
466
|
|
|
468
|
-
function isPlainConfigRecord(value: unknown): value is Record<string, unknown> {
|
|
469
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
467
|
function cloneTelegramConfig<T>(value: T): T {
|
|
473
468
|
return structuredClone(value);
|
|
474
469
|
}
|
|
@@ -963,7 +958,7 @@ export function createTelegramConfigStore(
|
|
|
963
958
|
};
|
|
964
959
|
}
|
|
965
960
|
|
|
966
|
-
|
|
961
|
+
function createTelegramDraftPreviewsChecker(
|
|
967
962
|
configStore: Pick<TelegramConfigStore, "get">,
|
|
968
963
|
): () => boolean {
|
|
969
964
|
return () => {
|
|
@@ -977,7 +972,7 @@ export function createTelegramDraftPreviewsChecker(
|
|
|
977
972
|
};
|
|
978
973
|
}
|
|
979
974
|
|
|
980
|
-
|
|
975
|
+
function createTelegramDraftPreviewsSetter(
|
|
981
976
|
configStore: TelegramMutableConfigStore,
|
|
982
977
|
): (enabled: boolean) => Promise<void> {
|
|
983
978
|
return async (enabled) => {
|
|
@@ -996,7 +991,7 @@ export function createTelegramDraftPreviewsSetter(
|
|
|
996
991
|
};
|
|
997
992
|
}
|
|
998
993
|
|
|
999
|
-
|
|
994
|
+
function createTelegramAssistantRenderingModeGetter(
|
|
1000
995
|
configStore: Pick<TelegramConfigStore, "get">,
|
|
1001
996
|
): () => TelegramAssistantRenderingMode {
|
|
1002
997
|
return () => {
|
|
@@ -1006,7 +1001,7 @@ export function createTelegramAssistantRenderingModeGetter(
|
|
|
1006
1001
|
};
|
|
1007
1002
|
}
|
|
1008
1003
|
|
|
1009
|
-
|
|
1004
|
+
function createTelegramAssistantRenderingModeSetter(
|
|
1010
1005
|
configStore: TelegramMutableConfigStore,
|
|
1011
1006
|
): (mode: TelegramAssistantRenderingMode) => Promise<void> {
|
|
1012
1007
|
return async (mode) => {
|
|
@@ -1022,7 +1017,7 @@ export function createTelegramAssistantRenderingModeSetter(
|
|
|
1022
1017
|
};
|
|
1023
1018
|
}
|
|
1024
1019
|
|
|
1025
|
-
|
|
1020
|
+
function createTelegramActivityVerbosityGetter(
|
|
1026
1021
|
configStore: Pick<TelegramConfigStore, "get">,
|
|
1027
1022
|
): () => TelegramActivityVerbosity {
|
|
1028
1023
|
return () => {
|
|
@@ -1044,13 +1039,13 @@ export function createTelegramActivityVerbosityGetter(
|
|
|
1044
1039
|
};
|
|
1045
1040
|
}
|
|
1046
1041
|
|
|
1047
|
-
|
|
1042
|
+
function createTelegramActivityVerbosityRefresher(
|
|
1048
1043
|
configStore: TelegramMutableConfigStore,
|
|
1049
1044
|
): () => Promise<void> {
|
|
1050
1045
|
return () => loadLatestTelegramConfig(configStore);
|
|
1051
1046
|
}
|
|
1052
1047
|
|
|
1053
|
-
|
|
1048
|
+
function createTelegramActivityVerbositySetter(
|
|
1054
1049
|
configStore: TelegramMutableConfigStore,
|
|
1055
1050
|
): (verbosity: TelegramActivityVerbosity) => Promise<void> {
|
|
1056
1051
|
return async (verbosity) => {
|
|
@@ -1210,13 +1205,13 @@ export function createTelegramProactivePushTargetGetter(deps: {
|
|
|
1210
1205
|
};
|
|
1211
1206
|
}
|
|
1212
1207
|
|
|
1213
|
-
|
|
1208
|
+
function createTelegramAutomaticThreadCleanupChecker(
|
|
1214
1209
|
configStore: Pick<TelegramConfigStore, "get">,
|
|
1215
1210
|
): () => boolean {
|
|
1216
1211
|
return () => configStore.get().threads?.automaticCleanup ?? true;
|
|
1217
1212
|
}
|
|
1218
1213
|
|
|
1219
|
-
|
|
1214
|
+
function createTelegramAutomaticThreadCleanupResolver(
|
|
1220
1215
|
configStore: TelegramMutableConfigStore,
|
|
1221
1216
|
): () => Promise<boolean> {
|
|
1222
1217
|
return async () => {
|
|
@@ -1230,7 +1225,7 @@ export function createTelegramAutomaticThreadCleanupResolver(
|
|
|
1230
1225
|
};
|
|
1231
1226
|
}
|
|
1232
1227
|
|
|
1233
|
-
|
|
1228
|
+
function createTelegramAutomaticThreadCleanupSetter(
|
|
1234
1229
|
configStore: TelegramMutableConfigStore,
|
|
1235
1230
|
): (enabled: boolean) => Promise<void> {
|
|
1236
1231
|
return async (enabled) => {
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
renderTelegramMessage,
|
|
15
15
|
} from "./replies.ts";
|
|
16
16
|
import {
|
|
17
|
+
areTelegramTargetsEqual as areDeliveryTargetsEqual,
|
|
17
18
|
getTelegramTargetThreadParams,
|
|
18
19
|
type TelegramTarget,
|
|
19
20
|
} from "./target.ts";
|
|
@@ -262,7 +263,7 @@ function failure<T>(
|
|
|
262
263
|
: { ok: false, reason, message, partial, ...retry };
|
|
263
264
|
}
|
|
264
265
|
|
|
265
|
-
|
|
266
|
+
function classifyTelegramDeliveryTransportError(error: unknown): {
|
|
266
267
|
reason: Extract<TelegramDeliveryFailureReason,
|
|
267
268
|
"commit-unknown" | "message-unavailable" | "rate-limited" |
|
|
268
269
|
"transport-retryable" | "transport-failed">;
|
|
@@ -374,13 +375,6 @@ export function isTelegramDeliveryExplicitTargetAuthorized(
|
|
|
374
375
|
});
|
|
375
376
|
}
|
|
376
377
|
|
|
377
|
-
function areDeliveryTargetsEqual(
|
|
378
|
-
left: TelegramDeliveryTarget,
|
|
379
|
-
right: TelegramDeliveryTarget,
|
|
380
|
-
): boolean {
|
|
381
|
-
return left.chatId === right.chatId && left.threadId === right.threadId;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
378
|
function cloneTarget(target: TelegramDeliveryTarget): TelegramDeliveryTarget {
|
|
385
379
|
return target.threadId === undefined
|
|
386
380
|
? { chatId: target.chatId }
|