@deadragdoll/tellymcp 0.0.14 → 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 +19 -39
- package/.env.example.gateway +40 -64
- package/CHANGELOG.md +27 -0
- package/README-ru.md +66 -6
- package/README.md +66 -6
- package/TOOLS.md +38 -1
- package/config/templates/env.both.template +4 -5
- package/config/templates/env.client.template +4 -17
- package/config/templates/env.gateway.template +4 -29
- package/dist/cli.js +225 -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/collaboration.service.js +2 -2
- package/dist/services/features/telegram-mcp/ensuredb.service.js +1 -1
- package/dist/services/features/telegram-mcp/gateway.service.js +1 -1
- package/dist/services/features/telegram-mcp/mcp-server.service.js +2 -0
- package/dist/services/features/telegram-mcp/session-context.service.js +25 -1
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +70 -66
- package/dist/services/features/telegram-mcp/src/app/config/env.js +10 -36
- package/dist/services/features/telegram-mcp/src/app/config/environmentContract.js +66 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +28 -2
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +2 -2
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +5 -5
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +1 -1
- 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 +0 -1
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +4 -3
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +4 -4
- 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 +1 -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/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/lib/gatewayScope.js +5 -5
- package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +10 -0
- package/docs/STANDALONE-ru.md +29 -4
- package/docs/STANDALONE.md +29 -4
- package/package.json +1 -1
- package/scripts/postinstall.js +33 -1
|
@@ -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,
|
|
@@ -117,24 +117,16 @@ const envSchema = z.object({
|
|
|
117
117
|
.string()
|
|
118
118
|
.optional()
|
|
119
119
|
.transform((value) => value === "true"),
|
|
120
|
-
MCP_VFS_SCOPE: z.string().min(1).default("mcp"),
|
|
121
120
|
DISTRIBUTED_MODE: z.enum(["client", "gateway", "both"]).default("client"),
|
|
122
121
|
GATEWAY_PUBLIC_URL: optionalUrlString,
|
|
123
|
-
GATEWAY_BIND_HOST: z.string().min(1).default("127.0.0.1"),
|
|
124
|
-
GATEWAY_BIND_PORT: z.coerce.number().int().positive().default(8790),
|
|
125
122
|
GATEWAY_WS_URL: optionalUrlString,
|
|
126
123
|
GATEWAY_WS_PATH: z
|
|
127
124
|
.string()
|
|
128
125
|
.min(1)
|
|
129
126
|
.default(`${(process.env.ROOT_PREFIX || "/api").replace(/\/+$/u, "")}/gateway/ws`),
|
|
130
|
-
|
|
127
|
+
GATEWAY_SCOPE_TOKEN: optionalNonEmptyString,
|
|
131
128
|
GATEWAY_USER_UUID: optionalNonEmptyString,
|
|
132
129
|
GATEWAY_AUTH_TOKEN: optionalNonEmptyString,
|
|
133
|
-
GATEWAY_DATABASE_URL: optionalNonEmptyString,
|
|
134
|
-
GATEWAY_S3_ENDPOINT: optionalNonEmptyString,
|
|
135
|
-
GATEWAY_S3_BUCKET: optionalNonEmptyString,
|
|
136
|
-
GATEWAY_S3_ACCESS_KEY: optionalNonEmptyString,
|
|
137
|
-
GATEWAY_S3_SECRET_KEY: optionalNonEmptyString,
|
|
138
130
|
RMQ_HOST: optionalNonEmptyString,
|
|
139
131
|
RMQ_PORT: z.coerce.number().int().positive().optional(),
|
|
140
132
|
RMQ_USER: optionalNonEmptyString,
|
|
@@ -256,6 +248,7 @@ function loadConfig() {
|
|
|
256
248
|
else if ((0, node_fs_1.existsSync)(".env")) {
|
|
257
249
|
process.loadEnvFile(".env");
|
|
258
250
|
}
|
|
251
|
+
(0, environmentContract_1.assertNoLegacyEnvironmentVariables)(process.env);
|
|
259
252
|
const parsed = envSchema.parse(process.env);
|
|
260
253
|
if (parsed.DISTRIBUTED_MODE !== "client" &&
|
|
261
254
|
!parsed.TELEGRAM_BOT_TOKEN?.trim()) {
|
|
@@ -403,13 +396,11 @@ function loadConfig() {
|
|
|
403
396
|
...(parsed.REDIS_USERNAME ? { username: parsed.REDIS_USERNAME } : {}),
|
|
404
397
|
...(parsed.REDIS_PASSWORD ? { password: parsed.REDIS_PASSWORD } : {}),
|
|
405
398
|
},
|
|
406
|
-
mode: parsed.
|
|
407
|
-
pairCodeTtlSeconds: parsed.PAIR_CODE_TTL_SECONDS,
|
|
399
|
+
mode: parsed.TELEGRAM_REQUEST_MODE,
|
|
408
400
|
mcp: {
|
|
409
401
|
httpHost: parsed.MCP_HTTP_HOST,
|
|
410
402
|
httpPort: parsed.MCP_HTTP_PORT,
|
|
411
403
|
httpPath: parsed.MCP_HTTP_PATH,
|
|
412
|
-
vfsScope: parsed.MCP_VFS_SCOPE,
|
|
413
404
|
...(parsed.MCP_HTTP_BEARER_TOKEN
|
|
414
405
|
? { bearerToken: parsed.MCP_HTTP_BEARER_TOKEN }
|
|
415
406
|
: {}),
|
|
@@ -451,14 +442,12 @@ function loadConfig() {
|
|
|
451
442
|
...(parsed.GATEWAY_PUBLIC_URL
|
|
452
443
|
? { gatewayPublicUrl: parsed.GATEWAY_PUBLIC_URL }
|
|
453
444
|
: {}),
|
|
454
|
-
gatewayBindHost: parsed.GATEWAY_BIND_HOST,
|
|
455
|
-
gatewayBindPort: parsed.GATEWAY_BIND_PORT,
|
|
456
445
|
...(parsed.GATEWAY_WS_URL
|
|
457
446
|
? { gatewayWsUrl: parsed.GATEWAY_WS_URL }
|
|
458
447
|
: {}),
|
|
459
448
|
gatewayWsPath: parsed.GATEWAY_WS_PATH,
|
|
460
|
-
...(parsed.
|
|
461
|
-
? {
|
|
449
|
+
...(parsed.GATEWAY_SCOPE_TOKEN
|
|
450
|
+
? { gatewayScopeToken: parsed.GATEWAY_SCOPE_TOKEN }
|
|
462
451
|
: {}),
|
|
463
452
|
...(parsed.GATEWAY_USER_UUID
|
|
464
453
|
? { gatewayUserUuid: parsed.GATEWAY_USER_UUID }
|
|
@@ -466,21 +455,6 @@ function loadConfig() {
|
|
|
466
455
|
...(parsed.GATEWAY_AUTH_TOKEN
|
|
467
456
|
? { gatewayAuthToken: parsed.GATEWAY_AUTH_TOKEN }
|
|
468
457
|
: {}),
|
|
469
|
-
...(parsed.GATEWAY_DATABASE_URL
|
|
470
|
-
? { gatewayDatabaseUrl: parsed.GATEWAY_DATABASE_URL }
|
|
471
|
-
: {}),
|
|
472
|
-
...(parsed.GATEWAY_S3_ENDPOINT
|
|
473
|
-
? { gatewayS3Endpoint: parsed.GATEWAY_S3_ENDPOINT }
|
|
474
|
-
: {}),
|
|
475
|
-
...(parsed.GATEWAY_S3_BUCKET
|
|
476
|
-
? { gatewayS3Bucket: parsed.GATEWAY_S3_BUCKET }
|
|
477
|
-
: {}),
|
|
478
|
-
...(parsed.GATEWAY_S3_ACCESS_KEY
|
|
479
|
-
? { gatewayS3AccessKey: parsed.GATEWAY_S3_ACCESS_KEY }
|
|
480
|
-
: {}),
|
|
481
|
-
...(parsed.GATEWAY_S3_SECRET_KEY
|
|
482
|
-
? { gatewayS3SecretKey: parsed.GATEWAY_S3_SECRET_KEY }
|
|
483
|
-
: {}),
|
|
484
458
|
...(parsed.RMQ_HOST
|
|
485
459
|
? {
|
|
486
460
|
rmq: {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.REMOVED_ENV_KEYS = exports.LEGACY_ENV_RENAMES = void 0;
|
|
4
|
+
exports.getTmuxReplacement = getTmuxReplacement;
|
|
5
|
+
exports.assertNoLegacyEnvironmentVariables = assertNoLegacyEnvironmentVariables;
|
|
6
|
+
exports.LEGACY_ENV_RENAMES = {
|
|
7
|
+
MODE: "TELEGRAM_REQUEST_MODE",
|
|
8
|
+
GATEWAY_TOKEN: "GATEWAY_SCOPE_TOKEN",
|
|
9
|
+
DB_SCHEME: "DB_SCHEMA",
|
|
10
|
+
ENABLE_LOGFEED: "LOGFEED_ENABLED",
|
|
11
|
+
};
|
|
12
|
+
exports.REMOVED_ENV_KEYS = [
|
|
13
|
+
"APP_NAME",
|
|
14
|
+
"BROWSER_ATTACH_TOKEN",
|
|
15
|
+
"GATEWAY_BIND_HOST",
|
|
16
|
+
"GATEWAY_BIND_PORT",
|
|
17
|
+
"GATEWAY_DATABASE_URL",
|
|
18
|
+
"GATEWAY_S3_ACCESS_KEY",
|
|
19
|
+
"GATEWAY_S3_BUCKET",
|
|
20
|
+
"GATEWAY_S3_ENDPOINT",
|
|
21
|
+
"GATEWAY_S3_SECRET_KEY",
|
|
22
|
+
"MAX_BODY_SIZE",
|
|
23
|
+
"MCP_VFS_SCOPE",
|
|
24
|
+
"PAIR_CODE_TTL_SECONDS",
|
|
25
|
+
"SESSION_SECRET",
|
|
26
|
+
"TELEGRAM_INBOX_BATCH_SIZE",
|
|
27
|
+
"TERMINAL_TRANSPORT",
|
|
28
|
+
"TOKEN_BINDING_SECRET",
|
|
29
|
+
"WEBAPP_POLL_INTERVAL_MS",
|
|
30
|
+
];
|
|
31
|
+
function getTmuxReplacement(name) {
|
|
32
|
+
if (!name.startsWith("TMUX_")) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
if (name === "TMUX_SOCKET_PATH") {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return `TERMINAL_${name.slice("TMUX_".length)}`;
|
|
39
|
+
}
|
|
40
|
+
function assertNoLegacyEnvironmentVariables(environment) {
|
|
41
|
+
const issues = [];
|
|
42
|
+
for (const [legacyName, replacement] of Object.entries(exports.LEGACY_ENV_RENAMES)) {
|
|
43
|
+
const value = environment[legacyName];
|
|
44
|
+
if (value !== undefined) {
|
|
45
|
+
// MODE is also set by tools such as Vite. Only the two former TellyMCP
|
|
46
|
+
// queue-policy values identify it as our legacy setting.
|
|
47
|
+
if (legacyName === "MODE" && value !== "queue" && value !== "reject") {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
issues.push(`${legacyName} -> ${replacement}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
for (const name of exports.REMOVED_ENV_KEYS) {
|
|
54
|
+
if (environment[name] !== undefined) {
|
|
55
|
+
issues.push(`${name} (remove)`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const tmuxName of Object.keys(environment).filter((name) => name.startsWith("TMUX_"))) {
|
|
59
|
+
const replacement = getTmuxReplacement(tmuxName);
|
|
60
|
+
issues.push(replacement ? `${tmuxName} -> ${replacement}` : `${tmuxName} (remove)`);
|
|
61
|
+
}
|
|
62
|
+
if (issues.length > 0) {
|
|
63
|
+
throw new Error(`Environment migration is required: ${issues.sort().join(", ")}. ` +
|
|
64
|
+
"Run: tellymcp migrate-env <input.env> > .migrated-env");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -33,8 +33,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
37
|
-
exports.markXchangeRecordReadOutputSchema = exports.markXchangeRecordReadInputSchema = exports.getXchangeRecordOutputSchema = exports.getXchangeRecordInputSchema = exports.listXchangeRecordsOutputSchema = exports.listXchangeRecordsInputSchema = exports.sendPartnerNoteOutputSchema = exports.sendPartnerFileInputSchema = exports.sendPartnerNoteInputSchema = exports.browserCloseOutputSchema = exports.browserCloseInputSchema = exports.browserScreenshotOutputSchema = exports.browserScreenshotInputSchema = exports.browserComputedStyleOutputSchema = exports.browserComputedStyleInputSchema = exports.browserDomOutputSchema = exports.browserDomInputSchema = exports.browserClearLogsOutputSchema = exports.browserClearLogsInputSchema = exports.browserNetworkFailuresOutputSchema = exports.browserNetworkFailuresInputSchema = exports.browserErrorsOutputSchema = exports.browserErrorsInputSchema = exports.browserConsoleOutputSchema = exports.browserConsoleInputSchema = exports.browserWaitForUrlOutputSchema = exports.browserWaitForUrlInputSchema = exports.browserWaitForOutputSchema = void 0;
|
|
36
|
+
exports.browserInjectScriptInputSchema = exports.browserPressOutputSchema = exports.browserPressInputSchema = exports.browserFillOutputSchema = exports.browserFillInputSchema = exports.browserClickOutputSchema = exports.browserClickInputSchema = exports.browserReloadOutputSchema = exports.browserReloadInputSchema = exports.browserRecordingStatusOutputSchema = exports.browserRecordingStatusInputSchema = exports.browserRecordingStopOutputSchema = exports.browserRecordingStopInputSchema = exports.browserRecordingStartOutputSchema = exports.browserRecordingStartInputSchema = exports.browserDetachTabOutputSchema = exports.browserDetachTabInputSchema = exports.browserAttachTabOutputSchema = exports.browserAttachTabInputSchema = exports.browserAttachActiveTabInputSchema = exports.browserListTabsOutputSchema = exports.browserListTabsInputSchema = exports.browserListAttachedInstancesOutputSchema = exports.browserListAttachedInstancesInputSchema = exports.browserOpenOutputSchema = exports.browserOpenInputSchema = exports.clearSessionContextOutputSchema = exports.clearSessionContextInputSchema = exports.getRuntimeDiagnosticsOutputSchema = exports.getRuntimeDiagnosticsInputSchema = exports.getSessionContextOutputSchema = exports.getSessionContextInputSchema = exports.setSessionContextOutputSchema = exports.renameSessionOutputSchema = exports.renameSessionInputSchema = exports.setSessionContextInputSchema = exports.refreshToolsMarkdownOutputSchema = exports.refreshToolsMarkdownInputSchema = exports.listGatewaySessionsOutputSchema = exports.listGatewaySessionsInputSchema = exports.getFileListOutputSchema = exports.getFileListInputSchema = exports.getFileOutputSchema = exports.getFileInputSchema = exports.sendFileToTelegramOutputSchema = exports.sendFileToTelegramInputSchema = exports.notifyTelegramOutputSchema = exports.notifyTelegramInputSchema = exports.askUserTelegramOutputSchema = exports.askUserTelegramInputSchema = void 0;
|
|
37
|
+
exports.markXchangeRecordReadOutputSchema = exports.markXchangeRecordReadInputSchema = exports.getXchangeRecordOutputSchema = exports.getXchangeRecordInputSchema = exports.listXchangeRecordsOutputSchema = exports.listXchangeRecordsInputSchema = exports.sendPartnerNoteOutputSchema = exports.sendPartnerFileInputSchema = exports.sendPartnerNoteInputSchema = exports.browserCloseOutputSchema = exports.browserCloseInputSchema = exports.browserScreenshotOutputSchema = exports.browserScreenshotInputSchema = exports.browserComputedStyleOutputSchema = exports.browserComputedStyleInputSchema = exports.browserDomOutputSchema = exports.browserDomInputSchema = exports.browserClearLogsOutputSchema = exports.browserClearLogsInputSchema = exports.browserNetworkFailuresOutputSchema = exports.browserNetworkFailuresInputSchema = exports.browserErrorsOutputSchema = exports.browserErrorsInputSchema = exports.browserConsoleOutputSchema = exports.browserConsoleInputSchema = exports.browserWaitForUrlOutputSchema = exports.browserWaitForUrlInputSchema = exports.browserWaitForOutputSchema = exports.browserWaitForInputSchema = exports.browserInjectScriptOutputSchema = void 0;
|
|
38
38
|
const z = __importStar(require("zod/v4"));
|
|
39
39
|
const bodyLimits_1 = require("../../../shared/lib/bodyLimits");
|
|
40
40
|
const bodyStringSchema = z.string().max(bodyLimits_1.MAX_BODY_SIZE_BYTES);
|
|
@@ -224,6 +224,32 @@ exports.getSessionContextOutputSchema = z.object({
|
|
|
224
224
|
})
|
|
225
225
|
.optional(),
|
|
226
226
|
});
|
|
227
|
+
const runtimeDiagnosticCheckSchema = z.object({
|
|
228
|
+
status: z.enum(["ok", "warn", "error"]),
|
|
229
|
+
message: z.string(),
|
|
230
|
+
});
|
|
231
|
+
exports.getRuntimeDiagnosticsInputSchema = z.object({
|
|
232
|
+
session_id: z.string().trim().min(1).optional(),
|
|
233
|
+
});
|
|
234
|
+
exports.getRuntimeDiagnosticsOutputSchema = z.object({
|
|
235
|
+
status: z.enum(["ok", "degraded"]),
|
|
236
|
+
checked_at: z.string(),
|
|
237
|
+
session_id: z.string(),
|
|
238
|
+
runtime: z.object({
|
|
239
|
+
mode: z.enum(["client", "gateway", "both"]),
|
|
240
|
+
package_version: z.string(),
|
|
241
|
+
protocol_version: z.string(),
|
|
242
|
+
node_id: z.string().optional(),
|
|
243
|
+
}),
|
|
244
|
+
checks: z.object({
|
|
245
|
+
configuration: runtimeDiagnosticCheckSchema,
|
|
246
|
+
redis: runtimeDiagnosticCheckSchema,
|
|
247
|
+
session_store: runtimeDiagnosticCheckSchema,
|
|
248
|
+
terminal: runtimeDiagnosticCheckSchema,
|
|
249
|
+
gateway_configuration: runtimeDiagnosticCheckSchema,
|
|
250
|
+
relay: runtimeDiagnosticCheckSchema,
|
|
251
|
+
}),
|
|
252
|
+
});
|
|
227
253
|
exports.clearSessionContextInputSchema = z.object({
|
|
228
254
|
session_id: z.string().trim().min(1).optional(),
|
|
229
255
|
});
|
|
@@ -1752,8 +1752,8 @@ for (const __tellyKey of Object.getOwnPropertyNames(window)) {
|
|
|
1752
1752
|
...(this.config.distributed.gatewayAuthToken
|
|
1753
1753
|
? { gatewayAuthToken: this.config.distributed.gatewayAuthToken }
|
|
1754
1754
|
: {}),
|
|
1755
|
-
...(this.config.distributed.
|
|
1756
|
-
? {
|
|
1755
|
+
...(this.config.distributed.gatewayScopeToken
|
|
1756
|
+
? { gatewayScopeToken: this.config.distributed.gatewayScopeToken }
|
|
1757
1757
|
: {}),
|
|
1758
1758
|
...(this.config.project.name
|
|
1759
1759
|
? { projectName: this.config.project.name }
|
|
@@ -7,16 +7,16 @@ class GatewaySessionsService {
|
|
|
7
7
|
maintenanceStore;
|
|
8
8
|
gatewayPublicUrl;
|
|
9
9
|
gatewayAuthToken;
|
|
10
|
-
|
|
10
|
+
gatewayScopeToken;
|
|
11
11
|
gatewayUserUuid;
|
|
12
12
|
projectName;
|
|
13
13
|
botUsername;
|
|
14
|
-
constructor(logger, maintenanceStore, gatewayPublicUrl, gatewayAuthToken,
|
|
14
|
+
constructor(logger, maintenanceStore, gatewayPublicUrl, gatewayAuthToken, gatewayScopeToken, gatewayUserUuid, projectName, botUsername) {
|
|
15
15
|
this.logger = logger;
|
|
16
16
|
this.maintenanceStore = maintenanceStore;
|
|
17
17
|
this.gatewayPublicUrl = gatewayPublicUrl;
|
|
18
18
|
this.gatewayAuthToken = gatewayAuthToken;
|
|
19
|
-
this.
|
|
19
|
+
this.gatewayScopeToken = gatewayScopeToken;
|
|
20
20
|
this.gatewayUserUuid = gatewayUserUuid;
|
|
21
21
|
this.projectName = projectName;
|
|
22
22
|
this.botUsername = botUsername;
|
|
@@ -31,7 +31,7 @@ class GatewaySessionsService {
|
|
|
31
31
|
...(this.gatewayAuthToken
|
|
32
32
|
? { gatewayAuthToken: this.gatewayAuthToken }
|
|
33
33
|
: {}),
|
|
34
|
-
...(this.
|
|
34
|
+
...(this.gatewayScopeToken ? { gatewayScopeToken: this.gatewayScopeToken } : {}),
|
|
35
35
|
...(this.gatewayUserUuid ? { gatewayUserUuid: this.gatewayUserUuid } : {}),
|
|
36
36
|
...(this.projectName ? { projectName: this.projectName } : {}),
|
|
37
37
|
...(this.botUsername ? { botUsername: this.botUsername } : {}),
|
|
@@ -46,7 +46,7 @@ class GatewaySessionsService {
|
|
|
46
46
|
...(input.client_uuid?.trim()
|
|
47
47
|
? { client_uuid: input.client_uuid.trim() }
|
|
48
48
|
: {}),
|
|
49
|
-
...(this.
|
|
49
|
+
...(this.gatewayScopeToken ? { gateway_token: this.gatewayScopeToken } : {}),
|
|
50
50
|
...(this.gatewayUserUuid
|
|
51
51
|
? { owner_user_uuid: this.gatewayUserUuid }
|
|
52
52
|
: {}),
|
|
@@ -68,7 +68,7 @@ async function ensureGatewayClientUuid(input) {
|
|
|
68
68
|
input.botUsername ||
|
|
69
69
|
"tellymcp client",
|
|
70
70
|
...(input.botUsername ? { bot_username: input.botUsername } : {}),
|
|
71
|
-
...(input.
|
|
71
|
+
...(input.gatewayScopeToken ? { gateway_token: input.gatewayScopeToken } : {}),
|
|
72
72
|
...(input.gatewayUserUuid ? { owner_user_uuid: input.gatewayUserUuid } : {}),
|
|
73
73
|
meta: {
|
|
74
74
|
...(namespace ? { namespace } : {}),
|
|
@@ -7,16 +7,16 @@ class GatewayCollaborationBackend {
|
|
|
7
7
|
maintenanceStore;
|
|
8
8
|
gatewayPublicUrl;
|
|
9
9
|
gatewayAuthToken;
|
|
10
|
-
|
|
10
|
+
gatewayScopeToken;
|
|
11
11
|
gatewayUserUuid;
|
|
12
12
|
projectName;
|
|
13
13
|
botUsername;
|
|
14
|
-
constructor(logger, maintenanceStore, gatewayPublicUrl, gatewayAuthToken,
|
|
14
|
+
constructor(logger, maintenanceStore, gatewayPublicUrl, gatewayAuthToken, gatewayScopeToken, gatewayUserUuid, projectName, botUsername) {
|
|
15
15
|
this.logger = logger;
|
|
16
16
|
this.maintenanceStore = maintenanceStore;
|
|
17
17
|
this.gatewayPublicUrl = gatewayPublicUrl;
|
|
18
18
|
this.gatewayAuthToken = gatewayAuthToken;
|
|
19
|
-
this.
|
|
19
|
+
this.gatewayScopeToken = gatewayScopeToken;
|
|
20
20
|
this.gatewayUserUuid = gatewayUserUuid;
|
|
21
21
|
this.projectName = projectName;
|
|
22
22
|
this.botUsername = botUsername;
|
|
@@ -33,7 +33,7 @@ class GatewayCollaborationBackend {
|
|
|
33
33
|
...(this.gatewayAuthToken
|
|
34
34
|
? { gatewayAuthToken: this.gatewayAuthToken }
|
|
35
35
|
: {}),
|
|
36
|
-
...(this.
|
|
36
|
+
...(this.gatewayScopeToken ? { gatewayScopeToken: this.gatewayScopeToken } : {}),
|
|
37
37
|
...(this.gatewayUserUuid ? { gatewayUserUuid: this.gatewayUserUuid } : {}),
|
|
38
38
|
...(this.projectName ? { projectName: this.projectName } : {}),
|
|
39
39
|
...(this.botUsername ? { botUsername: this.botUsername } : {}),
|
|
@@ -241,7 +241,6 @@ class GatewayHttpService {
|
|
|
241
241
|
service: "tellymcp-gateway",
|
|
242
242
|
mode: this.config.distributed.mode,
|
|
243
243
|
databaseConfigured: Boolean(process.env.DB_HOST && process.env.DB_NAME),
|
|
244
|
-
s3Configured: Boolean(this.config.distributed.gatewayS3Bucket),
|
|
245
244
|
});
|
|
246
245
|
return true;
|
|
247
246
|
}
|
|
@@ -9,6 +9,7 @@ function isBackendErrorLike(value) {
|
|
|
9
9
|
typeof value.code === "string");
|
|
10
10
|
}
|
|
11
11
|
function formatBackendErrorLike(value) {
|
|
12
|
+
const truncate = (text, maxLength = 2_000) => text.length > maxLength ? `${text.slice(0, maxLength - 3)}...` : text;
|
|
12
13
|
const details = [];
|
|
13
14
|
if (typeof value.code === "string" && value.code.trim()) {
|
|
14
15
|
details.push(`code=${value.code.trim()}`);
|
|
@@ -18,14 +19,14 @@ function formatBackendErrorLike(value) {
|
|
|
18
19
|
}
|
|
19
20
|
if (value.data !== undefined) {
|
|
20
21
|
try {
|
|
21
|
-
details.push(`data=${JSON.stringify(value.data)}`);
|
|
22
|
+
details.push(`data=${truncate(JSON.stringify(value.data))}`);
|
|
22
23
|
}
|
|
23
24
|
catch {
|
|
24
|
-
details.push(`data=${String(value.data)}`);
|
|
25
|
+
details.push(`data=${truncate(String(value.data))}`);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
const base = typeof value.message === "string" && value.message.trim()
|
|
28
|
-
? value.message.trim()
|
|
29
|
+
? truncate(value.message.trim())
|
|
29
30
|
: `${value.name ?? "BackendError"} (${value.code})`;
|
|
30
31
|
return details.length > 0 ? `${base}\n${details.join("\n")}` : base;
|
|
31
32
|
}
|
|
@@ -325,8 +325,8 @@ class NotifyService {
|
|
|
325
325
|
...(this._config.distributed.gatewayAuthToken
|
|
326
326
|
? { gatewayAuthToken: this._config.distributed.gatewayAuthToken }
|
|
327
327
|
: {}),
|
|
328
|
-
...(this._config.distributed.
|
|
329
|
-
? {
|
|
328
|
+
...(this._config.distributed.gatewayScopeToken
|
|
329
|
+
? { gatewayScopeToken: this._config.distributed.gatewayScopeToken }
|
|
330
330
|
: {}),
|
|
331
331
|
...(this._config.project.name
|
|
332
332
|
? { projectName: this._config.project.name }
|
|
@@ -382,8 +382,8 @@ class NotifyService {
|
|
|
382
382
|
...(this._config.distributed.gatewayAuthToken
|
|
383
383
|
? { gatewayAuthToken: this._config.distributed.gatewayAuthToken }
|
|
384
384
|
: {}),
|
|
385
|
-
...(this._config.distributed.
|
|
386
|
-
? {
|
|
385
|
+
...(this._config.distributed.gatewayScopeToken
|
|
386
|
+
? { gatewayScopeToken: this._config.distributed.gatewayScopeToken }
|
|
387
387
|
: {}),
|
|
388
388
|
...(this._config.project.name
|
|
389
389
|
? { projectName: this._config.project.name }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetRuntimeDiagnosticsTool = void 0;
|
|
4
|
+
const schema_1 = require("../../../entities/request/model/schema");
|
|
5
|
+
class GetRuntimeDiagnosticsTool {
|
|
6
|
+
sessionContextService;
|
|
7
|
+
constructor(sessionContextService) {
|
|
8
|
+
this.sessionContextService = sessionContextService;
|
|
9
|
+
}
|
|
10
|
+
register(server) {
|
|
11
|
+
server.registerTool("get_runtime_diagnostics", {
|
|
12
|
+
title: "Get Runtime Diagnostics",
|
|
13
|
+
description: "Run safe, read-only health checks for a selected console: environment schema, package/protocol version, runtime state store, PTY state, gateway configuration, and gateway-to-client relay. Redis is probed only for gateway runtimes. Secrets and raw connection strings are never returned. In gateway mode, pass session_id exactly as returned by list_gateway_sessions.",
|
|
14
|
+
inputSchema: schema_1.getRuntimeDiagnosticsInputSchema,
|
|
15
|
+
outputSchema: schema_1.getRuntimeDiagnosticsOutputSchema,
|
|
16
|
+
}, async (args) => {
|
|
17
|
+
const output = await this.sessionContextService.getRuntimeDiagnostics(args);
|
|
18
|
+
return {
|
|
19
|
+
content: [
|
|
20
|
+
{
|
|
21
|
+
type: "text",
|
|
22
|
+
text: JSON.stringify(output, null, 2),
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
structuredContent: output,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.GetRuntimeDiagnosticsTool = GetRuntimeDiagnosticsTool;
|
|
@@ -9,16 +9,174 @@ class SessionContextService {
|
|
|
9
9
|
logger;
|
|
10
10
|
projectIdentityResolver;
|
|
11
11
|
remoteConsoleInvoker;
|
|
12
|
-
|
|
12
|
+
runtimeDiagnostics;
|
|
13
|
+
constructor(sessionStore, bindingStore, logger, projectIdentityResolver, remoteConsoleInvoker, runtimeDiagnostics) {
|
|
13
14
|
this.sessionStore = sessionStore;
|
|
14
15
|
this.bindingStore = bindingStore;
|
|
15
16
|
this.logger = logger;
|
|
16
17
|
this.projectIdentityResolver = projectIdentityResolver;
|
|
17
18
|
this.remoteConsoleInvoker = remoteConsoleInvoker;
|
|
19
|
+
this.runtimeDiagnostics = runtimeDiagnostics;
|
|
20
|
+
}
|
|
21
|
+
getRemoteConsoleInvoker() {
|
|
22
|
+
return this.runtimeDiagnostics?.mode === "client"
|
|
23
|
+
? undefined
|
|
24
|
+
: this.remoteConsoleInvoker;
|
|
25
|
+
}
|
|
26
|
+
formatDiagnosticError(error) {
|
|
27
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
28
|
+
const redacted = (0, redactSecrets_1.redactSecrets)(message).replace(/\s+/gu, " ").trim();
|
|
29
|
+
return redacted.length > 500
|
|
30
|
+
? `${redacted.slice(0, 497)}...`
|
|
31
|
+
: redacted || "Unknown error";
|
|
32
|
+
}
|
|
33
|
+
finalizeDiagnostics(output) {
|
|
34
|
+
const degraded = Object.values(output.checks).some((check) => check.status !== "ok");
|
|
35
|
+
return {
|
|
36
|
+
...output,
|
|
37
|
+
status: degraded ? "degraded" : "ok",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async collectLocalDiagnostics(sessionId) {
|
|
41
|
+
const runtime = this.runtimeDiagnostics;
|
|
42
|
+
let session = null;
|
|
43
|
+
let sessionStoreCheck;
|
|
44
|
+
try {
|
|
45
|
+
session = await this.sessionStore.getSession(sessionId);
|
|
46
|
+
await this.bindingStore.getBinding(sessionId);
|
|
47
|
+
sessionStoreCheck = {
|
|
48
|
+
status: "ok",
|
|
49
|
+
message: session
|
|
50
|
+
? "Session and route stores are readable; session metadata exists."
|
|
51
|
+
: "Session and route stores are readable; no saved metadata exists for this id.",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
sessionStoreCheck = {
|
|
56
|
+
status: "error",
|
|
57
|
+
message: `Session store check failed: ${this.formatDiagnosticError(error)}`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
let redisCheck;
|
|
61
|
+
if (runtime?.mode === "client") {
|
|
62
|
+
redisCheck = {
|
|
63
|
+
status: "ok",
|
|
64
|
+
message: "Redis is not required in client mode; process-local state is active.",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
else if (!runtime?.pingRedis) {
|
|
68
|
+
redisCheck = {
|
|
69
|
+
status: "warn",
|
|
70
|
+
message: "Runtime Redis probe is unavailable.",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
try {
|
|
75
|
+
const reply = await runtime.pingRedis();
|
|
76
|
+
redisCheck = {
|
|
77
|
+
status: reply.trim().toUpperCase() === "PONG" ? "ok" : "warn",
|
|
78
|
+
message: `Redis probe returned ${reply.trim() || "an empty response"}.`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
redisCheck = {
|
|
83
|
+
status: "error",
|
|
84
|
+
message: `Redis probe failed: ${this.formatDiagnosticError(error)}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const mode = runtime?.mode ?? "client";
|
|
89
|
+
const gatewayConfigured = Boolean(runtime?.gatewayWsUrlConfigured);
|
|
90
|
+
const gatewayConfiguration = mode === "gateway"
|
|
91
|
+
? {
|
|
92
|
+
status: "ok",
|
|
93
|
+
message: "Gateway runtime does not require an outbound gateway WebSocket URL.",
|
|
94
|
+
}
|
|
95
|
+
: gatewayConfigured
|
|
96
|
+
? {
|
|
97
|
+
status: "ok",
|
|
98
|
+
message: runtime?.gatewayAuthConfigured
|
|
99
|
+
? "Gateway WebSocket URL and authentication are configured."
|
|
100
|
+
: "Gateway WebSocket URL is configured; authentication is not configured.",
|
|
101
|
+
}
|
|
102
|
+
: {
|
|
103
|
+
status: "error",
|
|
104
|
+
message: "Gateway WebSocket URL is not configured for this client runtime.",
|
|
105
|
+
};
|
|
106
|
+
return this.finalizeDiagnostics({
|
|
107
|
+
checked_at: new Date().toISOString(),
|
|
108
|
+
session_id: sessionId,
|
|
109
|
+
runtime: {
|
|
110
|
+
mode,
|
|
111
|
+
package_version: runtime?.packageVersion ?? "unknown",
|
|
112
|
+
protocol_version: runtime?.protocolVersion ?? "unknown",
|
|
113
|
+
...(runtime?.nodeId ? { node_id: runtime.nodeId } : {}),
|
|
114
|
+
},
|
|
115
|
+
checks: {
|
|
116
|
+
configuration: runtime
|
|
117
|
+
? {
|
|
118
|
+
status: "ok",
|
|
119
|
+
message: "Normalized environment schema was accepted at startup.",
|
|
120
|
+
}
|
|
121
|
+
: {
|
|
122
|
+
status: "warn",
|
|
123
|
+
message: "Runtime configuration metadata is unavailable.",
|
|
124
|
+
},
|
|
125
|
+
redis: redisCheck,
|
|
126
|
+
session_store: sessionStoreCheck,
|
|
127
|
+
terminal: session?.terminalTarget
|
|
128
|
+
? {
|
|
129
|
+
status: "ok",
|
|
130
|
+
message: "A PTY terminal target is configured for this session.",
|
|
131
|
+
}
|
|
132
|
+
: {
|
|
133
|
+
status: "warn",
|
|
134
|
+
message: "No PTY terminal target is configured for this session.",
|
|
135
|
+
},
|
|
136
|
+
gateway_configuration: gatewayConfiguration,
|
|
137
|
+
relay: {
|
|
138
|
+
status: "ok",
|
|
139
|
+
message: "Local diagnostic action completed.",
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
async getRuntimeDiagnostics(input) {
|
|
145
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
146
|
+
const remoteConsoleInvoker = this.getRemoteConsoleInvoker();
|
|
147
|
+
if (!remoteConsoleInvoker) {
|
|
148
|
+
return await this.collectLocalDiagnostics(resolved.sessionId);
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const remote = await remoteConsoleInvoker.invokeForRelaySession(resolved.sessionId, "telegramMcp.sessionContext.getRuntimeDiagnosticsRemote", input);
|
|
152
|
+
return this.finalizeDiagnostics({
|
|
153
|
+
...remote,
|
|
154
|
+
checks: {
|
|
155
|
+
...remote.checks,
|
|
156
|
+
relay: {
|
|
157
|
+
status: "ok",
|
|
158
|
+
message: "Gateway-to-client relay completed successfully.",
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const local = await this.collectLocalDiagnostics(resolved.sessionId);
|
|
165
|
+
return this.finalizeDiagnostics({
|
|
166
|
+
...local,
|
|
167
|
+
checks: {
|
|
168
|
+
...local.checks,
|
|
169
|
+
relay: {
|
|
170
|
+
status: "error",
|
|
171
|
+
message: `Gateway-to-client relay failed: ${this.formatDiagnosticError(error)}`,
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}
|
|
18
176
|
}
|
|
19
177
|
async setContext(input) {
|
|
20
178
|
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
21
|
-
const remote = await this.
|
|
179
|
+
const remote = await this.getRemoteConsoleInvoker()?.invokeForRelaySession(resolved.sessionId, "telegramMcp.sessionContext.setContextRemote", input);
|
|
22
180
|
if (remote) {
|
|
23
181
|
return remote;
|
|
24
182
|
}
|
|
@@ -62,7 +220,9 @@ class SessionContextService {
|
|
|
62
220
|
: existing?.risks
|
|
63
221
|
? { risks: existing.risks }
|
|
64
222
|
: {}),
|
|
65
|
-
...(existing?.terminalTarget
|
|
223
|
+
...(existing?.terminalTarget
|
|
224
|
+
? { terminalTarget: existing.terminalTarget }
|
|
225
|
+
: {}),
|
|
66
226
|
...(existing?.lastTerminalNudgeAt
|
|
67
227
|
? { lastTerminalNudgeAt: existing.lastTerminalNudgeAt }
|
|
68
228
|
: {}),
|
|
@@ -98,7 +258,7 @@ class SessionContextService {
|
|
|
98
258
|
}
|
|
99
259
|
async renameSession(input) {
|
|
100
260
|
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
101
|
-
const remote = await this.
|
|
261
|
+
const remote = await this.getRemoteConsoleInvoker()?.invokeForRelaySession(resolved.sessionId, "telegramMcp.sessionContext.renameSessionRemote", input);
|
|
102
262
|
if (remote) {
|
|
103
263
|
return remote;
|
|
104
264
|
}
|
|
@@ -120,7 +280,9 @@ class SessionContextService {
|
|
|
120
280
|
...(existing?.files ? { files: existing.files } : {}),
|
|
121
281
|
...(existing?.decisions ? { decisions: existing.decisions } : {}),
|
|
122
282
|
...(existing?.risks ? { risks: existing.risks } : {}),
|
|
123
|
-
...(existing?.terminalTarget
|
|
283
|
+
...(existing?.terminalTarget
|
|
284
|
+
? { terminalTarget: existing.terminalTarget }
|
|
285
|
+
: {}),
|
|
124
286
|
...(existing?.lastTerminalNudgeAt
|
|
125
287
|
? { lastTerminalNudgeAt: existing.lastTerminalNudgeAt }
|
|
126
288
|
: {}),
|
|
@@ -151,7 +313,7 @@ class SessionContextService {
|
|
|
151
313
|
}
|
|
152
314
|
async getContext(input) {
|
|
153
315
|
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
154
|
-
const remote = await this.
|
|
316
|
+
const remote = await this.getRemoteConsoleInvoker()?.invokeForRelaySession(resolved.sessionId, "telegramMcp.sessionContext.getContextRemote", input);
|
|
155
317
|
if (remote) {
|
|
156
318
|
return remote;
|
|
157
319
|
}
|
|
@@ -224,7 +386,7 @@ class SessionContextService {
|
|
|
224
386
|
}
|
|
225
387
|
async clearContext(input) {
|
|
226
388
|
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
227
|
-
const remote = await this.
|
|
389
|
+
const remote = await this.getRemoteConsoleInvoker()?.invokeForRelaySession(resolved.sessionId, "telegramMcp.sessionContext.clearContextRemote", input);
|
|
228
390
|
if (remote) {
|
|
229
391
|
return remote;
|
|
230
392
|
}
|