@deadragdoll/tellymcp 0.0.9 → 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 (157) hide show
  1. package/.env.example.client +42 -50
  2. package/.env.example.gateway +49 -61
  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 +36 -10
  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 +40 -20
  15. package/config/templates/env.client.template +34 -18
  16. package/config/templates/env.gateway.template +38 -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/approval.service.js +1 -1
  23. package/dist/services/features/telegram-mcp/browser.service.js +95 -2
  24. package/dist/services/features/telegram-mcp/collaboration.service.js +41 -4
  25. package/dist/services/features/telegram-mcp/ensuredb.service.js +145 -26
  26. package/dist/services/features/telegram-mcp/gateway-delivery.service.js +285 -103
  27. package/dist/services/features/telegram-mcp/gateway-rmq.service.js +3 -2
  28. package/dist/services/features/telegram-mcp/gateway-socket.service.js +905 -87
  29. package/dist/services/features/telegram-mcp/gateway.service.js +876 -81
  30. package/dist/services/features/telegram-mcp/mcp-http.service.js +9 -1
  31. package/dist/services/features/telegram-mcp/mcp-server.service.js +17 -26
  32. package/dist/services/features/telegram-mcp/notify.service.js +128 -2
  33. package/dist/services/features/telegram-mcp/runtime.service.js +27 -7
  34. package/dist/services/features/telegram-mcp/session-context.service.js +29 -2
  35. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +133 -10
  36. package/dist/services/features/telegram-mcp/src/app/config/env.js +161 -51
  37. package/dist/services/features/telegram-mcp/src/app/http.js +375 -42
  38. package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +386 -58
  39. package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +3 -0
  40. package/dist/services/features/telegram-mcp/src/app/webapp/terminal.js +12 -0
  41. package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +116 -104
  42. package/dist/services/features/telegram-mcp/src/entities/xchange/model/types.js +2 -0
  43. package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +1 -1
  44. package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
  45. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +249 -19
  46. package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +71 -0
  47. package/dist/services/features/telegram-mcp/src/features/collaboration/model/listGatewaySessionsTool.js +33 -0
  48. package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +93 -82
  49. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +47 -5
  50. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +1 -1
  51. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +1 -1
  52. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +82 -0
  53. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +22 -14
  54. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +649 -75
  55. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +76 -0
  56. package/dist/services/features/telegram-mcp/src/features/embedded-runtime/model/embeddedRuntimeBroker.js +92 -0
  57. package/dist/services/features/telegram-mcp/src/features/foreground-terminal/model/foregroundTerminalRuntime.js +192 -0
  58. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +382 -3
  59. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +1 -1
  60. package/dist/services/features/telegram-mcp/src/features/notify/model/sendFileToTelegramTool.js +33 -0
  61. package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +1 -1
  62. package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +1 -1
  63. package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +1 -1
  64. package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +42 -200
  65. package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +1 -1
  66. package/dist/services/features/telegram-mcp/src/features/terminal-buffer/model/terminalBufferService.js +96 -0
  67. package/dist/services/features/telegram-mcp/src/features/terminal-input/model/terminalInputService.js +97 -0
  68. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +107 -58
  69. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +1 -1
  70. package/dist/services/features/telegram-mcp/src/features/xchange/model/getXchangeRecordTool.js +28 -0
  71. package/dist/services/features/telegram-mcp/src/features/xchange/model/listXchangeRecordsTool.js +28 -0
  72. package/dist/services/features/telegram-mcp/src/features/xchange/model/markXchangeRecordReadTool.js +28 -0
  73. package/dist/services/features/telegram-mcp/src/features/xchange/model/xchangeService.js +169 -0
  74. package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +5 -4
  75. package/dist/services/features/telegram-mcp/src/shared/i18n/index.js +46 -0
  76. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/en.js +652 -0
  77. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/ru.js +652 -0
  78. package/dist/services/features/telegram-mcp/src/shared/integrations/memory/processLocalSessionStore.js +27 -0
  79. package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +11 -8
  80. package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +51 -71
  81. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +21 -22
  82. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +411 -6524
  83. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportAttachmentStore.js +93 -0
  84. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportBroadcastActions.js +385 -0
  85. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConsoleRegistry.js +143 -0
  86. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConstructorWiring.js +633 -0
  87. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContent.js +84 -0
  88. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContext.js +78 -0
  89. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportDocumentActions.js +36 -0
  90. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportEventActions.js +292 -0
  91. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +352 -0
  92. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFormatting.js +75 -0
  93. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportGatewayActions.js +44 -0
  94. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLifecycleActions.js +161 -0
  95. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLive.js +56 -0
  96. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLiveActions.js +77 -0
  97. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuCallbacks.js +254 -0
  98. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFactories.js +538 -0
  99. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFingerprints.js +93 -0
  100. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFlow.js +344 -0
  101. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuShell.js +62 -0
  102. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuState.js +408 -0
  103. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuText.js +216 -0
  104. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMessageFlow.js +452 -0
  105. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportOutputActions.js +189 -0
  106. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPartnerActions.js +286 -0
  107. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPayloadState.js +101 -0
  108. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectActions.js +463 -0
  109. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEntryActions.js +202 -0
  110. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEvents.js +99 -0
  111. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectMenus.js +138 -0
  112. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectState.js +308 -0
  113. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectView.js +426 -0
  114. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportRequestFlow.js +278 -0
  115. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportSessionActions.js +143 -0
  116. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalActions.js +468 -0
  117. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalRuntime.js +171 -0
  118. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTypes.js +2 -0
  119. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportUtils.js +330 -0
  120. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportXchangeState.js +107 -0
  121. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +255 -0
  122. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +543 -0
  123. package/dist/services/features/telegram-mcp/src/shared/integrations/xchange/sqliteRecordStore.js +223 -0
  124. package/dist/services/features/telegram-mcp/src/shared/lib/gatewayScope.js +24 -0
  125. package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +6 -0
  126. package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +147 -76
  127. package/dist/services/features/telegram-mcp/src/shared/lib/telegramXchangeRecords.js +72 -0
  128. package/dist/services/features/telegram-mcp/src/shared/lib/terminalPromptDetection.js +237 -0
  129. package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +129 -1
  130. package/dist/services/features/telegram-mcp/src/shared/lib/xchangeRecordHints.js +98 -0
  131. package/dist/services/features/telegram-mcp/standalone-http.service.js +13 -1
  132. package/dist/services/features/telegram-mcp/terminal-buffer.service.js +42 -0
  133. package/dist/services/features/telegram-mcp/terminal-input.service.js +41 -0
  134. package/dist/services/features/telegram-mcp/tools-sync.service.js +16 -2
  135. package/dist/services/features/telegram-mcp/xchange.service.js +123 -0
  136. package/docs/STANDALONE-ru.md +172 -0
  137. package/docs/STANDALONE.md +172 -0
  138. package/package.json +11 -5
  139. package/scripts/build-package-artifact.sh +27 -0
  140. package/scripts/deploy-gateway.sh +64 -0
  141. package/scripts/deploy-onebot-branch.sh +27 -0
  142. package/scripts/postinstall.js +11 -36
  143. package/STANDALONE-ru.md +0 -274
  144. package/STANDALONE.md +0 -274
  145. package/dist/services/features/telegram-mcp/inbox.service.js +0 -33
  146. package/dist/services/features/telegram-mcp/pair.service.js +0 -33
  147. package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +0 -10
  148. package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +0 -33
  149. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +0 -33
  150. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +0 -33
  151. package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +0 -77
  152. package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +0 -33
  153. package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +0 -33
  154. package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +0 -202
  155. package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +0 -33
  156. package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +0 -33
  157. package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +0 -363
@@ -6,8 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TELEGRAM_MCP_GATEWAY_DELIVERY_SERVICE_NAME = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
8
  const runtime_service_1 = require("./runtime.service");
9
- const ids_1 = require("./src/shared/lib/ids/ids");
10
- const client_1 = require("./src/shared/integrations/tmux/client");
9
+ const xchangeRecordHints_1 = require("./src/shared/lib/xchangeRecordHints");
10
+ const client_1 = require("./src/shared/integrations/terminal/client");
11
+ const sqliteRecordStore_1 = require("./src/shared/integrations/xchange/sqliteRecordStore");
11
12
  exports.TELEGRAM_MCP_GATEWAY_DELIVERY_SERVICE_NAME = "telegramMcp.gatewayDelivery";
12
13
  function renderYamlArray(values) {
13
14
  if (values.length === 0) {
@@ -15,7 +16,55 @@ function renderYamlArray(values) {
15
16
  }
16
17
  return `\n${values.map((value) => ` - ${JSON.stringify(value)}`).join("\n")}`;
17
18
  }
19
+ function looksLikeFileDeliveryRequest(input) {
20
+ if (input.kind !== "request" && input.kind !== "question") {
21
+ return false;
22
+ }
23
+ const haystack = [
24
+ input.summary,
25
+ input.message,
26
+ input.expectedReply ?? "",
27
+ ]
28
+ .join("\n")
29
+ .toLowerCase();
30
+ return (/\b(send_partner_file|file delivery path|artifact|artifacts)\b/u.test(haystack) ||
31
+ /\b(файл|артефакт|артефакты)\b/u.test(haystack) ||
32
+ /\b[\w.-]+\.(html|txt|md|json|ts|tsx|js|jsx|css|scss|png|jpg|jpeg|webp|pdf|zip)\b/u.test(haystack));
33
+ }
34
+ function looksLikeBrowserScreenshotRequest(input) {
35
+ if (input.kind !== "request" && input.kind !== "question") {
36
+ return false;
37
+ }
38
+ const haystack = [
39
+ input.summary,
40
+ input.message,
41
+ input.expectedReply ?? "",
42
+ ]
43
+ .join("\n")
44
+ .toLowerCase();
45
+ return (/\b(browser_open|browser_screenshot|playwright)\b/u.test(haystack) ||
46
+ /\b(скриншот|screenshot|скрин)\b/u.test(haystack) ||
47
+ /\bhttps?:\/\/[^\s]+/u.test(haystack));
48
+ }
18
49
  function buildNoteContent(input) {
50
+ const isDirectRoute = input.delivery.route_mode === "direct";
51
+ const isTelegramHumanSource = input.delivery.source_client_uuid === "gateway-telegram";
52
+ const prefersFileDelivery = looksLikeFileDeliveryRequest({
53
+ kind: input.delivery.kind,
54
+ summary: input.delivery.summary,
55
+ message: input.delivery.message,
56
+ ...(input.delivery.expected_reply
57
+ ? { expectedReply: input.delivery.expected_reply }
58
+ : {}),
59
+ });
60
+ const prefersBrowserScreenshot = looksLikeBrowserScreenshotRequest({
61
+ kind: input.delivery.kind,
62
+ summary: input.delivery.summary,
63
+ message: input.delivery.message,
64
+ ...(input.delivery.expected_reply
65
+ ? { expectedReply: input.delivery.expected_reply }
66
+ : {}),
67
+ });
19
68
  const lines = ["---"];
20
69
  lines.push(`message_uuid: ${JSON.stringify(input.delivery.message_uuid)}`);
21
70
  lines.push(`kind: ${JSON.stringify(input.delivery.kind)}`);
@@ -40,70 +89,112 @@ function buildNoteContent(input) {
40
89
  if (input.delivery.expected_reply?.trim()) {
41
90
  lines.push("", "# Expected Reply", input.delivery.expected_reply.trim());
42
91
  }
43
- if (input.delivery.requires_reply) {
44
- lines.push("", "# Reply Params", `message_uuid: ${input.delivery.message_uuid}`, `target_session_id: ${input.delivery.source_session_uuid}`, ...(input.delivery.project_uuid
92
+ if (isTelegramHumanSource) {
93
+ lines.push("", "# Human Reply Route", "Reply to the human with notify_telegram after you finish the requested work.", "Do not use send_partner_note for a human Telegram reply.");
94
+ }
95
+ else if (input.delivery.requires_reply) {
96
+ lines.push("", "# Reply Params", `message_uuid: ${input.delivery.message_uuid}`, ...(isDirectRoute
97
+ ? [
98
+ ...(input.delivery.source_client_uuid
99
+ ? [`target_client_uuid: ${input.delivery.source_client_uuid}`]
100
+ : []),
101
+ `target_local_session_id: ${input.delivery.source_local_session_id}`,
102
+ ]
103
+ : [`target_session_id: ${input.delivery.source_session_uuid}`]), ...(!isDirectRoute && input.delivery.project_uuid
45
104
  ? [`project_uuid: ${input.delivery.project_uuid}`]
46
- : []), "", "# Action Required", "You must send a reply via send_partner_note.", "Your task is not complete until send_partner_note succeeds.", "Do not stop after local analysis or a chat explanation.", "Do not rely on linked partner.", "Pass target_session_id explicitly.", "If possible, also pass in_reply_to=message_uuid.", "Only after the tool succeeds may you say that the reply was sent.", "", "# Reply Tool Call Example", "send_partner_note(", ` session_id=${JSON.stringify(input.delivery.target_local_session_id)},`, ` target_session_id=${JSON.stringify(input.delivery.source_session_uuid)},`, ` kind=${JSON.stringify("reply")},`, ...(input.delivery.project_uuid
105
+ : []), "", "# Action Required", ...(prefersFileDelivery
106
+ ? [
107
+ "You must send the requested file via send_partner_file.",
108
+ ...(prefersBrowserScreenshot
109
+ ? [
110
+ "For a webpage screenshot request, first use browser_open and browser_screenshot in this console.",
111
+ "Do not replace the browser workflow with a shell Playwright command unless the browser tools actually fail.",
112
+ ]
113
+ : []),
114
+ "Do not paste file contents into send_partner_note.",
115
+ "Do not stop after reading, listing files, or explaining what you found.",
116
+ "Your task is not complete until send_partner_file succeeds.",
117
+ "Do not mark_xchange_record_read before send_partner_file succeeds.",
118
+ ]
119
+ : [
120
+ "You must send a reply via send_partner_note.",
121
+ "Do not stop after reading, listing files, or explaining what you found.",
122
+ "Your task is not complete until send_partner_note succeeds.",
123
+ "Do not mark_xchange_record_read before send_partner_note succeeds.",
124
+ ]), "Do not stop after local analysis, inspection, or a chat explanation.", "If the request asks you to produce an artifact, actually produce and send the artifact.", ...(isDirectRoute
125
+ ? [
126
+ "Do not rely on implicit partner selection or project-scoped target_session_id.",
127
+ "Pass target_client_uuid and target_local_session_id explicitly.",
128
+ ]
129
+ : [
130
+ "Do not rely on implicit partner selection.",
131
+ "Pass target_session_id explicitly.",
132
+ ]), "If possible, also pass in_reply_to=message_uuid.", "Only after the tool succeeds may you say that the reply was sent.", "", ...(prefersFileDelivery
133
+ ? [
134
+ ...(prefersBrowserScreenshot
135
+ ? [
136
+ "# Preferred Browser Workflow Example",
137
+ "browser_open(",
138
+ " url=\"https://github.com\",",
139
+ " wait_until=\"networkidle\"",
140
+ ")",
141
+ "browser_screenshot(",
142
+ " file_name=\"github.com.png\"",
143
+ ")",
144
+ "",
145
+ ]
146
+ : []),
147
+ "# Preferred Reply Tool Call Example",
148
+ "send_partner_file(",
149
+ ` session_id=${JSON.stringify(input.delivery.target_local_session_id)},`,
150
+ ...(isDirectRoute
151
+ ? [
152
+ ...(input.delivery.source_client_uuid
153
+ ? [
154
+ ` target_client_uuid=${JSON.stringify(input.delivery.source_client_uuid)},`,
155
+ ]
156
+ : []),
157
+ ` target_local_session_id=${JSON.stringify(input.delivery.source_local_session_id)},`,
158
+ ]
159
+ : [
160
+ ` target_session_id=${JSON.stringify(input.delivery.source_session_uuid)},`,
161
+ ]),
162
+ ...(!isDirectRoute && input.delivery.project_uuid
163
+ ? [` project_uuid=${JSON.stringify(input.delivery.project_uuid)},`]
164
+ : []),
165
+ ` file_path=${JSON.stringify(prefersBrowserScreenshot ? "github.com.png" : "index.html")},`,
166
+ ` in_reply_to=${JSON.stringify(input.delivery.message_uuid)},`,
167
+ " summary=\"Передаю запрошенный файл\",",
168
+ " message=\"Передаю реальный файл как артефакт\"",
169
+ ")",
170
+ "",
171
+ "# Alternate Reply Tool Call Example",
172
+ ]
173
+ : ["# Reply Tool Call Example"]), "send_partner_note(", ` session_id=${JSON.stringify(input.delivery.target_local_session_id)},`, ...(isDirectRoute
174
+ ? [
175
+ ...(input.delivery.source_client_uuid
176
+ ? [
177
+ ` target_client_uuid=${JSON.stringify(input.delivery.source_client_uuid)},`,
178
+ ]
179
+ : []),
180
+ ` target_local_session_id=${JSON.stringify(input.delivery.source_local_session_id)},`,
181
+ ]
182
+ : [
183
+ ` target_session_id=${JSON.stringify(input.delivery.source_session_uuid)},`,
184
+ ]), ` kind=${JSON.stringify("reply")},`, ...(!isDirectRoute && input.delivery.project_uuid
47
185
  ? [` project_uuid=${JSON.stringify(input.delivery.project_uuid)},`]
48
186
  : []), ` in_reply_to=${JSON.stringify(input.delivery.message_uuid)},`, " summary=\"Короткий итог\",", " message=\"Подробный ответ\"", ")");
49
187
  }
188
+ if (!input.delivery.requires_reply && input.delivery.kind === "reply") {
189
+ lines.push("", "# Follow-up", "If this reply completes a task that originally came from a human Telegram request in the receiving session, the receiving session must now deliver the final result to the human.", "Use notify_telegram for text-only results.", "If this reply returned a real artifact or file, use send_file_to_telegram from the receiving session instead of leaving the artifact only in local xchange storage.");
190
+ }
50
191
  if (input.copiedArtifacts.length > 0) {
51
192
  lines.push("", "# Artifacts", ...input.copiedArtifacts.map((artifact) => `- ${artifact}`));
52
193
  }
53
194
  return `${lines.join("\n")}\n`;
54
195
  }
55
- function buildShareIndexLine(input) {
56
- return [
57
- "-",
58
- `[${input.delivery.created_at}]`,
59
- `${input.delivery.source_session_label} → ${input.delivery.target_session_label}`,
60
- `| ${input.delivery.kind} |`,
61
- `${input.delivery.summary}`,
62
- `| \`${input.relativeNotePath}\``,
63
- ].join(" ");
64
- }
65
- function buildPartnerInboxText(input) {
66
- const sourceActorLabel = input.delivery.source_actor_label || input.delivery.source_session_label;
67
- const kindTitle = input.delivery.kind === "question"
68
- ? `Получен вопрос от ${sourceActorLabel}.`
69
- : input.delivery.kind === "reply"
70
- ? `Получен ответ от ${sourceActorLabel}.`
71
- : input.delivery.kind === "request"
72
- ? `Получен запрос от ${sourceActorLabel}.`
73
- : input.delivery.kind === "handoff"
74
- ? `Получен handoff от ${sourceActorLabel}.`
75
- : `Получено обновление от ${sourceActorLabel}.`;
76
- return [
77
- kindTitle,
78
- ...(input.delivery.project_name
79
- ? [`Проект: ${input.delivery.project_name}`]
80
- : []),
81
- `Сессия: ${input.delivery.source_session_label} -> ${input.delivery.target_session_label}`,
82
- `Кратко: ${input.delivery.summary}`,
83
- "",
84
- `Действие: открой ${input.delivery.share_index_file_name}, затем note ниже.`,
85
- `Note: ${input.notePath}`,
86
- ...(input.copiedArtifacts.length > 0
87
- ? ["", "Файлы:", ...input.copiedArtifacts.map((item) => `- ${item}`)]
88
- : []),
89
- ...(input.delivery.requires_reply
90
- ? [
91
- "",
92
- `Reply message_uuid: ${input.delivery.message_uuid}`,
93
- `Reply target_session_id: ${input.delivery.source_session_uuid}`,
94
- ...(input.delivery.project_uuid
95
- ? [`Reply project_uuid: ${input.delivery.project_uuid}`]
96
- : []),
97
- "Обязательно отправь reply через send_partner_note.",
98
- "Задача не завершена, пока send_partner_note не отработал успешно.",
99
- "Не останавливайся на локальном объяснении.",
100
- "Не используй linked partner для ответа. Передай эти параметры явно в send_partner_note.",
101
- "Только после успешного tool call можно считать ответ отправленным.",
102
- ]
103
- : []),
104
- ].join("\n");
105
- }
106
196
  function buildTelegramDeliveryNotification(input) {
197
+ const isDirectRoute = input.delivery.route_mode === "direct";
107
198
  const sourceActorLabel = input.delivery.source_actor_label || input.delivery.source_session_label;
108
199
  const kindTitle = input.delivery.kind === "question"
109
200
  ? `Получен вопрос от ${sourceActorLabel}.`
@@ -135,8 +226,17 @@ function buildTelegramDeliveryNotification(input) {
135
226
  ? [
136
227
  "",
137
228
  `Reply message_uuid: ${input.delivery.message_uuid}`,
138
- `Reply target_session_id: ${input.delivery.source_session_uuid}`,
139
- ...(input.delivery.project_uuid
229
+ ...(isDirectRoute
230
+ ? [
231
+ ...(input.delivery.source_client_uuid
232
+ ? [
233
+ `Reply target_client_uuid: ${input.delivery.source_client_uuid}`,
234
+ ]
235
+ : []),
236
+ `Reply target_local_session_id: ${input.delivery.source_local_session_id}`,
237
+ ]
238
+ : [`Reply target_session_id: ${input.delivery.source_session_uuid}`]),
239
+ ...(!isDirectRoute && input.delivery.project_uuid
140
240
  ? [`Reply project_uuid: ${input.delivery.project_uuid}`]
141
241
  : []),
142
242
  ]
@@ -207,19 +307,19 @@ const TelegramMcpGatewayDeliveryService = {
207
307
  }
208
308
  const targetBinding = await runtime.bindingStore.getBinding(targetSession.sessionId);
209
309
  if (!targetBinding) {
210
- runtime.logger.warn("Skipping gateway delivery because target session is not paired with Telegram", {
310
+ runtime.logger.info("Gateway delivery will be materialized without Telegram route", {
211
311
  deliveryUuid: delivery.delivery_uuid,
212
312
  sessionId: targetSession.sessionId,
213
313
  });
214
- return;
215
314
  }
315
+ const workspaceDir = runtime.objectStore.resolveWorkspaceDir(targetSession);
216
316
  const copiedArtifacts = [];
217
317
  for (const artifact of delivery.artifacts) {
218
318
  const relativePath = artifact.relative_path ||
219
319
  `shares/files/${delivery.share_id}/${artifact.original_name}`;
220
320
  let localArtifactPath;
221
321
  if (artifact.content_base64) {
222
- localArtifactPath = await (0, client_1.writeXchangeRelativeFile)(runtime.config.tmux, runtime.objectStore.resolveWorkspaceDir(targetSession), runtime.config.exchange.dir, relativePath, Buffer.from(artifact.content_base64, "base64"));
322
+ localArtifactPath = await (0, client_1.writeXchangeRelativeFile)(runtime.config.terminal, workspaceDir, runtime.config.exchange.dir, relativePath, Buffer.from(artifact.content_base64, "base64"));
223
323
  }
224
324
  else {
225
325
  localArtifactPath = await runtime.objectStore.ensureLocalFile({
@@ -246,7 +346,7 @@ const TelegramMcpGatewayDeliveryService = {
246
346
  });
247
347
  }
248
348
  const noteContent = buildNoteContent({ delivery, copiedArtifacts });
249
- const notePath = await (0, client_1.writeXchangeRelativeFile)(runtime.config.tmux, runtime.objectStore.resolveWorkspaceDir(targetSession), runtime.config.exchange.dir, delivery.note_relative_path, Buffer.from(noteContent, "utf8"));
349
+ const notePath = await (0, client_1.writeXchangeRelativeFile)(runtime.config.terminal, workspaceDir, runtime.config.exchange.dir, delivery.note_relative_path, Buffer.from(noteContent, "utf8"));
250
350
  await runtime.xchangeFileMetaStore.setXchangeFileMeta({
251
351
  sessionId: targetSession.sessionId,
252
352
  filePath: notePath,
@@ -256,52 +356,134 @@ const TelegramMcpGatewayDeliveryService = {
256
356
  mimeType: "text/markdown",
257
357
  sizeBytes: Buffer.byteLength(noteContent, "utf8"),
258
358
  });
259
- await (0, client_1.writeXchangeRelativeFile)(runtime.config.tmux, runtime.objectStore.resolveWorkspaceDir(targetSession), runtime.config.exchange.dir, delivery.share_index_file_name, Buffer.from(`${buildShareIndexLine({
260
- delivery,
261
- relativeNotePath: delivery.note_relative_path,
262
- })}\n`, "utf8"), { append: true });
263
- const inboxMessage = {
264
- id: (0, ids_1.createInboxMessageId)(new Date(delivery.created_at)),
265
- sessionId: targetSession.sessionId,
266
- telegramChatId: targetBinding.telegramChatId,
267
- telegramUserId: targetBinding.telegramUserId,
268
- sourceTelegramMessageId: Date.now(),
269
- text: buildPartnerInboxText({
270
- delivery,
271
- notePath,
272
- copiedArtifacts,
273
- }),
274
- attachments: [notePath, ...copiedArtifacts],
275
- receivedAt: delivery.created_at,
276
- };
277
- await runtime.inboxStore.createInboxMessage(inboxMessage);
278
- try {
279
- await runtime.telegramTransport.sendNotification({
280
- sessionId: targetSession.sessionId,
281
- sessionLabel: delivery.source_session_label,
282
- recipient: {
283
- telegramChatId: targetBinding.telegramChatId,
284
- telegramUserId: targetBinding.telegramUserId,
359
+ const isTelegramHumanSource = delivery.source_client_uuid === "gateway-telegram";
360
+ const prefersFileDelivery = looksLikeFileDeliveryRequest({
361
+ kind: delivery.kind,
362
+ summary: delivery.summary,
363
+ message: delivery.message,
364
+ ...(delivery.expected_reply
365
+ ? { expectedReply: delivery.expected_reply }
366
+ : {}),
367
+ });
368
+ const prefersBrowserScreenshot = looksLikeBrowserScreenshotRequest({
369
+ kind: delivery.kind,
370
+ summary: delivery.summary,
371
+ message: delivery.message,
372
+ ...(delivery.expected_reply
373
+ ? { expectedReply: delivery.expected_reply }
374
+ : {}),
375
+ });
376
+ const actionDesc = isTelegramHumanSource
377
+ ? (0, xchangeRecordHints_1.buildIncomingTelegramMessageActionDesc)(delivery.kind, (0, xchangeRecordHints_1.detectIncomingTelegramBrowserScreenshotRequest)({
378
+ kind: delivery.kind,
379
+ text: delivery.message,
380
+ ...(delivery.summary.trim()
381
+ ? { summary: delivery.summary.trim() }
382
+ : {}),
383
+ }))
384
+ : (0, xchangeRecordHints_1.buildIncomingPartnerActionDesc)(delivery.kind, delivery.requires_reply, prefersFileDelivery, prefersBrowserScreenshot);
385
+ await (0, sqliteRecordStore_1.upsertXchangeRecord)(runtime.config.terminal, workspaceDir, runtime.config.exchange.dir, {
386
+ record_id: delivery.share_id,
387
+ session_id: targetSession.sessionId,
388
+ category: isTelegramHumanSource ? "telegram_message" : "partner_note",
389
+ direction: "incoming",
390
+ status: "new",
391
+ kind: delivery.kind,
392
+ summary: delivery.summary,
393
+ body_text: noteContent,
394
+ action_desc: actionDesc,
395
+ tools: isTelegramHumanSource
396
+ ? (0, xchangeRecordHints_1.buildIncomingTelegramMessageTools)(delivery.kind, (0, xchangeRecordHints_1.detectIncomingTelegramBrowserScreenshotRequest)({
397
+ kind: delivery.kind,
398
+ text: delivery.message,
399
+ ...(delivery.summary.trim()
400
+ ? { summary: delivery.summary.trim() }
401
+ : {}),
402
+ }))
403
+ : (0, xchangeRecordHints_1.buildIncomingPartnerTools)(delivery.kind, delivery.requires_reply, prefersFileDelivery, prefersBrowserScreenshot),
404
+ note_path: notePath,
405
+ note_relative_path: delivery.note_relative_path,
406
+ source_session_id: delivery.source_session_uuid,
407
+ source_label: delivery.source_session_label,
408
+ ...(delivery.source_client_uuid
409
+ ? { source_client_uuid: delivery.source_client_uuid }
410
+ : {}),
411
+ source_local_session_id: delivery.source_local_session_id,
412
+ target_session_id: delivery.target_session_uuid,
413
+ target_label: delivery.target_session_label,
414
+ ...(delivery.target_client_uuid
415
+ ? { target_client_uuid: delivery.target_client_uuid }
416
+ : {}),
417
+ target_local_session_id: delivery.target_local_session_id,
418
+ ...(delivery.project_uuid ? { project_uuid: delivery.project_uuid } : {}),
419
+ ...(delivery.project_name ? { project_name: delivery.project_name } : {}),
420
+ requires_reply: delivery.requires_reply,
421
+ ...(delivery.expected_reply
422
+ ? { expected_reply: delivery.expected_reply }
423
+ : {}),
424
+ ...(delivery.in_reply_to ? { in_reply_to: delivery.in_reply_to } : {}),
425
+ attachments: [
426
+ {
427
+ file_path: notePath,
428
+ relative_path: delivery.note_relative_path,
429
+ original_name: node_path_1.default.basename(delivery.note_relative_path),
430
+ mime_type: "text/markdown",
431
+ size_bytes: Buffer.byteLength(noteContent, "utf8"),
285
432
  },
286
- message: buildTelegramDeliveryNotification({
287
- delivery,
288
- notePath,
289
- copiedArtifacts,
290
- }),
291
- });
292
- }
293
- catch (error) {
294
- runtime.logger.warn("Failed to send Telegram notification for gateway delivery", {
295
- deliveryUuid: delivery.delivery_uuid,
296
- sessionId: targetSession.sessionId,
297
- error: error instanceof Error ? (error.stack ?? error.message) : String(error),
298
- });
433
+ ...delivery.artifacts.map((artifact, index) => ({
434
+ file_path: copiedArtifacts[index] ?? artifact.original_name,
435
+ ...(artifact.relative_path
436
+ ? { relative_path: artifact.relative_path }
437
+ : {}),
438
+ original_name: artifact.original_name,
439
+ ...(artifact.mime_type ? { mime_type: artifact.mime_type } : {}),
440
+ ...(typeof artifact.size_bytes === "number"
441
+ ? { size_bytes: artifact.size_bytes }
442
+ : {}),
443
+ ...(artifact.storage_ref ? { storage_ref: artifact.storage_ref } : {}),
444
+ })),
445
+ ],
446
+ tags: [
447
+ "partner",
448
+ delivery.kind,
449
+ ...(delivery.project_uuid ? ["project"] : ["direct"]),
450
+ ...(delivery.requires_reply ? ["requires-reply"] : []),
451
+ ],
452
+ created_at: delivery.created_at,
453
+ updated_at: delivery.created_at,
454
+ });
455
+ if (targetBinding && !isTelegramHumanSource) {
456
+ try {
457
+ await runtime.telegramTransport.sendNotification({
458
+ sessionId: targetSession.sessionId,
459
+ sessionLabel: delivery.source_session_label,
460
+ recipient: {
461
+ telegramChatId: targetBinding.telegramChatId,
462
+ telegramUserId: targetBinding.telegramUserId,
463
+ },
464
+ message: buildTelegramDeliveryNotification({
465
+ delivery,
466
+ notePath,
467
+ copiedArtifacts,
468
+ }),
469
+ });
470
+ }
471
+ catch (error) {
472
+ runtime.logger.warn("Failed to send Telegram notification for gateway delivery", {
473
+ deliveryUuid: delivery.delivery_uuid,
474
+ sessionId: targetSession.sessionId,
475
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
476
+ });
477
+ }
299
478
  }
300
479
  try {
301
- await runtime.telegramTransport.nudgeSessionPartnerNote(targetSession.sessionId);
480
+ await runtime.telegramTransport.nudgeSessionPartnerNote(targetSession.sessionId, {
481
+ kind: delivery.kind,
482
+ requiresReply: delivery.requires_reply,
483
+ });
302
484
  }
303
485
  catch (error) {
304
- runtime.logger.warn("Failed to nudge tmux after gateway delivery", {
486
+ runtime.logger.warn("Failed to nudge terminal after gateway delivery", {
305
487
  deliveryUuid: delivery.delivery_uuid,
306
488
  sessionId: targetSession.sessionId,
307
489
  error: error instanceof Error ? (error.stack ?? error.message) : String(error),
@@ -276,10 +276,11 @@ const TelegramMcpGatewayRmqService = {
276
276
  throw new Error(`Local Moleculer service '${runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME}' is unavailable`);
277
277
  }
278
278
  this.runtimeService = runtimeService;
279
+ const runtime = await runtimeService.waitUntilReady();
279
280
  if (!this.isEnabled?.()) {
280
281
  this.logger.info("Gateway RMQ is disabled", {
281
- distributedMode: runtimeService.getRuntime().config.distributed.mode,
282
- rmqConfigured: Boolean(runtimeService.getRuntime().config.distributed.rmq?.host),
282
+ distributedMode: runtime.config.distributed.mode,
283
+ rmqConfigured: Boolean(runtime.config.distributed.rmq?.host),
283
284
  });
284
285
  return;
285
286
  }