negotium 0.7.1 → 0.8.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/README.md +3 -4
- package/dist/agent-helpers.js +17 -8
- package/dist/agent-helpers.js.map +10 -9
- package/dist/background-bash.js.map +2 -2
- package/dist/browser-runtime.js.map +2 -2
- package/dist/{chunk-4y98yvq8.js → chunk-1bfta5qh.js} +2 -2
- package/dist/{chunk-4y98yvq8.js.map → chunk-1bfta5qh.js.map} +2 -2
- package/dist/chunk-pp6dvrzq.js.map +2 -2
- package/dist/hosted-agent.js +2 -2
- package/dist/hosted-agent.js.map +4 -4
- package/dist/main.js +355 -148
- package/dist/main.js.map +16 -15
- package/dist/mcp-factories.js +17 -8
- package/dist/mcp-factories.js.map +10 -9
- package/dist/media.js.map +2 -2
- package/dist/prompts.js.map +2 -2
- package/dist/query-runtime.js +7 -2
- package/dist/query-runtime.js.map +7 -6
- package/dist/registry.js +1 -1
- package/dist/runtime/src/identifiers.ts +28 -0
- package/dist/runtime/src/index.ts +12 -0
- package/dist/runtime/src/query/index.ts +0 -1
- package/dist/runtime/src/query/public-runtime.ts +1 -5
- package/dist/runtime/src/query/room-query-registry.ts +4 -2
- package/dist/runtime/src/query/types.ts +0 -76
- package/dist/runtime/src/runtime/turn-runner.ts +4 -2
- package/dist/runtime/src/storage/api-topics.ts +32 -12
- package/dist/runtime/src/storage/storage-public.ts +4 -39
- package/dist/runtime/src/topics/personal-general.ts +3 -3
- package/dist/runtime/src/types.ts +0 -11
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js.map +2 -2
- package/dist/storage.js +11 -35
- package/dist/storage.js.map +4 -4
- package/dist/types/packages/core/src/identifiers.d.ts +21 -0
- package/dist/types/packages/core/src/query/public-runtime.d.ts +1 -1
- package/dist/types/packages/core/src/query/room-query-registry.d.ts +2 -1
- package/dist/types/packages/core/src/query/types.d.ts +0 -59
- package/dist/types/packages/core/src/storage/api-topics.d.ts +10 -4
- package/dist/types/packages/core/src/storage/storage-public.d.ts +2 -3
- package/dist/types/packages/core/src/types.d.ts +0 -10
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js.map +2 -2
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -3708,7 +3708,7 @@ var exports_version = {};
|
|
|
3708
3708
|
__export(exports_version, {
|
|
3709
3709
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
3710
3710
|
});
|
|
3711
|
-
var NEGOTIUM_VERSION = "0.
|
|
3711
|
+
var NEGOTIUM_VERSION = "0.8.0";
|
|
3712
3712
|
|
|
3713
3713
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
3714
3714
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -7884,6 +7884,7 @@ __export(exports_api_topics, {
|
|
|
7884
7884
|
upsertTopic: () => upsertTopic,
|
|
7885
7885
|
stampUnscopedOtiumTopics: () => stampUnscopedOtiumTopics,
|
|
7886
7886
|
setTopicSurfaces: () => setTopicSurfaces,
|
|
7887
|
+
setTopicSurfaceScope: () => setTopicSurfaceScope,
|
|
7887
7888
|
setTopicSessionId: () => setTopicSessionId,
|
|
7888
7889
|
setSurfaceScopeRequired: () => setSurfaceScopeRequired,
|
|
7889
7890
|
setDefaultSurfaceScope: () => setDefaultSurfaceScope,
|
|
@@ -8412,11 +8413,9 @@ function normalizedTitle(title) {
|
|
|
8412
8413
|
return title.trim().toLowerCase();
|
|
8413
8414
|
}
|
|
8414
8415
|
function surfaceScopeForWrite(t) {
|
|
8415
|
-
if (normalizeTopicSurface(t.surface ?? defaultTopicSurface()) !== "otium")
|
|
8416
|
-
return null;
|
|
8417
8416
|
if (t.surfaceScope !== undefined)
|
|
8418
8417
|
return normalizeSurfaceScope(t.surfaceScope);
|
|
8419
|
-
return defaultSurfaceScope();
|
|
8418
|
+
return normalizeTopicSurface(t.surface ?? defaultTopicSurface()) === "otium" ? defaultSurfaceScope() : null;
|
|
8420
8419
|
}
|
|
8421
8420
|
function upsertTopic(t) {
|
|
8422
8421
|
const normalized = normalizeTopicState({
|
|
@@ -8561,6 +8560,13 @@ function setTopicSurfaces(topicIds, surface) {
|
|
|
8561
8560
|
})();
|
|
8562
8561
|
return changed;
|
|
8563
8562
|
}
|
|
8563
|
+
function setTopicSurfaceScope(topicId, surface, surfaceScope) {
|
|
8564
|
+
const normalizedSurface = normalizeTopicSurface(surface);
|
|
8565
|
+
const normalizedScope = normalizeSurfaceScope(surfaceScope);
|
|
8566
|
+
const result = db.query(`UPDATE api_topics SET surface = ?, surface_scope = ?
|
|
8567
|
+
WHERE id = ? AND (surface IS NOT ? OR surface_scope IS NOT ?)`).run(normalizedSurface, normalizedScope, topicId, normalizedSurface, normalizedScope);
|
|
8568
|
+
return Number(result.changes ?? 0) > 0;
|
|
8569
|
+
}
|
|
8564
8570
|
function getTopicByNameForUser(title, userId, lookupScope) {
|
|
8565
8571
|
const opts = "scope" in lookupScope ? {} : lookupScope;
|
|
8566
8572
|
const trimmed = title.trim();
|
|
@@ -11511,9 +11517,17 @@ var init_manager2 = __esm(async () => {
|
|
|
11511
11517
|
}, 30 * 60 * 1000).unref();
|
|
11512
11518
|
});
|
|
11513
11519
|
|
|
11520
|
+
// ../../packages/core/src/identifiers.ts
|
|
11521
|
+
function asTurnId(value) {
|
|
11522
|
+
return value;
|
|
11523
|
+
}
|
|
11524
|
+
function asTurnSlotKey(value) {
|
|
11525
|
+
return value;
|
|
11526
|
+
}
|
|
11527
|
+
|
|
11514
11528
|
// ../../packages/core/src/query/room-query-registry.ts
|
|
11515
11529
|
function isolatedTurnRoomId(topicId, queryId) {
|
|
11516
|
-
return `${topicId}${ISOLATED_TURN_ROOM_MARKER}${queryId}
|
|
11530
|
+
return asTurnSlotKey(`${topicId}${ISOLATED_TURN_ROOM_MARKER}${queryId}`);
|
|
11517
11531
|
}
|
|
11518
11532
|
function isIsolatedTurnRoomId(roomId) {
|
|
11519
11533
|
return roomId.includes(ISOLATED_TURN_ROOM_MARKER);
|
|
@@ -11642,6 +11656,7 @@ function createRoomQueryRegistry(host) {
|
|
|
11642
11656
|
};
|
|
11643
11657
|
}
|
|
11644
11658
|
var ISOLATED_TURN_ROOM_MARKER = "::isolated-turn::";
|
|
11659
|
+
var init_room_query_registry = () => {};
|
|
11645
11660
|
|
|
11646
11661
|
// ../../packages/core/src/query/types.ts
|
|
11647
11662
|
var AbortReason;
|
|
@@ -11867,7 +11882,9 @@ var roomQueryRegistry, interSessionQueue;
|
|
|
11867
11882
|
var init_active_rooms = __esm(async () => {
|
|
11868
11883
|
init_logger();
|
|
11869
11884
|
await init_runtime_leases();
|
|
11885
|
+
init_room_query_registry();
|
|
11870
11886
|
init_types2();
|
|
11887
|
+
init_room_query_registry();
|
|
11871
11888
|
roomQueryRegistry = createRoomQueryRegistry({
|
|
11872
11889
|
instanceId: RUNTIME_INSTANCE_ID,
|
|
11873
11890
|
internalAbortReason: "internal" /* Internal */,
|
|
@@ -19713,8 +19730,8 @@ function startAiTurn(params) {
|
|
|
19713
19730
|
const askReplySources = params.askReplySources;
|
|
19714
19731
|
const sessionRetried = params._sessionRetried === true;
|
|
19715
19732
|
const emptyResponseRetried = params._emptyResponseRetried === true;
|
|
19716
|
-
const queryId = params._queryId ?? randomUUID17();
|
|
19717
|
-
const roomId = turnConcurrency === "isolated" ? isolatedTurnRoomId(topicId, queryId) : topicId;
|
|
19733
|
+
const queryId = asTurnId(params._queryId ?? randomUUID17());
|
|
19734
|
+
const roomId = turnConcurrency === "isolated" ? isolatedTurnRoomId(topicId, queryId) : asTurnSlotKey(topicId);
|
|
19718
19735
|
const currentRuntimeEpoch = getRuntimeTopicEpoch(topic.id);
|
|
19719
19736
|
const runtimeEpoch = params._runtimeEpoch ?? currentRuntimeEpoch;
|
|
19720
19737
|
if (params._runtimeEpoch !== undefined && params._runtimeEpoch !== currentRuntimeEpoch) {
|
|
@@ -24134,6 +24151,7 @@ __export(exports_src, {
|
|
|
24134
24151
|
startAiTurn: () => startAiTurn,
|
|
24135
24152
|
stampUnscopedOtiumTopics: () => stampUnscopedOtiumTopics,
|
|
24136
24153
|
setTopicSurfaces: () => setTopicSurfaces,
|
|
24154
|
+
setTopicSurfaceScope: () => setTopicSurfaceScope,
|
|
24137
24155
|
setTopicSessionId: () => setTopicSessionId,
|
|
24138
24156
|
setSurfaceScopeRequired: () => setSurfaceScopeRequired,
|
|
24139
24157
|
setRuntimeMcpPort: () => setRuntimeMcpPort,
|
|
@@ -29407,7 +29425,6 @@ __export(exports_storage_public, {
|
|
|
29407
29425
|
waitForRequiredRuntimeProcessLease: () => waitForRequiredRuntimeProcessLease,
|
|
29408
29426
|
validateDecisionGraph: () => validateDecisionGraph,
|
|
29409
29427
|
upsertTopic: () => upsertTopic,
|
|
29410
|
-
updateTopicThreadId: () => updateTopicThreadId,
|
|
29411
29428
|
updateTasks: () => updateTasks,
|
|
29412
29429
|
updateDecisions: () => updateDecisions,
|
|
29413
29430
|
updateApiMessageUsage: () => updateApiMessageUsage,
|
|
@@ -29429,21 +29446,12 @@ __export(exports_storage_public, {
|
|
|
29429
29446
|
softDeleteApiMessage: () => softDeleteApiMessage,
|
|
29430
29447
|
settleTopicArchiveJob: () => settleTopicArchiveJob,
|
|
29431
29448
|
setTopicSurfaces: () => setTopicSurfaces,
|
|
29449
|
+
setTopicSurfaceScope: () => setTopicSurfaceScope,
|
|
29432
29450
|
setTopicSessionId: () => setTopicSessionId,
|
|
29433
|
-
setTopicMcpExtra: () => setTopicMcpExtra,
|
|
29434
|
-
setTopicMcpEnabled: () => setTopicMcpEnabled,
|
|
29435
|
-
setTopicForkOrigin: () => setTopicForkOrigin,
|
|
29436
|
-
setTopicDescription: () => setTopicDescription,
|
|
29437
29451
|
setTopicBrief: () => setTopicBrief,
|
|
29438
29452
|
setTopicArchiveState: () => setTopicArchiveState,
|
|
29439
|
-
setTopicAgentAndSession: () => setTopicAgentAndSession,
|
|
29440
|
-
setTopicAgentAndClearSession: () => setTopicAgentAndClearSession,
|
|
29441
|
-
setTopicAgent: () => setTopicAgent,
|
|
29442
29453
|
setSurfaceScopeRequired: () => setSurfaceScopeRequired,
|
|
29443
|
-
setSessionForTopic: () => setSessionForTopic,
|
|
29444
|
-
setLastShownConfig: () => setLastShownConfig,
|
|
29445
29454
|
setGlobalAiName: () => setGlobalAiName,
|
|
29446
|
-
setDmSessionId: () => setDmSessionId,
|
|
29447
29455
|
setDefaultSurfaceScope: () => setDefaultSurfaceScope,
|
|
29448
29456
|
setApiTopicConfig: () => setApiTopicConfig,
|
|
29449
29457
|
setApiTopicAgent: () => setApiTopicAgent,
|
|
@@ -29459,8 +29467,6 @@ __export(exports_storage_public, {
|
|
|
29459
29467
|
reparentTopicChildren: () => reparentTopicChildren,
|
|
29460
29468
|
renderTaskList: () => renderTaskList,
|
|
29461
29469
|
renderDecisionList: () => renderDecisionList,
|
|
29462
|
-
renameTopic: () => renameTopic,
|
|
29463
|
-
removeTopic: () => removeTopic,
|
|
29464
29470
|
removeSentFilesForTopic: () => removeSentFilesForTopic,
|
|
29465
29471
|
removeParticipantFromDB: () => removeParticipantFromDB,
|
|
29466
29472
|
removeDeadRuntimeProcessLeases: () => removeDeadRuntimeProcessLeases,
|
|
@@ -29503,49 +29509,34 @@ __export(exports_storage_public, {
|
|
|
29503
29509
|
hasActiveConversation: () => hasActiveConversation,
|
|
29504
29510
|
grantSubagentTellTarget: () => grantSubagentTellTarget,
|
|
29505
29511
|
getWikiDir: () => getWikiDir,
|
|
29506
|
-
getUserConfig: () => getUserConfig,
|
|
29507
29512
|
getTopicStats: () => getTopicStats,
|
|
29508
29513
|
getTopicSessionId: () => getTopicSessionId,
|
|
29509
|
-
getTopicNames: () => getTopicNames,
|
|
29510
29514
|
getTopicMemoryOrigin: () => getTopicMemoryOrigin,
|
|
29511
29515
|
getTopicMemoryFilePaths: () => getTopicMemoryFilePaths,
|
|
29512
|
-
getTopicMcpConfig: () => getTopicMcpConfig,
|
|
29513
|
-
getTopicDescription: () => getTopicDescription,
|
|
29514
29516
|
getTopicByNameForUser: () => getTopicByNameForUser,
|
|
29515
29517
|
getTopicByNameAndKind: () => getTopicByNameAndKind,
|
|
29516
29518
|
getTopicByName: () => getTopicByName,
|
|
29517
29519
|
getTopicBrief: () => getTopicBrief,
|
|
29518
29520
|
getTopicArchiveState: () => getTopicArchiveState,
|
|
29519
|
-
getTopicAgentSwitchState: () => getTopicAgentSwitchState,
|
|
29520
|
-
getTopicAgent: () => getTopicAgent,
|
|
29521
29521
|
getTopic: () => getTopic,
|
|
29522
29522
|
getThreadSummaries: () => getThreadSummaries,
|
|
29523
29523
|
getTaskFilePath: () => getTaskFilePath,
|
|
29524
29524
|
getStats: () => getStats,
|
|
29525
29525
|
getSharedWikiDir: () => getSharedWikiDir,
|
|
29526
|
-
getSessionForTopic: () => getSessionForTopic,
|
|
29527
29526
|
getRuntimeProcessLease: () => getRuntimeProcessLease,
|
|
29528
29527
|
getMessagesForTopicAfterRowid: () => getMessagesForTopicAfterRowid,
|
|
29529
29528
|
getManagerTopicForUser: () => getManagerTopicForUser,
|
|
29530
|
-
getLastShownConfig: () => getLastShownConfig,
|
|
29531
29529
|
getLastMessagePreviews: () => getLastMessagePreviews,
|
|
29532
29530
|
getGlobalAiName: () => getGlobalAiName,
|
|
29533
|
-
getForumTopicByName: () => getTopicByName2,
|
|
29534
|
-
getDmSessionId: () => getDmSessionId,
|
|
29535
29531
|
getDecisionGraphSvgPath: () => getDecisionGraphSvgPath,
|
|
29536
29532
|
getDecisionFilePath: () => getDecisionFilePath,
|
|
29537
29533
|
getConversationPath: () => getConversationPath,
|
|
29538
|
-
getCommunicateThreadId: () => getCommunicateThreadId,
|
|
29539
29534
|
getApiTopicConfig: () => getApiTopicConfig,
|
|
29540
29535
|
getApiMessage: () => getApiMessage,
|
|
29541
|
-
getAllUserIds: () => getAllUserIds,
|
|
29542
|
-
getAllTopics: () => getAllTopics,
|
|
29543
29536
|
getAllMessagesForTopic: () => getAllMessagesForTopic,
|
|
29544
29537
|
getActiveConversationPath: () => getActiveConversationPath,
|
|
29545
29538
|
forum: () => exports_forum,
|
|
29546
29539
|
formatTopicArchiveTranscriptRecord: () => formatTopicArchiveTranscriptRecord,
|
|
29547
|
-
flushSessionCache: () => flushSessionCache,
|
|
29548
|
-
findUserByThread: () => findUserByThread,
|
|
29549
29540
|
findTopicTitleConflict: () => findTopicTitleConflict,
|
|
29550
29541
|
findRecentUserMessage: () => findRecentUserMessage,
|
|
29551
29542
|
findLastSessionIdForAgent: () => findLastSessionIdForAgent,
|
|
@@ -29573,10 +29564,8 @@ __export(exports_storage_public, {
|
|
|
29573
29564
|
configureStorageHost: () => configureStorageHost2,
|
|
29574
29565
|
cloneConversationLog: () => cloneConversationLog,
|
|
29575
29566
|
clearTopicSessionId: () => clearTopicSessionId,
|
|
29576
|
-
clearSessionForTopic: () => clearSessionForTopic,
|
|
29577
29567
|
clearPendingAskSources: () => clearPendingAskSources,
|
|
29578
29568
|
clearPendingAsk: () => clearPendingAsk,
|
|
29579
|
-
clearDmSessionId: () => clearDmSessionId,
|
|
29580
29569
|
claimTopicArchiveJob: () => claimTopicArchiveJob,
|
|
29581
29570
|
claimAskUserGateAndSelect: () => claimAskUserGateAndSelect,
|
|
29582
29571
|
captureMessageSnapshotForTopic: () => captureMessageSnapshotForTopic,
|
|
@@ -29596,7 +29585,6 @@ __export(exports_storage_public, {
|
|
|
29596
29585
|
apiMessages: () => exports_api_messages,
|
|
29597
29586
|
anonymizeApiMessages: () => anonymizeApiMessages,
|
|
29598
29587
|
aiMentionFromMode: () => aiMentionFromMode,
|
|
29599
|
-
addTopic: () => addTopic,
|
|
29600
29588
|
addParticipantToDB: () => addParticipantToDB,
|
|
29601
29589
|
activityLog: () => exports_activity_log,
|
|
29602
29590
|
acquireRuntimeProcessLease: () => acquireRuntimeProcessLease,
|
|
@@ -29628,7 +29616,6 @@ var init_storage_public = __esm(async () => {
|
|
|
29628
29616
|
await init_decisions();
|
|
29629
29617
|
init_decisions();
|
|
29630
29618
|
await init_forum();
|
|
29631
|
-
await init_forum();
|
|
29632
29619
|
await init_runtime_process_leases();
|
|
29633
29620
|
init_runtime_process_leases();
|
|
29634
29621
|
await init_session_asks();
|
|
@@ -29643,7 +29630,6 @@ var init_storage_public = __esm(async () => {
|
|
|
29643
29630
|
await init_topic_archive_state();
|
|
29644
29631
|
init_topic_archive_state();
|
|
29645
29632
|
await init_topic_settings();
|
|
29646
|
-
init_topic_settings();
|
|
29647
29633
|
await init_wiki();
|
|
29648
29634
|
init_wiki();
|
|
29649
29635
|
init_wiki_summary_names();
|
|
@@ -42719,12 +42705,15 @@ var init_telegram_api = __esm(() => {
|
|
|
42719
42705
|
});
|
|
42720
42706
|
|
|
42721
42707
|
// ../../adapters/telegram/src/commands.ts
|
|
42722
|
-
function resolveTelegramTopicArg(argument, userId) {
|
|
42723
|
-
const byName = getTopicByNameForUser(argument, userId, {
|
|
42708
|
+
function resolveTelegramTopicArg(argument, userId, surfaceScope) {
|
|
42709
|
+
const byName = getTopicByNameForUser(argument, userId, {
|
|
42710
|
+
surface: "telegram",
|
|
42711
|
+
surfaceScope
|
|
42712
|
+
});
|
|
42724
42713
|
if (byName)
|
|
42725
42714
|
return byName;
|
|
42726
42715
|
const byId = getTopic(argument);
|
|
42727
|
-
return byId?.surface === "telegram" ? byId : null;
|
|
42716
|
+
return byId?.surface === "telegram" && (byId.surfaceScope ?? null) === surfaceScope ? byId : null;
|
|
42728
42717
|
}
|
|
42729
42718
|
function createTelegramCommandRouter(context) {
|
|
42730
42719
|
const { userId, reply, currentTopicId, bindMapping, loadTopic, unloadTopic, abortTurn } = context;
|
|
@@ -42762,7 +42751,7 @@ function createTelegramCommandRouter(context) {
|
|
|
42762
42751
|
return;
|
|
42763
42752
|
}
|
|
42764
42753
|
try {
|
|
42765
|
-
const topic = context.getOrCreateTopic(`${context.titleFor(chatId, threadId)}-${argument}`, argument);
|
|
42754
|
+
const topic = context.getOrCreateTopic(chatId, `${context.titleFor(chatId, threadId)}-${argument}`, argument);
|
|
42766
42755
|
bindMapping(chatId, threadId, topic.id);
|
|
42767
42756
|
reply(chatId, threadId, `agent set to ${argument} \u2014 topic "${topic.title}"`);
|
|
42768
42757
|
} catch (err2) {
|
|
@@ -42771,7 +42760,10 @@ function createTelegramCommandRouter(context) {
|
|
|
42771
42760
|
return;
|
|
42772
42761
|
}
|
|
42773
42762
|
case "/topics": {
|
|
42774
|
-
const topics = listTopics({
|
|
42763
|
+
const topics = listTopics({
|
|
42764
|
+
surface: "telegram",
|
|
42765
|
+
surfaceScope: context.surfaceScopeFor(chatId)
|
|
42766
|
+
}).filter((topic) => isTopicVisible(topic) && topic.participants.some((person) => person.userId === userId));
|
|
42775
42767
|
reply(chatId, threadId, topics.length ? topics.map((topic) => `- ${topic.title}${topic.agent ? ` (${topic.agent})` : ""}`).join(`
|
|
42776
42768
|
`) : "no topics");
|
|
42777
42769
|
return;
|
|
@@ -42802,9 +42794,10 @@ function createTelegramCommandRouter(context) {
|
|
|
42802
42794
|
userId,
|
|
42803
42795
|
kind: "agent",
|
|
42804
42796
|
surface: "telegram",
|
|
42797
|
+
surfaceScope: context.surfaceScopeFor(chatId),
|
|
42805
42798
|
...context.defaultAgent ? { agent: context.defaultAgent } : {}
|
|
42806
42799
|
};
|
|
42807
|
-
const fromForumGeneral = context.
|
|
42800
|
+
const fromForumGeneral = context.isForumGeneral(chatId, threadId);
|
|
42808
42801
|
const topic = fromForumGeneral ? topicService.create(createOptions) : context.registerTopic(createOptions);
|
|
42809
42802
|
if (fromForumGeneral) {
|
|
42810
42803
|
reply(chatId, threadId, `creating new topic "${topic.title}"`);
|
|
@@ -42822,7 +42815,7 @@ function createTelegramCommandRouter(context) {
|
|
|
42822
42815
|
reply(chatId, threadId, "usage: /load <topic>");
|
|
42823
42816
|
return;
|
|
42824
42817
|
}
|
|
42825
|
-
const candidate = resolveTelegramTopicArg(argument, userId);
|
|
42818
|
+
const candidate = resolveTelegramTopicArg(argument, userId, context.surfaceScopeFor(chatId));
|
|
42826
42819
|
const topic = candidate && isTopicVisible(candidate) ? candidate : null;
|
|
42827
42820
|
if (!topic || !loadTopic(chatId, topic.id, threadId)) {
|
|
42828
42821
|
reply(chatId, threadId, `no visible topic matching "${argument}"`);
|
|
@@ -42867,7 +42860,7 @@ function createTelegramCommandRouter(context) {
|
|
|
42867
42860
|
case "/del!": {
|
|
42868
42861
|
const force = command === "/del!";
|
|
42869
42862
|
const topicId = currentTopicId(chatId, threadId);
|
|
42870
|
-
const topic = argument ? resolveTelegramTopicArg(argument, userId) : topicId ? getTopic(topicId) : null;
|
|
42863
|
+
const topic = argument ? resolveTelegramTopicArg(argument, userId, context.surfaceScopeFor(chatId)) : topicId ? getTopic(topicId) : null;
|
|
42871
42864
|
if (!topic) {
|
|
42872
42865
|
reply(chatId, threadId, argument ? `no topic named "${argument}"` : "this chat has no topic \u2014 usage: /del [name]");
|
|
42873
42866
|
return;
|
|
@@ -42952,6 +42945,12 @@ function createTables(db4) {
|
|
|
42952
42945
|
key TEXT PRIMARY KEY,
|
|
42953
42946
|
value TEXT NOT NULL
|
|
42954
42947
|
)`);
|
|
42948
|
+
db4.run(`CREATE TABLE IF NOT EXISTS telegram_groups (
|
|
42949
|
+
chat_id INTEGER PRIMARY KEY,
|
|
42950
|
+
title TEXT,
|
|
42951
|
+
owner_telegram_user_id INTEGER,
|
|
42952
|
+
created_at TEXT NOT NULL
|
|
42953
|
+
)`);
|
|
42955
42954
|
db4.run(`CREATE TABLE IF NOT EXISTS runtime_inbox (
|
|
42956
42955
|
seq INTEGER PRIMARY KEY,
|
|
42957
42956
|
runtime_message_id TEXT,
|
|
@@ -42981,6 +42980,14 @@ function openMappingStore(path) {
|
|
|
42981
42980
|
const db4 = new Database2(dbPath);
|
|
42982
42981
|
migrateLegacySchema(db4);
|
|
42983
42982
|
createTables(db4);
|
|
42983
|
+
const legacyForum = db4.query("SELECT value FROM settings WHERE key = 'forum_chat_id'").get();
|
|
42984
|
+
if (legacyForum) {
|
|
42985
|
+
const chatId = Number.parseInt(legacyForum.value, 10);
|
|
42986
|
+
if (Number.isSafeInteger(chatId)) {
|
|
42987
|
+
db4.run(`INSERT OR IGNORE INTO telegram_groups (chat_id, created_at)
|
|
42988
|
+
VALUES (?, ?)`, [chatId, new Date().toISOString()]);
|
|
42989
|
+
}
|
|
42990
|
+
}
|
|
42984
42991
|
migrateOutboxSchema(db4);
|
|
42985
42992
|
migrateRuntimeInboxSchema(db4);
|
|
42986
42993
|
return {
|
|
@@ -43033,6 +43040,32 @@ function openMappingStore(path) {
|
|
|
43033
43040
|
clearForumChatId() {
|
|
43034
43041
|
db4.run("DELETE FROM settings WHERE key = 'forum_chat_id'");
|
|
43035
43042
|
},
|
|
43043
|
+
loadGroups() {
|
|
43044
|
+
const rows = db4.query("SELECT chat_id, title, owner_telegram_user_id FROM telegram_groups ORDER BY created_at").all();
|
|
43045
|
+
return rows.map((row) => ({
|
|
43046
|
+
chatId: row.chat_id,
|
|
43047
|
+
...row.title ? { title: row.title } : {},
|
|
43048
|
+
...row.owner_telegram_user_id !== null ? { ownerTelegramUserId: row.owner_telegram_user_id } : {}
|
|
43049
|
+
}));
|
|
43050
|
+
},
|
|
43051
|
+
saveGroup(group) {
|
|
43052
|
+
db4.run(`INSERT INTO telegram_groups (chat_id, title, owner_telegram_user_id, created_at)
|
|
43053
|
+
VALUES (?, ?, ?, ?)
|
|
43054
|
+
ON CONFLICT(chat_id) DO UPDATE SET
|
|
43055
|
+
title = COALESCE(excluded.title, telegram_groups.title),
|
|
43056
|
+
owner_telegram_user_id = COALESCE(
|
|
43057
|
+
excluded.owner_telegram_user_id,
|
|
43058
|
+
telegram_groups.owner_telegram_user_id
|
|
43059
|
+
)`, [
|
|
43060
|
+
group.chatId,
|
|
43061
|
+
group.title ?? null,
|
|
43062
|
+
group.ownerTelegramUserId ?? null,
|
|
43063
|
+
new Date().toISOString()
|
|
43064
|
+
]);
|
|
43065
|
+
},
|
|
43066
|
+
deleteGroup(chatId) {
|
|
43067
|
+
db4.run("DELETE FROM telegram_groups WHERE chat_id = ?", [chatId]);
|
|
43068
|
+
},
|
|
43036
43069
|
isFlagSet(key) {
|
|
43037
43070
|
return db4.query("SELECT 1 FROM settings WHERE key = ?").get(key) !== null;
|
|
43038
43071
|
},
|
|
@@ -43372,6 +43405,15 @@ function renderOutbound(text2, maxLen = 4096) {
|
|
|
43372
43405
|
// ../../adapters/telegram/src/adapter.ts
|
|
43373
43406
|
import { existsSync as existsSync37 } from "fs";
|
|
43374
43407
|
import { basename as basename13, extname as extname6 } from "path";
|
|
43408
|
+
function telegramGroupScope(chatId) {
|
|
43409
|
+
return `tg:${chatId}`;
|
|
43410
|
+
}
|
|
43411
|
+
function telegramGroupIdFromScope(scope) {
|
|
43412
|
+
if (!scope?.startsWith("tg:"))
|
|
43413
|
+
return null;
|
|
43414
|
+
const chatId = Number(scope.slice(3));
|
|
43415
|
+
return Number.isSafeInteger(chatId) ? chatId : null;
|
|
43416
|
+
}
|
|
43375
43417
|
function startTelegramAdapter(opts) {
|
|
43376
43418
|
const { client, forumChatId } = opts;
|
|
43377
43419
|
const userId = opts.userId ?? "local";
|
|
@@ -43390,16 +43432,42 @@ function startTelegramAdapter(opts) {
|
|
|
43390
43432
|
const dispatchTurn = opts.startTurn ?? startAiTurn;
|
|
43391
43433
|
const store = openMappingStore(opts.mappingDbPath);
|
|
43392
43434
|
const restoredForumChatId = store.loadForumChatId();
|
|
43393
|
-
|
|
43394
|
-
|
|
43395
|
-
let forumMode = initialForumChatId !== undefined && typeof client.createForumTopic === "function";
|
|
43396
|
-
let forumManageTopicsAvailable = forumMode && forumChatId !== undefined;
|
|
43397
|
-
if (forumChatId !== undefined)
|
|
43435
|
+
if (forumChatId !== undefined) {
|
|
43436
|
+
store.saveGroup({ chatId: forumChatId });
|
|
43398
43437
|
store.saveForumChatId(forumChatId);
|
|
43399
|
-
|
|
43400
|
-
|
|
43438
|
+
}
|
|
43439
|
+
const forumGroups = new Map;
|
|
43440
|
+
for (const group of store.loadGroups()) {
|
|
43441
|
+
forumGroups.set(group.chatId, {
|
|
43442
|
+
chatId: group.chatId,
|
|
43443
|
+
manageTopicsAvailable: group.chatId === forumChatId,
|
|
43444
|
+
configured: group.chatId === forumChatId,
|
|
43445
|
+
permissionRevision: 0
|
|
43446
|
+
});
|
|
43447
|
+
}
|
|
43448
|
+
if (restoredForumChatId !== undefined && !forumGroups.has(restoredForumChatId)) {
|
|
43449
|
+
forumGroups.set(restoredForumChatId, {
|
|
43450
|
+
chatId: restoredForumChatId,
|
|
43451
|
+
manageTopicsAvailable: false,
|
|
43452
|
+
configured: false,
|
|
43453
|
+
permissionRevision: 0
|
|
43454
|
+
});
|
|
43455
|
+
}
|
|
43456
|
+
if (forumGroups.size > 0 && typeof client.createForumTopic !== "function") {
|
|
43457
|
+
logger.warn({ forumChatIds: [...forumGroups.keys()] }, "telegram adapter: forum groups configured but client lacks createForumTopic");
|
|
43401
43458
|
}
|
|
43402
43459
|
const personalGeneral = ensurePersonalGeneral(userId, "telegram");
|
|
43460
|
+
const groupGenerals = new Map;
|
|
43461
|
+
const generalForGroup = (chatId) => {
|
|
43462
|
+
const existing = groupGenerals.get(chatId);
|
|
43463
|
+
if (existing)
|
|
43464
|
+
return existing;
|
|
43465
|
+
const general = ensurePersonalGeneral(userId, "telegram", {
|
|
43466
|
+
surfaceScope: telegramGroupScope(chatId)
|
|
43467
|
+
});
|
|
43468
|
+
groupGenerals.set(chatId, general);
|
|
43469
|
+
return general;
|
|
43470
|
+
};
|
|
43403
43471
|
const byKey = new Map;
|
|
43404
43472
|
const byTopic = new Map;
|
|
43405
43473
|
const targetByQueryId = new Map;
|
|
@@ -43573,6 +43641,22 @@ function startTelegramAdapter(opts) {
|
|
|
43573
43641
|
}
|
|
43574
43642
|
function bindMapping(chatId, threadId, topicId, { persist = true } = {}) {
|
|
43575
43643
|
const key = mappingKey(chatId, threadId);
|
|
43644
|
+
if (forumGroups.has(chatId)) {
|
|
43645
|
+
const topic = getTopic(topicId);
|
|
43646
|
+
const expectedScope = telegramGroupScope(chatId);
|
|
43647
|
+
if (!topic || topic.surface !== "telegram" || (topic.surfaceScope ?? null) !== expectedScope) {
|
|
43648
|
+
throw new Error(`refusing to bind Telegram group ${chatId} to topic ${topicId} outside ${expectedScope}`);
|
|
43649
|
+
}
|
|
43650
|
+
for (const existing of [...byTopic.get(topicId) ?? []]) {
|
|
43651
|
+
if (existing.chatId !== chatId || mappingKey(existing.chatId, existing.threadId) === key) {
|
|
43652
|
+
continue;
|
|
43653
|
+
}
|
|
43654
|
+
detachFromTopic(existing);
|
|
43655
|
+
byKey.delete(mappingKey(existing.chatId, existing.threadId));
|
|
43656
|
+
if (persist)
|
|
43657
|
+
store.deleteByChat(existing.chatId, existing.threadId);
|
|
43658
|
+
}
|
|
43659
|
+
}
|
|
43576
43660
|
const prev = byKey.get(key);
|
|
43577
43661
|
if (prev) {
|
|
43578
43662
|
if (prev.topicId === topicId)
|
|
@@ -43639,7 +43723,8 @@ function startTelegramAdapter(opts) {
|
|
|
43639
43723
|
}
|
|
43640
43724
|
function loadExistingTopic(chatId, topicId, threadId) {
|
|
43641
43725
|
const topic = getTopic(topicId);
|
|
43642
|
-
|
|
43726
|
+
const expectedScope = forumGroups.has(chatId) ? telegramGroupScope(chatId) : null;
|
|
43727
|
+
if (!topic?.participants.some((participant) => participant.userId === userId) || topic.surface !== "telegram" || (topic.surfaceScope ?? null) !== expectedScope) {
|
|
43643
43728
|
return false;
|
|
43644
43729
|
}
|
|
43645
43730
|
bindMapping(chatId, threadId, topic.id);
|
|
@@ -43647,7 +43732,10 @@ function startTelegramAdapter(opts) {
|
|
|
43647
43732
|
}
|
|
43648
43733
|
if (!store.isFlagSet(SURFACE_BACKFILL_FLAG)) {
|
|
43649
43734
|
const mappedIds = [
|
|
43650
|
-
...new Set(store.load().
|
|
43735
|
+
...new Set(store.load().flatMap((mapping) => {
|
|
43736
|
+
const topic = getTopic(mapping.topicId);
|
|
43737
|
+
return topic && topic.kind !== "manager" && topic.participants.some((participant) => participant.userId === userId) ? [topic.id] : [];
|
|
43738
|
+
}))
|
|
43651
43739
|
];
|
|
43652
43740
|
const moved = setTopicSurfaces(mappedIds, "telegram");
|
|
43653
43741
|
store.setFlag(SURFACE_BACKFILL_FLAG);
|
|
@@ -43655,12 +43743,70 @@ function startTelegramAdapter(opts) {
|
|
|
43655
43743
|
logger.info({ moved, mapped: mappedIds.length }, "telegram adapter: moved mapped topics onto the telegram surface");
|
|
43656
43744
|
}
|
|
43657
43745
|
}
|
|
43746
|
+
if (!store.isFlagSet(GROUP_SCOPE_BACKFILL_FLAG)) {
|
|
43747
|
+
const groupIds = new Set(forumGroups.keys());
|
|
43748
|
+
const groupsByTopic = new Map;
|
|
43749
|
+
for (const mapping of store.load()) {
|
|
43750
|
+
if (!groupIds.has(mapping.chatId))
|
|
43751
|
+
continue;
|
|
43752
|
+
const groups = groupsByTopic.get(mapping.topicId) ?? new Set;
|
|
43753
|
+
groups.add(mapping.chatId);
|
|
43754
|
+
groupsByTopic.set(mapping.topicId, groups);
|
|
43755
|
+
}
|
|
43756
|
+
let filed = 0;
|
|
43757
|
+
for (const [topicId, groups] of groupsByTopic) {
|
|
43758
|
+
if (groups.size !== 1) {
|
|
43759
|
+
logger.warn({ topicId, groupIds: [...groups] }, "telegram adapter: legacy topic spans multiple groups; scope migration skipped");
|
|
43760
|
+
continue;
|
|
43761
|
+
}
|
|
43762
|
+
const topic = getTopic(topicId);
|
|
43763
|
+
if (!topic || topic.kind === "manager" || topic.surface !== "telegram" || !topic.participants.some((participant) => participant.userId === userId)) {
|
|
43764
|
+
continue;
|
|
43765
|
+
}
|
|
43766
|
+
const [chatId] = groups;
|
|
43767
|
+
if (chatId !== undefined) {
|
|
43768
|
+
const targetScope = telegramGroupScope(chatId);
|
|
43769
|
+
const currentScope = topic.surfaceScope ?? null;
|
|
43770
|
+
if (currentScope !== null && currentScope !== targetScope) {
|
|
43771
|
+
logger.warn({ topicId, currentScope, targetScope }, "telegram adapter: legacy mapping conflicts with an existing topic namespace");
|
|
43772
|
+
continue;
|
|
43773
|
+
}
|
|
43774
|
+
const titleConflict = findTopicTitleConflict(topic.title, topic.kind ?? "agent", {
|
|
43775
|
+
excludeTopicId: topic.id,
|
|
43776
|
+
surface: "telegram",
|
|
43777
|
+
surfaceScope: targetScope
|
|
43778
|
+
});
|
|
43779
|
+
if (titleConflict) {
|
|
43780
|
+
logger.warn({ topicId, conflictTopicId: titleConflict.id, targetScope }, "telegram adapter: legacy topic title conflicts in target namespace");
|
|
43781
|
+
continue;
|
|
43782
|
+
}
|
|
43783
|
+
filed += Number(setTopicSurfaceScope(topicId, "telegram", targetScope));
|
|
43784
|
+
}
|
|
43785
|
+
}
|
|
43786
|
+
store.setFlag(GROUP_SCOPE_BACKFILL_FLAG);
|
|
43787
|
+
if (filed > 0) {
|
|
43788
|
+
logger.info({ filed }, "telegram adapter: filed legacy topics into group namespaces");
|
|
43789
|
+
}
|
|
43790
|
+
}
|
|
43658
43791
|
for (const persisted of store.load()) {
|
|
43659
43792
|
const topic = getTopic(persisted.topicId);
|
|
43660
|
-
|
|
43793
|
+
const expectedScope = forumGroups.has(persisted.chatId) ? telegramGroupScope(persisted.chatId) : null;
|
|
43794
|
+
if (topic?.participants.some((participant) => participant.userId === userId) && topic.surface === "telegram" && (topic.surfaceScope ?? null) === expectedScope) {
|
|
43661
43795
|
bindMapping(persisted.chatId, persisted.threadId, persisted.topicId, { persist: false });
|
|
43662
43796
|
continue;
|
|
43663
43797
|
}
|
|
43798
|
+
if (topic) {
|
|
43799
|
+
store.deleteByChat(persisted.chatId, persisted.threadId);
|
|
43800
|
+
logger.warn({
|
|
43801
|
+
chatId: persisted.chatId,
|
|
43802
|
+
threadId: persisted.threadId,
|
|
43803
|
+
topicId: persisted.topicId,
|
|
43804
|
+
topicSurface: topic.surface,
|
|
43805
|
+
topicSurfaceScope: topic.surfaceScope ?? null,
|
|
43806
|
+
expectedScope
|
|
43807
|
+
}, "telegram adapter: quarantined mapping outside its topic namespace");
|
|
43808
|
+
continue;
|
|
43809
|
+
}
|
|
43664
43810
|
cleanupPersistedMapping(persisted, "telegram adapter: stale forum thread cleanup failed");
|
|
43665
43811
|
}
|
|
43666
43812
|
function reconcileStaleMappings() {
|
|
@@ -43680,8 +43826,15 @@ function startTelegramAdapter(opts) {
|
|
|
43680
43826
|
suppressMaterialize--;
|
|
43681
43827
|
}
|
|
43682
43828
|
}
|
|
43683
|
-
function getOrCreateTopic(title, agent) {
|
|
43684
|
-
|
|
43829
|
+
function getOrCreateTopic(chatId, title, agent) {
|
|
43830
|
+
const surfaceScope = forumGroups.has(chatId) ? telegramGroupScope(chatId) : null;
|
|
43831
|
+
return getTopicByNameForUser(title, userId, { surface: "telegram", surfaceScope }) ?? registerTopicLocal({
|
|
43832
|
+
title,
|
|
43833
|
+
userId,
|
|
43834
|
+
kind: "agent",
|
|
43835
|
+
surfaceScope,
|
|
43836
|
+
...agent ? { agent } : {}
|
|
43837
|
+
});
|
|
43685
43838
|
}
|
|
43686
43839
|
function resolveMapping(chatId, threadId) {
|
|
43687
43840
|
const cached = byKey.get(mappingKey(chatId, threadId));
|
|
@@ -43691,7 +43844,7 @@ function startTelegramAdapter(opts) {
|
|
|
43691
43844
|
return topic2;
|
|
43692
43845
|
unbindTopic(cached.topicId);
|
|
43693
43846
|
}
|
|
43694
|
-
const topic = getOrCreateTopic(titleFor(chatId, threadId), opts.defaultAgent);
|
|
43847
|
+
const topic = getOrCreateTopic(chatId, titleFor(chatId, threadId), opts.defaultAgent);
|
|
43695
43848
|
bindMapping(chatId, threadId, topic.id);
|
|
43696
43849
|
return topic;
|
|
43697
43850
|
}
|
|
@@ -44009,12 +44162,16 @@ function startTelegramAdapter(opts) {
|
|
|
44009
44162
|
const pendingByTopic = new Map;
|
|
44010
44163
|
const permissionBlockedTopics = new Map;
|
|
44011
44164
|
const materializeTombstones = new Map;
|
|
44012
|
-
if (
|
|
44165
|
+
if (forumGroups.size > 0) {
|
|
44013
44166
|
for (const t of store.loadTombstones())
|
|
44014
44167
|
materializeTombstones.set(t.topicId, t.title);
|
|
44015
44168
|
}
|
|
44016
44169
|
function deliverFallback(topicId, title, payload) {
|
|
44017
|
-
|
|
44170
|
+
const topic = getTopic(topicId);
|
|
44171
|
+
const chatId = telegramGroupIdFromScope(topic?.surfaceScope);
|
|
44172
|
+
if (chatId === null)
|
|
44173
|
+
return Promise.resolve();
|
|
44174
|
+
return deliverToTargets(topicId, [{ chatId, topicId }], {
|
|
44018
44175
|
text: payload.text ? `[${title}] ${payload.text}` : "",
|
|
44019
44176
|
files: payload.files,
|
|
44020
44177
|
runtimeMessageId: payload.runtimeMessageId,
|
|
@@ -44027,16 +44184,18 @@ function startTelegramAdapter(opts) {
|
|
|
44027
44184
|
}
|
|
44028
44185
|
}
|
|
44029
44186
|
function materializeTopic(topic) {
|
|
44030
|
-
if (
|
|
44187
|
+
if (topic.surface !== "telegram" || !topic.participants?.some((participant) => participant.userId === userId)) {
|
|
44031
44188
|
return false;
|
|
44032
44189
|
}
|
|
44033
|
-
|
|
44190
|
+
const materializationChat = telegramGroupIdFromScope(topic.surfaceScope);
|
|
44191
|
+
if (materializationChat === null)
|
|
44034
44192
|
return false;
|
|
44035
|
-
|
|
44193
|
+
const group = forumGroups.get(materializationChat);
|
|
44194
|
+
if (!group?.manageTopicsAvailable || suppressMaterialize > 0 || byTopic.has(topic.id) || pendingByTopic.has(topic.id) || permissionBlockedTopics.has(topic.id) || materializeTombstones.has(topic.id)) {
|
|
44036
44195
|
return false;
|
|
44037
|
-
|
|
44196
|
+
}
|
|
44197
|
+
if (!isTopicVisible(topic))
|
|
44038
44198
|
return false;
|
|
44039
|
-
const materializationChat = forumChat;
|
|
44040
44199
|
const pending2 = { buffer: [], cancelled: false };
|
|
44041
44200
|
pendingByTopic.set(topic.id, pending2);
|
|
44042
44201
|
(async () => {
|
|
@@ -44050,12 +44209,12 @@ function startTelegramAdapter(opts) {
|
|
|
44050
44209
|
return;
|
|
44051
44210
|
const errorInfo = telegramErrorInfo(err2);
|
|
44052
44211
|
if (isManageTopicsPermissionError(errorInfo)) {
|
|
44053
|
-
const permissionWasAvailable =
|
|
44054
|
-
|
|
44212
|
+
const permissionWasAvailable = group.manageTopicsAvailable;
|
|
44213
|
+
group.manageTopicsAvailable = false;
|
|
44055
44214
|
permissionBlockedTopics.set(topic.id, topic.title);
|
|
44056
44215
|
logger.warn({ err: err2, topicId: topic.id, title: topic.title }, "telegram adapter: Manage Topics unavailable \u2014 waiting for permission recovery");
|
|
44057
44216
|
if (permissionWasAvailable) {
|
|
44058
|
-
reply(
|
|
44217
|
+
reply(materializationChat, undefined, 'Forum topic creation is paused. Enable the bot administrator permission "Manage Topics"; pending topics will be retried automatically.');
|
|
44059
44218
|
}
|
|
44060
44219
|
flushBuffered(topic.id, pending2.buffer, (payload) => deliverFallback(topic.id, topic.title, payload));
|
|
44061
44220
|
return;
|
|
@@ -44144,8 +44303,10 @@ function startTelegramAdapter(opts) {
|
|
|
44144
44303
|
const topic = getTopic(topicId);
|
|
44145
44304
|
if (!topic)
|
|
44146
44305
|
return false;
|
|
44147
|
-
|
|
44148
|
-
|
|
44306
|
+
const groupId = telegramGroupIdFromScope(topic.surfaceScope);
|
|
44307
|
+
const group = groupId === null ? undefined : forumGroups.get(groupId);
|
|
44308
|
+
if (group) {
|
|
44309
|
+
if (!group.manageTopicsAvailable || permissionBlockedTopics.has(topicId)) {
|
|
44149
44310
|
enqueueSend(topicId, () => deliverFallback(topicId, topic.title, payload)).then(payload.onSettled);
|
|
44150
44311
|
return true;
|
|
44151
44312
|
}
|
|
@@ -44291,32 +44452,52 @@ ${suffix}`;
|
|
|
44291
44452
|
return;
|
|
44292
44453
|
await client.sendMessage(chatId, onboardingGuide(bot?.username), threadOpts(threadId)).catch((err2) => logger.warn({ err: err2, chatId }, "telegram adapter: onboarding guide failed"));
|
|
44293
44454
|
}
|
|
44294
|
-
function materializeVisibleTopics() {
|
|
44295
|
-
|
|
44455
|
+
function materializeVisibleTopics(chatId) {
|
|
44456
|
+
const group = forumGroups.get(chatId);
|
|
44457
|
+
if (!group?.manageTopicsAvailable)
|
|
44296
44458
|
return;
|
|
44297
|
-
|
|
44459
|
+
const topics = listTopics({
|
|
44460
|
+
surface: "telegram",
|
|
44461
|
+
surfaceScope: telegramGroupScope(chatId)
|
|
44462
|
+
});
|
|
44463
|
+
for (const topic of topics) {
|
|
44464
|
+
if (topic.kind === "manager")
|
|
44465
|
+
continue;
|
|
44298
44466
|
if (isTopicVisible(topic) && topic.participants.some((participant) => participant.userId === userId)) {
|
|
44299
44467
|
materializeTopic(topic);
|
|
44300
44468
|
}
|
|
44301
44469
|
}
|
|
44302
44470
|
}
|
|
44303
|
-
function restoreForumTopicCreation({ retryPermanent = false } = {}) {
|
|
44304
|
-
|
|
44305
|
-
|
|
44471
|
+
function restoreForumTopicCreation(chatId, { retryPermanent = false } = {}) {
|
|
44472
|
+
const group = forumGroups.get(chatId);
|
|
44473
|
+
if (!group)
|
|
44474
|
+
return;
|
|
44475
|
+
group.manageTopicsAvailable = true;
|
|
44476
|
+
for (const topicId of [...permissionBlockedTopics.keys()]) {
|
|
44477
|
+
if (telegramGroupIdFromScope(getTopic(topicId)?.surfaceScope) === chatId) {
|
|
44478
|
+
permissionBlockedTopics.delete(topicId);
|
|
44479
|
+
}
|
|
44480
|
+
}
|
|
44306
44481
|
if (retryPermanent) {
|
|
44307
|
-
materializeTombstones.
|
|
44308
|
-
|
|
44482
|
+
for (const topicId of [...materializeTombstones.keys()]) {
|
|
44483
|
+
if (telegramGroupIdFromScope(getTopic(topicId)?.surfaceScope) === chatId) {
|
|
44484
|
+
materializeTombstones.delete(topicId);
|
|
44485
|
+
store.deleteTombstone(topicId);
|
|
44486
|
+
}
|
|
44487
|
+
}
|
|
44309
44488
|
}
|
|
44310
44489
|
reconcileStaleMappings();
|
|
44311
|
-
materializeVisibleTopics();
|
|
44490
|
+
materializeVisibleTopics(chatId);
|
|
44312
44491
|
}
|
|
44313
44492
|
async function notifyOwnerDms(text2) {
|
|
44314
44493
|
await Promise.allSettled([...ownerDmChatIds].map((chatId) => client.sendMessage(chatId, text2)));
|
|
44315
44494
|
}
|
|
44316
44495
|
async function disconnectForum(chatId) {
|
|
44317
|
-
if (!
|
|
44496
|
+
if (!forumGroups.has(chatId))
|
|
44318
44497
|
return false;
|
|
44319
44498
|
for (const [topicId, pending2] of pendingByTopic) {
|
|
44499
|
+
if (telegramGroupIdFromScope(getTopic(topicId)?.surfaceScope) !== chatId)
|
|
44500
|
+
continue;
|
|
44320
44501
|
pending2.cancelled = true;
|
|
44321
44502
|
if (pendingByTopic.get(topicId) === pending2)
|
|
44322
44503
|
pendingByTopic.delete(topicId);
|
|
@@ -44329,14 +44510,23 @@ ${suffix}`;
|
|
|
44329
44510
|
if (target.chatId === chatId)
|
|
44330
44511
|
targetByQueryId.delete(queryId);
|
|
44331
44512
|
}
|
|
44332
|
-
permissionBlockedTopics.
|
|
44333
|
-
|
|
44334
|
-
|
|
44513
|
+
for (const topicId of [...permissionBlockedTopics.keys()]) {
|
|
44514
|
+
if (telegramGroupIdFromScope(getTopic(topicId)?.surfaceScope) === chatId) {
|
|
44515
|
+
permissionBlockedTopics.delete(topicId);
|
|
44516
|
+
}
|
|
44517
|
+
}
|
|
44518
|
+
for (const topicId of [...materializeTombstones.keys()]) {
|
|
44519
|
+
if (telegramGroupIdFromScope(getTopic(topicId)?.surfaceScope) === chatId) {
|
|
44520
|
+
materializeTombstones.delete(topicId);
|
|
44521
|
+
store.deleteTombstone(topicId);
|
|
44522
|
+
}
|
|
44523
|
+
}
|
|
44335
44524
|
store.outboxDeleteByChat(chatId);
|
|
44336
|
-
store.
|
|
44337
|
-
|
|
44338
|
-
|
|
44339
|
-
|
|
44525
|
+
store.deleteGroup(chatId);
|
|
44526
|
+
if (store.loadForumChatId() === chatId)
|
|
44527
|
+
store.clearForumChatId();
|
|
44528
|
+
forumGroups.delete(chatId);
|
|
44529
|
+
groupGenerals.delete(chatId);
|
|
44340
44530
|
await notifyOwnerDms("The Telegram forum was disconnected because the bot left or was removed. Your Negotium topics were preserved; promote the bot in a forum group to reconnect.");
|
|
44341
44531
|
logger.info({ userId, forumChatId: chatId }, "telegram adapter: forum disconnected");
|
|
44342
44532
|
return true;
|
|
@@ -44346,16 +44536,14 @@ ${suffix}`;
|
|
|
44346
44536
|
reply(ownerTelegramId, undefined, "This Telegram client cannot create forum topics, so the group was not connected.");
|
|
44347
44537
|
return false;
|
|
44348
44538
|
}
|
|
44349
|
-
if (forumMode && forumChat !== chat.id) {
|
|
44350
|
-
reply(ownerTelegramId, undefined, `A different forum group (${forumChat}) is already connected to this Negotium node.`);
|
|
44351
|
-
return false;
|
|
44352
|
-
}
|
|
44353
44539
|
const hasManageTopics = canManageTopics(botMember);
|
|
44354
|
-
|
|
44355
|
-
|
|
44356
|
-
|
|
44540
|
+
const existingGroup = forumGroups.get(chat.id);
|
|
44541
|
+
if (existingGroup) {
|
|
44542
|
+
existingGroup.permissionRevision += 1;
|
|
44543
|
+
const recovered = hasManageTopics && !existingGroup.manageTopicsAvailable;
|
|
44544
|
+
const lostPermission = !hasManageTopics && existingGroup.manageTopicsAvailable;
|
|
44357
44545
|
if (hasManageTopics) {
|
|
44358
|
-
restoreForumTopicCreation({ retryPermanent: recovered });
|
|
44546
|
+
restoreForumTopicCreation(chat.id, { retryPermanent: recovered });
|
|
44359
44547
|
if (recovered) {
|
|
44360
44548
|
await Promise.allSettled([
|
|
44361
44549
|
client.sendMessage(chat.id, "Manage Topics permission confirmed. Pending Negotium topics are being created now."),
|
|
@@ -44363,23 +44551,29 @@ ${suffix}`;
|
|
|
44363
44551
|
]);
|
|
44364
44552
|
}
|
|
44365
44553
|
} else {
|
|
44366
|
-
|
|
44554
|
+
existingGroup.manageTopicsAvailable = false;
|
|
44367
44555
|
if (lostPermission) {
|
|
44368
44556
|
await notifyOwnerDms(`Manage Topics permission was removed from \u201C${chat.title?.trim() || chat.id}\u201D. Existing topics are preserved; restore the permission to resume topic creation.`);
|
|
44369
44557
|
}
|
|
44370
44558
|
}
|
|
44371
44559
|
return true;
|
|
44372
44560
|
}
|
|
44373
|
-
|
|
44374
|
-
|
|
44375
|
-
|
|
44376
|
-
|
|
44377
|
-
|
|
44378
|
-
|
|
44379
|
-
store.
|
|
44380
|
-
|
|
44561
|
+
forumGroups.set(chat.id, {
|
|
44562
|
+
chatId: chat.id,
|
|
44563
|
+
manageTopicsAvailable: hasManageTopics,
|
|
44564
|
+
configured: chat.id === forumChatId,
|
|
44565
|
+
permissionRevision: 1
|
|
44566
|
+
});
|
|
44567
|
+
store.saveGroup({
|
|
44568
|
+
chatId: chat.id,
|
|
44569
|
+
title: chat.title?.trim(),
|
|
44570
|
+
ownerTelegramUserId: ownerTelegramId
|
|
44571
|
+
});
|
|
44572
|
+
if (store.loadForumChatId() === undefined)
|
|
44573
|
+
store.saveForumChatId(chat.id);
|
|
44574
|
+
bindMapping(chat.id, undefined, generalForGroup(chat.id).id);
|
|
44381
44575
|
ownerDmChatIds.add(ownerTelegramId);
|
|
44382
|
-
materializeVisibleTopics();
|
|
44576
|
+
materializeVisibleTopics(chat.id);
|
|
44383
44577
|
const title = chat.title?.trim() || String(chat.id);
|
|
44384
44578
|
const permissionWarning = hasManageTopics ? "" : `
|
|
44385
44579
|
|
|
@@ -44401,9 +44595,8 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44401
44595
|
if (msg.chat.type !== "supergroup" || !msg.chat.is_forum || senderId === undefined || !isAllowed(senderId)) {
|
|
44402
44596
|
return false;
|
|
44403
44597
|
}
|
|
44404
|
-
|
|
44405
|
-
|
|
44406
|
-
if (forumMode && forumManageTopicsAvailable)
|
|
44598
|
+
const connected = forumGroups.get(msg.chat.id);
|
|
44599
|
+
if (connected?.manageTopicsAvailable)
|
|
44407
44600
|
return true;
|
|
44408
44601
|
if (typeof client.getMe !== "function" || typeof client.getChatMember !== "function") {
|
|
44409
44602
|
return false;
|
|
@@ -44419,38 +44612,49 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44419
44612
|
if (!isChatAdmin(botMember) || !isChatAdmin(senderMember))
|
|
44420
44613
|
return false;
|
|
44421
44614
|
await linkForumAndAnnounce(senderId, msg.chat, botMember);
|
|
44422
|
-
return
|
|
44615
|
+
return forumGroups.has(msg.chat.id);
|
|
44423
44616
|
} catch (err2) {
|
|
44424
44617
|
logger.debug({ err: err2, groupId: msg.chat.id, senderId }, "telegram adapter: lazy forum auto-connect check failed");
|
|
44425
44618
|
return false;
|
|
44426
44619
|
}
|
|
44427
44620
|
}
|
|
44428
44621
|
async function verifyInitialForumPermissions() {
|
|
44429
|
-
|
|
44430
|
-
|
|
44431
|
-
if (forumChatId !== undefined)
|
|
44622
|
+
const initialGroups = [...forumGroups.values()];
|
|
44623
|
+
if (initialGroups.length === 0)
|
|
44432
44624
|
return;
|
|
44433
44625
|
if (typeof client.getMe !== "function" || typeof client.getChatMember !== "function") {
|
|
44434
|
-
|
|
44626
|
+
for (const group of initialGroups) {
|
|
44627
|
+
if (forumGroups.get(group.chatId) === group)
|
|
44628
|
+
group.manageTopicsAvailable = true;
|
|
44629
|
+
}
|
|
44435
44630
|
return;
|
|
44436
44631
|
}
|
|
44437
|
-
|
|
44438
|
-
|
|
44439
|
-
|
|
44440
|
-
|
|
44441
|
-
|
|
44442
|
-
|
|
44443
|
-
|
|
44444
|
-
|
|
44445
|
-
|
|
44446
|
-
|
|
44447
|
-
const
|
|
44448
|
-
|
|
44449
|
-
|
|
44450
|
-
|
|
44632
|
+
const bot = await resolveBotIdentity();
|
|
44633
|
+
if (!bot || stopped)
|
|
44634
|
+
return;
|
|
44635
|
+
for (const group of initialGroups) {
|
|
44636
|
+
if (forumGroups.get(group.chatId) !== group)
|
|
44637
|
+
continue;
|
|
44638
|
+
if (group.configured)
|
|
44639
|
+
continue;
|
|
44640
|
+
try {
|
|
44641
|
+
const permissionRevision = group.permissionRevision;
|
|
44642
|
+
const member = await client.getChatMember(group.chatId, bot.id);
|
|
44643
|
+
if (forumGroups.get(group.chatId) !== group || group.permissionRevision !== permissionRevision) {
|
|
44644
|
+
continue;
|
|
44645
|
+
}
|
|
44646
|
+
if (member.status === "left" || member.status === "kicked") {
|
|
44647
|
+
await disconnectForum(group.chatId);
|
|
44648
|
+
continue;
|
|
44649
|
+
}
|
|
44650
|
+
if (canManageTopics(member)) {
|
|
44651
|
+
restoreForumTopicCreation(group.chatId, { retryPermanent: !group.configured });
|
|
44652
|
+
} else {
|
|
44653
|
+
group.manageTopicsAvailable = false;
|
|
44654
|
+
}
|
|
44655
|
+
} catch (err2) {
|
|
44656
|
+
logger.warn({ err: err2, forumChatId: group.chatId }, "telegram adapter: initial forum permission check failed");
|
|
44451
44657
|
}
|
|
44452
|
-
} catch (err2) {
|
|
44453
|
-
logger.warn({ err: err2, forumChatId: forumChat }, "telegram adapter: initial forum permission check failed");
|
|
44454
44658
|
}
|
|
44455
44659
|
}
|
|
44456
44660
|
verifyInitialForumPermissions();
|
|
@@ -44502,7 +44706,8 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44502
44706
|
const handleCommand = createTelegramCommandRouter({
|
|
44503
44707
|
userId,
|
|
44504
44708
|
defaultAgent: opts.defaultAgent,
|
|
44505
|
-
|
|
44709
|
+
surfaceScopeFor: (chatId) => forumGroups.has(chatId) ? telegramGroupScope(chatId) : null,
|
|
44710
|
+
isForumGeneral: (chatId, threadId) => forumGroups.has(chatId) && threadId === undefined,
|
|
44506
44711
|
resolveBotUsername: async () => (await resolveBotIdentity())?.username,
|
|
44507
44712
|
isVaultOwner,
|
|
44508
44713
|
reply,
|
|
@@ -44528,8 +44733,10 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44528
44733
|
const firstPrivateContact = privateDm && !byKey.has(mappingKey(chatId));
|
|
44529
44734
|
if (privateDm)
|
|
44530
44735
|
ownerDmChatIds.add(chatId);
|
|
44531
|
-
if (privateDm
|
|
44736
|
+
if (privateDm) {
|
|
44532
44737
|
bindMapping(chatId, threadId, personalGeneral.id);
|
|
44738
|
+
} else if (forumGroups.has(chatId) && threadId === undefined) {
|
|
44739
|
+
bindMapping(chatId, threadId, generalForGroup(chatId).id);
|
|
44533
44740
|
}
|
|
44534
44741
|
if (firstPrivateContact && text2 !== "/start") {
|
|
44535
44742
|
sendOnboardingGuide(chatId);
|
|
@@ -44561,9 +44768,7 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44561
44768
|
if (!isAllowed(msg.from?.id))
|
|
44562
44769
|
return;
|
|
44563
44770
|
if (msg.chat.type === "supergroup" && msg.chat.is_forum) {
|
|
44564
|
-
if (
|
|
44565
|
-
return;
|
|
44566
|
-
if (!forumMode || !forumManageTopicsAvailable) {
|
|
44771
|
+
if (!forumGroups.get(msg.chat.id)?.manageTopicsAvailable) {
|
|
44567
44772
|
tryAutoConnectFromMessage(msg).then((connected) => {
|
|
44568
44773
|
if (connected && !stopped)
|
|
44569
44774
|
handleIncomingMessage(msg);
|
|
@@ -44577,19 +44782,21 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44577
44782
|
if (stopped || update.chat.type !== "supergroup" || !update.chat.is_forum)
|
|
44578
44783
|
return;
|
|
44579
44784
|
const status = update.new_chat_member?.status;
|
|
44580
|
-
if ((status === "left" || status === "kicked") &&
|
|
44785
|
+
if ((status === "left" || status === "kicked") && forumGroups.has(update.chat.id)) {
|
|
44581
44786
|
disconnectForum(update.chat.id).catch((err2) => logger.warn({ err: err2, groupId: update.chat.id }, "telegram adapter: forum disconnect failed"));
|
|
44582
44787
|
return;
|
|
44583
44788
|
}
|
|
44584
|
-
if (
|
|
44585
|
-
const
|
|
44586
|
-
|
|
44789
|
+
if (forumGroups.has(update.chat.id) && status !== "administrator" && status !== "creator") {
|
|
44790
|
+
const group = forumGroups.get(update.chat.id);
|
|
44791
|
+
group.permissionRevision += 1;
|
|
44792
|
+
const permissionWasAvailable = group.manageTopicsAvailable;
|
|
44793
|
+
group.manageTopicsAvailable = false;
|
|
44587
44794
|
if (permissionWasAvailable) {
|
|
44588
44795
|
notifyOwnerDms('The bot no longer has forum administrator access. Existing topics are preserved; restore administrator + "Manage Topics" to resume topic creation.');
|
|
44589
44796
|
}
|
|
44590
44797
|
return;
|
|
44591
44798
|
}
|
|
44592
|
-
if (status !== "administrator" && status !== "creator" || update.from?.id === undefined || !isAllowed(update.from.id) && (
|
|
44799
|
+
if (status !== "administrator" && status !== "creator" || update.from?.id === undefined || !isAllowed(update.from.id) && !forumGroups.has(update.chat.id)) {
|
|
44593
44800
|
return;
|
|
44594
44801
|
}
|
|
44595
44802
|
linkForumAndAnnounce(update.from.id, update.chat, update.new_chat_member).catch((err2) => logger.warn({ err: err2, groupId: update.chat.id }, "telegram adapter: forum auto-connect failed"));
|
|
@@ -44704,7 +44911,7 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44704
44911
|
const unsubscribe = runtimeBus().subscribe((event) => {
|
|
44705
44912
|
if (stopped)
|
|
44706
44913
|
return;
|
|
44707
|
-
if (event.type === "topic-created"
|
|
44914
|
+
if (event.type === "topic-created") {
|
|
44708
44915
|
materializeTopic(event.payload);
|
|
44709
44916
|
return;
|
|
44710
44917
|
}
|
|
@@ -44755,9 +44962,9 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44755
44962
|
pollRuntimeEvents();
|
|
44756
44963
|
const runtimeEventPollTimer = setInterval(pollRuntimeEvents, 100);
|
|
44757
44964
|
runtimeEventPollTimer.unref?.();
|
|
44758
|
-
|
|
44759
|
-
bindMapping(
|
|
44760
|
-
materializeVisibleTopics();
|
|
44965
|
+
for (const group of forumGroups.values()) {
|
|
44966
|
+
bindMapping(group.chatId, undefined, generalForGroup(group.chatId).id);
|
|
44967
|
+
materializeVisibleTopics(group.chatId);
|
|
44761
44968
|
}
|
|
44762
44969
|
return {
|
|
44763
44970
|
name: "telegram",
|
|
@@ -44780,7 +44987,7 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44780
44987
|
}
|
|
44781
44988
|
};
|
|
44782
44989
|
}
|
|
44783
|
-
var SURFACE_BACKFILL_FLAG = "surface_backfill_20260808", FORUM_TOPIC_NAME_MAX = 128, MAX_PARENT_HOPS = 5, DEFAULT_SEND_TIMEOUT_MS = 60000, PHOTO_EXTS;
|
|
44990
|
+
var SURFACE_BACKFILL_FLAG = "surface_backfill_20260808", GROUP_SCOPE_BACKFILL_FLAG = "telegram_group_scope_backfill_20260829", FORUM_TOPIC_NAME_MAX = 128, MAX_PARENT_HOPS = 5, DEFAULT_SEND_TIMEOUT_MS = 60000, PHOTO_EXTS;
|
|
44784
44991
|
var init_adapter = __esm(async () => {
|
|
44785
44992
|
await init_src();
|
|
44786
44993
|
await init_commands2();
|
|
@@ -49743,4 +49950,4 @@ switch (command) {
|
|
|
49743
49950
|
}
|
|
49744
49951
|
}
|
|
49745
49952
|
|
|
49746
|
-
//# debugId=
|
|
49953
|
+
//# debugId=37C7DCC041D0DB9F64756E2164756E21
|