@llblab/pi-telegram 0.27.12 → 0.29.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/AGENTS.md +152 -258
- package/BACKLOG.md +1 -169
- package/CHANGELOG.md +398 -443
- package/README.md +10 -7
- package/api/updates.ts +5 -0
- package/docs/architecture.md +73 -28
- package/docs/multi-instance-bus.md +23 -5
- package/docs/outbound.md +2 -2
- package/docs/public-api.md +8 -7
- package/docs/ui-style.md +6 -6
- package/docs/updates.md +29 -11
- package/index.ts +358 -246
- package/lib/activity-verbosity.ts +26 -0
- package/lib/bindings.ts +240 -5
- package/lib/bus-follower.ts +436 -238
- package/lib/bus-leader.ts +395 -42
- package/lib/bus.ts +994 -153
- package/lib/commands.ts +184 -30
- package/lib/config.ts +23 -2
- package/lib/journal.ts +3140 -0
- package/lib/lifecycle.ts +4 -0
- package/lib/locks.ts +4 -2
- package/lib/media.ts +71 -32
- package/lib/menu-queue.ts +31 -17
- package/lib/menu.ts +5 -3
- package/lib/model.ts +51 -24
- package/lib/ownership.ts +42 -7
- package/lib/paths.ts +35 -0
- package/lib/polling.ts +591 -106
- package/lib/prompts.ts +20 -89
- package/lib/queue.ts +732 -143
- package/lib/routing.ts +291 -64
- package/lib/runtime.ts +26 -10
- package/lib/skills.ts +21 -0
- package/lib/status.ts +257 -18
- package/lib/sync.ts +131 -5
- package/lib/telegram-api.ts +41 -11
- package/lib/text-groups.ts +75 -35
- package/lib/threads.ts +112 -4
- package/lib/turns.ts +79 -14
- package/lib/updates.ts +3771 -223
- package/package.json +7 -3
- package/scripts/check-downgrade.mjs +435 -0
- package/skills/button-console/SKILL.md +139 -0
- package/skills/telegram-bridge/SKILL.md +138 -0
package/lib/commands.ts
CHANGED
|
@@ -13,7 +13,9 @@ import type { TelegramBridgeStatusLineOptions } from "./status.ts";
|
|
|
13
13
|
import {
|
|
14
14
|
createTelegramControlItemBuilder,
|
|
15
15
|
createTelegramControlQueueController,
|
|
16
|
+
createTelegramQueueAdmissionReceipt,
|
|
16
17
|
type PendingTelegramControlItem,
|
|
18
|
+
type TelegramQueueAdmissionReceipt,
|
|
17
19
|
} from "./queue.ts";
|
|
18
20
|
|
|
19
21
|
export interface ParsedTelegramCommand {
|
|
@@ -282,7 +284,16 @@ export async function registerTelegramBotCommands(
|
|
|
282
284
|
export function createTelegramBotCommandRegistrar(
|
|
283
285
|
deps: TelegramBotCommandRegistrationDeps,
|
|
284
286
|
): () => Promise<void> {
|
|
285
|
-
|
|
287
|
+
let pending: Promise<void> | undefined;
|
|
288
|
+
return () => {
|
|
289
|
+
if (pending) return pending;
|
|
290
|
+
let request: Promise<void>;
|
|
291
|
+
request = registerTelegramBotCommands(deps).finally(() => {
|
|
292
|
+
if (pending === request) pending = undefined;
|
|
293
|
+
});
|
|
294
|
+
pending = request;
|
|
295
|
+
return request;
|
|
296
|
+
};
|
|
286
297
|
}
|
|
287
298
|
|
|
288
299
|
export interface TelegramBridgeCommandStartPollingOptions {
|
|
@@ -652,6 +663,7 @@ export interface TelegramCommandRuntimeMessage {
|
|
|
652
663
|
message_id: number;
|
|
653
664
|
message_thread_id?: number;
|
|
654
665
|
from?: { id?: number };
|
|
666
|
+
pi_telegram_source_update_id?: number;
|
|
655
667
|
}
|
|
656
668
|
|
|
657
669
|
export interface TelegramCommandMessageTarget {
|
|
@@ -673,6 +685,14 @@ export interface TelegramCommandTargetRuntimeDeps<TContext> {
|
|
|
673
685
|
controlType: TelegramControlCommandType,
|
|
674
686
|
statusSummary: string,
|
|
675
687
|
execute: (ctx: TContext) => Promise<void>,
|
|
688
|
+
admissionReceipts?: TelegramQueueAdmissionReceipt[],
|
|
689
|
+
onQueued?: (item: PendingTelegramControlItem<TContext>) => void,
|
|
690
|
+
) => void;
|
|
691
|
+
getAdmissionScope?: () => string | undefined;
|
|
692
|
+
getAdmissionJournalBinding?: () => string | undefined;
|
|
693
|
+
onControlQueued?: (
|
|
694
|
+
message: TelegramCommandRuntimeMessage,
|
|
695
|
+
receipt: TelegramQueueAdmissionReceipt,
|
|
676
696
|
) => void;
|
|
677
697
|
showStatus: (
|
|
678
698
|
chatId: number,
|
|
@@ -737,6 +757,7 @@ export interface TelegramCommandControlQueueRuntimeDeps<TContext> {
|
|
|
737
757
|
replyToMessageId: number;
|
|
738
758
|
controlType: TelegramControlCommandType;
|
|
739
759
|
statusSummary: string;
|
|
760
|
+
admissionReceipts?: TelegramQueueAdmissionReceipt[];
|
|
740
761
|
execute: (ctx: TContext) => Promise<void>;
|
|
741
762
|
}) => PendingTelegramControlItem<TContext>;
|
|
742
763
|
appendControlItem: (
|
|
@@ -766,22 +787,34 @@ export function createTelegramCommandControlEnqueueAdapter<TContext>(deps: {
|
|
|
766
787
|
replyToMessageId: number;
|
|
767
788
|
controlType: TelegramControlCommandType;
|
|
768
789
|
statusSummary: string;
|
|
790
|
+
admissionReceipts?: TelegramQueueAdmissionReceipt[];
|
|
769
791
|
execute: (ctx: TContext) => Promise<void>;
|
|
770
792
|
}) => PendingTelegramControlItem<TContext>;
|
|
771
793
|
enqueueControlItem: (
|
|
772
794
|
item: PendingTelegramControlItem<TContext>,
|
|
773
795
|
ctx: TContext,
|
|
796
|
+
onQueued?: (item: PendingTelegramControlItem<TContext>) => void,
|
|
774
797
|
) => void;
|
|
775
798
|
}): TelegramCommandTargetRuntimeDeps<TContext>["enqueueControlItem"] {
|
|
776
|
-
return (
|
|
799
|
+
return (
|
|
800
|
+
target,
|
|
801
|
+
ctx,
|
|
802
|
+
controlType,
|
|
803
|
+
statusSummary,
|
|
804
|
+
execute,
|
|
805
|
+
admissionReceipts,
|
|
806
|
+
onQueued,
|
|
807
|
+
) => {
|
|
777
808
|
deps.enqueueControlItem(
|
|
778
809
|
deps.createControlItem({
|
|
779
810
|
...target,
|
|
780
811
|
controlType,
|
|
781
812
|
statusSummary,
|
|
813
|
+
...(admissionReceipts?.length ? { admissionReceipts } : {}),
|
|
782
814
|
execute,
|
|
783
815
|
}),
|
|
784
816
|
ctx,
|
|
817
|
+
onQueued,
|
|
785
818
|
);
|
|
786
819
|
};
|
|
787
820
|
}
|
|
@@ -802,6 +835,9 @@ export function createTelegramCommandTargetQueueRuntime<
|
|
|
802
835
|
appendControlItem: deps.appendControlItem,
|
|
803
836
|
dispatchNextQueuedTelegramTurn: deps.dispatchNextQueuedTelegramTurn,
|
|
804
837
|
}),
|
|
838
|
+
getAdmissionScope: deps.getAdmissionScope,
|
|
839
|
+
getAdmissionJournalBinding: deps.getAdmissionJournalBinding,
|
|
840
|
+
onControlQueued: deps.onControlQueued,
|
|
805
841
|
showStatus: deps.showStatus,
|
|
806
842
|
openModelMenu: deps.openModelMenu,
|
|
807
843
|
openSettingsMenu: deps.openSettingsMenu,
|
|
@@ -817,12 +853,32 @@ export function createTelegramCommandTargetRuntime<
|
|
|
817
853
|
): TelegramCommandTargetRuntime<TMessage, TContext> {
|
|
818
854
|
return {
|
|
819
855
|
enqueueControlItem: (message, ctx, controlType, statusSummary, execute) => {
|
|
856
|
+
const sourceUpdateId = message.pi_telegram_source_update_id;
|
|
857
|
+
const baseReceipt =
|
|
858
|
+
typeof sourceUpdateId === "number"
|
|
859
|
+
? createTelegramQueueAdmissionReceipt({
|
|
860
|
+
queueKind: "control",
|
|
861
|
+
scope: deps.getAdmissionScope?.() ?? "",
|
|
862
|
+
sourceUpdateIds: [sourceUpdateId],
|
|
863
|
+
})
|
|
864
|
+
: undefined;
|
|
865
|
+
const journalBindingKey = deps.getAdmissionJournalBinding?.();
|
|
866
|
+
const receipt = baseReceipt
|
|
867
|
+
? {
|
|
868
|
+
...baseReceipt,
|
|
869
|
+
...(journalBindingKey ? { journalBindingKey } : {}),
|
|
870
|
+
}
|
|
871
|
+
: undefined;
|
|
820
872
|
deps.enqueueControlItem(
|
|
821
873
|
getTelegramCommandMessageTarget(message),
|
|
822
874
|
ctx,
|
|
823
875
|
controlType,
|
|
824
876
|
statusSummary,
|
|
825
877
|
execute,
|
|
878
|
+
receipt ? [receipt] : undefined,
|
|
879
|
+
receipt
|
|
880
|
+
? () => deps.onControlQueued?.(message, receipt)
|
|
881
|
+
: undefined,
|
|
826
882
|
);
|
|
827
883
|
},
|
|
828
884
|
showStatus: (message, ctx) => {
|
|
@@ -889,6 +945,7 @@ export interface TelegramCommandOrPromptRuntimeDeps<TMessage, TContext> {
|
|
|
889
945
|
) => string | undefined;
|
|
890
946
|
replaceMessageText: (message: TMessage, text: string) => TMessage;
|
|
891
947
|
enqueueTurn: (messages: TMessage[], ctx: TContext) => Promise<void>;
|
|
948
|
+
assertExecutionCurrent?: (message: TMessage) => void;
|
|
892
949
|
}
|
|
893
950
|
|
|
894
951
|
export interface TelegramCommandRuntimeDeps<
|
|
@@ -908,6 +965,7 @@ export interface TelegramCommandRuntimeDeps<
|
|
|
908
965
|
isCompactionInProgress: () => boolean;
|
|
909
966
|
setCompactionInProgress: (inProgress: boolean) => void;
|
|
910
967
|
updateStatus: (ctx: TContext) => void;
|
|
968
|
+
isContextActive?: (ctx: TContext) => boolean;
|
|
911
969
|
dispatchNextQueuedTelegramTurn: (ctx: TContext) => void;
|
|
912
970
|
requestDeferredDispatchNextQueuedTelegramTurn?: (
|
|
913
971
|
dispatch: (ctx: TContext) => void,
|
|
@@ -946,6 +1004,7 @@ export interface TelegramCommandRuntimeDeps<
|
|
|
946
1004
|
persistConfig: () => Promise<void>;
|
|
947
1005
|
sendTextReply: (message: TMessage, text: string) => Promise<void>;
|
|
948
1006
|
sendInteractiveMessage?: TelegramCompactConfirmationDeps["sendInteractiveMessage"];
|
|
1007
|
+
assertExecutionCurrent?: (message: TMessage) => void;
|
|
949
1008
|
}
|
|
950
1009
|
|
|
951
1010
|
export const TELEGRAM_APP_MENU_INTRO_HTML = [
|
|
@@ -1420,6 +1479,9 @@ export function createTelegramCommandHandlerTargetRuntime<
|
|
|
1420
1479
|
}),
|
|
1421
1480
|
appendControlItem: deps.appendControlItem,
|
|
1422
1481
|
dispatchNextQueuedTelegramTurn: deps.dispatchNextQueuedTelegramTurn,
|
|
1482
|
+
getAdmissionScope: deps.getAdmissionScope,
|
|
1483
|
+
getAdmissionJournalBinding: deps.getAdmissionJournalBinding,
|
|
1484
|
+
onControlQueued: deps.onControlQueued,
|
|
1423
1485
|
showStatus: deps.showStatus,
|
|
1424
1486
|
openModelMenu: deps.openModelMenu,
|
|
1425
1487
|
openSettingsMenu: deps.openSettingsMenu,
|
|
@@ -1439,6 +1501,7 @@ export function createTelegramCommandHandlerTargetRuntime<
|
|
|
1439
1501
|
isCompactionInProgress: deps.isCompactionInProgress,
|
|
1440
1502
|
setCompactionInProgress: deps.setCompactionInProgress,
|
|
1441
1503
|
updateStatus: deps.updateStatus,
|
|
1504
|
+
isContextActive: deps.isContextActive,
|
|
1442
1505
|
dispatchNextQueuedTelegramTurn: deps.dispatchNextQueuedTelegramTurn,
|
|
1443
1506
|
startTypingLoop: deps.startTypingLoop,
|
|
1444
1507
|
stopTypingLoop: deps.stopTypingLoop,
|
|
@@ -1487,12 +1550,14 @@ export function createTelegramCommandOrPromptRuntime<TMessage, TContext>(
|
|
|
1487
1550
|
const firstMessage = messages[0];
|
|
1488
1551
|
if (!firstMessage) return;
|
|
1489
1552
|
if (deps.shouldIgnoreMessages?.(messages)) return;
|
|
1553
|
+
deps.assertExecutionCurrent?.(firstMessage);
|
|
1490
1554
|
const command = parseTelegramCommand(deps.extractRawText(messages));
|
|
1491
1555
|
const handled = await deps.handleCommand(
|
|
1492
1556
|
command?.name,
|
|
1493
1557
|
firstMessage,
|
|
1494
1558
|
ctx,
|
|
1495
1559
|
);
|
|
1560
|
+
deps.assertExecutionCurrent?.(firstMessage);
|
|
1496
1561
|
if (handled) return;
|
|
1497
1562
|
if (command && deps.executeExtensionCommand) {
|
|
1498
1563
|
const handledByExtension = await deps.executeExtensionCommand(
|
|
@@ -1500,6 +1565,7 @@ export function createTelegramCommandOrPromptRuntime<TMessage, TContext>(
|
|
|
1500
1565
|
messages[0]!,
|
|
1501
1566
|
ctx,
|
|
1502
1567
|
);
|
|
1568
|
+
deps.assertExecutionCurrent?.(firstMessage);
|
|
1503
1569
|
if (handledByExtension) return;
|
|
1504
1570
|
}
|
|
1505
1571
|
if (command?.name && deps.expandPromptTemplateCommand) {
|
|
@@ -1508,6 +1574,7 @@ export function createTelegramCommandOrPromptRuntime<TMessage, TContext>(
|
|
|
1508
1574
|
command.args,
|
|
1509
1575
|
);
|
|
1510
1576
|
if (expanded !== undefined) {
|
|
1577
|
+
deps.assertExecutionCurrent?.(firstMessage);
|
|
1511
1578
|
await deps.enqueueTurn(
|
|
1512
1579
|
[
|
|
1513
1580
|
deps.replaceMessageText(firstMessage, expanded),
|
|
@@ -1518,11 +1585,41 @@ export function createTelegramCommandOrPromptRuntime<TMessage, TContext>(
|
|
|
1518
1585
|
return;
|
|
1519
1586
|
}
|
|
1520
1587
|
}
|
|
1588
|
+
deps.assertExecutionCurrent?.(firstMessage);
|
|
1521
1589
|
await deps.enqueueTurn(messages, ctx);
|
|
1522
1590
|
},
|
|
1523
1591
|
};
|
|
1524
1592
|
}
|
|
1525
1593
|
|
|
1594
|
+
function scheduleTelegramCommandEffect<TContext>(
|
|
1595
|
+
ctx: TContext,
|
|
1596
|
+
command: string,
|
|
1597
|
+
phase: string,
|
|
1598
|
+
deps: TelegramRuntimeEventRecorderPort & {
|
|
1599
|
+
isContextActive?: (ctx: TContext) => boolean;
|
|
1600
|
+
},
|
|
1601
|
+
effect: () => Promise<void>,
|
|
1602
|
+
assertExecutionCurrent?: () => void,
|
|
1603
|
+
): void {
|
|
1604
|
+
void Promise.resolve()
|
|
1605
|
+
.then(async () => {
|
|
1606
|
+
if (deps.isContextActive?.(ctx) === false) return;
|
|
1607
|
+
assertExecutionCurrent?.();
|
|
1608
|
+
await effect();
|
|
1609
|
+
assertExecutionCurrent?.();
|
|
1610
|
+
})
|
|
1611
|
+
.catch((error) => {
|
|
1612
|
+
try {
|
|
1613
|
+
deps.recordRuntimeEvent?.("telegram-command", error, {
|
|
1614
|
+
command,
|
|
1615
|
+
phase,
|
|
1616
|
+
});
|
|
1617
|
+
} catch {
|
|
1618
|
+
// Effect diagnostics cannot create an unhandled detached Promise.
|
|
1619
|
+
}
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1526
1623
|
async function handleTelegramCommandRuntime<
|
|
1527
1624
|
TMessage extends TelegramCommandRuntimeMessage,
|
|
1528
1625
|
TContext,
|
|
@@ -1532,8 +1629,13 @@ async function handleTelegramCommandRuntime<
|
|
|
1532
1629
|
ctx: TContext,
|
|
1533
1630
|
deps: TelegramCommandRuntimeDeps<TMessage, TContext>,
|
|
1534
1631
|
): Promise<boolean> {
|
|
1535
|
-
const
|
|
1536
|
-
deps.
|
|
1632
|
+
const assertExecutionCurrentFor = (nextMessage: TMessage) => (): void =>
|
|
1633
|
+
deps.assertExecutionCurrent?.(nextMessage);
|
|
1634
|
+
const sendReplyFor = (nextMessage: TMessage) => async (text: string) => {
|
|
1635
|
+
deps.assertExecutionCurrent?.(nextMessage);
|
|
1636
|
+
await deps.sendTextReply(nextMessage, text);
|
|
1637
|
+
deps.assertExecutionCurrent?.(nextMessage);
|
|
1638
|
+
};
|
|
1537
1639
|
const updateStatusFor = (commandCtx: TContext) => () =>
|
|
1538
1640
|
deps.updateStatus(commandCtx);
|
|
1539
1641
|
return executeTelegramCommandAction(
|
|
@@ -1585,7 +1687,14 @@ async function handleTelegramCommandRuntime<
|
|
|
1585
1687
|
});
|
|
1586
1688
|
},
|
|
1587
1689
|
handleQueue: async (nextMessage, commandCtx) => {
|
|
1588
|
-
|
|
1690
|
+
scheduleTelegramCommandEffect(
|
|
1691
|
+
commandCtx,
|
|
1692
|
+
"queue",
|
|
1693
|
+
"menu-render",
|
|
1694
|
+
deps,
|
|
1695
|
+
() => deps.openQueueMenu(nextMessage, commandCtx),
|
|
1696
|
+
assertExecutionCurrentFor(nextMessage),
|
|
1697
|
+
);
|
|
1589
1698
|
},
|
|
1590
1699
|
handleCompact: async (nextMessage, commandCtx) => {
|
|
1591
1700
|
if (deps.sendInteractiveMessage) {
|
|
@@ -1626,33 +1735,53 @@ async function handleTelegramCommandRuntime<
|
|
|
1626
1735
|
});
|
|
1627
1736
|
},
|
|
1628
1737
|
handleStatus: async (nextMessage, commandCtx) => {
|
|
1629
|
-
|
|
1738
|
+
scheduleTelegramCommandEffect(
|
|
1739
|
+
commandCtx,
|
|
1740
|
+
"status",
|
|
1741
|
+
"menu-render",
|
|
1742
|
+
deps,
|
|
1743
|
+
() => deps.showStatus(nextMessage, commandCtx),
|
|
1744
|
+
assertExecutionCurrentFor(nextMessage),
|
|
1745
|
+
);
|
|
1630
1746
|
},
|
|
1631
1747
|
handleModel: async (nextMessage, commandCtx) => {
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1748
|
+
scheduleTelegramCommandEffect(
|
|
1749
|
+
commandCtx,
|
|
1750
|
+
"model",
|
|
1751
|
+
"menu-render",
|
|
1752
|
+
deps,
|
|
1753
|
+
() =>
|
|
1754
|
+
handleTelegramModelCommand<TContext>({
|
|
1755
|
+
ctx: commandCtx,
|
|
1756
|
+
openModelMenu: (controlCtx) =>
|
|
1757
|
+
deps.openModelMenu(nextMessage, controlCtx),
|
|
1758
|
+
}),
|
|
1759
|
+
assertExecutionCurrentFor(nextMessage),
|
|
1760
|
+
);
|
|
1637
1761
|
},
|
|
1638
1762
|
handleThinking: async (nextMessage, commandCtx) => {
|
|
1639
|
-
|
|
1763
|
+
scheduleTelegramCommandEffect(
|
|
1764
|
+
commandCtx,
|
|
1765
|
+
"thinking",
|
|
1766
|
+
"menu-render",
|
|
1767
|
+
deps,
|
|
1768
|
+
() => deps.openThinkingMenu(nextMessage, commandCtx),
|
|
1769
|
+
assertExecutionCurrentFor(nextMessage),
|
|
1770
|
+
);
|
|
1640
1771
|
},
|
|
1641
1772
|
handleSettings: deps.openSettingsMenu
|
|
1642
1773
|
? async (nextMessage, commandCtx) => {
|
|
1643
|
-
|
|
1774
|
+
scheduleTelegramCommandEffect(
|
|
1775
|
+
commandCtx,
|
|
1776
|
+
"settings",
|
|
1777
|
+
"menu-render",
|
|
1778
|
+
deps,
|
|
1779
|
+
() => deps.openSettingsMenu!(nextMessage, commandCtx),
|
|
1780
|
+
assertExecutionCurrentFor(nextMessage),
|
|
1781
|
+
);
|
|
1644
1782
|
}
|
|
1645
1783
|
: undefined,
|
|
1646
1784
|
handleHelp: async (nextMessage, nextCommandName, commandCtx) => {
|
|
1647
|
-
try {
|
|
1648
|
-
await deps.registerBotCommands();
|
|
1649
|
-
} catch (error) {
|
|
1650
|
-
const errorMessage = getTelegramCommandErrorMessage(error);
|
|
1651
|
-
await deps.sendTextReply(
|
|
1652
|
-
nextMessage,
|
|
1653
|
-
`Warning: failed to register bot commands menu: ${errorMessage}`,
|
|
1654
|
-
);
|
|
1655
|
-
}
|
|
1656
1785
|
if (
|
|
1657
1786
|
nextMessage.from?.id !== undefined &&
|
|
1658
1787
|
canPairTelegramUserFromCommandMessage(nextMessage)
|
|
@@ -1663,16 +1792,41 @@ async function handleTelegramCommandRuntime<
|
|
|
1663
1792
|
setAllowedUserId: deps.setAllowedUserId,
|
|
1664
1793
|
persistConfig: deps.persistConfig,
|
|
1665
1794
|
updateStatus: updateStatusFor(commandCtx),
|
|
1795
|
+
assertExecutionCurrent: assertExecutionCurrentFor(nextMessage),
|
|
1666
1796
|
});
|
|
1667
1797
|
}
|
|
1668
|
-
const
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1798
|
+
const isContextActive = () =>
|
|
1799
|
+
deps.isContextActive?.(commandCtx) !== false;
|
|
1800
|
+
scheduleTelegramCommandEffect(
|
|
1801
|
+
commandCtx,
|
|
1802
|
+
nextCommandName,
|
|
1803
|
+
"menu-render",
|
|
1804
|
+
deps,
|
|
1805
|
+
async () => {
|
|
1806
|
+
let forumBootstrapMessage: string | undefined;
|
|
1807
|
+
if (nextCommandName === "start" && deps.handleForumBootstrap) {
|
|
1808
|
+
forumBootstrapMessage = await deps.handleForumBootstrap(
|
|
1809
|
+
nextMessage,
|
|
1810
|
+
commandCtx,
|
|
1811
|
+
);
|
|
1812
|
+
}
|
|
1813
|
+
if (!isContextActive()) return;
|
|
1814
|
+
if (forumBootstrapMessage) {
|
|
1815
|
+
await deps.sendTextReply(nextMessage, forumBootstrapMessage);
|
|
1816
|
+
}
|
|
1817
|
+
if (!isContextActive()) return;
|
|
1818
|
+
await deps.showStatus(nextMessage, commandCtx);
|
|
1819
|
+
},
|
|
1820
|
+
assertExecutionCurrentFor(nextMessage),
|
|
1821
|
+
);
|
|
1822
|
+
scheduleTelegramCommandEffect(
|
|
1823
|
+
commandCtx,
|
|
1824
|
+
nextCommandName,
|
|
1825
|
+
"bot-command-sync",
|
|
1826
|
+
deps,
|
|
1827
|
+
deps.registerBotCommands,
|
|
1828
|
+
assertExecutionCurrentFor(nextMessage),
|
|
1829
|
+
);
|
|
1676
1830
|
},
|
|
1677
1831
|
},
|
|
1678
1832
|
);
|
package/lib/config.ts
CHANGED
|
@@ -186,6 +186,18 @@ export interface TelegramConfigStore {
|
|
|
186
186
|
persist: (config?: TelegramConfig) => Promise<void>;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
export function createTelegramConfigBotIdGetter(
|
|
190
|
+
store: Pick<TelegramConfigStore, "get">,
|
|
191
|
+
): () => number | undefined {
|
|
192
|
+
return () => store.get().botId;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function createTelegramActiveProfileKeyGetter(
|
|
196
|
+
store: Pick<TelegramConfigStore, "getActiveProfileName">,
|
|
197
|
+
): () => string {
|
|
198
|
+
return () => store.getActiveProfileName() ?? TELEGRAM_DEFAULT_PROFILE_NAME;
|
|
199
|
+
}
|
|
200
|
+
|
|
189
201
|
export interface TelegramConfigStoreOptions {
|
|
190
202
|
initialConfig?: TelegramConfig;
|
|
191
203
|
agentDir?: string;
|
|
@@ -1053,6 +1065,7 @@ export interface TelegramUserPairingDeps<TContext> {
|
|
|
1053
1065
|
setAllowedUserId: (userId: number) => void;
|
|
1054
1066
|
persistConfig: () => Promise<void>;
|
|
1055
1067
|
updateStatus: (ctx: TContext) => void;
|
|
1068
|
+
assertExecutionCurrent?: () => void;
|
|
1056
1069
|
}
|
|
1057
1070
|
|
|
1058
1071
|
export interface TelegramUserPairingRuntimeDeps<TContext> {
|
|
@@ -1063,7 +1076,11 @@ export interface TelegramUserPairingRuntimeDeps<TContext> {
|
|
|
1063
1076
|
}
|
|
1064
1077
|
|
|
1065
1078
|
export interface TelegramUserPairingRuntime<TContext> {
|
|
1066
|
-
pairIfNeeded: (
|
|
1079
|
+
pairIfNeeded: (
|
|
1080
|
+
userId: number,
|
|
1081
|
+
ctx: TContext,
|
|
1082
|
+
assertExecutionCurrent?: () => void,
|
|
1083
|
+
) => Promise<boolean>;
|
|
1067
1084
|
}
|
|
1068
1085
|
|
|
1069
1086
|
export function getTelegramAuthorizationState(
|
|
@@ -1096,8 +1113,11 @@ export async function pairTelegramUserIfNeeded<TContext>(
|
|
|
1096
1113
|
deps.allowedUserId,
|
|
1097
1114
|
);
|
|
1098
1115
|
if (authorization.kind !== "pair") return false;
|
|
1116
|
+
deps.assertExecutionCurrent?.();
|
|
1099
1117
|
deps.setAllowedUserId(authorization.userId);
|
|
1118
|
+
deps.assertExecutionCurrent?.();
|
|
1100
1119
|
await deps.persistConfig();
|
|
1120
|
+
deps.assertExecutionCurrent?.();
|
|
1101
1121
|
try {
|
|
1102
1122
|
deps.updateStatus(deps.ctx);
|
|
1103
1123
|
} catch (error) {
|
|
@@ -1110,13 +1130,14 @@ export function createTelegramUserPairingRuntime<TContext>(
|
|
|
1110
1130
|
deps: TelegramUserPairingRuntimeDeps<TContext>,
|
|
1111
1131
|
): TelegramUserPairingRuntime<TContext> {
|
|
1112
1132
|
return {
|
|
1113
|
-
pairIfNeeded: (userId, ctx) =>
|
|
1133
|
+
pairIfNeeded: (userId, ctx, assertExecutionCurrent) =>
|
|
1114
1134
|
pairTelegramUserIfNeeded(userId, {
|
|
1115
1135
|
allowedUserId: deps.getAllowedUserId(),
|
|
1116
1136
|
ctx,
|
|
1117
1137
|
setAllowedUserId: deps.setAllowedUserId,
|
|
1118
1138
|
persistConfig: deps.persistConfig,
|
|
1119
1139
|
updateStatus: deps.updateStatus,
|
|
1140
|
+
assertExecutionCurrent,
|
|
1120
1141
|
}),
|
|
1121
1142
|
};
|
|
1122
1143
|
}
|