@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
|
@@ -19,8 +19,7 @@ REDIS_HOST=127.0.0.1
|
|
|
19
19
|
REDIS_PORT=6379
|
|
20
20
|
REDIS_DB=1
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
PAIR_CODE_TTL_SECONDS=300
|
|
22
|
+
TELEGRAM_REQUEST_MODE=reject
|
|
24
23
|
|
|
25
24
|
MCP_HTTP_HOST=127.0.0.1
|
|
26
25
|
MCP_HTTP_PORT=8787
|
|
@@ -47,7 +46,7 @@ DISTRIBUTED_MODE=both
|
|
|
47
46
|
GATEWAY_PUBLIC_URL=
|
|
48
47
|
GATEWAY_WS_URL=
|
|
49
48
|
GATEWAY_WS_PATH=/api/gateway/ws
|
|
50
|
-
|
|
49
|
+
GATEWAY_SCOPE_TOKEN=
|
|
51
50
|
GATEWAY_USER_UUID=
|
|
52
51
|
GATEWAY_AUTH_TOKEN=
|
|
53
52
|
|
|
@@ -61,7 +60,7 @@ DB_PORT=5432
|
|
|
61
60
|
DB_USER=
|
|
62
61
|
DB_PASSWORD=
|
|
63
62
|
DB_NAME=
|
|
64
|
-
|
|
63
|
+
DB_SCHEMA=mcp
|
|
65
64
|
|
|
66
65
|
# RMQ_HOST=127.0.0.1
|
|
67
66
|
# RMQ_PORT=5672
|
|
@@ -113,4 +112,4 @@ BROWSER_SLOW_MO_MS=0
|
|
|
113
112
|
LOG_LEVEL=info
|
|
114
113
|
LOG_FILE_ENABLED=false
|
|
115
114
|
LOG_FILE_PATH=.tellymcp/log.jsonl
|
|
116
|
-
|
|
115
|
+
LOGFEED_ENABLED=0
|
|
@@ -4,12 +4,8 @@
|
|
|
4
4
|
# TELLYMCP_SESSION_ID=NEW
|
|
5
5
|
# TELLYMCP_SESSION_LABEL=NEW
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
REDIS_DB=1
|
|
10
|
-
|
|
11
|
-
MODE=reject
|
|
12
|
-
PAIR_CODE_TTL_SECONDS=300
|
|
7
|
+
# Client state is process-local. Redis is gateway-only.
|
|
8
|
+
TELEGRAM_REQUEST_MODE=reject
|
|
13
9
|
|
|
14
10
|
MCP_HTTP_HOST=127.0.0.1
|
|
15
11
|
MCP_HTTP_PORT=8787
|
|
@@ -22,7 +18,7 @@ DISTRIBUTED_MODE=client
|
|
|
22
18
|
GATEWAY_PUBLIC_URL=
|
|
23
19
|
GATEWAY_WS_URL=
|
|
24
20
|
GATEWAY_WS_PATH=/api/gateway/ws
|
|
25
|
-
|
|
21
|
+
GATEWAY_SCOPE_TOKEN=
|
|
26
22
|
GATEWAY_USER_UUID=
|
|
27
23
|
GATEWAY_AUTH_TOKEN=
|
|
28
24
|
|
|
@@ -44,15 +40,6 @@ TERMINAL_PROMPT_SCAN_INTERVAL_SECONDS=15
|
|
|
44
40
|
TERMINAL_PROMPT_SCAN_COOLDOWN_SECONDS=120
|
|
45
41
|
TERMINAL_PROMPT_SCAN_STRATEGY=strict
|
|
46
42
|
TERMINAL_PROMPT_SCAN_MIN_SCORE=5
|
|
47
|
-
WEBAPP_ENABLED=true
|
|
48
|
-
WEBAPP_BASE_PATH=/webapp
|
|
49
|
-
WEBAPP_PUBLIC_URL=
|
|
50
|
-
WEBAPP_INITDATA_TTL_SECONDS=300
|
|
51
|
-
WEBAPP_SESSION_TTL_SECONDS=900
|
|
52
|
-
WEBAPP_LAUNCH_MODE=fullscreen
|
|
53
|
-
WEBAPP_VISIBLE_SCREENS=10
|
|
54
|
-
WEBAPP_ACTION_COOLDOWN_MS=150
|
|
55
|
-
|
|
56
43
|
MCP_XCHANGE_DIR=.mcp-xchange
|
|
57
44
|
|
|
58
45
|
BROWSER_ENABLED=true
|
|
@@ -76,4 +63,4 @@ NODE_ID=agent
|
|
|
76
63
|
LOG_LEVEL=info
|
|
77
64
|
LOG_FILE_ENABLED=false
|
|
78
65
|
LOG_FILE_PATH=.tellymcp/log.jsonl
|
|
79
|
-
|
|
66
|
+
LOGFEED_ENABLED=0
|
|
@@ -15,8 +15,7 @@ REDIS_HOST=127.0.0.1
|
|
|
15
15
|
REDIS_PORT=6379
|
|
16
16
|
REDIS_DB=1
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
PAIR_CODE_TTL_SECONDS=300
|
|
18
|
+
TELEGRAM_REQUEST_MODE=reject
|
|
20
19
|
|
|
21
20
|
MCP_HTTP_HOST=127.0.0.1
|
|
22
21
|
MCP_HTTP_PORT=8787
|
|
@@ -43,7 +42,7 @@ DISTRIBUTED_MODE=gateway
|
|
|
43
42
|
GATEWAY_PUBLIC_URL=
|
|
44
43
|
GATEWAY_WS_URL=
|
|
45
44
|
GATEWAY_WS_PATH=/api/gateway/ws
|
|
46
|
-
|
|
45
|
+
GATEWAY_SCOPE_TOKEN=
|
|
47
46
|
GATEWAY_AUTH_TOKEN=
|
|
48
47
|
|
|
49
48
|
ROOT_PREFIX=/api
|
|
@@ -56,7 +55,7 @@ DB_PORT=5432
|
|
|
56
55
|
DB_USER=
|
|
57
56
|
DB_PASSWORD=
|
|
58
57
|
DB_NAME=
|
|
59
|
-
|
|
58
|
+
DB_SCHEMA=mcp
|
|
60
59
|
|
|
61
60
|
# RMQ_HOST=127.0.0.1
|
|
62
61
|
# RMQ_PORT=5672
|
|
@@ -76,36 +75,12 @@ WEBAPP_ACTION_COOLDOWN_MS=150
|
|
|
76
75
|
|
|
77
76
|
MCP_XCHANGE_DIR=.mcp-xchange
|
|
78
77
|
|
|
79
|
-
TERMINAL_SHELL=bash
|
|
80
|
-
TERMINAL_COLS=120
|
|
81
|
-
TERMINAL_ROWS=40
|
|
82
|
-
TERMINAL_SCROLLBACK_LINES=4000
|
|
83
|
-
|
|
84
|
-
TERMINAL_NUDGE_ENABLED=true
|
|
85
|
-
TERMINAL_NUDGE_DEBOUNCE_SECONDS=10
|
|
86
|
-
TERMINAL_NUDGE_COOLDOWN_SECONDS=30
|
|
87
|
-
TERMINAL_NUDGE_MESSAGE=получи newest telegram_message через list_xchange_records/get_xchange_record, выполни запрос и ответь человеку через notify_telegram; не останавливайся на анализе
|
|
88
|
-
TERMINAL_PARTNER_NUDGE_MESSAGE=получи newest partner_note через list_xchange_records/get_xchange_record, выполни задачу в текущей консоли и обязательно отправь результат через send_partner_note или send_partner_file; только потом mark_xchange_record_read
|
|
89
|
-
TERMINAL_PARTNER_REPLY_NUDGE_MESSAGE=получи newest partner_note через list_xchange_records/get_xchange_record; если newest note имеет kind=reply или не требует ответа, не отправляй новый send_partner_note/send_partner_file без явного нового запроса. Если этот reply завершает задачу от человека, сразу отправь финальный результат в Telegram через notify_telegram или send_file_to_telegram; только потом mark_xchange_record_read
|
|
90
|
-
TERMINAL_CAPTURE_MODE=visible
|
|
91
|
-
TERMINAL_CAPTURE_LINES=300
|
|
92
78
|
TERMINAL_PROMPT_SCAN_ENABLED=false
|
|
93
79
|
TERMINAL_PROMPT_SCAN_INTERVAL_SECONDS=15
|
|
94
80
|
TERMINAL_PROMPT_SCAN_COOLDOWN_SECONDS=120
|
|
95
81
|
TERMINAL_PROMPT_SCAN_STRATEGY=strict
|
|
96
82
|
TERMINAL_PROMPT_SCAN_MIN_SCORE=5
|
|
97
|
-
BROWSER_ENABLED=false
|
|
98
|
-
BROWSER_HEADLESS=false
|
|
99
|
-
BROWSER_DEVTOOLS=false
|
|
100
|
-
# BROWSER_ADDRESS=http://localhost:5173
|
|
101
|
-
BROWSER_TIMEOUT_MS=20000
|
|
102
|
-
BROWSER_MAX_EVENTS=200
|
|
103
|
-
BROWSER_WAIT_UNTIL=load
|
|
104
|
-
# BROWSER_EXECUTABLE_PATH=
|
|
105
|
-
# BROWSER_CHANNEL=chrome
|
|
106
|
-
BROWSER_SLOW_MO_MS=0
|
|
107
|
-
|
|
108
83
|
LOG_LEVEL=info
|
|
109
84
|
LOG_FILE_ENABLED=false
|
|
110
85
|
LOG_FILE_PATH=.tellymcp/log.jsonl
|
|
111
|
-
|
|
86
|
+
LOGFEED_ENABLED=0
|
package/dist/cli.js
CHANGED
|
@@ -16,10 +16,44 @@ const ws_1 = __importDefault(require("ws"));
|
|
|
16
16
|
const codexPluginInstaller_1 = require("./codexPluginInstaller");
|
|
17
17
|
const versionHandshake_1 = require("./services/features/telegram-mcp/src/shared/lib/version/versionHandshake");
|
|
18
18
|
const projectIdentity_1 = require("./services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity");
|
|
19
|
-
const
|
|
19
|
+
const envMigration_1 = require("./envMigration");
|
|
20
|
+
const configureServer_1 = require("./configureServer");
|
|
20
21
|
const distDir = __dirname;
|
|
21
22
|
const packageRoot = node_path_1.default.resolve(distDir, "..");
|
|
22
23
|
const cliPackageVersion = (0, versionHandshake_1.getTellyMcpPackageVersion)(__dirname);
|
|
24
|
+
function nativePtyRecoveryLines() {
|
|
25
|
+
return [
|
|
26
|
+
...(process.platform === "linux"
|
|
27
|
+
? [
|
|
28
|
+
"Install native build prerequisites (Debian/Ubuntu): sudo apt install -y python3 make g++",
|
|
29
|
+
]
|
|
30
|
+
: []),
|
|
31
|
+
"Ensure npm lifecycle scripts are enabled: npm config set ignore-scripts false",
|
|
32
|
+
"Rebuild the global package: npm rebuild -g @deadragdoll/tellymcp --foreground-scripts",
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
async function checkNativePtyRuntime() {
|
|
36
|
+
try {
|
|
37
|
+
const nodePty = await import("node-pty");
|
|
38
|
+
if (typeof nodePty.spawn !== "function") {
|
|
39
|
+
return {
|
|
40
|
+
available: false,
|
|
41
|
+
message: "node-pty loaded without a spawn function.",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return { available: true };
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
48
|
+
return {
|
|
49
|
+
available: false,
|
|
50
|
+
message: message.split("\n", 1)[0] || "node-pty failed to load.",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function isForegroundPtyClientMode(parsed) {
|
|
55
|
+
return (parsed.DISTRIBUTED_MODE || "client").trim() === "client";
|
|
56
|
+
}
|
|
23
57
|
function printBanner(title, subtitle) {
|
|
24
58
|
process.stdout.write(`${picocolors_1.default.bold(picocolors_1.default.cyan("TellyMCP"))} ${picocolors_1.default.bold(picocolors_1.default.white(`v${cliPackageVersion}`))} ${picocolors_1.default.dim(title)}\n`);
|
|
25
59
|
if (subtitle) {
|
|
@@ -66,6 +100,8 @@ function printHelp() {
|
|
|
66
100
|
printBanner("CLI", "Telegram control plane for MCP-connected coding agents");
|
|
67
101
|
printSection("Usage", [
|
|
68
102
|
" tellymcp init <client|gateway|both> [directory]",
|
|
103
|
+
" tellymcp configure [--no-open]",
|
|
104
|
+
" tellymcp migrate-env <input.env> > .migrated-env",
|
|
69
105
|
" tellymcp run [--env <file>]",
|
|
70
106
|
" tellymcp run --env=<file>",
|
|
71
107
|
" tellymcp run --env .env-client -s backendDev",
|
|
@@ -84,6 +120,8 @@ function printHelp() {
|
|
|
84
120
|
printSection("Examples", [
|
|
85
121
|
" tellymcp init client",
|
|
86
122
|
" tellymcp init gateway ./gateway-node",
|
|
123
|
+
" tellymcp configure",
|
|
124
|
+
" tellymcp migrate-env ./old.env > ./new.env",
|
|
87
125
|
" tellymcp run",
|
|
88
126
|
" tellymcp run --env .env.client",
|
|
89
127
|
" tellymcp run --env .env-client -s backendDev",
|
|
@@ -99,7 +137,7 @@ function printHelp() {
|
|
|
99
137
|
" tellymcp oauth key",
|
|
100
138
|
]);
|
|
101
139
|
printSection("terminal", [
|
|
102
|
-
|
|
140
|
+
" built-in PTY runtime (validated by tellymcp doctor and tellymcp run)",
|
|
103
141
|
" Live view, session nudges and browser flows use the built-in terminal runtime.",
|
|
104
142
|
]);
|
|
105
143
|
}
|
|
@@ -110,7 +148,9 @@ function formatMarkerEnvPath(envPath, cwd) {
|
|
|
110
148
|
const resolvedCwd = node_path_1.default.resolve(cwd);
|
|
111
149
|
const resolvedEnvPath = node_path_1.default.resolve(envPath);
|
|
112
150
|
const relativePath = node_path_1.default.relative(resolvedCwd, resolvedEnvPath);
|
|
113
|
-
return relativePath &&
|
|
151
|
+
return relativePath &&
|
|
152
|
+
!relativePath.startsWith("..") &&
|
|
153
|
+
!node_path_1.default.isAbsolute(relativePath)
|
|
114
154
|
? relativePath
|
|
115
155
|
: resolvedEnvPath;
|
|
116
156
|
}
|
|
@@ -157,7 +197,7 @@ function loadCliEnv(args) {
|
|
|
157
197
|
const sessionOverride = explicitSessionOverride ?? marker?.localSessionId ?? null;
|
|
158
198
|
const sessionLabelOverride = explicitSessionOverride
|
|
159
199
|
? explicitSessionOverride
|
|
160
|
-
: marker?.sessionLabel ?? sessionOverride ?? null;
|
|
200
|
+
: (marker?.sessionLabel ?? sessionOverride ?? null);
|
|
161
201
|
if (!(0, node_fs_1.existsSync)(envPath)) {
|
|
162
202
|
fail(`Missing env file: ${envPath}`);
|
|
163
203
|
}
|
|
@@ -263,9 +303,7 @@ function runOAuthCommand(args) {
|
|
|
263
303
|
}
|
|
264
304
|
function printBrowserHelp() {
|
|
265
305
|
printBanner("browser helper", "Manage Playwright browser binaries used by browser_* tools");
|
|
266
|
-
printSection("Usage", [
|
|
267
|
-
" tellymcp browser install",
|
|
268
|
-
]);
|
|
306
|
+
printSection("Usage", [" tellymcp browser install"]);
|
|
269
307
|
printSection("What this command does", [
|
|
270
308
|
" Installs the bundled Playwright Chromium browser.",
|
|
271
309
|
" Uses the Playwright dependency shipped with TellyMCP.",
|
|
@@ -323,12 +361,67 @@ function loadTemplate(mode) {
|
|
|
323
361
|
: "env.both.template";
|
|
324
362
|
const templatePath = node_path_1.default.join(packageRoot, templateName);
|
|
325
363
|
const nestedTemplatePath = node_path_1.default.join(packageRoot, "config", "templates", templateName);
|
|
326
|
-
const resolvedTemplatePath = (0, node_fs_1.existsSync)(templatePath)
|
|
364
|
+
const resolvedTemplatePath = (0, node_fs_1.existsSync)(templatePath)
|
|
365
|
+
? templatePath
|
|
366
|
+
: nestedTemplatePath;
|
|
327
367
|
if (!(0, node_fs_1.existsSync)(resolvedTemplatePath)) {
|
|
328
368
|
fail(`Missing packaged template: ${templateName}`);
|
|
329
369
|
}
|
|
330
370
|
return (0, node_fs_1.readFileSync)(resolvedTemplatePath, "utf8");
|
|
331
371
|
}
|
|
372
|
+
async function runConfigure(args) {
|
|
373
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
374
|
+
printBanner("configure", "Local web configurator for a TellyMCP dotenv file");
|
|
375
|
+
printSection("Usage", [
|
|
376
|
+
" tellymcp configure [--no-open]",
|
|
377
|
+
" tellymcp configure [--port 8790] [--no-open]",
|
|
378
|
+
]);
|
|
379
|
+
printSection("Safety", [
|
|
380
|
+
" The configurator binds only to 127.0.0.1 on a random free port.",
|
|
381
|
+
" Its URL contains a one-time access token.",
|
|
382
|
+
" The browser downloads .env-client or .env-gateway after validation.",
|
|
383
|
+
]);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
387
|
+
const value = args[index];
|
|
388
|
+
if (value === "--no-open" || value?.startsWith("--port=")) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (value === "--port") {
|
|
392
|
+
index += 1;
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
fail("configure does not accept a role or output path; choose Client or Gateway in the browser wizard.");
|
|
396
|
+
}
|
|
397
|
+
const portArg = readFlagValue(args, "--port");
|
|
398
|
+
const port = portArg === null ? 0 : Number(portArg);
|
|
399
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
400
|
+
fail("--port must be an integer between 0 and 65535.");
|
|
401
|
+
}
|
|
402
|
+
printBanner("configure", "Choose Client or Gateway in the local browser wizard");
|
|
403
|
+
await (0, configureServer_1.startConfigureServer)({
|
|
404
|
+
templates: {
|
|
405
|
+
client: loadTemplate("client"),
|
|
406
|
+
gateway: loadTemplate("gateway"),
|
|
407
|
+
},
|
|
408
|
+
port,
|
|
409
|
+
open: !args.includes("--no-open"),
|
|
410
|
+
onListening(url) {
|
|
411
|
+
printSection("Configurator", [
|
|
412
|
+
` ${picocolors_1.default.green("OPEN")} ${url}`,
|
|
413
|
+
" Keep this terminal open until the file is saved.",
|
|
414
|
+
" Press Ctrl+C to cancel.",
|
|
415
|
+
]);
|
|
416
|
+
},
|
|
417
|
+
onDownloaded(filename) {
|
|
418
|
+
printSection("Download", [
|
|
419
|
+
` ${picocolors_1.default.green("OK")} ${filename} sent to the browser`,
|
|
420
|
+
` next: chmod 600 ${filename}`,
|
|
421
|
+
]);
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
}
|
|
332
425
|
function initWorkspace(mode, directoryArg) {
|
|
333
426
|
const targetDir = node_path_1.default.resolve(directoryArg ?? process.cwd());
|
|
334
427
|
(0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
|
|
@@ -354,6 +447,40 @@ function initWorkspace(mode, directoryArg) {
|
|
|
354
447
|
" 3. tellymcp run",
|
|
355
448
|
]);
|
|
356
449
|
}
|
|
450
|
+
function runMigrateEnv(args) {
|
|
451
|
+
const [inputArg, extraArg] = args;
|
|
452
|
+
if (!inputArg || extraArg || inputArg === "--help" || inputArg === "-h") {
|
|
453
|
+
printBanner("migrate-env", "Normalize a legacy TellyMCP environment file");
|
|
454
|
+
printSection("Usage", [
|
|
455
|
+
" tellymcp migrate-env <input.env> > .migrated-env",
|
|
456
|
+
" The role is read from DISTRIBUTED_MODE or inferred from gateway-only keys.",
|
|
457
|
+
" Normalized dotenv is written to stdout; migration notes go to stderr.",
|
|
458
|
+
]);
|
|
459
|
+
if (!inputArg || inputArg === "--help" || inputArg === "-h") {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
fail("migrate-env expects exactly one input env file.");
|
|
463
|
+
}
|
|
464
|
+
const inputPath = node_path_1.default.resolve(process.cwd(), inputArg);
|
|
465
|
+
if (!(0, node_fs_1.existsSync)(inputPath)) {
|
|
466
|
+
fail(`Missing input env file: ${inputPath}`);
|
|
467
|
+
}
|
|
468
|
+
const result = (0, envMigration_1.migrateEnvironmentContent)((0, node_fs_1.readFileSync)(inputPath, "utf8"));
|
|
469
|
+
process.stdout.write(result.content);
|
|
470
|
+
const notes = [
|
|
471
|
+
`migrate-env: role=${result.role}`,
|
|
472
|
+
`migrate-env: kept ${result.keptKeys.length} keys from ${inputPath}`,
|
|
473
|
+
];
|
|
474
|
+
if (result.renamedKeys.length > 0) {
|
|
475
|
+
notes.push(`migrate-env: renamed ${result.renamedKeys
|
|
476
|
+
.map(({ from, to }) => `${from}->${to}`)
|
|
477
|
+
.join(", ")}`);
|
|
478
|
+
}
|
|
479
|
+
if (result.droppedKeys.length > 0) {
|
|
480
|
+
notes.push(`migrate-env: dropped ${result.droppedKeys.join(", ")}`);
|
|
481
|
+
}
|
|
482
|
+
process.stderr.write(`${notes.join("\n")}\n`);
|
|
483
|
+
}
|
|
357
484
|
function resolveRunEnvPath(args) {
|
|
358
485
|
const [firstArg, secondArg] = args;
|
|
359
486
|
const marker = getSessionMarkerForCwd(process.cwd());
|
|
@@ -424,9 +551,7 @@ function readFlagValue(args, flagName) {
|
|
|
424
551
|
return null;
|
|
425
552
|
}
|
|
426
553
|
function printMcpConfig(args) {
|
|
427
|
-
if (args.length === 0 ||
|
|
428
|
-
args.includes("--help") ||
|
|
429
|
-
args.includes("-h")) {
|
|
554
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
430
555
|
printMcpHelp();
|
|
431
556
|
return;
|
|
432
557
|
}
|
|
@@ -554,11 +679,18 @@ async function checkWebSocketUrl(url, timeoutMs = 3000) {
|
|
|
554
679
|
}
|
|
555
680
|
async function runDoctor(args) {
|
|
556
681
|
const { envPath, parsed } = loadCliEnv(args);
|
|
682
|
+
const nativePtyStatus = await checkNativePtyRuntime();
|
|
557
683
|
printBanner("doctor", "Local installation diagnostics");
|
|
558
684
|
printSection("terminal", [
|
|
559
|
-
|
|
685
|
+
nativePtyStatus.available
|
|
686
|
+
? `${picocolors_1.default.green(" OK")} built-in PTY runtime: native module loaded`
|
|
687
|
+
: `${picocolors_1.default.red(" ERROR")} built-in PTY runtime: ${nativePtyStatus.message}`,
|
|
688
|
+
` platform: ${process.platform}-${process.arch}, Node ${process.versions.node}`,
|
|
560
689
|
` shell: ${parsed.TERMINAL_SHELL?.trim() || process.env.SHELL || "bash"}`,
|
|
561
690
|
` size: ${parsed.TERMINAL_COLS?.trim() || "120"}x${parsed.TERMINAL_ROWS?.trim() || "40"}`,
|
|
691
|
+
...(!nativePtyStatus.available
|
|
692
|
+
? nativePtyRecoveryLines().map((line) => `${picocolors_1.default.yellow(" ACTION")} ${line}`)
|
|
693
|
+
: []),
|
|
562
694
|
]);
|
|
563
695
|
const mode = (parsed.DISTRIBUTED_MODE || "client").trim();
|
|
564
696
|
const httpHost = (parsed.MCP_HTTP_HOST || "0.0.0.0").trim();
|
|
@@ -617,10 +749,15 @@ async function runDoctor(args) {
|
|
|
617
749
|
checks.push(`${picocolors_1.default.red(" ERROR")} playwright chromium: ${playwrightStatus.message}`);
|
|
618
750
|
capabilities.push(`${picocolors_1.default.red(" ERROR")} browser tools: browsers are not installed`);
|
|
619
751
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
752
|
+
if (mode === "client") {
|
|
753
|
+
checks.push(`${picocolors_1.default.green(" OK")} local state: process-local (Redis is not required)`);
|
|
754
|
+
}
|
|
755
|
+
else {
|
|
756
|
+
const redisHost = (parsed.REDIS_HOST || "127.0.0.1").trim();
|
|
757
|
+
const redisPort = Number(parsed.REDIS_PORT || 6379);
|
|
758
|
+
const redisCheck = await checkTcpPort(redisHost, redisPort);
|
|
759
|
+
checks.push(`${redisCheck.ok ? picocolors_1.default.green(" OK") : picocolors_1.default.red(" ERROR")} redis: ${redisCheck.message}`);
|
|
760
|
+
}
|
|
624
761
|
if (mode === "client") {
|
|
625
762
|
const gatewayPublicUrl = parsed.GATEWAY_PUBLIC_URL?.trim();
|
|
626
763
|
if (gatewayPublicUrl) {
|
|
@@ -720,9 +857,12 @@ async function runDoctor(args) {
|
|
|
720
857
|
printSection("notes", notes);
|
|
721
858
|
}
|
|
722
859
|
else {
|
|
723
|
-
printSection("notes", [
|
|
860
|
+
printSection("notes", [
|
|
861
|
+
`${picocolors_1.default.green(" OK")} No obvious local config issues detected.`,
|
|
862
|
+
]);
|
|
724
863
|
}
|
|
725
|
-
if (browserEnabled &&
|
|
864
|
+
if (browserEnabled &&
|
|
865
|
+
(!playwrightStatus.enabled || !playwrightStatus.installed)) {
|
|
726
866
|
printSection("playwright", [
|
|
727
867
|
`${picocolors_1.default.yellow(" ACTION")} Install browser binaries before using browser_* tools:`,
|
|
728
868
|
" tellymcp browser install",
|
|
@@ -742,7 +882,9 @@ function normalizeExtensionFlavor(rawValue) {
|
|
|
742
882
|
return null;
|
|
743
883
|
}
|
|
744
884
|
function getBundledExtensionDir(flavor) {
|
|
745
|
-
return node_path_1.default.join(packageRoot, "packages", flavor === "firefox"
|
|
885
|
+
return node_path_1.default.join(packageRoot, "packages", flavor === "firefox"
|
|
886
|
+
? "firefox-attach-extension"
|
|
887
|
+
: "chrome-attach-extension", "dist");
|
|
746
888
|
}
|
|
747
889
|
function getDefaultExtensionTargetDir(flavor) {
|
|
748
890
|
return node_path_1.default.resolve(process.cwd(), flavor === "firefox" ? "tellymcp-firefox-attach" : "tellymcp-chrome-attach");
|
|
@@ -783,7 +925,7 @@ async function runSystemPrune(args) {
|
|
|
783
925
|
const dbUser = parsed.DB_USER?.trim();
|
|
784
926
|
const dbPassword = parsed.DB_PASSWORD?.trim();
|
|
785
927
|
const dbName = parsed.DB_NAME?.trim();
|
|
786
|
-
const dbSchema = (parsed.
|
|
928
|
+
const dbSchema = (parsed.DB_SCHEMA || "mcp").trim();
|
|
787
929
|
const xchangeDir = node_path_1.default.resolve(process.cwd(), parsed.MCP_XCHANGE_DIR || ".mcp-xchange");
|
|
788
930
|
const sessionMarkerPath = node_path_1.default.resolve(process.cwd(), ".mcpsession.json");
|
|
789
931
|
const sqliteDbPath = node_path_1.default.join(xchangeDir, "xchange.sqlite3");
|
|
@@ -791,35 +933,39 @@ async function runSystemPrune(args) {
|
|
|
791
933
|
printSection("Target", [
|
|
792
934
|
` env: ${envPath}`,
|
|
793
935
|
` mode: ${mode}`,
|
|
794
|
-
|
|
936
|
+
...(mode === "client"
|
|
937
|
+
? [` state: process-local (Redis skipped)`]
|
|
938
|
+
: [` redis: ${redisHost}:${redisPort}/${redisDb}`]),
|
|
795
939
|
...(dbHost && dbUser && dbName
|
|
796
940
|
? [` postgres: ${dbHost}:${dbPort}/${dbName} schema ${dbSchema}`]
|
|
797
941
|
: [` postgres: ${picocolors_1.default.dim("skipped (not configured)")}`]),
|
|
798
942
|
` xchange dir: ${xchangeDir}`,
|
|
799
943
|
` session marker: ${sessionMarkerPath}`,
|
|
800
944
|
]);
|
|
801
|
-
const redis = new ioredis_1.default({
|
|
802
|
-
host: redisHost,
|
|
803
|
-
port: redisPort,
|
|
804
|
-
db: redisDb,
|
|
805
|
-
...(redisUsername ? { username: redisUsername } : {}),
|
|
806
|
-
...(redisPassword ? { password: redisPassword } : {}),
|
|
807
|
-
maxRetriesPerRequest: 1,
|
|
808
|
-
enableReadyCheck: true,
|
|
809
|
-
});
|
|
810
945
|
let deletedRedisKeys = 0;
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
946
|
+
if (mode !== "client") {
|
|
947
|
+
const redis = new ioredis_1.default({
|
|
948
|
+
host: redisHost,
|
|
949
|
+
port: redisPort,
|
|
950
|
+
db: redisDb,
|
|
951
|
+
...(redisUsername ? { username: redisUsername } : {}),
|
|
952
|
+
...(redisPassword ? { password: redisPassword } : {}),
|
|
953
|
+
maxRetriesPerRequest: 1,
|
|
954
|
+
enableReadyCheck: true,
|
|
955
|
+
});
|
|
956
|
+
try {
|
|
957
|
+
let cursor = "0";
|
|
958
|
+
do {
|
|
959
|
+
const [nextCursor, keys] = await redis.scan(cursor, "MATCH", "telegram-mcp:*", "COUNT", 500);
|
|
960
|
+
cursor = nextCursor;
|
|
961
|
+
if (keys.length > 0) {
|
|
962
|
+
deletedRedisKeys += await redis.del(...keys);
|
|
963
|
+
}
|
|
964
|
+
} while (cursor !== "0");
|
|
965
|
+
}
|
|
966
|
+
finally {
|
|
967
|
+
redis.disconnect();
|
|
968
|
+
}
|
|
823
969
|
}
|
|
824
970
|
let truncatedTables = [];
|
|
825
971
|
if (dbHost && dbUser && dbName) {
|
|
@@ -1013,8 +1159,19 @@ async function runRuntime(args) {
|
|
|
1013
1159
|
sessionId: parsed.TELLYMCP_SESSION_ID,
|
|
1014
1160
|
sessionLabel: parsed.TELLYMCP_SESSION_LABEL,
|
|
1015
1161
|
});
|
|
1016
|
-
|
|
1017
|
-
|
|
1162
|
+
const nativePtyStatus = await checkNativePtyRuntime();
|
|
1163
|
+
if (!nativePtyStatus.available) {
|
|
1164
|
+
fail([
|
|
1165
|
+
`Built-in PTY runtime is unavailable on ${process.platform}-${process.arch} with Node ${process.versions.node}.`,
|
|
1166
|
+
nativePtyStatus.message,
|
|
1167
|
+
"",
|
|
1168
|
+
...nativePtyRecoveryLines(),
|
|
1169
|
+
"Then rerun: tellymcp doctor --env <file>",
|
|
1170
|
+
].join("\n"));
|
|
1171
|
+
}
|
|
1172
|
+
if (isForegroundPtyClientMode(parsed)) {
|
|
1173
|
+
const { runForegroundPtyRuntime } = await import("./services/features/telegram-mcp/src/features/foreground-terminal/model/foregroundTerminalRuntime.js");
|
|
1174
|
+
await runForegroundPtyRuntime({
|
|
1018
1175
|
envPath,
|
|
1019
1176
|
packageRoot,
|
|
1020
1177
|
printBanner,
|
|
@@ -1068,11 +1225,24 @@ async function runRuntime(args) {
|
|
|
1068
1225
|
}
|
|
1069
1226
|
async function main(argv) {
|
|
1070
1227
|
const [rawCommand, firstArg, secondArg] = argv;
|
|
1071
|
-
const command = rawCommand === "init" ||
|
|
1072
|
-
|
|
1228
|
+
const command = rawCommand === "init" ||
|
|
1229
|
+
rawCommand === "configure" ||
|
|
1230
|
+
rawCommand === "migrate-env" ||
|
|
1231
|
+
rawCommand === "run" ||
|
|
1232
|
+
rawCommand === "help" ||
|
|
1233
|
+
rawCommand === "mcp" ||
|
|
1234
|
+
rawCommand === "oauth" ||
|
|
1235
|
+
rawCommand === "doctor" ||
|
|
1236
|
+
rawCommand === "browser" ||
|
|
1237
|
+
rawCommand === "system-prune" ||
|
|
1238
|
+
rawCommand === "codex-plugin" ||
|
|
1239
|
+
rawCommand === "extension"
|
|
1073
1240
|
? rawCommand
|
|
1074
1241
|
: "help";
|
|
1075
|
-
if (command === "help" ||
|
|
1242
|
+
if (command === "help" ||
|
|
1243
|
+
!rawCommand ||
|
|
1244
|
+
rawCommand === "--help" ||
|
|
1245
|
+
rawCommand === "-h") {
|
|
1076
1246
|
printHelp();
|
|
1077
1247
|
return;
|
|
1078
1248
|
}
|
|
@@ -1080,6 +1250,14 @@ async function main(argv) {
|
|
|
1080
1250
|
initWorkspace(ensureMode(firstArg), secondArg);
|
|
1081
1251
|
return;
|
|
1082
1252
|
}
|
|
1253
|
+
if (command === "configure") {
|
|
1254
|
+
await runConfigure(argv.slice(1));
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
if (command === "migrate-env") {
|
|
1258
|
+
runMigrateEnv(argv.slice(1));
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1083
1261
|
if (command === "mcp") {
|
|
1084
1262
|
printMcpConfig(argv.slice(1));
|
|
1085
1263
|
return;
|