@anweat/dsh-browser 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +92 -0
- package/cordis.patch.yml +15 -0
- package/lib/browser-service.d.ts +127 -0
- package/lib/browser-service.js +362 -0
- package/lib/browser-service.js.map +1 -0
- package/lib/config.d.ts +37 -0
- package/lib/config.js +37 -0
- package/lib/config.js.map +1 -0
- package/lib/deps.d.ts +46 -0
- package/lib/deps.js +155 -0
- package/lib/deps.js.map +1 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.js +43 -0
- package/lib/index.js.map +1 -0
- package/lib/tools.d.ts +10 -0
- package/lib/tools.js +240 -0
- package/lib/tools.js.map +1 -0
- package/package.json +52 -0
- package/scripts/install-browser.mjs +18 -0
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-browser plugin configuration (schemastery) and the resolved runtime shape.
|
|
3
|
+
* @module dsh-browser/config
|
|
4
|
+
*/
|
|
5
|
+
import z from '@deepseek-ai/schemastery';
|
|
6
|
+
export interface Config {
|
|
7
|
+
/** Whether the browser service is active. */
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
/** Browser channel: 'chromium' (bundled, self-contained) or 'msedge'. */
|
|
10
|
+
channel: string;
|
|
11
|
+
headless: boolean;
|
|
12
|
+
/** Path to a Playwright storageState JSON (persisted login state). */
|
|
13
|
+
storageStatePath?: string;
|
|
14
|
+
/** Explicit browser executable path override (rare). */
|
|
15
|
+
executablePath?: string;
|
|
16
|
+
/** Whether the bundled OpenCLI is enabled. */
|
|
17
|
+
opencliEnabled: boolean;
|
|
18
|
+
/** Lazily run `playwright install chromium` when the browser is missing. */
|
|
19
|
+
autoInstall: boolean;
|
|
20
|
+
/** Directory for browser screenshots; defaults to $DSH_HOME/data/browser/snapshots. */
|
|
21
|
+
snapshotDir?: string;
|
|
22
|
+
verbose: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare const Config: z<Config>;
|
|
25
|
+
export interface ResolvedConfig {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
channel: string;
|
|
28
|
+
headless: boolean;
|
|
29
|
+
storageStatePath?: string;
|
|
30
|
+
executablePath?: string;
|
|
31
|
+
opencliEnabled: boolean;
|
|
32
|
+
autoInstall: boolean;
|
|
33
|
+
snapshotDir: string;
|
|
34
|
+
verbose: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function defaultSnapshotDir(): string;
|
|
37
|
+
export declare function resolveConfig(config: Config): ResolvedConfig;
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-browser plugin configuration (schemastery) and the resolved runtime shape.
|
|
3
|
+
* @module dsh-browser/config
|
|
4
|
+
*/
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import z from '@deepseek-ai/schemastery';
|
|
8
|
+
export const Config = z.object({
|
|
9
|
+
enabled: z.boolean().default(true),
|
|
10
|
+
channel: z.string().default('chromium'),
|
|
11
|
+
headless: z.boolean().default(true),
|
|
12
|
+
storageStatePath: z.string(),
|
|
13
|
+
executablePath: z.string(),
|
|
14
|
+
opencliEnabled: z.boolean().default(true),
|
|
15
|
+
autoInstall: z.boolean().default(false),
|
|
16
|
+
snapshotDir: z.string(),
|
|
17
|
+
verbose: z.boolean().default(false),
|
|
18
|
+
});
|
|
19
|
+
export function defaultSnapshotDir() {
|
|
20
|
+
const home = process.env.DSH_HOME ?? path.join(os.homedir(), '.dsh');
|
|
21
|
+
return path.join(home, 'data', 'browser', 'snapshots');
|
|
22
|
+
}
|
|
23
|
+
export function resolveConfig(config) {
|
|
24
|
+
const snapshotDir = config.snapshotDir ?? defaultSnapshotDir();
|
|
25
|
+
return {
|
|
26
|
+
enabled: config.enabled ?? true,
|
|
27
|
+
channel: config.channel ?? 'chromium',
|
|
28
|
+
headless: config.headless ?? true,
|
|
29
|
+
opencliEnabled: config.opencliEnabled ?? true,
|
|
30
|
+
autoInstall: config.autoInstall ?? false,
|
|
31
|
+
snapshotDir,
|
|
32
|
+
verbose: config.verbose ?? false,
|
|
33
|
+
...config.storageStatePath !== undefined && config.storageStatePath !== '' ? { storageStatePath: config.storageStatePath } : {},
|
|
34
|
+
...config.executablePath !== undefined && config.executablePath !== '' ? { executablePath: config.executablePath } : {},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAqBxC,MAAM,CAAC,MAAM,MAAM,GAAc,CAAC,CAAC,MAAM,CAAC;IACxC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;IACvC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACnC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;IAC1B,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACzC,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACvC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACpC,CAAC,CAAA;AAcF,MAAM,UAAU,kBAAkB;IAChC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAA;IACpE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,kBAAkB,EAAE,CAAA;IAC9D,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,UAAU;QACrC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;QACjC,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,IAAI;QAC7C,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;QACxC,WAAW;QACX,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK;QAChC,GAAG,MAAM,CAAC,gBAAgB,KAAK,SAAS,IAAI,MAAM,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE;QAC/H,GAAG,MAAM,CAAC,cAAc,KAAK,SAAS,IAAI,MAAM,CAAC,cAAc,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE;KACxH,CAAA;AACH,CAAC"}
|
package/lib/deps.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency resolution for dsh-browser, with reuse fallback.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order (per dependency):
|
|
5
|
+
* 1. THIS plugin's own node_modules — self-contained when distributed
|
|
6
|
+
* (playwright / @jackwener/opencli are declared in package.json).
|
|
7
|
+
* 2. The global npm root — reuse what's already installed on the machine,
|
|
8
|
+
* so a dev box needs zero extra install.
|
|
9
|
+
*
|
|
10
|
+
* The Playwright BROWSER BINARY (chromium) is NOT bundled here and NOT
|
|
11
|
+
* re-downloaded: playwright loads it from its shared cache (Windows:
|
|
12
|
+
* %LOCALAPPDATA%\ms-playwright), which this machine already has. So
|
|
13
|
+
* `channel: chromium` is pure reuse of chromium-1234.
|
|
14
|
+
* @module dsh-browser/deps
|
|
15
|
+
*/
|
|
16
|
+
/** Plugin package root (scratch-plugin/browser). */
|
|
17
|
+
export declare const PLUGIN_ROOT: string;
|
|
18
|
+
export interface CliResult {
|
|
19
|
+
code: number;
|
|
20
|
+
stdout: string;
|
|
21
|
+
stderr: string;
|
|
22
|
+
timedOut: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Resolve the playwright module (plugin-local, then global reuse). */
|
|
25
|
+
export declare function loadPlaywright(): any;
|
|
26
|
+
/** playwright CLI entry (for `playwright install chromium`). */
|
|
27
|
+
export declare function playwrightCliPath(): string;
|
|
28
|
+
/** Entry JS for the bundled/reused @jackwener/opencli (its bin/main). */
|
|
29
|
+
export declare function opencliEntryPath(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Run a Node.js script with piped stdio capture (bundled opencli / playwright
|
|
32
|
+
* CLI). Mirrors web-search-pro's runCli contract.
|
|
33
|
+
*/
|
|
34
|
+
export declare function runNode(script: string, args: string[], opts?: {
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
signal: AbortSignal | undefined;
|
|
37
|
+
maxOutput?: number;
|
|
38
|
+
cwd?: string;
|
|
39
|
+
env?: Record<string, string>;
|
|
40
|
+
}): Promise<CliResult>;
|
|
41
|
+
/** Run opencli (bundled or global-reuse). */
|
|
42
|
+
export declare function runOpencli(args: string[], opts?: {
|
|
43
|
+
timeoutMs?: number;
|
|
44
|
+
signal: AbortSignal | undefined;
|
|
45
|
+
maxOutput?: number;
|
|
46
|
+
}): Promise<CliResult>;
|
package/lib/deps.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency resolution for dsh-browser, with reuse fallback.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order (per dependency):
|
|
5
|
+
* 1. THIS plugin's own node_modules — self-contained when distributed
|
|
6
|
+
* (playwright / @jackwener/opencli are declared in package.json).
|
|
7
|
+
* 2. The global npm root — reuse what's already installed on the machine,
|
|
8
|
+
* so a dev box needs zero extra install.
|
|
9
|
+
*
|
|
10
|
+
* The Playwright BROWSER BINARY (chromium) is NOT bundled here and NOT
|
|
11
|
+
* re-downloaded: playwright loads it from its shared cache (Windows:
|
|
12
|
+
* %LOCALAPPDATA%\ms-playwright), which this machine already has. So
|
|
13
|
+
* `channel: chromium` is pure reuse of chromium-1234.
|
|
14
|
+
* @module dsh-browser/deps
|
|
15
|
+
*/
|
|
16
|
+
import { createRequire } from 'node:module';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import fs from 'node:fs';
|
|
21
|
+
/** Plugin package root (scratch-plugin/browser). */
|
|
22
|
+
export const PLUGIN_ROOT = fileURLToPath(new URL('..', import.meta.url));
|
|
23
|
+
let cachedGlobalRoot;
|
|
24
|
+
/** `npm root -g`, computed once (falls back to the APPDATA npm dir on Windows). */
|
|
25
|
+
function globalNpmRoot() {
|
|
26
|
+
if (cachedGlobalRoot)
|
|
27
|
+
return cachedGlobalRoot;
|
|
28
|
+
try {
|
|
29
|
+
cachedGlobalRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', windowsHide: true, timeout: 15000 }).trim();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
cachedGlobalRoot = path.join(process.env.APPDATA ?? '', 'npm', 'node_modules');
|
|
33
|
+
}
|
|
34
|
+
return cachedGlobalRoot;
|
|
35
|
+
}
|
|
36
|
+
/** Walk up from a resolved file to the nearest package.json (its package root). */
|
|
37
|
+
function findPackageRoot(fromFile) {
|
|
38
|
+
let dir = path.dirname(fromFile);
|
|
39
|
+
for (let i = 0; i < 20; i++) {
|
|
40
|
+
const pj = path.join(dir, 'package.json');
|
|
41
|
+
if (fs.existsSync(pj))
|
|
42
|
+
return pj;
|
|
43
|
+
const parent = path.dirname(dir);
|
|
44
|
+
if (parent === dir)
|
|
45
|
+
return undefined;
|
|
46
|
+
dir = parent;
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve a dependency's package.json: plugin-local first, global npm second.
|
|
52
|
+
* Packages that do NOT export `./package.json` (e.g. @jackwener/opencli) are
|
|
53
|
+
* resolved via their main entry and then walked up to the package root.
|
|
54
|
+
*/
|
|
55
|
+
function resolvePkgJson(name) {
|
|
56
|
+
const anchors = [
|
|
57
|
+
path.join(PLUGIN_ROOT, 'package.json'),
|
|
58
|
+
path.join(globalNpmRoot(), name, 'package.json'),
|
|
59
|
+
];
|
|
60
|
+
for (const anchor of anchors) {
|
|
61
|
+
const req = createRequire(anchor);
|
|
62
|
+
try {
|
|
63
|
+
return req.resolve(name + '/package.json');
|
|
64
|
+
}
|
|
65
|
+
catch { /* exports-restricted */ }
|
|
66
|
+
try {
|
|
67
|
+
const entry = req.resolve(name);
|
|
68
|
+
const root = findPackageRoot(entry);
|
|
69
|
+
if (root)
|
|
70
|
+
return root;
|
|
71
|
+
}
|
|
72
|
+
catch { /* not found at this anchor */ }
|
|
73
|
+
}
|
|
74
|
+
throw new Error('dsh-browser: ' + name + ' not found in plugin node_modules or global npm. Run `npm install` in ' + PLUGIN_ROOT + ' (or install ' + name + ' globally).');
|
|
75
|
+
}
|
|
76
|
+
function pkgDir(name) {
|
|
77
|
+
return path.dirname(resolvePkgJson(name));
|
|
78
|
+
}
|
|
79
|
+
let cachedPlaywright;
|
|
80
|
+
/** Resolve the playwright module (plugin-local, then global reuse). */
|
|
81
|
+
export function loadPlaywright() {
|
|
82
|
+
if (cachedPlaywright)
|
|
83
|
+
return cachedPlaywright;
|
|
84
|
+
cachedPlaywright = createRequire(resolvePkgJson('playwright'))('playwright');
|
|
85
|
+
return cachedPlaywright;
|
|
86
|
+
}
|
|
87
|
+
/** playwright CLI entry (for `playwright install chromium`). */
|
|
88
|
+
export function playwrightCliPath() {
|
|
89
|
+
return path.join(pkgDir('playwright'), 'cli.js');
|
|
90
|
+
}
|
|
91
|
+
/** Entry JS for the bundled/reused @jackwener/opencli (its bin/main). */
|
|
92
|
+
export function opencliEntryPath() {
|
|
93
|
+
const dir = pkgDir('@jackwener/opencli');
|
|
94
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
95
|
+
const bin = typeof pkg.bin === 'string' ? pkg.bin : (pkg.bin?.opencli ?? pkg.main ?? 'dist/src/main.js');
|
|
96
|
+
return path.join(dir, bin);
|
|
97
|
+
}
|
|
98
|
+
function quoteArg(arg) {
|
|
99
|
+
if (/[^\w@%+=:,./-]/.test(arg)) {
|
|
100
|
+
return '"' + arg.replace(/"/g, '\\"') + '"';
|
|
101
|
+
}
|
|
102
|
+
return arg;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Run a Node.js script with piped stdio capture (bundled opencli / playwright
|
|
106
|
+
* CLI). Mirrors web-search-pro's runCli contract.
|
|
107
|
+
*/
|
|
108
|
+
export function runNode(script, args, opts = { signal: undefined }) {
|
|
109
|
+
return new Promise((resolve) => {
|
|
110
|
+
const maxOutput = opts.maxOutput ?? 4 * 1024 * 1024;
|
|
111
|
+
let stdout = '';
|
|
112
|
+
let stderr = '';
|
|
113
|
+
let settled = false;
|
|
114
|
+
let child;
|
|
115
|
+
let timer;
|
|
116
|
+
const finish = (code, timedOut) => {
|
|
117
|
+
if (settled)
|
|
118
|
+
return;
|
|
119
|
+
settled = true;
|
|
120
|
+
if (timer)
|
|
121
|
+
clearTimeout(timer);
|
|
122
|
+
opts.signal?.removeEventListener('abort', onAbort);
|
|
123
|
+
if (child.exitCode === null)
|
|
124
|
+
child.kill();
|
|
125
|
+
resolve({ code, stdout, stderr, timedOut });
|
|
126
|
+
};
|
|
127
|
+
const onAbort = () => {
|
|
128
|
+
if (child.exitCode === null)
|
|
129
|
+
child.kill();
|
|
130
|
+
finish(-1, false);
|
|
131
|
+
};
|
|
132
|
+
timer = opts.timeoutMs ? setTimeout(() => finish(-1, true), opts.timeoutMs) : undefined;
|
|
133
|
+
child = spawn(process.execPath, [script, ...args.map(quoteArg)], {
|
|
134
|
+
env: { ...process.env, ...opts.env },
|
|
135
|
+
cwd: opts.cwd,
|
|
136
|
+
windowsHide: true,
|
|
137
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
138
|
+
});
|
|
139
|
+
child.stdout?.on('data', (d) => { if (stdout.length < maxOutput)
|
|
140
|
+
stdout += d.toString('utf8'); });
|
|
141
|
+
child.stderr?.on('data', (d) => { if (stderr.length < maxOutput)
|
|
142
|
+
stderr += d.toString('utf8'); });
|
|
143
|
+
child.on('error', () => finish(-1, false));
|
|
144
|
+
child.on('close', (code) => finish(code ?? -1, false));
|
|
145
|
+
if (opts.signal?.aborted)
|
|
146
|
+
onAbort();
|
|
147
|
+
else
|
|
148
|
+
opts.signal?.addEventListener('abort', onAbort);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/** Run opencli (bundled or global-reuse). */
|
|
152
|
+
export function runOpencli(args, opts = { signal: undefined }) {
|
|
153
|
+
return runNode(opencliEntryPath(), args, opts);
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=deps.js.map
|
package/lib/deps.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-browser — self-contained browser runtime plugin for DeepSeek Harness.
|
|
3
|
+
*
|
|
4
|
+
* Bundles Playwright (chromium) + OpenCLI as plugin-local npm dependencies and
|
|
5
|
+
* provides a `browser` service for other plugins (web-search-pro injects it),
|
|
6
|
+
* plus model-facing interactive browser tools.
|
|
7
|
+
* @module dsh-browser
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import { Config } from './config.ts';
|
|
11
|
+
export declare const name = "dsh-browser";
|
|
12
|
+
export declare const inject: string[];
|
|
13
|
+
export { Config };
|
|
14
|
+
export type { Config as BrowserConfig } from './config.ts';
|
|
15
|
+
export type { BrowserService, RenderRule, RenderResult, SnapshotResult, PlatformSpec, SearchItem, InteractiveState } from './browser-service.ts';
|
|
16
|
+
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-browser — self-contained browser runtime plugin for DeepSeek Harness.
|
|
3
|
+
*
|
|
4
|
+
* Bundles Playwright (chromium) + OpenCLI as plugin-local npm dependencies and
|
|
5
|
+
* provides a `browser` service for other plugins (web-search-pro injects it),
|
|
6
|
+
* plus model-facing interactive browser tools.
|
|
7
|
+
* @module dsh-browser
|
|
8
|
+
*/
|
|
9
|
+
import fs from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { Config, resolveConfig } from "./config.js";
|
|
12
|
+
import { BrowserService } from "./browser-service.js";
|
|
13
|
+
import { registerTools } from "./tools.js";
|
|
14
|
+
export const name = 'dsh-browser';
|
|
15
|
+
export const inject = ['tools'];
|
|
16
|
+
export { Config };
|
|
17
|
+
export function apply(ctx, config) {
|
|
18
|
+
const resolved = resolveConfig(config);
|
|
19
|
+
fs.mkdirSync(resolved.snapshotDir, { recursive: true });
|
|
20
|
+
const service = new BrowserService(resolved);
|
|
21
|
+
// Provide the `browser` service so consumers (web-search-pro) can inject it.
|
|
22
|
+
// ctx.provide is scoped to this plugin's fiber; the browser instance itself
|
|
23
|
+
// is closed via the effect disposer below.
|
|
24
|
+
ctx.provide('browser', service);
|
|
25
|
+
ctx.effect(() => () => void service.close());
|
|
26
|
+
registerTools(ctx, resolved, service);
|
|
27
|
+
if (resolved.verbose) {
|
|
28
|
+
try {
|
|
29
|
+
const markerPath = path.join(resolved.snapshotDir, 'apply.log');
|
|
30
|
+
fs.appendFileSync(markerPath, JSON.stringify({
|
|
31
|
+
ts: new Date().toISOString(),
|
|
32
|
+
plugin: name,
|
|
33
|
+
channel: resolved.channel,
|
|
34
|
+
headless: resolved.headless,
|
|
35
|
+
opencliEnabled: resolved.opencliEnabled,
|
|
36
|
+
snapshotDir: resolved.snapshotDir,
|
|
37
|
+
}) + '\n', 'utf8');
|
|
38
|
+
}
|
|
39
|
+
catch { /* marker is best-effort */ }
|
|
40
|
+
}
|
|
41
|
+
ctx.logger?.(name).info('dsh-browser loaded: channel=' + resolved.channel + ' headless=' + resolved.headless + ' opencli=' + resolved.opencliEnabled);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAuB,MAAM,aAAa,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,MAAM,CAAC,MAAM,IAAI,GAAG,aAAa,CAAA;AACjC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,CAAA;AAE/B,OAAO,EAAE,MAAM,EAAE,CAAA;AAIjB,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,MAAc;IAChD,MAAM,QAAQ,GAAmB,aAAa,CAAC,MAAM,CAAC,CAAA;IACtD,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEvD,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAA;IAE5C,6EAA6E;IAC7E,4EAA4E;IAC5E,2CAA2C;IAC3C,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC/B,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;IAE5C,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;IAErC,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,CAAA;YAC/D,EAAE,CAAC,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC;gBAC3C,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAC5B,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,cAAc,EAAE,QAAQ,CAAC,cAAc;gBACvC,WAAW,EAAE,QAAQ,CAAC,WAAW;aAClC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;IACzC,CAAC;IAED,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,8BAA8B,GAAG,QAAQ,CAAC,OAAO,GAAG,YAAY,GAAG,QAAQ,CAAC,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAA;AACvJ,CAAC"}
|
package/lib/tools.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing browser tools for dsh-browser: an interactive, multi-step
|
|
3
|
+
* browser over a persistent page (open/click/type/scroll/read/screenshot/close)
|
|
4
|
+
* plus status and chromium-install helpers.
|
|
5
|
+
* @module dsh-browser/tools
|
|
6
|
+
*/
|
|
7
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
8
|
+
import type { ResolvedConfig } from './config.ts';
|
|
9
|
+
import type { BrowserService } from './browser-service.ts';
|
|
10
|
+
export declare function registerTools(ctx: Context, config: ResolvedConfig, service: BrowserService): void;
|
package/lib/tools.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing browser tools for dsh-browser: an interactive, multi-step
|
|
3
|
+
* browser over a persistent page (open/click/type/scroll/read/screenshot/close)
|
|
4
|
+
* plus status and chromium-install helpers.
|
|
5
|
+
* @module dsh-browser/tools
|
|
6
|
+
*/
|
|
7
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
8
|
+
function renderState(v) {
|
|
9
|
+
const parts = [];
|
|
10
|
+
if (v.title)
|
|
11
|
+
parts.push('Title: ' + v.title);
|
|
12
|
+
parts.push(v.url);
|
|
13
|
+
parts.push(v.text);
|
|
14
|
+
if (v.screenshotPath)
|
|
15
|
+
parts.push('Screenshot: ' + v.screenshotPath);
|
|
16
|
+
return [{ type: 'text', text: parts.join('\n\n') }];
|
|
17
|
+
}
|
|
18
|
+
export function registerTools(ctx, config, service) {
|
|
19
|
+
ctx.tools.register(defineTool({
|
|
20
|
+
name: 'browser_open',
|
|
21
|
+
description: 'Open a URL in the persistent browser page and return the rendered title, readable text, and a full-page screenshot path. Use this to start a multi-step browsing session.',
|
|
22
|
+
parameters: {
|
|
23
|
+
url: { type: 'string', required: true, description: 'The HTTP(S) URL to open.' },
|
|
24
|
+
waitMs: { type: 'number', description: 'Extra settle time in ms after load.' },
|
|
25
|
+
},
|
|
26
|
+
output: {
|
|
27
|
+
schema: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
properties: {
|
|
31
|
+
url: { type: 'string', required: true },
|
|
32
|
+
title: { type: 'string' },
|
|
33
|
+
text: { type: 'string', required: true },
|
|
34
|
+
screenshotPath: { type: 'string' },
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
render: (_args, value) => renderState(value),
|
|
38
|
+
},
|
|
39
|
+
timeoutMs: 60_000,
|
|
40
|
+
isConcurrencySafe: () => false,
|
|
41
|
+
async execute(args) {
|
|
42
|
+
return service.open(args.url, args.waitMs !== undefined ? { waitMs: args.waitMs } : {});
|
|
43
|
+
},
|
|
44
|
+
}));
|
|
45
|
+
ctx.tools.register(defineTool({
|
|
46
|
+
name: 'browser_click',
|
|
47
|
+
description: 'Click a CSS selector on the current browser page, then return the updated page state. Use after browser_open to follow links or press buttons.',
|
|
48
|
+
parameters: {
|
|
49
|
+
selector: { type: 'string', required: true, description: 'CSS selector of the element to click.' },
|
|
50
|
+
},
|
|
51
|
+
output: {
|
|
52
|
+
schema: {
|
|
53
|
+
type: 'object',
|
|
54
|
+
additionalProperties: false,
|
|
55
|
+
properties: {
|
|
56
|
+
url: { type: 'string', required: true },
|
|
57
|
+
title: { type: 'string' },
|
|
58
|
+
text: { type: 'string', required: true },
|
|
59
|
+
screenshotPath: { type: 'string' },
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
render: (_args, value) => renderState(value),
|
|
63
|
+
},
|
|
64
|
+
timeoutMs: 30_000,
|
|
65
|
+
isConcurrencySafe: () => false,
|
|
66
|
+
async execute(args) {
|
|
67
|
+
return service.click(args.selector);
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
ctx.tools.register(defineTool({
|
|
71
|
+
name: 'browser_type',
|
|
72
|
+
description: 'Type text into an input/textarea (CSS selector) on the current browser page, then return the page state. Use to fill search boxes and forms.',
|
|
73
|
+
parameters: {
|
|
74
|
+
selector: { type: 'string', required: true, description: 'CSS selector of the input/textarea to fill.' },
|
|
75
|
+
text: { type: 'string', required: true, description: 'Text to type.' },
|
|
76
|
+
},
|
|
77
|
+
output: {
|
|
78
|
+
schema: {
|
|
79
|
+
type: 'object',
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
properties: {
|
|
82
|
+
url: { type: 'string', required: true },
|
|
83
|
+
title: { type: 'string' },
|
|
84
|
+
text: { type: 'string', required: true },
|
|
85
|
+
screenshotPath: { type: 'string' },
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
render: (_args, value) => renderState(value),
|
|
89
|
+
},
|
|
90
|
+
timeoutMs: 30_000,
|
|
91
|
+
isConcurrencySafe: () => false,
|
|
92
|
+
async execute(args) {
|
|
93
|
+
return service.type(args.selector, args.text);
|
|
94
|
+
},
|
|
95
|
+
}));
|
|
96
|
+
ctx.tools.register(defineTool({
|
|
97
|
+
name: 'browser_scroll',
|
|
98
|
+
description: 'Scroll the current browser page vertically by deltaY pixels (positive = down) to trigger lazy loading, then return the page state.',
|
|
99
|
+
parameters: {
|
|
100
|
+
deltaY: { type: 'number', description: 'Pixels to scroll; positive scrolls down. Default 2000.' },
|
|
101
|
+
},
|
|
102
|
+
output: {
|
|
103
|
+
schema: {
|
|
104
|
+
type: 'object',
|
|
105
|
+
additionalProperties: false,
|
|
106
|
+
properties: {
|
|
107
|
+
url: { type: 'string', required: true },
|
|
108
|
+
title: { type: 'string' },
|
|
109
|
+
text: { type: 'string', required: true },
|
|
110
|
+
screenshotPath: { type: 'string' },
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
render: (_args, value) => renderState(value),
|
|
114
|
+
},
|
|
115
|
+
timeoutMs: 20_000,
|
|
116
|
+
isConcurrencySafe: () => false,
|
|
117
|
+
async execute(args) {
|
|
118
|
+
return service.scroll(args.deltaY ?? 2000);
|
|
119
|
+
},
|
|
120
|
+
}));
|
|
121
|
+
ctx.tools.register(defineTool({
|
|
122
|
+
name: 'browser_read',
|
|
123
|
+
description: 'Read the current browser page state (URL, title, readable text) without taking a screenshot.',
|
|
124
|
+
parameters: {},
|
|
125
|
+
output: {
|
|
126
|
+
schema: {
|
|
127
|
+
type: 'object',
|
|
128
|
+
additionalProperties: false,
|
|
129
|
+
properties: {
|
|
130
|
+
url: { type: 'string', required: true },
|
|
131
|
+
title: { type: 'string' },
|
|
132
|
+
text: { type: 'string', required: true },
|
|
133
|
+
screenshotPath: { type: 'string' },
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
render: (_args, value) => renderState(value),
|
|
137
|
+
},
|
|
138
|
+
timeoutMs: 20_000,
|
|
139
|
+
isConcurrencySafe: () => false,
|
|
140
|
+
async execute() {
|
|
141
|
+
return service.read();
|
|
142
|
+
},
|
|
143
|
+
}));
|
|
144
|
+
ctx.tools.register(defineTool({
|
|
145
|
+
name: 'browser_screenshot',
|
|
146
|
+
description: 'Capture a full-page screenshot of the current browser page and return the file path.',
|
|
147
|
+
parameters: {},
|
|
148
|
+
output: {
|
|
149
|
+
schema: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
additionalProperties: false,
|
|
152
|
+
properties: {
|
|
153
|
+
path: { type: 'string', required: true },
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
render: (_args, value) => [{ type: 'text', text: 'Screenshot: ' + value.path }],
|
|
157
|
+
},
|
|
158
|
+
timeoutMs: 30_000,
|
|
159
|
+
isConcurrencySafe: () => false,
|
|
160
|
+
async execute() {
|
|
161
|
+
return service.screenshot();
|
|
162
|
+
},
|
|
163
|
+
}));
|
|
164
|
+
ctx.tools.register(defineTool({
|
|
165
|
+
name: 'browser_close',
|
|
166
|
+
description: 'Close the current browser page (and its context). The next browser_open starts a fresh page.',
|
|
167
|
+
parameters: {},
|
|
168
|
+
output: {
|
|
169
|
+
schema: { type: 'object', additionalProperties: false, properties: { closed: { type: 'boolean', required: true } } },
|
|
170
|
+
render: () => [{ type: 'text', text: 'Browser page closed.' }],
|
|
171
|
+
},
|
|
172
|
+
timeoutMs: 15_000,
|
|
173
|
+
async execute() {
|
|
174
|
+
await service.closePage();
|
|
175
|
+
return { closed: true };
|
|
176
|
+
},
|
|
177
|
+
}));
|
|
178
|
+
ctx.tools.register(defineTool({
|
|
179
|
+
name: 'browser_status',
|
|
180
|
+
description: 'Report the browser runtime status: enabled, channel, headless, whether chromium is installed, whether the bundled OpenCLI is enabled, and the active page URL.',
|
|
181
|
+
parameters: {},
|
|
182
|
+
output: {
|
|
183
|
+
schema: {
|
|
184
|
+
type: 'object',
|
|
185
|
+
additionalProperties: false,
|
|
186
|
+
properties: {
|
|
187
|
+
enabled: { type: 'boolean', required: true },
|
|
188
|
+
channel: { type: 'string', required: true },
|
|
189
|
+
headless: { type: 'boolean', required: true },
|
|
190
|
+
opencliEnabled: { type: 'boolean', required: true },
|
|
191
|
+
chromiumInstalled: { type: 'boolean', required: true },
|
|
192
|
+
activeUrl: { type: 'string' },
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
render: (_args, value) => {
|
|
196
|
+
const v = value;
|
|
197
|
+
return [{ type: 'text', text: [
|
|
198
|
+
'browser: ' + (v.enabled ? 'enabled' : 'disabled'),
|
|
199
|
+
'channel: ' + v.channel + (v.headless ? ' (headless)' : ' (headed)'),
|
|
200
|
+
'chromium installed: ' + v.chromiumInstalled,
|
|
201
|
+
'opencli (bundled): ' + (v.opencliEnabled ? 'enabled' : 'disabled'),
|
|
202
|
+
...(v.activeUrl ? ['active page: ' + v.activeUrl] : []),
|
|
203
|
+
].join('\n') }];
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
timeoutMs: 15_000,
|
|
207
|
+
isConcurrencySafe: () => true,
|
|
208
|
+
async execute() {
|
|
209
|
+
return service.status();
|
|
210
|
+
},
|
|
211
|
+
}));
|
|
212
|
+
ctx.tools.register(defineTool({
|
|
213
|
+
name: 'browser_install',
|
|
214
|
+
description: 'Install the bundled Playwright chromium browser (downloads to the Playwright cache). Run this once if browser_status reports chromium not installed.',
|
|
215
|
+
parameters: {},
|
|
216
|
+
output: {
|
|
217
|
+
schema: {
|
|
218
|
+
type: 'object',
|
|
219
|
+
additionalProperties: false,
|
|
220
|
+
properties: {
|
|
221
|
+
code: { type: 'number', required: true },
|
|
222
|
+
stdout: { type: 'string' },
|
|
223
|
+
stderr: { type: 'string' },
|
|
224
|
+
timedOut: { type: 'boolean', required: true },
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
render: (_args, value) => {
|
|
228
|
+
const v = value;
|
|
229
|
+
return [{ type: 'text', text: 'install exit=' + v.code + (v.timedOut ? ' (timeout)' : '') + '\n' + ((v.stderr || v.stdout) ?? '').slice(0, 2000) }];
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
timeoutMs: 600_000,
|
|
233
|
+
isConcurrencySafe: () => false,
|
|
234
|
+
async execute() {
|
|
235
|
+
const r = await service.installChromium();
|
|
236
|
+
return { code: r.code, stdout: r.stdout, stderr: r.stderr, timedOut: r.timedOut };
|
|
237
|
+
},
|
|
238
|
+
}));
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=tools.js.map
|
package/lib/tools.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|