@deadragdoll/tellymcp 0.0.1

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 (124) hide show
  1. package/.env.example.client +93 -0
  2. package/.env.example.gateway +120 -0
  3. package/CHANGELOG.md +155 -0
  4. package/LICENSE +21 -0
  5. package/README-ru.md +338 -0
  6. package/README.md +1262 -0
  7. package/STANDALONE-ru.md +266 -0
  8. package/STANDALONE.md +266 -0
  9. package/TOOLS.md +1296 -0
  10. package/config/templates/env.both.template +83 -0
  11. package/config/templates/env.client.template +60 -0
  12. package/config/templates/env.gateway.template +82 -0
  13. package/dist/cli.js +636 -0
  14. package/dist/index.js +17 -0
  15. package/dist/lib/logfeed/store.js +52 -0
  16. package/dist/lib/middlewares/tracer.js +172 -0
  17. package/dist/lib/mixins/db.js +267 -0
  18. package/dist/lib/mixins/logfeed.js +34 -0
  19. package/dist/lib/mixins/session.errors.js +142 -0
  20. package/dist/lib/moleculer.js +2 -0
  21. package/dist/lib/trace.js +147 -0
  22. package/dist/lib/traceContext.js +116 -0
  23. package/dist/moleculer.config.js +274 -0
  24. package/dist/services/features/telegram-mcp/approval.service.js +33 -0
  25. package/dist/services/features/telegram-mcp/browser.service.js +42 -0
  26. package/dist/services/features/telegram-mcp/collaboration.service.js +53 -0
  27. package/dist/services/features/telegram-mcp/ensuredb.service.js +337 -0
  28. package/dist/services/features/telegram-mcp/gateway-delivery.service.js +378 -0
  29. package/dist/services/features/telegram-mcp/gateway-loopback.js +10 -0
  30. package/dist/services/features/telegram-mcp/gateway-rmq.service.js +294 -0
  31. package/dist/services/features/telegram-mcp/gateway-socket.service.js +1463 -0
  32. package/dist/services/features/telegram-mcp/gateway.service.js +1141 -0
  33. package/dist/services/features/telegram-mcp/inbox.service.js +33 -0
  34. package/dist/services/features/telegram-mcp/mcp-http.service.js +76 -0
  35. package/dist/services/features/telegram-mcp/mcp-server.service.js +127 -0
  36. package/dist/services/features/telegram-mcp/notify.service.js +33 -0
  37. package/dist/services/features/telegram-mcp/pair.service.js +33 -0
  38. package/dist/services/features/telegram-mcp/runtime.service.js +36 -0
  39. package/dist/services/features/telegram-mcp/session-context.service.js +33 -0
  40. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +103 -0
  41. package/dist/services/features/telegram-mcp/src/app/config/env.js +317 -0
  42. package/dist/services/features/telegram-mcp/src/app/http.js +774 -0
  43. package/dist/services/features/telegram-mcp/src/app/index.js +2 -0
  44. package/dist/services/features/telegram-mcp/src/app/providers/mcp/server.js +13 -0
  45. package/dist/services/features/telegram-mcp/src/app/providers/redis/client.js +18 -0
  46. package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +740 -0
  47. package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +267 -0
  48. package/dist/services/features/telegram-mcp/src/app/webapp/relay.js +69 -0
  49. package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +9 -0
  50. package/dist/services/features/telegram-mcp/src/entities/auth/model/types.js +2 -0
  51. package/dist/services/features/telegram-mcp/src/entities/browser/model/types.js +2 -0
  52. package/dist/services/features/telegram-mcp/src/entities/collaboration/model/types.js +2 -0
  53. package/dist/services/features/telegram-mcp/src/entities/inbox/model/types.js +2 -0
  54. package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +545 -0
  55. package/dist/services/features/telegram-mcp/src/entities/request/model/types.js +2 -0
  56. package/dist/services/features/telegram-mcp/src/entities/session/model/types.js +2 -0
  57. package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +33 -0
  58. package/dist/services/features/telegram-mcp/src/features/browser/model/browserClearLogsTool.js +28 -0
  59. package/dist/services/features/telegram-mcp/src/features/browser/model/browserClickTool.js +28 -0
  60. package/dist/services/features/telegram-mcp/src/features/browser/model/browserCloseTool.js +28 -0
  61. package/dist/services/features/telegram-mcp/src/features/browser/model/browserComputedStyleTool.js +28 -0
  62. package/dist/services/features/telegram-mcp/src/features/browser/model/browserConsoleTool.js +28 -0
  63. package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +28 -0
  64. package/dist/services/features/telegram-mcp/src/features/browser/model/browserErrorsTool.js +28 -0
  65. package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +28 -0
  66. package/dist/services/features/telegram-mcp/src/features/browser/model/browserNetworkFailuresTool.js +28 -0
  67. package/dist/services/features/telegram-mcp/src/features/browser/model/browserOpenTool.js +33 -0
  68. package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +28 -0
  69. package/dist/services/features/telegram-mcp/src/features/browser/model/browserReloadTool.js +28 -0
  70. package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +28 -0
  71. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +689 -0
  72. package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForTool.js +28 -0
  73. package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForUrlTool.js +28 -0
  74. package/dist/services/features/telegram-mcp/src/features/collaboration/model/backend.js +2 -0
  75. package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +26 -0
  76. package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +390 -0
  77. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +102 -0
  78. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +33 -0
  79. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +33 -0
  80. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +69 -0
  81. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +657 -0
  82. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayReplyResolution.js +17 -0
  83. package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +33 -0
  84. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +33 -0
  85. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +33 -0
  86. package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +77 -0
  87. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +93 -0
  88. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +33 -0
  89. package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +33 -0
  90. package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +33 -0
  91. package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +202 -0
  92. package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +33 -0
  93. package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +33 -0
  94. package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +33 -0
  95. package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +33 -0
  96. package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +409 -0
  97. package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +33 -0
  98. package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +33 -0
  99. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +123 -0
  100. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +33 -0
  101. package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +243 -0
  102. package/dist/services/features/telegram-mcp/src/shared/api/storage/contract.js +2 -0
  103. package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/registry.js +8 -0
  104. package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/types.js +2 -0
  105. package/dist/services/features/telegram-mcp/src/shared/api/transport/contract.js +2 -0
  106. package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +86 -0
  107. package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +436 -0
  108. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabSemantics.js +21 -0
  109. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabUi.js +87 -0
  110. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/messageFormat.js +60 -0
  111. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +46 -0
  112. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +6534 -0
  113. package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +280 -0
  114. package/dist/services/features/telegram-mcp/src/shared/lib/ids/ids.js +34 -0
  115. package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +68 -0
  116. package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +223 -0
  117. package/dist/services/features/telegram-mcp/src/shared/lib/redact-secrets/redactSecrets.js +22 -0
  118. package/dist/services/features/telegram-mcp/src/shared/lib/truncate/truncate.js +12 -0
  119. package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +124 -0
  120. package/dist/services/features/telegram-mcp/src/shared/types/common.js +2 -0
  121. package/dist/services/features/telegram-mcp/standalone-http.service.js +113 -0
  122. package/dist/services/features/telegram-mcp/tools-sync.service.js +33 -0
  123. package/package.json +110 -0
  124. package/scripts/postinstall.js +60 -0
@@ -0,0 +1,740 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WEBAPP_APP_JS = exports.WEBAPP_STYLES_CSS = void 0;
4
+ exports.renderWebAppHtml = renderWebAppHtml;
5
+ exports.WEBAPP_STYLES_CSS = `
6
+ :root {
7
+ color-scheme: dark;
8
+ --bg: #0f1115;
9
+ --panel: rgba(18, 22, 30, 0.82);
10
+ --panel-2: #202431;
11
+ --text: #edf1f7;
12
+ --muted: #98a2b3;
13
+ --accent: #57c1ff;
14
+ --success: #4cd964;
15
+ --danger: #ff7474;
16
+ --border: #2b3242;
17
+ --shadow: rgba(0, 0, 0, 0.28);
18
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
19
+ }
20
+
21
+ * { box-sizing: border-box; }
22
+
23
+ html, body {
24
+ margin: 0;
25
+ min-height: 100%;
26
+ background: linear-gradient(180deg, #121620 0%, #0d1017 100%);
27
+ color: var(--text);
28
+ }
29
+
30
+ body {
31
+ padding: 0;
32
+ }
33
+
34
+ .app {
35
+ min-height: 100vh;
36
+ }
37
+
38
+ .toolbar {
39
+ position: fixed;
40
+ left: 0;
41
+ right: 0;
42
+ bottom: calc(42px + env(safe-area-inset-bottom, 0px));
43
+ z-index: 30;
44
+ display: flex;
45
+ justify-content: center;
46
+ flex-wrap: wrap;
47
+ gap: 8px;
48
+ padding: 10px 14px;
49
+ border-top: 1px solid var(--border);
50
+ background: rgba(16, 20, 28, 0.68);
51
+ box-shadow: 0 -18px 40px var(--shadow);
52
+ backdrop-filter: blur(14px);
53
+ }
54
+
55
+ .btn {
56
+ appearance: none;
57
+ border: 1px solid var(--border);
58
+ background: var(--panel-2);
59
+ color: var(--text);
60
+ border-radius: 12px;
61
+ padding: 10px 14px;
62
+ font: inherit;
63
+ cursor: pointer;
64
+ }
65
+
66
+ .btn.compact {
67
+ min-width: 46px;
68
+ padding: 9px 12px;
69
+ text-align: center;
70
+ }
71
+
72
+ .btn:hover { border-color: var(--accent); }
73
+ .btn:disabled { cursor: not-allowed; opacity: 0.55; }
74
+ .btn.danger:hover { border-color: var(--danger); }
75
+
76
+ .statusbar {
77
+ position: fixed;
78
+ left: 0;
79
+ right: 0;
80
+ bottom: 0;
81
+ z-index: 25;
82
+ display: flex;
83
+ flex-wrap: wrap;
84
+ align-items: center;
85
+ justify-content: space-between;
86
+ gap: 8px 16px;
87
+ padding: 10px 14px calc(10px + env(safe-area-inset-bottom, 0px));
88
+ color: var(--muted);
89
+ font-size: 13px;
90
+ background: rgba(14, 17, 24, 0.94);
91
+ border-top: 1px solid var(--border);
92
+ backdrop-filter: blur(16px);
93
+ }
94
+
95
+ .status-left,
96
+ .status-right {
97
+ display: flex;
98
+ flex-wrap: wrap;
99
+ align-items: center;
100
+ gap: 8px 16px;
101
+ }
102
+
103
+ .session-label {
104
+ color: var(--text);
105
+ font-weight: 600;
106
+ }
107
+
108
+ .ok {
109
+ color: var(--success);
110
+ }
111
+
112
+ .terminal {
113
+ margin: 0;
114
+ padding: 18px 14px calc(122px + env(safe-area-inset-bottom, 0px)) 14px;
115
+ min-height: 100vh;
116
+ overflow: auto;
117
+ white-space: pre-wrap;
118
+ word-break: break-word;
119
+ font: 13px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
120
+ }
121
+
122
+ .ansi-bold {
123
+ font-weight: 700;
124
+ }
125
+
126
+ .ansi-underline {
127
+ text-decoration: underline;
128
+ }
129
+
130
+ .error {
131
+ color: var(--danger);
132
+ }
133
+
134
+ @media (max-width: 680px) {
135
+ .toolbar {
136
+ bottom: calc(46px + env(safe-area-inset-bottom, 0px));
137
+ gap: 6px;
138
+ padding: 8px 10px;
139
+ }
140
+
141
+ .btn.compact {
142
+ min-width: 42px;
143
+ padding: 8px 10px;
144
+ }
145
+
146
+ .statusbar {
147
+ font-size: 12px;
148
+ }
149
+
150
+ .terminal {
151
+ padding: 14px 12px calc(146px + env(safe-area-inset-bottom, 0px)) 12px;
152
+ }
153
+ }
154
+ `;
155
+ exports.WEBAPP_APP_JS = `
156
+ const tg = window.Telegram?.WebApp;
157
+ const config = window.__TELEGRAM_MCP_WEBAPP__;
158
+
159
+ const state = {
160
+ token: null,
161
+ sessionId: null,
162
+ timer: null,
163
+ actionBusy: false,
164
+ pollIntervalMs: 2000,
165
+ };
166
+
167
+ const elements = {
168
+ session: document.querySelector("[data-role=session]"),
169
+ status: document.querySelector("[data-role=status]"),
170
+ updated: document.querySelector("[data-role=updated]"),
171
+ esc: document.querySelector("[data-role=escape]"),
172
+ tab: document.querySelector("[data-role=tab]"),
173
+ slash: document.querySelector("[data-role=slash]"),
174
+ del: document.querySelector("[data-role=delete]"),
175
+ up: document.querySelector("[data-role=up]"),
176
+ down: document.querySelector("[data-role=down]"),
177
+ enter: document.querySelector("[data-role=enter]"),
178
+ terminal: document.querySelector("[data-role=terminal]"),
179
+ };
180
+
181
+ function setStatus(text, isError = false) {
182
+ const sessionName = elements.session.textContent || "Live View";
183
+ elements.status.textContent = text + " - " + sessionName;
184
+ elements.status.classList.toggle("error", isError);
185
+ elements.status.classList.toggle("ok", !isError);
186
+ }
187
+
188
+ function setUpdated(text) {
189
+ elements.updated.textContent = text;
190
+ }
191
+
192
+ function formatCapturedAt(value) {
193
+ if (!value) {
194
+ return "never";
195
+ }
196
+
197
+ const date = new Date(value);
198
+ if (Number.isNaN(date.getTime())) {
199
+ return value;
200
+ }
201
+
202
+ return new Intl.DateTimeFormat(undefined, {
203
+ year: "numeric",
204
+ month: "2-digit",
205
+ day: "2-digit",
206
+ hour: "2-digit",
207
+ minute: "2-digit",
208
+ second: "2-digit",
209
+ }).format(date);
210
+ }
211
+
212
+ function escapeHtml(text) {
213
+ return text
214
+ .replace(/&/g, "&")
215
+ .replace(/</g, "&lt;")
216
+ .replace(/>/g, "&gt;");
217
+ }
218
+
219
+ function xtermColor(index) {
220
+ const base = [
221
+ "#000000",
222
+ "#800000",
223
+ "#008000",
224
+ "#808000",
225
+ "#000080",
226
+ "#800080",
227
+ "#008080",
228
+ "#c0c0c0",
229
+ "#808080",
230
+ "#ff0000",
231
+ "#00ff00",
232
+ "#ffff00",
233
+ "#0000ff",
234
+ "#ff00ff",
235
+ "#00ffff",
236
+ "#ffffff",
237
+ ];
238
+
239
+ if (index < 16) {
240
+ return base[index];
241
+ }
242
+
243
+ if (index >= 16 && index <= 231) {
244
+ const value = index - 16;
245
+ const r = Math.floor(value / 36);
246
+ const g = Math.floor((value % 36) / 6);
247
+ const b = value % 6;
248
+ const steps = [0, 95, 135, 175, 215, 255];
249
+ return "rgb(" + steps[r] + "," + steps[g] + "," + steps[b] + ")";
250
+ }
251
+
252
+ if (index >= 232 && index <= 255) {
253
+ const gray = 8 + (index - 232) * 10;
254
+ return "rgb(" + gray + "," + gray + "," + gray + ")";
255
+ }
256
+
257
+ return null;
258
+ }
259
+
260
+ function sgrColor(code, bright) {
261
+ const palette = bright
262
+ ? ["#808080", "#ff6b6b", "#51cf66", "#ffd43b", "#4dabf7", "#da77f2", "#22b8cf", "#ffffff"]
263
+ : ["#000000", "#c92a2a", "#2b8a3e", "#e67700", "#1864ab", "#862e9c", "#0b7285", "#ced4da"];
264
+ const index = code % 10;
265
+ return palette[index] || null;
266
+ }
267
+
268
+ function defaultAnsiState() {
269
+ return {
270
+ fg: null,
271
+ bg: null,
272
+ bold: false,
273
+ underline: false,
274
+ inverse: false,
275
+ };
276
+ }
277
+
278
+ function cloneAnsiState(state) {
279
+ return {
280
+ fg: state.fg,
281
+ bg: state.bg,
282
+ bold: state.bold,
283
+ underline: state.underline,
284
+ inverse: state.inverse,
285
+ };
286
+ }
287
+
288
+ function applySgrCodes(state, codes) {
289
+ const next = cloneAnsiState(state);
290
+ const queue = codes.length ? codes.slice() : [0];
291
+
292
+ while (queue.length > 0) {
293
+ const code = queue.shift();
294
+
295
+ if (code === 0) {
296
+ next.fg = null;
297
+ next.bg = null;
298
+ next.bold = false;
299
+ next.underline = false;
300
+ next.inverse = false;
301
+ continue;
302
+ }
303
+
304
+ if (code === 1) {
305
+ next.bold = true;
306
+ continue;
307
+ }
308
+
309
+ if (code === 22) {
310
+ next.bold = false;
311
+ continue;
312
+ }
313
+
314
+ if (code === 4) {
315
+ next.underline = true;
316
+ continue;
317
+ }
318
+
319
+ if (code === 24) {
320
+ next.underline = false;
321
+ continue;
322
+ }
323
+
324
+ if (code === 7) {
325
+ next.inverse = true;
326
+ continue;
327
+ }
328
+
329
+ if (code === 27) {
330
+ next.inverse = false;
331
+ continue;
332
+ }
333
+
334
+ if (code === 39) {
335
+ next.fg = null;
336
+ continue;
337
+ }
338
+
339
+ if (code === 49) {
340
+ next.bg = null;
341
+ continue;
342
+ }
343
+
344
+ if (code >= 30 && code <= 37) {
345
+ next.fg = sgrColor(code, false);
346
+ continue;
347
+ }
348
+
349
+ if (code >= 90 && code <= 97) {
350
+ next.fg = sgrColor(code, true);
351
+ continue;
352
+ }
353
+
354
+ if (code >= 40 && code <= 47) {
355
+ next.bg = sgrColor(code, false);
356
+ continue;
357
+ }
358
+
359
+ if (code >= 100 && code <= 107) {
360
+ next.bg = sgrColor(code, true);
361
+ continue;
362
+ }
363
+
364
+ if (code === 38 || code === 48) {
365
+ const mode = queue.shift();
366
+ if (mode === 5) {
367
+ const colorIndex = queue.shift();
368
+ const color = typeof colorIndex === "number" ? xtermColor(colorIndex) : null;
369
+ if (code === 38) {
370
+ next.fg = color;
371
+ } else {
372
+ next.bg = color;
373
+ }
374
+ } else if (mode === 2) {
375
+ const r = queue.shift();
376
+ const g = queue.shift();
377
+ const b = queue.shift();
378
+ if (
379
+ typeof r === "number" &&
380
+ typeof g === "number" &&
381
+ typeof b === "number"
382
+ ) {
383
+ const color = "rgb(" + r + "," + g + "," + b + ")";
384
+ if (code === 38) {
385
+ next.fg = color;
386
+ } else {
387
+ next.bg = color;
388
+ }
389
+ }
390
+ }
391
+ }
392
+ }
393
+
394
+ return next;
395
+ }
396
+
397
+ function ansiStateToStyle(state) {
398
+ const fg = state.inverse ? state.bg : state.fg;
399
+ const bg = state.inverse ? state.fg : state.bg;
400
+ const styles = [];
401
+ if (fg) {
402
+ styles.push("color:" + fg);
403
+ }
404
+ if (bg) {
405
+ styles.push("background:" + bg);
406
+ }
407
+ return styles.join(";");
408
+ }
409
+
410
+ function renderAnsiToHtml(text) {
411
+ const pattern = new RegExp("\\\\x1b\\\\[([0-9;]*)m", "g");
412
+ const parts = [];
413
+ let lastIndex = 0;
414
+ let match = null;
415
+ let state = defaultAnsiState();
416
+
417
+ const pushText = (chunk) => {
418
+ if (!chunk) {
419
+ return;
420
+ }
421
+ const escaped = escapeHtml(chunk);
422
+ const classNames = [];
423
+ if (state.bold) {
424
+ classNames.push("ansi-bold");
425
+ }
426
+ if (state.underline) {
427
+ classNames.push("ansi-underline");
428
+ }
429
+ const style = ansiStateToStyle(state);
430
+ if (classNames.length === 0 && !style) {
431
+ parts.push(escaped);
432
+ return;
433
+ }
434
+ const attrs = [];
435
+ if (classNames.length > 0) {
436
+ attrs.push('class="' + classNames.join(" ") + '"');
437
+ }
438
+ if (style) {
439
+ attrs.push('style="' + style + '"');
440
+ }
441
+ parts.push("<span " + attrs.join(" ") + ">" + escaped + "</span>");
442
+ };
443
+
444
+ while ((match = pattern.exec(text)) !== null) {
445
+ pushText(text.slice(lastIndex, match.index));
446
+ const codes = match[1]
447
+ ? match[1]
448
+ .split(";")
449
+ .map((value) => Number.parseInt(value, 10))
450
+ .filter((value) => Number.isFinite(value))
451
+ : [0];
452
+ state = applySgrCodes(state, codes);
453
+ lastIndex = pattern.lastIndex;
454
+ }
455
+
456
+ pushText(text.slice(lastIndex));
457
+ return parts.join("");
458
+ }
459
+
460
+ function trimTrailingSlashes(value) {
461
+ let current = value;
462
+ while (current.endsWith("/") && current.length > 1) {
463
+ current = current.slice(0, -1);
464
+ }
465
+ return current;
466
+ }
467
+
468
+ function getRequestedSessionId() {
469
+ const url = new URL(window.location.href);
470
+ const fromQuery = url.searchParams.get("session");
471
+ if (fromQuery) {
472
+ return fromQuery;
473
+ }
474
+
475
+ const fromHash = new URLSearchParams(url.hash.replace(/^#/, "")).get("session");
476
+ if (fromHash) {
477
+ return fromHash;
478
+ }
479
+
480
+ const pathname = trimTrailingSlashes(url.pathname);
481
+ const basePath = trimTrailingSlashes(config.basePath);
482
+ if (pathname.startsWith(basePath + "/live/")) {
483
+ const suffix = pathname.slice((basePath + "/live/").length).trim();
484
+ if (suffix) {
485
+ return decodeURIComponent(suffix);
486
+ }
487
+ }
488
+
489
+ return null;
490
+ }
491
+
492
+ function getInitData() {
493
+ return tg?.initData || "";
494
+ }
495
+
496
+ function getInitDataUnsafe() {
497
+ return tg?.initDataUnsafe || null;
498
+ }
499
+
500
+ async function bootstrap() {
501
+ const sessionId = getRequestedSessionId();
502
+ const initData = getInitData();
503
+ const initDataUnsafe = getInitDataUnsafe();
504
+
505
+ if (!initDataUnsafe || !initData || !initData.includes("hash=")) {
506
+ throw new Error("Open this page inside Telegram Mini App.");
507
+ }
508
+
509
+ const payload = { initDataRaw: initData, initDataUnsafe };
510
+ if (sessionId) {
511
+ payload.sessionId = sessionId;
512
+ }
513
+
514
+ const response = await fetch(config.basePath + "/api/bootstrap", {
515
+ method: "POST",
516
+ headers: {
517
+ "content-type": "application/json",
518
+ },
519
+ body: JSON.stringify(payload),
520
+ });
521
+
522
+ if (!response.ok) {
523
+ const text = await response.text();
524
+ throw new Error(text || "WebApp bootstrap failed.");
525
+ }
526
+
527
+ return response.json();
528
+ }
529
+
530
+ async function fetchVisibleBuffer() {
531
+ const response = await fetch(config.basePath + "/api/view", {
532
+ method: "GET",
533
+ headers: {
534
+ authorization: "Bearer " + state.token,
535
+ },
536
+ });
537
+
538
+ if (!response.ok) {
539
+ const text = await response.text();
540
+ throw new Error(text || "Failed to fetch visible buffer.");
541
+ }
542
+
543
+ return response.json();
544
+ }
545
+
546
+ async function sendAction(action) {
547
+ if (state.actionBusy || !state.token) {
548
+ return;
549
+ }
550
+
551
+ state.actionBusy = true;
552
+ try {
553
+ const response = await fetch(config.basePath + "/api/action", {
554
+ method: "POST",
555
+ headers: {
556
+ "content-type": "application/json",
557
+ authorization: "Bearer " + state.token,
558
+ },
559
+ body: JSON.stringify({ action }),
560
+ });
561
+
562
+ if (!response.ok) {
563
+ const text = await response.text();
564
+ throw new Error(text || "Failed to send action.");
565
+ }
566
+
567
+ await refreshVisibleBuffer();
568
+ } finally {
569
+ state.actionBusy = false;
570
+ }
571
+ }
572
+
573
+ async function refreshVisibleBuffer() {
574
+ const payload = await fetchVisibleBuffer();
575
+ elements.terminal.innerHTML = renderAnsiToHtml(payload.content || "");
576
+ setUpdated("Updated: " + formatCapturedAt(payload.captured_at));
577
+ }
578
+
579
+ function stopPolling() {
580
+ if (state.timer) {
581
+ clearTimeout(state.timer);
582
+ state.timer = null;
583
+ }
584
+ }
585
+
586
+ function startPolling() {
587
+ stopPolling();
588
+ state.timer = setTimeout(async () => {
589
+ try {
590
+ await refreshVisibleBuffer();
591
+ } catch (error) {
592
+ setStatus(error.message || String(error), true);
593
+ } finally {
594
+ startPolling();
595
+ }
596
+ }, state.pollIntervalMs);
597
+ }
598
+
599
+ function bindUi() {
600
+ elements.esc.addEventListener("click", () => {
601
+ sendAction("escape").catch((error) => setStatus(error.message || String(error), true));
602
+ });
603
+
604
+ elements.tab.addEventListener("click", () => {
605
+ sendAction("tab").catch((error) => setStatus(error.message || String(error), true));
606
+ });
607
+
608
+ elements.slash.addEventListener("click", () => {
609
+ sendAction("slash").catch((error) => setStatus(error.message || String(error), true));
610
+ });
611
+
612
+ elements.del.addEventListener("click", () => {
613
+ sendAction("delete").catch((error) => setStatus(error.message || String(error), true));
614
+ });
615
+
616
+ elements.up.addEventListener("click", () => {
617
+ sendAction("up").catch((error) => setStatus(error.message || String(error), true));
618
+ });
619
+
620
+ elements.down.addEventListener("click", () => {
621
+ sendAction("down").catch((error) => setStatus(error.message || String(error), true));
622
+ });
623
+
624
+ elements.enter.addEventListener("click", () => {
625
+ sendAction("enter").catch((error) => setStatus(error.message || String(error), true));
626
+ });
627
+ }
628
+
629
+ async function applyLaunchMode() {
630
+ tg?.ready?.();
631
+
632
+ if (!tg) {
633
+ return;
634
+ }
635
+
636
+ const launchMode = config?.launchMode || "default";
637
+ if (launchMode === "fullscreen") {
638
+ if (typeof tg.requestFullscreen === "function") {
639
+ try {
640
+ await tg.requestFullscreen();
641
+ return;
642
+ } catch (_error) {
643
+ }
644
+ }
645
+ tg.expand?.();
646
+ return;
647
+ }
648
+
649
+ if (launchMode === "expand") {
650
+ tg.expand?.();
651
+ }
652
+ }
653
+
654
+ async function main() {
655
+ try {
656
+ await applyLaunchMode();
657
+ bindUi();
658
+ setStatus("Authorizing Mini App...");
659
+ const bootstrapPayload = await bootstrap();
660
+ state.token = bootstrapPayload.token;
661
+ state.sessionId = bootstrapPayload.session_id;
662
+ state.pollIntervalMs = bootstrapPayload.poll_interval_ms || state.pollIntervalMs;
663
+ elements.session.textContent =
664
+ bootstrapPayload.session_label || bootstrapPayload.session_id;
665
+
666
+ if (!bootstrapPayload.tmux_target) {
667
+ elements.esc.disabled = true;
668
+ elements.tab.disabled = true;
669
+ elements.slash.disabled = true;
670
+ elements.del.disabled = true;
671
+ elements.up.disabled = true;
672
+ elements.down.disabled = true;
673
+ elements.enter.disabled = true;
674
+ setStatus("No tmux target", true);
675
+ }
676
+
677
+ await refreshVisibleBuffer();
678
+ if (bootstrapPayload.tmux_target) {
679
+ setStatus("Connected");
680
+ }
681
+ startPolling();
682
+ } catch (error) {
683
+ const message = error instanceof Error ? error.message : String(error);
684
+ setStatus(message, true);
685
+ elements.terminal.textContent = message;
686
+ }
687
+ }
688
+
689
+ main();
690
+ `;
691
+ function renderWebAppHtml(input) {
692
+ return `<!doctype html>
693
+ <html lang="en">
694
+ <head>
695
+ <meta charset="utf-8" />
696
+ <meta
697
+ name="viewport"
698
+ content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover"
699
+ />
700
+ <title>Telegram MCP Live View</title>
701
+ <script src="https://telegram.org/js/telegram-web-app.js"></script>
702
+ <link rel="stylesheet" href="${input.basePath}/styles.css" />
703
+ </head>
704
+ <body>
705
+ <div class="app">
706
+ <div class="toolbar">
707
+ <button class="btn compact" data-role="escape" type="button">Esc</button>
708
+ <button class="btn compact" data-role="tab" type="button">Tab</button>
709
+ <button class="btn compact" data-role="slash" type="button">/</button>
710
+ <button class="btn compact" data-role="delete" type="button">⌫</button>
711
+ <button class="btn compact" data-role="up" type="button">↑</button>
712
+ <button class="btn compact" data-role="down" type="button">↓</button>
713
+ <button class="btn compact" data-role="enter" type="button">↵</button>
714
+ </div>
715
+ <pre class="terminal" data-role="terminal">Waiting for tmux buffer…</pre>
716
+ <div class="statusbar">
717
+ <div class="status-left">
718
+ <span data-role="status">Loading… - Live View</span>
719
+ <span class="session-label" data-role="session" hidden>Live View</span>
720
+ </div>
721
+ <div class="status-right">
722
+ <span data-role="updated">Updated: never</span>
723
+ </div>
724
+ </div>
725
+ </div>
726
+ <script>
727
+ window.__TELEGRAM_MCP_WEBAPP__ = ${JSON.stringify({
728
+ basePath: input.basePath,
729
+ launchMode: input.launchMode,
730
+ })};
731
+ </script>
732
+ <script>
733
+ (() => {
734
+ const source = ${JSON.stringify(exports.WEBAPP_APP_JS)};
735
+ (0, eval)(source);
736
+ })();
737
+ </script>
738
+ </body>
739
+ </html>`;
740
+ }