@deadragdoll/tellymcp 0.0.10 โ†’ 0.0.12

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 (154) 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 +226 -376
  5. package/README.md +213 -1184
  6. package/TOOLS.md +320 -377
  7. package/VERSION.md +13 -13
  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 +907 -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 +120 -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/browserOpenTool.js +1 -1
  42. package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
  43. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +306 -26
  44. package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +71 -0
  45. package/dist/services/features/telegram-mcp/src/features/collaboration/model/listGatewaySessionsTool.js +33 -0
  46. package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +93 -82
  47. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +47 -5
  48. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +1 -1
  49. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +1 -1
  50. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +82 -0
  51. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +22 -14
  52. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +697 -75
  53. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +76 -0
  54. package/dist/services/features/telegram-mcp/src/features/embedded-runtime/model/embeddedRuntimeBroker.js +92 -0
  55. package/dist/services/features/telegram-mcp/src/features/foreground-terminal/model/foregroundTerminalRuntime.js +192 -0
  56. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +382 -3
  57. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +1 -1
  58. package/dist/services/features/telegram-mcp/src/features/notify/model/sendFileToTelegramTool.js +33 -0
  59. package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +1 -1
  60. package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +1 -1
  61. package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +1 -1
  62. package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +42 -200
  63. package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +1 -1
  64. package/dist/services/features/telegram-mcp/src/features/terminal-buffer/model/terminalBufferService.js +96 -0
  65. package/dist/services/features/telegram-mcp/src/features/terminal-input/model/terminalInputService.js +97 -0
  66. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +107 -58
  67. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +1 -1
  68. package/dist/services/features/telegram-mcp/src/features/xchange/model/getXchangeRecordTool.js +28 -0
  69. package/dist/services/features/telegram-mcp/src/features/xchange/model/listXchangeRecordsTool.js +28 -0
  70. package/dist/services/features/telegram-mcp/src/features/xchange/model/markXchangeRecordReadTool.js +28 -0
  71. package/dist/services/features/telegram-mcp/src/features/xchange/model/xchangeService.js +169 -0
  72. package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +5 -4
  73. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/en.js +143 -42
  74. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/ru.js +139 -38
  75. package/dist/services/features/telegram-mcp/src/shared/integrations/memory/processLocalSessionStore.js +27 -0
  76. package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +11 -8
  77. package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +69 -70
  78. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +21 -22
  79. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +444 -7093
  80. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportAttachmentStore.js +93 -0
  81. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportBroadcastActions.js +385 -0
  82. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConsoleRegistry.js +149 -0
  83. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConstructorWiring.js +642 -0
  84. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContent.js +84 -0
  85. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContext.js +78 -0
  86. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportDocumentActions.js +36 -0
  87. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportEventActions.js +292 -0
  88. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +352 -0
  89. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFormatting.js +75 -0
  90. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportGatewayActions.js +44 -0
  91. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLifecycleActions.js +161 -0
  92. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLive.js +56 -0
  93. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLiveActions.js +77 -0
  94. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuCallbacks.js +254 -0
  95. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFactories.js +538 -0
  96. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFingerprints.js +93 -0
  97. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFlow.js +344 -0
  98. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuShell.js +65 -0
  99. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuState.js +408 -0
  100. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuText.js +216 -0
  101. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMessageFlow.js +452 -0
  102. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportOutputActions.js +189 -0
  103. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPartnerActions.js +286 -0
  104. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPayloadState.js +108 -0
  105. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectActions.js +463 -0
  106. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEntryActions.js +202 -0
  107. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEvents.js +99 -0
  108. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectMenus.js +138 -0
  109. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectState.js +308 -0
  110. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectView.js +426 -0
  111. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportRequestFlow.js +278 -0
  112. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportSessionActions.js +143 -0
  113. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalActions.js +665 -0
  114. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalRuntime.js +226 -0
  115. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTypes.js +2 -0
  116. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportUtils.js +330 -0
  117. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportXchangeState.js +107 -0
  118. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +255 -0
  119. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +543 -0
  120. package/dist/services/features/telegram-mcp/src/shared/integrations/xchange/sqliteRecordStore.js +223 -0
  121. package/dist/services/features/telegram-mcp/src/shared/lib/gatewayScope.js +24 -0
  122. package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +6 -0
  123. package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +147 -76
  124. package/dist/services/features/telegram-mcp/src/shared/lib/telegramXchangeRecords.js +72 -0
  125. package/dist/services/features/telegram-mcp/src/shared/lib/terminalPromptDetection.js +409 -0
  126. package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +129 -1
  127. package/dist/services/features/telegram-mcp/src/shared/lib/xchangeRecordHints.js +98 -0
  128. package/dist/services/features/telegram-mcp/standalone-http.service.js +12 -0
  129. package/dist/services/features/telegram-mcp/terminal-buffer.service.js +42 -0
  130. package/dist/services/features/telegram-mcp/terminal-input.service.js +41 -0
  131. package/dist/services/features/telegram-mcp/tools-sync.service.js +15 -1
  132. package/dist/services/features/telegram-mcp/xchange.service.js +123 -0
  133. package/docs/STANDALONE-ru.md +172 -0
  134. package/docs/STANDALONE.md +172 -0
  135. package/package.json +10 -5
  136. package/scripts/build-package-artifact.sh +27 -0
  137. package/scripts/deploy-gateway.sh +64 -0
  138. package/scripts/deploy-onebot-branch.sh +27 -0
  139. package/scripts/postinstall.js +11 -36
  140. package/STANDALONE-ru.md +0 -274
  141. package/STANDALONE.md +0 -274
  142. package/dist/services/features/telegram-mcp/inbox.service.js +0 -33
  143. package/dist/services/features/telegram-mcp/pair.service.js +0 -33
  144. package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +0 -10
  145. package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +0 -33
  146. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +0 -33
  147. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +0 -33
  148. package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +0 -77
  149. package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +0 -33
  150. package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +0 -33
  151. package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +0 -202
  152. package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +0 -33
  153. package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +0 -33
  154. package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +0 -363
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransportTerminalRuntime = void 0;
4
+ const grammy_1 = require("grammy");
5
+ const client_1 = require("../terminal/client");
6
+ class TransportTerminalRuntime {
7
+ host;
8
+ terminalPromptScanTimer;
9
+ terminalPromptScanInFlight = false;
10
+ constructor(host) {
11
+ this.host = host;
12
+ }
13
+ get actions() {
14
+ const actions = this.host.terminalActions;
15
+ if (!actions) {
16
+ throw new Error("TransportTerminalRuntime requires terminal actions");
17
+ }
18
+ return actions;
19
+ }
20
+ clearTerminalNudgeDebounceTimers() {
21
+ for (const timer of this.host.terminalNudgeDebounceTimers.values()) {
22
+ clearTimeout(timer);
23
+ }
24
+ this.host.terminalNudgeDebounceTimers.clear();
25
+ }
26
+ startPromptScan() {
27
+ if (!this.host.config.terminal.promptScanEnabled) {
28
+ this.host.logger.debug("terminal prompt scan disabled", {
29
+ promptScanEnabled: this.host.config.terminal.promptScanEnabled,
30
+ });
31
+ return;
32
+ }
33
+ if (this.host.config.distributed.mode === "gateway") {
34
+ this.host.logger.info("terminal prompt scan armed for live clients", {
35
+ intervalSeconds: this.host.config.terminal.promptScanIntervalSeconds,
36
+ cooldownSeconds: this.host.config.terminal.promptScanCooldownSeconds,
37
+ strategy: this.host.config.terminal.promptScanStrategy,
38
+ minScore: this.host.config.terminal.promptScanMinScore,
39
+ });
40
+ return;
41
+ }
42
+ this.ensurePromptScanRunning();
43
+ }
44
+ clearTerminalPromptScanTimer() {
45
+ if (this.terminalPromptScanTimer) {
46
+ clearInterval(this.terminalPromptScanTimer);
47
+ this.terminalPromptScanTimer = undefined;
48
+ }
49
+ }
50
+ ensurePromptScanRunning() {
51
+ if (!this.host.config.terminal.promptScanEnabled) {
52
+ return;
53
+ }
54
+ if (this.terminalPromptScanTimer) {
55
+ return;
56
+ }
57
+ const intervalMs = this.host.config.terminal.promptScanIntervalSeconds * 1000;
58
+ const timer = setInterval(() => {
59
+ void this.runTerminalPromptScanCycle().catch((error) => {
60
+ this.host.logger.warn("terminal prompt scan cycle failed", {
61
+ error: error instanceof Error
62
+ ? (error.stack ?? error.message)
63
+ : String(error),
64
+ });
65
+ });
66
+ }, intervalMs);
67
+ timer.unref();
68
+ this.terminalPromptScanTimer = timer;
69
+ this.host.logger.info("terminal prompt scan scheduled", {
70
+ intervalSeconds: this.host.config.terminal.promptScanIntervalSeconds,
71
+ cooldownSeconds: this.host.config.terminal.promptScanCooldownSeconds,
72
+ strategy: this.host.config.terminal.promptScanStrategy,
73
+ minScore: this.host.config.terminal.promptScanMinScore,
74
+ });
75
+ void this.runTerminalPromptScanCycle().catch((error) => {
76
+ this.host.logger.warn("initial terminal prompt scan failed", {
77
+ error: error instanceof Error
78
+ ? (error.stack ?? error.message)
79
+ : String(error),
80
+ });
81
+ });
82
+ }
83
+ pausePromptScan() {
84
+ if (!this.terminalPromptScanTimer) {
85
+ return;
86
+ }
87
+ this.clearTerminalPromptScanTimer();
88
+ this.host.logger.info("terminal prompt scan paused", {});
89
+ }
90
+ scheduleTerminalNudgeForInboxMessage(sessionId, session) {
91
+ if (!this.host.config.terminal.nudgeEnabled) {
92
+ return;
93
+ }
94
+ if (!session?.terminalTarget) {
95
+ this.host.logger.debug("terminal nudge scheduling skipped for inbox message", {
96
+ sessionId,
97
+ reason: "no_terminal_target",
98
+ });
99
+ return;
100
+ }
101
+ const existingTimer = this.host.terminalNudgeDebounceTimers.get(sessionId);
102
+ if (existingTimer) {
103
+ clearTimeout(existingTimer);
104
+ }
105
+ const timer = setTimeout(() => {
106
+ this.host.terminalNudgeDebounceTimers.delete(sessionId);
107
+ void this.actions
108
+ .nudgeForInboxMessage(sessionId)
109
+ .catch((error) => {
110
+ const payload = {
111
+ sessionId,
112
+ error: error instanceof Error
113
+ ? (error.stack ?? error.message)
114
+ : String(error),
115
+ };
116
+ if ((0, client_1.isTerminalUnavailableError)(error)) {
117
+ void this.host.sessionStore
118
+ .getSession(sessionId)
119
+ .then((currentSession) => {
120
+ if (!currentSession?.terminalTarget) {
121
+ return;
122
+ }
123
+ return this.actions.notifyUnavailable(sessionId, currentSession, error);
124
+ });
125
+ this.host.logger.warn("terminal nudge skipped because terminal is unavailable", payload);
126
+ return;
127
+ }
128
+ this.host.logger.error("terminal nudge failed", payload);
129
+ });
130
+ }, this.host.config.terminal.nudgeDebounceSeconds * 1000);
131
+ timer.unref();
132
+ this.host.terminalNudgeDebounceTimers.set(sessionId, timer);
133
+ this.host.logger.info("terminal nudge scheduled for inbox message", {
134
+ sessionId,
135
+ terminalTarget: session.terminalTarget,
136
+ debounceSeconds: this.host.config.terminal.nudgeDebounceSeconds,
137
+ });
138
+ }
139
+ async sendTypingForSession(sessionId) {
140
+ if (!this.host.isTelegramEnabled()) {
141
+ this.host.logger.debug("Telegram typing skipped because transport is disabled", {
142
+ sessionId,
143
+ });
144
+ return;
145
+ }
146
+ const binding = await this.host.bindingStore.getBinding(sessionId);
147
+ if (!binding) {
148
+ this.host.logger.debug("Telegram typing skipped because session is unbound", {
149
+ sessionId,
150
+ });
151
+ return;
152
+ }
153
+ let attempt = 0;
154
+ while (true) {
155
+ attempt += 1;
156
+ try {
157
+ await this.host.bot.api.sendChatAction(binding.telegramChatId, "typing");
158
+ this.host.logger.debug("Telegram typing action sent", {
159
+ sessionId,
160
+ telegramChatId: binding.telegramChatId,
161
+ telegramUserId: binding.telegramUserId,
162
+ });
163
+ return;
164
+ }
165
+ catch (error) {
166
+ if (!(error instanceof grammy_1.GrammyError) || error.error_code !== 429) {
167
+ throw error;
168
+ }
169
+ const retryAfterSeconds = Math.max(1, error.parameters.retry_after ?? 1);
170
+ this.host.logger.warn("Telegram rate limit hit while sending typing action, cooling down", {
171
+ sessionId,
172
+ telegramChatId: binding.telegramChatId,
173
+ telegramUserId: binding.telegramUserId,
174
+ attempt,
175
+ retryAfterSeconds,
176
+ description: error.description,
177
+ });
178
+ await new Promise((resolve) => setTimeout(resolve, retryAfterSeconds * 1000));
179
+ }
180
+ }
181
+ }
182
+ async runTerminalPromptScanCycle() {
183
+ if (!this.host.config.terminal.promptScanEnabled) {
184
+ this.host.logger.debug("terminal prompt scan cycle skipped", {
185
+ skipReason: "disabled",
186
+ });
187
+ return;
188
+ }
189
+ if (this.terminalPromptScanInFlight) {
190
+ this.host.logger.debug("terminal prompt scan cycle skipped", {
191
+ skipReason: "in_flight",
192
+ });
193
+ return;
194
+ }
195
+ this.terminalPromptScanInFlight = true;
196
+ try {
197
+ if (this.host.ensureGatewayScopedConsolesBoundForPrincipal) {
198
+ const principals = await this.host.bindingStore.listBoundPrincipals();
199
+ this.host.logger.debug("terminal prompt scan syncing bound gateway principals", {
200
+ principalCount: principals.length,
201
+ });
202
+ for (const principal of principals) {
203
+ await this.host.ensureGatewayScopedConsolesBoundForPrincipal(principal);
204
+ }
205
+ }
206
+ const sessions = await this.host.sessionStore.listSessions();
207
+ this.host.logger.debug("terminal prompt scan cycle started", {
208
+ sessionCount: sessions.length,
209
+ });
210
+ if (sessions.length === 0) {
211
+ this.host.logger.debug("terminal prompt scan cycle found no sessions");
212
+ return;
213
+ }
214
+ for (const session of sessions) {
215
+ await this.actions.scanPromptForSession(session);
216
+ }
217
+ this.host.logger.debug("terminal prompt scan cycle completed", {
218
+ sessionCount: sessions.length,
219
+ });
220
+ }
221
+ finally {
222
+ this.terminalPromptScanInFlight = false;
223
+ }
224
+ }
225
+ }
226
+ exports.TransportTerminalRuntime = TransportTerminalRuntime;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,330 @@
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.trimTrailingSlashes = trimTrailingSlashes;
7
+ exports.normalizeBasePath = normalizeBasePath;
8
+ exports.joinHttpPath = joinHttpPath;
9
+ exports.resolveWebAppPublicBaseUrl = resolveWebAppPublicBaseUrl;
10
+ exports.resolveGatewayControlBaseUrl = resolveGatewayControlBaseUrl;
11
+ exports.isMenuEntryCommand = isMenuEntryCommand;
12
+ exports.isHelpCommand = isHelpCommand;
13
+ exports.parseAdminAuthCommand = parseAdminAuthCommand;
14
+ exports.readMenuPayloadKey = readMenuPayloadKey;
15
+ exports.buildDatedRelativePath = buildDatedRelativePath;
16
+ exports.buildPrincipalKey = buildPrincipalKey;
17
+ exports.formatTerminalBridgeError = formatTerminalBridgeError;
18
+ exports.splitLongTelegramText = splitLongTelegramText;
19
+ exports.escapeMarkdownV2 = escapeMarkdownV2;
20
+ exports.escapeMarkdownV2CodeBlock = escapeMarkdownV2CodeBlock;
21
+ exports.escapeHtml = escapeHtml;
22
+ exports.splitTitleAndBody = splitTitleAndBody;
23
+ exports.renderMarkdownChunk = renderMarkdownChunk;
24
+ exports.shouldNudge = shouldNudge;
25
+ exports.slugifyFilenamePart = slugifyFilenamePart;
26
+ exports.formatMenuTimestamp = formatMenuTimestamp;
27
+ exports.normalizeGatewayBaseUrl = normalizeGatewayBaseUrl;
28
+ exports.buildLocalHandoffId = buildLocalHandoffId;
29
+ exports.buildLocalNoteContent = buildLocalNoteContent;
30
+ exports.buildAdminClientTitle = buildAdminClientTitle;
31
+ exports.buildAdminClientButtonLabel = buildAdminClientButtonLabel;
32
+ exports.extractCallbackSuffix = extractCallbackSuffix;
33
+ const node_path_1 = __importDefault(require("node:path"));
34
+ const client_1 = require("../terminal/client");
35
+ function trimTrailingSlashes(value) {
36
+ return value.replace(/\/+$/u, "");
37
+ }
38
+ function normalizeBasePath(value) {
39
+ const trimmed = trimTrailingSlashes(value.trim());
40
+ return trimmed.startsWith("/") ? trimmed || "/" : `/${trimmed || ""}`;
41
+ }
42
+ function joinHttpPath(prefix, suffix) {
43
+ const normalizedPrefix = prefix ? normalizeBasePath(prefix) : "";
44
+ const normalizedSuffix = normalizeBasePath(suffix);
45
+ if (!normalizedPrefix || normalizedPrefix === "/") {
46
+ return normalizedSuffix;
47
+ }
48
+ return `${normalizedPrefix}${normalizedSuffix}`.replace(/\/{2,}/gu, "/");
49
+ }
50
+ function resolveWebAppPublicBaseUrl(config) {
51
+ if (!config.webapp.publicUrl) {
52
+ return null;
53
+ }
54
+ const rootPrefix = normalizeBasePath(process.env.ROOT_PREFIX || "/api");
55
+ const webAppBasePath = normalizeBasePath(config.webapp.basePath || "/webapp");
56
+ const expectedPath = trimTrailingSlashes(`${rootPrefix === "/" ? "" : rootPrefix}${webAppBasePath}`) || "/";
57
+ const url = new URL(config.webapp.publicUrl);
58
+ const currentPath = normalizeBasePath(url.pathname || "/");
59
+ if (currentPath === expectedPath) {
60
+ return trimTrailingSlashes(url.toString());
61
+ }
62
+ if (currentPath === webAppBasePath) {
63
+ url.pathname = expectedPath;
64
+ return trimTrailingSlashes(url.toString());
65
+ }
66
+ if (currentPath.endsWith(webAppBasePath)) {
67
+ url.pathname = expectedPath;
68
+ return trimTrailingSlashes(url.toString());
69
+ }
70
+ url.pathname = expectedPath;
71
+ return trimTrailingSlashes(url.toString());
72
+ }
73
+ function resolveGatewayControlBaseUrl(config) {
74
+ if (config.distributed.mode === "gateway" ||
75
+ config.distributed.mode === "both") {
76
+ const runtimePort = Number(process.env.PORT || config.mcp.httpPort);
77
+ const rootPrefix = normalizeBasePath(process.env.ROOT_PREFIX || "/api");
78
+ const gatewayPath = joinHttpPath(rootPrefix, "/gateway");
79
+ return trimTrailingSlashes(`http://127.0.0.1:${runtimePort}${gatewayPath}`);
80
+ }
81
+ if (!config.distributed.gatewayPublicUrl) {
82
+ return null;
83
+ }
84
+ const url = new URL(config.distributed.gatewayPublicUrl);
85
+ url.pathname = url.pathname.replace(/\/+$/u, "");
86
+ if (!url.pathname.endsWith("/gateway")) {
87
+ url.pathname = `${url.pathname}/gateway`.replace(/\/{2,}/gu, "/");
88
+ }
89
+ return trimTrailingSlashes(url.toString());
90
+ }
91
+ function isMenuEntryCommand(text) {
92
+ return /^\/(?:menu|start)(?:@\w+)?$/i.test(text.trim());
93
+ }
94
+ function isHelpCommand(text) {
95
+ return /^\/help(?:@\w+)?$/i.test(text.trim());
96
+ }
97
+ function parseAdminAuthCommand(text) {
98
+ const match = text.trim().match(/^\/auth(?:@\w+)?(?:\s+(.+))?$/i);
99
+ return match?.[1]?.trim() || null;
100
+ }
101
+ function readMenuPayloadKey(ctx) {
102
+ const payload = ctx.match;
103
+ return typeof payload === "string" && payload.length > 0 ? payload : null;
104
+ }
105
+ function buildDatedRelativePath(fileName, date = new Date()) {
106
+ const dateSegment = date.toISOString().slice(0, 10);
107
+ const timeSegment = date.toTimeString().slice(0, 8).replace(/:/gu, "-");
108
+ return `${dateSegment}/${timeSegment}/${fileName}`;
109
+ }
110
+ function buildPrincipalKey(principal) {
111
+ return `${principal.telegramChatId}:${principal.telegramUserId}`;
112
+ }
113
+ function formatTerminalBridgeError(_config, error, fallback) {
114
+ if ((0, client_1.isTerminalUnavailableError)(error)) {
115
+ return "Terminal runtime is unavailable right now.";
116
+ }
117
+ return fallback;
118
+ }
119
+ function splitLongTelegramText(text, maxChars) {
120
+ const normalized = text.trim();
121
+ if (normalized.length <= maxChars) {
122
+ return [normalized];
123
+ }
124
+ const paragraphs = normalized.split("\n\n");
125
+ const chunks = [];
126
+ let current = "";
127
+ const flush = () => {
128
+ const trimmed = current.trim();
129
+ if (trimmed) {
130
+ chunks.push(trimmed);
131
+ }
132
+ current = "";
133
+ };
134
+ const appendSegment = (segment) => {
135
+ if (!segment) {
136
+ return;
137
+ }
138
+ if (segment.length <= maxChars) {
139
+ const candidate = current ? `${current}\n\n${segment}` : segment;
140
+ if (candidate.length <= maxChars) {
141
+ current = candidate;
142
+ return;
143
+ }
144
+ flush();
145
+ current = segment;
146
+ return;
147
+ }
148
+ flush();
149
+ const lines = segment.split("\n");
150
+ let lineChunk = "";
151
+ for (const line of lines) {
152
+ if (line.length > maxChars) {
153
+ if (lineChunk) {
154
+ chunks.push(lineChunk.trim());
155
+ lineChunk = "";
156
+ }
157
+ for (let index = 0; index < line.length; index += maxChars) {
158
+ chunks.push(line.slice(index, index + maxChars).trim());
159
+ }
160
+ continue;
161
+ }
162
+ const candidate = lineChunk ? `${lineChunk}\n${line}` : line;
163
+ if (candidate.length <= maxChars) {
164
+ lineChunk = candidate;
165
+ }
166
+ else {
167
+ chunks.push(lineChunk.trim());
168
+ lineChunk = line;
169
+ }
170
+ }
171
+ if (lineChunk) {
172
+ current = lineChunk;
173
+ }
174
+ };
175
+ for (const paragraph of paragraphs) {
176
+ appendSegment(paragraph);
177
+ }
178
+ flush();
179
+ return chunks.filter((chunk) => chunk.length > 0);
180
+ }
181
+ function escapeMarkdownV2(text) {
182
+ const specialChars = new Set([
183
+ "_",
184
+ "*",
185
+ "[",
186
+ "]",
187
+ "(",
188
+ ")",
189
+ "~",
190
+ "`",
191
+ ">",
192
+ "#",
193
+ "+",
194
+ "-",
195
+ "=",
196
+ "|",
197
+ "{",
198
+ "}",
199
+ ".",
200
+ "!",
201
+ "\\",
202
+ ]);
203
+ return Array.from(text, (char) => specialChars.has(char) ? `\\${char}` : char).join("");
204
+ }
205
+ function escapeMarkdownV2CodeBlock(text) {
206
+ return text.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
207
+ }
208
+ function escapeHtml(text) {
209
+ return text
210
+ .replace(/&/g, "&amp;")
211
+ .replace(/</g, "&lt;")
212
+ .replace(/>/g, "&gt;");
213
+ }
214
+ function splitTitleAndBody(text) {
215
+ const normalized = text.trim();
216
+ const [firstLine = "", ...rest] = normalized.split("\n");
217
+ const title = firstLine.trim() || "Codex";
218
+ const body = rest.join("\n").trim();
219
+ return {
220
+ title,
221
+ body: body || firstLine.trim(),
222
+ };
223
+ }
224
+ function renderMarkdownChunk(title, body) {
225
+ return `*${escapeMarkdownV2(title)}*\n\n\`\`\`\n${escapeMarkdownV2CodeBlock(body)}\n\`\`\``;
226
+ }
227
+ function shouldNudge(lastNudgeAt, cooldownSeconds, nowMs) {
228
+ if (!lastNudgeAt) {
229
+ return true;
230
+ }
231
+ const lastMs = Date.parse(lastNudgeAt);
232
+ if (Number.isNaN(lastMs)) {
233
+ return true;
234
+ }
235
+ return nowMs - lastMs >= cooldownSeconds * 1000;
236
+ }
237
+ function slugifyFilenamePart(input) {
238
+ return input
239
+ .trim()
240
+ .toLowerCase()
241
+ .replace(/[^a-z0-9]+/g, "-")
242
+ .replace(/^-+|-+$/g, "")
243
+ .slice(0, 48);
244
+ }
245
+ function formatMenuTimestamp(timestamp) {
246
+ if (!timestamp) {
247
+ return null;
248
+ }
249
+ const date = new Date(timestamp);
250
+ if (Number.isNaN(date.getTime())) {
251
+ return null;
252
+ }
253
+ const day = String(date.getDate()).padStart(2, "0");
254
+ const month = String(date.getMonth() + 1).padStart(2, "0");
255
+ const year = date.getFullYear();
256
+ const hours = String(date.getHours()).padStart(2, "0");
257
+ const minutes = String(date.getMinutes()).padStart(2, "0");
258
+ return `${day}.${month}.${year} ${hours}:${minutes}`;
259
+ }
260
+ function normalizeGatewayBaseUrl(value) {
261
+ const url = new URL(value);
262
+ url.pathname = url.pathname.replace(/\/+$/u, "");
263
+ if (!url.pathname.endsWith("/gateway")) {
264
+ url.pathname = `${url.pathname}/gateway`.replace(/\/{2,}/gu, "/");
265
+ }
266
+ return url;
267
+ }
268
+ function buildLocalHandoffId(fileName, now) {
269
+ const timestamp = now.toISOString().replace(/[:.]/gu, "-");
270
+ return `${timestamp}-${slugifyFilenamePart(fileName) || "file-handoff"}`;
271
+ }
272
+ function buildLocalNoteContent(input) {
273
+ return [
274
+ "---",
275
+ `handoff_id: ${JSON.stringify(input.handoffId)}`,
276
+ `kind: "local-file"`,
277
+ `created_at: ${JSON.stringify(input.createdAt)}`,
278
+ `session_id: ${JSON.stringify(input.sessionId)}`,
279
+ `session_label: ${JSON.stringify(input.sessionLabel ?? input.sessionId)}`,
280
+ `artifacts:\n - ${JSON.stringify(input.filePath)}`,
281
+ "---",
282
+ "",
283
+ "# Summary",
284
+ `Local file handoff: ${node_path_1.default.basename(input.filePath)}`,
285
+ "",
286
+ "# Message",
287
+ input.description.trim(),
288
+ "",
289
+ "# Artifacts",
290
+ `- ${input.filePath}`,
291
+ "",
292
+ ].join("\n");
293
+ }
294
+ function buildAdminClientTitle(client) {
295
+ const displayName = client.telegram_display_name?.trim() || "";
296
+ const telegramUsername = client.telegram_username?.trim().replace(/^@/u, "") || "";
297
+ const botUsername = client.bot_username?.trim().replace(/^@/u, "") || "";
298
+ const clientLabel = client.client_label?.trim() || "";
299
+ const namespace = client.namespace?.trim() || "";
300
+ const nodeId = client.node_id?.trim() || "";
301
+ const runtimeLabel = [namespace, nodeId].filter(Boolean).join("/") || nodeId || "";
302
+ const fallback = (clientLabel || runtimeLabel || client.client_uuid).trim();
303
+ const identityParts = [
304
+ displayName || null,
305
+ !displayName && telegramUsername ? `@${telegramUsername}` : null,
306
+ !displayName && !telegramUsername && clientLabel ? clientLabel : null,
307
+ !displayName && !telegramUsername && !clientLabel && runtimeLabel
308
+ ? runtimeLabel
309
+ : null,
310
+ botUsername ? `๐Ÿค–@${botUsername}` : null,
311
+ ].filter(Boolean);
312
+ return identityParts.length > 0 ? identityParts.join(" ยท ") : fallback;
313
+ }
314
+ function buildAdminClientButtonLabel(client) {
315
+ const markers = [
316
+ client.is_connected ? "๐ŸŸข" : null,
317
+ client.is_registered ? "๐Ÿ—‚" : null,
318
+ ]
319
+ .filter(Boolean)
320
+ .join("");
321
+ const prefix = markers ? `${markers} ` : "";
322
+ return `${prefix}${buildAdminClientTitle(client)}`.slice(0, 56);
323
+ }
324
+ function extractCallbackSuffix(ctx, prefix) {
325
+ const data = ctx.callbackQuery?.data;
326
+ if (!data || !data.startsWith(prefix)) {
327
+ return null;
328
+ }
329
+ return data.slice(prefix.length) || null;
330
+ }
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransportXchangeState = void 0;
4
+ const relay_1 = require("../../../app/webapp/relay");
5
+ const client_1 = require("../terminal/client");
6
+ class TransportXchangeState {
7
+ host;
8
+ constructor(host) {
9
+ this.host = host;
10
+ }
11
+ async resolveSessionStorageAccess(sessionId) {
12
+ const trimmed = sessionId.trim();
13
+ if (!trimmed) {
14
+ return { sessionId: trimmed, mode: "meta" };
15
+ }
16
+ const relay = (0, relay_1.parseLiveRelaySessionId)(trimmed);
17
+ if (relay?.localSessionId) {
18
+ const localSession = await this.host.sessionStore.getSession(relay.localSessionId);
19
+ if (localSession?.cwd?.trim()) {
20
+ return { sessionId: relay.localSessionId, mode: "filesystem" };
21
+ }
22
+ return { sessionId: trimmed, mode: "relay" };
23
+ }
24
+ const direct = await this.host.sessionStore.getSession(trimmed);
25
+ if (direct?.cwd?.trim()) {
26
+ return { sessionId: trimmed, mode: "filesystem" };
27
+ }
28
+ return { sessionId: trimmed, mode: "meta" };
29
+ }
30
+ async listActiveSessionFiles(sessionId) {
31
+ const access = await this.resolveSessionStorageAccess(sessionId);
32
+ const metas = access.mode === "filesystem"
33
+ ? await this.listReconciledSessionXchangeMetas(access.sessionId, await this.listSessionFilesystemXchangeFiles(access.sessionId))
34
+ : access.mode === "relay"
35
+ ? await this.listRelaySessionXchangeFileMetas(access.sessionId, "telegram-upload")
36
+ : await this.host.xchangeFileMetaStore.listXchangeFileMetas(access.sessionId);
37
+ const uploadFiles = metas
38
+ .filter((meta) => meta.source === "telegram-upload")
39
+ .map((meta) => meta.filePath);
40
+ return uploadFiles.sort((left, right) => right.localeCompare(left));
41
+ }
42
+ async listActiveSessionStorageEntries(sessionId) {
43
+ const access = await this.resolveSessionStorageAccess(sessionId);
44
+ if (access.mode === "relay") {
45
+ const metas = await this.listRelaySessionXchangeFileMetas(access.sessionId);
46
+ return metas.map((meta) => ({
47
+ filePath: meta.filePath,
48
+ meta,
49
+ }));
50
+ }
51
+ if (access.mode === "meta") {
52
+ const metas = await this.host.xchangeFileMetaStore.listXchangeFileMetas(access.sessionId);
53
+ return metas.map((meta) => ({
54
+ filePath: meta.filePath,
55
+ meta,
56
+ }));
57
+ }
58
+ const filePaths = await this.listSessionFilesystemXchangeFiles(access.sessionId);
59
+ const metas = await this.listReconciledSessionXchangeMetas(access.sessionId, filePaths);
60
+ const metaByPath = new Map(metas.map((meta) => [meta.filePath, meta]));
61
+ return filePaths.map((filePath) => ({
62
+ filePath,
63
+ meta: metaByPath.get(filePath) ?? null,
64
+ }));
65
+ }
66
+ async listActiveSessionScreenshots(sessionId) {
67
+ const access = await this.resolveSessionStorageAccess(sessionId);
68
+ const metas = access.mode === "filesystem"
69
+ ? await this.listReconciledSessionXchangeMetas(access.sessionId, await this.listSessionFilesystemXchangeFiles(access.sessionId))
70
+ : access.mode === "relay"
71
+ ? await this.listRelaySessionXchangeFileMetas(access.sessionId, "browser-screenshot")
72
+ : await this.host.xchangeFileMetaStore.listXchangeFileMetas(access.sessionId);
73
+ const screenshots = metas
74
+ .filter((meta) => meta.source === "browser-screenshot")
75
+ .map((meta) => meta.filePath);
76
+ return screenshots.sort((left, right) => right.localeCompare(left));
77
+ }
78
+ async listSessionFilesystemXchangeFiles(sessionId) {
79
+ const session = await this.host.sessionStore.getSession(sessionId);
80
+ const resolvedWorkspaceDir = session?.cwd?.trim() || "";
81
+ if (!resolvedWorkspaceDir) {
82
+ throw new Error(`Workspace cwd is not registered for console '${sessionId}'.`);
83
+ }
84
+ const files = await (0, client_1.listXchangeFiles)(this.host.config.terminal, resolvedWorkspaceDir, this.host.config.exchange.dir);
85
+ return files.sort((left, right) => right.localeCompare(left));
86
+ }
87
+ async listReconciledSessionXchangeMetas(sessionId, existingFiles) {
88
+ const metas = await this.host.xchangeFileMetaStore.listXchangeFileMetas(sessionId);
89
+ if (metas.length === 0) {
90
+ return [];
91
+ }
92
+ const existingSet = new Set(existingFiles);
93
+ const staleMetas = metas.filter((meta) => !existingSet.has(meta.filePath));
94
+ for (const meta of staleMetas) {
95
+ await this.host.xchangeFileMetaStore.deleteXchangeFileMeta(sessionId, meta.filePath);
96
+ }
97
+ return metas.filter((meta) => existingSet.has(meta.filePath));
98
+ }
99
+ async listRelaySessionXchangeFileMetas(sessionId, source) {
100
+ const output = await this.host.callGatewayJson("/storage/list", {
101
+ session_id: sessionId,
102
+ ...(source ? { source } : {}),
103
+ });
104
+ return Array.isArray(output.metas) ? output.metas : [];
105
+ }
106
+ }
107
+ exports.TransportXchangeState = TransportXchangeState;