dsh-inner-browser-use 0.11.44 → 0.13.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 +108 -75
- package/README.zh.md +88 -45
- package/client.js +473 -3276
- package/docs/ARCHITECTURE.md +183 -151
- package/docs/BENCH.md +124 -0
- package/docs/COMPATIBILITY.md +72 -102
- package/docs/ROADMAP.md +108 -0
- package/docs/VERIFY.md +80 -417
- package/index.js +227 -1117
- package/locale/en.json +11 -22
- package/locale/zh.json +11 -22
- package/package.json +9 -5
- package/scripts/doctor.mjs +89 -0
- package/sidecar.js +1323 -0
- package/docs/upstream/cookie-persistence.md +0 -52
package/locale/en.json
CHANGED
|
@@ -1,26 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
|
-
"title": "
|
|
4
|
-
"description": "
|
|
3
|
+
"title": "Background browser",
|
|
4
|
+
"description": "A browser the agent drives behind the chat, mirrored into the right column."
|
|
5
5
|
},
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"error.background": "This chat is not open on screen — open it to drive its page.",
|
|
16
|
-
"phase.act.navigate": "Opening the page",
|
|
17
|
-
"phase.act.click": "Clicking",
|
|
18
|
-
"phase.act.read": "Reading the page",
|
|
19
|
-
"phase.act.type": "Typing",
|
|
20
|
-
"phase.act.scroll": "Scrolling",
|
|
21
|
-
"phase.act.shot": "Taking an image",
|
|
22
|
-
"phase.act.download": "Saving a file",
|
|
23
|
-
"phase.act.upload": "Uploading",
|
|
24
|
-
"phase.act.eval": "Working on the page",
|
|
25
|
-
"phase.act.select": "Choosing"
|
|
6
|
+
"side.label": "Background browser",
|
|
7
|
+
"side.empty": "No page open",
|
|
8
|
+
"side.connecting": "Connecting…",
|
|
9
|
+
"side.failed": "The picture did not connect",
|
|
10
|
+
"side.back": "Back",
|
|
11
|
+
"side.forward": "Forward",
|
|
12
|
+
"side.reload": "Reload",
|
|
13
|
+
"side.address": "Enter an address",
|
|
14
|
+
"side.type": "Type here"
|
|
26
15
|
}
|
package/locale/zh.json
CHANGED
|
@@ -1,26 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
|
-
"title": "
|
|
4
|
-
"description": "
|
|
3
|
+
"title": "后台浏览器",
|
|
4
|
+
"description": "助手在后台操作的浏览器,画面镜像到右栏。"
|
|
5
5
|
},
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"error.background": "这个会话没在当前屏幕,切到它才能操作页面。",
|
|
16
|
-
"phase.act.navigate": "正在打开页面",
|
|
17
|
-
"phase.act.click": "正在点击",
|
|
18
|
-
"phase.act.read": "正在读取页面",
|
|
19
|
-
"phase.act.type": "正在输入",
|
|
20
|
-
"phase.act.scroll": "正在滚动",
|
|
21
|
-
"phase.act.shot": "正在截图",
|
|
22
|
-
"phase.act.download": "正在下载",
|
|
23
|
-
"phase.act.upload": "正在上传",
|
|
24
|
-
"phase.act.eval": "正在操作页面",
|
|
25
|
-
"phase.act.select": "正在选择"
|
|
6
|
+
"side.label": "后台浏览器",
|
|
7
|
+
"side.empty": "还没有打开的页面",
|
|
8
|
+
"side.connecting": "正在连接…",
|
|
9
|
+
"side.failed": "画面没有连上",
|
|
10
|
+
"side.back": "后退",
|
|
11
|
+
"side.forward": "前进",
|
|
12
|
+
"side.reload": "刷新",
|
|
13
|
+
"side.address": "输入地址",
|
|
14
|
+
"side.type": "输入文字"
|
|
26
15
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-inner-browser-use",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"description": "An agent-owned Chromium sidecar mirrored into the DeepSeek Harness right column: the agent drives it, the person watches and can take the mouse, and logins survive restarts.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"exports": {
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"index.js",
|
|
16
|
+
"sidecar.js",
|
|
16
17
|
"client.js",
|
|
17
18
|
"locale/*.json",
|
|
18
19
|
"cordis.patch.yml",
|
|
19
20
|
"icon.svg",
|
|
21
|
+
"scripts/doctor.mjs",
|
|
20
22
|
"docs/",
|
|
21
23
|
"README.md",
|
|
22
24
|
"README.zh.md",
|
|
@@ -28,8 +30,9 @@
|
|
|
28
30
|
"dsh-plugin",
|
|
29
31
|
"browser-use",
|
|
30
32
|
"computer-use",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
+
"chrome",
|
|
34
|
+
"cdp",
|
|
35
|
+
"screencast",
|
|
33
36
|
"deepseek"
|
|
34
37
|
],
|
|
35
38
|
"engines": {
|
|
@@ -38,7 +41,8 @@
|
|
|
38
41
|
},
|
|
39
42
|
"scripts": {
|
|
40
43
|
"test": "node --test test/*.test.mjs",
|
|
41
|
-
"doctor": "node scripts/doctor.mjs"
|
|
44
|
+
"doctor": "node scripts/doctor.mjs",
|
|
45
|
+
"breadth": "node scripts/breadth.mjs"
|
|
42
46
|
},
|
|
43
47
|
"license": "MIT",
|
|
44
48
|
"author": "regrevia",
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Report what the sidecar browser is doing right now: whether the Host answers,
|
|
4
|
+
* whether a Chromium is attached, which profile it uses, and whether that
|
|
5
|
+
* profile is outside the Host so logins outlive a restart. Reads only; nothing
|
|
6
|
+
* is started, attached, or closed.
|
|
7
|
+
*
|
|
8
|
+
* node scripts/doctor.mjs
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { execFile } from 'node:child_process'
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
13
|
+
import { homedir } from 'node:os'
|
|
14
|
+
import { join } from 'node:path'
|
|
15
|
+
import { promisify } from 'node:util'
|
|
16
|
+
|
|
17
|
+
const run = promisify(execFile)
|
|
18
|
+
const ROUTE = '/dsh-inner-browser-use'
|
|
19
|
+
const PROFILES = join(homedir(), '.dsh', 'inner-browser-use', 'chrome')
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The Host picks its port each time it starts, so try the asked-for address
|
|
23
|
+
* first and then whatever the running app is listening on.
|
|
24
|
+
* @returns {Promise<string[]>} candidate addresses, without trailing slash.
|
|
25
|
+
*/
|
|
26
|
+
async function addresses() {
|
|
27
|
+
const asked = (process.env.DSH_BRIDGE ?? '').trim().replace(/\/+$/, '')
|
|
28
|
+
const found = asked === '' ? [] : [asked]
|
|
29
|
+
found.push('http://127.0.0.1:60930')
|
|
30
|
+
try {
|
|
31
|
+
const { stdout } = await run('lsof', ['-nP', '-iTCP', '-sTCP:LISTEN', '-a', '-c', 'DeepSeek'], { timeout: 4_000 })
|
|
32
|
+
for (const line of String(stdout).split('\n')) {
|
|
33
|
+
const hit = /127\.0\.0\.1:(\d{4,5})\s/.exec(line)
|
|
34
|
+
if (hit === null) continue
|
|
35
|
+
const address = `http://127.0.0.1:${hit[1]}`
|
|
36
|
+
if (found.includes(address) === false) found.push(address)
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
/* no lsof, or nothing listening: the default address is all that is left */
|
|
40
|
+
}
|
|
41
|
+
return found
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let base = ''
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {string} path - route under this plugin.
|
|
48
|
+
* @returns {Promise<any>} parsed body, or null when no address answers.
|
|
49
|
+
*/
|
|
50
|
+
async function get(path) {
|
|
51
|
+
const tried = base === '' ? await addresses() : [base]
|
|
52
|
+
for (const address of tried) {
|
|
53
|
+
try {
|
|
54
|
+
const response = await fetch(address + path, { signal: AbortSignal.timeout(4_000) })
|
|
55
|
+
if (response.ok !== true) continue
|
|
56
|
+
base = address
|
|
57
|
+
return await response.json()
|
|
58
|
+
} catch {
|
|
59
|
+
/* the next address may be the one this app is on */
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const state = await get(`${ROUTE}/sidecar/state`)
|
|
66
|
+
console.log(`host ${state === null ? `not answering under ${ROUTE}` : base}`)
|
|
67
|
+
if (state === null) {
|
|
68
|
+
console.log(' start the app, or set DSH_BRIDGE to the app address')
|
|
69
|
+
process.exit(0)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log(`browser ${state.alive === true ? `attached, ${state.headless === true ? 'headless' : 'with a window'}` : 'not running'}`)
|
|
73
|
+
const profileDir = join(PROFILES, String(state.profile ?? ''))
|
|
74
|
+
console.log(`profile ${state.profile} in ${profileDir}`)
|
|
75
|
+
console.log(`stored ${existsSync(profileDir) ? 'on disk, so cookies and logins survive a restart' : 'not created yet'}`)
|
|
76
|
+
if (state.alive === true) {
|
|
77
|
+
console.log(`page ${String(state.title ?? '') === '' ? String(state.url ?? '') : state.title}`)
|
|
78
|
+
console.log(`viewers ${state.viewers} | frames ${state.frames} | pointer ${state.pointer === null ? 'none' : `${state.pointer.x},${state.pointer.y}`}`)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const portFile = join(profileDir, 'DevToolsActivePort')
|
|
82
|
+
if (existsSync(portFile)) {
|
|
83
|
+
const [port = '', path = ''] = readFileSync(portFile, 'utf8').trim().split('\n')
|
|
84
|
+
console.log(`control port ${port}, ${path.startsWith('/devtools/') ? 'endpoint file present' : 'endpoint file odd'}`)
|
|
85
|
+
} else {
|
|
86
|
+
console.log('control no DevToolsActivePort yet')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (String(state.error ?? '') !== '') console.log(`error ${state.error}`)
|