@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.
Files changed (44) hide show
  1. package/.env.example.client +19 -39
  2. package/.env.example.gateway +40 -64
  3. package/CHANGELOG.md +27 -0
  4. package/README-ru.md +66 -6
  5. package/README.md +66 -6
  6. package/TOOLS.md +38 -1
  7. package/config/templates/env.both.template +4 -5
  8. package/config/templates/env.client.template +4 -17
  9. package/config/templates/env.gateway.template +4 -29
  10. package/dist/cli.js +225 -47
  11. package/dist/configureServer.js +966 -0
  12. package/dist/envMigration.js +316 -0
  13. package/dist/moleculer.config.js +1 -3
  14. package/dist/services/features/telegram-mcp/approval.service.js +1 -1
  15. package/dist/services/features/telegram-mcp/collaboration.service.js +2 -2
  16. package/dist/services/features/telegram-mcp/ensuredb.service.js +1 -1
  17. package/dist/services/features/telegram-mcp/gateway.service.js +1 -1
  18. package/dist/services/features/telegram-mcp/mcp-server.service.js +2 -0
  19. package/dist/services/features/telegram-mcp/session-context.service.js +25 -1
  20. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +70 -66
  21. package/dist/services/features/telegram-mcp/src/app/config/env.js +10 -36
  22. package/dist/services/features/telegram-mcp/src/app/config/environmentContract.js +66 -0
  23. package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +28 -2
  24. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +2 -2
  25. package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +5 -5
  26. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +1 -1
  27. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +4 -4
  28. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +0 -1
  29. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +4 -3
  30. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +4 -4
  31. package/dist/services/features/telegram-mcp/src/features/session-context/model/getRuntimeDiagnosticsTool.js +30 -0
  32. package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +169 -7
  33. package/dist/services/features/telegram-mcp/src/shared/integrations/memory/processLocalStateStore.js +260 -0
  34. package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +1 -1
  35. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +1 -1
  36. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConsoleRegistry.js +2 -2
  37. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMessageFlow.js +1 -1
  38. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectState.js +2 -2
  39. package/dist/services/features/telegram-mcp/src/shared/lib/gatewayScope.js +5 -5
  40. package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +10 -0
  41. package/docs/STANDALONE-ru.md +29 -4
  42. package/docs/STANDALONE.md +29 -4
  43. package/package.json +1 -1
  44. package/scripts/postinstall.js +33 -1
@@ -0,0 +1,316 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.migrateEnvironmentContent = migrateEnvironmentContent;
4
+ const dotenv_1 = require("dotenv");
5
+ const environmentContract_1 = require("./services/features/telegram-mcp/src/app/config/environmentContract");
6
+ const allRoles = ["client", "gateway", "both"];
7
+ const gatewayRoles = ["gateway", "both"];
8
+ const clientRoles = ["client", "both"];
9
+ const environmentSections = [
10
+ {
11
+ title: "Runtime role and request policy",
12
+ roles: allRoles,
13
+ keys: ["DISTRIBUTED_MODE", "TELEGRAM_REQUEST_MODE"],
14
+ },
15
+ {
16
+ title: "Workspace identity",
17
+ roles: clientRoles,
18
+ keys: [
19
+ "PROJECT_NAME",
20
+ "TELLYMCP_SESSION_ID",
21
+ "TELLYMCP_SESSION_LABEL",
22
+ "GATEWAY_USER_UUID",
23
+ ],
24
+ },
25
+ {
26
+ title: "Gateway connection and scope",
27
+ roles: allRoles,
28
+ keys: [
29
+ "GATEWAY_PUBLIC_URL",
30
+ "GATEWAY_WS_URL",
31
+ "GATEWAY_WS_PATH",
32
+ "GATEWAY_SCOPE_TOKEN",
33
+ "GATEWAY_AUTH_TOKEN",
34
+ ],
35
+ },
36
+ {
37
+ title: "Telegram gateway",
38
+ roles: gatewayRoles,
39
+ keys: [
40
+ "TELEGRAM_BOT_TOKEN",
41
+ "TELEGRAM_BOT_USERNAME",
42
+ "ADMIN_TOKEN",
43
+ "DEBUG_LANGUAGE",
44
+ "TELEGRAM_POLL_INTERVAL_MS",
45
+ "TELEGRAM_DEFAULT_TIMEOUT_SECONDS",
46
+ "TELEGRAM_MAX_CONTEXT_CHARS",
47
+ "TELEGRAM_MAX_QUESTION_CHARS",
48
+ "TELEGRAM_MAX_MESSAGE_CHARS",
49
+ "TELEGRAM_MENU_PAYLOAD_TTL_SECONDS",
50
+ "TELEGRAM_WEBHOOK_ENABLED",
51
+ "TELEGRAM_WEBHOOK_PATH",
52
+ "TELEGRAM_WEBHOOK_PUBLIC_URL",
53
+ "TELEGRAM_WEBHOOK_SECRET",
54
+ "TELEGRAM_WEBHOOK_TRACE",
55
+ "TELEGRAM_WEBHOOK_DROP_PENDING_UPDATES",
56
+ ],
57
+ },
58
+ {
59
+ title: "Redis",
60
+ roles: gatewayRoles,
61
+ keys: [
62
+ "REDIS_HOST",
63
+ "REDIS_PORT",
64
+ "REDIS_DB",
65
+ "REDIS_USERNAME",
66
+ "REDIS_PASSWORD",
67
+ ],
68
+ },
69
+ {
70
+ title: "PostgreSQL gateway metadata",
71
+ roles: gatewayRoles,
72
+ keys: [
73
+ "DB_HOST",
74
+ "DB_PORT",
75
+ "DB_USER",
76
+ "DB_PASSWORD",
77
+ "DB_NAME",
78
+ "DB_SCHEMA",
79
+ ],
80
+ },
81
+ {
82
+ title: "Standalone HTTP and MCP",
83
+ roles: allRoles,
84
+ keys: [
85
+ "ROOT_PREFIX",
86
+ "PORT",
87
+ "MCP_HTTP_HOST",
88
+ "MCP_HTTP_PORT",
89
+ "MCP_HTTP_PATH",
90
+ "MCP_HTTP_BEARER_TOKEN",
91
+ "MCP_HTTP_ENABLE_DEBUG_ROUTES",
92
+ "MCP_HTTP_ENABLE_PRUNE_ROUTE",
93
+ "MCP_XCHANGE_DIR",
94
+ ],
95
+ },
96
+ {
97
+ title: "Chat connector OAuth",
98
+ roles: gatewayRoles,
99
+ keys: [
100
+ "TELLYMCP_PUBLIC_URL",
101
+ "TELLYMCP_OAUTH_ISSUER",
102
+ "TELLYMCP_OAUTH_AUDIENCE",
103
+ "TELLYMCP_MAGIC_TOKEN",
104
+ "TELLYMCP_MAGIC_TOKEN_HASH",
105
+ "TELLYMCP_OAUTH_CLIENT_ID",
106
+ "TELLYMCP_OAUTH_CLIENT_SECRET",
107
+ "TELLYMCP_ALLOWED_REDIRECT_URIS",
108
+ "TELLYMCP_OAUTH_PRIVATE_KEY_PEM",
109
+ "TELLYMCP_AUTH_CODE_TTL_SECONDS",
110
+ "TELLYMCP_OAUTH_SCOPES",
111
+ "TELLYMCP_OAUTH_KEY_ID",
112
+ ],
113
+ },
114
+ {
115
+ title: "RabbitMQ fanout",
116
+ roles: gatewayRoles,
117
+ keys: [
118
+ "RMQ_HOST",
119
+ "RMQ_PORT",
120
+ "RMQ_USER",
121
+ "RMQ_PASSWORD",
122
+ "RMQ_VHOST",
123
+ "RMQ_EXCHANGE",
124
+ ],
125
+ },
126
+ {
127
+ title: "Telegram Mini App",
128
+ roles: gatewayRoles,
129
+ keys: [
130
+ "WEBAPP_ENABLED",
131
+ "WEBAPP_BASE_PATH",
132
+ "WEBAPP_PUBLIC_URL",
133
+ "WEBAPP_INITDATA_TTL_SECONDS",
134
+ "WEBAPP_SESSION_TTL_SECONDS",
135
+ "WEBAPP_LAUNCH_MODE",
136
+ "WEBAPP_VISIBLE_SCREENS",
137
+ "WEBAPP_ACTION_COOLDOWN_MS",
138
+ ],
139
+ },
140
+ {
141
+ title: "Built-in PTY terminal",
142
+ roles: clientRoles,
143
+ keys: [
144
+ "TERMINAL_SHELL",
145
+ "TERMINAL_COLS",
146
+ "TERMINAL_ROWS",
147
+ "TERMINAL_SCROLLBACK_LINES",
148
+ "TERMINAL_NUDGE_ENABLED",
149
+ "TERMINAL_NUDGE_DEBOUNCE_SECONDS",
150
+ "TERMINAL_NUDGE_COOLDOWN_SECONDS",
151
+ "TERMINAL_NUDGE_MESSAGE",
152
+ "TERMINAL_PARTNER_NUDGE_MESSAGE",
153
+ "TERMINAL_PARTNER_REPLY_NUDGE_MESSAGE",
154
+ "TERMINAL_CAPTURE_MODE",
155
+ "TERMINAL_CAPTURE_LINES",
156
+ "TERMINAL_PROMPT_SCAN_ENABLED",
157
+ "TERMINAL_PROMPT_SCAN_INTERVAL_SECONDS",
158
+ "TERMINAL_PROMPT_SCAN_COOLDOWN_SECONDS",
159
+ "TERMINAL_PROMPT_SCAN_STRATEGY",
160
+ "TERMINAL_PROMPT_SCAN_MIN_SCORE",
161
+ ],
162
+ },
163
+ {
164
+ title: "Gateway-side prompt detection",
165
+ roles: ["gateway"],
166
+ keys: [
167
+ "TERMINAL_PROMPT_SCAN_ENABLED",
168
+ "TERMINAL_PROMPT_SCAN_INTERVAL_SECONDS",
169
+ "TERMINAL_PROMPT_SCAN_COOLDOWN_SECONDS",
170
+ "TERMINAL_PROMPT_SCAN_STRATEGY",
171
+ "TERMINAL_PROMPT_SCAN_MIN_SCORE",
172
+ ],
173
+ },
174
+ {
175
+ title: "Browser automation",
176
+ roles: clientRoles,
177
+ keys: [
178
+ "BROWSER_ENABLED",
179
+ "BROWSER_HEADLESS",
180
+ "BROWSER_DEVTOOLS",
181
+ "BROWSER_ADDRESS",
182
+ "BROWSER_TIMEOUT_MS",
183
+ "BROWSER_MAX_EVENTS",
184
+ "BROWSER_WAIT_UNTIL",
185
+ "BROWSER_EXECUTABLE_PATH",
186
+ "BROWSER_CHANNEL",
187
+ "BROWSER_SLOW_MO_MS",
188
+ "BROWSER_ATTACH_ENABLED",
189
+ "BROWSER_ATTACH_WS_HOST",
190
+ "BROWSER_ATTACH_WS_PORT",
191
+ "BROWSER_ATTACH_WS_PATH",
192
+ ],
193
+ },
194
+ {
195
+ title: "Outbound proxy",
196
+ roles: allRoles,
197
+ keys: ["PROXY_USE", "HTTP_PROXY", "SOCKS5_PROXY", "NO_PROXY"],
198
+ },
199
+ {
200
+ title: "Moleculer identity and diagnostics",
201
+ roles: allRoles,
202
+ keys: [
203
+ "NAMESPACE",
204
+ "NODE_ID",
205
+ "TRANSPORT",
206
+ "MOLECULER_TRACE",
207
+ "MOLECULER_METRICS",
208
+ "METRICS_PORT",
209
+ "METRICS_PATH",
210
+ ],
211
+ },
212
+ {
213
+ title: "Logging",
214
+ roles: allRoles,
215
+ keys: [
216
+ "LOG_LEVEL",
217
+ "LOG_STDERR_LEVEL",
218
+ "LOG_FILE_ENABLED",
219
+ "LOG_FILE_LEVEL",
220
+ "LOG_FILE_PATH",
221
+ "LOGFEED_ENABLED",
222
+ "LOGFEED_LEVEL",
223
+ "LOGFEED_BUFFER_SIZE",
224
+ ],
225
+ },
226
+ ];
227
+ function inferRole(environment) {
228
+ const configuredMode = environment.DISTRIBUTED_MODE?.trim();
229
+ if (configuredMode === "client" ||
230
+ configuredMode === "gateway" ||
231
+ configuredMode === "both") {
232
+ return configuredMode;
233
+ }
234
+ if (configuredMode) {
235
+ throw new Error(`DISTRIBUTED_MODE must be client, gateway, or both; received ${configuredMode}.`);
236
+ }
237
+ return environment.TELEGRAM_BOT_TOKEN ||
238
+ environment.DB_HOST ||
239
+ environment.ROOT_PREFIX ||
240
+ environment.PORT
241
+ ? "gateway"
242
+ : "client";
243
+ }
244
+ function formatEnvironmentValue(value) {
245
+ if (/^[A-Za-z0-9_./:@%+,?&=-]*$/u.test(value)) {
246
+ return value;
247
+ }
248
+ return JSON.stringify(value);
249
+ }
250
+ function migrateEnvironmentContent(source) {
251
+ const parsed = (0, dotenv_1.parse)(source);
252
+ const normalized = { ...parsed };
253
+ const renamedKeys = [];
254
+ const handledLegacyKeys = new Set();
255
+ for (const [from, to] of Object.entries(environmentContract_1.LEGACY_ENV_RENAMES)) {
256
+ if (!(from in parsed)) {
257
+ continue;
258
+ }
259
+ if (!(to in parsed)) {
260
+ normalized[to] = parsed[from] ?? "";
261
+ }
262
+ delete normalized[from];
263
+ handledLegacyKeys.add(from);
264
+ renamedKeys.push({ from, to });
265
+ }
266
+ for (const [name, value] of Object.entries(parsed)) {
267
+ if (!name.startsWith("TMUX_")) {
268
+ continue;
269
+ }
270
+ const replacement = (0, environmentContract_1.getTmuxReplacement)(name);
271
+ if (replacement && !(replacement in parsed)) {
272
+ normalized[replacement] = value;
273
+ renamedKeys.push({ from: name, to: replacement });
274
+ }
275
+ delete normalized[name];
276
+ handledLegacyKeys.add(name);
277
+ }
278
+ for (const name of environmentContract_1.REMOVED_ENV_KEYS) {
279
+ delete normalized[name];
280
+ }
281
+ const role = inferRole(normalized);
282
+ normalized.DISTRIBUTED_MODE = role;
283
+ const emitted = new Set();
284
+ const keptKeys = [];
285
+ const output = [
286
+ "# Generated by tellymcp migrate-env.",
287
+ `# Role: ${role}`,
288
+ "",
289
+ ];
290
+ for (const section of environmentSections) {
291
+ if (!section.roles.includes(role)) {
292
+ continue;
293
+ }
294
+ const sectionKeys = section.keys.filter((key) => key in normalized && !emitted.has(key));
295
+ if (sectionKeys.length === 0) {
296
+ continue;
297
+ }
298
+ output.push(`# ${section.title}`);
299
+ for (const key of sectionKeys) {
300
+ output.push(`${key}=${formatEnvironmentValue(normalized[key] ?? "")}`);
301
+ emitted.add(key);
302
+ keptKeys.push(key);
303
+ }
304
+ output.push("");
305
+ }
306
+ const droppedKeys = Object.keys(parsed)
307
+ .filter((key) => !emitted.has(key) && !handledLegacyKeys.has(key))
308
+ .sort();
309
+ return {
310
+ role,
311
+ content: `${output.join("\n").trimEnd()}\n`,
312
+ keptKeys,
313
+ renamedKeys,
314
+ droppedKeys,
315
+ };
316
+ }
@@ -67,9 +67,7 @@ const logger = [
67
67
  const metricsEnabled = process.env.MOLECULER_METRICS === "true";
68
68
  const metricsPort = +(process.env.METRICS_PORT || 3030);
69
69
  const metricsPath = process.env.METRICS_PATH || "/metrics";
70
- const logFeedEnabled = process.env.ENABLE_LOGFEED != null
71
- ? !["0", "false", "no", "off"].includes(process.env.ENABLE_LOGFEED.toLowerCase())
72
- : process.env.LOGFEED_ENABLED !== "false";
70
+ const logFeedEnabled = !["0", "false", "no", "off"].includes((process.env.LOGFEED_ENABLED ?? "true").toLowerCase());
73
71
  if (logFeedEnabled) {
74
72
  logger.push(new logfeed_1.LogFeedLogger({
75
73
  level: process.env.LOGFEED_LEVEL || process.env.LOG_LEVEL || "info",
@@ -26,7 +26,7 @@ const TelegramMcpApprovalService = {
26
26
  }
27
27
  const runtime = await runtimeService.waitUntilReady();
28
28
  this.logger.info("Starting telegram_mcp approval service");
29
- this.approvalOrchestrator = new orchestrator_1.HumanApprovalOrchestrator(runtime.config, runtime.stateStore, runtime.stateStore, runtime.stateStore, runtime.telegramTransport, runtime.logger, runtime.projectIdentityResolver);
29
+ this.approvalOrchestrator = new orchestrator_1.HumanApprovalOrchestrator(runtime.config, runtime.sessionStore, runtime.stateStore, runtime.stateStore, runtime.telegramTransport, runtime.logger, runtime.projectIdentityResolver);
30
30
  this.logger.info("telegram_mcp approval service is ready");
31
31
  },
32
32
  };
@@ -78,11 +78,11 @@ const TelegramMcpCollaborationService = {
78
78
  return localBackend.sendPartnerNote(input, resolved);
79
79
  });
80
80
  const backend = runtime.config.distributed.gatewayPublicUrl
81
- ? new gatewayCollaborationBackend_1.GatewayCollaborationBackend(runtime.logger, runtime.stateStore, runtime.config.distributed.gatewayPublicUrl, runtime.config.distributed.gatewayAuthToken, runtime.config.distributed.gatewayToken, runtime.config.distributed.gatewayUserUuid, runtime.config.project.name, runtime.config.telegram.botUsername)
81
+ ? new gatewayCollaborationBackend_1.GatewayCollaborationBackend(runtime.logger, runtime.stateStore, runtime.config.distributed.gatewayPublicUrl, runtime.config.distributed.gatewayAuthToken, runtime.config.distributed.gatewayScopeToken, runtime.config.distributed.gatewayUserUuid, runtime.config.project.name, runtime.config.telegram.botUsername)
82
82
  : localBackend;
83
83
  this.collaborationService = new collaborationService_1.CollaborationService(backend, runtime.logger, runtime.projectIdentityResolver);
84
84
  this.sendPartnerFileService = new sendPartnerFileService_1.SendPartnerFileService(runtime.config, runtime.sessionStore, runtime.stateStore, runtime.logger, runtime.projectIdentityResolver, this.collaborationService, new remoteConsoleActionClient_1.RemoteConsoleActionClient((actionName, params) => this.broker.call(actionName, params, { meta: { internal_call: true } })));
85
- this.gatewaySessionsService = new gatewaySessionsService_1.GatewaySessionsService(runtime.logger, runtime.stateStore, runtime.config.distributed.gatewayPublicUrl, runtime.config.distributed.gatewayAuthToken, runtime.config.distributed.gatewayToken, runtime.config.distributed.gatewayUserUuid, runtime.config.project.name, runtime.config.telegram.botUsername);
85
+ this.gatewaySessionsService = new gatewaySessionsService_1.GatewaySessionsService(runtime.logger, runtime.stateStore, runtime.config.distributed.gatewayPublicUrl, runtime.config.distributed.gatewayAuthToken, runtime.config.distributed.gatewayScopeToken, runtime.config.distributed.gatewayUserUuid, runtime.config.project.name, runtime.config.telegram.botUsername);
86
86
  runtime.telegramTransport.setCollaborationService(this.collaborationService);
87
87
  this.logger.info("telegram_mcp collaboration service is ready");
88
88
  },
@@ -5,7 +5,7 @@ const db_1 = require("../../../lib/mixins/db");
5
5
  exports.TELEGRAM_MCP_ENSUREDB_SERVICE_NAME = "telegramMcp.ensuredb";
6
6
  const DISTRIBUTED_MODE = process.env.DISTRIBUTED_MODE || "client";
7
7
  const GATEWAY_ENABLED = DISTRIBUTED_MODE === "gateway" || DISTRIBUTED_MODE === "both";
8
- const MCP_SCHEMA = process.env.DB_SCHEME || "mcp";
8
+ const MCP_SCHEMA = process.env.DB_SCHEMA || "mcp";
9
9
  const TelegramMcpEnsureDbService = {
10
10
  name: exports.TELEGRAM_MCP_ENSUREDB_SERVICE_NAME,
11
11
  mixins: [db_1.DBMixin],
@@ -11,7 +11,7 @@ const gatewayReplyResolution_1 = require("./src/features/distributed-gateway/mod
11
11
  const gatewayScope_1 = require("./src/shared/lib/gatewayScope");
12
12
  const ensuredb_service_1 = require("./ensuredb.service");
13
13
  exports.TELEGRAM_MCP_GATEWAY_SERVICE_NAME = "telegramMcp.gateway";
14
- const MCP_SCHEMA = process.env.DB_SCHEME || "mcp";
14
+ const MCP_SCHEMA = process.env.DB_SCHEMA || "mcp";
15
15
  const DISTRIBUTED_MODE = process.env.DISTRIBUTED_MODE || "client";
16
16
  const GATEWAY_ENABLED = DISTRIBUTED_MODE === "gateway" || DISTRIBUTED_MODE === "both";
17
17
  function trimOptionalText(value) {
@@ -43,6 +43,7 @@ const getFileListTool_1 = require("./src/features/file-content/model/getFileList
43
43
  const sendFileToTelegramTool_1 = require("./src/features/notify/model/sendFileToTelegramTool");
44
44
  const notifyTelegramTool_1 = require("./src/features/notify/model/notifyTelegramTool");
45
45
  const clearSessionContextTool_1 = require("./src/features/session-context/model/clearSessionContextTool");
46
+ const getRuntimeDiagnosticsTool_1 = require("./src/features/session-context/model/getRuntimeDiagnosticsTool");
46
47
  const getSessionContextTool_1 = require("./src/features/session-context/model/getSessionContextTool");
47
48
  const renameSessionTool_1 = require("./src/features/session-context/model/renameSessionTool");
48
49
  const setSessionContextTool_1 = require("./src/features/session-context/model/setSessionContextTool");
@@ -87,6 +88,7 @@ const TelegramMcpMcpServerService = {
87
88
  new setSessionContextTool_1.SetSessionContextTool(sessionContextService.getSessionContextService()),
88
89
  new renameSessionTool_1.RenameSessionTool(sessionContextService.getSessionContextService()),
89
90
  new getSessionContextTool_1.GetSessionContextTool(sessionContextService.getSessionContextService()),
91
+ new getRuntimeDiagnosticsTool_1.GetRuntimeDiagnosticsTool(sessionContextService.getSessionContextService()),
90
92
  new clearSessionContextTool_1.ClearSessionContextTool(sessionContextService.getSessionContextService()),
91
93
  new notifyTelegramTool_1.NotifyTelegramTool(notifyService.getNotifyService()),
92
94
  new sendFileToTelegramTool_1.SendFileToTelegramTool(notifyService.getNotifyService()),
@@ -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, new remoteConsoleActionClient_1.RemoteConsoleActionClient((actionName, params) => this.broker.call(actionName, params, { meta: { internal_call: true } })));
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,6 +8,7 @@ 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");
@@ -22,11 +23,14 @@ async function createAppRuntime(input) {
22
23
  const projectIdentityResolver = new projectIdentity_1.ProjectIdentityResolver(config, logger);
23
24
  logger.info("Configuration loaded", {
24
25
  mode: config.mode,
25
- redis: {
26
- host: config.redis.host,
27
- port: config.redis.port,
28
- db: config.redis.db,
29
- },
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
+ },
30
34
  logging: {
31
35
  level: config.logging.level,
32
36
  },
@@ -42,13 +46,9 @@ async function createAppRuntime(input) {
42
46
  distributed: {
43
47
  mode: config.distributed.mode,
44
48
  gatewayPublicUrlConfigured: Boolean(config.distributed.gatewayPublicUrl),
45
- gatewayBindHost: config.distributed.gatewayBindHost,
46
- gatewayBindPort: config.distributed.gatewayBindPort,
47
49
  gatewayWsUrlConfigured: Boolean(config.distributed.gatewayWsUrl),
48
50
  gatewayWsPath: config.distributed.gatewayWsPath,
49
51
  gatewayAuthEnabled: Boolean(config.distributed.gatewayAuthToken),
50
- gatewayDatabaseConfigured: Boolean(config.distributed.gatewayDatabaseUrl),
51
- gatewayS3Configured: Boolean(config.distributed.gatewayS3Bucket),
52
52
  gatewayRmqConfigured: Boolean(config.distributed.rmq?.host),
53
53
  },
54
54
  webapp: {
@@ -82,81 +82,85 @@ async function createAppRuntime(input) {
82
82
  },
83
83
  project: projectIdentityResolver.getIdentity(),
84
84
  });
85
- const redis = await (0, client_1.createRedisClient)(config);
86
- logger.info("Redis connected", {
87
- host: config.redis.host,
88
- port: config.redis.port,
89
- db: config.redis.db,
90
- });
91
- const stateStore = new stateStore_1.RedisStateStore(redis);
92
- let sessionStore = stateStore;
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
+ }
93
128
  const webAppLaunchRegistry = new auth_1.WebAppLaunchRegistry();
94
- const objectStore = new minioExchangeStore_1.MinioExchangeStore(input.callBroker, stateStore, config.terminal, config.exchange.dir, config.mcp.vfsScope, logger, config.distributed.mode, config.distributed.gatewayPublicUrl, config.distributed.gatewayAuthToken);
129
+ const objectStore = new minioExchangeStore_1.MinioExchangeStore(config.terminal, config.exchange.dir, logger);
95
130
  if (config.distributed.mode === "client") {
96
131
  const resolvedSession = projectIdentityResolver.resolveSessionDefaults({
97
132
  cwd: process.cwd(),
98
133
  });
99
- const existingSession = await stateStore.getSession(resolvedSession.sessionId);
100
134
  const persistedToolsState = (0, projectIdentity_1.readSessionMarkerState)(resolvedSession.cwd, logger);
101
135
  const terminalTarget = (0, client_2.ensureTerminalTargetForSession)(config.terminal, {
102
136
  sessionId: resolvedSession.sessionId,
103
137
  cwd: resolvedSession.cwd,
104
- ...(typeof existingSession?.terminalTarget === "string"
105
- ? { target: existingSession.terminalTarget }
106
- : {}),
107
138
  });
108
139
  if (!terminalTarget) {
109
140
  throw new Error("PTY terminal target could not be created during runtime bootstrap");
110
141
  }
111
142
  const initialSession = {
112
143
  sessionId: resolvedSession.sessionId,
113
- ...(typeof existingSession?.label === "string"
114
- ? { label: existingSession.label }
115
- : { label: resolvedSession.sessionLabel }),
116
- ...(typeof existingSession?.cwd === "string"
117
- ? { cwd: existingSession.cwd }
118
- : { cwd: resolvedSession.cwd }),
119
- ...(typeof existingSession?.activeProjectUuid === "string"
120
- ? { activeProjectUuid: existingSession.activeProjectUuid }
121
- : {}),
122
- ...(typeof existingSession?.activeProjectName === "string"
123
- ? { activeProjectName: existingSession.activeProjectName }
124
- : {}),
125
- ...(typeof existingSession?.task === "string"
126
- ? { task: existingSession.task }
127
- : {}),
128
- ...(typeof existingSession?.summary === "string"
129
- ? { summary: existingSession.summary }
130
- : {}),
131
- ...(Array.isArray(existingSession?.files)
132
- ? { files: existingSession.files }
133
- : {}),
134
- ...(Array.isArray(existingSession?.decisions)
135
- ? { decisions: existingSession.decisions }
136
- : {}),
137
- ...(Array.isArray(existingSession?.risks)
138
- ? { risks: existingSession.risks }
139
- : {}),
144
+ label: resolvedSession.sessionLabel,
145
+ cwd: resolvedSession.cwd,
140
146
  terminalTarget: terminalTarget,
141
- ...(typeof existingSession?.lastTerminalNudgeAt === "string"
142
- ? { lastTerminalNudgeAt: existingSession.lastTerminalNudgeAt }
147
+ ...(typeof persistedToolsState?.lastSeenToolsHash === "string"
148
+ ? { lastSeenToolsHash: persistedToolsState.lastSeenToolsHash }
149
+ : {}),
150
+ ...(typeof persistedToolsState?.lastNotifiedToolsHash === "string"
151
+ ? { lastNotifiedToolsHash: persistedToolsState.lastNotifiedToolsHash }
143
152
  : {}),
144
- ...(typeof existingSession?.lastSeenToolsHash === "string"
145
- ? { lastSeenToolsHash: existingSession.lastSeenToolsHash }
146
- : typeof persistedToolsState?.lastSeenToolsHash === "string"
147
- ? { lastSeenToolsHash: persistedToolsState.lastSeenToolsHash }
148
- : {}),
149
- ...(typeof existingSession?.lastNotifiedToolsHash === "string"
150
- ? { lastNotifiedToolsHash: existingSession.lastNotifiedToolsHash }
151
- : typeof persistedToolsState?.lastNotifiedToolsHash === "string"
152
- ? { lastNotifiedToolsHash: persistedToolsState.lastNotifiedToolsHash }
153
- : {}),
154
153
  updatedAt: new Date().toISOString(),
155
154
  };
156
155
  sessionStore = new processLocalSessionStore_1.ProcessLocalSessionStore({
157
156
  initialSessions: [initialSession],
158
157
  onClearSession: async (sessionId) => {
159
- await stateStore.clearSession(sessionId);
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
+ }
160
164
  },
161
165
  });
162
166
  logger.info("Client PTY process-local session store initialized", {
@@ -175,8 +179,8 @@ async function createAppRuntime(input) {
175
179
  : {}),
176
180
  ...(config.project.name ? { projectName: config.project.name } : {}),
177
181
  ...(config.telegram.botUsername ? { botUsername: config.telegram.botUsername } : {}),
178
- ...(config.distributed.gatewayToken
179
- ? { gatewayToken: config.distributed.gatewayToken }
182
+ ...(config.distributed.gatewayScopeToken
183
+ ? { gatewayScopeToken: config.distributed.gatewayScopeToken }
180
184
  : {}),
181
185
  ...(config.distributed.gatewayUserUuid
182
186
  ? { gatewayUserUuid: config.distributed.gatewayUserUuid }
@@ -216,7 +220,7 @@ async function createAppRuntime(input) {
216
220
  ? new temporaryFileLinkStore_1.TemporaryFileLinkStore(config.distributed.gatewayPublicUrl, logger)
217
221
  : null;
218
222
  await temporaryFileLinkStore?.start();
219
- const firefoxAttachServer = new firefoxAttachServer_1.FirefoxAttachServer(config, logger, stateStore, stateStore);
223
+ const firefoxAttachServer = new firefoxAttachServer_1.FirefoxAttachServer(config, logger, sessionStore, stateStore);
220
224
  await firefoxAttachServer.start();
221
225
  return {
222
226
  callBroker: input.callBroker,
@@ -243,7 +247,7 @@ async function createAppRuntime(input) {
243
247
  await firefoxAttachServer.stop();
244
248
  await telegramTransport.stop();
245
249
  (0, ptyRegistry_1.stopAllPtyTargets)();
246
- redis.disconnect();
250
+ redis?.disconnect();
247
251
  logger.info("Shutdown completed");
248
252
  },
249
253
  };