@framers/agentos-ext-browser-automation 0.2.0 → 0.3.0
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.md +91 -0
- package/dist/BrowserService.js +9 -45
- package/dist/BrowserService.js.map +1 -1
- package/dist/attach/AttachController.d.ts +54 -0
- package/dist/attach/AttachController.d.ts.map +1 -1
- package/dist/attach/AttachController.js +129 -41
- package/dist/attach/AttachController.js.map +1 -1
- package/dist/attach/backends/jxa.d.ts.map +1 -1
- package/dist/attach/backends/jxa.js +35 -62
- package/dist/attach/backends/jxa.js.map +1 -1
- package/dist/attach/backends/raw-cdp.d.ts +14 -0
- package/dist/attach/backends/raw-cdp.d.ts.map +1 -1
- package/dist/attach/backends/raw-cdp.js +66 -35
- package/dist/attach/backends/raw-cdp.js.map +1 -1
- package/dist/attach/daemon/client.d.ts +10 -0
- package/dist/attach/daemon/client.d.ts.map +1 -1
- package/dist/attach/daemon/client.js +34 -23
- package/dist/attach/daemon/client.js.map +1 -1
- package/dist/attach/daemon/daemon-lock.js +14 -17
- package/dist/attach/daemon/daemon-lock.js.map +1 -1
- package/dist/attach/daemon/daemon-main.d.ts +11 -0
- package/dist/attach/daemon/daemon-main.d.ts.map +1 -1
- package/dist/attach/daemon/daemon-main.js +39 -18
- package/dist/attach/daemon/daemon-main.js.map +1 -1
- package/dist/attach/daemon/daemon.d.ts.map +1 -1
- package/dist/attach/daemon/daemon.js +49 -32
- package/dist/attach/daemon/daemon.js.map +1 -1
- package/dist/attach/daemon/index.js +7 -25
- package/dist/attach/daemon/index.js.map +1 -1
- package/dist/attach/daemon/protocol.d.ts +1 -1
- package/dist/attach/daemon/protocol.d.ts.map +1 -1
- package/dist/attach/daemon/protocol.js +33 -45
- package/dist/attach/daemon/protocol.js.map +1 -1
- package/dist/attach/daemon/runner.js +1 -4
- package/dist/attach/daemon/runner.js.map +1 -1
- package/dist/attach/daemon/surface.d.ts +5 -0
- package/dist/attach/daemon/surface.d.ts.map +1 -1
- package/dist/attach/daemon/surface.js +16 -14
- package/dist/attach/daemon/surface.js.map +1 -1
- package/dist/attach/devtools-port.js +1 -4
- package/dist/attach/devtools-port.js.map +1 -1
- package/dist/attach/errors.js +4 -9
- package/dist/attach/errors.js.map +1 -1
- package/dist/attach/evidence.d.ts +64 -0
- package/dist/attach/evidence.d.ts.map +1 -0
- package/dist/attach/evidence.js +269 -0
- package/dist/attach/evidence.js.map +1 -0
- package/dist/attach/lease.js +18 -23
- package/dist/attach/lease.js.map +1 -1
- package/dist/attach/singleton-lock.js +1 -4
- package/dist/attach/singleton-lock.js.map +1 -1
- package/dist/attach/state.js +6 -13
- package/dist/attach/state.js.map +1 -1
- package/dist/attach/tools.d.ts +42 -2
- package/dist/attach/tools.d.ts.map +1 -1
- package/dist/attach/tools.js +124 -88
- package/dist/attach/tools.js.map +1 -1
- package/dist/attach/url-policy.js +2 -6
- package/dist/attach/url-policy.js.map +1 -1
- package/dist/attach.js +7 -23
- package/dist/attach.js.map +1 -1
- package/dist/captcha/CaptchaSolver.js +4 -7
- package/dist/captcha/CaptchaSolver.js.map +1 -1
- package/dist/captcha/ICaptchaProvider.js +1 -2
- package/dist/captcha/ICaptchaProvider.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +56 -75
- package/dist/index.js.map +1 -1
- package/dist/proxy/IProxyProvider.js +1 -2
- package/dist/proxy/IProxyProvider.js.map +1 -1
- package/dist/proxy/ProxyManager.js +7 -10
- package/dist/proxy/ProxyManager.js.map +1 -1
- package/dist/tools/ClickTool.js +17 -20
- package/dist/tools/ClickTool.js.map +1 -1
- package/dist/tools/EvaluateTool.js +16 -19
- package/dist/tools/EvaluateTool.js.map +1 -1
- package/dist/tools/ExtractTool.js +23 -26
- package/dist/tools/ExtractTool.js.map +1 -1
- package/dist/tools/FillTool.js +17 -20
- package/dist/tools/FillTool.js.map +1 -1
- package/dist/tools/NavigateTool.js +31 -34
- package/dist/tools/NavigateTool.js.map +1 -1
- package/dist/tools/PageSnapshotTool.js +13 -16
- package/dist/tools/PageSnapshotTool.js.map +1 -1
- package/dist/tools/ScreenshotTool.js +16 -19
- package/dist/tools/ScreenshotTool.js.map +1 -1
- package/dist/tools/ScrollTool.js +17 -20
- package/dist/tools/ScrollTool.js.map +1 -1
- package/dist/tools/SessionTool.js +24 -27
- package/dist/tools/SessionTool.js.map +1 -1
- package/dist/tools/WaitTool.js +22 -25
- package/dist/tools/WaitTool.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +5 -4
- package/dist/attach/__tests__/AttachController.test.d.ts +0 -2
- package/dist/attach/__tests__/AttachController.test.d.ts.map +0 -1
- package/dist/attach/__tests__/AttachController.test.js +0 -278
- package/dist/attach/__tests__/AttachController.test.js.map +0 -1
- package/dist/attach/__tests__/attach-primitives.test.d.ts +0 -2
- package/dist/attach/__tests__/attach-primitives.test.d.ts.map +0 -1
- package/dist/attach/__tests__/attach-primitives.test.js +0 -158
- package/dist/attach/__tests__/attach-primitives.test.js.map +0 -1
- package/dist/attach/__tests__/jxa-args.test.d.ts +0 -2
- package/dist/attach/__tests__/jxa-args.test.d.ts.map +0 -1
- package/dist/attach/__tests__/jxa-args.test.js +0 -37
- package/dist/attach/__tests__/jxa-args.test.js.map +0 -1
- package/dist/attach/__tests__/pack-registration.test.d.ts +0 -2
- package/dist/attach/__tests__/pack-registration.test.d.ts.map +0 -1
- package/dist/attach/__tests__/pack-registration.test.js +0 -34
- package/dist/attach/__tests__/pack-registration.test.js.map +0 -1
- package/dist/attach/__tests__/tools.test.d.ts +0 -2
- package/dist/attach/__tests__/tools.test.d.ts.map +0 -1
- package/dist/attach/__tests__/tools.test.js +0 -155
- package/dist/attach/__tests__/tools.test.js.map +0 -1
- package/dist/attach/backends/__tests__/raw-cdp.test.d.ts +0 -2
- package/dist/attach/backends/__tests__/raw-cdp.test.d.ts.map +0 -1
- package/dist/attach/backends/__tests__/raw-cdp.test.js +0 -133
- package/dist/attach/backends/__tests__/raw-cdp.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/client.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/client.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/client.test.js +0 -58
- package/dist/attach/daemon/__tests__/client.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/daemon-lock.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/daemon-lock.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/daemon-lock.test.js +0 -72
- package/dist/attach/daemon/__tests__/daemon-lock.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/daemon-loop.integration.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/daemon-loop.integration.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/daemon-loop.integration.test.js +0 -102
- package/dist/attach/daemon/__tests__/daemon-loop.integration.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/harness.d.ts +0 -44
- package/dist/attach/daemon/__tests__/harness.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/harness.js +0 -96
- package/dist/attach/daemon/__tests__/harness.js.map +0 -1
- package/dist/attach/daemon/__tests__/protocol.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/protocol.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/protocol.test.js +0 -71
- package/dist/attach/daemon/__tests__/protocol.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/runner.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/runner.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/runner.test.js +0 -67
- package/dist/attach/daemon/__tests__/runner.test.js.map +0 -1
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export class PageSnapshotTool {
|
|
2
|
+
browser;
|
|
3
|
+
id = 'browserSnapshot';
|
|
4
|
+
name = 'browserSnapshot';
|
|
5
|
+
displayName = 'Page Snapshot';
|
|
6
|
+
description = 'Get a structured inventory of the current page — all interactive elements, forms, links, and metadata. Essential for agent-driven navigation.';
|
|
7
|
+
category = 'browser';
|
|
8
|
+
version = '0.1.0';
|
|
9
|
+
hasSideEffects = false;
|
|
10
|
+
inputSchema = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {},
|
|
13
|
+
};
|
|
5
14
|
constructor(browser) {
|
|
6
15
|
this.browser = browser;
|
|
7
|
-
this.id = 'browserSnapshot';
|
|
8
|
-
this.name = 'browserSnapshot';
|
|
9
|
-
this.displayName = 'Page Snapshot';
|
|
10
|
-
this.description = 'Get a structured inventory of the current page — all interactive elements, forms, links, and metadata. Essential for agent-driven navigation.';
|
|
11
|
-
this.category = 'browser';
|
|
12
|
-
this.version = '0.1.0';
|
|
13
|
-
this.hasSideEffects = false;
|
|
14
|
-
this.inputSchema = {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {},
|
|
17
|
-
};
|
|
18
16
|
}
|
|
19
17
|
async execute() {
|
|
20
18
|
try {
|
|
@@ -26,5 +24,4 @@ class PageSnapshotTool {
|
|
|
26
24
|
}
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
|
-
exports.PageSnapshotTool = PageSnapshotTool;
|
|
30
27
|
//# sourceMappingURL=PageSnapshotTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageSnapshotTool.js","sourceRoot":"","sources":["../../src/tools/PageSnapshotTool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PageSnapshotTool.js","sourceRoot":"","sources":["../../src/tools/PageSnapshotTool.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,gBAAgB;IAcP;IAbX,EAAE,GAAG,iBAAiB,CAAC;IACvB,IAAI,GAAG,iBAAiB,CAAC;IACzB,WAAW,GAAG,eAAe,CAAC;IAC9B,WAAW,GAAG,+IAA+I,CAAC;IAC9J,QAAQ,GAAG,SAAS,CAAC;IACrB,OAAO,GAAG,OAAO,CAAC;IAClB,cAAc,GAAG,KAAK,CAAC;IAEvB,WAAW,GAAG;QACrB,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE,EAAE;KACf,CAAC;IAEF,YAAoB,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAG,CAAC;IAE/C,KAAK,CAAC,OAAO;QACX,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export class ScreenshotTool {
|
|
2
|
+
browser;
|
|
3
|
+
id = 'browserScreenshot';
|
|
4
|
+
name = 'browserScreenshot';
|
|
5
|
+
displayName = 'Take Screenshot';
|
|
6
|
+
description = 'Capture a screenshot of the current page or a specific element. Returns base64-encoded PNG.';
|
|
7
|
+
category = 'browser';
|
|
8
|
+
version = '0.1.0';
|
|
9
|
+
hasSideEffects = false;
|
|
10
|
+
inputSchema = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
selector: { type: 'string', description: 'CSS selector to screenshot a specific element (omit for full page)' },
|
|
14
|
+
fullPage: { type: 'boolean', description: 'Capture the full scrollable page', default: false },
|
|
15
|
+
},
|
|
16
|
+
};
|
|
5
17
|
constructor(browser) {
|
|
6
18
|
this.browser = browser;
|
|
7
|
-
this.id = 'browserScreenshot';
|
|
8
|
-
this.name = 'browserScreenshot';
|
|
9
|
-
this.displayName = 'Take Screenshot';
|
|
10
|
-
this.description = 'Capture a screenshot of the current page or a specific element. Returns base64-encoded PNG.';
|
|
11
|
-
this.category = 'browser';
|
|
12
|
-
this.version = '0.1.0';
|
|
13
|
-
this.hasSideEffects = false;
|
|
14
|
-
this.inputSchema = {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {
|
|
17
|
-
selector: { type: 'string', description: 'CSS selector to screenshot a specific element (omit for full page)' },
|
|
18
|
-
fullPage: { type: 'boolean', description: 'Capture the full scrollable page', default: false },
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
19
|
}
|
|
22
20
|
async execute(args) {
|
|
23
21
|
try {
|
|
@@ -32,5 +30,4 @@ class ScreenshotTool {
|
|
|
32
30
|
}
|
|
33
31
|
}
|
|
34
32
|
}
|
|
35
|
-
exports.ScreenshotTool = ScreenshotTool;
|
|
36
33
|
//# sourceMappingURL=ScreenshotTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScreenshotTool.js","sourceRoot":"","sources":["../../src/tools/ScreenshotTool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ScreenshotTool.js","sourceRoot":"","sources":["../../src/tools/ScreenshotTool.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,cAAc;IAiBL;IAhBX,EAAE,GAAG,mBAAmB,CAAC;IACzB,IAAI,GAAG,mBAAmB,CAAC;IAC3B,WAAW,GAAG,iBAAiB,CAAC;IAChC,WAAW,GAAG,6FAA6F,CAAC;IAC5G,QAAQ,GAAG,SAAS,CAAC;IACrB,OAAO,GAAG,OAAO,CAAC;IAClB,cAAc,GAAG,KAAK,CAAC;IAEvB,WAAW,GAAG;QACrB,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oEAAoE,EAAE;YAC/G,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,kCAAkC,EAAE,OAAO,EAAE,KAAK,EAAE;SAC/F;KACF,CAAC;IAEF,YAAoB,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAG,CAAC;IAE/C,KAAK,CAAC,OAAO,CAAC,IAA+C;QAC3D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACnD,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE;aACnE,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
package/dist/tools/ScrollTool.js
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export class ScrollTool {
|
|
2
|
+
browser;
|
|
3
|
+
id = 'browserScroll';
|
|
4
|
+
name = 'browserScroll';
|
|
5
|
+
displayName = 'Scroll Page';
|
|
6
|
+
description = 'Scroll the page up/down by a pixel amount, or scroll a specific element into view.';
|
|
7
|
+
category = 'browser';
|
|
8
|
+
version = '0.1.0';
|
|
9
|
+
hasSideEffects = true;
|
|
10
|
+
inputSchema = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
direction: { type: 'string', enum: ['up', 'down'], description: 'Scroll direction', default: 'down' },
|
|
14
|
+
selector: { type: 'string', description: 'CSS selector of element to scroll into view (overrides direction/pixels)' },
|
|
15
|
+
pixels: { type: 'number', description: 'Number of pixels to scroll', default: 500 },
|
|
16
|
+
},
|
|
17
|
+
};
|
|
5
18
|
constructor(browser) {
|
|
6
19
|
this.browser = browser;
|
|
7
|
-
this.id = 'browserScroll';
|
|
8
|
-
this.name = 'browserScroll';
|
|
9
|
-
this.displayName = 'Scroll Page';
|
|
10
|
-
this.description = 'Scroll the page up/down by a pixel amount, or scroll a specific element into view.';
|
|
11
|
-
this.category = 'browser';
|
|
12
|
-
this.version = '0.1.0';
|
|
13
|
-
this.hasSideEffects = true;
|
|
14
|
-
this.inputSchema = {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {
|
|
17
|
-
direction: { type: 'string', enum: ['up', 'down'], description: 'Scroll direction', default: 'down' },
|
|
18
|
-
selector: { type: 'string', description: 'CSS selector of element to scroll into view (overrides direction/pixels)' },
|
|
19
|
-
pixels: { type: 'number', description: 'Number of pixels to scroll', default: 500 },
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
20
|
}
|
|
23
21
|
async execute(args) {
|
|
24
22
|
try {
|
|
@@ -30,5 +28,4 @@ class ScrollTool {
|
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
30
|
}
|
|
33
|
-
exports.ScrollTool = ScrollTool;
|
|
34
31
|
//# sourceMappingURL=ScrollTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollTool.js","sourceRoot":"","sources":["../../src/tools/ScrollTool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ScrollTool.js","sourceRoot":"","sources":["../../src/tools/ScrollTool.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,UAAU;IAkBD;IAjBX,EAAE,GAAG,eAAe,CAAC;IACrB,IAAI,GAAG,eAAe,CAAC;IACvB,WAAW,GAAG,aAAa,CAAC;IAC5B,WAAW,GAAG,oFAAoF,CAAC;IACnG,QAAQ,GAAG,SAAS,CAAC;IACrB,OAAO,GAAG,OAAO,CAAC;IAClB,cAAc,GAAG,IAAI,CAAC;IAEtB,WAAW,GAAG;QACrB,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE;YACrG,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0EAA0E,EAAE;YACrH,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4BAA4B,EAAE,OAAO,EAAE,GAAG,EAAE;SACpF;KACF,CAAC;IAEF,YAAoB,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAG,CAAC;IAE/C,KAAK,CAAC,OAAO,CAAC,IAAuE;QACnF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export class SessionTool {
|
|
2
|
+
browser;
|
|
3
|
+
id = 'browserSession';
|
|
4
|
+
name = 'browserSession';
|
|
5
|
+
displayName = 'Manage Session';
|
|
6
|
+
description = 'Save or restore browser login sessions (cookies + localStorage). Use "save" to persist the current session, "restore" to load a previously saved session.';
|
|
7
|
+
category = 'browser';
|
|
8
|
+
version = '0.1.0';
|
|
9
|
+
hasSideEffects = true;
|
|
10
|
+
inputSchema = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
action: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
enum: ['save', 'restore'],
|
|
16
|
+
description: 'Whether to save the current session or restore a previous one',
|
|
17
|
+
},
|
|
18
|
+
sessionData: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
description: 'Session state to restore (required for "restore" action)',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
required: ['action'],
|
|
24
|
+
};
|
|
5
25
|
constructor(browser) {
|
|
6
26
|
this.browser = browser;
|
|
7
|
-
this.id = 'browserSession';
|
|
8
|
-
this.name = 'browserSession';
|
|
9
|
-
this.displayName = 'Manage Session';
|
|
10
|
-
this.description = 'Save or restore browser login sessions (cookies + localStorage). Use "save" to persist the current session, "restore" to load a previously saved session.';
|
|
11
|
-
this.category = 'browser';
|
|
12
|
-
this.version = '0.1.0';
|
|
13
|
-
this.hasSideEffects = true;
|
|
14
|
-
this.inputSchema = {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {
|
|
17
|
-
action: {
|
|
18
|
-
type: 'string',
|
|
19
|
-
enum: ['save', 'restore'],
|
|
20
|
-
description: 'Whether to save the current session or restore a previous one',
|
|
21
|
-
},
|
|
22
|
-
sessionData: {
|
|
23
|
-
type: 'object',
|
|
24
|
-
description: 'Session state to restore (required for "restore" action)',
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
required: ['action'],
|
|
28
|
-
};
|
|
29
27
|
}
|
|
30
28
|
async execute(args) {
|
|
31
29
|
try {
|
|
@@ -46,5 +44,4 @@ class SessionTool {
|
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
|
-
exports.SessionTool = SessionTool;
|
|
50
47
|
//# sourceMappingURL=SessionTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionTool.js","sourceRoot":"","sources":["../../src/tools/SessionTool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SessionTool.js","sourceRoot":"","sources":["../../src/tools/SessionTool.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,WAAW;IAyBF;IAxBX,EAAE,GAAG,gBAAgB,CAAC;IACtB,IAAI,GAAG,gBAAgB,CAAC;IACxB,WAAW,GAAG,gBAAgB,CAAC;IAC/B,WAAW,GAAG,2JAA2J,CAAC;IAC1K,QAAQ,GAAG,SAAS,CAAC;IACrB,OAAO,GAAG,OAAO,CAAC;IAClB,cAAc,GAAG,IAAI,CAAC;IAEtB,WAAW,GAAG;QACrB,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;gBACzB,WAAW,EAAE,+DAA+D;aAC7E;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,0DAA0D;aACxE;SACF;QACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;KACrB,CAAC;IAEF,YAAoB,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAG,CAAC;IAE/C,KAAK,CAAC,OAAO,CAAC,IAAuD;QACnE,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;gBAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;oBACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAC;gBACjF,CAAC;gBACD,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
package/dist/tools/WaitTool.js
CHANGED
|
@@ -1,29 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export class WaitTool {
|
|
2
|
+
browser;
|
|
3
|
+
id = 'browserWait';
|
|
4
|
+
name = 'browserWait';
|
|
5
|
+
displayName = 'Wait for Condition';
|
|
6
|
+
description = 'Wait for a CSS selector to appear/disappear, or wait for a specified duration.';
|
|
7
|
+
category = 'browser';
|
|
8
|
+
version = '0.1.0';
|
|
9
|
+
hasSideEffects = false;
|
|
10
|
+
inputSchema = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
selector: { type: 'string', description: 'CSS selector to wait for (omit for time-based wait)' },
|
|
14
|
+
timeout: { type: 'number', description: 'Maximum wait time in milliseconds', default: 30000 },
|
|
15
|
+
state: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['visible', 'hidden', 'attached', 'detached'],
|
|
18
|
+
description: 'Element state to wait for',
|
|
19
|
+
default: 'visible',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
5
23
|
constructor(browser) {
|
|
6
24
|
this.browser = browser;
|
|
7
|
-
this.id = 'browserWait';
|
|
8
|
-
this.name = 'browserWait';
|
|
9
|
-
this.displayName = 'Wait for Condition';
|
|
10
|
-
this.description = 'Wait for a CSS selector to appear/disappear, or wait for a specified duration.';
|
|
11
|
-
this.category = 'browser';
|
|
12
|
-
this.version = '0.1.0';
|
|
13
|
-
this.hasSideEffects = false;
|
|
14
|
-
this.inputSchema = {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {
|
|
17
|
-
selector: { type: 'string', description: 'CSS selector to wait for (omit for time-based wait)' },
|
|
18
|
-
timeout: { type: 'number', description: 'Maximum wait time in milliseconds', default: 30000 },
|
|
19
|
-
state: {
|
|
20
|
-
type: 'string',
|
|
21
|
-
enum: ['visible', 'hidden', 'attached', 'detached'],
|
|
22
|
-
description: 'Element state to wait for',
|
|
23
|
-
default: 'visible',
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
25
|
}
|
|
28
26
|
async execute(args) {
|
|
29
27
|
try {
|
|
@@ -35,5 +33,4 @@ class WaitTool {
|
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
|
-
exports.WaitTool = WaitTool;
|
|
39
36
|
//# sourceMappingURL=WaitTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WaitTool.js","sourceRoot":"","sources":["../../src/tools/WaitTool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WaitTool.js","sourceRoot":"","sources":["../../src/tools/WaitTool.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,QAAQ;IAuBC;IAtBX,EAAE,GAAG,aAAa,CAAC;IACnB,IAAI,GAAG,aAAa,CAAC;IACrB,WAAW,GAAG,oBAAoB,CAAC;IACnC,WAAW,GAAG,gFAAgF,CAAC;IAC/F,QAAQ,GAAG,SAAS,CAAC;IACrB,OAAO,GAAG,OAAO,CAAC;IAClB,cAAc,GAAG,KAAK,CAAC;IAEvB,WAAW,GAAG;QACrB,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qDAAqD,EAAE;YAChG,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE,OAAO,EAAE,KAAK,EAAE;YAC7F,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC;gBACnD,WAAW,EAAE,2BAA2B;gBACxC,OAAO,EAAE,SAAS;aACnB;SACF;KACF,CAAC;IAEF,YAAoB,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAG,CAAC;IAE/C,KAAK,CAAC,OAAO,CAAC,IAAqG;QACjH,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
package/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://agentos.sh/schemas/extension-manifest-v1.json",
|
|
3
3
|
"id": "com.framers.system.browser-automation",
|
|
4
4
|
"name": "Browser Automation Extension",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.3.0",
|
|
6
6
|
"description": "Full browser automation for autonomous agents — navigate URLs, interact with DOM elements, capture screenshots, solve captchas, and rotate proxies. Powered by Playwright with persistent session support.",
|
|
7
7
|
"categories": ["system", "automation", "browser"],
|
|
8
8
|
"sdk": "playwright",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@framers/agentos-ext-browser-automation",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Full browser automation extension for AgentOS — provides agents with autonomous web navigation, DOM interaction, screenshotting, captcha solving, and proxy rotation via Playwright.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"manifest.json"
|
|
20
20
|
],
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@framers/agentos": "
|
|
22
|
+
"@framers/agentos": ">=0.10.40"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"playwright": "^1.50.0"
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"2captcha-ts": "^1.3.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@framers/agentos": "^0.
|
|
31
|
+
"@framers/agentos": "^0.13.59",
|
|
32
32
|
"@types/node": "^22.0.0",
|
|
33
33
|
"typescript": "^5.0.0",
|
|
34
|
-
"vitest": "^
|
|
34
|
+
"vitest": "^3.2.7",
|
|
35
35
|
"ws": "^8.18.0"
|
|
36
36
|
},
|
|
37
37
|
"repository": {
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"bugs": {
|
|
44
44
|
"url": "https://github.com/framerslab/agentos-extensions/issues"
|
|
45
45
|
},
|
|
46
|
+
"type": "module",
|
|
46
47
|
"scripts": {
|
|
47
48
|
"build": "tsc",
|
|
48
49
|
"dev": "tsc --watch",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AttachController.test.d.ts","sourceRoot":"","sources":["../../../src/attach/__tests__/AttachController.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
const vitest_1 = require("vitest");
|
|
37
|
-
const node_fs_1 = require("node:fs");
|
|
38
|
-
const node_os_1 = require("node:os");
|
|
39
|
-
const node_path_1 = require("node:path");
|
|
40
|
-
const AttachController_js_1 = require("../AttachController.js");
|
|
41
|
-
/**
|
|
42
|
-
* Spy backend that records every method call. Its type deliberately mirrors
|
|
43
|
-
* AttachBackend, which has NO browser/tab close surface — the core F10 claim
|
|
44
|
-
* is proven structurally plus asserted behaviorally here.
|
|
45
|
-
*/
|
|
46
|
-
function makeBackend(overrides = {}) {
|
|
47
|
-
const calls = [];
|
|
48
|
-
const backend = {
|
|
49
|
-
kind: 'jxa',
|
|
50
|
-
async connect() {
|
|
51
|
-
calls.push('connect');
|
|
52
|
-
},
|
|
53
|
-
async disconnectTransport() {
|
|
54
|
-
calls.push('disconnectTransport');
|
|
55
|
-
},
|
|
56
|
-
async claimAgentTab() {
|
|
57
|
-
calls.push('claimAgentTab');
|
|
58
|
-
return 'w1 t1';
|
|
59
|
-
},
|
|
60
|
-
async probeIdentity() {
|
|
61
|
-
calls.push('probeIdentity');
|
|
62
|
-
return 'Inbox - johnny@example.com - Gmail';
|
|
63
|
-
},
|
|
64
|
-
async gotoTab(_tab, url) {
|
|
65
|
-
calls.push(`goto:${url}`);
|
|
66
|
-
return url;
|
|
67
|
-
},
|
|
68
|
-
async readTab() {
|
|
69
|
-
calls.push('read');
|
|
70
|
-
return 'text';
|
|
71
|
-
},
|
|
72
|
-
...overrides,
|
|
73
|
-
};
|
|
74
|
-
return { backend, calls };
|
|
75
|
-
}
|
|
76
|
-
let leaseFile;
|
|
77
|
-
(0, vitest_1.beforeEach)(() => {
|
|
78
|
-
leaseFile = (0, node_path_1.join)((0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'attach-ctl-')), 'attach.lease');
|
|
79
|
-
});
|
|
80
|
-
function controller(backend, extra = {}) {
|
|
81
|
-
return new AttachController_js_1.AttachController({
|
|
82
|
-
backend,
|
|
83
|
-
leaseFile,
|
|
84
|
-
expectedIdentity: 'johnny@example.com',
|
|
85
|
-
...extra,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
(0, vitest_1.describe)('AttachController', () => {
|
|
89
|
-
(0, vitest_1.it)('claims: lease → connect → identity probe → agent tab', async () => {
|
|
90
|
-
const { backend, calls } = makeBackend();
|
|
91
|
-
const c = controller(backend);
|
|
92
|
-
const st = await c.claim();
|
|
93
|
-
(0, vitest_1.expect)(st.state).toBe('ready');
|
|
94
|
-
(0, vitest_1.expect)(st.leaseHeld).toBe(true);
|
|
95
|
-
(0, vitest_1.expect)(st.agentTab).toBe('w1 t1');
|
|
96
|
-
(0, vitest_1.expect)(calls).toEqual(['connect', 'probeIdentity', 'claimAgentTab']);
|
|
97
|
-
await c.detach();
|
|
98
|
-
});
|
|
99
|
-
(0, vitest_1.it)('ABORTS with PROFILE_MISMATCH instead of proceeding on wrong identity (never launches)', async () => {
|
|
100
|
-
const { backend, calls } = makeBackend({
|
|
101
|
-
async probeIdentity() {
|
|
102
|
-
calls.push('probeIdentity');
|
|
103
|
-
return 'someone-else@example.com session';
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
const { backend: b2, calls: c2 } = { backend, calls };
|
|
107
|
-
const c = controller(b2);
|
|
108
|
-
await (0, vitest_1.expect)(c.claim()).rejects.toMatchObject({ code: 'PROFILE_MISMATCH' });
|
|
109
|
-
(0, vitest_1.expect)(c2).not.toContain('claimAgentTab'); // no tab was touched
|
|
110
|
-
(0, vitest_1.expect)(c.status().leaseHeld).toBe(false); // lease released on failure
|
|
111
|
-
});
|
|
112
|
-
(0, vitest_1.it)('policy-blocks bad navigation before touching the backend', async () => {
|
|
113
|
-
const { backend, calls } = makeBackend();
|
|
114
|
-
const c = controller(backend);
|
|
115
|
-
await c.claim();
|
|
116
|
-
await (0, vitest_1.expect)(c.goto('file:///etc/passwd')).rejects.toMatchObject({ code: 'POLICY_BLOCKED' });
|
|
117
|
-
(0, vitest_1.expect)(calls.filter((x) => x.startsWith('goto:'))).toHaveLength(0);
|
|
118
|
-
await c.detach();
|
|
119
|
-
});
|
|
120
|
-
(0, vitest_1.it)('revalidates redirects: an https→http downgrade fails the op', async () => {
|
|
121
|
-
const { backend } = makeBackend({
|
|
122
|
-
async gotoTab() {
|
|
123
|
-
return 'http://downgraded.example.com/';
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
const c = controller(backend);
|
|
127
|
-
await c.claim();
|
|
128
|
-
await (0, vitest_1.expect)(c.goto('https://ok.example.com/')).rejects.toMatchObject({ code: 'POLICY_BLOCKED' });
|
|
129
|
-
await c.detach();
|
|
130
|
-
});
|
|
131
|
-
(0, vitest_1.it)('detach closes ONLY the transport and releases the lease — no close surface exists', async () => {
|
|
132
|
-
const { backend, calls } = makeBackend();
|
|
133
|
-
const c = controller(backend);
|
|
134
|
-
await c.claim();
|
|
135
|
-
await c.detach();
|
|
136
|
-
(0, vitest_1.expect)(calls).toContain('disconnectTransport');
|
|
137
|
-
// Structural F10 guarantee: the backend contract exposes no browser/tab
|
|
138
|
-
// close method for the controller to call.
|
|
139
|
-
const forbidden = ['close', 'closeBrowser', 'closeTab', 'quit'];
|
|
140
|
-
for (const name of forbidden) {
|
|
141
|
-
(0, vitest_1.expect)(backend[name]).toBeUndefined();
|
|
142
|
-
}
|
|
143
|
-
// Lease is released → a second controller can claim.
|
|
144
|
-
const c2 = controller(makeBackend().backend);
|
|
145
|
-
await (0, vitest_1.expect)(c2.claim()).resolves.toMatchObject({ state: 'ready' });
|
|
146
|
-
await c2.detach();
|
|
147
|
-
});
|
|
148
|
-
(0, vitest_1.it)('second concurrent claim is LEASE_DENIED while the first holds', async () => {
|
|
149
|
-
const { backend } = makeBackend();
|
|
150
|
-
const c1 = controller(backend);
|
|
151
|
-
await c1.claim();
|
|
152
|
-
const c2 = controller(makeBackend().backend);
|
|
153
|
-
await (0, vitest_1.expect)(c2.claim()).rejects.toMatchObject({ code: 'LEASE_DENIED' });
|
|
154
|
-
await c1.detach();
|
|
155
|
-
});
|
|
156
|
-
(0, vitest_1.it)('a failed navigation lands in failed state and refuses further ops (no silent replay)', async () => {
|
|
157
|
-
const { backend } = makeBackend({
|
|
158
|
-
async gotoTab() {
|
|
159
|
-
throw new Error('tab 999 not found in window 1');
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
const c = controller(backend);
|
|
163
|
-
await c.claim();
|
|
164
|
-
await (0, vitest_1.expect)(c.goto('https://ok.example.com/')).rejects.toBeTruthy();
|
|
165
|
-
(0, vitest_1.expect)(c.status().state).toBe('failed');
|
|
166
|
-
(0, vitest_1.expect)(c.status().lastError?.code).toBe('TAB_CLOSED');
|
|
167
|
-
await (0, vitest_1.expect)(c.read()).rejects.toMatchObject({ code: 'UNKNOWN' });
|
|
168
|
-
await c.detach();
|
|
169
|
-
(0, vitest_1.expect)(c.status().state).toBe('disconnected');
|
|
170
|
-
});
|
|
171
|
-
(0, vitest_1.it)('HITL approver can deny a policy-clean navigation', async () => {
|
|
172
|
-
const { backend, calls } = makeBackend();
|
|
173
|
-
const c = controller(backend, { onNavigate: (url) => !url.includes('secret') });
|
|
174
|
-
await c.claim();
|
|
175
|
-
await (0, vitest_1.expect)(c.goto('https://ok.example.com/secret')).rejects.toMatchObject({ code: 'POLICY_BLOCKED' });
|
|
176
|
-
(0, vitest_1.expect)(calls.filter((x) => x.startsWith('goto:'))).toHaveLength(0); // never reached the backend
|
|
177
|
-
await (0, vitest_1.expect)(c.goto('https://ok.example.com/public')).resolves.toContain('public');
|
|
178
|
-
await c.detach();
|
|
179
|
-
});
|
|
180
|
-
(0, vitest_1.it)('dry-run reports the target without touching the backend, and counts navigations', async () => {
|
|
181
|
-
const { backend, calls } = makeBackend();
|
|
182
|
-
const c = controller(backend, { dryRun: true });
|
|
183
|
-
await c.claim();
|
|
184
|
-
(0, vitest_1.expect)(await c.goto('https://ok.example.com/')).toBe('https://ok.example.com/');
|
|
185
|
-
(0, vitest_1.expect)(await c.read()).toContain('dry-run');
|
|
186
|
-
(0, vitest_1.expect)(calls.filter((x) => x.startsWith('goto:'))).toHaveLength(0);
|
|
187
|
-
(0, vitest_1.expect)(c.status().dryRun).toBe(true);
|
|
188
|
-
(0, vitest_1.expect)(c.status().navigations).toBe(1);
|
|
189
|
-
(0, vitest_1.expect)(c.status().lastUrl).toBe('https://ok.example.com/');
|
|
190
|
-
await c.detach();
|
|
191
|
-
});
|
|
192
|
-
(0, vitest_1.it)('pause refuses operations until resume', async () => {
|
|
193
|
-
const { backend } = makeBackend();
|
|
194
|
-
const c = controller(backend);
|
|
195
|
-
await c.claim();
|
|
196
|
-
c.pause();
|
|
197
|
-
(0, vitest_1.expect)(c.status().paused).toBe(true);
|
|
198
|
-
await (0, vitest_1.expect)(c.goto('https://ok.example.com/')).rejects.toThrow(/paused/i);
|
|
199
|
-
c.resume();
|
|
200
|
-
await (0, vitest_1.expect)(c.goto('https://ok.example.com/')).resolves.toContain('ok.example.com');
|
|
201
|
-
await c.detach();
|
|
202
|
-
});
|
|
203
|
-
(0, vitest_1.it)('status tracks navigation count and last url on real ops', async () => {
|
|
204
|
-
const { backend } = makeBackend();
|
|
205
|
-
const c = controller(backend);
|
|
206
|
-
await c.claim();
|
|
207
|
-
await c.goto('https://a.example.com/');
|
|
208
|
-
await c.goto('https://b.example.com/');
|
|
209
|
-
(0, vitest_1.expect)(c.status().navigations).toBe(2);
|
|
210
|
-
(0, vitest_1.expect)(c.status().lastUrl).toBe('https://b.example.com/');
|
|
211
|
-
await c.detach();
|
|
212
|
-
});
|
|
213
|
-
(0, vitest_1.it)('ops enforce the lease nonce at call time (foreign takeover is detected)', async () => {
|
|
214
|
-
let t = 1000000;
|
|
215
|
-
const { backend } = makeBackend();
|
|
216
|
-
const c = controller(backend, { deadlineMs: 500 });
|
|
217
|
-
await c.claim();
|
|
218
|
-
// Simulate a foreign session force-taking the lease file.
|
|
219
|
-
const { acquireLease } = await Promise.resolve().then(() => __importStar(require('../lease.js')));
|
|
220
|
-
acquireLease({ file: leaseFile, isPidAlive: () => false, now: () => (t += 1) });
|
|
221
|
-
await (0, vitest_1.expect)(c.goto('https://ok.example.com/')).rejects.toMatchObject({ code: 'LEASE_DENIED' });
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
(0, vitest_1.describe)('extract and evaluate', () => {
|
|
225
|
-
(0, vitest_1.it)('extract maps {name: selector} to text lists via a FIXED expression (selectors are data)', async () => {
|
|
226
|
-
const exprs = [];
|
|
227
|
-
const { backend } = makeBackend({
|
|
228
|
-
async evalInTab(_tab, expression) {
|
|
229
|
-
exprs.push(expression);
|
|
230
|
-
return { perks: ['Late checkout', 'Breakfast for two'] };
|
|
231
|
-
},
|
|
232
|
-
});
|
|
233
|
-
const c = controller(backend);
|
|
234
|
-
await c.claim();
|
|
235
|
-
const out = await c.extract({ perks: "[class*='perk'] li" });
|
|
236
|
-
(0, vitest_1.expect)(out).toEqual({ perks: ['Late checkout', 'Breakfast for two'] });
|
|
237
|
-
(0, vitest_1.expect)(exprs[0]).toContain('querySelectorAll');
|
|
238
|
-
(0, vitest_1.expect)(exprs[0]).toContain('perk');
|
|
239
|
-
});
|
|
240
|
-
(0, vitest_1.it)('extract without fields requests the default page summary expression', async () => {
|
|
241
|
-
const exprs = [];
|
|
242
|
-
const { backend } = makeBackend({
|
|
243
|
-
async evalInTab(_tab, expression) {
|
|
244
|
-
exprs.push(expression);
|
|
245
|
-
return { url: 'https://x/', links: [] };
|
|
246
|
-
},
|
|
247
|
-
});
|
|
248
|
-
const c = controller(backend);
|
|
249
|
-
await c.claim();
|
|
250
|
-
await c.extract();
|
|
251
|
-
(0, vitest_1.expect)(exprs[0]).toContain('location.href');
|
|
252
|
-
(0, vitest_1.expect)(exprs[0]).toContain('document.title');
|
|
253
|
-
});
|
|
254
|
-
(0, vitest_1.it)('extract and evaluate surface UNSUPPORTED_OP when the backend lacks evalInTab', async () => {
|
|
255
|
-
const { backend } = makeBackend();
|
|
256
|
-
const c = controller(backend);
|
|
257
|
-
await c.claim();
|
|
258
|
-
await (0, vitest_1.expect)(c.extract()).rejects.toMatchObject({ code: 'UNSUPPORTED_OP' });
|
|
259
|
-
await (0, vitest_1.expect)(c.evaluate('1+1')).rejects.toMatchObject({ code: 'UNSUPPORTED_OP' });
|
|
260
|
-
});
|
|
261
|
-
(0, vitest_1.it)('evaluate passes the expression through (user lane; no tool exposes it)', async () => {
|
|
262
|
-
const { backend } = makeBackend({
|
|
263
|
-
async evalInTab(_tab, expression) {
|
|
264
|
-
return expression === '1+1' ? 2 : undefined;
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
const c = controller(backend);
|
|
268
|
-
await c.claim();
|
|
269
|
-
await (0, vitest_1.expect)(c.evaluate('1+1')).resolves.toBe(2);
|
|
270
|
-
});
|
|
271
|
-
(0, vitest_1.it)('both refuse before claim like every other driving op', async () => {
|
|
272
|
-
const { backend } = makeBackend({ async evalInTab() { return 1; } });
|
|
273
|
-
const c = controller(backend);
|
|
274
|
-
await (0, vitest_1.expect)(c.extract()).rejects.toMatchObject({ code: 'UNKNOWN' });
|
|
275
|
-
await (0, vitest_1.expect)(c.evaluate('1')).rejects.toMatchObject({ code: 'UNKNOWN' });
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
//# sourceMappingURL=AttachController.test.js.map
|