@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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-browser contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # dsh-browser
2
+
3
+ 自包含的浏览器运行时插件 for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)。
4
+
5
+ 把 **Playwright(chromium 内核)** 与 **OpenCLI** 作为插件自身的 npm 依赖打包(优先插件本地,缺省回退全局复用),对外提供一个 `browser` 服务 + 一组交互式浏览器工具。`dsh-web-search-pro` 通过 `inject: ['browser']` 注入该服务,驱动它的 playwright / opencli 后端——**不再依赖全局 CLI**。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ dsh plugin --profile web add @anweat/dsh-browser
11
+ # 或本地目录 / tarball:
12
+ dsh plugin --profile web add ./dsh-browser
13
+ # 重启(web profile 关闭了 HMR):
14
+ dsh --profile web
15
+ ```
16
+
17
+ > 依赖 `@deepseek-ai/*` 已发布到 npm(`^0.1.0-rc.6`)。
18
+ > 若你的 harness 是本地源码 checkout(如 `0.1.0-rc.5`),版本号可能有出入——用
19
+ > `dsh plugin --profile web add ./<path>` 并在 profile 的 `pnpm-workspace.yaml`
20
+ > 里对齐版本后重装即可。
21
+
22
+ ## 内核与依赖的"打包 vs 复用"
23
+
24
+ | 层 | 实际是什么 | 打包还是复用 |
25
+ |---|---|---|
26
+ | **chromium 内核** | 共享缓存 `%LOCALAPPDATA%\ms-playwright`(约 400MB) | **永远复用共享缓存**,不塞进插件、不重复下载;缺失时 `browser_install` 一键补 |
27
+ | **playwright 驱动**(JS 包) | `playwright` npm 依赖 | 插件本地 node_modules 优先,缺省回退全局 npm |
28
+ | **opencli**(纯 Node CLI) | `@jackwener/opencli` npm 依赖 | 同上,本地优先 / 全局复用 |
29
+
30
+ ## 服务:`browser`
31
+
32
+ `dsh-browser` 在 `apply()` 里 `ctx.provide('browser', service)`。任何插件声明
33
+ `inject: ['browser']` 即可消费:
34
+
35
+ ```ts
36
+ export const inject = ['tools', 'browser']
37
+ export function apply(ctx: Context) {
38
+ const browser = ctx.get('browser') as BrowserService
39
+ // browser.render / snapshot / searchResults / opencli / open / click / type / scroll / read / screenshot / close
40
+ }
41
+ ```
42
+
43
+ 服务接口(结构性,无需共享类型包)见 `src/browser-service.ts`。
44
+
45
+ ## 工具(9 个)
46
+
47
+ | 工具 | 作用 |
48
+ |---|---|
49
+ | `browser_open` | 打开 URL,返回标题/可读文本/全页截图路径(持久页会话) |
50
+ | `browser_click` | 按 CSS 选择器点击 |
51
+ | `browser_type` | 向 input/textarea 输入 |
52
+ | `browser_scroll` | 纵向滚动(触发懒加载) |
53
+ | `browser_read` | 读当前页 URL/标题/文本(不截图) |
54
+ | `browser_screenshot` | 当前页全页截图 |
55
+ | `browser_close` | 关闭当前页(下次 open 全新) |
56
+ | `browser_status` | 运行时状态(channel/headless/chromium 是否就绪/opencli 是否启用/当前页) |
57
+ | `browser_install` | 安装 playwright chromium(`browser_status` 报缺失时执行一次) |
58
+
59
+ ## 配置(cordis.yml / patch config)
60
+
61
+ ```yaml
62
+ - insert:
63
+ - id: browser
64
+ name: '@anweat/dsh-browser'
65
+ config:
66
+ channel: chromium # 'chromium'(打包内核)| 'msedge'(系统 Edge)
67
+ headless: true
68
+ opencliEnabled: true
69
+ storageStatePath: '' # Playwright 登录态 JSON(复用已登录会话)
70
+ autoInstall: false # 缺内核时是否自动 install chromium
71
+ verbose: false
72
+ ```
73
+
74
+ ## 登录态复用
75
+
76
+ - `channel: chromium` + `storageStatePath` 指向一份 storageState JSON,即可用你已登录的身份抓受限页面。
77
+ - 生成登录态:`npx playwright codegen --save-storage=storageState.json`(或复用 `dsh-web-search-pro` 的 `scripts/save-login.mjs`),把产物路径填进 `storageStatePath`。
78
+ - opencli 的社交平台后端(小红书/推特/Reddit/IG/FB)仍需浏览器扩展 + 登录态在线,即使 opencli 已打包为依赖也绕不开扩展。
79
+
80
+ ## 发布 / 构建
81
+
82
+ ```bash
83
+ pnpm install # 装依赖(playwright / opencli / @deepseek-ai/*)
84
+ pnpm run build # tsc → lib/
85
+ node scripts/install-browser.mjs # 安装 chromium 内核(发布前验证,可选)
86
+ ```
87
+
88
+ ## 与 dsh-web-search-pro 的关系
89
+
90
+ `dsh-web-search-pro` 现在 `inject: ['browser']`,其 `web_snapshot` / `web_fetch_pro`(playwright 后端) /
91
+ `web_platform_search`(中文社区 playwright + 社交平台 opencli) 全部走本插件的 `browser` 服务。
92
+ 两者可独立安装,但 web-search-pro 的浏览器类能力依赖 dsh-browser 先行提供 `browser` 服务(Cordis `inject` 自动排序,无需手动控制挂载顺序)。
@@ -0,0 +1,15 @@
1
+ # dsh-browser bundle patch — installs the browser runtime as one more row over
2
+ # the active profile. Install with:
3
+ # dsh plugin --profile <name> add @anweat/dsh-browser
4
+ # then boot the profile (the web profile has HMR disabled, so a restart applies it).
5
+ #
6
+ # Login state: set `storageStatePath` to a Playwright storageState JSON (see
7
+ # README) to reuse an already-logged-in browser session.
8
+ - insert:
9
+ - id: browser
10
+ name: '@anweat/dsh-browser'
11
+ config:
12
+ channel: chromium
13
+ headless: true
14
+ opencliEnabled: true
15
+ verbose: false
@@ -0,0 +1,127 @@
1
+ /**
2
+ * BrowserService — the `browser` service provided by dsh-browser and injected
3
+ * by consumers (web-search-pro).
4
+ *
5
+ * - Playwright (bundled chromium) is resolved from this plugin's own
6
+ * node_modules and launched lazily; the browser is reused for the plugin
7
+ * lifetime and disposed on unload.
8
+ * - render / snapshot / searchResults are the drop-in replacements for
9
+ * web-search-pro's former PlaywrightManager (rules-aware page extraction and
10
+ * platform search-page list extraction run in the page itself).
11
+ * - opencli(...) runs the bundled @jackwener/opencli (no global CLI).
12
+ * - The interactive surface (open/click/type/scroll/read/screenshot/closePage)
13
+ * drives ONE persistent context+page, giving the model multi-step browsing.
14
+ *
15
+ * The page-side extractors are raw JS strings, not closures: tsx/esbuild would
16
+ * inject a __name helper into compiled closures, which does not exist in the
17
+ * page context. Strings pass through unevaluated. Regex escapes are written
18
+ * doubled (\\s) so the evaluated page code sees a correct \s.
19
+ * @module dsh-browser/browser-service
20
+ */
21
+ import { type CliResult } from './deps.ts';
22
+ import type { ResolvedConfig } from './config.ts';
23
+ export interface RenderRule {
24
+ hostname: string;
25
+ contentSelectors: string[];
26
+ removeSelectors?: string[];
27
+ }
28
+ export interface RenderResult {
29
+ title: string;
30
+ text: string;
31
+ html: string;
32
+ usedRule?: string;
33
+ }
34
+ export interface SnapshotResult {
35
+ title: string;
36
+ text: string;
37
+ screenshotPath: string;
38
+ htmlPath: string;
39
+ usedRule?: string;
40
+ }
41
+ /** Structural platform-search spec (matches web-search-pro's PlatformSearchSpec). */
42
+ export interface PlatformSpec {
43
+ item: string;
44
+ title: string;
45
+ link: string;
46
+ text?: string;
47
+ }
48
+ export interface SearchItem {
49
+ url: string;
50
+ title: string;
51
+ snippet?: string;
52
+ }
53
+ export interface InteractiveState {
54
+ url: string;
55
+ title: string;
56
+ text: string;
57
+ screenshotPath?: string;
58
+ }
59
+ export declare class BrowserService {
60
+ private readonly config;
61
+ private browser;
62
+ private launching?;
63
+ private activeContext;
64
+ private activePage;
65
+ constructor(config: ResolvedConfig);
66
+ available(): boolean;
67
+ private ensure;
68
+ /** Run `playwright install chromium` from the bundled playwright CLI. */
69
+ installChromium(): Promise<CliResult>;
70
+ private transientContext;
71
+ render(url: string, rules: readonly RenderRule[], opts?: {
72
+ signal?: AbortSignal;
73
+ maxChars?: number;
74
+ waitMs?: number;
75
+ }): Promise<RenderResult>;
76
+ snapshot(url: string, rules: readonly RenderRule[], opts: {
77
+ signal?: AbortSignal;
78
+ outDir: string;
79
+ maxChars?: number;
80
+ }): Promise<SnapshotResult>;
81
+ searchResults(url: string, spec: PlatformSpec, opts?: {
82
+ signal?: AbortSignal;
83
+ count?: number;
84
+ waitMs?: number;
85
+ cookies?: {
86
+ name: string;
87
+ value: string;
88
+ domain: string;
89
+ path: string;
90
+ }[];
91
+ }): Promise<SearchItem[]>;
92
+ opencliAvailable(): boolean;
93
+ opencli(args: string[], opts?: {
94
+ timeoutMs?: number;
95
+ signal?: AbortSignal;
96
+ }): Promise<CliResult>;
97
+ private ensureActivePage;
98
+ private captureScreenshot;
99
+ private readState;
100
+ open(url: string, opts?: {
101
+ waitMs?: number;
102
+ }): Promise<InteractiveState>;
103
+ click(selector: string, opts?: {
104
+ timeoutMs?: number;
105
+ waitMs?: number;
106
+ }): Promise<InteractiveState>;
107
+ type(selector: string, text: string, opts?: {
108
+ timeoutMs?: number;
109
+ }): Promise<InteractiveState>;
110
+ scroll(deltaY: number, opts?: {
111
+ waitMs?: number;
112
+ }): Promise<InteractiveState>;
113
+ read(): Promise<InteractiveState>;
114
+ screenshot(): Promise<{
115
+ path: string;
116
+ }>;
117
+ closePage(): Promise<void>;
118
+ status(): Promise<{
119
+ enabled: boolean;
120
+ channel: string;
121
+ headless: boolean;
122
+ opencliEnabled: boolean;
123
+ chromiumInstalled: boolean;
124
+ activeUrl?: string;
125
+ }>;
126
+ close(): Promise<void>;
127
+ }
@@ -0,0 +1,362 @@
1
+ /**
2
+ * BrowserService — the `browser` service provided by dsh-browser and injected
3
+ * by consumers (web-search-pro).
4
+ *
5
+ * - Playwright (bundled chromium) is resolved from this plugin's own
6
+ * node_modules and launched lazily; the browser is reused for the plugin
7
+ * lifetime and disposed on unload.
8
+ * - render / snapshot / searchResults are the drop-in replacements for
9
+ * web-search-pro's former PlaywrightManager (rules-aware page extraction and
10
+ * platform search-page list extraction run in the page itself).
11
+ * - opencli(...) runs the bundled @jackwener/opencli (no global CLI).
12
+ * - The interactive surface (open/click/type/scroll/read/screenshot/closePage)
13
+ * drives ONE persistent context+page, giving the model multi-step browsing.
14
+ *
15
+ * The page-side extractors are raw JS strings, not closures: tsx/esbuild would
16
+ * inject a __name helper into compiled closures, which does not exist in the
17
+ * page context. Strings pass through unevaluated. Regex escapes are written
18
+ * doubled (\\s) so the evaluated page code sees a correct \s.
19
+ * @module dsh-browser/browser-service
20
+ */
21
+ import fs from 'node:fs';
22
+ import path from 'node:path';
23
+ import crypto from 'node:crypto';
24
+ import { loadPlaywright, runOpencli, runNode, playwrightCliPath } from "./deps.js";
25
+ /** Rules-aware content extractor (runs in the page). */
26
+ const EXTRACTOR_FN = `(ruleList) => {
27
+ const doc = document
28
+ const title = doc.title ? doc.title.trim() : ''
29
+ let host = ''
30
+ try { host = location.hostname } catch (e) {}
31
+ const norm = (h) => { const x = h.toLowerCase(); return x.startsWith('www.') ? x.slice(4) : x }
32
+ let rule = null
33
+ for (const r of ruleList) {
34
+ const rh = norm(r.hostname)
35
+ if (host === rh || host.endsWith('.' + rh)) rule = r
36
+ }
37
+ const pick = (selectors) => {
38
+ for (const sel of selectors) {
39
+ try {
40
+ const el = doc.querySelector(sel)
41
+ if (el && (el.textContent || '').trim().length > 40) return el
42
+ } catch (e) {}
43
+ }
44
+ return null
45
+ }
46
+ const content = rule ? pick(rule.contentSelectors) : (pick(['article', 'main', '[role="main"]']) || doc.body)
47
+ if (content && rule && rule.removeSelectors) {
48
+ for (const sel of rule.removeSelectors) {
49
+ try { content.querySelectorAll(sel).forEach((el) => el.remove()) } catch (e) {}
50
+ }
51
+ }
52
+ const text = content ? (content.innerText || content.textContent || '') : ''
53
+ return { title, text, html: doc.documentElement.outerHTML.slice(0, 2000000), usedRule: rule ? rule.hostname : null }
54
+ }`;
55
+ /** Platform search-page list extractor (runs in the page). */
56
+ const LIST_EXTRACTOR = `(spec) => {
57
+ const items = []
58
+ const nodes = document.querySelectorAll(spec.item)
59
+ for (let i = 0; i < nodes.length && items.length < 20; i++) {
60
+ const el = nodes[i]
61
+ const titleEl = spec.title ? el.querySelector(spec.title) : null
62
+ const linkEl = spec.link ? el.querySelector(spec.link) : null
63
+ const textEl = spec.text ? el.querySelector(spec.text) : null
64
+ const title = (titleEl ? titleEl.textContent : el.textContent || '').trim().replace(/\\s+/g, ' ')
65
+ let url = linkEl ? (linkEl.href || linkEl.getAttribute('href') || '') : ''
66
+ if (url && url.startsWith('/')) url = location.origin + url
67
+ if (!url && linkEl === null && titleEl) { const a = titleEl.closest ? titleEl.closest('a') : null; if (a) url = a.href }
68
+ const snippet = textEl ? (textEl.textContent || '').trim().replace(/\\s+/g, ' ').slice(0, 300) : ''
69
+ if (!url || !title || title.length < 2) continue
70
+ items.push({ url, title, snippet })
71
+ }
72
+ return items
73
+ }`;
74
+ function uid() {
75
+ return crypto.randomUUID();
76
+ }
77
+ function capText(text, maxChars) {
78
+ if (text.length <= maxChars)
79
+ return text;
80
+ return text.slice(0, maxChars) + '\n\n(Content truncated at ' + maxChars + ' characters.)';
81
+ }
82
+ function specArg(spec) {
83
+ return { item: spec.item, title: spec.title, link: spec.link, text: spec.text ?? '' };
84
+ }
85
+ function evaluateExtractor(page, rules) {
86
+ return page.evaluate('(' + EXTRACTOR_FN + ')(' + JSON.stringify(rules) + ')');
87
+ }
88
+ export class BrowserService {
89
+ config;
90
+ browser;
91
+ launching;
92
+ activeContext;
93
+ activePage;
94
+ constructor(config) {
95
+ this.config = config;
96
+ }
97
+ available() {
98
+ return this.config.enabled;
99
+ }
100
+ async ensure() {
101
+ if (this.browser)
102
+ return this.browser;
103
+ if (!this.launching) {
104
+ this.launching = (async () => {
105
+ const pw = loadPlaywright();
106
+ const launchOptions = { headless: this.config.headless };
107
+ if (this.config.channel)
108
+ launchOptions.channel = this.config.channel;
109
+ if (this.config.executablePath)
110
+ launchOptions.executablePath = this.config.executablePath;
111
+ try {
112
+ this.browser = await pw.chromium.launch(launchOptions);
113
+ }
114
+ catch (error) {
115
+ const msg = String(error);
116
+ if (/Executable doesn't exist|playwright install|not found/i.test(msg)) {
117
+ if (this.config.autoInstall) {
118
+ await this.installChromium();
119
+ this.browser = await pw.chromium.launch(launchOptions);
120
+ }
121
+ else {
122
+ throw new Error('dsh-browser: chromium is not installed. Run the browser_install tool, or: node "' + playwrightCliPath() + '" install chromium');
123
+ }
124
+ }
125
+ else {
126
+ throw error;
127
+ }
128
+ }
129
+ return this.browser;
130
+ })().catch((error) => {
131
+ this.launching = undefined;
132
+ throw error;
133
+ });
134
+ }
135
+ return this.launching;
136
+ }
137
+ /** Run `playwright install chromium` from the bundled playwright CLI. */
138
+ installChromium() {
139
+ return runNode(playwrightCliPath(), ['install', 'chromium'], { timeoutMs: 600_000, signal: undefined, maxOutput: 256 * 1024 });
140
+ }
141
+ async transientContext() {
142
+ const browser = await this.ensure();
143
+ return browser.newContext(this.config.storageStatePath ? { storageState: this.config.storageStatePath } : {});
144
+ }
145
+ // ── render / snapshot / searchResults (web-search-pro contract) ──────────
146
+ async render(url, rules, opts = {}) {
147
+ const context = await this.transientContext();
148
+ const page = await context.newPage();
149
+ const signal = opts.signal;
150
+ const onAbort = () => void page.close().catch(() => { });
151
+ if (signal?.aborted)
152
+ onAbort();
153
+ else
154
+ signal?.addEventListener('abort', onAbort);
155
+ try {
156
+ page.setDefaultTimeout(20_000);
157
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 25_000 });
158
+ await page.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => { });
159
+ if (opts.waitMs)
160
+ await page.waitForTimeout(opts.waitMs);
161
+ const data = await evaluateExtractor(page, rules);
162
+ return {
163
+ title: String(data.title ?? ''),
164
+ text: capText(String(data.text ?? '').replace(/\n{3,}/g, '\n\n').trim(), opts.maxChars ?? 200_000),
165
+ html: String(data.html ?? ''),
166
+ ...data.usedRule ? { usedRule: String(data.usedRule) } : {},
167
+ };
168
+ }
169
+ catch (error) {
170
+ throw new Error('browser render failed for ' + url + ': ' + String(error).slice(0, 300));
171
+ }
172
+ finally {
173
+ signal?.removeEventListener('abort', onAbort);
174
+ await context.close().catch(() => { });
175
+ }
176
+ }
177
+ async snapshot(url, rules, opts) {
178
+ const context = await this.transientContext();
179
+ const page = await context.newPage();
180
+ const signal = opts.signal;
181
+ const onAbort = () => void page.close().catch(() => { });
182
+ if (signal?.aborted)
183
+ onAbort();
184
+ else
185
+ signal?.addEventListener('abort', onAbort);
186
+ fs.mkdirSync(opts.outDir, { recursive: true });
187
+ const stamp = Date.now() + '-' + uid().slice(0, 8);
188
+ const screenshotPath = path.join(opts.outDir, stamp + '.png');
189
+ const htmlPath = path.join(opts.outDir, stamp + '.html');
190
+ try {
191
+ page.setDefaultTimeout(25_000);
192
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
193
+ await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => { });
194
+ await page.screenshot({ path: screenshotPath, fullPage: true });
195
+ const html = await page.content();
196
+ fs.writeFileSync(htmlPath, html, 'utf8');
197
+ const data = await evaluateExtractor(page, rules);
198
+ return {
199
+ title: String(data.title ?? ''),
200
+ text: capText(String(data.text ?? '').replace(/\n{3,}/g, '\n\n').trim(), opts.maxChars ?? 200_000),
201
+ screenshotPath,
202
+ htmlPath,
203
+ ...data.usedRule ? { usedRule: String(data.usedRule) } : {},
204
+ };
205
+ }
206
+ catch (error) {
207
+ throw new Error('browser snapshot failed for ' + url + ': ' + String(error).slice(0, 300));
208
+ }
209
+ finally {
210
+ signal?.removeEventListener('abort', onAbort);
211
+ await context.close().catch(() => { });
212
+ }
213
+ }
214
+ async searchResults(url, spec, opts = {}) {
215
+ const context = await this.transientContext();
216
+ if (opts.cookies?.length)
217
+ await context.addCookies(opts.cookies).catch(() => { });
218
+ const page = await context.newPage();
219
+ const signal = opts.signal;
220
+ const onAbort = () => void page.close().catch(() => { });
221
+ if (signal?.aborted)
222
+ onAbort();
223
+ else
224
+ signal?.addEventListener('abort', onAbort);
225
+ try {
226
+ page.setDefaultTimeout(25_000);
227
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
228
+ await page.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => { });
229
+ if (opts.waitMs)
230
+ await page.waitForTimeout(opts.waitMs);
231
+ await page.mouse?.wheel(0, 2000).catch(() => { });
232
+ await page.waitForTimeout(800);
233
+ const data = await page.evaluate('(' + LIST_EXTRACTOR + ')(' + JSON.stringify(specArg(spec)) + ')');
234
+ const rows = Array.isArray(data) ? data : [];
235
+ return rows.slice(0, Math.min(Math.max(opts.count ?? 8, 1), 20)).map((r) => ({
236
+ url: String(r.url ?? ''),
237
+ title: String(r.title ?? ''),
238
+ ...r.snippet ? { snippet: String(r.snippet) } : {},
239
+ }));
240
+ }
241
+ catch (error) {
242
+ throw new Error('browser platform search failed for ' + url + ': ' + String(error).slice(0, 300));
243
+ }
244
+ finally {
245
+ signal?.removeEventListener('abort', onAbort);
246
+ await context.close().catch(() => { });
247
+ }
248
+ }
249
+ // ── bundled opencli ───────────────────────────────────────────────────────
250
+ opencliAvailable() {
251
+ return this.config.opencliEnabled;
252
+ }
253
+ opencli(args, opts = {}) {
254
+ return runOpencli(args, { ...opts, signal: opts.signal });
255
+ }
256
+ // ── interactive surface (one persistent context + page) ──────────────────
257
+ async ensureActivePage() {
258
+ if (this.activePage && !this.activePage.isClosed())
259
+ return this.activePage;
260
+ const browser = await this.ensure();
261
+ this.activeContext = await browser.newContext(this.config.storageStatePath ? { storageState: this.config.storageStatePath } : {});
262
+ this.activePage = await this.activeContext.newPage();
263
+ return this.activePage;
264
+ }
265
+ async captureScreenshot(page) {
266
+ fs.mkdirSync(this.config.snapshotDir, { recursive: true });
267
+ const file = path.join(this.config.snapshotDir, 'shot-' + Date.now() + '-' + uid().slice(0, 8) + '.png');
268
+ await page.screenshot({ path: file, fullPage: true });
269
+ return file;
270
+ }
271
+ async readState(page, includeScreenshot) {
272
+ const data = await evaluateExtractor(page, []);
273
+ const state = {
274
+ url: page.url(),
275
+ title: String(data.title ?? ''),
276
+ text: capText(String(data.text ?? '').replace(/\n{3,}/g, '\n\n').trim(), 100_000),
277
+ };
278
+ if (includeScreenshot)
279
+ state.screenshotPath = await this.captureScreenshot(page);
280
+ return state;
281
+ }
282
+ async open(url, opts = {}) {
283
+ const page = await this.ensureActivePage();
284
+ page.setDefaultTimeout(30_000);
285
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
286
+ await page.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => { });
287
+ if (opts.waitMs)
288
+ await page.waitForTimeout(opts.waitMs);
289
+ return this.readState(page, true);
290
+ }
291
+ async click(selector, opts = {}) {
292
+ const page = await this.ensureActivePage();
293
+ await page.waitForSelector(selector, { timeout: opts.timeoutMs ?? 15_000 });
294
+ await page.click(selector);
295
+ if (opts.waitMs !== undefined)
296
+ await page.waitForTimeout(opts.waitMs);
297
+ else
298
+ await page.waitForTimeout(500);
299
+ return this.readState(page, true);
300
+ }
301
+ async type(selector, text, opts = {}) {
302
+ const page = await this.ensureActivePage();
303
+ await page.waitForSelector(selector, { timeout: opts.timeoutMs ?? 15_000 });
304
+ await page.fill(selector, text);
305
+ return this.readState(page, false);
306
+ }
307
+ async scroll(deltaY, opts = {}) {
308
+ const page = await this.ensureActivePage();
309
+ await page.mouse?.wheel(0, deltaY || 2000).catch(() => { });
310
+ await page.waitForTimeout(opts.waitMs ?? 500);
311
+ return this.readState(page, false);
312
+ }
313
+ async read() {
314
+ const page = await this.ensureActivePage();
315
+ return this.readState(page, false);
316
+ }
317
+ async screenshot() {
318
+ const page = await this.ensureActivePage();
319
+ return { path: await this.captureScreenshot(page) };
320
+ }
321
+ async closePage() {
322
+ if (this.activePage) {
323
+ await this.activePage.close().catch(() => { });
324
+ }
325
+ this.activePage = undefined;
326
+ if (this.activeContext) {
327
+ await this.activeContext.close().catch(() => { });
328
+ }
329
+ this.activeContext = undefined;
330
+ }
331
+ async status() {
332
+ let chromiumInstalled = false;
333
+ try {
334
+ const pw = loadPlaywright();
335
+ chromiumInstalled = !!pw.chromium.executablePath();
336
+ }
337
+ catch {
338
+ chromiumInstalled = false;
339
+ }
340
+ return {
341
+ enabled: this.config.enabled,
342
+ channel: this.config.channel,
343
+ headless: this.config.headless,
344
+ opencliEnabled: this.config.opencliEnabled,
345
+ chromiumInstalled,
346
+ ...(this.activePage && !this.activePage.isClosed() ? { activeUrl: this.activePage.url() } : {}),
347
+ };
348
+ }
349
+ async close() {
350
+ await this.closePage();
351
+ const b = this.browser;
352
+ this.browser = undefined;
353
+ this.launching = undefined;
354
+ if (b) {
355
+ try {
356
+ await b.close();
357
+ }
358
+ catch { /* already closed */ }
359
+ }
360
+ }
361
+ }
362
+ //# sourceMappingURL=browser-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-service.js","sourceRoot":"","sources":["../src/browser-service.ts"],"names":[],"mappings":"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"}