@deadragdoll/tellymcp 0.0.13 → 0.0.14
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/.env.example.client +5 -1
- package/.env.example.gateway +16 -1
- package/CHANGELOG.md +30 -0
- package/README-ru.md +14 -0
- package/README.md +14 -0
- package/TOOLS.md +182 -10
- package/config/templates/env.both.template +15 -2
- package/config/templates/env.client.template +5 -2
- package/config/templates/env.gateway.template +15 -2
- package/dist/cli.js +28 -1
- package/dist/services/features/telegram-mcp/browser.service.js +18 -0
- package/dist/services/features/telegram-mcp/file-content.service.js +94 -0
- package/dist/services/features/telegram-mcp/gateway-delivery.service.js +5 -1
- package/dist/services/features/telegram-mcp/gateway-socket.service.js +43 -11
- package/dist/services/features/telegram-mcp/mcp-http.service.js +1 -0
- package/dist/services/features/telegram-mcp/mcp-server.service.js +18 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +9 -1
- package/dist/services/features/telegram-mcp/src/app/config/env.js +119 -2
- package/dist/services/features/telegram-mcp/src/app/http.js +139 -99
- package/dist/services/features/telegram-mcp/src/app/oauthFacade.js +642 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +151 -170
- package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +96 -99
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +62 -19
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachActiveTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDetachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +410 -27
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +37 -3
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +7 -6
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +214 -37
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +186 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +6 -3
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +4 -1
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +33 -35
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileListTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileService.js +327 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileTool.js +81 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/temporaryFileLinkStore.js +307 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/workspaceFilePolicy.js +115 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +5 -1
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +3 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +6 -3
- package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +29 -6
- package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +100 -2
- package/dist/services/features/telegram-mcp/src/shared/lib/bodyLimits.js +63 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/gatewayAuth.js +13 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/time/localTimestamp.js +21 -0
- package/docs/CHAT_CONNECTOR.md +134 -0
- package/docs/STANDALONE-ru.md +13 -0
- package/docs/STANDALONE.md +13 -0
- package/package.json +5 -3
- package/packages/chrome-attach-extension/dist/background.js +572 -163
- package/packages/chrome-attach-extension/dist/manifest.json +2 -1
- package/packages/chrome-attach-extension/dist/options.js +15 -2
- package/packages/chrome-attach-extension/dist/recorder-content.js +14 -1
- package/packages/chrome-attach-extension/dist/recorder-page.js +34 -18
- package/packages/firefox-attach-extension/dist/background.js +413 -33
- package/packages/firefox-attach-extension/dist/manifest.json +0 -12
- package/packages/firefox-attach-extension/dist/options.js +14 -1
- package/packages/firefox-attach-extension/dist/recorder-content.js +14 -1
- package/packages/firefox-attach-extension/dist/recorder-page.js +34 -18
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.BrowserService = void 0;
|
|
7
7
|
const promises_1 = require("node:fs/promises");
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const bodyLimits_1 = require("../../../shared/lib/bodyLimits");
|
|
10
|
+
const localTimestamp_1 = require("../../../shared/lib/time/localTimestamp");
|
|
9
11
|
const gatewayClientAccess_1 = require("../../distributed-client/model/gatewayClientAccess");
|
|
10
12
|
function pushBounded(list, entry, max) {
|
|
11
13
|
list.push(entry);
|
|
@@ -22,7 +24,7 @@ function trimList(list, limit) {
|
|
|
22
24
|
function sanitizeScreenshotName(fileName) {
|
|
23
25
|
const trimmed = fileName?.trim();
|
|
24
26
|
if (!trimmed) {
|
|
25
|
-
const timestamp = new Date()
|
|
27
|
+
const timestamp = (0, localTimestamp_1.formatLocalTimestampForFileName)(new Date());
|
|
26
28
|
return `browser-screenshot-${timestamp}.png`;
|
|
27
29
|
}
|
|
28
30
|
const parsed = node_path_1.default.parse(trimmed);
|
|
@@ -31,8 +33,8 @@ function sanitizeScreenshotName(fileName) {
|
|
|
31
33
|
return `${base}${extension}`;
|
|
32
34
|
}
|
|
33
35
|
function buildDatedRelativePath(fileName, date = new Date()) {
|
|
34
|
-
const dateSegment =
|
|
35
|
-
const timeSegment =
|
|
36
|
+
const dateSegment = (0, localTimestamp_1.formatLocalDateSegment)(date);
|
|
37
|
+
const timeSegment = (0, localTimestamp_1.formatLocalTimeSegment)(date);
|
|
36
38
|
return `${dateSegment}/${timeSegment}/${fileName}`;
|
|
37
39
|
}
|
|
38
40
|
function isAbsoluteBrowserUrl(value) {
|
|
@@ -166,6 +168,137 @@ class BrowserService {
|
|
|
166
168
|
})),
|
|
167
169
|
};
|
|
168
170
|
}
|
|
171
|
+
async attachActiveTab(input) {
|
|
172
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
173
|
+
const normalizedSessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
|
|
174
|
+
const remote = await this.invokeRemote(normalizedSessionId, "telegramMcp.browser.attachActiveTabRemote", {
|
|
175
|
+
...input,
|
|
176
|
+
session_id: normalizedSessionId,
|
|
177
|
+
});
|
|
178
|
+
if (remote) {
|
|
179
|
+
return remote;
|
|
180
|
+
}
|
|
181
|
+
const instances = this.listFirefoxAttachInstances();
|
|
182
|
+
const instance = input.instance_id?.trim()
|
|
183
|
+
? instances.find((item) => item.instanceId === input.instance_id?.trim())
|
|
184
|
+
: instances.length === 1
|
|
185
|
+
? instances[0]
|
|
186
|
+
: undefined;
|
|
187
|
+
if (!instance) {
|
|
188
|
+
if (input.instance_id?.trim()) {
|
|
189
|
+
throw new Error(`Attached browser instance '${input.instance_id.trim()}' was not found.`);
|
|
190
|
+
}
|
|
191
|
+
throw new Error("Attached browser instance is ambiguous. Pass instance_id or keep exactly one connected browser instance.");
|
|
192
|
+
}
|
|
193
|
+
const activeTab = instance.activeTab;
|
|
194
|
+
if (!activeTab) {
|
|
195
|
+
throw new Error(`Attached browser instance '${instance.instanceId}' does not expose an active tab.`);
|
|
196
|
+
}
|
|
197
|
+
return await this.attachTab({
|
|
198
|
+
session_id: normalizedSessionId,
|
|
199
|
+
instance_id: instance.instanceId,
|
|
200
|
+
tab_id: activeTab.tab_id,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
async attachTab(input) {
|
|
204
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
205
|
+
const normalizedSessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
|
|
206
|
+
const remote = await this.invokeRemote(normalizedSessionId, "telegramMcp.browser.attachTabRemote", {
|
|
207
|
+
...input,
|
|
208
|
+
session_id: normalizedSessionId,
|
|
209
|
+
});
|
|
210
|
+
if (remote) {
|
|
211
|
+
return remote;
|
|
212
|
+
}
|
|
213
|
+
if (!this.firefoxAttachRegistry) {
|
|
214
|
+
throw new Error("Attached browser backend is not available.");
|
|
215
|
+
}
|
|
216
|
+
const instances = this.listFirefoxAttachInstances();
|
|
217
|
+
const instance = input.instance_id?.trim()
|
|
218
|
+
? instances.find((item) => item.instanceId === input.instance_id?.trim())
|
|
219
|
+
: instances.length === 1
|
|
220
|
+
? instances[0]
|
|
221
|
+
: undefined;
|
|
222
|
+
if (!instance) {
|
|
223
|
+
if (input.instance_id?.trim()) {
|
|
224
|
+
throw new Error(`Attached browser instance '${input.instance_id.trim()}' was not found.`);
|
|
225
|
+
}
|
|
226
|
+
throw new Error("Attached browser instance is ambiguous. Pass instance_id or keep exactly one connected browser instance.");
|
|
227
|
+
}
|
|
228
|
+
const tab = instance.tabs.find((item) => item.tab_id === input.tab_id);
|
|
229
|
+
if (!tab) {
|
|
230
|
+
throw new Error(`Tab '${input.tab_id}' was not found in attached browser instance '${instance.instanceId}'.`);
|
|
231
|
+
}
|
|
232
|
+
const result = await this.firefoxAttachRegistry.invokeTabAction({
|
|
233
|
+
instanceId: instance.instanceId,
|
|
234
|
+
tabId: tab.tab_id,
|
|
235
|
+
action: "attach",
|
|
236
|
+
});
|
|
237
|
+
const attachedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
238
|
+
await this.maintenanceStore.setBrowserAttachment({
|
|
239
|
+
sessionId: normalizedSessionId,
|
|
240
|
+
backend: "firefox-attached",
|
|
241
|
+
instanceId: instance.instanceId,
|
|
242
|
+
tabId: tab.tab_id,
|
|
243
|
+
attachedAt,
|
|
244
|
+
...(result?.title
|
|
245
|
+
? { title: String(result.title) }
|
|
246
|
+
: tab.title
|
|
247
|
+
? { title: tab.title }
|
|
248
|
+
: {}),
|
|
249
|
+
...(result?.url
|
|
250
|
+
? { url: String(result.url) }
|
|
251
|
+
: tab.url
|
|
252
|
+
? { url: tab.url }
|
|
253
|
+
: {}),
|
|
254
|
+
});
|
|
255
|
+
return {
|
|
256
|
+
session_id: normalizedSessionId,
|
|
257
|
+
backend: "firefox-attached",
|
|
258
|
+
instance_id: instance.instanceId,
|
|
259
|
+
tab_id: tab.tab_id,
|
|
260
|
+
attached_at: attachedAt,
|
|
261
|
+
...(result?.title
|
|
262
|
+
? { title: String(result.title) }
|
|
263
|
+
: tab.title
|
|
264
|
+
? { title: tab.title }
|
|
265
|
+
: {}),
|
|
266
|
+
...(result?.url
|
|
267
|
+
? { url: String(result.url) }
|
|
268
|
+
: tab.url
|
|
269
|
+
? { url: tab.url }
|
|
270
|
+
: {}),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
async detachTab(input) {
|
|
274
|
+
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
275
|
+
const normalizedSessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
|
|
276
|
+
const remote = await this.invokeRemote(normalizedSessionId, "telegramMcp.browser.detachTabRemote", {
|
|
277
|
+
...input,
|
|
278
|
+
session_id: normalizedSessionId,
|
|
279
|
+
});
|
|
280
|
+
if (remote) {
|
|
281
|
+
return remote;
|
|
282
|
+
}
|
|
283
|
+
const attachment = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
284
|
+
if (attachment && this.firefoxAttachRegistry) {
|
|
285
|
+
try {
|
|
286
|
+
await this.firefoxAttachRegistry.invokeTabAction({
|
|
287
|
+
instanceId: attachment.instanceId,
|
|
288
|
+
tabId: attachment.tabId,
|
|
289
|
+
action: "detach",
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
// Clearing local state is still the source of truth.
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
await this.maintenanceStore.clearBrowserAttachment(normalizedSessionId);
|
|
297
|
+
return {
|
|
298
|
+
session_id: normalizedSessionId,
|
|
299
|
+
detached: true,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
169
302
|
async startRecording(input) {
|
|
170
303
|
const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
|
|
171
304
|
const normalizedSessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
|
|
@@ -178,7 +311,7 @@ class BrowserService {
|
|
|
178
311
|
}
|
|
179
312
|
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
180
313
|
if (!attached) {
|
|
181
|
-
throw new Error("No attached
|
|
314
|
+
throw new Error("No attached browser tab is selected for this session. Select a tab in the browser attach panel first.");
|
|
182
315
|
}
|
|
183
316
|
if (!this.firefoxAttachRegistry) {
|
|
184
317
|
throw new Error("Firefox attach backend is not available.");
|
|
@@ -284,7 +417,7 @@ class BrowserService {
|
|
|
284
417
|
});
|
|
285
418
|
state.currentUrl = state.page.url();
|
|
286
419
|
state.title = await state.page.title();
|
|
287
|
-
state.lastUsedAt = new Date()
|
|
420
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
288
421
|
this.logger.info("Browser page opened", {
|
|
289
422
|
sessionId: resolved.sessionId,
|
|
290
423
|
normalizedSessionId,
|
|
@@ -318,8 +451,40 @@ class BrowserService {
|
|
|
318
451
|
return remote;
|
|
319
452
|
}
|
|
320
453
|
this.ensureEnabled();
|
|
454
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
455
|
+
if (attached) {
|
|
456
|
+
const result = await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
457
|
+
action: "get_logs",
|
|
458
|
+
payload: {
|
|
459
|
+
limit: input.limit,
|
|
460
|
+
},
|
|
461
|
+
});
|
|
462
|
+
const consoleMessages = Array.isArray(result?.console_messages)
|
|
463
|
+
? result.console_messages
|
|
464
|
+
: [];
|
|
465
|
+
return {
|
|
466
|
+
session_id: normalizedSessionId,
|
|
467
|
+
total: typeof result?.console_total === "number"
|
|
468
|
+
? result.console_total
|
|
469
|
+
: consoleMessages.length,
|
|
470
|
+
messages: consoleMessages.map((message) => ({
|
|
471
|
+
type: typeof message?.type === "string"
|
|
472
|
+
? message.type
|
|
473
|
+
: "log",
|
|
474
|
+
text: typeof message?.text === "string"
|
|
475
|
+
? message.text
|
|
476
|
+
: "",
|
|
477
|
+
...(typeof message?.location === "string"
|
|
478
|
+
? { location: message.location }
|
|
479
|
+
: {}),
|
|
480
|
+
timestamp: typeof message?.timestamp === "string"
|
|
481
|
+
? message.timestamp
|
|
482
|
+
: (0, localTimestamp_1.formatLocalTimestamp)(new Date()),
|
|
483
|
+
})),
|
|
484
|
+
};
|
|
485
|
+
}
|
|
321
486
|
const { sessionId, state } = await this.requireSessionState(input);
|
|
322
|
-
state.lastUsedAt = new Date()
|
|
487
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
323
488
|
return {
|
|
324
489
|
session_id: sessionId,
|
|
325
490
|
total: state.consoleMessages.length,
|
|
@@ -365,7 +530,7 @@ class BrowserService {
|
|
|
365
530
|
});
|
|
366
531
|
state.currentUrl = state.page.url();
|
|
367
532
|
state.title = await state.page.title().catch(() => state.title);
|
|
368
|
-
state.lastUsedAt = new Date()
|
|
533
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
369
534
|
return {
|
|
370
535
|
session_id: sessionId,
|
|
371
536
|
clicked: true,
|
|
@@ -414,7 +579,7 @@ class BrowserService {
|
|
|
414
579
|
});
|
|
415
580
|
state.currentUrl = state.page.url();
|
|
416
581
|
state.title = await state.page.title().catch(() => state.title);
|
|
417
|
-
state.lastUsedAt = new Date()
|
|
582
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
418
583
|
return {
|
|
419
584
|
session_id: sessionId,
|
|
420
585
|
filled: true,
|
|
@@ -469,7 +634,7 @@ class BrowserService {
|
|
|
469
634
|
}
|
|
470
635
|
state.currentUrl = state.page.url();
|
|
471
636
|
state.title = await state.page.title().catch(() => state.title);
|
|
472
|
-
state.lastUsedAt = new Date()
|
|
637
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
473
638
|
return {
|
|
474
639
|
session_id: sessionId,
|
|
475
640
|
pressed: true,
|
|
@@ -493,14 +658,22 @@ class BrowserService {
|
|
|
493
658
|
}
|
|
494
659
|
this.ensureEnabled();
|
|
495
660
|
const namespace = input.namespace?.trim() || "TELLY";
|
|
661
|
+
const sourcePath = input.file_path?.trim()
|
|
662
|
+
? node_path_1.default.resolve(input.file_path.trim())
|
|
663
|
+
: null;
|
|
664
|
+
if (!input.source?.trim().length && sourcePath) {
|
|
665
|
+
const sourceStats = await (0, promises_1.stat)(sourcePath);
|
|
666
|
+
(0, bodyLimits_1.assertBodySize)(sourceStats.size);
|
|
667
|
+
}
|
|
496
668
|
const source = input.source?.trim().length
|
|
497
669
|
? input.source
|
|
498
|
-
:
|
|
499
|
-
? await (0, promises_1.readFile)(
|
|
670
|
+
: sourcePath
|
|
671
|
+
? await (0, promises_1.readFile)(sourcePath, "utf8")
|
|
500
672
|
: null;
|
|
501
673
|
if (!source) {
|
|
502
674
|
throw new Error("Provide source or file_path.");
|
|
503
675
|
}
|
|
676
|
+
(0, bodyLimits_1.assertStringBodySize)(source);
|
|
504
677
|
const sourceType = input.source?.trim().length ? "inline" : "file";
|
|
505
678
|
const wrappedSource = this.wrapInjectedScript(source, namespace);
|
|
506
679
|
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
@@ -528,7 +701,7 @@ class BrowserService {
|
|
|
528
701
|
});
|
|
529
702
|
state.currentUrl = state.page.url();
|
|
530
703
|
state.title = await state.page.title().catch(() => state.title);
|
|
531
|
-
state.lastUsedAt = new Date()
|
|
704
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
532
705
|
return {
|
|
533
706
|
session_id: sessionId,
|
|
534
707
|
injected: true,
|
|
@@ -550,6 +723,18 @@ class BrowserService {
|
|
|
550
723
|
return remote;
|
|
551
724
|
}
|
|
552
725
|
this.ensureEnabled();
|
|
726
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
727
|
+
if (attached) {
|
|
728
|
+
const result = await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
729
|
+
action: "reload",
|
|
730
|
+
});
|
|
731
|
+
return {
|
|
732
|
+
session_id: normalizedSessionId,
|
|
733
|
+
reloaded: true,
|
|
734
|
+
url: String(result?.url || attached.url || ""),
|
|
735
|
+
...(result?.title ? { title: String(result.title) } : {}),
|
|
736
|
+
};
|
|
737
|
+
}
|
|
553
738
|
const { sessionId, state } = await this.requireSessionState(input);
|
|
554
739
|
const waitUntil = (input.wait_until ??
|
|
555
740
|
this.config.browser.waitUntil);
|
|
@@ -559,7 +744,7 @@ class BrowserService {
|
|
|
559
744
|
});
|
|
560
745
|
state.currentUrl = state.page.url();
|
|
561
746
|
state.title = await state.page.title().catch(() => state.title);
|
|
562
|
-
state.lastUsedAt = new Date()
|
|
747
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
563
748
|
this.logger.info("Browser page reloaded", {
|
|
564
749
|
sessionId,
|
|
565
750
|
url: state.currentUrl,
|
|
@@ -584,6 +769,30 @@ class BrowserService {
|
|
|
584
769
|
return remote;
|
|
585
770
|
}
|
|
586
771
|
this.ensureEnabled();
|
|
772
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
773
|
+
if (attached) {
|
|
774
|
+
const waitState = input.state ?? "visible";
|
|
775
|
+
const result = await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
776
|
+
action: "wait_for",
|
|
777
|
+
payload: {
|
|
778
|
+
...this.buildAttachedLocatorPayload(input),
|
|
779
|
+
state: waitState,
|
|
780
|
+
...(typeof input.timeout_ms === "number"
|
|
781
|
+
? { timeout_ms: input.timeout_ms }
|
|
782
|
+
: {}),
|
|
783
|
+
},
|
|
784
|
+
});
|
|
785
|
+
return {
|
|
786
|
+
session_id: normalizedSessionId,
|
|
787
|
+
waited: true,
|
|
788
|
+
state: waitState,
|
|
789
|
+
...(input.ai_tag ? { ai_tag: input.ai_tag } : {}),
|
|
790
|
+
...(input.selector ? { selector: input.selector } : {}),
|
|
791
|
+
...(input.text ? { text: input.text } : {}),
|
|
792
|
+
url: String(result?.url || attached.url || ""),
|
|
793
|
+
...(result?.title ? { title: String(result.title) } : {}),
|
|
794
|
+
};
|
|
795
|
+
}
|
|
587
796
|
const { sessionId, state } = await this.requireSessionState(input);
|
|
588
797
|
const locator = this.resolveLocator(state.page, input);
|
|
589
798
|
const waitState = input.state ?? "visible";
|
|
@@ -593,7 +802,7 @@ class BrowserService {
|
|
|
593
802
|
});
|
|
594
803
|
state.currentUrl = state.page.url();
|
|
595
804
|
state.title = await state.page.title().catch(() => state.title);
|
|
596
|
-
state.lastUsedAt = new Date()
|
|
805
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
597
806
|
return {
|
|
598
807
|
session_id: sessionId,
|
|
599
808
|
waited: true,
|
|
@@ -616,6 +825,32 @@ class BrowserService {
|
|
|
616
825
|
return remote;
|
|
617
826
|
}
|
|
618
827
|
this.ensureEnabled();
|
|
828
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
829
|
+
if (attached) {
|
|
830
|
+
const result = await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
831
|
+
action: "wait_for_url",
|
|
832
|
+
payload: {
|
|
833
|
+
...(input.url?.trim() ? { url: input.url.trim() } : {}),
|
|
834
|
+
...(input.url_contains?.trim()
|
|
835
|
+
? { url_contains: input.url_contains.trim() }
|
|
836
|
+
: {}),
|
|
837
|
+
...(typeof input.timeout_ms === "number"
|
|
838
|
+
? { timeout_ms: input.timeout_ms }
|
|
839
|
+
: {}),
|
|
840
|
+
},
|
|
841
|
+
});
|
|
842
|
+
return {
|
|
843
|
+
session_id: normalizedSessionId,
|
|
844
|
+
waited: true,
|
|
845
|
+
matched: input.url?.trim() ? "url" : "url_contains",
|
|
846
|
+
...(input.url?.trim() ? { url: input.url.trim() } : {}),
|
|
847
|
+
...(input.url_contains?.trim()
|
|
848
|
+
? { url_contains: input.url_contains.trim() }
|
|
849
|
+
: {}),
|
|
850
|
+
current_url: String(result?.url || attached.url || ""),
|
|
851
|
+
...(result?.title ? { title: String(result.title) } : {}),
|
|
852
|
+
};
|
|
853
|
+
}
|
|
619
854
|
const { sessionId, state } = await this.requireSessionState(input);
|
|
620
855
|
const timeout = this.resolveTimeoutMs(input.timeout_ms);
|
|
621
856
|
if (input.url?.trim()) {
|
|
@@ -634,7 +869,7 @@ class BrowserService {
|
|
|
634
869
|
}
|
|
635
870
|
state.currentUrl = state.page.url();
|
|
636
871
|
state.title = await state.page.title().catch(() => state.title);
|
|
637
|
-
state.lastUsedAt = new Date()
|
|
872
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
638
873
|
return {
|
|
639
874
|
session_id: sessionId,
|
|
640
875
|
waited: true,
|
|
@@ -658,8 +893,37 @@ class BrowserService {
|
|
|
658
893
|
return remote;
|
|
659
894
|
}
|
|
660
895
|
this.ensureEnabled();
|
|
896
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
897
|
+
if (attached) {
|
|
898
|
+
const result = await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
899
|
+
action: "get_logs",
|
|
900
|
+
payload: {
|
|
901
|
+
limit: input.limit,
|
|
902
|
+
},
|
|
903
|
+
});
|
|
904
|
+
const pageErrors = Array.isArray(result?.page_errors)
|
|
905
|
+
? result.page_errors
|
|
906
|
+
: [];
|
|
907
|
+
return {
|
|
908
|
+
session_id: normalizedSessionId,
|
|
909
|
+
total: typeof result?.page_error_total === "number"
|
|
910
|
+
? result.page_error_total
|
|
911
|
+
: pageErrors.length,
|
|
912
|
+
errors: pageErrors.map((error) => ({
|
|
913
|
+
message: typeof error?.message === "string"
|
|
914
|
+
? error.message
|
|
915
|
+
: "",
|
|
916
|
+
...(typeof error?.stack === "string"
|
|
917
|
+
? { stack: error.stack }
|
|
918
|
+
: {}),
|
|
919
|
+
timestamp: typeof error?.timestamp === "string"
|
|
920
|
+
? error.timestamp
|
|
921
|
+
: (0, localTimestamp_1.formatLocalTimestamp)(new Date()),
|
|
922
|
+
})),
|
|
923
|
+
};
|
|
924
|
+
}
|
|
661
925
|
const { sessionId, state } = await this.requireSessionState(input);
|
|
662
|
-
state.lastUsedAt = new Date()
|
|
926
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
663
927
|
return {
|
|
664
928
|
session_id: sessionId,
|
|
665
929
|
total: state.pageErrors.length,
|
|
@@ -681,8 +945,46 @@ class BrowserService {
|
|
|
681
945
|
return remote;
|
|
682
946
|
}
|
|
683
947
|
this.ensureEnabled();
|
|
948
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
949
|
+
if (attached) {
|
|
950
|
+
const result = await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
951
|
+
action: "get_logs",
|
|
952
|
+
payload: {
|
|
953
|
+
limit: input.limit,
|
|
954
|
+
},
|
|
955
|
+
});
|
|
956
|
+
const failures = Array.isArray(result?.network_failures)
|
|
957
|
+
? result.network_failures
|
|
958
|
+
: [];
|
|
959
|
+
return {
|
|
960
|
+
session_id: normalizedSessionId,
|
|
961
|
+
total: typeof result?.network_failure_total === "number"
|
|
962
|
+
? result.network_failure_total
|
|
963
|
+
: failures.length,
|
|
964
|
+
failures: failures.map((failure) => ({
|
|
965
|
+
url: typeof failure?.url === "string"
|
|
966
|
+
? failure.url
|
|
967
|
+
: "",
|
|
968
|
+
method: typeof failure?.method === "string"
|
|
969
|
+
? failure.method
|
|
970
|
+
: "GET",
|
|
971
|
+
...(typeof failure?.status === "number"
|
|
972
|
+
? { status: failure.status }
|
|
973
|
+
: {}),
|
|
974
|
+
...(typeof failure?.error_text === "string"
|
|
975
|
+
? { error_text: failure.error_text }
|
|
976
|
+
: {}),
|
|
977
|
+
...(typeof failure?.resource_type === "string"
|
|
978
|
+
? { resource_type: failure.resource_type }
|
|
979
|
+
: {}),
|
|
980
|
+
timestamp: typeof failure?.timestamp === "string"
|
|
981
|
+
? failure.timestamp
|
|
982
|
+
: (0, localTimestamp_1.formatLocalTimestamp)(new Date()),
|
|
983
|
+
})),
|
|
984
|
+
};
|
|
985
|
+
}
|
|
684
986
|
const { sessionId, state } = await this.requireSessionState(input);
|
|
685
|
-
state.lastUsedAt = new Date()
|
|
987
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
686
988
|
return {
|
|
687
989
|
session_id: sessionId,
|
|
688
990
|
total: state.networkFailures.length,
|
|
@@ -709,6 +1011,25 @@ class BrowserService {
|
|
|
709
1011
|
return remote;
|
|
710
1012
|
}
|
|
711
1013
|
this.ensureEnabled();
|
|
1014
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
1015
|
+
if (attached) {
|
|
1016
|
+
const result = await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
1017
|
+
action: "clear_logs",
|
|
1018
|
+
});
|
|
1019
|
+
return {
|
|
1020
|
+
session_id: normalizedSessionId,
|
|
1021
|
+
cleared: true,
|
|
1022
|
+
console_messages_cleared: typeof result?.console_messages_cleared === "number"
|
|
1023
|
+
? result.console_messages_cleared
|
|
1024
|
+
: 0,
|
|
1025
|
+
page_errors_cleared: typeof result?.page_errors_cleared === "number"
|
|
1026
|
+
? result.page_errors_cleared
|
|
1027
|
+
: 0,
|
|
1028
|
+
network_failures_cleared: typeof result?.network_failures_cleared === "number"
|
|
1029
|
+
? result.network_failures_cleared
|
|
1030
|
+
: 0,
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
712
1033
|
const { sessionId, state } = await this.requireSessionState(input);
|
|
713
1034
|
const consoleMessagesCleared = state.consoleMessages.length;
|
|
714
1035
|
const pageErrorsCleared = state.pageErrors.length;
|
|
@@ -716,7 +1037,7 @@ class BrowserService {
|
|
|
716
1037
|
state.consoleMessages = [];
|
|
717
1038
|
state.pageErrors = [];
|
|
718
1039
|
state.networkFailures = [];
|
|
719
|
-
state.lastUsedAt = new Date()
|
|
1040
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
720
1041
|
return {
|
|
721
1042
|
session_id: sessionId,
|
|
722
1043
|
cleared: true,
|
|
@@ -801,7 +1122,7 @@ class BrowserService {
|
|
|
801
1122
|
includeText: input.include_text !== false,
|
|
802
1123
|
})
|
|
803
1124
|
.catch(() => ({ found: false }));
|
|
804
|
-
state.lastUsedAt = new Date()
|
|
1125
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
805
1126
|
state.currentUrl = state.page.url();
|
|
806
1127
|
state.title = await state.page.title().catch(() => state.title);
|
|
807
1128
|
return {
|
|
@@ -831,6 +1152,57 @@ class BrowserService {
|
|
|
831
1152
|
return remote;
|
|
832
1153
|
}
|
|
833
1154
|
this.ensureEnabled();
|
|
1155
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
1156
|
+
if (attached) {
|
|
1157
|
+
const properties = input.properties?.length
|
|
1158
|
+
? input.properties
|
|
1159
|
+
: [
|
|
1160
|
+
"display",
|
|
1161
|
+
"position",
|
|
1162
|
+
"visibility",
|
|
1163
|
+
"opacity",
|
|
1164
|
+
"color",
|
|
1165
|
+
"background-color",
|
|
1166
|
+
"font-size",
|
|
1167
|
+
"z-index",
|
|
1168
|
+
"overflow",
|
|
1169
|
+
];
|
|
1170
|
+
const result = await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
1171
|
+
action: "computed_style",
|
|
1172
|
+
payload: {
|
|
1173
|
+
selector: input.selector,
|
|
1174
|
+
properties,
|
|
1175
|
+
},
|
|
1176
|
+
});
|
|
1177
|
+
return {
|
|
1178
|
+
session_id: normalizedSessionId,
|
|
1179
|
+
selector: input.selector,
|
|
1180
|
+
found: result?.found === true,
|
|
1181
|
+
...(result?.url ? { url: String(result.url) } : {}),
|
|
1182
|
+
...(result?.title ? { title: String(result.title) } : {}),
|
|
1183
|
+
...(typeof result?.visible === "boolean"
|
|
1184
|
+
? { visible: result.visible }
|
|
1185
|
+
: {}),
|
|
1186
|
+
...(result?.styles && typeof result.styles === "object"
|
|
1187
|
+
? { styles: result.styles }
|
|
1188
|
+
: {}),
|
|
1189
|
+
...(result?.box &&
|
|
1190
|
+
typeof result.box === "object" &&
|
|
1191
|
+
typeof result.box.x === "number" &&
|
|
1192
|
+
typeof result.box.y === "number" &&
|
|
1193
|
+
typeof result.box.width === "number" &&
|
|
1194
|
+
typeof result.box.height === "number"
|
|
1195
|
+
? {
|
|
1196
|
+
box: {
|
|
1197
|
+
x: Number(result.box.x),
|
|
1198
|
+
y: Number(result.box.y),
|
|
1199
|
+
width: Number(result.box.width),
|
|
1200
|
+
height: Number(result.box.height),
|
|
1201
|
+
},
|
|
1202
|
+
}
|
|
1203
|
+
: {}),
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
834
1206
|
const { sessionId, state } = await this.requireSessionState(input);
|
|
835
1207
|
const properties = input.properties?.length
|
|
836
1208
|
? input.properties
|
|
@@ -870,7 +1242,7 @@ class BrowserService {
|
|
|
870
1242
|
};
|
|
871
1243
|
}, properties)
|
|
872
1244
|
.catch(() => ({ found: false }));
|
|
873
|
-
state.lastUsedAt = new Date()
|
|
1245
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
874
1246
|
state.currentUrl = state.page.url();
|
|
875
1247
|
state.title = await state.page.title().catch(() => state.title);
|
|
876
1248
|
return {
|
|
@@ -924,7 +1296,7 @@ class BrowserService {
|
|
|
924
1296
|
filePath: storedFile.filePath,
|
|
925
1297
|
relativePath: storedFile.relativePath,
|
|
926
1298
|
source: "browser-screenshot",
|
|
927
|
-
uploadedAt: new Date()
|
|
1299
|
+
uploadedAt: (0, localTimestamp_1.formatLocalTimestamp)(new Date()),
|
|
928
1300
|
storageRef: storedFile.storageRef,
|
|
929
1301
|
bucketName: storedFile.bucketName,
|
|
930
1302
|
objectName: storedFile.objectName,
|
|
@@ -992,7 +1364,7 @@ class BrowserService {
|
|
|
992
1364
|
mimeType: "image/png",
|
|
993
1365
|
});
|
|
994
1366
|
const filePath = storedFile.filePath;
|
|
995
|
-
state.lastUsedAt = new Date()
|
|
1367
|
+
state.lastUsedAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
996
1368
|
state.currentUrl = state.page.url();
|
|
997
1369
|
state.title = await state.page.title().catch(() => state.title);
|
|
998
1370
|
this.logger.info("Browser screenshot captured", {
|
|
@@ -1006,7 +1378,7 @@ class BrowserService {
|
|
|
1006
1378
|
filePath,
|
|
1007
1379
|
relativePath: storedFile.relativePath,
|
|
1008
1380
|
source: "browser-screenshot",
|
|
1009
|
-
uploadedAt: new Date()
|
|
1381
|
+
uploadedAt: (0, localTimestamp_1.formatLocalTimestamp)(new Date()),
|
|
1010
1382
|
storageRef: storedFile.storageRef,
|
|
1011
1383
|
bucketName: storedFile.bucketName,
|
|
1012
1384
|
objectName: storedFile.objectName,
|
|
@@ -1059,6 +1431,17 @@ class BrowserService {
|
|
|
1059
1431
|
return remote;
|
|
1060
1432
|
}
|
|
1061
1433
|
this.ensureEnabled();
|
|
1434
|
+
const attached = await this.getAttachedBrowserAttachment(normalizedSessionId);
|
|
1435
|
+
if (attached) {
|
|
1436
|
+
await this.runAttachedTabAction(normalizedSessionId, attached, {
|
|
1437
|
+
action: "close",
|
|
1438
|
+
});
|
|
1439
|
+
await this.maintenanceStore.clearBrowserAttachment(normalizedSessionId);
|
|
1440
|
+
return {
|
|
1441
|
+
session_id: normalizedSessionId,
|
|
1442
|
+
closed: true,
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1062
1445
|
const state = this.sessionStates.get(normalizedSessionId);
|
|
1063
1446
|
if (state) {
|
|
1064
1447
|
await this.closeState(normalizedSessionId, state);
|
|
@@ -1132,7 +1515,7 @@ class BrowserService {
|
|
|
1132
1515
|
const browser = await this.ensureBrowser();
|
|
1133
1516
|
const context = await browser.newContext(this.buildContextOptions(openInput));
|
|
1134
1517
|
const page = await context.newPage();
|
|
1135
|
-
const createdAt = new Date()
|
|
1518
|
+
const createdAt = (0, localTimestamp_1.formatLocalTimestamp)(new Date());
|
|
1136
1519
|
const state = {
|
|
1137
1520
|
context,
|
|
1138
1521
|
page,
|
|
@@ -1149,14 +1532,14 @@ class BrowserService {
|
|
|
1149
1532
|
...(formatConsoleLocation(message)
|
|
1150
1533
|
? { location: formatConsoleLocation(message) }
|
|
1151
1534
|
: {}),
|
|
1152
|
-
timestamp: new Date()
|
|
1535
|
+
timestamp: (0, localTimestamp_1.formatLocalTimestamp)(new Date()),
|
|
1153
1536
|
}, this.config.browser.maxEvents);
|
|
1154
1537
|
});
|
|
1155
1538
|
page.on("pageerror", (error) => {
|
|
1156
1539
|
pushBounded(state.pageErrors, {
|
|
1157
1540
|
message: error.message,
|
|
1158
1541
|
...(error.stack ? { stack: error.stack } : {}),
|
|
1159
|
-
timestamp: new Date()
|
|
1542
|
+
timestamp: (0, localTimestamp_1.formatLocalTimestamp)(new Date()),
|
|
1160
1543
|
}, this.config.browser.maxEvents);
|
|
1161
1544
|
});
|
|
1162
1545
|
page.on("requestfailed", (request) => {
|
|
@@ -1206,7 +1589,7 @@ class BrowserService {
|
|
|
1206
1589
|
: {}),
|
|
1207
1590
|
...(failure?.errorText ? { errorText: failure.errorText } : {}),
|
|
1208
1591
|
resourceType: request.resourceType(),
|
|
1209
|
-
timestamp: new Date()
|
|
1592
|
+
timestamp: (0, localTimestamp_1.formatLocalTimestamp)(new Date()),
|
|
1210
1593
|
}, this.config.browser.maxEvents);
|
|
1211
1594
|
}
|
|
1212
1595
|
async requireSessionState(input) {
|