@deadragdoll/tellymcp 0.0.10 → 0.0.11

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 (153) hide show
  1. package/.env.example.client +42 -52
  2. package/.env.example.gateway +48 -62
  3. package/CHANGELOG.md +3 -3
  4. package/README-ru.md +205 -384
  5. package/README.md +195 -1194
  6. package/TOOLS.md +294 -377
  7. package/VERSION.md +11 -11
  8. package/config/codex/plugins/telly-workflows/.codex-plugin/plugin.json +18 -0
  9. package/config/codex/plugins/telly-workflows/references/invariants.md +10 -0
  10. package/config/codex/plugins/telly-workflows/skills/telly-browser-screenshot/SKILL.md +27 -0
  11. package/config/codex/plugins/telly-workflows/skills/telly-collab-artifact/SKILL.md +22 -0
  12. package/config/codex/plugins/telly-workflows/skills/telly-human-telegram/SKILL.md +31 -0
  13. package/config/codex/plugins/telly-workflows/skills/telly-partner-note/SKILL.md +36 -0
  14. package/config/templates/env.both.template +39 -20
  15. package/config/templates/env.client.template +34 -19
  16. package/config/templates/env.gateway.template +37 -22
  17. package/dist/cli.js +322 -75
  18. package/dist/codexPluginInstaller.js +215 -0
  19. package/dist/lib/mixins/session.errors.js +34 -1
  20. package/dist/lib/pinoTargets.js +2 -2
  21. package/dist/moleculer.config.js +7 -5
  22. package/dist/services/features/telegram-mcp/browser.service.js +94 -1
  23. package/dist/services/features/telegram-mcp/collaboration.service.js +40 -3
  24. package/dist/services/features/telegram-mcp/ensuredb.service.js +145 -26
  25. package/dist/services/features/telegram-mcp/gateway-delivery.service.js +285 -103
  26. package/dist/services/features/telegram-mcp/gateway-socket.service.js +897 -85
  27. package/dist/services/features/telegram-mcp/gateway.service.js +876 -81
  28. package/dist/services/features/telegram-mcp/mcp-http.service.js +8 -0
  29. package/dist/services/features/telegram-mcp/mcp-server.service.js +17 -26
  30. package/dist/services/features/telegram-mcp/notify.service.js +127 -1
  31. package/dist/services/features/telegram-mcp/session-context.service.js +28 -1
  32. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +132 -10
  33. package/dist/services/features/telegram-mcp/src/app/config/env.js +158 -52
  34. package/dist/services/features/telegram-mcp/src/app/http.js +375 -42
  35. package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +386 -58
  36. package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +3 -0
  37. package/dist/services/features/telegram-mcp/src/app/webapp/terminal.js +12 -0
  38. package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +116 -104
  39. package/dist/services/features/telegram-mcp/src/entities/xchange/model/types.js +2 -0
  40. package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +1 -1
  41. package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
  42. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +249 -19
  43. package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +71 -0
  44. package/dist/services/features/telegram-mcp/src/features/collaboration/model/listGatewaySessionsTool.js +33 -0
  45. package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +93 -82
  46. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +47 -5
  47. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +1 -1
  48. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +1 -1
  49. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +82 -0
  50. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +22 -14
  51. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +649 -75
  52. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +76 -0
  53. package/dist/services/features/telegram-mcp/src/features/embedded-runtime/model/embeddedRuntimeBroker.js +92 -0
  54. package/dist/services/features/telegram-mcp/src/features/foreground-terminal/model/foregroundTerminalRuntime.js +192 -0
  55. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +382 -3
  56. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +1 -1
  57. package/dist/services/features/telegram-mcp/src/features/notify/model/sendFileToTelegramTool.js +33 -0
  58. package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +1 -1
  59. package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +1 -1
  60. package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +1 -1
  61. package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +42 -200
  62. package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +1 -1
  63. package/dist/services/features/telegram-mcp/src/features/terminal-buffer/model/terminalBufferService.js +96 -0
  64. package/dist/services/features/telegram-mcp/src/features/terminal-input/model/terminalInputService.js +97 -0
  65. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +107 -58
  66. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +1 -1
  67. package/dist/services/features/telegram-mcp/src/features/xchange/model/getXchangeRecordTool.js +28 -0
  68. package/dist/services/features/telegram-mcp/src/features/xchange/model/listXchangeRecordsTool.js +28 -0
  69. package/dist/services/features/telegram-mcp/src/features/xchange/model/markXchangeRecordReadTool.js +28 -0
  70. package/dist/services/features/telegram-mcp/src/features/xchange/model/xchangeService.js +169 -0
  71. package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +5 -4
  72. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/en.js +139 -42
  73. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/ru.js +135 -38
  74. package/dist/services/features/telegram-mcp/src/shared/integrations/memory/processLocalSessionStore.js +27 -0
  75. package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +11 -8
  76. package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +42 -71
  77. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +21 -22
  78. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +415 -7101
  79. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportAttachmentStore.js +93 -0
  80. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportBroadcastActions.js +385 -0
  81. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConsoleRegistry.js +143 -0
  82. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConstructorWiring.js +633 -0
  83. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContent.js +84 -0
  84. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContext.js +78 -0
  85. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportDocumentActions.js +36 -0
  86. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportEventActions.js +292 -0
  87. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +352 -0
  88. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFormatting.js +75 -0
  89. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportGatewayActions.js +44 -0
  90. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLifecycleActions.js +161 -0
  91. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLive.js +56 -0
  92. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLiveActions.js +77 -0
  93. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuCallbacks.js +254 -0
  94. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFactories.js +538 -0
  95. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFingerprints.js +93 -0
  96. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFlow.js +344 -0
  97. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuShell.js +62 -0
  98. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuState.js +408 -0
  99. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuText.js +216 -0
  100. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMessageFlow.js +452 -0
  101. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportOutputActions.js +189 -0
  102. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPartnerActions.js +286 -0
  103. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPayloadState.js +101 -0
  104. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectActions.js +463 -0
  105. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEntryActions.js +202 -0
  106. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEvents.js +99 -0
  107. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectMenus.js +138 -0
  108. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectState.js +308 -0
  109. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectView.js +426 -0
  110. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportRequestFlow.js +278 -0
  111. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportSessionActions.js +143 -0
  112. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalActions.js +468 -0
  113. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalRuntime.js +171 -0
  114. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTypes.js +2 -0
  115. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportUtils.js +330 -0
  116. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportXchangeState.js +107 -0
  117. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +255 -0
  118. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +543 -0
  119. package/dist/services/features/telegram-mcp/src/shared/integrations/xchange/sqliteRecordStore.js +223 -0
  120. package/dist/services/features/telegram-mcp/src/shared/lib/gatewayScope.js +24 -0
  121. package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +6 -0
  122. package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +147 -76
  123. package/dist/services/features/telegram-mcp/src/shared/lib/telegramXchangeRecords.js +72 -0
  124. package/dist/services/features/telegram-mcp/src/shared/lib/terminalPromptDetection.js +237 -0
  125. package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +129 -1
  126. package/dist/services/features/telegram-mcp/src/shared/lib/xchangeRecordHints.js +98 -0
  127. package/dist/services/features/telegram-mcp/standalone-http.service.js +12 -0
  128. package/dist/services/features/telegram-mcp/terminal-buffer.service.js +42 -0
  129. package/dist/services/features/telegram-mcp/terminal-input.service.js +41 -0
  130. package/dist/services/features/telegram-mcp/tools-sync.service.js +15 -1
  131. package/dist/services/features/telegram-mcp/xchange.service.js +123 -0
  132. package/docs/STANDALONE-ru.md +172 -0
  133. package/docs/STANDALONE.md +172 -0
  134. package/package.json +10 -5
  135. package/scripts/build-package-artifact.sh +27 -0
  136. package/scripts/deploy-gateway.sh +64 -0
  137. package/scripts/deploy-onebot-branch.sh +27 -0
  138. package/scripts/postinstall.js +11 -36
  139. package/STANDALONE-ru.md +0 -274
  140. package/STANDALONE.md +0 -274
  141. package/dist/services/features/telegram-mcp/inbox.service.js +0 -33
  142. package/dist/services/features/telegram-mcp/pair.service.js +0 -33
  143. package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +0 -10
  144. package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +0 -33
  145. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +0 -33
  146. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +0 -33
  147. package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +0 -77
  148. package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +0 -33
  149. package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +0 -33
  150. package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +0 -202
  151. package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +0 -33
  152. package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +0 -33
  153. package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +0 -363
@@ -4,6 +4,8 @@ exports.GatewayHttpService = void 0;
4
4
  const node_fs_1 = require("node:fs");
5
5
  const node_path_1 = require("node:path");
6
6
  const schema_1 = require("../../../entities/request/model/schema");
7
+ const relay_1 = require("../../../app/webapp/relay");
8
+ const versionHandshake_1 = require("../../../shared/lib/version/versionHandshake");
7
9
  function readHeader(req, headerName) {
8
10
  const value = req.headers[headerName];
9
11
  return Array.isArray(value) ? value[0] : value;
@@ -18,6 +20,28 @@ function writeText(res, statusCode, message) {
18
20
  res.setHeader("content-type", "text/plain; charset=utf-8");
19
21
  res.end(message);
20
22
  }
23
+ function isBackendErrorLike(value) {
24
+ return Boolean(value &&
25
+ typeof value === "object" &&
26
+ typeof value.statusCode === "number" &&
27
+ typeof value.code === "string");
28
+ }
29
+ function parseCanonicalGatewaySessionId(value) {
30
+ const trimmed = value?.trim();
31
+ if (!trimmed) {
32
+ return null;
33
+ }
34
+ const separatorIndex = trimmed.indexOf(":");
35
+ if (separatorIndex <= 0 || separatorIndex === trimmed.length - 1) {
36
+ return null;
37
+ }
38
+ const clientUuid = trimmed.slice(0, separatorIndex).trim();
39
+ const localSessionId = trimmed.slice(separatorIndex + 1).trim();
40
+ if (!clientUuid || !localSessionId) {
41
+ return null;
42
+ }
43
+ return { clientUuid, localSessionId };
44
+ }
21
45
  function unwrapLiveRelayResult(response) {
22
46
  if (!response || typeof response !== "object") {
23
47
  return null;
@@ -48,50 +72,20 @@ function normalizeLiveRelayBootstrapResult(response) {
48
72
  return {
49
73
  session_id: sessionId,
50
74
  session_label: typeof record.session_label === "string" ? record.session_label : null,
51
- tmux_target: record.tmux_target === true,
75
+ terminal_target: record.terminal_target === true,
52
76
  poll_interval_ms: typeof record.poll_interval_ms === "number" && record.poll_interval_ms > 0
53
77
  ? record.poll_interval_ms
54
78
  : 2000,
55
79
  telegram_user_id: telegramUserId,
56
80
  };
57
81
  }
58
- function buildPartnerNoteOutputFallback(input, rawOutput) {
59
- const outputRecord = rawOutput && typeof rawOutput === "object"
60
- ? rawOutput
61
- : {};
62
- return {
63
- session_id: typeof outputRecord.session_id === "string"
64
- ? outputRecord.session_id
65
- : input.session_id ?? "unknown-session",
66
- partner_session_id: typeof outputRecord.partner_session_id === "string"
67
- ? outputRecord.partner_session_id
68
- : input.target_session_id ?? "unknown-partner-session",
69
- kind: typeof outputRecord.kind === "string"
70
- ? outputRecord.kind
71
- : input.kind,
72
- share_id: typeof outputRecord.share_id === "string"
73
- ? outputRecord.share_id
74
- : `gateway-${Date.now()}`,
75
- delivery_status: outputRecord.delivery_status === "delivered" ? "delivered" : "queued",
76
- note_path: typeof outputRecord.note_path === "string"
77
- ? outputRecord.note_path
78
- : "gateway://shares/pending.md",
79
- share_index_path: typeof outputRecord.share_index_path === "string"
80
- ? outputRecord.share_index_path
81
- : "gateway://SHARED_INDEX.md",
82
- copied_artifacts: Array.isArray(outputRecord.copied_artifacts)
83
- ? outputRecord.copied_artifacts.filter((item) => typeof item === "string")
84
- : [
85
- ...(input.artifact_refs?.map((item) => item.original_name ?? item.relative_path ?? item.file_path) ?? []),
86
- ...(input.artifacts ?? []),
87
- ],
88
- inbox_message_id: typeof outputRecord.inbox_message_id === "string"
89
- ? outputRecord.inbox_message_id
90
- : `gateway-${Date.now()}`,
91
- requires_reply: typeof outputRecord.requires_reply === "boolean"
92
- ? outputRecord.requires_reply
93
- : Boolean(input.requires_reply ?? (input.kind === "question" || input.kind === "request")),
94
- };
82
+ function slugifyGatewayFilenamePart(value) {
83
+ return value
84
+ .trim()
85
+ .toLowerCase()
86
+ .replace(/[^a-z0-9._-]+/gu, "-")
87
+ .replace(/-+/gu, "-")
88
+ .replace(/^-|-$/gu, "");
95
89
  }
96
90
  class GatewayHttpService {
97
91
  config;
@@ -207,6 +201,27 @@ class GatewayHttpService {
207
201
  }
208
202
  return fallback;
209
203
  }
204
+ async resolveConnectedConsoleTarget(sessionId) {
205
+ const relayTarget = (0, relay_1.parseLiveRelaySessionId)(sessionId);
206
+ if (relayTarget) {
207
+ return {
208
+ clientUuid: relayTarget.clientUuid,
209
+ localSessionId: relayTarget.localSessionId,
210
+ };
211
+ }
212
+ const trimmedSessionId = sessionId.trim();
213
+ if (!trimmedSessionId) {
214
+ throw new Error("relay or canonical session_id is required");
215
+ }
216
+ const resolved = await this.callBroker("telegramMcp.gatewaySocket.resolveConnectedSessionTarget", { sessionId: trimmedSessionId }, { meta: { internal_call: true } });
217
+ if (!resolved) {
218
+ throw new Error(`Could not resolve live console target for session_id '${trimmedSessionId}'.`);
219
+ }
220
+ return {
221
+ clientUuid: resolved.client_uuid,
222
+ localSessionId: resolved.local_session_id,
223
+ };
224
+ }
210
225
  async readJsonBody(req) {
211
226
  const knownBody = req.body;
212
227
  if (knownBody !== undefined) {
@@ -258,7 +273,11 @@ class GatewayHttpService {
258
273
  return true;
259
274
  }
260
275
  try {
261
- const toolsPath = (0, node_path_1.join)(process.cwd(), "TOOLS.md");
276
+ const packageRoot = (0, versionHandshake_1.getTellyMcpPackageRoot)(__dirname);
277
+ if (!packageRoot) {
278
+ throw new Error("Could not resolve installed package root for TOOLS.md.");
279
+ }
280
+ const toolsPath = (0, node_path_1.join)(packageRoot, "TOOLS.md");
262
281
  res.statusCode = 200;
263
282
  res.setHeader("content-type", "text/markdown; charset=utf-8");
264
283
  res.end((0, node_fs_1.readFileSync)(toolsPath, "utf8"));
@@ -279,16 +298,90 @@ class GatewayHttpService {
279
298
  try {
280
299
  const body = await this.readJsonBody(req);
281
300
  const input = schema_1.sendPartnerNoteInputSchema.parse(body);
282
- const useQueuedGatewayDelivery = typeof body?.client_uuid === "string" &&
301
+ const canonicalSource = parseCanonicalGatewaySessionId(input.session_id);
302
+ const relaySource = (0, relay_1.parseLiveRelaySessionId)(input.session_id);
303
+ const resolvedSourceClientUuid = canonicalSource?.clientUuid ||
304
+ relaySource?.clientUuid ||
305
+ (typeof body?.client_uuid === "string"
306
+ ? String(body.client_uuid).trim()
307
+ : "");
308
+ const resolvedSourceLocalSessionId = canonicalSource?.localSessionId ||
309
+ relaySource?.localSessionId ||
310
+ input.session_id?.trim() ||
311
+ "";
312
+ const explicitTargetClientUuid = typeof body?.target_client_uuid ===
313
+ "string"
314
+ ? String(body.target_client_uuid).trim()
315
+ : "";
316
+ const explicitTargetLocalSessionId = typeof body
317
+ ?.target_local_session_id === "string"
318
+ ? String(body.target_local_session_id).trim()
319
+ : "";
320
+ const canonicalTarget = parseCanonicalGatewaySessionId(input.target_session_id);
321
+ const resolvedTargetClientUuid = explicitTargetClientUuid || canonicalTarget?.clientUuid || "";
322
+ const resolvedTargetLocalSessionId = explicitTargetLocalSessionId || canonicalTarget?.localSessionId || "";
323
+ const useDirectGatewayDelivery = Boolean(resolvedSourceClientUuid) &&
324
+ Boolean(resolvedSourceLocalSessionId) &&
325
+ Boolean(resolvedTargetClientUuid) &&
326
+ Boolean(resolvedTargetLocalSessionId);
327
+ const useQueuedGatewayDelivery = !useDirectGatewayDelivery &&
328
+ Boolean(resolvedSourceClientUuid) &&
329
+ Boolean(resolvedSourceLocalSessionId) &&
283
330
  typeof input.target_session_id === "string" &&
284
331
  input.target_session_id.trim().length > 0;
285
- const output = useQueuedGatewayDelivery
286
- ? await this.callBroker("telegramMcp.gateway.sendPartnerNote", body, { meta: { internal_call: true } })
287
- : this.partnerNoteRelayHandler
288
- ? await this.partnerNoteRelayHandler(input)
289
- : (() => {
290
- throw new Error("Gateway partner relay handler is not configured.");
291
- })();
332
+ const output = useDirectGatewayDelivery
333
+ ? await this.callBroker("telegramMcp.gatewaySocket.sendDirectPartnerNote", {
334
+ clientUuid: resolvedSourceClientUuid,
335
+ localSessionId: resolvedSourceLocalSessionId,
336
+ targetClientUuid: resolvedTargetClientUuid,
337
+ targetLocalSessionId: resolvedTargetLocalSessionId,
338
+ kind: input.kind,
339
+ summary: input.summary,
340
+ message: input.message,
341
+ ...(input.expected_reply?.trim()
342
+ ? { expectedReply: input.expected_reply.trim() }
343
+ : {}),
344
+ ...(typeof input.requires_reply === "boolean"
345
+ ? { requiresReply: input.requires_reply }
346
+ : {}),
347
+ ...(input.in_reply_to?.trim()
348
+ ? { inReplyTo: input.in_reply_to.trim() }
349
+ : {}),
350
+ ...(Array.isArray(input.artifact_refs)
351
+ ? { artifactRefs: input.artifact_refs }
352
+ : {}),
353
+ }, { meta: { internal_call: true } })
354
+ : useQueuedGatewayDelivery
355
+ ? await this.callBroker("telegramMcp.gateway.sendPartnerNote", {
356
+ ...body,
357
+ client_uuid: resolvedSourceClientUuid,
358
+ session_id: resolvedSourceLocalSessionId,
359
+ }, { meta: { internal_call: true } })
360
+ : this.partnerNoteRelayHandler
361
+ ? await this.partnerNoteRelayHandler(input)
362
+ : (() => {
363
+ throw new Error("Gateway partner relay handler is not configured.");
364
+ })();
365
+ if (isBackendErrorLike(output)) {
366
+ const detail = typeof output.data !== "undefined"
367
+ ? (() => {
368
+ try {
369
+ return JSON.stringify(output.data);
370
+ }
371
+ catch {
372
+ return String(output.data);
373
+ }
374
+ })()
375
+ : "";
376
+ throw new Error([
377
+ typeof output.message === "string" && output.message.trim()
378
+ ? output.message.trim()
379
+ : `${output.name ?? "BackendError"} (${output.code})`,
380
+ `code=${output.code}`,
381
+ `statusCode=${output.statusCode}`,
382
+ ...(detail ? [`data=${detail}`] : []),
383
+ ].join("\n"));
384
+ }
292
385
  if (useQueuedGatewayDelivery &&
293
386
  output &&
294
387
  typeof output === "object" &&
@@ -309,22 +402,22 @@ class GatewayHttpService {
309
402
  }
310
403
  const parsedOutput = schema_1.sendPartnerNoteOutputSchema.safeParse(output);
311
404
  if (!parsedOutput.success) {
312
- if (useQueuedGatewayDelivery) {
313
- writeJson(res, 500, {
314
- error: "Invalid queued gateway partner-note response",
315
- details: parsedOutput.error.issues,
316
- output,
317
- });
318
- return true;
319
- }
320
- const fallback = buildPartnerNoteOutputFallback(input, output);
321
- writeJson(res, 200, fallback);
405
+ writeJson(res, 500, {
406
+ error: useQueuedGatewayDelivery
407
+ ? "Invalid queued gateway partner-note response"
408
+ : "Invalid direct gateway partner-note response",
409
+ details: parsedOutput.error.issues,
410
+ output,
411
+ });
322
412
  return true;
323
413
  }
324
414
  writeJson(res, 200, parsedOutput.data);
325
415
  return true;
326
416
  }
327
417
  catch (error) {
418
+ console.error("Gateway partner-note request failed", {
419
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
420
+ });
328
421
  writeJson(res, 400, {
329
422
  error: error instanceof Error ? error.message : String(error),
330
423
  });
@@ -354,6 +447,111 @@ class GatewayHttpService {
354
447
  return true;
355
448
  }
356
449
  catch (error) {
450
+ console.error("Gateway live approval request failed", {
451
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
452
+ });
453
+ writeJson(res, 400, {
454
+ error: error instanceof Error ? error.message : String(error),
455
+ });
456
+ return true;
457
+ }
458
+ }
459
+ if (pathname === "/gateway/storage/list") {
460
+ if (req.method !== "POST") {
461
+ writeText(res, 405, "Method not allowed");
462
+ return true;
463
+ }
464
+ try {
465
+ const body = (await this.readJsonBody(req));
466
+ const sessionId = typeof body.session_id === "string" ? body.session_id.trim() : "";
467
+ const source = typeof body.source === "string" ? body.source.trim() : "";
468
+ const target = await this.resolveConnectedConsoleTarget(sessionId);
469
+ const output = await this.callBroker("telegramMcp.gatewaySocket.requestClientAction", {
470
+ clientUuid: target.clientUuid,
471
+ actionName: "telegramMcp.xchange.listFileMetasRemote",
472
+ params: {
473
+ session_id: target.localSessionId,
474
+ ...(source ? { source } : {}),
475
+ },
476
+ }, { meta: { internal_call: true } });
477
+ if (isBackendErrorLike(output)) {
478
+ throw new Error(this.extractActionErrorMessage(output, "Storage list failed"));
479
+ }
480
+ writeJson(res, 200, output);
481
+ return true;
482
+ }
483
+ catch (error) {
484
+ console.error("Gateway storage list request failed", {
485
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
486
+ });
487
+ writeJson(res, 400, {
488
+ error: error instanceof Error ? error.message : String(error),
489
+ });
490
+ return true;
491
+ }
492
+ }
493
+ if (pathname === "/gateway/storage/meta") {
494
+ if (req.method !== "POST") {
495
+ writeText(res, 405, "Method not allowed");
496
+ return true;
497
+ }
498
+ try {
499
+ const body = (await this.readJsonBody(req));
500
+ const sessionId = typeof body.session_id === "string" ? body.session_id.trim() : "";
501
+ const filePath = typeof body.file_path === "string" ? body.file_path.trim() : "";
502
+ const target = await this.resolveConnectedConsoleTarget(sessionId);
503
+ const output = await this.callBroker("telegramMcp.gatewaySocket.requestClientAction", {
504
+ clientUuid: target.clientUuid,
505
+ actionName: "telegramMcp.xchange.getFileMetaRemote",
506
+ params: {
507
+ session_id: target.localSessionId,
508
+ file_path: filePath,
509
+ },
510
+ }, { meta: { internal_call: true } });
511
+ if (isBackendErrorLike(output)) {
512
+ throw new Error(this.extractActionErrorMessage(output, "Storage meta fetch failed"));
513
+ }
514
+ writeJson(res, 200, output);
515
+ return true;
516
+ }
517
+ catch (error) {
518
+ console.error("Gateway storage meta request failed", {
519
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
520
+ });
521
+ writeJson(res, 400, {
522
+ error: error instanceof Error ? error.message : String(error),
523
+ });
524
+ return true;
525
+ }
526
+ }
527
+ if (pathname === "/gateway/storage/delete-meta") {
528
+ if (req.method !== "POST") {
529
+ writeText(res, 405, "Method not allowed");
530
+ return true;
531
+ }
532
+ try {
533
+ const body = (await this.readJsonBody(req));
534
+ const sessionId = typeof body.session_id === "string" ? body.session_id.trim() : "";
535
+ const filePath = typeof body.file_path === "string" ? body.file_path.trim() : "";
536
+ const target = await this.resolveConnectedConsoleTarget(sessionId);
537
+ const output = await this.callBroker("telegramMcp.gatewaySocket.requestClientAction", {
538
+ clientUuid: target.clientUuid,
539
+ actionName: "telegramMcp.xchange.deleteFileMetaRemote",
540
+ params: {
541
+ session_id: target.localSessionId,
542
+ file_path: filePath,
543
+ },
544
+ }, { meta: { internal_call: true } });
545
+ if (isBackendErrorLike(output)) {
546
+ throw new Error(this.extractActionErrorMessage(output, "Storage meta delete failed"));
547
+ }
548
+ writeJson(res, 200, output);
549
+ return true;
550
+ }
551
+ catch (error) {
552
+ console.error("Gateway storage delete-meta request failed", {
553
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
554
+ });
357
555
  writeJson(res, 400, {
358
556
  error: error instanceof Error ? error.message : String(error),
359
557
  });
@@ -385,12 +583,99 @@ class GatewayHttpService {
385
583
  return true;
386
584
  }
387
585
  catch (error) {
586
+ console.error("Gateway live approval resolution failed", {
587
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
588
+ });
388
589
  writeJson(res, 400, {
389
590
  error: error instanceof Error ? error.message : String(error),
390
591
  });
391
592
  return true;
392
593
  }
393
594
  }
595
+ if (pathname === "/gateway/live/capture-buffer") {
596
+ if (req.method !== "POST") {
597
+ writeText(res, 405, "Method not allowed");
598
+ return true;
599
+ }
600
+ try {
601
+ const body = (await this.readJsonBody(req));
602
+ const sessionId = typeof body.session_id === "string" ? body.session_id.trim() : "";
603
+ const relayTarget = (0, relay_1.parseLiveRelaySessionId)(sessionId);
604
+ const scope = body.scope && typeof body.scope === "object"
605
+ ? body.scope
606
+ : null;
607
+ if (!relayTarget || !scope) {
608
+ writeJson(res, 400, {
609
+ error: "relay session_id and scope are required",
610
+ });
611
+ return true;
612
+ }
613
+ if (scope.mode === "visible") {
614
+ const rawResponse = await this.callBroker("telegramMcp.gatewaySocket.requestLiveRelay", {
615
+ clientUuid: relayTarget.clientUuid,
616
+ localSessionId: relayTarget.localSessionId,
617
+ requestType: "view",
618
+ payload: {},
619
+ }, { meta: { internal_call: true } });
620
+ const response = unwrapLiveRelayResult(rawResponse);
621
+ if (!response ||
622
+ typeof response !== "object" ||
623
+ typeof response.content !== "string") {
624
+ throw new Error("Invalid live relay view response");
625
+ }
626
+ const capturedAt = new Date().toISOString();
627
+ const titleBase = typeof response.session_label === "string" && response.session_label.trim()
628
+ ? response.session_label.trim()
629
+ : relayTarget.localSessionId;
630
+ const filenameBase = slugifyGatewayFilenamePart(titleBase) || "session-buffer";
631
+ const timestamp = capturedAt.replace(/[:.]/g, "-");
632
+ writeJson(res, 200, {
633
+ session_id: sessionId,
634
+ ...(typeof response.session_label === "string" &&
635
+ response.session_label.trim()
636
+ ? { session_label: response.session_label.trim() }
637
+ : {}),
638
+ terminal_target: `relay:${relayTarget.clientUuid}/${relayTarget.localSessionId}`,
639
+ filename: `${filenameBase}-${timestamp}.md`,
640
+ markdown_content: [
641
+ "# Terminal Buffer",
642
+ "",
643
+ `- Session: ${titleBase}`,
644
+ `- Session ID: ${sessionId}`,
645
+ `- terminal target: relay:${relayTarget.clientUuid}/${relayTarget.localSessionId}`,
646
+ "- Capture scope: visible pane",
647
+ `- Captured at: ${capturedAt}`,
648
+ "",
649
+ "```text",
650
+ response.content.replaceAll("\u0000", ""),
651
+ "```",
652
+ "",
653
+ ].join("\n"),
654
+ capture_mode: "visible",
655
+ scope_description: "visible pane",
656
+ });
657
+ return true;
658
+ }
659
+ const result = await this.callBroker("telegramMcp.gatewaySocket.requestClientAction", {
660
+ clientUuid: relayTarget.clientUuid,
661
+ actionName: "telegramMcp.terminalBuffer.captureBufferRemote",
662
+ params: {
663
+ session_id: relayTarget.localSessionId,
664
+ scope,
665
+ },
666
+ }, { meta: { internal_call: true } });
667
+ writeJson(res, 200, result);
668
+ return true;
669
+ }
670
+ catch (error) {
671
+ writeJson(res, 400, {
672
+ error: error instanceof Error
673
+ ? error.message
674
+ : `Failed to capture remote buffer. Update the client agent if it is not on the latest build. Cause: ${String(error)}`,
675
+ });
676
+ return true;
677
+ }
678
+ }
394
679
  if (pathname === "/gateway/client/register") {
395
680
  if (req.method !== "POST") {
396
681
  writeText(res, 405, "Method not allowed");
@@ -409,6 +694,298 @@ class GatewayHttpService {
409
694
  return true;
410
695
  }
411
696
  }
697
+ if (pathname === "/gateway/user/auth") {
698
+ if (req.method !== "POST") {
699
+ writeText(res, 405, "Method not allowed");
700
+ return true;
701
+ }
702
+ try {
703
+ const body = (await this.readJsonBody(req));
704
+ const result = await this.callBroker("telegramMcp.gateway.upsertGatewayUser", body, { meta: { internal_call: true } });
705
+ writeJson(res, 200, result);
706
+ return true;
707
+ }
708
+ catch (error) {
709
+ writeJson(res, 400, {
710
+ error: error instanceof Error ? error.message : String(error),
711
+ });
712
+ return true;
713
+ }
714
+ }
715
+ if (pathname === "/gateway/user/route") {
716
+ if (req.method !== "POST") {
717
+ writeText(res, 405, "Method not allowed");
718
+ return true;
719
+ }
720
+ try {
721
+ const body = (await this.readJsonBody(req));
722
+ const result = await this.callBroker("telegramMcp.gateway.resolveGatewayUserRoute", body, { meta: { internal_call: true } });
723
+ writeJson(res, 200, result ?? {});
724
+ return true;
725
+ }
726
+ catch (error) {
727
+ writeJson(res, 400, {
728
+ error: error instanceof Error ? error.message : String(error),
729
+ });
730
+ return true;
731
+ }
732
+ }
733
+ if (pathname === "/gateway/admin/prune-state") {
734
+ if (req.method !== "POST") {
735
+ writeText(res, 405, "Method not allowed");
736
+ return true;
737
+ }
738
+ try {
739
+ const result = await this.callBroker("telegramMcp.gateway.pruneGatewayState", {}, { meta: { internal_call: true } });
740
+ writeJson(res, 200, result);
741
+ return true;
742
+ }
743
+ catch (error) {
744
+ writeJson(res, 400, {
745
+ error: error instanceof Error ? error.message : String(error),
746
+ });
747
+ return true;
748
+ }
749
+ }
750
+ if (pathname === "/gateway/relay/console-message") {
751
+ if (req.method !== "POST") {
752
+ writeText(res, 405, "Method not allowed");
753
+ return true;
754
+ }
755
+ try {
756
+ const body = (await this.readJsonBody(req));
757
+ const targetClientUuid = typeof body.target_client_uuid === "string"
758
+ ? body.target_client_uuid.trim()
759
+ : "";
760
+ const targetLocalSessionId = typeof body.target_local_session_id === "string"
761
+ ? body.target_local_session_id.trim()
762
+ : "";
763
+ const text = typeof body.message === "string" ? body.message.trim() : "";
764
+ const attachments = Array.isArray(body.attachments)
765
+ ? body.attachments.filter((item) => typeof item === "string" && item.trim().length > 0)
766
+ : [];
767
+ const sourceLabel = typeof body.source_actor_label === "string"
768
+ ? body.source_actor_label.trim()
769
+ : undefined;
770
+ if (!targetClientUuid || !targetLocalSessionId || !text) {
771
+ writeJson(res, 400, {
772
+ error: "target_client_uuid, target_local_session_id, and message are required",
773
+ });
774
+ return true;
775
+ }
776
+ const submittedText = attachments.length > 0
777
+ ? `${text} [attachments saved: ${attachments.join(", ")}]`.trim()
778
+ : text;
779
+ await this.requestLiveRelayAction({
780
+ clientUuid: targetClientUuid,
781
+ localSessionId: targetLocalSessionId,
782
+ action: "text",
783
+ text: submittedText,
784
+ });
785
+ await this.requestLiveRelayAction({
786
+ clientUuid: targetClientUuid,
787
+ localSessionId: targetLocalSessionId,
788
+ action: "enter",
789
+ });
790
+ writeJson(res, 200, {
791
+ ok: true,
792
+ session_id: targetLocalSessionId,
793
+ submitted_text: submittedText,
794
+ ...(sourceLabel ? { source_label: sourceLabel } : {}),
795
+ });
796
+ return true;
797
+ }
798
+ catch (error) {
799
+ writeJson(res, 400, {
800
+ error: error instanceof Error ? error.message : String(error),
801
+ });
802
+ return true;
803
+ }
804
+ }
805
+ if (pathname === "/gateway/transport/notify") {
806
+ if (req.method !== "POST") {
807
+ writeText(res, 405, "Method not allowed");
808
+ return true;
809
+ }
810
+ try {
811
+ const body = await this.readJsonBody(req);
812
+ const output = await this.callBroker("telegramMcp.notify.sendForGatewaySession", body, { meta: { internal_call: true } });
813
+ writeJson(res, 200, output);
814
+ }
815
+ catch (error) {
816
+ writeText(res, 500, error instanceof Error ? error.message : String(error));
817
+ }
818
+ return true;
819
+ }
820
+ if (pathname === "/gateway/transport/document") {
821
+ if (req.method !== "POST") {
822
+ writeText(res, 405, "Method not allowed");
823
+ return true;
824
+ }
825
+ try {
826
+ const body = await this.readJsonBody(req);
827
+ const output = await this.callBroker("telegramMcp.notify.sendDocumentForGatewaySession", body, { meta: { internal_call: true } });
828
+ writeJson(res, 200, output);
829
+ }
830
+ catch (error) {
831
+ writeText(res, 500, error instanceof Error ? error.message : String(error));
832
+ }
833
+ return true;
834
+ }
835
+ if (pathname === "/gateway/transport/send-file") {
836
+ if (req.method !== "POST") {
837
+ writeText(res, 405, "Method not allowed");
838
+ return true;
839
+ }
840
+ try {
841
+ const body = (await this.readJsonBody(req));
842
+ const sessionId = typeof body.session_id === "string" ? body.session_id.trim() : "";
843
+ const filePath = typeof body.file_path === "string" ? body.file_path.trim() : "";
844
+ const caption = typeof body.caption === "string" && body.caption.trim()
845
+ ? body.caption.trim()
846
+ : undefined;
847
+ const target = await this.resolveConnectedConsoleTarget(sessionId);
848
+ const output = await this.callBroker("telegramMcp.gatewaySocket.requestClientAction", {
849
+ clientUuid: target.clientUuid,
850
+ actionName: "telegramMcp.notify.sendDocumentRemote",
851
+ params: {
852
+ session_id: target.localSessionId,
853
+ file_path: filePath,
854
+ ...(caption ? { caption } : {}),
855
+ },
856
+ }, { meta: { internal_call: true } });
857
+ if (isBackendErrorLike(output)) {
858
+ throw new Error(this.extractActionErrorMessage(output, "Storage file send failed"));
859
+ }
860
+ writeJson(res, 200, output);
861
+ }
862
+ catch (error) {
863
+ writeText(res, 500, error instanceof Error ? error.message : String(error));
864
+ }
865
+ return true;
866
+ }
867
+ if (pathname === "/gateway/transport/request") {
868
+ if (req.method !== "POST") {
869
+ writeText(res, 405, "Method not allowed");
870
+ return true;
871
+ }
872
+ try {
873
+ const body = await this.readJsonBody(req);
874
+ const output = await this.callBroker("telegramMcp.notify.sendRequestForGatewaySession", body, { meta: { internal_call: true } });
875
+ writeJson(res, 200, output);
876
+ }
877
+ catch (error) {
878
+ writeText(res, 500, error instanceof Error ? error.message : String(error));
879
+ }
880
+ return true;
881
+ }
882
+ if (pathname === "/gateway/transport/reply") {
883
+ if (req.method !== "POST") {
884
+ writeText(res, 405, "Method not allowed");
885
+ return true;
886
+ }
887
+ try {
888
+ const body = await this.readJsonBody(req);
889
+ const output = await this.callBroker("telegramMcp.gatewaySocket.notifyTransportReply", body, { meta: { internal_call: true } });
890
+ writeJson(res, 200, output);
891
+ }
892
+ catch (error) {
893
+ writeText(res, 500, error instanceof Error ? error.message : String(error));
894
+ }
895
+ return true;
896
+ }
897
+ if (pathname === "/gateway/clients/list") {
898
+ if (req.method !== "POST") {
899
+ writeText(res, 405, "Method not allowed");
900
+ return true;
901
+ }
902
+ try {
903
+ const body = (await this.readJsonBody(req));
904
+ const result = await this.callBroker("telegramMcp.gateway.listClients", body, { meta: { internal_call: true } });
905
+ writeJson(res, 200, result);
906
+ return true;
907
+ }
908
+ catch (error) {
909
+ writeJson(res, 400, {
910
+ error: error instanceof Error ? error.message : String(error),
911
+ });
912
+ return true;
913
+ }
914
+ }
915
+ if (pathname === "/gateway/clients/connected") {
916
+ if (req.method !== "POST") {
917
+ writeText(res, 405, "Method not allowed");
918
+ return true;
919
+ }
920
+ try {
921
+ const body = (await this.readJsonBody(req));
922
+ const result = await this.callBroker("telegramMcp.gateway.listLiveClients", body, { meta: { internal_call: true } });
923
+ writeJson(res, 200, result);
924
+ return true;
925
+ }
926
+ catch (error) {
927
+ writeJson(res, 400, {
928
+ error: error instanceof Error ? error.message : String(error),
929
+ });
930
+ return true;
931
+ }
932
+ }
933
+ if (pathname === "/gateway/sessions/known") {
934
+ if (req.method !== "POST") {
935
+ writeText(res, 405, "Method not allowed");
936
+ return true;
937
+ }
938
+ try {
939
+ const body = (await this.readJsonBody(req));
940
+ const filterClientUuid = typeof body.client_uuid === "string" && body.client_uuid.trim()
941
+ ? body.client_uuid.trim()
942
+ : null;
943
+ const ownerUserUuid = typeof body.owner_user_uuid === "string" && body.owner_user_uuid.trim()
944
+ ? body.owner_user_uuid.trim()
945
+ : null;
946
+ const telegramUserId = typeof body.telegram_user_id === "number"
947
+ ? String(body.telegram_user_id)
948
+ : typeof body.telegram_user_id === "string" && body.telegram_user_id.trim()
949
+ ? body.telegram_user_id.trim()
950
+ : null;
951
+ const connectedOnly = typeof body.connected_only === "boolean"
952
+ ? body.connected_only
953
+ : false;
954
+ const [liveResult, scopedClientsResult] = await Promise.all([
955
+ this.callBroker("telegramMcp.gateway.listLiveConsoles", body, { meta: { internal_call: true } }),
956
+ this.callBroker("telegramMcp.gateway.listClients", body, { meta: { internal_call: true } }),
957
+ ]);
958
+ const allowedClientUuids = ownerUserUuid || telegramUserId
959
+ ? new Set((Array.isArray(scopedClientsResult.clients)
960
+ ? scopedClientsResult.clients
961
+ : [])
962
+ .map((client) => typeof client.client_uuid === "string"
963
+ ? client.client_uuid.trim()
964
+ : "")
965
+ .filter(Boolean))
966
+ : null;
967
+ const sessions = (Array.isArray(liveResult.sessions) ? liveResult.sessions : [])
968
+ .filter((session) => allowedClientUuids ? allowedClientUuids.has(session.client_uuid) : true)
969
+ .filter((session) => filterClientUuid ? session.client_uuid === filterClientUuid : true)
970
+ .filter((session) => (connectedOnly ? session.connected : true))
971
+ .sort((left, right) => {
972
+ const leftLabel = left.session_label?.trim() || left.local_session_id;
973
+ const rightLabel = right.session_label?.trim() || right.local_session_id;
974
+ return `${left.client_uuid}:${leftLabel}`.localeCompare(`${right.client_uuid}:${rightLabel}`);
975
+ });
976
+ writeJson(res, 200, {
977
+ total: sessions.length,
978
+ sessions,
979
+ });
980
+ return true;
981
+ }
982
+ catch (error) {
983
+ writeJson(res, 400, {
984
+ error: error instanceof Error ? error.message : String(error),
985
+ });
986
+ return true;
987
+ }
988
+ }
412
989
  if (pathname === "/gateway/projects/create") {
413
990
  if (req.method !== "POST") {
414
991
  writeText(res, 405, "Method not allowed");
@@ -417,6 +994,11 @@ class GatewayHttpService {
417
994
  try {
418
995
  const body = (await this.readJsonBody(req));
419
996
  const result = await this.callBroker("telegramMcp.gateway.createProject", body, { meta: { internal_call: true } });
997
+ if (isBackendErrorLike(result)) {
998
+ throw new Error(result.message
999
+ ? `${result.message}${result.code ? ` [${result.code}]` : ""}`
1000
+ : `Gateway createProject failed [${result.code}]`);
1001
+ }
420
1002
  writeJson(res, 200, result);
421
1003
  return true;
422
1004
  }
@@ -435,6 +1017,11 @@ class GatewayHttpService {
435
1017
  try {
436
1018
  const body = (await this.readJsonBody(req));
437
1019
  const result = await this.callBroker("telegramMcp.gateway.joinProject", body, { meta: { internal_call: true } });
1020
+ if (isBackendErrorLike(result)) {
1021
+ throw new Error(result.message
1022
+ ? `${result.message}${result.code ? ` [${result.code}]` : ""}`
1023
+ : `Gateway joinProject failed [${result.code}]`);
1024
+ }
438
1025
  if (Array.isArray(result.notify_client_uuids) &&
439
1026
  result.notify_client_uuids.length > 0 &&
440
1027
  typeof result.project_uuid === "string" &&
@@ -482,24 +1069,11 @@ class GatewayHttpService {
482
1069
  try {
483
1070
  const body = (await this.readJsonBody(req));
484
1071
  const result = await this.callBroker("telegramMcp.gateway.registerSession", body, { meta: { internal_call: true } });
485
- writeJson(res, 200, result);
486
- return true;
487
- }
488
- catch (error) {
489
- writeJson(res, 400, {
490
- error: error instanceof Error ? error.message : String(error),
491
- });
492
- return true;
493
- }
494
- }
495
- if (pathname === "/gateway/sessions/unregister") {
496
- if (req.method !== "POST") {
497
- writeText(res, 405, "Method not allowed");
498
- return true;
499
- }
500
- try {
501
- const body = (await this.readJsonBody(req));
502
- const result = await this.callBroker("telegramMcp.gateway.unregisterSession", body, { meta: { internal_call: true } });
1072
+ if (isBackendErrorLike(result)) {
1073
+ throw new Error(result.message
1074
+ ? `${result.message}${result.code ? ` [${result.code}]` : ""}`
1075
+ : `Gateway registerSession failed [${result.code}]`);
1076
+ }
503
1077
  writeJson(res, 200, result);
504
1078
  return true;
505
1079
  }