@deadragdoll/tellymcp 0.0.1
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/.env.example.client +93 -0
- package/.env.example.gateway +120 -0
- package/CHANGELOG.md +155 -0
- package/LICENSE +21 -0
- package/README-ru.md +338 -0
- package/README.md +1262 -0
- package/STANDALONE-ru.md +266 -0
- package/STANDALONE.md +266 -0
- package/TOOLS.md +1296 -0
- package/config/templates/env.both.template +83 -0
- package/config/templates/env.client.template +60 -0
- package/config/templates/env.gateway.template +82 -0
- package/dist/cli.js +636 -0
- package/dist/index.js +17 -0
- package/dist/lib/logfeed/store.js +52 -0
- package/dist/lib/middlewares/tracer.js +172 -0
- package/dist/lib/mixins/db.js +267 -0
- package/dist/lib/mixins/logfeed.js +34 -0
- package/dist/lib/mixins/session.errors.js +142 -0
- package/dist/lib/moleculer.js +2 -0
- package/dist/lib/trace.js +147 -0
- package/dist/lib/traceContext.js +116 -0
- package/dist/moleculer.config.js +274 -0
- package/dist/services/features/telegram-mcp/approval.service.js +33 -0
- package/dist/services/features/telegram-mcp/browser.service.js +42 -0
- package/dist/services/features/telegram-mcp/collaboration.service.js +53 -0
- package/dist/services/features/telegram-mcp/ensuredb.service.js +337 -0
- package/dist/services/features/telegram-mcp/gateway-delivery.service.js +378 -0
- package/dist/services/features/telegram-mcp/gateway-loopback.js +10 -0
- package/dist/services/features/telegram-mcp/gateway-rmq.service.js +294 -0
- package/dist/services/features/telegram-mcp/gateway-socket.service.js +1463 -0
- package/dist/services/features/telegram-mcp/gateway.service.js +1141 -0
- package/dist/services/features/telegram-mcp/inbox.service.js +33 -0
- package/dist/services/features/telegram-mcp/mcp-http.service.js +76 -0
- package/dist/services/features/telegram-mcp/mcp-server.service.js +127 -0
- package/dist/services/features/telegram-mcp/notify.service.js +33 -0
- package/dist/services/features/telegram-mcp/pair.service.js +33 -0
- package/dist/services/features/telegram-mcp/runtime.service.js +36 -0
- package/dist/services/features/telegram-mcp/session-context.service.js +33 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +103 -0
- package/dist/services/features/telegram-mcp/src/app/config/env.js +317 -0
- package/dist/services/features/telegram-mcp/src/app/http.js +774 -0
- package/dist/services/features/telegram-mcp/src/app/index.js +2 -0
- package/dist/services/features/telegram-mcp/src/app/providers/mcp/server.js +13 -0
- package/dist/services/features/telegram-mcp/src/app/providers/redis/client.js +18 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +740 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +267 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/relay.js +69 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +9 -0
- package/dist/services/features/telegram-mcp/src/entities/auth/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/browser/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/collaboration/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/inbox/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +545 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/session/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClearLogsTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClickTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserCloseTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserComputedStyleTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserConsoleTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserErrorsTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserNetworkFailuresTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserOpenTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserReloadTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +689 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForUrlTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/backend.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +26 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +390 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +102 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +69 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +657 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayReplyResolution.js +17 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +77 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +93 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +202 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +409 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +123 -0
- package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +243 -0
- package/dist/services/features/telegram-mcp/src/shared/api/storage/contract.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/registry.js +8 -0
- package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/api/transport/contract.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +86 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +436 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabSemantics.js +21 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabUi.js +87 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/messageFormat.js +60 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +46 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +6534 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +280 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/ids/ids.js +34 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +68 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +223 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/redact-secrets/redactSecrets.js +22 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/truncate/truncate.js +12 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +124 -0
- package/dist/services/features/telegram-mcp/src/shared/types/common.js +2 -0
- package/dist/services/features/telegram-mcp/standalone-http.service.js +113 -0
- package/dist/services/features/telegram-mcp/tools-sync.service.js +33 -0
- package/package.json +110 -0
- package/scripts/postinstall.js +60 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeleteTelegramInboxMessageTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
function createContent(output) {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
type: "text",
|
|
9
|
+
text: JSON.stringify(output, null, 2),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
class DeleteTelegramInboxMessageTool {
|
|
14
|
+
inboxService;
|
|
15
|
+
constructor(inboxService) {
|
|
16
|
+
this.inboxService = inboxService;
|
|
17
|
+
}
|
|
18
|
+
register(server) {
|
|
19
|
+
server.registerTool("delete_telegram_inbox_message", {
|
|
20
|
+
title: "Delete Telegram Inbox Message",
|
|
21
|
+
description: "Use this only after you have fully processed an ordinary human Telegram inbox message. Pass session_id explicitly after pairing; do not rely on implicit defaults unless cwd is also correct for this agent workspace. Delete the message so future inbox reads do not return it again.",
|
|
22
|
+
inputSchema: schema_1.deleteTelegramInboxMessageInputSchema,
|
|
23
|
+
outputSchema: schema_1.deleteTelegramInboxMessageOutputSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const output = await this.inboxService.deleteInboxMessage(args);
|
|
26
|
+
return {
|
|
27
|
+
content: createContent(output),
|
|
28
|
+
structuredContent: output,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.DeleteTelegramInboxMessageTool = DeleteTelegramInboxMessageTool;
|
package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetTelegramInboxCountTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
function createContent(output) {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
type: "text",
|
|
9
|
+
text: JSON.stringify(output, null, 2),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
class GetTelegramInboxCountTool {
|
|
14
|
+
inboxService;
|
|
15
|
+
constructor(inboxService) {
|
|
16
|
+
this.inboxService = inboxService;
|
|
17
|
+
}
|
|
18
|
+
register(server) {
|
|
19
|
+
server.registerTool("get_telegram_inbox_count", {
|
|
20
|
+
title: "Get Telegram Inbox Count",
|
|
21
|
+
description: "Use this to cheaply check whether ordinary human Telegram messages are waiting for the session. Pass session_id explicitly after pairing; do not rely on implicit defaults unless cwd is also correct for this agent workspace. Do not use it for partner-note wakeups; partner notes must be read from .mcp-xchange/SHARED_INDEX.md instead.",
|
|
22
|
+
inputSchema: schema_1.getTelegramInboxCountInputSchema,
|
|
23
|
+
outputSchema: schema_1.getTelegramInboxCountOutputSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const output = await this.inboxService.getInboxCount(args);
|
|
26
|
+
return {
|
|
27
|
+
content: createContent(output),
|
|
28
|
+
structuredContent: output,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.GetTelegramInboxCountTool = GetTelegramInboxCountTool;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetTelegramInboxTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
function createContent(output) {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
type: "text",
|
|
9
|
+
text: JSON.stringify(output, null, 2),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
class GetTelegramInboxTool {
|
|
14
|
+
inboxService;
|
|
15
|
+
constructor(inboxService) {
|
|
16
|
+
this.inboxService = inboxService;
|
|
17
|
+
}
|
|
18
|
+
register(server) {
|
|
19
|
+
server.registerTool("get_telegram_inbox", {
|
|
20
|
+
title: "Get Telegram Inbox",
|
|
21
|
+
description: "Use this to read unsolicited Telegram inbox messages stored for the session. Pass session_id explicitly after pairing; do not rely on implicit defaults unless cwd is also correct for this agent workspace. Each item now includes message_kind: human or system. Treat system messages as operational instructions from the service, not as normal user prompts. Returned items may also include local attachment paths from .mcp-xchange when the human message contained a photo or document. Do not use this first for partner-note wakeups; partner collaboration notes must be read from .mcp-xchange/SHARED_INDEX.md and the referenced note files.",
|
|
22
|
+
inputSchema: schema_1.getTelegramInboxInputSchema,
|
|
23
|
+
outputSchema: schema_1.getTelegramInboxOutputSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const output = await this.inboxService.getInbox(args);
|
|
26
|
+
return {
|
|
27
|
+
content: createContent(output),
|
|
28
|
+
structuredContent: output,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.GetTelegramInboxTool = GetTelegramInboxTool;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InboxService = void 0;
|
|
4
|
+
class InboxService {
|
|
5
|
+
config;
|
|
6
|
+
inboxStore;
|
|
7
|
+
_sessionStore;
|
|
8
|
+
logger;
|
|
9
|
+
projectIdentityResolver;
|
|
10
|
+
constructor(config, inboxStore, _sessionStore, logger, projectIdentityResolver) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.inboxStore = inboxStore;
|
|
13
|
+
this._sessionStore = _sessionStore;
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
this.projectIdentityResolver = projectIdentityResolver;
|
|
16
|
+
}
|
|
17
|
+
async getInboxCount(input) {
|
|
18
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
19
|
+
const total = await this.inboxStore.countInboxMessages(resolved.sessionId);
|
|
20
|
+
this.logger.info("Telegram inbox count fetched", {
|
|
21
|
+
sessionId: resolved.sessionId,
|
|
22
|
+
sessionIdDerived: resolved.sessionIdDerived,
|
|
23
|
+
total,
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
session_id: resolved.sessionId,
|
|
27
|
+
total,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async getInbox(input) {
|
|
31
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
32
|
+
const limit = this.config.telegram.inboxBatchSize;
|
|
33
|
+
const messages = await this.inboxStore.listInboxMessages(resolved.sessionId, limit);
|
|
34
|
+
const total = await this.inboxStore.countInboxMessages(resolved.sessionId);
|
|
35
|
+
this.logger.info("Telegram inbox fetched", {
|
|
36
|
+
sessionId: resolved.sessionId,
|
|
37
|
+
sessionIdDerived: resolved.sessionIdDerived,
|
|
38
|
+
limit,
|
|
39
|
+
returned: messages.length,
|
|
40
|
+
total,
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
session_id: resolved.sessionId,
|
|
44
|
+
total,
|
|
45
|
+
has_more: total > messages.length,
|
|
46
|
+
messages: messages.map((message) => ({
|
|
47
|
+
message_id: message.id,
|
|
48
|
+
source: "telegram",
|
|
49
|
+
message_kind: message.sourceTelegramMessageId > 0 ? "human" : "system",
|
|
50
|
+
telegram_chat_id: message.telegramChatId,
|
|
51
|
+
telegram_user_id: message.telegramUserId,
|
|
52
|
+
telegram_message_id: message.sourceTelegramMessageId,
|
|
53
|
+
text: message.text,
|
|
54
|
+
...(message.attachments?.length
|
|
55
|
+
? { attachments: message.attachments }
|
|
56
|
+
: {}),
|
|
57
|
+
received_at: message.receivedAt,
|
|
58
|
+
})),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async deleteInboxMessage(input) {
|
|
62
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
63
|
+
const deleted = await this.inboxStore.deleteInboxMessage(resolved.sessionId, input.message_id);
|
|
64
|
+
this.logger.info("Telegram inbox message deleted", {
|
|
65
|
+
sessionId: resolved.sessionId,
|
|
66
|
+
sessionIdDerived: resolved.sessionIdDerived,
|
|
67
|
+
messageId: input.message_id,
|
|
68
|
+
deleted,
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
deleted,
|
|
72
|
+
session_id: resolved.sessionId,
|
|
73
|
+
message_id: input.message_id,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.InboxService = InboxService;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotifyService = void 0;
|
|
4
|
+
const redactSecrets_1 = require("../../../shared/lib/redact-secrets/redactSecrets");
|
|
5
|
+
function mergeSavedContext(input, session) {
|
|
6
|
+
const savedSections = [];
|
|
7
|
+
if (input.use_saved_context && session?.summary) {
|
|
8
|
+
savedSections.push(session.summary);
|
|
9
|
+
}
|
|
10
|
+
if (input.use_saved_context && session?.files?.length) {
|
|
11
|
+
savedSections.push(`Known files:\n${session.files.map((file) => `- ${file}`).join("\n")}`);
|
|
12
|
+
}
|
|
13
|
+
if (input.use_saved_context && session?.decisions?.length) {
|
|
14
|
+
savedSections.push(`Known decisions:\n${session.decisions.map((item) => `- ${item}`).join("\n")}`);
|
|
15
|
+
}
|
|
16
|
+
if (input.use_saved_context && session?.risks?.length) {
|
|
17
|
+
savedSections.push(`Known risks:\n${session.risks.map((item) => `- ${item}`).join("\n")}`);
|
|
18
|
+
}
|
|
19
|
+
const mergedContext = [input.context, ...savedSections]
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
.join("\n\n")
|
|
22
|
+
.trim();
|
|
23
|
+
return {
|
|
24
|
+
...(mergedContext ? { context: mergedContext } : {}),
|
|
25
|
+
...(input.task
|
|
26
|
+
? { task: input.task }
|
|
27
|
+
: session?.task
|
|
28
|
+
? { task: session.task }
|
|
29
|
+
: {}),
|
|
30
|
+
...(session?.label ? { sessionLabel: session.label } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
class NotifyService {
|
|
34
|
+
_config;
|
|
35
|
+
sessionStore;
|
|
36
|
+
bindingStore;
|
|
37
|
+
transport;
|
|
38
|
+
logger;
|
|
39
|
+
projectIdentityResolver;
|
|
40
|
+
constructor(_config, sessionStore, bindingStore, transport, logger, projectIdentityResolver) {
|
|
41
|
+
this._config = _config;
|
|
42
|
+
this.sessionStore = sessionStore;
|
|
43
|
+
this.bindingStore = bindingStore;
|
|
44
|
+
this.transport = transport;
|
|
45
|
+
this.logger = logger;
|
|
46
|
+
this.projectIdentityResolver = projectIdentityResolver;
|
|
47
|
+
}
|
|
48
|
+
async send(input) {
|
|
49
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
50
|
+
const binding = await this.bindingStore.getBinding(resolved.sessionId);
|
|
51
|
+
if (!binding) {
|
|
52
|
+
throw new Error("Session is not linked to Telegram. Call create_session_pair_code first.");
|
|
53
|
+
}
|
|
54
|
+
const session = await this.sessionStore.getSession(resolved.sessionId);
|
|
55
|
+
const merged = mergeSavedContext(input, session);
|
|
56
|
+
this.logger.info("Telegram notification requested", {
|
|
57
|
+
sessionId: resolved.sessionId,
|
|
58
|
+
sessionLabel: resolved.sessionLabel,
|
|
59
|
+
sessionIdDerived: resolved.sessionIdDerived,
|
|
60
|
+
hasContext: Boolean(merged.context),
|
|
61
|
+
hasTask: Boolean(merged.task),
|
|
62
|
+
});
|
|
63
|
+
const sendResult = await this.transport.sendNotification({
|
|
64
|
+
sessionId: resolved.sessionId,
|
|
65
|
+
...(merged.sessionLabel
|
|
66
|
+
? { sessionLabel: merged.sessionLabel }
|
|
67
|
+
: resolved.sessionLabel
|
|
68
|
+
? { sessionLabel: resolved.sessionLabel }
|
|
69
|
+
: {}),
|
|
70
|
+
recipient: {
|
|
71
|
+
telegramChatId: binding.telegramChatId,
|
|
72
|
+
telegramUserId: binding.telegramUserId,
|
|
73
|
+
},
|
|
74
|
+
message: (0, redactSecrets_1.redactSecrets)(input.message),
|
|
75
|
+
...(merged.task ? { task: (0, redactSecrets_1.redactSecrets)(merged.task) } : {}),
|
|
76
|
+
...(merged.context ? { context: (0, redactSecrets_1.redactSecrets)(merged.context) } : {}),
|
|
77
|
+
...(input.risk_level ? { riskLevel: input.risk_level } : {}),
|
|
78
|
+
});
|
|
79
|
+
this.logger.info("Telegram notification sent", {
|
|
80
|
+
sessionId: resolved.sessionId,
|
|
81
|
+
messageId: typeof sendResult.externalMessageId === "number"
|
|
82
|
+
? sendResult.externalMessageId
|
|
83
|
+
: undefined,
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
sent: true,
|
|
87
|
+
...(typeof sendResult.externalMessageId === "number"
|
|
88
|
+
? { message_id: sendResult.externalMessageId }
|
|
89
|
+
: {}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.NotifyService = NotifyService;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotifyTelegramTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
function createContent(output) {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
type: "text",
|
|
9
|
+
text: JSON.stringify(output, null, 2),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
class NotifyTelegramTool {
|
|
14
|
+
notifyService;
|
|
15
|
+
constructor(notifyService) {
|
|
16
|
+
this.notifyService = notifyService;
|
|
17
|
+
}
|
|
18
|
+
register(server) {
|
|
19
|
+
server.registerTool("notify_telegram", {
|
|
20
|
+
title: "Notify Telegram",
|
|
21
|
+
description: "Use this for one-way status or progress notifications to the human linked to the session. Pass session_id explicitly after pairing; do not rely on implicit defaults unless cwd is also correct for this agent workspace. This does not wait for a reply and does not create inbox work for the agent.",
|
|
22
|
+
inputSchema: schema_1.notifyTelegramInputSchema,
|
|
23
|
+
outputSchema: schema_1.notifyTelegramOutputSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const output = await this.notifyService.send(args);
|
|
26
|
+
return {
|
|
27
|
+
content: createContent(output),
|
|
28
|
+
structuredContent: output,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.NotifyTelegramTool = NotifyTelegramTool;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClearSessionPairingTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
function createContent(output) {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
type: "text",
|
|
9
|
+
text: JSON.stringify(output, null, 2),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
class ClearSessionPairingTool {
|
|
14
|
+
pairSessionService;
|
|
15
|
+
constructor(pairSessionService) {
|
|
16
|
+
this.pairSessionService = pairSessionService;
|
|
17
|
+
}
|
|
18
|
+
register(server) {
|
|
19
|
+
server.registerTool("clear_session_pairing", {
|
|
20
|
+
title: "Clear Session Pairing",
|
|
21
|
+
description: "Use this when the user asks to unpair, unlink, detach, or reset Telegram binding for the current session. Remove Telegram binding for a session so it can be paired again.",
|
|
22
|
+
inputSchema: schema_1.clearSessionPairingInputSchema,
|
|
23
|
+
outputSchema: schema_1.clearSessionPairingOutputSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const output = await this.pairSessionService.clearPairing(args);
|
|
26
|
+
return {
|
|
27
|
+
content: createContent(output),
|
|
28
|
+
structuredContent: output,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.ClearSessionPairingTool = ClearSessionPairingTool;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CreateSessionPairCodeTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
function createContent(output) {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
type: "text",
|
|
9
|
+
text: JSON.stringify(output, null, 2),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
class CreateSessionPairCodeTool {
|
|
14
|
+
pairSessionService;
|
|
15
|
+
constructor(pairSessionService) {
|
|
16
|
+
this.pairSessionService = pairSessionService;
|
|
17
|
+
}
|
|
18
|
+
register(server) {
|
|
19
|
+
server.registerTool("create_session_pair_code", {
|
|
20
|
+
title: "Create Session Pair Code",
|
|
21
|
+
description: "Use this when the user asks to link, pair, register, or connect the current agent/session to Telegram. Before calling it, determine the correct workspace cwd and, if tmux is available, collect current tmux attributes. Then create a short-lived Telegram pairing code for that session. After success, remember the returned session_id and pass it explicitly to later session-scoped tools.",
|
|
22
|
+
inputSchema: schema_1.createSessionPairCodeInputSchema,
|
|
23
|
+
outputSchema: schema_1.createSessionPairCodeOutputSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const output = await this.pairSessionService.createPairCode(args);
|
|
26
|
+
return {
|
|
27
|
+
content: createContent(output),
|
|
28
|
+
structuredContent: output,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.CreateSessionPairCodeTool = CreateSessionPairCodeTool;
|
package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PairSessionService = void 0;
|
|
4
|
+
const ids_1 = require("../../../shared/lib/ids/ids");
|
|
5
|
+
class PairSessionService {
|
|
6
|
+
config;
|
|
7
|
+
sessionStore;
|
|
8
|
+
bindingStore;
|
|
9
|
+
maintenanceStore;
|
|
10
|
+
logger;
|
|
11
|
+
projectIdentityResolver;
|
|
12
|
+
static MAX_PAIR_CODE_ATTEMPTS = 20;
|
|
13
|
+
constructor(config, sessionStore, bindingStore, maintenanceStore, logger, projectIdentityResolver) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.sessionStore = sessionStore;
|
|
16
|
+
this.bindingStore = bindingStore;
|
|
17
|
+
this.maintenanceStore = maintenanceStore;
|
|
18
|
+
this.logger = logger;
|
|
19
|
+
this.projectIdentityResolver = projectIdentityResolver;
|
|
20
|
+
}
|
|
21
|
+
async unregisterGatewaySession(localSessionId) {
|
|
22
|
+
if (!this.config.distributed.gatewayPublicUrl) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const clientUuid = await this.maintenanceStore.getGatewayClientUuid();
|
|
26
|
+
if (!clientUuid) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const url = new URL(this.config.distributed.gatewayPublicUrl);
|
|
30
|
+
url.pathname = url.pathname.replace(/\/+$/u, "");
|
|
31
|
+
if (!url.pathname.endsWith("/gateway")) {
|
|
32
|
+
url.pathname = `${url.pathname}/gateway`.replace(/\/{2,}/gu, "/");
|
|
33
|
+
}
|
|
34
|
+
url.pathname = `${url.pathname}/sessions/unregister`.replace(/\/{2,}/gu, "/");
|
|
35
|
+
const response = await fetch(url, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: {
|
|
38
|
+
"content-type": "application/json",
|
|
39
|
+
...(this.config.distributed.gatewayAuthToken
|
|
40
|
+
? { authorization: `Bearer ${this.config.distributed.gatewayAuthToken}` }
|
|
41
|
+
: {}),
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify({
|
|
44
|
+
client_uuid: clientUuid,
|
|
45
|
+
local_session_id: localSessionId,
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
const text = await response.text();
|
|
50
|
+
throw new Error(`Gateway session unregister failed with status ${response.status}: ${text || response.statusText}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async createPairCode(input) {
|
|
54
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
55
|
+
const now = new Date();
|
|
56
|
+
const ttlSeconds = input.expires_in_seconds ?? this.config.pairCodeTtlSeconds;
|
|
57
|
+
const expiresAt = new Date(now.getTime() + ttlSeconds * 1000).toISOString();
|
|
58
|
+
let code = null;
|
|
59
|
+
const existingSession = await this.sessionStore.getSession(resolved.sessionId);
|
|
60
|
+
await this.sessionStore.setSession({
|
|
61
|
+
sessionId: resolved.sessionId,
|
|
62
|
+
...(input.session_label
|
|
63
|
+
? { label: input.session_label }
|
|
64
|
+
: resolved.sessionLabel
|
|
65
|
+
? { label: resolved.sessionLabel }
|
|
66
|
+
: existingSession?.label
|
|
67
|
+
? { label: existingSession.label }
|
|
68
|
+
: {}),
|
|
69
|
+
...(input.cwd
|
|
70
|
+
? { cwd: resolved.cwd }
|
|
71
|
+
: existingSession?.cwd
|
|
72
|
+
? { cwd: existingSession.cwd }
|
|
73
|
+
: { cwd: resolved.cwd }),
|
|
74
|
+
...(existingSession?.linkedSessionId
|
|
75
|
+
? { linkedSessionId: existingSession.linkedSessionId }
|
|
76
|
+
: {}),
|
|
77
|
+
...(existingSession?.activeProjectUuid
|
|
78
|
+
? { activeProjectUuid: existingSession.activeProjectUuid }
|
|
79
|
+
: {}),
|
|
80
|
+
...(existingSession?.activeProjectName
|
|
81
|
+
? { activeProjectName: existingSession.activeProjectName }
|
|
82
|
+
: {}),
|
|
83
|
+
...(existingSession?.task ? { task: existingSession.task } : {}),
|
|
84
|
+
...(existingSession?.summary ? { summary: existingSession.summary } : {}),
|
|
85
|
+
...(existingSession?.files ? { files: existingSession.files } : {}),
|
|
86
|
+
...(existingSession?.decisions
|
|
87
|
+
? { decisions: existingSession.decisions }
|
|
88
|
+
: {}),
|
|
89
|
+
...(existingSession?.risks ? { risks: existingSession.risks } : {}),
|
|
90
|
+
...(input.tmux_session_name
|
|
91
|
+
? { tmuxSessionName: input.tmux_session_name }
|
|
92
|
+
: existingSession?.tmuxSessionName
|
|
93
|
+
? { tmuxSessionName: existingSession.tmuxSessionName }
|
|
94
|
+
: {}),
|
|
95
|
+
...(input.tmux_window_name
|
|
96
|
+
? { tmuxWindowName: input.tmux_window_name }
|
|
97
|
+
: existingSession?.tmuxWindowName
|
|
98
|
+
? { tmuxWindowName: existingSession.tmuxWindowName }
|
|
99
|
+
: {}),
|
|
100
|
+
...(typeof input.tmux_window_index === "number"
|
|
101
|
+
? { tmuxWindowIndex: input.tmux_window_index }
|
|
102
|
+
: typeof existingSession?.tmuxWindowIndex === "number"
|
|
103
|
+
? { tmuxWindowIndex: existingSession.tmuxWindowIndex }
|
|
104
|
+
: {}),
|
|
105
|
+
...(input.tmux_pane_id
|
|
106
|
+
? { tmuxPaneId: input.tmux_pane_id, tmuxTarget: input.tmux_pane_id }
|
|
107
|
+
: existingSession?.tmuxPaneId
|
|
108
|
+
? {
|
|
109
|
+
tmuxPaneId: existingSession.tmuxPaneId,
|
|
110
|
+
...(existingSession.tmuxTarget
|
|
111
|
+
? { tmuxTarget: existingSession.tmuxTarget }
|
|
112
|
+
: {}),
|
|
113
|
+
}
|
|
114
|
+
: existingSession?.tmuxTarget
|
|
115
|
+
? { tmuxTarget: existingSession.tmuxTarget }
|
|
116
|
+
: {}),
|
|
117
|
+
...(typeof input.tmux_pane_index === "number"
|
|
118
|
+
? { tmuxPaneIndex: input.tmux_pane_index }
|
|
119
|
+
: typeof existingSession?.tmuxPaneIndex === "number"
|
|
120
|
+
? { tmuxPaneIndex: existingSession.tmuxPaneIndex }
|
|
121
|
+
: {}),
|
|
122
|
+
...(existingSession?.lastTmuxNudgeAt
|
|
123
|
+
? { lastTmuxNudgeAt: existingSession.lastTmuxNudgeAt }
|
|
124
|
+
: {}),
|
|
125
|
+
updatedAt: now.toISOString(),
|
|
126
|
+
});
|
|
127
|
+
this.projectIdentityResolver.persistSessionMarker({
|
|
128
|
+
cwd: resolved.cwd,
|
|
129
|
+
sessionId: resolved.sessionId,
|
|
130
|
+
sessionLabel: input.session_label?.trim() || resolved.sessionLabel,
|
|
131
|
+
});
|
|
132
|
+
for (let attempt = 0; attempt < PairSessionService.MAX_PAIR_CODE_ATTEMPTS; attempt += 1) {
|
|
133
|
+
const candidate = (0, ids_1.createPairCode)();
|
|
134
|
+
const record = {
|
|
135
|
+
code: candidate,
|
|
136
|
+
sessionId: resolved.sessionId,
|
|
137
|
+
...(resolved.sessionLabel
|
|
138
|
+
? { sessionLabel: resolved.sessionLabel }
|
|
139
|
+
: {}),
|
|
140
|
+
createdAt: now.toISOString(),
|
|
141
|
+
expiresAt,
|
|
142
|
+
};
|
|
143
|
+
const reserved = await this.bindingStore.createPairCode(record, ttlSeconds);
|
|
144
|
+
if (reserved) {
|
|
145
|
+
code = candidate;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!code) {
|
|
150
|
+
throw new Error("Failed to reserve a unique 3-digit pairing code. Try again in a moment.");
|
|
151
|
+
}
|
|
152
|
+
this.logger.info("Session pair code created", {
|
|
153
|
+
sessionId: resolved.sessionId,
|
|
154
|
+
sessionLabel: resolved.sessionLabel,
|
|
155
|
+
sessionIdDerived: resolved.sessionIdDerived,
|
|
156
|
+
sessionLabelDerived: resolved.sessionLabelDerived,
|
|
157
|
+
cwd: input.cwd?.trim(),
|
|
158
|
+
tmuxSessionName: input.tmux_session_name,
|
|
159
|
+
tmuxWindowName: input.tmux_window_name,
|
|
160
|
+
tmuxWindowIndex: input.tmux_window_index,
|
|
161
|
+
tmuxPaneId: input.tmux_pane_id,
|
|
162
|
+
tmuxPaneIndex: input.tmux_pane_index,
|
|
163
|
+
expiresAt,
|
|
164
|
+
ttlSeconds,
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
session_id: resolved.sessionId,
|
|
168
|
+
code,
|
|
169
|
+
expires_at: expiresAt,
|
|
170
|
+
status: "pending",
|
|
171
|
+
status_message: "Pairing code created. Send it to the Telegram bot and then use get_session_context to confirm that pairing is active.",
|
|
172
|
+
...(this.config.telegram.botUsername
|
|
173
|
+
? {
|
|
174
|
+
telegram_link_hint: `https://t.me/${this.config.telegram.botUsername}?start=${encodeURIComponent(code)}`,
|
|
175
|
+
}
|
|
176
|
+
: {}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
async clearPairing(input) {
|
|
180
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
181
|
+
const existingSession = await this.sessionStore.getSession(resolved.sessionId);
|
|
182
|
+
if (existingSession) {
|
|
183
|
+
await this.unregisterGatewaySession(resolved.sessionId);
|
|
184
|
+
await this.sessionStore.setSession({
|
|
185
|
+
...existingSession,
|
|
186
|
+
activeProjectUuid: undefined,
|
|
187
|
+
activeProjectName: undefined,
|
|
188
|
+
updatedAt: new Date().toISOString(),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
await this.bindingStore.clearBinding(resolved.sessionId);
|
|
192
|
+
this.logger.info("Session pairing cleared", {
|
|
193
|
+
sessionId: resolved.sessionId,
|
|
194
|
+
sessionIdDerived: resolved.sessionIdDerived,
|
|
195
|
+
});
|
|
196
|
+
return {
|
|
197
|
+
cleared: true,
|
|
198
|
+
session_id: resolved.sessionId,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
exports.PairSessionService = PairSessionService;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClearSessionContextTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
function createContent(output) {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
type: "text",
|
|
9
|
+
text: JSON.stringify(output, null, 2),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
class ClearSessionContextTool {
|
|
14
|
+
sessionContextService;
|
|
15
|
+
constructor(sessionContextService) {
|
|
16
|
+
this.sessionContextService = sessionContextService;
|
|
17
|
+
}
|
|
18
|
+
register(server) {
|
|
19
|
+
server.registerTool("clear_session_context", {
|
|
20
|
+
title: "Clear Session Context",
|
|
21
|
+
description: "Use this for full session cleanup/reset. It removes saved context, pairing, and related per-session state for the session.",
|
|
22
|
+
inputSchema: schema_1.clearSessionContextInputSchema,
|
|
23
|
+
outputSchema: schema_1.clearSessionContextOutputSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const output = await this.sessionContextService.clearContext(args);
|
|
26
|
+
return {
|
|
27
|
+
content: createContent(output),
|
|
28
|
+
structuredContent: output,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.ClearSessionContextTool = ClearSessionContextTool;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetSessionContextTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
function createContent(output) {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
type: "text",
|
|
9
|
+
text: JSON.stringify(output, null, 2),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
class GetSessionContextTool {
|
|
14
|
+
sessionContextService;
|
|
15
|
+
constructor(sessionContextService) {
|
|
16
|
+
this.sessionContextService = sessionContextService;
|
|
17
|
+
}
|
|
18
|
+
register(server) {
|
|
19
|
+
server.registerTool("get_session_context", {
|
|
20
|
+
title: "Get Session Context",
|
|
21
|
+
description: "Debug/setup tool. Read the saved context and Telegram binding status for a session. Do not call this in the normal inbox-processing path after a tmux nudge unless you are diagnosing state.",
|
|
22
|
+
inputSchema: schema_1.getSessionContextInputSchema,
|
|
23
|
+
outputSchema: schema_1.getSessionContextOutputSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const output = await this.sessionContextService.getContext(args);
|
|
26
|
+
return {
|
|
27
|
+
content: createContent(output),
|
|
28
|
+
structuredContent: output,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.GetSessionContextTool = GetSessionContextTool;
|