@deadragdoll/tellymcp 0.0.13 → 0.0.15
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 +23 -39
- package/.env.example.gateway +52 -61
- package/CHANGELOG.md +57 -0
- package/README-ru.md +80 -6
- package/README.md +80 -6
- package/TOOLS.md +219 -10
- package/config/templates/env.both.template +19 -7
- package/config/templates/env.client.template +9 -19
- package/config/templates/env.gateway.template +19 -31
- package/dist/cli.js +252 -47
- package/dist/configureServer.js +966 -0
- package/dist/envMigration.js +316 -0
- package/dist/moleculer.config.js +1 -3
- package/dist/services/features/telegram-mcp/approval.service.js +1 -1
- package/dist/services/features/telegram-mcp/browser.service.js +18 -0
- package/dist/services/features/telegram-mcp/collaboration.service.js +2 -2
- package/dist/services/features/telegram-mcp/ensuredb.service.js +1 -1
- package/dist/services/features/telegram-mcp/file-content.service.js +94 -0
- package/dist/services/features/telegram-mcp/gateway-delivery.service.js +5 -1
- package/dist/services/features/telegram-mcp/gateway-socket.service.js +43 -11
- package/dist/services/features/telegram-mcp/gateway.service.js +1 -1
- package/dist/services/features/telegram-mcp/mcp-http.service.js +1 -0
- package/dist/services/features/telegram-mcp/mcp-server.service.js +20 -0
- package/dist/services/features/telegram-mcp/session-context.service.js +25 -1
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +79 -67
- package/dist/services/features/telegram-mcp/src/app/config/env.js +129 -38
- package/dist/services/features/telegram-mcp/src/app/config/environmentContract.js +66 -0
- package/dist/services/features/telegram-mcp/src/app/http.js +139 -99
- package/dist/services/features/telegram-mcp/src/app/oauthFacade.js +642 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +151 -170
- package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +96 -99
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +88 -19
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachActiveTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDetachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +412 -29
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +37 -3
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +7 -6
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +214 -37
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +186 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +5 -5
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +6 -3
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +5 -2
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +4 -4
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +33 -36
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +4 -3
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileListTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileService.js +327 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileTool.js +81 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/temporaryFileLinkStore.js +307 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/workspaceFilePolicy.js +115 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +9 -5
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getRuntimeDiagnosticsTool.js +30 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +169 -7
- package/dist/services/features/telegram-mcp/src/shared/integrations/memory/processLocalStateStore.js +260 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +1 -1
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +4 -1
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConsoleRegistry.js +2 -2
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +6 -3
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMessageFlow.js +1 -1
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectState.js +2 -2
- package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +29 -6
- package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +100 -2
- package/dist/services/features/telegram-mcp/src/shared/lib/bodyLimits.js +63 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/gatewayAuth.js +13 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/gatewayScope.js +5 -5
- package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +10 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/time/localTimestamp.js +21 -0
- package/docs/CHAT_CONNECTOR.md +134 -0
- package/docs/STANDALONE-ru.md +41 -3
- package/docs/STANDALONE.md +41 -3
- package/package.json +5 -3
- package/packages/chrome-attach-extension/dist/background.js +572 -163
- package/packages/chrome-attach-extension/dist/manifest.json +2 -1
- package/packages/chrome-attach-extension/dist/options.js +15 -2
- package/packages/chrome-attach-extension/dist/recorder-content.js +14 -1
- package/packages/chrome-attach-extension/dist/recorder-page.js +34 -18
- package/packages/firefox-attach-extension/dist/background.js +413 -33
- package/packages/firefox-attach-extension/dist/manifest.json +0 -12
- package/packages/firefox-attach-extension/dist/options.js +14 -1
- package/packages/firefox-attach-extension/dist/recorder-content.js +14 -1
- package/packages/firefox-attach-extension/dist/recorder-page.js +34 -18
- package/scripts/postinstall.js +33 -1
|
@@ -5,16 +5,20 @@ const server_1 = require("./src/app/providers/mcp/server");
|
|
|
5
5
|
const approval_service_1 = require("./approval.service");
|
|
6
6
|
const browser_service_1 = require("./browser.service");
|
|
7
7
|
const collaboration_service_1 = require("./collaboration.service");
|
|
8
|
+
const file_content_service_1 = require("./file-content.service");
|
|
8
9
|
const notify_service_1 = require("./notify.service");
|
|
9
10
|
const session_context_service_1 = require("./session-context.service");
|
|
10
11
|
const tools_sync_service_1 = require("./tools-sync.service");
|
|
11
12
|
const xchange_service_1 = require("./xchange.service");
|
|
12
13
|
const askUserTelegram_1 = require("./src/features/ask-user/model/askUserTelegram");
|
|
14
|
+
const browserAttachActiveTabTool_1 = require("./src/features/browser/model/browserAttachActiveTabTool");
|
|
15
|
+
const browserAttachTabTool_1 = require("./src/features/browser/model/browserAttachTabTool");
|
|
13
16
|
const browserClickTool_1 = require("./src/features/browser/model/browserClickTool");
|
|
14
17
|
const browserClearLogsTool_1 = require("./src/features/browser/model/browserClearLogsTool");
|
|
15
18
|
const browserCloseTool_1 = require("./src/features/browser/model/browserCloseTool");
|
|
16
19
|
const browserComputedStyleTool_1 = require("./src/features/browser/model/browserComputedStyleTool");
|
|
17
20
|
const browserConsoleTool_1 = require("./src/features/browser/model/browserConsoleTool");
|
|
21
|
+
const browserDetachTabTool_1 = require("./src/features/browser/model/browserDetachTabTool");
|
|
18
22
|
const browserDomTool_1 = require("./src/features/browser/model/browserDomTool");
|
|
19
23
|
const browserErrorsTool_1 = require("./src/features/browser/model/browserErrorsTool");
|
|
20
24
|
const browserFillTool_1 = require("./src/features/browser/model/browserFillTool");
|
|
@@ -34,9 +38,12 @@ const browserWaitForUrlTool_1 = require("./src/features/browser/model/browserWai
|
|
|
34
38
|
const sendPartnerFileTool_1 = require("./src/features/collaboration/model/sendPartnerFileTool");
|
|
35
39
|
const listGatewaySessionsTool_1 = require("./src/features/collaboration/model/listGatewaySessionsTool");
|
|
36
40
|
const sendPartnerNoteTool_1 = require("./src/features/collaboration/model/sendPartnerNoteTool");
|
|
41
|
+
const getFileTool_1 = require("./src/features/file-content/model/getFileTool");
|
|
42
|
+
const getFileListTool_1 = require("./src/features/file-content/model/getFileListTool");
|
|
37
43
|
const sendFileToTelegramTool_1 = require("./src/features/notify/model/sendFileToTelegramTool");
|
|
38
44
|
const notifyTelegramTool_1 = require("./src/features/notify/model/notifyTelegramTool");
|
|
39
45
|
const clearSessionContextTool_1 = require("./src/features/session-context/model/clearSessionContextTool");
|
|
46
|
+
const getRuntimeDiagnosticsTool_1 = require("./src/features/session-context/model/getRuntimeDiagnosticsTool");
|
|
40
47
|
const getSessionContextTool_1 = require("./src/features/session-context/model/getSessionContextTool");
|
|
41
48
|
const renameSessionTool_1 = require("./src/features/session-context/model/renameSessionTool");
|
|
42
49
|
const setSessionContextTool_1 = require("./src/features/session-context/model/setSessionContextTool");
|
|
@@ -53,6 +60,7 @@ const TelegramMcpMcpServerService = {
|
|
|
53
60
|
approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME,
|
|
54
61
|
browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME,
|
|
55
62
|
collaboration_service_1.TELEGRAM_MCP_COLLABORATION_SERVICE_NAME,
|
|
63
|
+
file_content_service_1.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME,
|
|
56
64
|
tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME,
|
|
57
65
|
xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME,
|
|
58
66
|
],
|
|
@@ -63,6 +71,7 @@ const TelegramMcpMcpServerService = {
|
|
|
63
71
|
const approvalService = this.broker.getLocalService(approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME);
|
|
64
72
|
const browserService = this.broker.getLocalService(browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME);
|
|
65
73
|
const collaborationService = this.broker.getLocalService(collaboration_service_1.TELEGRAM_MCP_COLLABORATION_SERVICE_NAME);
|
|
74
|
+
const fileContentService = this.broker.getLocalService(file_content_service_1.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME);
|
|
66
75
|
const toolsSyncService = this.broker.getLocalService(tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME);
|
|
67
76
|
const xchangeService = this.broker.getLocalService(xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME);
|
|
68
77
|
if (!sessionContextService ||
|
|
@@ -70,6 +79,7 @@ const TelegramMcpMcpServerService = {
|
|
|
70
79
|
!approvalService ||
|
|
71
80
|
!browserService ||
|
|
72
81
|
!collaborationService ||
|
|
82
|
+
!fileContentService ||
|
|
73
83
|
!toolsSyncService ||
|
|
74
84
|
!xchangeService) {
|
|
75
85
|
throw new Error("telegram_mcp MCP server dependencies are not ready");
|
|
@@ -78,12 +88,16 @@ const TelegramMcpMcpServerService = {
|
|
|
78
88
|
new setSessionContextTool_1.SetSessionContextTool(sessionContextService.getSessionContextService()),
|
|
79
89
|
new renameSessionTool_1.RenameSessionTool(sessionContextService.getSessionContextService()),
|
|
80
90
|
new getSessionContextTool_1.GetSessionContextTool(sessionContextService.getSessionContextService()),
|
|
91
|
+
new getRuntimeDiagnosticsTool_1.GetRuntimeDiagnosticsTool(sessionContextService.getSessionContextService()),
|
|
81
92
|
new clearSessionContextTool_1.ClearSessionContextTool(sessionContextService.getSessionContextService()),
|
|
82
93
|
new notifyTelegramTool_1.NotifyTelegramTool(notifyService.getNotifyService()),
|
|
83
94
|
new sendFileToTelegramTool_1.SendFileToTelegramTool(notifyService.getNotifyService()),
|
|
84
95
|
new askUserTelegram_1.AskUserTelegramTool(approvalService.getApprovalOrchestrator()),
|
|
85
96
|
new browserListAttachedInstancesTool_1.BrowserListAttachedInstancesTool(browserService.getBrowserService()),
|
|
86
97
|
new browserListTabsTool_1.BrowserListTabsTool(browserService.getBrowserService()),
|
|
98
|
+
new browserAttachActiveTabTool_1.BrowserAttachActiveTabTool(browserService.getBrowserService()),
|
|
99
|
+
new browserAttachTabTool_1.BrowserAttachTabTool(browserService.getBrowserService()),
|
|
100
|
+
new browserDetachTabTool_1.BrowserDetachTabTool(browserService.getBrowserService()),
|
|
87
101
|
new browserRecordingStartTool_1.BrowserRecordingStartTool(browserService.getBrowserService()),
|
|
88
102
|
new browserRecordingStopTool_1.BrowserRecordingStopTool(browserService.getBrowserService()),
|
|
89
103
|
new browserRecordingStatusTool_1.BrowserRecordingStatusTool(browserService.getBrowserService()),
|
|
@@ -106,11 +120,16 @@ const TelegramMcpMcpServerService = {
|
|
|
106
120
|
new sendPartnerNoteTool_1.SendPartnerNoteTool(collaborationService.getCollaborationService()),
|
|
107
121
|
new listGatewaySessionsTool_1.ListGatewaySessionsTool(collaborationService.getGatewaySessionsService()),
|
|
108
122
|
new sendPartnerFileTool_1.SendPartnerFileTool(collaborationService.getSendPartnerFileService()),
|
|
123
|
+
new getFileTool_1.GetFileTool(fileContentService.getGetFileService()),
|
|
124
|
+
new getFileListTool_1.GetFileListTool(fileContentService.getGetFileService()),
|
|
109
125
|
new listXchangeRecordsTool_1.ListXchangeRecordsTool(xchangeService.getXchangeService()),
|
|
110
126
|
new getXchangeRecordTool_1.GetXchangeRecordTool(xchangeService.getXchangeService()),
|
|
111
127
|
new markXchangeRecordReadTool_1.MarkXchangeRecordReadTool(xchangeService.getXchangeService()),
|
|
112
128
|
new refreshToolsMarkdownTool_1.RefreshToolsMarkdownTool(toolsSyncService.getRefreshToolsMarkdownService()),
|
|
113
129
|
];
|
|
130
|
+
this.logger.info("telegram_mcp MCP server instance created", {
|
|
131
|
+
toolCount: tools.length,
|
|
132
|
+
});
|
|
114
133
|
return (0, server_1.createMcpServer)(tools);
|
|
115
134
|
},
|
|
116
135
|
},
|
|
@@ -121,6 +140,7 @@ const TelegramMcpMcpServerService = {
|
|
|
121
140
|
approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME,
|
|
122
141
|
browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME,
|
|
123
142
|
collaboration_service_1.TELEGRAM_MCP_COLLABORATION_SERVICE_NAME,
|
|
143
|
+
file_content_service_1.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME,
|
|
124
144
|
tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME,
|
|
125
145
|
xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME,
|
|
126
146
|
]);
|
|
@@ -4,6 +4,7 @@ exports.TELEGRAM_MCP_SESSION_CONTEXT_SERVICE_NAME = void 0;
|
|
|
4
4
|
const runtime_service_1 = require("./runtime.service");
|
|
5
5
|
const remoteConsoleActionClient_1 = require("./src/features/distributed-gateway/model/remoteConsoleActionClient");
|
|
6
6
|
const sessionContextService_1 = require("./src/features/session-context/model/sessionContextService");
|
|
7
|
+
const versionHandshake_1 = require("./src/shared/lib/version/versionHandshake");
|
|
7
8
|
exports.TELEGRAM_MCP_SESSION_CONTEXT_SERVICE_NAME = "telegramMcp.sessionContext";
|
|
8
9
|
const TelegramMcpSessionContextService = {
|
|
9
10
|
name: exports.TELEGRAM_MCP_SESSION_CONTEXT_SERVICE_NAME,
|
|
@@ -15,6 +16,12 @@ const TelegramMcpSessionContextService = {
|
|
|
15
16
|
return this.getSessionContextService().getContext(ctx.params);
|
|
16
17
|
},
|
|
17
18
|
},
|
|
19
|
+
getRuntimeDiagnosticsRemote: {
|
|
20
|
+
params: { $$strict: false },
|
|
21
|
+
async handler(ctx) {
|
|
22
|
+
return this.getSessionContextService().getRuntimeDiagnostics(ctx.params);
|
|
23
|
+
},
|
|
24
|
+
},
|
|
18
25
|
setContextRemote: {
|
|
19
26
|
params: { $$strict: false },
|
|
20
27
|
async handler(ctx) {
|
|
@@ -53,7 +60,24 @@ const TelegramMcpSessionContextService = {
|
|
|
53
60
|
}
|
|
54
61
|
const runtime = await runtimeService.waitUntilReady();
|
|
55
62
|
this.logger.info("Starting telegram_mcp session-context service");
|
|
56
|
-
this.sessionContextService = new sessionContextService_1.SessionContextService(runtime.sessionStore, runtime.stateStore, runtime.logger, runtime.projectIdentityResolver,
|
|
63
|
+
this.sessionContextService = new sessionContextService_1.SessionContextService(runtime.sessionStore, runtime.stateStore, runtime.logger, runtime.projectIdentityResolver, runtime.config.distributed.mode === "client"
|
|
64
|
+
? undefined
|
|
65
|
+
: new remoteConsoleActionClient_1.RemoteConsoleActionClient((actionName, params) => this.broker.call(actionName, params, {
|
|
66
|
+
meta: { internal_call: true },
|
|
67
|
+
})), {
|
|
68
|
+
mode: runtime.config.distributed.mode,
|
|
69
|
+
packageVersion: (0, versionHandshake_1.getTellyMcpPackageVersion)(__dirname),
|
|
70
|
+
protocolVersion: versionHandshake_1.TELLYMCP_PROTOCOL_VERSION,
|
|
71
|
+
...(process.env.NODE_ID?.trim()
|
|
72
|
+
? { nodeId: process.env.NODE_ID.trim() }
|
|
73
|
+
: {}),
|
|
74
|
+
gatewayWsUrlConfigured: Boolean(runtime.config.distributed.gatewayWsUrl),
|
|
75
|
+
gatewayAuthConfigured: Boolean(runtime.config.distributed.gatewayAuthToken ||
|
|
76
|
+
runtime.config.distributed.gatewayScopeToken),
|
|
77
|
+
...(runtime.redis
|
|
78
|
+
? { pingRedis: async () => await runtime.redis.ping() }
|
|
79
|
+
: {}),
|
|
80
|
+
});
|
|
57
81
|
this.logger.info("telegram_mcp session-context service is ready");
|
|
58
82
|
},
|
|
59
83
|
};
|
|
@@ -8,11 +8,13 @@ const logger_1 = require("../../shared/lib/logger/logger");
|
|
|
8
8
|
const projectIdentity_1 = require("../../shared/lib/project-identity/projectIdentity");
|
|
9
9
|
const stateStore_1 = require("../../shared/integrations/redis/stateStore");
|
|
10
10
|
const processLocalSessionStore_1 = require("../../shared/integrations/memory/processLocalSessionStore");
|
|
11
|
+
const processLocalStateStore_1 = require("../../shared/integrations/memory/processLocalStateStore");
|
|
11
12
|
const transport_1 = require("../../shared/integrations/telegram/transport");
|
|
12
13
|
const minioExchangeStore_1 = require("../../shared/integrations/object-storage/minioExchangeStore");
|
|
13
14
|
const gatewayHttpService_1 = require("../../features/distributed-gateway/model/gatewayHttpService");
|
|
14
15
|
const gatewayClientAccess_1 = require("../../features/distributed-client/model/gatewayClientAccess");
|
|
15
16
|
const firefoxAttachServer_1 = require("../../features/browser-attach/model/firefoxAttachServer");
|
|
17
|
+
const temporaryFileLinkStore_1 = require("../../features/file-content/model/temporaryFileLinkStore");
|
|
16
18
|
const client_2 = require("../../shared/integrations/terminal/client");
|
|
17
19
|
const ptyRegistry_1 = require("../../shared/integrations/terminal/ptyRegistry");
|
|
18
20
|
async function createAppRuntime(input) {
|
|
@@ -21,11 +23,14 @@ async function createAppRuntime(input) {
|
|
|
21
23
|
const projectIdentityResolver = new projectIdentity_1.ProjectIdentityResolver(config, logger);
|
|
22
24
|
logger.info("Configuration loaded", {
|
|
23
25
|
mode: config.mode,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
state: config.distributed.mode === "client"
|
|
27
|
+
? { backend: "process-local" }
|
|
28
|
+
: {
|
|
29
|
+
backend: "redis",
|
|
30
|
+
host: config.redis.host,
|
|
31
|
+
port: config.redis.port,
|
|
32
|
+
db: config.redis.db,
|
|
33
|
+
},
|
|
29
34
|
logging: {
|
|
30
35
|
level: config.logging.level,
|
|
31
36
|
},
|
|
@@ -34,19 +39,16 @@ async function createAppRuntime(input) {
|
|
|
34
39
|
httpPort: config.mcp.httpPort,
|
|
35
40
|
httpPath: config.mcp.httpPath,
|
|
36
41
|
bearerAuthEnabled: Boolean(config.mcp.bearerToken),
|
|
42
|
+
oauthConnectorEnabled: Boolean(config.oauth),
|
|
37
43
|
enableDebugRoutes: config.mcp.enableDebugRoutes,
|
|
38
44
|
enablePruneRoute: config.mcp.enablePruneRoute,
|
|
39
45
|
},
|
|
40
46
|
distributed: {
|
|
41
47
|
mode: config.distributed.mode,
|
|
42
48
|
gatewayPublicUrlConfigured: Boolean(config.distributed.gatewayPublicUrl),
|
|
43
|
-
gatewayBindHost: config.distributed.gatewayBindHost,
|
|
44
|
-
gatewayBindPort: config.distributed.gatewayBindPort,
|
|
45
49
|
gatewayWsUrlConfigured: Boolean(config.distributed.gatewayWsUrl),
|
|
46
50
|
gatewayWsPath: config.distributed.gatewayWsPath,
|
|
47
51
|
gatewayAuthEnabled: Boolean(config.distributed.gatewayAuthToken),
|
|
48
|
-
gatewayDatabaseConfigured: Boolean(config.distributed.gatewayDatabaseUrl),
|
|
49
|
-
gatewayS3Configured: Boolean(config.distributed.gatewayS3Bucket),
|
|
50
52
|
gatewayRmqConfigured: Boolean(config.distributed.rmq?.host),
|
|
51
53
|
},
|
|
52
54
|
webapp: {
|
|
@@ -56,7 +58,6 @@ async function createAppRuntime(input) {
|
|
|
56
58
|
initDataTtlSeconds: config.webapp.initDataTtlSeconds,
|
|
57
59
|
sessionTtlSeconds: config.webapp.sessionTtlSeconds,
|
|
58
60
|
launchMode: config.webapp.launchMode,
|
|
59
|
-
pollIntervalMs: config.webapp.pollIntervalMs,
|
|
60
61
|
actionCooldownMs: config.webapp.actionCooldownMs,
|
|
61
62
|
},
|
|
62
63
|
terminal: {
|
|
@@ -81,81 +82,85 @@ async function createAppRuntime(input) {
|
|
|
81
82
|
},
|
|
82
83
|
project: projectIdentityResolver.getIdentity(),
|
|
83
84
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
let redis = null;
|
|
86
|
+
let stateStore;
|
|
87
|
+
let sessionStore;
|
|
88
|
+
if (config.distributed.mode === "client") {
|
|
89
|
+
const resolvedSession = projectIdentityResolver.resolveSessionDefaults({ cwd: process.cwd() });
|
|
90
|
+
const marker = (0, projectIdentity_1.readSessionMarkerState)(resolvedSession.cwd, logger);
|
|
91
|
+
stateStore = new processLocalStateStore_1.ProcessLocalStateStore({
|
|
92
|
+
...(marker?.gatewayClientUuid
|
|
93
|
+
? { gatewayClientUuid: marker.gatewayClientUuid }
|
|
94
|
+
: {}),
|
|
95
|
+
onGatewayClientUuidChange: (gatewayClientUuid) => {
|
|
96
|
+
(0, projectIdentity_1.writeSessionMarkerState)({
|
|
97
|
+
cwd: resolvedSession.cwd,
|
|
98
|
+
localSessionId: resolvedSession.sessionId,
|
|
99
|
+
sessionLabel: resolvedSession.sessionLabel,
|
|
100
|
+
...(marker?.envFile ? { envFile: marker.envFile } : {}),
|
|
101
|
+
...(marker?.lastSeenToolsHash
|
|
102
|
+
? { lastSeenToolsHash: marker.lastSeenToolsHash }
|
|
103
|
+
: {}),
|
|
104
|
+
...(marker?.lastNotifiedToolsHash
|
|
105
|
+
? { lastNotifiedToolsHash: marker.lastNotifiedToolsHash }
|
|
106
|
+
: {}),
|
|
107
|
+
gatewayClientUuid,
|
|
108
|
+
logger,
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
sessionStore = new processLocalSessionStore_1.ProcessLocalSessionStore();
|
|
113
|
+
logger.info("Client process-local state store initialized", {
|
|
114
|
+
gatewayClientUuidRestored: Boolean(marker?.gatewayClientUuid),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
redis = await (0, client_1.createRedisClient)(config);
|
|
119
|
+
logger.info("Redis connected", {
|
|
120
|
+
host: config.redis.host,
|
|
121
|
+
port: config.redis.port,
|
|
122
|
+
db: config.redis.db,
|
|
123
|
+
});
|
|
124
|
+
const redisStateStore = new stateStore_1.RedisStateStore(redis);
|
|
125
|
+
stateStore = redisStateStore;
|
|
126
|
+
sessionStore = redisStateStore;
|
|
127
|
+
}
|
|
92
128
|
const webAppLaunchRegistry = new auth_1.WebAppLaunchRegistry();
|
|
93
|
-
const objectStore = new minioExchangeStore_1.MinioExchangeStore(
|
|
129
|
+
const objectStore = new minioExchangeStore_1.MinioExchangeStore(config.terminal, config.exchange.dir, logger);
|
|
94
130
|
if (config.distributed.mode === "client") {
|
|
95
131
|
const resolvedSession = projectIdentityResolver.resolveSessionDefaults({
|
|
96
132
|
cwd: process.cwd(),
|
|
97
133
|
});
|
|
98
|
-
const existingSession = await stateStore.getSession(resolvedSession.sessionId);
|
|
99
134
|
const persistedToolsState = (0, projectIdentity_1.readSessionMarkerState)(resolvedSession.cwd, logger);
|
|
100
135
|
const terminalTarget = (0, client_2.ensureTerminalTargetForSession)(config.terminal, {
|
|
101
136
|
sessionId: resolvedSession.sessionId,
|
|
102
137
|
cwd: resolvedSession.cwd,
|
|
103
|
-
...(typeof existingSession?.terminalTarget === "string"
|
|
104
|
-
? { target: existingSession.terminalTarget }
|
|
105
|
-
: {}),
|
|
106
138
|
});
|
|
107
139
|
if (!terminalTarget) {
|
|
108
140
|
throw new Error("PTY terminal target could not be created during runtime bootstrap");
|
|
109
141
|
}
|
|
110
142
|
const initialSession = {
|
|
111
143
|
sessionId: resolvedSession.sessionId,
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
: { label: resolvedSession.sessionLabel }),
|
|
115
|
-
...(typeof existingSession?.cwd === "string"
|
|
116
|
-
? { cwd: existingSession.cwd }
|
|
117
|
-
: { cwd: resolvedSession.cwd }),
|
|
118
|
-
...(typeof existingSession?.activeProjectUuid === "string"
|
|
119
|
-
? { activeProjectUuid: existingSession.activeProjectUuid }
|
|
120
|
-
: {}),
|
|
121
|
-
...(typeof existingSession?.activeProjectName === "string"
|
|
122
|
-
? { activeProjectName: existingSession.activeProjectName }
|
|
123
|
-
: {}),
|
|
124
|
-
...(typeof existingSession?.task === "string"
|
|
125
|
-
? { task: existingSession.task }
|
|
126
|
-
: {}),
|
|
127
|
-
...(typeof existingSession?.summary === "string"
|
|
128
|
-
? { summary: existingSession.summary }
|
|
129
|
-
: {}),
|
|
130
|
-
...(Array.isArray(existingSession?.files)
|
|
131
|
-
? { files: existingSession.files }
|
|
132
|
-
: {}),
|
|
133
|
-
...(Array.isArray(existingSession?.decisions)
|
|
134
|
-
? { decisions: existingSession.decisions }
|
|
135
|
-
: {}),
|
|
136
|
-
...(Array.isArray(existingSession?.risks)
|
|
137
|
-
? { risks: existingSession.risks }
|
|
138
|
-
: {}),
|
|
144
|
+
label: resolvedSession.sessionLabel,
|
|
145
|
+
cwd: resolvedSession.cwd,
|
|
139
146
|
terminalTarget: terminalTarget,
|
|
140
|
-
...(typeof
|
|
141
|
-
? {
|
|
147
|
+
...(typeof persistedToolsState?.lastSeenToolsHash === "string"
|
|
148
|
+
? { lastSeenToolsHash: persistedToolsState.lastSeenToolsHash }
|
|
149
|
+
: {}),
|
|
150
|
+
...(typeof persistedToolsState?.lastNotifiedToolsHash === "string"
|
|
151
|
+
? { lastNotifiedToolsHash: persistedToolsState.lastNotifiedToolsHash }
|
|
142
152
|
: {}),
|
|
143
|
-
...(typeof existingSession?.lastSeenToolsHash === "string"
|
|
144
|
-
? { lastSeenToolsHash: existingSession.lastSeenToolsHash }
|
|
145
|
-
: typeof persistedToolsState?.lastSeenToolsHash === "string"
|
|
146
|
-
? { lastSeenToolsHash: persistedToolsState.lastSeenToolsHash }
|
|
147
|
-
: {}),
|
|
148
|
-
...(typeof existingSession?.lastNotifiedToolsHash === "string"
|
|
149
|
-
? { lastNotifiedToolsHash: existingSession.lastNotifiedToolsHash }
|
|
150
|
-
: typeof persistedToolsState?.lastNotifiedToolsHash === "string"
|
|
151
|
-
? { lastNotifiedToolsHash: persistedToolsState.lastNotifiedToolsHash }
|
|
152
|
-
: {}),
|
|
153
153
|
updatedAt: new Date().toISOString(),
|
|
154
154
|
};
|
|
155
155
|
sessionStore = new processLocalSessionStore_1.ProcessLocalSessionStore({
|
|
156
156
|
initialSessions: [initialSession],
|
|
157
157
|
onClearSession: async (sessionId) => {
|
|
158
|
-
await stateStore.
|
|
158
|
+
await stateStore.clearBinding(sessionId);
|
|
159
|
+
await stateStore.clearBrowserAttachment(sessionId);
|
|
160
|
+
await stateStore.clearBrowserRecording(sessionId);
|
|
161
|
+
for (const meta of await stateStore.listXchangeFileMetas(sessionId)) {
|
|
162
|
+
await stateStore.deleteXchangeFileMeta(sessionId, meta.filePath);
|
|
163
|
+
}
|
|
159
164
|
},
|
|
160
165
|
});
|
|
161
166
|
logger.info("Client PTY process-local session store initialized", {
|
|
@@ -174,8 +179,8 @@ async function createAppRuntime(input) {
|
|
|
174
179
|
: {}),
|
|
175
180
|
...(config.project.name ? { projectName: config.project.name } : {}),
|
|
176
181
|
...(config.telegram.botUsername ? { botUsername: config.telegram.botUsername } : {}),
|
|
177
|
-
...(config.distributed.
|
|
178
|
-
? {
|
|
182
|
+
...(config.distributed.gatewayScopeToken
|
|
183
|
+
? { gatewayScopeToken: config.distributed.gatewayScopeToken }
|
|
179
184
|
: {}),
|
|
180
185
|
...(config.distributed.gatewayUserUuid
|
|
181
186
|
? { gatewayUserUuid: config.distributed.gatewayUserUuid }
|
|
@@ -210,7 +215,12 @@ async function createAppRuntime(input) {
|
|
|
210
215
|
await telegramTransport.sendStartupNotifications();
|
|
211
216
|
logger.info("Startup Telegram notifications completed");
|
|
212
217
|
const gatewayHttpService = new gatewayHttpService_1.GatewayHttpService(config, input.callBroker);
|
|
213
|
-
const
|
|
218
|
+
const temporaryFileLinkStore = config.distributed.mode !== "client" &&
|
|
219
|
+
config.distributed.gatewayPublicUrl?.trim()
|
|
220
|
+
? new temporaryFileLinkStore_1.TemporaryFileLinkStore(config.distributed.gatewayPublicUrl, logger)
|
|
221
|
+
: null;
|
|
222
|
+
await temporaryFileLinkStore?.start();
|
|
223
|
+
const firefoxAttachServer = new firefoxAttachServer_1.FirefoxAttachServer(config, logger, sessionStore, stateStore);
|
|
214
224
|
await firefoxAttachServer.start();
|
|
215
225
|
return {
|
|
216
226
|
callBroker: input.callBroker,
|
|
@@ -230,12 +240,14 @@ async function createAppRuntime(input) {
|
|
|
230
240
|
webAppLaunchRegistry,
|
|
231
241
|
gatewayHttpService,
|
|
232
242
|
firefoxAttachServer,
|
|
243
|
+
temporaryFileLinkStore,
|
|
233
244
|
shutdown: async () => {
|
|
234
245
|
logger.info("Shutdown started");
|
|
246
|
+
await temporaryFileLinkStore?.stop();
|
|
235
247
|
await firefoxAttachServer.stop();
|
|
236
248
|
await telegramTransport.stop();
|
|
237
249
|
(0, ptyRegistry_1.stopAllPtyTargets)();
|
|
238
|
-
redis
|
|
250
|
+
redis?.disconnect();
|
|
239
251
|
logger.info("Shutdown completed");
|
|
240
252
|
},
|
|
241
253
|
};
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.loadConfig = loadConfig;
|
|
37
37
|
const node_fs_1 = require("node:fs");
|
|
38
38
|
const z = __importStar(require("zod/v4"));
|
|
39
|
+
const environmentContract_1 = require("./environmentContract");
|
|
39
40
|
const emptyStringToUndefined = (value) => {
|
|
40
41
|
if (typeof value !== "string") {
|
|
41
42
|
return value;
|
|
@@ -79,13 +80,12 @@ const envSchema = z.object({
|
|
|
79
80
|
.optional()
|
|
80
81
|
.transform((value) => value === "true"),
|
|
81
82
|
DEBUG_LANGUAGE: z.preprocess(emptyStringToUndefined, z.enum(["en", "ru"]).optional()),
|
|
82
|
-
REDIS_HOST: z.string().min(1),
|
|
83
|
-
REDIS_PORT: z.coerce.number().int().positive(),
|
|
84
|
-
REDIS_DB: z.coerce.number().int().nonnegative(),
|
|
83
|
+
REDIS_HOST: z.string().min(1).default("127.0.0.1"),
|
|
84
|
+
REDIS_PORT: z.coerce.number().int().positive().default(6379),
|
|
85
|
+
REDIS_DB: z.coerce.number().int().nonnegative().default(1),
|
|
85
86
|
REDIS_USERNAME: optionalNonEmptyString,
|
|
86
87
|
REDIS_PASSWORD: optionalNonEmptyString,
|
|
87
|
-
|
|
88
|
-
PAIR_CODE_TTL_SECONDS: z.coerce.number().int().positive().default(600),
|
|
88
|
+
TELEGRAM_REQUEST_MODE: z.enum(["queue", "reject"]).default("queue"),
|
|
89
89
|
PROJECT_NAME: optionalNonEmptyString,
|
|
90
90
|
TELLYMCP_SESSION_ID: optionalNonEmptyString,
|
|
91
91
|
TELLYMCP_SESSION_LABEL: optionalNonEmptyString,
|
|
@@ -93,6 +93,22 @@ const envSchema = z.object({
|
|
|
93
93
|
MCP_HTTP_PORT: z.coerce.number().int().positive().default(8787),
|
|
94
94
|
MCP_HTTP_PATH: z.string().min(1).default("/mcp"),
|
|
95
95
|
MCP_HTTP_BEARER_TOKEN: optionalNonEmptyString,
|
|
96
|
+
TELLYMCP_PUBLIC_URL: optionalUrlString,
|
|
97
|
+
TELLYMCP_OAUTH_ISSUER: optionalUrlString,
|
|
98
|
+
TELLYMCP_OAUTH_AUDIENCE: optionalUrlString,
|
|
99
|
+
TELLYMCP_MAGIC_TOKEN: optionalNonEmptyString,
|
|
100
|
+
TELLYMCP_MAGIC_TOKEN_HASH: optionalNonEmptyString,
|
|
101
|
+
TELLYMCP_OAUTH_CLIENT_ID: optionalNonEmptyString,
|
|
102
|
+
TELLYMCP_OAUTH_CLIENT_SECRET: optionalNonEmptyString,
|
|
103
|
+
TELLYMCP_ALLOWED_REDIRECT_URIS: optionalNonEmptyString,
|
|
104
|
+
TELLYMCP_OAUTH_PRIVATE_KEY_PEM: optionalNonEmptyString,
|
|
105
|
+
TELLYMCP_AUTH_CODE_TTL_SECONDS: z.coerce
|
|
106
|
+
.number()
|
|
107
|
+
.int()
|
|
108
|
+
.positive()
|
|
109
|
+
.default(300),
|
|
110
|
+
TELLYMCP_OAUTH_SCOPES: z.string().min(1).default("tellymcp:read tellymcp:write"),
|
|
111
|
+
TELLYMCP_OAUTH_KEY_ID: z.string().min(1).default("tellymcp-oauth"),
|
|
96
112
|
MCP_HTTP_ENABLE_DEBUG_ROUTES: z
|
|
97
113
|
.string()
|
|
98
114
|
.optional()
|
|
@@ -101,24 +117,16 @@ const envSchema = z.object({
|
|
|
101
117
|
.string()
|
|
102
118
|
.optional()
|
|
103
119
|
.transform((value) => value === "true"),
|
|
104
|
-
MCP_VFS_SCOPE: z.string().min(1).default("mcp"),
|
|
105
120
|
DISTRIBUTED_MODE: z.enum(["client", "gateway", "both"]).default("client"),
|
|
106
121
|
GATEWAY_PUBLIC_URL: optionalUrlString,
|
|
107
|
-
GATEWAY_BIND_HOST: z.string().min(1).default("127.0.0.1"),
|
|
108
|
-
GATEWAY_BIND_PORT: z.coerce.number().int().positive().default(8790),
|
|
109
122
|
GATEWAY_WS_URL: optionalUrlString,
|
|
110
123
|
GATEWAY_WS_PATH: z
|
|
111
124
|
.string()
|
|
112
125
|
.min(1)
|
|
113
126
|
.default(`${(process.env.ROOT_PREFIX || "/api").replace(/\/+$/u, "")}/gateway/ws`),
|
|
114
|
-
|
|
127
|
+
GATEWAY_SCOPE_TOKEN: optionalNonEmptyString,
|
|
115
128
|
GATEWAY_USER_UUID: optionalNonEmptyString,
|
|
116
129
|
GATEWAY_AUTH_TOKEN: optionalNonEmptyString,
|
|
117
|
-
GATEWAY_DATABASE_URL: optionalNonEmptyString,
|
|
118
|
-
GATEWAY_S3_ENDPOINT: optionalNonEmptyString,
|
|
119
|
-
GATEWAY_S3_BUCKET: optionalNonEmptyString,
|
|
120
|
-
GATEWAY_S3_ACCESS_KEY: optionalNonEmptyString,
|
|
121
|
-
GATEWAY_S3_SECRET_KEY: optionalNonEmptyString,
|
|
122
130
|
RMQ_HOST: optionalNonEmptyString,
|
|
123
131
|
RMQ_PORT: z.coerce.number().int().positive().optional(),
|
|
124
132
|
RMQ_USER: optionalNonEmptyString,
|
|
@@ -145,7 +153,6 @@ const envSchema = z.object({
|
|
|
145
153
|
.enum(["default", "expand", "fullscreen"])
|
|
146
154
|
.default("fullscreen"),
|
|
147
155
|
WEBAPP_VISIBLE_SCREENS: z.coerce.number().int().positive().default(2),
|
|
148
|
-
WEBAPP_POLL_INTERVAL_MS: z.coerce.number().int().positive().default(2000),
|
|
149
156
|
WEBAPP_ACTION_COOLDOWN_MS: z.coerce.number().int().nonnegative().default(150),
|
|
150
157
|
MCP_XCHANGE_DIR: z.string().min(1).default(".mcp-xchange"),
|
|
151
158
|
TERMINAL_SHELL: z.string().min(1).default(process.env.SHELL || "bash"),
|
|
@@ -241,11 +248,22 @@ function loadConfig() {
|
|
|
241
248
|
else if ((0, node_fs_1.existsSync)(".env")) {
|
|
242
249
|
process.loadEnvFile(".env");
|
|
243
250
|
}
|
|
251
|
+
(0, environmentContract_1.assertNoLegacyEnvironmentVariables)(process.env);
|
|
244
252
|
const parsed = envSchema.parse(process.env);
|
|
245
253
|
if (parsed.DISTRIBUTED_MODE !== "client" &&
|
|
246
254
|
!parsed.TELEGRAM_BOT_TOKEN?.trim()) {
|
|
247
255
|
throw new Error("TELEGRAM_BOT_TOKEN is required for gateway and both distributed modes.");
|
|
248
256
|
}
|
|
257
|
+
const gatewayServerEnabled = parsed.DISTRIBUTED_MODE === "gateway" ||
|
|
258
|
+
parsed.DISTRIBUTED_MODE === "both";
|
|
259
|
+
const gatewayClientConfigured = parsed.DISTRIBUTED_MODE === "client" &&
|
|
260
|
+
Boolean(parsed.GATEWAY_PUBLIC_URL || parsed.GATEWAY_WS_URL);
|
|
261
|
+
if ((gatewayServerEnabled || gatewayClientConfigured) &&
|
|
262
|
+
!parsed.GATEWAY_AUTH_TOKEN?.trim()) {
|
|
263
|
+
throw new Error(gatewayServerEnabled
|
|
264
|
+
? "GATEWAY_AUTH_TOKEN is required for gateway and both distributed modes."
|
|
265
|
+
: "GATEWAY_AUTH_TOKEN is required when a client connects to a gateway.");
|
|
266
|
+
}
|
|
249
267
|
if (parsed.ADMIN_TOKEN?.trim() && !parsed.TELEGRAM_BOT_TOKEN?.trim()) {
|
|
250
268
|
throw new Error("ADMIN_TOKEN requires TELEGRAM_BOT_TOKEN because admin mode runs through the gateway bot.");
|
|
251
269
|
}
|
|
@@ -257,6 +275,69 @@ function loadConfig() {
|
|
|
257
275
|
throw new Error("TELEGRAM_WEBHOOK_ENABLED=true requires TELEGRAM_WEBHOOK_SECRET.");
|
|
258
276
|
}
|
|
259
277
|
}
|
|
278
|
+
const oauthConfigured = Boolean(parsed.TELLYMCP_PUBLIC_URL ||
|
|
279
|
+
parsed.TELLYMCP_OAUTH_ISSUER ||
|
|
280
|
+
parsed.TELLYMCP_OAUTH_AUDIENCE ||
|
|
281
|
+
parsed.TELLYMCP_MAGIC_TOKEN ||
|
|
282
|
+
parsed.TELLYMCP_MAGIC_TOKEN_HASH ||
|
|
283
|
+
parsed.TELLYMCP_OAUTH_CLIENT_ID ||
|
|
284
|
+
parsed.TELLYMCP_OAUTH_CLIENT_SECRET ||
|
|
285
|
+
parsed.TELLYMCP_ALLOWED_REDIRECT_URIS ||
|
|
286
|
+
parsed.TELLYMCP_OAUTH_PRIVATE_KEY_PEM);
|
|
287
|
+
if (oauthConfigured && !parsed.TELLYMCP_PUBLIC_URL) {
|
|
288
|
+
throw new Error("TELLYMCP_PUBLIC_URL is required when OAuth connector settings are configured.");
|
|
289
|
+
}
|
|
290
|
+
if (oauthConfigured &&
|
|
291
|
+
!parsed.TELLYMCP_MAGIC_TOKEN &&
|
|
292
|
+
!parsed.TELLYMCP_MAGIC_TOKEN_HASH) {
|
|
293
|
+
throw new Error("TELLYMCP_MAGIC_TOKEN or TELLYMCP_MAGIC_TOKEN_HASH is required when OAuth is configured.");
|
|
294
|
+
}
|
|
295
|
+
if (parsed.TELLYMCP_MAGIC_TOKEN && parsed.TELLYMCP_MAGIC_TOKEN_HASH) {
|
|
296
|
+
throw new Error("Configure only one of TELLYMCP_MAGIC_TOKEN and TELLYMCP_MAGIC_TOKEN_HASH.");
|
|
297
|
+
}
|
|
298
|
+
if (parsed.TELLYMCP_MAGIC_TOKEN_HASH &&
|
|
299
|
+
!/^sha256:[a-f0-9]{64}$/iu.test(parsed.TELLYMCP_MAGIC_TOKEN_HASH)) {
|
|
300
|
+
throw new Error("TELLYMCP_MAGIC_TOKEN_HASH must use the format sha256:<64 hex characters>.");
|
|
301
|
+
}
|
|
302
|
+
if (parsed.TELLYMCP_OAUTH_CLIENT_SECRET && !parsed.TELLYMCP_OAUTH_CLIENT_ID) {
|
|
303
|
+
throw new Error("TELLYMCP_OAUTH_CLIENT_SECRET requires TELLYMCP_OAUTH_CLIENT_ID.");
|
|
304
|
+
}
|
|
305
|
+
for (const [name, value] of [
|
|
306
|
+
["TELLYMCP_PUBLIC_URL", parsed.TELLYMCP_PUBLIC_URL],
|
|
307
|
+
["TELLYMCP_OAUTH_ISSUER", parsed.TELLYMCP_OAUTH_ISSUER],
|
|
308
|
+
["TELLYMCP_OAUTH_AUDIENCE", parsed.TELLYMCP_OAUTH_AUDIENCE],
|
|
309
|
+
]) {
|
|
310
|
+
if (!value) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
const url = new URL(value);
|
|
314
|
+
if (url.search || url.hash) {
|
|
315
|
+
throw new Error(`${name} must not contain a query string or fragment.`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const oauthScopes = parsed.TELLYMCP_OAUTH_SCOPES
|
|
319
|
+
.split(/[\s,]+/u)
|
|
320
|
+
.map((scope) => scope.trim())
|
|
321
|
+
.filter(Boolean);
|
|
322
|
+
if (oauthConfigured && oauthScopes.length === 0) {
|
|
323
|
+
throw new Error("TELLYMCP_OAUTH_SCOPES must contain at least one scope.");
|
|
324
|
+
}
|
|
325
|
+
const allowedRedirectUris = parsed.TELLYMCP_ALLOWED_REDIRECT_URIS
|
|
326
|
+
? parsed.TELLYMCP_ALLOWED_REDIRECT_URIS.split(",")
|
|
327
|
+
.map((redirectUri) => redirectUri.trim())
|
|
328
|
+
.filter(Boolean)
|
|
329
|
+
: [];
|
|
330
|
+
for (const redirectUri of allowedRedirectUris) {
|
|
331
|
+
try {
|
|
332
|
+
const parsedRedirectUri = new URL(redirectUri);
|
|
333
|
+
if (parsedRedirectUri.hash) {
|
|
334
|
+
throw new Error("fragment");
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
throw new Error(`TELLYMCP_ALLOWED_REDIRECT_URIS contains an invalid URL: ${redirectUri}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
260
341
|
const telegramProxy = parsed.PROXY_USE === "http"
|
|
261
342
|
? parsed.HTTP_PROXY
|
|
262
343
|
? {
|
|
@@ -315,32 +396,58 @@ function loadConfig() {
|
|
|
315
396
|
...(parsed.REDIS_USERNAME ? { username: parsed.REDIS_USERNAME } : {}),
|
|
316
397
|
...(parsed.REDIS_PASSWORD ? { password: parsed.REDIS_PASSWORD } : {}),
|
|
317
398
|
},
|
|
318
|
-
mode: parsed.
|
|
319
|
-
pairCodeTtlSeconds: parsed.PAIR_CODE_TTL_SECONDS,
|
|
399
|
+
mode: parsed.TELEGRAM_REQUEST_MODE,
|
|
320
400
|
mcp: {
|
|
321
401
|
httpHost: parsed.MCP_HTTP_HOST,
|
|
322
402
|
httpPort: parsed.MCP_HTTP_PORT,
|
|
323
403
|
httpPath: parsed.MCP_HTTP_PATH,
|
|
324
|
-
vfsScope: parsed.MCP_VFS_SCOPE,
|
|
325
404
|
...(parsed.MCP_HTTP_BEARER_TOKEN
|
|
326
405
|
? { bearerToken: parsed.MCP_HTTP_BEARER_TOKEN }
|
|
327
406
|
: {}),
|
|
328
407
|
enableDebugRoutes: parsed.MCP_HTTP_ENABLE_DEBUG_ROUTES,
|
|
329
408
|
enablePruneRoute: parsed.MCP_HTTP_ENABLE_PRUNE_ROUTE,
|
|
330
409
|
},
|
|
410
|
+
...(oauthConfigured && parsed.TELLYMCP_PUBLIC_URL
|
|
411
|
+
? {
|
|
412
|
+
oauth: {
|
|
413
|
+
publicUrl: parsed.TELLYMCP_PUBLIC_URL.replace(/\/+$/u, ""),
|
|
414
|
+
issuer: (parsed.TELLYMCP_OAUTH_ISSUER ?? parsed.TELLYMCP_PUBLIC_URL).replace(/\/+$/u, ""),
|
|
415
|
+
audience: (parsed.TELLYMCP_OAUTH_AUDIENCE ?? parsed.TELLYMCP_PUBLIC_URL).replace(/\/+$/u, ""),
|
|
416
|
+
...(parsed.TELLYMCP_MAGIC_TOKEN
|
|
417
|
+
? { magicToken: parsed.TELLYMCP_MAGIC_TOKEN }
|
|
418
|
+
: {}),
|
|
419
|
+
...(parsed.TELLYMCP_MAGIC_TOKEN_HASH
|
|
420
|
+
? { magicTokenHash: parsed.TELLYMCP_MAGIC_TOKEN_HASH }
|
|
421
|
+
: {}),
|
|
422
|
+
...(parsed.TELLYMCP_OAUTH_CLIENT_ID
|
|
423
|
+
? { clientId: parsed.TELLYMCP_OAUTH_CLIENT_ID }
|
|
424
|
+
: {}),
|
|
425
|
+
...(parsed.TELLYMCP_OAUTH_CLIENT_SECRET
|
|
426
|
+
? { clientSecret: parsed.TELLYMCP_OAUTH_CLIENT_SECRET }
|
|
427
|
+
: {}),
|
|
428
|
+
allowedRedirectUris,
|
|
429
|
+
...(parsed.TELLYMCP_OAUTH_PRIVATE_KEY_PEM
|
|
430
|
+
? {
|
|
431
|
+
privateKeyPem: parsed.TELLYMCP_OAUTH_PRIVATE_KEY_PEM.replace(/\\n/gu, "\n"),
|
|
432
|
+
}
|
|
433
|
+
: {}),
|
|
434
|
+
authCodeTtlSeconds: parsed.TELLYMCP_AUTH_CODE_TTL_SECONDS,
|
|
435
|
+
scopes: oauthScopes,
|
|
436
|
+
keyId: parsed.TELLYMCP_OAUTH_KEY_ID,
|
|
437
|
+
},
|
|
438
|
+
}
|
|
439
|
+
: {}),
|
|
331
440
|
distributed: {
|
|
332
441
|
mode: parsed.DISTRIBUTED_MODE,
|
|
333
442
|
...(parsed.GATEWAY_PUBLIC_URL
|
|
334
443
|
? { gatewayPublicUrl: parsed.GATEWAY_PUBLIC_URL }
|
|
335
444
|
: {}),
|
|
336
|
-
gatewayBindHost: parsed.GATEWAY_BIND_HOST,
|
|
337
|
-
gatewayBindPort: parsed.GATEWAY_BIND_PORT,
|
|
338
445
|
...(parsed.GATEWAY_WS_URL
|
|
339
446
|
? { gatewayWsUrl: parsed.GATEWAY_WS_URL }
|
|
340
447
|
: {}),
|
|
341
448
|
gatewayWsPath: parsed.GATEWAY_WS_PATH,
|
|
342
|
-
...(parsed.
|
|
343
|
-
? {
|
|
449
|
+
...(parsed.GATEWAY_SCOPE_TOKEN
|
|
450
|
+
? { gatewayScopeToken: parsed.GATEWAY_SCOPE_TOKEN }
|
|
344
451
|
: {}),
|
|
345
452
|
...(parsed.GATEWAY_USER_UUID
|
|
346
453
|
? { gatewayUserUuid: parsed.GATEWAY_USER_UUID }
|
|
@@ -348,21 +455,6 @@ function loadConfig() {
|
|
|
348
455
|
...(parsed.GATEWAY_AUTH_TOKEN
|
|
349
456
|
? { gatewayAuthToken: parsed.GATEWAY_AUTH_TOKEN }
|
|
350
457
|
: {}),
|
|
351
|
-
...(parsed.GATEWAY_DATABASE_URL
|
|
352
|
-
? { gatewayDatabaseUrl: parsed.GATEWAY_DATABASE_URL }
|
|
353
|
-
: {}),
|
|
354
|
-
...(parsed.GATEWAY_S3_ENDPOINT
|
|
355
|
-
? { gatewayS3Endpoint: parsed.GATEWAY_S3_ENDPOINT }
|
|
356
|
-
: {}),
|
|
357
|
-
...(parsed.GATEWAY_S3_BUCKET
|
|
358
|
-
? { gatewayS3Bucket: parsed.GATEWAY_S3_BUCKET }
|
|
359
|
-
: {}),
|
|
360
|
-
...(parsed.GATEWAY_S3_ACCESS_KEY
|
|
361
|
-
? { gatewayS3AccessKey: parsed.GATEWAY_S3_ACCESS_KEY }
|
|
362
|
-
: {}),
|
|
363
|
-
...(parsed.GATEWAY_S3_SECRET_KEY
|
|
364
|
-
? { gatewayS3SecretKey: parsed.GATEWAY_S3_SECRET_KEY }
|
|
365
|
-
: {}),
|
|
366
458
|
...(parsed.RMQ_HOST
|
|
367
459
|
? {
|
|
368
460
|
rmq: {
|
|
@@ -386,7 +478,6 @@ function loadConfig() {
|
|
|
386
478
|
sessionTtlSeconds: parsed.WEBAPP_SESSION_TTL_SECONDS,
|
|
387
479
|
launchMode: parsed.WEBAPP_LAUNCH_MODE,
|
|
388
480
|
visibleScreens: parsed.WEBAPP_VISIBLE_SCREENS,
|
|
389
|
-
pollIntervalMs: parsed.WEBAPP_POLL_INTERVAL_MS,
|
|
390
481
|
actionCooldownMs: parsed.WEBAPP_ACTION_COOLDOWN_MS,
|
|
391
482
|
},
|
|
392
483
|
exchange: {
|