@deadragdoll/tellymcp 0.0.12 → 0.0.13
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.
- package/README-ru.md +19 -0
- package/README.md +19 -0
- package/TOOLS.md +206 -3
- package/dist/cli.js +109 -1
- package/dist/services/features/telegram-mcp/browser.service.js +38 -1
- package/dist/services/features/telegram-mcp/mcp-server.service.js +12 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +14 -0
- package/dist/services/features/telegram-mcp/src/app/config/env.js +13 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +147 -2
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClickTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserInjectScriptTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStartTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStatusTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStopTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +485 -1
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +502 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +79 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +559 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +28 -0
- package/docs/STANDALONE-ru.md +42 -6
- package/docs/STANDALONE.md +42 -6
- package/package.json +6 -3
- package/packages/chrome-attach-extension/dist/background.js +1326 -0
- package/packages/chrome-attach-extension/dist/icon.svg +6 -0
- package/packages/chrome-attach-extension/dist/manifest.json +36 -0
- package/packages/chrome-attach-extension/dist/options.html +312 -0
- package/packages/chrome-attach-extension/dist/options.js +593 -0
- package/packages/chrome-attach-extension/dist/popup.html +93 -0
- package/packages/chrome-attach-extension/dist/popup.js +79 -0
- package/packages/chrome-attach-extension/dist/recorder-content.js +83 -0
- package/packages/chrome-attach-extension/dist/recorder-page.js +266 -0
- package/packages/firefox-attach-extension/README.md +13 -0
- package/packages/firefox-attach-extension/dist/background.js +1242 -0
- package/packages/firefox-attach-extension/dist/icon.svg +6 -0
- package/packages/firefox-attach-extension/dist/manifest.json +56 -0
- package/packages/firefox-attach-extension/dist/options.html +312 -0
- package/packages/firefox-attach-extension/dist/options.js +527 -0
- package/packages/firefox-attach-extension/dist/popup.html +93 -0
- package/packages/firefox-attach-extension/dist/popup.js +64 -0
- package/packages/firefox-attach-extension/dist/recorder-content.js +77 -0
- package/packages/firefox-attach-extension/dist/recorder-page.js +302 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
if (window.__tellyRecorderContentInstalled === true) {
|
|
3
|
+
return;
|
|
4
|
+
}
|
|
5
|
+
window.__tellyRecorderContentInstalled = true;
|
|
6
|
+
|
|
7
|
+
function emit(payload) {
|
|
8
|
+
try {
|
|
9
|
+
browser.runtime.sendMessage({
|
|
10
|
+
type: "telly_recording_page_event",
|
|
11
|
+
event: payload,
|
|
12
|
+
});
|
|
13
|
+
} catch {
|
|
14
|
+
// ignore
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function snapshot(reason) {
|
|
19
|
+
if (window.top !== window) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
emit({
|
|
23
|
+
kind: "page_snapshot",
|
|
24
|
+
source: "content",
|
|
25
|
+
reason,
|
|
26
|
+
at: new Date().toISOString(),
|
|
27
|
+
url: location.href,
|
|
28
|
+
title: document.title,
|
|
29
|
+
ready_state: document.readyState,
|
|
30
|
+
html: document.documentElement?.outerHTML || "",
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
window.addEventListener("message", (event) => {
|
|
35
|
+
if (event.source !== window) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!event.data || event.data.__tellyRecorderPageEvent !== true) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
emit(event.data.payload);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const injection = document.createElement("script");
|
|
45
|
+
injection.src = browser.runtime.getURL("recorder-page.js");
|
|
46
|
+
injection.async = false;
|
|
47
|
+
(document.documentElement || document.head || document.body).appendChild(injection);
|
|
48
|
+
injection.addEventListener(
|
|
49
|
+
"load",
|
|
50
|
+
() => {
|
|
51
|
+
injection.remove();
|
|
52
|
+
},
|
|
53
|
+
{ once: true },
|
|
54
|
+
);
|
|
55
|
+
injection.addEventListener(
|
|
56
|
+
"error",
|
|
57
|
+
() => {
|
|
58
|
+
emit({
|
|
59
|
+
kind: "console_event",
|
|
60
|
+
source: "content",
|
|
61
|
+
level: "error",
|
|
62
|
+
text: "Failed to load recorder-page.js",
|
|
63
|
+
url: location.href,
|
|
64
|
+
title: document.title,
|
|
65
|
+
});
|
|
66
|
+
injection.remove();
|
|
67
|
+
},
|
|
68
|
+
{ once: true },
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
snapshot("recording-script-installed");
|
|
72
|
+
if (window.top === window) {
|
|
73
|
+
window.addEventListener("load", () => {
|
|
74
|
+
snapshot("window-load");
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
})();
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
if (window.__tellyRecorderPageInstalled === true) {
|
|
3
|
+
return;
|
|
4
|
+
}
|
|
5
|
+
window.__tellyRecorderPageInstalled = true;
|
|
6
|
+
|
|
7
|
+
const MAX_TEXT_CHARS = 64 * 1024;
|
|
8
|
+
const truncateText = (value) => {
|
|
9
|
+
const text = String(value ?? "");
|
|
10
|
+
return text.length > MAX_TEXT_CHARS ? text.slice(0, MAX_TEXT_CHARS) : text;
|
|
11
|
+
};
|
|
12
|
+
const serializeValue = (value, depth = 0) => {
|
|
13
|
+
if (depth >= 2) return truncateText(value);
|
|
14
|
+
if (value === null || value === undefined) return value;
|
|
15
|
+
if (typeof value === "string") return truncateText(value);
|
|
16
|
+
if (typeof value === "number" || typeof value === "boolean") return value;
|
|
17
|
+
if (value instanceof Error) {
|
|
18
|
+
return {
|
|
19
|
+
name: value.name,
|
|
20
|
+
message: truncateText(value.message),
|
|
21
|
+
stack: truncateText(value.stack || ""),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return value.slice(0, 20).map((item) => serializeValue(item, depth + 1));
|
|
26
|
+
}
|
|
27
|
+
if (typeof value === "object") {
|
|
28
|
+
const output = {};
|
|
29
|
+
for (const [key, nested] of Object.entries(value).slice(0, 20)) {
|
|
30
|
+
output[key] = serializeValue(nested, depth + 1);
|
|
31
|
+
}
|
|
32
|
+
return output;
|
|
33
|
+
}
|
|
34
|
+
return truncateText(value);
|
|
35
|
+
};
|
|
36
|
+
const emit = (payload) => {
|
|
37
|
+
window.postMessage({ __tellyRecorderPageEvent: true, payload }, "*");
|
|
38
|
+
};
|
|
39
|
+
const emitConsole = (level, args, textOverride) => {
|
|
40
|
+
emit({
|
|
41
|
+
kind: "console_event",
|
|
42
|
+
source: "page",
|
|
43
|
+
at: new Date().toISOString(),
|
|
44
|
+
level,
|
|
45
|
+
text:
|
|
46
|
+
textOverride ||
|
|
47
|
+
truncateText(
|
|
48
|
+
args
|
|
49
|
+
.map((item) => {
|
|
50
|
+
if (typeof item === "string") return item;
|
|
51
|
+
try {
|
|
52
|
+
return JSON.stringify(item);
|
|
53
|
+
} catch {
|
|
54
|
+
return String(item);
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
.join(" "),
|
|
58
|
+
),
|
|
59
|
+
args: args.map((item) => serializeValue(item)),
|
|
60
|
+
url: location.href,
|
|
61
|
+
title: document.title,
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
const headersToArray = (headers) => {
|
|
65
|
+
try {
|
|
66
|
+
return Array.from(headers.entries()).map(([name, value]) => ({ name, value }));
|
|
67
|
+
} catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const serializeRequestBody = async (request) => {
|
|
72
|
+
try {
|
|
73
|
+
const text = await request.clone().text();
|
|
74
|
+
if (!text) return { body_text: "" };
|
|
75
|
+
return {
|
|
76
|
+
body_text: truncateText(text),
|
|
77
|
+
body_truncated: text.length > MAX_TEXT_CHARS,
|
|
78
|
+
};
|
|
79
|
+
} catch {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
for (const level of [
|
|
85
|
+
"log",
|
|
86
|
+
"info",
|
|
87
|
+
"warn",
|
|
88
|
+
"error",
|
|
89
|
+
"debug",
|
|
90
|
+
"trace",
|
|
91
|
+
"dir",
|
|
92
|
+
"dirxml",
|
|
93
|
+
"table",
|
|
94
|
+
]) {
|
|
95
|
+
const original = console[level];
|
|
96
|
+
if (typeof original !== "function") {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
console[level] = function patchedConsole(...args) {
|
|
100
|
+
try {
|
|
101
|
+
const textOverride =
|
|
102
|
+
level === "trace"
|
|
103
|
+
? truncateText(new Error(args[0] ? String(args[0]) : "console.trace").stack || "")
|
|
104
|
+
: undefined;
|
|
105
|
+
emitConsole(level, args, textOverride);
|
|
106
|
+
} catch {
|
|
107
|
+
// ignore
|
|
108
|
+
}
|
|
109
|
+
return original.apply(this, args);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (typeof console.assert === "function") {
|
|
114
|
+
const originalAssert = console.assert;
|
|
115
|
+
console.assert = function patchedAssert(condition, ...args) {
|
|
116
|
+
try {
|
|
117
|
+
if (!condition) {
|
|
118
|
+
emitConsole("assert", args, truncateText(args[0] ? String(args[0]) : "Assertion failed"));
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
// ignore
|
|
122
|
+
}
|
|
123
|
+
return originalAssert.call(this, condition, ...args);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
window.addEventListener("error", (event) => {
|
|
128
|
+
emit({
|
|
129
|
+
kind: "console_event",
|
|
130
|
+
source: "page",
|
|
131
|
+
at: new Date().toISOString(),
|
|
132
|
+
level: "error",
|
|
133
|
+
text: truncateText(event.message || "window error"),
|
|
134
|
+
args: [
|
|
135
|
+
{
|
|
136
|
+
filename: event.filename || "",
|
|
137
|
+
lineno: event.lineno || 0,
|
|
138
|
+
colno: event.colno || 0,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
url: location.href,
|
|
142
|
+
title: document.title,
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
147
|
+
emit({
|
|
148
|
+
kind: "console_event",
|
|
149
|
+
source: "page",
|
|
150
|
+
at: new Date().toISOString(),
|
|
151
|
+
level: "error",
|
|
152
|
+
text: "Unhandled promise rejection",
|
|
153
|
+
args: [serializeValue(event.reason)],
|
|
154
|
+
url: location.href,
|
|
155
|
+
title: document.title,
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const originalFetch = window.fetch.bind(window);
|
|
160
|
+
window.fetch = async (...args) => {
|
|
161
|
+
const startedAt = new Date().toISOString();
|
|
162
|
+
const request = new Request(...args);
|
|
163
|
+
const requestId = `page-fetch-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
164
|
+
const body = await serializeRequestBody(request);
|
|
165
|
+
emit({
|
|
166
|
+
kind: "network_request",
|
|
167
|
+
source: "page",
|
|
168
|
+
at: startedAt,
|
|
169
|
+
request_id: requestId,
|
|
170
|
+
url: request.url,
|
|
171
|
+
method: request.method,
|
|
172
|
+
resource_type: "fetch",
|
|
173
|
+
headers: headersToArray(request.headers),
|
|
174
|
+
...body,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const response = await originalFetch(...args);
|
|
178
|
+
emit({
|
|
179
|
+
kind: "network_response_complete",
|
|
180
|
+
source: "page",
|
|
181
|
+
at: new Date().toISOString(),
|
|
182
|
+
request_id: requestId,
|
|
183
|
+
url: request.url,
|
|
184
|
+
method: request.method,
|
|
185
|
+
resource_type: "fetch",
|
|
186
|
+
status_code: response.status,
|
|
187
|
+
headers: headersToArray(response.headers),
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
const bodyText = await response.clone().text();
|
|
192
|
+
emit({
|
|
193
|
+
kind: "network_response_body",
|
|
194
|
+
source: "page",
|
|
195
|
+
at: new Date().toISOString(),
|
|
196
|
+
request_id: requestId,
|
|
197
|
+
url: request.url,
|
|
198
|
+
body_text: truncateText(bodyText),
|
|
199
|
+
body_truncated: bodyText.length > MAX_TEXT_CHARS,
|
|
200
|
+
});
|
|
201
|
+
} catch {
|
|
202
|
+
// ignore
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return response;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const originalOpen = XMLHttpRequest.prototype.open;
|
|
209
|
+
const originalSend = XMLHttpRequest.prototype.send;
|
|
210
|
+
const originalSetHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
211
|
+
XMLHttpRequest.prototype.open = function patchedOpen(method, url, async, user, password) {
|
|
212
|
+
this.__tellyRecorder = {
|
|
213
|
+
request_id: `page-xhr-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`,
|
|
214
|
+
method: String(method || "GET"),
|
|
215
|
+
url: String(url || ""),
|
|
216
|
+
headers: [],
|
|
217
|
+
};
|
|
218
|
+
return originalOpen.call(this, method, url, async, user, password);
|
|
219
|
+
};
|
|
220
|
+
XMLHttpRequest.prototype.setRequestHeader = function patchedSetHeader(name, value) {
|
|
221
|
+
if (this.__tellyRecorder?.headers) {
|
|
222
|
+
this.__tellyRecorder.headers.push({ name: String(name), value: String(value) });
|
|
223
|
+
}
|
|
224
|
+
return originalSetHeader.call(this, name, value);
|
|
225
|
+
};
|
|
226
|
+
XMLHttpRequest.prototype.send = function patchedSend(body) {
|
|
227
|
+
const startedAt = new Date().toISOString();
|
|
228
|
+
const meta = this.__tellyRecorder || {
|
|
229
|
+
request_id: `page-xhr-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`,
|
|
230
|
+
method: "GET",
|
|
231
|
+
url: "",
|
|
232
|
+
headers: [],
|
|
233
|
+
};
|
|
234
|
+
const bodyText =
|
|
235
|
+
typeof body === "string"
|
|
236
|
+
? body
|
|
237
|
+
: body instanceof URLSearchParams
|
|
238
|
+
? body.toString()
|
|
239
|
+
: body instanceof FormData
|
|
240
|
+
? Array.from(body.entries())
|
|
241
|
+
.map(([k, v]) => `${String(k)}=${String(v)}`)
|
|
242
|
+
.join("&")
|
|
243
|
+
: "";
|
|
244
|
+
emit({
|
|
245
|
+
kind: "network_request",
|
|
246
|
+
source: "page",
|
|
247
|
+
at: startedAt,
|
|
248
|
+
request_id: meta.request_id,
|
|
249
|
+
url: meta.url,
|
|
250
|
+
method: meta.method,
|
|
251
|
+
resource_type: "xmlhttprequest",
|
|
252
|
+
headers: meta.headers,
|
|
253
|
+
body_text: truncateText(bodyText),
|
|
254
|
+
body_truncated: bodyText.length > MAX_TEXT_CHARS,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
this.addEventListener(
|
|
258
|
+
"loadend",
|
|
259
|
+
() => {
|
|
260
|
+
const headersRaw = this.getAllResponseHeaders() || "";
|
|
261
|
+
const headers = headersRaw
|
|
262
|
+
.split(/\r?\n/)
|
|
263
|
+
.map((line) => line.trim())
|
|
264
|
+
.filter(Boolean)
|
|
265
|
+
.map((line) => {
|
|
266
|
+
const separatorIndex = line.indexOf(":");
|
|
267
|
+
return separatorIndex <= 0
|
|
268
|
+
? { name: line, value: "" }
|
|
269
|
+
: {
|
|
270
|
+
name: line.slice(0, separatorIndex).trim(),
|
|
271
|
+
value: line.slice(separatorIndex + 1).trim(),
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
emit({
|
|
275
|
+
kind: "network_response_complete",
|
|
276
|
+
source: "page",
|
|
277
|
+
at: new Date().toISOString(),
|
|
278
|
+
request_id: meta.request_id,
|
|
279
|
+
url: meta.url,
|
|
280
|
+
method: meta.method,
|
|
281
|
+
resource_type: "xmlhttprequest",
|
|
282
|
+
status_code: this.status,
|
|
283
|
+
headers,
|
|
284
|
+
});
|
|
285
|
+
if (typeof this.responseText === "string") {
|
|
286
|
+
emit({
|
|
287
|
+
kind: "network_response_body",
|
|
288
|
+
source: "page",
|
|
289
|
+
at: new Date().toISOString(),
|
|
290
|
+
request_id: meta.request_id,
|
|
291
|
+
url: meta.url,
|
|
292
|
+
body_text: truncateText(this.responseText),
|
|
293
|
+
body_truncated: this.responseText.length > MAX_TEXT_CHARS,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
{ once: true },
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
return originalSend.call(this, body);
|
|
301
|
+
};
|
|
302
|
+
})();
|