dsh-browser-playwright-codex 0.5.2 → 0.5.3
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/CHANGELOG.md +30 -0
- package/lib/browser-lifecycle.d.ts +12 -0
- package/lib/browser-lifecycle.js +186 -0
- package/lib/challenge.d.ts +20 -0
- package/lib/challenge.js +40 -0
- package/lib/config.d.ts +81 -0
- package/lib/config.js +61 -0
- package/lib/extract.d.ts +13 -0
- package/lib/extract.js +34 -0
- package/lib/index.d.ts +4 -2
- package/lib/index.js +3 -1
- package/lib/login-state.d.ts +10 -0
- package/lib/login-state.js +83 -0
- package/lib/page-actions.d.ts +134 -0
- package/lib/page-actions.js +725 -0
- package/lib/page-diagnostics.d.ts +65 -0
- package/lib/page-diagnostics.js +181 -0
- package/lib/page-probes.d.ts +78 -0
- package/lib/page-probes.js +281 -0
- package/lib/page-snapshot.d.ts +96 -0
- package/lib/page-snapshot.js +280 -0
- package/lib/playwright.d.ts +5 -644
- package/lib/playwright.js +28 -2602
- package/lib/provider.d.ts +157 -0
- package/lib/provider.js +352 -0
- package/lib/session.d.ts +410 -0
- package/lib/session.js +633 -0
- package/lib/tool-render.d.ts +20 -0
- package/lib/tool-render.js +137 -0
- package/lib/tool-schemas.d.ts +76 -0
- package/lib/tool-schemas.js +46 -0
- package/lib/tool-types.d.ts +82 -0
- package/lib/tool-types.js +1 -0
- package/lib/tool.d.ts +2 -26
- package/lib/tool.js +5 -252
- package/lib/url-policy.d.ts +2 -0
- package/lib/url-policy.js +26 -0
- package/lib/window-focus.d.ts +27 -0
- package/lib/window-focus.js +54 -0
- package/package.json +1 -1
- package/scripts/dsh-browser-verify.mjs +2 -1
- package/scripts/prompt-cost.mjs +1 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL 策略:只允许访问白名单域名(含点击后导航的校验)。
|
|
3
|
+
* @module dsh-browser-playwright-codex/url-policy
|
|
4
|
+
*/
|
|
5
|
+
import { BrowserError } from "./errors.js";
|
|
6
|
+
/** Validate one absolute URL against the navigation policy. */
|
|
7
|
+
export function assertAllowedUrl(raw, allowedDomains) {
|
|
8
|
+
let parsed;
|
|
9
|
+
try {
|
|
10
|
+
parsed = new URL(raw);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new BrowserError('URL_NOT_ALLOWED', 'invalid URL: ' + raw);
|
|
14
|
+
}
|
|
15
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
16
|
+
throw new BrowserError('URL_NOT_ALLOWED', 'only http(s) URLs can be navigated, got: ' + parsed.protocol);
|
|
17
|
+
}
|
|
18
|
+
if (allowedDomains.length > 0) {
|
|
19
|
+
const host = parsed.hostname.toLowerCase();
|
|
20
|
+
const allowed = allowedDomains.some((suffix) => host === suffix || host.endsWith('.' + suffix));
|
|
21
|
+
if (!allowed) {
|
|
22
|
+
throw new BrowserError('URL_NOT_ALLOWED', 'host ' + parsed.hostname + ' is not in allowedDomains');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 窗口与焦点行为:判断承载页面的系统窗口是否最小化,以及在后台创建标签页 —— 两项都是为了让
|
|
3
|
+
* 窗口/标签不打扰用户。背景与实测见 FOCUS-STEALING.md。
|
|
4
|
+
* @module dsh-browser-playwright-codex/window-focus
|
|
5
|
+
*/
|
|
6
|
+
import type { BrowserContext, Page } from 'playwright-core';
|
|
7
|
+
/**
|
|
8
|
+
* True when the OS window hosting this page is minimized. Tab selection lives
|
|
9
|
+
* in the browser context, not in the OS window, so activation is a side effect
|
|
10
|
+
* we are free to decline — and declining it is what keeps the agent from
|
|
11
|
+
* yanking a minimized window into the user's face. If the window state cannot
|
|
12
|
+
* be read we answer true (treat as minimized): the safe direction is to leave
|
|
13
|
+
* the user's desktop alone, and a skipped bringToFront costs nothing functional.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isWindowMinimized(page: Page): Promise<boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* Create a tab without raising the window. context.newPage() routes through CDP
|
|
18
|
+
* Target.createTarget without `background`, and Chromium activates the window
|
|
19
|
+
* on every tab creation -- plainly visible once the user has minimized it.
|
|
20
|
+
* Sending the command ourselves with background:true creates the tab silently;
|
|
21
|
+
* Playwright still auto-attaches and returns a fully driveable Page (verified
|
|
22
|
+
* live: Playwright learns the page and evaluate() runs on it). The URL is left
|
|
23
|
+
* at about:blank on purpose so the caller's own goto keeps owning navigation
|
|
24
|
+
* policy, timeouts and abort handling. On any failure this falls back to
|
|
25
|
+
* newPage(): a tab that pops the window beats no tab at all.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createBackgroundPage(context: BrowserContext): Promise<Page>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True when the OS window hosting this page is minimized. Tab selection lives
|
|
3
|
+
* in the browser context, not in the OS window, so activation is a side effect
|
|
4
|
+
* we are free to decline — and declining it is what keeps the agent from
|
|
5
|
+
* yanking a minimized window into the user's face. If the window state cannot
|
|
6
|
+
* be read we answer true (treat as minimized): the safe direction is to leave
|
|
7
|
+
* the user's desktop alone, and a skipped bringToFront costs nothing functional.
|
|
8
|
+
*/
|
|
9
|
+
export async function isWindowMinimized(page) {
|
|
10
|
+
let provider;
|
|
11
|
+
try {
|
|
12
|
+
provider = await page.context().newCDPSession(page);
|
|
13
|
+
const { windowId } = await provider.send('Browser.getWindowForTarget');
|
|
14
|
+
const { bounds } = await provider.send('Browser.getWindowBounds', { windowId });
|
|
15
|
+
return bounds.windowState === 'minimized';
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await provider?.detach().catch(() => { });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create a tab without raising the window. context.newPage() routes through CDP
|
|
26
|
+
* Target.createTarget without `background`, and Chromium activates the window
|
|
27
|
+
* on every tab creation -- plainly visible once the user has minimized it.
|
|
28
|
+
* Sending the command ourselves with background:true creates the tab silently;
|
|
29
|
+
* Playwright still auto-attaches and returns a fully driveable Page (verified
|
|
30
|
+
* live: Playwright learns the page and evaluate() runs on it). The URL is left
|
|
31
|
+
* at about:blank on purpose so the caller's own goto keeps owning navigation
|
|
32
|
+
* policy, timeouts and abort handling. On any failure this falls back to
|
|
33
|
+
* newPage(): a tab that pops the window beats no tab at all.
|
|
34
|
+
*/
|
|
35
|
+
export async function createBackgroundPage(context) {
|
|
36
|
+
const anchor = context.pages()[0];
|
|
37
|
+
if (anchor === undefined)
|
|
38
|
+
return await context.newPage();
|
|
39
|
+
let provider;
|
|
40
|
+
try {
|
|
41
|
+
provider = await context.newCDPSession(anchor);
|
|
42
|
+
// Arm the listener before sending: Playwright attaches as soon as the
|
|
43
|
+
// target exists, which can happen before createTarget resolves.
|
|
44
|
+
const attached = context.waitForEvent('page', { timeout: 10000 });
|
|
45
|
+
await provider.send('Target.createTarget', { url: 'about:blank', background: true });
|
|
46
|
+
return await attached;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return await context.newPage();
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
await provider?.detach().catch(() => { });
|
|
53
|
+
}
|
|
54
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-browser-playwright-codex",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Browser automation for DeepSeek Harness: fill in forms, scrape lists and work across tabs in real pages, using the logins you already have. Runs in a visible window that stays quiet when minimised, and stops for sign-ins, CAPTCHAs and native dialogs instead of confirming for you.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,8 @@ import http from 'node:http'
|
|
|
23
23
|
import { readdirSync, statSync } from 'node:fs'
|
|
24
24
|
import os from 'node:os'
|
|
25
25
|
import path from 'node:path'
|
|
26
|
-
import {
|
|
26
|
+
import { PlaywrightProvider } from '../lib/provider.js'
|
|
27
|
+
import { Config as ConfigSchema } from '../lib/config.js'
|
|
27
28
|
import { renderSnapshot } from '../lib/snapshot-render.js'
|
|
28
29
|
import { getEffectiveEngine, setSnapshotEngine } from '../lib/runtime-state.js'
|
|
29
30
|
|
package/scripts/prompt-cost.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { Context } from '@deepseek-ai/cordis'
|
|
|
12
12
|
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
|
13
13
|
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
|
14
14
|
import BrowserRuntime from '../src/service.ts'
|
|
15
|
-
import { PlaywrightProvider } from '../src/
|
|
15
|
+
import { PlaywrightProvider } from '../src/provider.ts'
|
|
16
16
|
import * as browserTool from '../src/tool.ts'
|
|
17
17
|
import { bundleConfig } from './shipped-gates.mjs'
|
|
18
18
|
|