yunti-browser-runtime 0.1.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/LICENSE +21 -0
- package/README.md +256 -0
- package/bin/yunti-browser-runtime.js +86 -0
- package/docs/EXECUTION_PLAN.md +1278 -0
- package/docs/INSTALL.md +205 -0
- package/docs/PROJECT_INTENT.md +44 -0
- package/docs/PROJECT_STATUS.md +263 -0
- package/docs/PUBLISHING_BLOCKERS.md +110 -0
- package/docs/RELEASE.md +148 -0
- package/docs/ROADMAP.md +42 -0
- package/docs/SECURITY.md +56 -0
- package/docs/TOOL_GUIDE.md +69 -0
- package/extension/background.js +55 -0
- package/extension/cdp.js +582 -0
- package/extension/content.css +9 -0
- package/extension/content.js +946 -0
- package/extension/manifest.json +35 -0
- package/extension/network-monitor.js +140 -0
- package/extension/popup.css +66 -0
- package/extension/popup.html +30 -0
- package/extension/popup.js +55 -0
- package/extension/session-manager.js +332 -0
- package/extension/settings.js +94 -0
- package/extension/tool-handlers.js +1158 -0
- package/lib/runtime-paths.js +39 -0
- package/mcp/bridge-hub.js +604 -0
- package/mcp/http-server.js +326 -0
- package/mcp/json-rpc.js +35 -0
- package/mcp/memory.js +126 -0
- package/mcp/redaction.js +94 -0
- package/mcp/server.js +269 -0
- package/mcp/tools.js +1092 -0
- package/package.json +60 -0
- package/scripts/check-package-metadata.js +131 -0
- package/scripts/check-published-package.js +113 -0
- package/scripts/doctor.js +163 -0
- package/scripts/package-extension.js +137 -0
- package/scripts/print-config.js +116 -0
- package/scripts/release-check.js +472 -0
- package/skills/yunti-browser-runtime/SKILL.md +77 -0
package/docs/RELEASE.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Release Runbook
|
|
2
|
+
|
|
3
|
+
This runbook describes the local release checklist for Yunti Browser Runtime.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js 22 or newer.
|
|
8
|
+
- A clean local checkout of the project.
|
|
9
|
+
- Access to the public repository that will be listed in `package.json`.
|
|
10
|
+
- npm publish permission for the `yunti-browser-runtime` package name.
|
|
11
|
+
|
|
12
|
+
## Required External Confirmation
|
|
13
|
+
|
|
14
|
+
Before publishing, confirm the package metadata points to live public URLs:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm run check:metadata
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Expected pre-first-release state:
|
|
21
|
+
|
|
22
|
+
- GitHub repository URL returns a non-404 status.
|
|
23
|
+
- GitHub issues URL returns a non-404 status or the issue tracker URL is updated.
|
|
24
|
+
- `npm view yunti-browser-runtime` may return E404 if `0.1.0` is the first release.
|
|
25
|
+
|
|
26
|
+
If the GitHub URLs return 404, do not publish. Create or publicize the repository,
|
|
27
|
+
or update `repository`, `homepage`, and `bugs.url` in `package.json`.
|
|
28
|
+
Detailed remediation options are tracked in
|
|
29
|
+
[`docs/PUBLISHING_BLOCKERS.md`](PUBLISHING_BLOCKERS.md).
|
|
30
|
+
|
|
31
|
+
`npm run check:metadata` exits non-zero when repository, homepage, or issue URLs
|
|
32
|
+
are not publicly reachable. It treats npm E404 as acceptable for a first release
|
|
33
|
+
and reports that state in JSON.
|
|
34
|
+
|
|
35
|
+
## Local Release Gate
|
|
36
|
+
|
|
37
|
+
Run the consolidated release gate:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm run release:check
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This command verifies:
|
|
44
|
+
|
|
45
|
+
- public docs do not contain local/internal residue;
|
|
46
|
+
- public Markdown relative links resolve to existing files;
|
|
47
|
+
- `package.json` and `extension/manifest.json` use the same version;
|
|
48
|
+
- npm bin smoke checks for `yunti-browser-runtime --help` and `--version` pass;
|
|
49
|
+
- Agent config smoke checks for Codex, Claude Code, Cursor, and Cline pass;
|
|
50
|
+
- doctor JSON smoke check returns structured diagnostics and local file checks;
|
|
51
|
+
- all JavaScript files pass `node --check`;
|
|
52
|
+
- the unit test suite passes;
|
|
53
|
+
- `npm pack --json --dry-run` includes required runtime, extension, skill,
|
|
54
|
+
release documentation, and release helper files.
|
|
55
|
+
- `npm run package:extension` creates an extension zip containing only the
|
|
56
|
+
required runtime files.
|
|
57
|
+
|
|
58
|
+
After external package metadata is live, run the stricter prepublish gate:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm run release:prepublish
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This runs `npm run check:metadata` first, then `npm run release:check`.
|
|
65
|
+
For the current `dingguangyi0/yunti-browser-runtime` repository metadata, this
|
|
66
|
+
gate is expected to pass before publishing.
|
|
67
|
+
|
|
68
|
+
## Extension Package
|
|
69
|
+
|
|
70
|
+
Build and inspect the browser extension zip:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run package:extension
|
|
74
|
+
unzip -l dist/yunti-browser-runtime-extension-0.1.0.zip
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`npm run release:check` also validates this zip automatically by parsing the
|
|
78
|
+
actual archive entries.
|
|
79
|
+
|
|
80
|
+
The zip should contain only the extension runtime files:
|
|
81
|
+
|
|
82
|
+
- `background.js`
|
|
83
|
+
- `cdp.js`
|
|
84
|
+
- `content.css`
|
|
85
|
+
- `content.js`
|
|
86
|
+
- `network-monitor.js`
|
|
87
|
+
- `manifest.json`
|
|
88
|
+
- `popup.css`
|
|
89
|
+
- `popup.html`
|
|
90
|
+
- `popup.js`
|
|
91
|
+
- `session-manager.js`
|
|
92
|
+
- `settings.js`
|
|
93
|
+
- `tool-handlers.js`
|
|
94
|
+
|
|
95
|
+
## Optional Real-Browser Smoke Test
|
|
96
|
+
|
|
97
|
+
Run this when Playwright and Chromium are available:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
YUNTI_E2E=1 npm run test:e2e
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The default `npm test` run skips the real-browser smoke test unless `YUNTI_E2E=1`
|
|
104
|
+
is set.
|
|
105
|
+
|
|
106
|
+
## Publish
|
|
107
|
+
|
|
108
|
+
After the external URL confirmation and local release gate pass:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npm run release:dry-run
|
|
112
|
+
npm run release:publish
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The dry-run and publish scripts both run `npm run release:prepublish` before
|
|
116
|
+
publishing. They also pin `https://registry.npmjs.org/` so a local mirror
|
|
117
|
+
registry configuration cannot accidentally receive the release.
|
|
118
|
+
`npm run release:publish` also runs `npm run release:whoami` before publishing.
|
|
119
|
+
|
|
120
|
+
If npm auth is missing, log in first:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm adduser --registry=https://registry.npmjs.org/
|
|
124
|
+
npm run release:whoami
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If the npm account requires two-factor authentication for publishing, pass the
|
|
128
|
+
current one-time password to the publish script:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm run release:publish -- --otp=<6-digit-code>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Alternatively, publish with a granular access token that has package publish
|
|
135
|
+
permission and bypass 2FA enabled.
|
|
136
|
+
|
|
137
|
+
After publishing, verify:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm run release:verify-published
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Post-Release
|
|
144
|
+
|
|
145
|
+
- Re-run `npm run doctor` in a fresh local setup.
|
|
146
|
+
- Re-run `npm run print-config -- --agent codex --human`.
|
|
147
|
+
- Load or package the extension from the published source.
|
|
148
|
+
- Update `docs/PROJECT_STATUS.md` with the release result and published version.
|
package/docs/ROADMAP.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
## Phase 0: Scaffold
|
|
4
|
+
|
|
5
|
+
- Create standalone repository structure.
|
|
6
|
+
- Document project intent and status.
|
|
7
|
+
- Define local-first architecture.
|
|
8
|
+
|
|
9
|
+
## Phase 1: Local Runtime MVP
|
|
10
|
+
|
|
11
|
+
- MCP stdio server starts a local bridge automatically.
|
|
12
|
+
- Browser extension registers local tabs with the bridge.
|
|
13
|
+
- Agent can list browser targets.
|
|
14
|
+
- Agent can inspect a page snapshot.
|
|
15
|
+
- Agent can send CDP commands through a stable browser route.
|
|
16
|
+
- Agent can click, type, navigate, screenshot, and read network/console logs.
|
|
17
|
+
|
|
18
|
+
## Phase 2: Install Experience
|
|
19
|
+
|
|
20
|
+
- Add `npm run doctor`.
|
|
21
|
+
- Add `npm run package:extension`.
|
|
22
|
+
- Add MCP config printer.
|
|
23
|
+
- Add clear Chrome/Edge extension loading instructions.
|
|
24
|
+
|
|
25
|
+
## Phase 3: Reliability
|
|
26
|
+
|
|
27
|
+
- Add session TTL and fast stale-session failures.
|
|
28
|
+
- Add better error messages for wrong parameter combinations.
|
|
29
|
+
- Add smoke tests for bridge, MCP, and extension message contracts.
|
|
30
|
+
|
|
31
|
+
## Phase 4: Productization
|
|
32
|
+
|
|
33
|
+
- Rename tools to `yunti_*`.
|
|
34
|
+
- Keep compatibility aliases only when useful.
|
|
35
|
+
- Publish an npm package.
|
|
36
|
+
- Prepare public docs and examples.
|
|
37
|
+
|
|
38
|
+
## Future: Remote Mode
|
|
39
|
+
|
|
40
|
+
Remote multi-user operation is intentionally out of the first release. It should
|
|
41
|
+
be designed as a separate server layer on top of the local runtime, not mixed
|
|
42
|
+
into the local core.
|
package/docs/SECURITY.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Security, Permissions, And Privacy Notes
|
|
2
|
+
|
|
3
|
+
## Current Boundary
|
|
4
|
+
|
|
5
|
+
The first release is local single-user software:
|
|
6
|
+
|
|
7
|
+
- bridge binds to `127.0.0.1` by default;
|
|
8
|
+
- bridge routes require `x-yunti-browser-token` except limited `/health`;
|
|
9
|
+
- CORS only echoes local debug origins and browser-extension origins by default;
|
|
10
|
+
- extension talks to the local bridge;
|
|
11
|
+
- MCP tools default to `userId=local`;
|
|
12
|
+
- no remote relay is part of the documented install path.
|
|
13
|
+
|
|
14
|
+
## Data Handling
|
|
15
|
+
|
|
16
|
+
- Cookies and raw authorization headers are not returned by network tools.
|
|
17
|
+
- Network URLs, headers, request bodies, and console messages are sanitized.
|
|
18
|
+
- Learning memory is stored under `~/.yunti_agent/users/{userId}/memory`.
|
|
19
|
+
- The content script does not call product-specific login APIs.
|
|
20
|
+
|
|
21
|
+
## Browser Permissions
|
|
22
|
+
|
|
23
|
+
The extension uses browser permissions required for automation:
|
|
24
|
+
|
|
25
|
+
- `tabs` for tab inventory and activation;
|
|
26
|
+
- `debugger` for CDP commands;
|
|
27
|
+
- `storage` for local bridge URL, token, user, and page-match settings;
|
|
28
|
+
- `webRequest` for sanitized network observations;
|
|
29
|
+
- `activeTab` for visible-tab capture fallback paths.
|
|
30
|
+
|
|
31
|
+
The extension currently declares broad `http://*/*` and `https://*/*` host
|
|
32
|
+
access so it can register and operate arbitrary local user-selected pages. It
|
|
33
|
+
also declares localhost bridge access for the local HTTP bridge. A narrower
|
|
34
|
+
allowlist can be configured in the extension popup with page match patterns, and
|
|
35
|
+
store-distributed releases should re-review whether broad host permissions are
|
|
36
|
+
still appropriate for the intended audience.
|
|
37
|
+
|
|
38
|
+
Users should only load the extension from a trusted local checkout.
|
|
39
|
+
|
|
40
|
+
## Privacy Notes
|
|
41
|
+
|
|
42
|
+
- The runtime is local-first and does not send browser observations to a Yunti
|
|
43
|
+
hosted service.
|
|
44
|
+
- Raw cookies, authorization headers, passwords, and token-like fields are not
|
|
45
|
+
returned by the documented tools.
|
|
46
|
+
- Learning memory is local filesystem data and should not contain secrets.
|
|
47
|
+
- Agents should summarize sensitive-looking output instead of repeating it.
|
|
48
|
+
|
|
49
|
+
## Not Yet Implemented
|
|
50
|
+
|
|
51
|
+
- Signed extension release package.
|
|
52
|
+
- Remote multi-user isolation layer.
|
|
53
|
+
- Per-tool allow/deny policy.
|
|
54
|
+
|
|
55
|
+
Remote deployment must be designed separately and should not reuse the local
|
|
56
|
+
single-user defaults without an authentication and ownership model.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Tool Guide
|
|
2
|
+
|
|
3
|
+
## Agent Workflow
|
|
4
|
+
|
|
5
|
+
1. Call `yunti_get_tool_usage_hints` when unsure about parameters or routing.
|
|
6
|
+
2. Call `yunti_list_browser_targets` to understand the live browser state.
|
|
7
|
+
3. Keep the returned `browserSessionId` for follow-up page/CDP tools.
|
|
8
|
+
4. If the session becomes stale, call `yunti_list_browser_targets` again and
|
|
9
|
+
retry with the latest route.
|
|
10
|
+
5. For multi-step page work, prefer one stable `browserSessionId` throughout the
|
|
11
|
+
task.
|
|
12
|
+
|
|
13
|
+
Sessions expire when the extension stops polling the local bridge. Stale-session
|
|
14
|
+
errors include a reason and recovery hint; do not keep retrying an expired id.
|
|
15
|
+
|
|
16
|
+
## Core Tools
|
|
17
|
+
|
|
18
|
+
- `yunti_list_browser_targets`: canonical live inventory for tabs and targets.
|
|
19
|
+
- `yunti_list_pages`: compatibility alias for the same live inventory.
|
|
20
|
+
- `yunti_get_page_snapshot`: lightweight page state and visible context.
|
|
21
|
+
- `yunti_take_snapshot`: element-oriented snapshot for uid-based actions.
|
|
22
|
+
- `yunti_click`, `yunti_fill`, `yunti_hover`: common DOM actions.
|
|
23
|
+
- `yunti_cdp_send_command`: low-level CDP access routed through the extension.
|
|
24
|
+
- `yunti_get_network_log`, `yunti_list_network_requests`: sanitized network
|
|
25
|
+
observations.
|
|
26
|
+
- `yunti_list_console_messages`: console diagnostics.
|
|
27
|
+
- `yunti_remember_learning`, `yunti_get_learning_memory`: local agent memory.
|
|
28
|
+
|
|
29
|
+
## Routing Rules
|
|
30
|
+
|
|
31
|
+
- Standalone local mode defaults to `userId=local`.
|
|
32
|
+
- Agents do not need to pass `userId` unless they intentionally override
|
|
33
|
+
`YUNTI_BROWSER_USER_ID`.
|
|
34
|
+
- `browserSessionId` identifies a registered browser page route.
|
|
35
|
+
- `browserSessionId` expires without extension heartbeat; refresh live inventory
|
|
36
|
+
when a stale-session error appears.
|
|
37
|
+
- New tabs can return a new `browserSessionId`; use the returned value for
|
|
38
|
+
follow-up calls on that tab.
|
|
39
|
+
- Raw `targetId` or `tabId` is for CDP/tab operations, not a replacement for
|
|
40
|
+
`browserSessionId`.
|
|
41
|
+
|
|
42
|
+
## CDP Rules
|
|
43
|
+
|
|
44
|
+
- Do not run CDP method names in a shell.
|
|
45
|
+
- Use `yunti_cdp_send_command` with `method` and optional `params`.
|
|
46
|
+
- `params` must be an object when provided.
|
|
47
|
+
- For `Target.activateTarget` or `Target.closeTarget`, pass top-level `tabId`
|
|
48
|
+
or `targetId` with a valid `browserSessionId`.
|
|
49
|
+
- Use `Runtime.evaluate` for JavaScript evaluation, but keep related multi-step
|
|
50
|
+
work in one eval when page state must stay in the same execution context.
|
|
51
|
+
|
|
52
|
+
## Parameter Rules
|
|
53
|
+
|
|
54
|
+
- `yunti_click` and `yunti_hover` require a `uid`, a `selector`, or both `x`
|
|
55
|
+
and `y`; use `yunti_take_snapshot` to get stable uids.
|
|
56
|
+
- `yunti_fill` requires `value` and either `uid` or `selector`; it does not
|
|
57
|
+
support coordinate-only targeting.
|
|
58
|
+
- `yunti_close_page` closes by `browserSessionId`; to close by raw `tabId` or
|
|
59
|
+
`targetId`, use `yunti_cdp_send_command` with `Target.closeTarget`.
|
|
60
|
+
- `yunti_forget_learning_memory` requires `id`, or `all=true` plus
|
|
61
|
+
`confirmed=true` when deleting every memory.
|
|
62
|
+
|
|
63
|
+
## Safety Rules
|
|
64
|
+
|
|
65
|
+
- Read-only inspection is allowed by default.
|
|
66
|
+
- Destructive, financial, credential, upload, or submit actions should require
|
|
67
|
+
explicit user confirmation in the agent workflow.
|
|
68
|
+
- Tool outputs redact likely cookies, authorization headers, passwords, and
|
|
69
|
+
token-like values.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createCdpController } from "./cdp.js"
|
|
2
|
+
import { installNetworkMonitor } from "./network-monitor.js"
|
|
3
|
+
import { createSessionManager } from "./session-manager.js"
|
|
4
|
+
import { createToolDispatcher } from "./tool-handlers.js"
|
|
5
|
+
|
|
6
|
+
const sessionManager = createSessionManager()
|
|
7
|
+
const {
|
|
8
|
+
forwardConsoleEvent,
|
|
9
|
+
postBridge,
|
|
10
|
+
pollers,
|
|
11
|
+
sessionsByTab,
|
|
12
|
+
startPolling,
|
|
13
|
+
} = sessionManager
|
|
14
|
+
|
|
15
|
+
const cdp = createCdpController({
|
|
16
|
+
sessionsByTab,
|
|
17
|
+
pollers,
|
|
18
|
+
postBridge,
|
|
19
|
+
startPolling,
|
|
20
|
+
forwardConsoleEvent,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const { detachCdpTab, installCdpEventForwarder } = cdp
|
|
24
|
+
const { executeToolRequest } = createToolDispatcher({
|
|
25
|
+
sessionsByTab,
|
|
26
|
+
pollers,
|
|
27
|
+
postBridge,
|
|
28
|
+
startPolling,
|
|
29
|
+
cdp,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
sessionManager.setToolRequestHandler(executeToolRequest)
|
|
33
|
+
|
|
34
|
+
installNetworkMonitor({
|
|
35
|
+
sessionsByTab,
|
|
36
|
+
postBridge,
|
|
37
|
+
getPlatformMatches: sessionManager.getPlatformMatches,
|
|
38
|
+
})
|
|
39
|
+
installCdpEventForwarder()
|
|
40
|
+
|
|
41
|
+
chrome.tabs.onRemoved.addListener((tabId) => {
|
|
42
|
+
void detachCdpTab(tabId, null, "tab_removed").catch(() => {})
|
|
43
|
+
sessionManager.forgetTab(tabId)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
chrome.tabs.onActivated.addListener(({ tabId }) => {
|
|
47
|
+
void sessionManager.activateTab(tabId)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
51
|
+
void sessionManager.handleMessage(message, sender).then(sendResponse, (error) =>
|
|
52
|
+
sendResponse({ ok: false, error: error?.message || String(error) })
|
|
53
|
+
)
|
|
54
|
+
return true
|
|
55
|
+
})
|