@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
@@ -0,0 +1,352 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TransportFileHandoffActions = void 0;
7
+ const node_buffer_1 = require("node:buffer");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const grammy_1 = require("grammy");
10
+ const xchangeRecordHints_1 = require("../../lib/xchangeRecordHints");
11
+ const sqliteRecordStore_1 = require("../xchange/sqliteRecordStore");
12
+ const client_1 = require("../terminal/client");
13
+ const transportUtils_1 = require("./transportUtils");
14
+ class TransportFileHandoffActions {
15
+ host;
16
+ constructor(host) {
17
+ this.host = host;
18
+ }
19
+ async beginModeForTarget(ctx, input) {
20
+ const principal = this.host.getPrincipalFromContext(ctx);
21
+ if (!principal) {
22
+ await ctx.answerCallbackQuery({
23
+ text: "Telegram user or chat is missing.",
24
+ show_alert: true,
25
+ });
26
+ return;
27
+ }
28
+ const session = await this.host.sessionStore.getSession(input.sessionId);
29
+ const meta = await this.host.xchangeFileMetaStore.getXchangeFileMeta(input.sessionId, input.filePath);
30
+ const fileName = meta?.originalName ||
31
+ (meta?.relativePath ? node_path_1.default.basename(meta.relativePath) : undefined) ||
32
+ node_path_1.default.basename(input.filePath);
33
+ const principalKey = (0, transportUtils_1.buildPrincipalKey)(principal);
34
+ const locale = await this.host.resolveLocaleForContext(ctx);
35
+ await ctx.answerCallbackQuery({
36
+ text: this.host.t(locale, "menu:handoff.prompt_title"),
37
+ });
38
+ const sent = await this.host.replyText(ctx, [
39
+ this.host.t(locale, "menu:handoff.prompt_title"),
40
+ "",
41
+ this.host.t(locale, "menu:handoff.route", {
42
+ sourceSessionName: session?.label ?? input.sessionId,
43
+ targetSessionName: input.targetSessionLabel,
44
+ }),
45
+ this.host.t(locale, "menu:handoff.recipient", {
46
+ label: input.targetSessionLabel,
47
+ }),
48
+ this.host.t(locale, "menu:handoff.file", { fileName }),
49
+ "",
50
+ this.host.t(locale, "menu:handoff.prompt_body"),
51
+ this.host.t(locale, "menu:handoff.prompt_hint"),
52
+ ].join("\n"), { kind: "menu", sessionId: input.sessionId }, {
53
+ reply_markup: new grammy_1.InlineKeyboard().text(this.host.t(locale, "menu:handoff.cancel"), "file-handoff-cancel"),
54
+ });
55
+ this.host.pendingFileHandoffs.set(principalKey, {
56
+ sessionId: input.sessionId,
57
+ filePath: input.filePath,
58
+ target: "partner",
59
+ targetSessionId: input.targetSessionId,
60
+ targetSessionLabel: input.targetSessionLabel,
61
+ ...(input.projectUuid ? { projectUuid: input.projectUuid } : {}),
62
+ initiatedAt: new Date().toISOString(),
63
+ ...(sent && "message_id" in sent ? { promptMessageId: sent.message_id } : {}),
64
+ });
65
+ }
66
+ async cancelPending(ctx) {
67
+ const locale = await this.host.resolveLocaleForContext(ctx);
68
+ const principal = this.host.getPrincipalFromContext(ctx);
69
+ if (!principal) {
70
+ await ctx.answerCallbackQuery({
71
+ text: this.host.t(locale, "common:errors.no_telegram_identity"),
72
+ show_alert: true,
73
+ });
74
+ return;
75
+ }
76
+ const principalKey = (0, transportUtils_1.buildPrincipalKey)(principal);
77
+ const pending = this.host.pendingFileHandoffs.get(principalKey);
78
+ if (!pending) {
79
+ await ctx.answerCallbackQuery({
80
+ text: this.host.t(locale, "menu:handoff.no_pending"),
81
+ show_alert: true,
82
+ });
83
+ return;
84
+ }
85
+ this.host.pendingFileHandoffs.delete(principalKey);
86
+ await this.deletePendingPrompt(ctx, pending);
87
+ await ctx.answerCallbackQuery({
88
+ text: this.host.t(locale, "menu:handoff.cancelled"),
89
+ });
90
+ if (pending.projectUuid && pending.targetSessionId && pending.targetSessionLabel) {
91
+ const project = await this.host.getProjectPayloadByUuid(pending.sessionId, pending.projectUuid);
92
+ if (project) {
93
+ await this.host.showProjectMemberDetail(ctx, {
94
+ sessionId: pending.sessionId,
95
+ projectUuid: pending.projectUuid,
96
+ projectName: project.projectName,
97
+ targetSessionId: pending.targetSessionId,
98
+ targetSessionLabel: pending.targetSessionLabel,
99
+ ...(project.inviteToken ? { inviteToken: project.inviteToken } : {}),
100
+ });
101
+ return;
102
+ }
103
+ }
104
+ if (pending.projectUuid) {
105
+ await this.host.showProjectsMenu(ctx);
106
+ return;
107
+ }
108
+ await this.host.showMainMenu(ctx);
109
+ }
110
+ async handlePending(ctx, text) {
111
+ const locale = await this.host.resolveLocaleForContext(ctx);
112
+ const principal = this.host.getPrincipalFromContext(ctx);
113
+ if (!principal) {
114
+ return false;
115
+ }
116
+ const principalKey = (0, transportUtils_1.buildPrincipalKey)(principal);
117
+ const pending = this.host.pendingFileHandoffs.get(principalKey);
118
+ if (!pending) {
119
+ return false;
120
+ }
121
+ if (text.startsWith("/")) {
122
+ this.host.pendingFileHandoffs.delete(principalKey);
123
+ await this.deletePendingPrompt(ctx, pending);
124
+ return false;
125
+ }
126
+ const description = text.trim();
127
+ if (!description) {
128
+ return true;
129
+ }
130
+ if (pending.target === "agent") {
131
+ await this.deliverToAgent({
132
+ principal,
133
+ sessionId: pending.sessionId,
134
+ filePath: pending.filePath,
135
+ sourceTelegramMessageId: ctx.message?.message_id ?? 0,
136
+ description,
137
+ });
138
+ this.host.pendingFileHandoffs.delete(principalKey);
139
+ await this.deletePendingPrompt(ctx, pending);
140
+ await this.host.replyText(ctx, this.host.t(locale, "menu:handoff.delivered_agent"), { kind: "menu", sessionId: pending.sessionId });
141
+ return true;
142
+ }
143
+ if (pending.projectUuid) {
144
+ await this.host.ensureProjectSessionRegistered({
145
+ principal,
146
+ sessionId: pending.sessionId,
147
+ projectUuid: pending.projectUuid,
148
+ });
149
+ }
150
+ const output = await this.deliverToPartner({
151
+ sessionId: pending.sessionId,
152
+ filePath: pending.filePath,
153
+ description,
154
+ ...(pending.targetSessionId ? { targetSessionId: pending.targetSessionId } : {}),
155
+ ...(pending.projectUuid ? { projectUuid: pending.projectUuid } : {}),
156
+ });
157
+ this.host.pendingFileHandoffs.delete(principalKey);
158
+ await this.deletePendingPrompt(ctx, pending);
159
+ const sent = await this.host.replyText(ctx, [
160
+ this.host.t(locale, "menu:handoff.queued_partner"),
161
+ ...(output.project_name
162
+ ? [this.host.t(locale, "menu:handoff.project", { projectName: output.project_name })]
163
+ : []),
164
+ ...(output.target_actor_label
165
+ ? [this.host.t(locale, "menu:handoff.recipient", { label: output.target_actor_label })]
166
+ : []),
167
+ ...(output.target_session_label
168
+ ? [this.host.t(locale, "menu:handoff.session", { label: output.target_session_label })]
169
+ : []),
170
+ this.host.t(locale, "menu:handoff.status", {
171
+ status: output.delivery_status === "delivered"
172
+ ? this.host.t(locale, "menu:handoff.delivered")
173
+ : this.host.t(locale, "menu:handoff.queued"),
174
+ }),
175
+ this.host.t(locale, "menu:handoff.share", { shareId: output.share_id }),
176
+ ].join("\n"), { kind: "menu", sessionId: pending.sessionId });
177
+ if (output.delivery_status === "queued" && sent && "message_id" in sent && ctx.chat) {
178
+ const meta = await this.host.xchangeFileMetaStore.getXchangeFileMeta(pending.sessionId, pending.filePath);
179
+ const fileName = meta?.originalName ||
180
+ (meta?.relativePath ? node_path_1.default.basename(meta.relativePath) : undefined) ||
181
+ node_path_1.default.basename(pending.filePath);
182
+ const handoffSummary = description
183
+ .split(/\r?\n/u)
184
+ .map((line) => line.trim())
185
+ .find(Boolean) ?? `Передача файла: ${fileName}`;
186
+ await this.host.maintenanceStore.setOutgoingDeliveryNotice({
187
+ deliveryUuid: output.inbox_message_id,
188
+ sessionId: pending.sessionId,
189
+ telegramChatId: ctx.chat.id,
190
+ telegramMessageId: sent.message_id,
191
+ shareId: output.share_id,
192
+ kind: output.kind,
193
+ summary: handoffSummary,
194
+ ...(output.project_name ? { projectName: output.project_name } : {}),
195
+ ...(output.target_actor_label
196
+ ? { targetLabel: output.target_actor_label }
197
+ : pending.targetSessionLabel
198
+ ? { targetLabel: pending.targetSessionLabel }
199
+ : {}),
200
+ ...(output.target_session_label ? { targetSessionLabel: output.target_session_label } : {}),
201
+ });
202
+ }
203
+ return true;
204
+ }
205
+ async deliverToPartnerPublic(input) {
206
+ return this.deliverToPartner(input);
207
+ }
208
+ async deletePendingPrompt(ctx, pending) {
209
+ if (!pending.promptMessageId) {
210
+ return;
211
+ }
212
+ try {
213
+ await this.host.deleteMessage(ctx.chat.id, pending.promptMessageId);
214
+ }
215
+ catch (error) {
216
+ this.host.logger.warn("Failed to delete pending file handoff prompt", {
217
+ sessionId: pending.sessionId,
218
+ promptMessageId: pending.promptMessageId,
219
+ target: pending.target,
220
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
221
+ });
222
+ }
223
+ }
224
+ async deliverToAgent(input) {
225
+ const meta = await this.host.xchangeFileMetaStore.getXchangeFileMeta(input.sessionId, input.filePath);
226
+ const session = await this.host.sessionStore.getSession(input.sessionId);
227
+ const fileName = meta?.originalName ||
228
+ (meta?.relativePath ? node_path_1.default.basename(meta.relativePath) : undefined) ||
229
+ node_path_1.default.basename(input.filePath);
230
+ const handoffSummary = input.description
231
+ .split(/\r?\n/u)
232
+ .map((line) => line.trim())
233
+ .find(Boolean) ?? `Локальная передача файла: ${fileName}`;
234
+ const now = new Date();
235
+ const createdAt = now.toISOString();
236
+ const handoffId = (0, transportUtils_1.buildLocalHandoffId)(fileName, now);
237
+ const relativeArtifactPath = `local/files/${handoffId}/${fileName}`;
238
+ const ensuredFilePath = meta?.storageRef
239
+ ? await this.host.objectStore.ensureLocalFile({
240
+ sessionId: input.sessionId,
241
+ session,
242
+ filePath: input.filePath,
243
+ relativePath: relativeArtifactPath,
244
+ storageRef: meta.storageRef,
245
+ source: "partner-artifact",
246
+ })
247
+ : input.filePath;
248
+ const workspaceDir = this.host.objectStore.resolveWorkspaceDir(session);
249
+ const relativeNotePath = `local/${handoffId}.md`;
250
+ const noteContent = (0, transportUtils_1.buildLocalNoteContent)({
251
+ handoffId,
252
+ createdAt,
253
+ sessionId: input.sessionId,
254
+ ...(session?.label ? { sessionLabel: session.label } : {}),
255
+ filePath: ensuredFilePath,
256
+ description: input.description,
257
+ });
258
+ const notePath = await (0, client_1.writeXchangeRelativeFile)(this.host.config.terminal, workspaceDir, this.host.config.exchange.dir, relativeNotePath, node_buffer_1.Buffer.from(noteContent, "utf8"));
259
+ await (0, sqliteRecordStore_1.upsertXchangeRecord)(this.host.config.terminal, workspaceDir, this.host.config.exchange.dir, {
260
+ record_id: handoffId,
261
+ session_id: input.sessionId,
262
+ category: "local_handoff",
263
+ direction: "local",
264
+ status: "new",
265
+ kind: "local-file",
266
+ summary: handoffSummary,
267
+ body_text: noteContent,
268
+ action_desc: (0, xchangeRecordHints_1.buildLocalHandoffActionDesc)(),
269
+ tools: (0, xchangeRecordHints_1.buildLocalHandoffTools)(),
270
+ note_path: notePath,
271
+ note_relative_path: relativeNotePath,
272
+ attachments: [
273
+ {
274
+ file_path: notePath,
275
+ relative_path: relativeNotePath,
276
+ original_name: node_path_1.default.basename(relativeNotePath),
277
+ mime_type: "text/markdown",
278
+ size_bytes: node_buffer_1.Buffer.byteLength(noteContent, "utf8"),
279
+ },
280
+ {
281
+ file_path: ensuredFilePath,
282
+ relative_path: relativeArtifactPath,
283
+ original_name: fileName,
284
+ ...(meta?.mimeType ? { mime_type: meta.mimeType } : {}),
285
+ ...(typeof meta?.sizeBytes === "number" ? { size_bytes: meta.sizeBytes } : {}),
286
+ ...(meta?.storageRef ? { storage_ref: meta.storageRef } : {}),
287
+ },
288
+ ],
289
+ tags: ["local", "handoff", "file"],
290
+ created_at: createdAt,
291
+ updated_at: createdAt,
292
+ });
293
+ try {
294
+ await this.host.nudgeSessionInbox(input.sessionId);
295
+ }
296
+ catch (error) {
297
+ this.host.logger.warn("terminal nudge failed after local agent handoff", {
298
+ sessionId: input.sessionId,
299
+ handoffId,
300
+ filePath: ensuredFilePath,
301
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
302
+ });
303
+ }
304
+ }
305
+ async deliverToPartner(input) {
306
+ const meta = await this.host.xchangeFileMetaStore.getXchangeFileMeta(input.sessionId, input.filePath);
307
+ const session = await this.host.sessionStore.getSession(input.sessionId);
308
+ const fileName = meta?.originalName ||
309
+ (meta?.relativePath ? node_path_1.default.basename(meta.relativePath) : undefined) ||
310
+ node_path_1.default.basename(input.filePath);
311
+ const localFilePath = await this.host.objectStore.ensureLocalFile({
312
+ sessionId: input.sessionId,
313
+ session,
314
+ filePath: input.filePath,
315
+ source: meta?.source ?? "telegram-upload",
316
+ ...(meta?.relativePath ? { relativePath: meta.relativePath } : {}),
317
+ ...(meta?.storageRef ? { storageRef: meta.storageRef } : {}),
318
+ });
319
+ const fileContent = await (0, client_1.readWorkspaceFile)(this.host.config.terminal, this.host.objectStore.resolveWorkspaceDir(session), localFilePath);
320
+ const handoffSummary = input.description
321
+ .split(/\r?\n/u)
322
+ .map((line) => line.trim())
323
+ .find(Boolean) ?? `Передача файла: ${fileName}`;
324
+ return this.host.sendPartnerNote({
325
+ session_id: input.sessionId,
326
+ ...(input.targetSessionId ? { target_session_id: input.targetSessionId } : {}),
327
+ ...(input.projectUuid ? { project_uuid: input.projectUuid } : {}),
328
+ kind: "handoff",
329
+ summary: handoffSummary,
330
+ message: [
331
+ "Partner sent a file for the current task.",
332
+ `File: ${fileName}`,
333
+ "",
334
+ "Description:",
335
+ input.description,
336
+ ...(meta?.caption ? ["", "Caption:", meta.caption] : []),
337
+ ].join("\n"),
338
+ artifacts: [input.filePath],
339
+ artifact_refs: [
340
+ {
341
+ file_path: input.filePath,
342
+ ...(meta?.relativePath ? { relative_path: meta.relativePath } : {}),
343
+ ...(meta?.originalName ? { original_name: meta.originalName } : { original_name: fileName }),
344
+ ...(meta?.mimeType ? { mime_type: meta.mimeType } : {}),
345
+ ...(typeof meta?.sizeBytes === "number" ? { size_bytes: meta.sizeBytes } : {}),
346
+ content_base64: node_buffer_1.Buffer.from(fileContent).toString("base64"),
347
+ },
348
+ ],
349
+ });
350
+ }
351
+ }
352
+ exports.TransportFileHandoffActions = TransportFileHandoffActions;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildAdminClientSessionButtonLabel = buildAdminClientSessionButtonLabel;
7
+ exports.buildAdminClientSessionViewButtonLabel = buildAdminClientSessionViewButtonLabel;
8
+ exports.formatFilePreviewLabel = formatFilePreviewLabel;
9
+ exports.formatStoragePreviewLabel = formatStoragePreviewLabel;
10
+ exports.formatSessionMenuLabel = formatSessionMenuLabel;
11
+ exports.buildInboxText = buildInboxText;
12
+ exports.parsePartnerNoteText = parsePartnerNoteText;
13
+ const node_path_1 = __importDefault(require("node:path"));
14
+ function buildAdminClientSessionButtonLabel(session) {
15
+ const sessionName = (session.label?.trim() || session.local_session_id).trim();
16
+ const projectName = session.project_name?.trim() || null;
17
+ return projectName
18
+ ? `${sessionName} · ${projectName}`.slice(0, 56)
19
+ : sessionName.slice(0, 56);
20
+ }
21
+ function buildAdminClientSessionViewButtonLabel(session) {
22
+ const markers = [
23
+ session.is_connected ? "🟢" : null,
24
+ session.is_collab ? "👥" : null,
25
+ ]
26
+ .filter(Boolean)
27
+ .join("");
28
+ const prefix = markers ? `${markers} ` : "";
29
+ return `${prefix}${buildAdminClientSessionButtonLabel(session)}`.slice(0, 56);
30
+ }
31
+ function formatFilePreviewLabel(filePath, meta) {
32
+ return (meta?.originalName ||
33
+ (meta?.relativePath ? node_path_1.default.basename(meta.relativePath) : undefined) ||
34
+ node_path_1.default.basename(filePath));
35
+ }
36
+ function formatStoragePreviewLabel(filePath, meta) {
37
+ const base = formatFilePreviewLabel(filePath, meta);
38
+ const prefix = meta?.source === "browser-screenshot"
39
+ ? "📸 "
40
+ : meta?.source === "partner-artifact"
41
+ ? "🤝 "
42
+ : "📄 ";
43
+ return `${prefix}${base}`.slice(0, 56);
44
+ }
45
+ function formatSessionMenuLabel(input) {
46
+ const base = input.sessionLabel ?? input.sessionId;
47
+ return `📁 ${base}`;
48
+ }
49
+ function buildInboxText(text, attachments) {
50
+ const lines = [];
51
+ if (text) {
52
+ lines.push(text);
53
+ }
54
+ if (attachments.length > 0) {
55
+ if (lines.length > 0) {
56
+ lines.push("");
57
+ }
58
+ lines.push("Files saved in .mcp-xchange:");
59
+ lines.push(...attachments.map((attachment) => `- ${attachment}`));
60
+ }
61
+ if (lines.length === 0) {
62
+ return "Files uploaded from Telegram.";
63
+ }
64
+ return lines.join("\n");
65
+ }
66
+ function parsePartnerNoteText(text) {
67
+ const normalized = text.trim();
68
+ const lines = normalized.split("\n");
69
+ const summary = lines[0]?.trim() || normalized;
70
+ const body = lines.slice(1).join("\n").replace(/^\s*\n/u, "").trim();
71
+ return {
72
+ summary,
73
+ message: body || normalized,
74
+ };
75
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransportGatewayActions = void 0;
4
+ class TransportGatewayActions {
5
+ host;
6
+ constructor(host) {
7
+ this.host = host;
8
+ }
9
+ async sendPartnerNote(input) {
10
+ const collaborationService = this.host.getCollaborationService();
11
+ if (collaborationService) {
12
+ return collaborationService.sendPartnerNote(input);
13
+ }
14
+ throw new Error("Collaboration service is not configured");
15
+ }
16
+ async ensureGatewayClientUuid(principal, actor) {
17
+ return this.host.projectState.ensureGatewayClientUuid(principal, actor);
18
+ }
19
+ async listGatewayProjects(principal, actor) {
20
+ return this.host.projectState.listGatewayProjects(principal, actor);
21
+ }
22
+ async listGatewayProjectSessions(principal, projectUuid) {
23
+ return this.host.projectState.listGatewayProjectSessions(principal, projectUuid);
24
+ }
25
+ async listGatewaySessionHistory(principal, localSessionId) {
26
+ return this.host.projectState.listGatewaySessionHistory(principal, localSessionId);
27
+ }
28
+ async ensureProjectSessionRegistered(input) {
29
+ await this.host.projectState.ensureProjectSessionRegistered(input);
30
+ }
31
+ async loadProjectsContext(ctx) {
32
+ return this.host.projectState.loadProjectsContext(ctx);
33
+ }
34
+ async activateProjectForSession(input) {
35
+ await this.host.projectState.activateProjectForSession(input);
36
+ }
37
+ async ensureOpenedProjectIsActive(input) {
38
+ await this.host.projectState.ensureOpenedProjectIsActive(input);
39
+ }
40
+ async buildProjectsFingerprint(ctx) {
41
+ return this.host.projectState.buildProjectsFingerprint(ctx);
42
+ }
43
+ }
44
+ exports.TransportGatewayActions = TransportGatewayActions;
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransportLifecycleActions = void 0;
4
+ const versionHandshake_1 = require("../../lib/version/versionHandshake");
5
+ const transportUtils_1 = require("./transportUtils");
6
+ class TransportLifecycleActions {
7
+ host;
8
+ constructor(host) {
9
+ this.host = host;
10
+ }
11
+ async sendStartupNotifications(runtimeDirname) {
12
+ if (!this.host.isTelegramEnabled()) {
13
+ this.host.logger.debug("Startup notifications skipped because Telegram transport is disabled");
14
+ return;
15
+ }
16
+ const packageVersion = (0, versionHandshake_1.getTellyMcpPackageVersion)(runtimeDirname);
17
+ const availableUpdate = await (0, versionHandshake_1.detectAvailablePackageUpdate)({
18
+ currentVersion: packageVersion,
19
+ });
20
+ if (availableUpdate) {
21
+ this.host.logger.warn("A newer TellyMCP package version is available", {
22
+ currentVersion: availableUpdate.currentVersion,
23
+ latestVersion: availableUpdate.latestVersion,
24
+ packageName: versionHandshake_1.TELLYMCP_PACKAGE_NAME,
25
+ });
26
+ }
27
+ const sessions = await this.host.sessionStore.listSessions();
28
+ const groupedRecipients = new Map();
29
+ for (const session of sessions) {
30
+ const binding = await this.host.bindingStore.getBinding(session.sessionId);
31
+ if (!binding) {
32
+ continue;
33
+ }
34
+ const key = `${binding.telegramChatId}:${binding.telegramUserId}`;
35
+ const current = groupedRecipients.get(key);
36
+ if (current) {
37
+ current.sessionIds.push(session.sessionId);
38
+ current.sessionLabels.push(session.label ?? session.sessionId);
39
+ continue;
40
+ }
41
+ groupedRecipients.set(key, {
42
+ binding: {
43
+ telegramChatId: binding.telegramChatId,
44
+ telegramUserId: binding.telegramUserId,
45
+ },
46
+ sessionIds: [session.sessionId],
47
+ sessionLabels: [session.label ?? session.sessionId],
48
+ });
49
+ }
50
+ if (groupedRecipients.size === 0) {
51
+ this.host.logger.info("Skipping startup notifications because no sessions have an active Telegram route");
52
+ return;
53
+ }
54
+ const runtimePort = this.host.config.distributed.mode === "gateway" ||
55
+ this.host.config.distributed.mode === "both"
56
+ ? Number(process.env.PORT || this.host.config.mcp.httpPort)
57
+ : this.host.config.mcp.httpPort;
58
+ const rootPrefix = this.host.config.distributed.mode === "gateway" ||
59
+ this.host.config.distributed.mode === "both"
60
+ ? (0, transportUtils_1.normalizeBasePath)(process.env.ROOT_PREFIX || "/api")
61
+ : "";
62
+ const localMcpPath = this.host.config.distributed.mode === "gateway" ||
63
+ this.host.config.distributed.mode === "both"
64
+ ? (0, transportUtils_1.joinHttpPath)(rootPrefix, this.host.config.mcp.httpPath)
65
+ : this.host.config.mcp.httpPath;
66
+ const localWebappPath = this.host.config.distributed.mode === "gateway" ||
67
+ this.host.config.distributed.mode === "both"
68
+ ? (0, transportUtils_1.joinHttpPath)(rootPrefix, this.host.config.webapp.basePath)
69
+ : this.host.config.webapp.basePath;
70
+ const localMcpUrl = `http://${this.host.config.mcp.httpHost}:${runtimePort}${localMcpPath}`;
71
+ const localWebappUrl = `http://${this.host.config.mcp.httpHost}:${runtimePort}${localWebappPath}`;
72
+ for (const recipientGroup of groupedRecipients.values()) {
73
+ const primarySessionId = recipientGroup.sessionIds[0];
74
+ if (!primarySessionId) {
75
+ continue;
76
+ }
77
+ const locale = await this.host.resolveLocaleForTelegramUserId(recipientGroup.binding.telegramUserId);
78
+ const uniqueSessionLabels = Array.from(new Set(recipientGroup.sessionLabels)).sort();
79
+ const browserStatus = this.host.config.browser.enabled
80
+ ? (this.host.config.browser.headless ? "enabled, headless" : "enabled, headed")
81
+ : "disabled";
82
+ const startupMessage = [
83
+ this.host.t(locale, "menu:notices.startup.title"),
84
+ this.host.t(locale, "menu:notices.startup.version", {
85
+ packageVersion,
86
+ }),
87
+ this.host.t(locale, "menu:notices.startup.protocol", {
88
+ protocolVersion: versionHandshake_1.TELLYMCP_PROTOCOL_VERSION,
89
+ }),
90
+ this.host.t(locale, "menu:notices.startup.mode", {
91
+ mode: this.host.config.distributed.mode,
92
+ }),
93
+ ...(this.host.config.telegram.botUsername
94
+ ? [
95
+ this.host.t(locale, "menu:notices.startup.bot", {
96
+ botUsername: this.host.config.telegram.botUsername.replace(/^@/u, ""),
97
+ }),
98
+ ]
99
+ : []),
100
+ this.host.t(locale, "menu:notices.startup.sessions", {
101
+ count: uniqueSessionLabels.length,
102
+ }),
103
+ this.host.t(locale, "menu:notices.startup.session_list", {
104
+ sessions: uniqueSessionLabels.join(", "),
105
+ }),
106
+ this.host.t(locale, "menu:notices.startup.mcp", {
107
+ url: localMcpUrl,
108
+ }),
109
+ ...(this.host.config.webapp.enabled
110
+ ? [this.host.t(locale, "menu:notices.startup.webapp", { url: localWebappUrl })]
111
+ : []),
112
+ ...(this.host.config.distributed.gatewayPublicUrl
113
+ ? [
114
+ this.host.t(locale, "menu:notices.startup.gateway", {
115
+ url: this.host.config.distributed.gatewayPublicUrl,
116
+ }),
117
+ ]
118
+ : []),
119
+ ...(this.host.config.distributed.gatewayWsUrl
120
+ ? [
121
+ this.host.t(locale, "menu:notices.startup.gateway_ws", {
122
+ url: this.host.config.distributed.gatewayWsUrl,
123
+ }),
124
+ ]
125
+ : []),
126
+ this.host.t(locale, "menu:notices.startup.browser", {
127
+ status: browserStatus,
128
+ }),
129
+ ...(availableUpdate
130
+ ? [
131
+ this.host.t(locale, "menu:notices.startup.update_available", {
132
+ currentVersion: availableUpdate.currentVersion,
133
+ latestVersion: availableUpdate.latestVersion,
134
+ }),
135
+ this.host.t(locale, "menu:notices.startup.update_command", {
136
+ packageName: versionHandshake_1.TELLYMCP_PACKAGE_NAME,
137
+ latestVersion: availableUpdate.latestVersion,
138
+ }),
139
+ ]
140
+ : []),
141
+ this.host.t(locale, "menu:notices.startup.hint"),
142
+ ].join("\n");
143
+ try {
144
+ await this.host.sendNotification({
145
+ sessionId: primarySessionId,
146
+ sessionLabel: "TellyMCP",
147
+ recipient: recipientGroup.binding,
148
+ message: startupMessage,
149
+ });
150
+ }
151
+ catch (error) {
152
+ this.host.logger.warn("Failed to deliver Telegram startup notification", {
153
+ telegramChatId: recipientGroup.binding.telegramChatId,
154
+ telegramUserId: recipientGroup.binding.telegramUserId,
155
+ error: error instanceof Error ? error.message : String(error),
156
+ });
157
+ }
158
+ }
159
+ }
160
+ }
161
+ exports.TransportLifecycleActions = TransportLifecycleActions;