@te-river/opencode-team-mode 1.5.5 → 1.5.6
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 +732 -634
- package/README.zh-CN.md +655 -576
- package/dist/agents.d.ts +6 -1
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +103 -531
- package/dist/agents.js.map +1 -1
- package/dist/approval-gate.d.ts +16 -0
- package/dist/approval-gate.d.ts.map +1 -1
- package/dist/approval-gate.js +8 -1
- package/dist/approval-gate.js.map +1 -1
- package/dist/blackboard.d.ts.map +1 -1
- package/dist/blackboard.js +3 -2
- package/dist/blackboard.js.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +7 -6
- package/dist/commands.js.map +1 -1
- package/dist/envprotect/bash-classify.d.ts +42 -0
- package/dist/envprotect/bash-classify.d.ts.map +1 -0
- package/dist/envprotect/bash-classify.js +221 -0
- package/dist/envprotect/bash-classify.js.map +1 -0
- package/dist/envprotect/gate-predicates.d.ts +57 -0
- package/dist/envprotect/gate-predicates.d.ts.map +1 -0
- package/dist/envprotect/gate-predicates.js +174 -0
- package/dist/envprotect/gate-predicates.js.map +1 -0
- package/dist/envprotect/hook.d.ts +45 -0
- package/dist/envprotect/hook.d.ts.map +1 -0
- package/dist/envprotect/hook.js +158 -0
- package/dist/envprotect/hook.js.map +1 -0
- package/dist/envprotect/path-classify.d.ts +16 -0
- package/dist/envprotect/path-classify.d.ts.map +1 -0
- package/dist/envprotect/path-classify.js +72 -0
- package/dist/envprotect/path-classify.js.map +1 -0
- package/dist/envprotect/patterns.d.ts +77 -0
- package/dist/envprotect/patterns.d.ts.map +1 -0
- package/dist/envprotect/patterns.js +182 -0
- package/dist/envprotect/patterns.js.map +1 -0
- package/dist/envprotect.d.ts +19 -217
- package/dist/envprotect.d.ts.map +1 -1
- package/dist/envprotect.js +18 -803
- package/dist/envprotect.js.map +1 -1
- package/dist/fs-safe.d.ts +16 -0
- package/dist/fs-safe.d.ts.map +1 -0
- package/dist/fs-safe.js +56 -0
- package/dist/fs-safe.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -6
- package/dist/index.js.map +1 -1
- package/dist/prompts/lead.d.ts +7 -0
- package/dist/prompts/lead.d.ts.map +1 -0
- package/dist/prompts/lead.js +230 -0
- package/dist/prompts/lead.js.map +1 -0
- package/dist/prompts/shared.d.ts +8 -0
- package/dist/prompts/shared.d.ts.map +1 -0
- package/dist/prompts/shared.js +118 -0
- package/dist/prompts/shared.js.map +1 -0
- package/dist/prompts/specialists.d.ts +12 -0
- package/dist/prompts/specialists.d.ts.map +1 -0
- package/dist/prompts/specialists.js +218 -0
- package/dist/prompts/specialists.js.map +1 -0
- package/dist/shell-text.d.ts +14 -0
- package/dist/shell-text.d.ts.map +1 -0
- package/dist/shell-text.js +16 -0
- package/dist/shell-text.js.map +1 -0
- package/dist/tm/args-schema.d.ts +36 -0
- package/dist/tm/args-schema.d.ts.map +1 -0
- package/dist/tm/args-schema.js +191 -0
- package/dist/tm/args-schema.js.map +1 -0
- package/dist/tm/browser.d.ts +52 -0
- package/dist/tm/browser.d.ts.map +1 -0
- package/dist/tm/browser.js +361 -0
- package/dist/tm/browser.js.map +1 -0
- package/dist/tm/client-unwrap.d.ts +38 -0
- package/dist/tm/client-unwrap.d.ts.map +1 -0
- package/dist/tm/client-unwrap.js +113 -0
- package/dist/tm/client-unwrap.js.map +1 -0
- package/dist/tm/config.d.ts +46 -18
- package/dist/tm/config.d.ts.map +1 -1
- package/dist/tm/config.js +60 -17
- package/dist/tm/config.js.map +1 -1
- package/dist/tm/guard.d.ts.map +1 -1
- package/dist/tm/guard.js +4 -7
- package/dist/tm/guard.js.map +1 -1
- package/dist/tm/index.d.ts +15 -5
- package/dist/tm/index.d.ts.map +1 -1
- package/dist/tm/index.js +95 -19
- package/dist/tm/index.js.map +1 -1
- package/dist/tm/memory.d.ts +82 -0
- package/dist/tm/memory.d.ts.map +1 -0
- package/dist/tm/memory.js +350 -0
- package/dist/tm/memory.js.map +1 -0
- package/dist/tm/pipelines.d.ts +58 -0
- package/dist/tm/pipelines.d.ts.map +1 -0
- package/dist/tm/pipelines.js +301 -0
- package/dist/tm/pipelines.js.map +1 -0
- package/dist/tm/preview.d.ts +6 -1
- package/dist/tm/preview.d.ts.map +1 -1
- package/dist/tm/preview.js +31 -8
- package/dist/tm/preview.js.map +1 -1
- package/dist/tm/ptc/budgets.d.ts +38 -0
- package/dist/tm/ptc/budgets.d.ts.map +1 -0
- package/dist/tm/ptc/budgets.js +59 -0
- package/dist/tm/ptc/budgets.js.map +1 -0
- package/dist/tm/ptc/contract.d.ts +131 -0
- package/dist/tm/ptc/contract.d.ts.map +1 -0
- package/dist/tm/ptc/contract.js +47 -0
- package/dist/tm/ptc/contract.js.map +1 -0
- package/dist/tm/ptc/driver.d.ts +37 -0
- package/dist/tm/ptc/driver.d.ts.map +1 -0
- package/dist/tm/ptc/driver.js +181 -0
- package/dist/tm/ptc/driver.js.map +1 -0
- package/dist/tm/ptc/engines.d.ts +32 -0
- package/dist/tm/ptc/engines.d.ts.map +1 -0
- package/dist/tm/ptc/engines.js +201 -0
- package/dist/tm/ptc/engines.js.map +1 -0
- package/dist/tm/ptc/gate.d.ts +28 -0
- package/dist/tm/ptc/gate.d.ts.map +1 -0
- package/dist/tm/ptc/gate.js +127 -0
- package/dist/tm/ptc/gate.js.map +1 -0
- package/dist/tm/ptc/index.d.ts +19 -0
- package/dist/tm/ptc/index.d.ts.map +1 -0
- package/dist/tm/ptc/index.js +15 -0
- package/dist/tm/ptc/index.js.map +1 -0
- package/dist/tm/ptc/pscan.d.ts +11 -0
- package/dist/tm/ptc/pscan.d.ts.map +1 -0
- package/dist/tm/ptc/pscan.js +27 -0
- package/dist/tm/ptc/pscan.js.map +1 -0
- package/dist/tm/ptc/summary.d.ts +17 -0
- package/dist/tm/ptc/summary.d.ts.map +1 -0
- package/dist/tm/ptc/summary.js +107 -0
- package/dist/tm/ptc/summary.js.map +1 -0
- package/dist/tm/ptc/tool.d.ts +35 -0
- package/dist/tm/ptc/tool.d.ts.map +1 -0
- package/dist/tm/ptc/tool.js +135 -0
- package/dist/tm/ptc/tool.js.map +1 -0
- package/dist/tm/ptc.d.ts +45 -26
- package/dist/tm/ptc.d.ts.map +1 -1
- package/dist/tm/ptc.js +71 -45
- package/dist/tm/ptc.js.map +1 -1
- package/dist/tm/result.d.ts +34 -0
- package/dist/tm/result.d.ts.map +1 -0
- package/dist/tm/result.js +87 -0
- package/dist/tm/result.js.map +1 -0
- package/dist/tm/shell-bridge.d.ts +22 -0
- package/dist/tm/shell-bridge.d.ts.map +1 -0
- package/dist/tm/shell-bridge.js +70 -0
- package/dist/tm/shell-bridge.js.map +1 -0
- package/dist/tm/store.d.ts.map +1 -1
- package/dist/tm/store.js +2 -1
- package/dist/tm/store.js.map +1 -1
- package/dist/tm/tools.d.ts +13 -71
- package/dist/tm/tools.d.ts.map +1 -1
- package/dist/tm/tools.js +21 -655
- package/dist/tm/tools.js.map +1 -1
- package/dist/tm/webfetch.d.ts +94 -0
- package/dist/tm/webfetch.d.ts.map +1 -0
- package/dist/tm/webfetch.js +225 -0
- package/dist/tm/webfetch.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm_browser — governed interactive browser (Plan C: the user's own
|
|
3
|
+
* Chromium-family browser driven headful over the CDP pipe protocol).
|
|
4
|
+
*
|
|
5
|
+
* Feasibility proven by smoke (Edge + --remote-debugging-pipe + JSON/NUL
|
|
6
|
+
* framing over fds 3/4 — zero deps, no WebSocket implementation). Qoder's
|
|
7
|
+
* hardening ideas are ported where the plugin can reach them:
|
|
8
|
+
* - isolated temp user-data-dir (never the user's real profile);
|
|
9
|
+
* - per-navigation allowlist enforced at the NETWORK layer via CDP
|
|
10
|
+
* Fetch.requestPaused (non-allowlisted hosts get BlockedByClient —
|
|
11
|
+
* the per-hop re-check analog);
|
|
12
|
+
* - hardened webPreferences are the spawn's own flags (no-first-run,
|
|
13
|
+
* no-extensions, mute);
|
|
14
|
+
* - hard per-command timeout + explicit close; dispose kills the child.
|
|
15
|
+
*
|
|
16
|
+
* Environment adaptivity (different OpenCode hosts):
|
|
17
|
+
* - headful by default (Plan C); display-less Linux (no DISPLAY/
|
|
18
|
+
* WAYLAND_DISPLAY) automatically falls back to headless; TM_BROWSER_
|
|
19
|
+
* HEADLESS=1|0 forces either way;
|
|
20
|
+
* - browser discovery: TM_BROWSER_PATH override, then per-OS candidate
|
|
21
|
+
* paths (Edge first on Windows — it is always there; Chrome/Chromium
|
|
22
|
+
* elsewhere). No browser → structured error, the agent falls back to
|
|
23
|
+
* tm_webfetch / user MCP tools per the priority ladder.
|
|
24
|
+
*
|
|
25
|
+
* Role access mirrors tm_webfetch: network roles (team + researcher) only.
|
|
26
|
+
*/
|
|
27
|
+
import { spawn } from "node:child_process";
|
|
28
|
+
import * as fs from "node:fs";
|
|
29
|
+
import * as os from "node:os";
|
|
30
|
+
import * as path from "node:path";
|
|
31
|
+
import { checkWebUrl } from "./webfetch.js";
|
|
32
|
+
import { tmError, toToolResult } from "./result.js";
|
|
33
|
+
import { rmForceSafe } from "../fs-safe.js";
|
|
34
|
+
/** Per-OS browser candidates, in preference order (first hit wins). */
|
|
35
|
+
const BROWSER_CANDIDATES = {
|
|
36
|
+
win32: [
|
|
37
|
+
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
38
|
+
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
39
|
+
"%LOCALAPPDATA%\\Google\\Chrome\\Application\\chrome.exe",
|
|
40
|
+
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
41
|
+
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
42
|
+
],
|
|
43
|
+
darwin: [
|
|
44
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
45
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
46
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
47
|
+
],
|
|
48
|
+
linux: [
|
|
49
|
+
"/usr/bin/google-chrome",
|
|
50
|
+
"/usr/bin/google-chrome-stable",
|
|
51
|
+
"/usr/bin/chromium-browser",
|
|
52
|
+
"/usr/bin/chromium",
|
|
53
|
+
"/snap/bin/chromium",
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
/** Resolve the browser executable: TM_BROWSER_PATH override, then per-OS
|
|
57
|
+
* candidates. %LOCALAPPDATA% style vars are expanded on win32. */
|
|
58
|
+
export function findBrowserExecutable(env = process.env) {
|
|
59
|
+
const override = String(env.TM_BROWSER_PATH ?? "").trim();
|
|
60
|
+
const tryPath = (p) => {
|
|
61
|
+
const expanded = p.replace(/%([A-Za-z_][A-Za-z0-9_]*)%/g, (_, name) => env[name] ?? "");
|
|
62
|
+
try {
|
|
63
|
+
return fs.existsSync(expanded) ? expanded : null;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
if (override)
|
|
70
|
+
return tryPath(override);
|
|
71
|
+
for (const c of BROWSER_CANDIDATES[process.platform] ?? []) {
|
|
72
|
+
const hit = tryPath(c);
|
|
73
|
+
if (hit)
|
|
74
|
+
return hit;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Headless resolution (Plan C = headful by default):
|
|
80
|
+
* TM_BROWSER_HEADLESS=1|true|force → headless (servers/CI)
|
|
81
|
+
* TM_BROWSER_HEADLESS=0|false|never → headful
|
|
82
|
+
* auto (default) → headless ONLY when there is no
|
|
83
|
+
* display possible (Linux without DISPLAY/WAYLAND_DISPLAY).
|
|
84
|
+
*/
|
|
85
|
+
export function resolveHeadless(env = process.env) {
|
|
86
|
+
const raw = String(env.TM_BROWSER_HEADLESS ?? "auto").trim().toLowerCase();
|
|
87
|
+
if (["1", "true", "force", "yes"].includes(raw))
|
|
88
|
+
return true;
|
|
89
|
+
if (["0", "false", "never", "no"].includes(raw))
|
|
90
|
+
return false;
|
|
91
|
+
if (process.platform === "linux")
|
|
92
|
+
return !env.DISPLAY && !env.WAYLAND_DISPLAY;
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
class PipeCdp {
|
|
96
|
+
child;
|
|
97
|
+
nextId = 1;
|
|
98
|
+
pending = new Map();
|
|
99
|
+
buf = Buffer.alloc(0);
|
|
100
|
+
events = [];
|
|
101
|
+
onEvent = (handler) => this.eventHandler = handler;
|
|
102
|
+
eventHandler = () => { };
|
|
103
|
+
constructor(child) {
|
|
104
|
+
this.child = child;
|
|
105
|
+
const inp = child.stdio[4];
|
|
106
|
+
inp?.on("data", (chunk) => {
|
|
107
|
+
this.buf = Buffer.concat([this.buf, chunk]);
|
|
108
|
+
for (;;) {
|
|
109
|
+
const i = this.buf.indexOf(0);
|
|
110
|
+
if (i === -1)
|
|
111
|
+
break;
|
|
112
|
+
const line = this.buf.subarray(0, i).toString("utf8");
|
|
113
|
+
this.buf = this.buf.subarray(i + 1);
|
|
114
|
+
try {
|
|
115
|
+
const m = JSON.parse(line);
|
|
116
|
+
if (m.id && this.pending.has(m.id)) {
|
|
117
|
+
this.pending.get(m.id)(m);
|
|
118
|
+
this.pending.delete(m.id);
|
|
119
|
+
}
|
|
120
|
+
else if (m.method) {
|
|
121
|
+
this.events.push(m);
|
|
122
|
+
this.eventHandler(m);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
/* partial frame */
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
call(method, params = {}, sessionId, timeoutMs = 20_000) {
|
|
132
|
+
const id = this.nextId++;
|
|
133
|
+
const pipe = this.child.stdio[3];
|
|
134
|
+
return new Promise((res, rej) => {
|
|
135
|
+
const timer = setTimeout(() => {
|
|
136
|
+
if (this.pending.has(id)) {
|
|
137
|
+
this.pending.delete(id);
|
|
138
|
+
rej(new Error(`CDP ${method} 超时(${timeoutMs}ms)`));
|
|
139
|
+
}
|
|
140
|
+
}, timeoutMs);
|
|
141
|
+
this.pending.set(id, (m) => {
|
|
142
|
+
clearTimeout(timer);
|
|
143
|
+
m.error ? rej(new Error(`CDP ${method} -> ${JSON.stringify(m.error)}`)) : res(m.result ?? {});
|
|
144
|
+
});
|
|
145
|
+
pipe?.write(Buffer.from(JSON.stringify({ id, method, params, ...(sessionId ? { sessionId } : {}) }) + "\0"));
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
async waitEvent(method, sessionId, timeoutMs = 15_000) {
|
|
149
|
+
const t0 = Date.now();
|
|
150
|
+
for (;;) {
|
|
151
|
+
const i = this.events.findIndex((e) => e.method === method && (!sessionId || e.sessionId === sessionId));
|
|
152
|
+
if (i >= 0)
|
|
153
|
+
return this.events.splice(i, 1)[0];
|
|
154
|
+
if (Date.now() - t0 > timeoutMs)
|
|
155
|
+
throw new Error(`等待 CDP 事件 ${method} 超时`);
|
|
156
|
+
await new Promise((r) => setTimeout(r, 80));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const SPAWN_TIMEOUT_MS = 15_000;
|
|
161
|
+
const NAVIGATE_EVENT_TIMEOUT_MS = 15_000;
|
|
162
|
+
// ---------- tool ----------------------------------------------------------------
|
|
163
|
+
export function buildTmBrowserTool(deps) {
|
|
164
|
+
const { pipelines } = deps;
|
|
165
|
+
const env = deps.env ?? process.env;
|
|
166
|
+
const tool = "tm_browser";
|
|
167
|
+
const traj = (e) => pipelines.store.appendTrajectory({ tool, ...e });
|
|
168
|
+
let session = null;
|
|
169
|
+
const allowlist = deps.cfg.webfetchAllowedDomains
|
|
170
|
+
?? ["*"];
|
|
171
|
+
async function ensureSession(headless) {
|
|
172
|
+
if (session)
|
|
173
|
+
return session;
|
|
174
|
+
const executable = findBrowserExecutable(env);
|
|
175
|
+
if (!executable) {
|
|
176
|
+
throw new Error("本机未找到可用的浏览器(按 Edge/Chrome/Chromium 顺序探测失败)。" +
|
|
177
|
+
"设置 TM_BROWSER_PATH 指向浏览器可执行文件,或改用 tm_webfetch / 用户 MCP 工具。");
|
|
178
|
+
}
|
|
179
|
+
const profileDir = fs.mkdtempSync(path.join(os.tmpdir(), "tm-browser-"));
|
|
180
|
+
const child = spawn(executable, [
|
|
181
|
+
headless ? "--headless=new" : "--start-maximized",
|
|
182
|
+
"--remote-debugging-pipe",
|
|
183
|
+
`--user-data-dir=${profileDir}`,
|
|
184
|
+
"--no-first-run", "--no-default-browser-check", "--disable-extensions",
|
|
185
|
+
"--disable-background-networking", "--mute-audio",
|
|
186
|
+
"about:blank",
|
|
187
|
+
], { stdio: ["ignore", "ignore", "ignore", "pipe", "pipe"], windowsHide: true });
|
|
188
|
+
const cdp = new PipeCdp(child);
|
|
189
|
+
const t0 = Date.now();
|
|
190
|
+
// ready loop: the pipe is not immediately writable-to-a-live-target
|
|
191
|
+
for (;;) {
|
|
192
|
+
try {
|
|
193
|
+
await cdp.call("Target.getTargets", {}, undefined, 3000);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
catch (e) {
|
|
197
|
+
if (Date.now() - t0 > SPAWN_TIMEOUT_MS || child.exitCode !== null) {
|
|
198
|
+
child.kill();
|
|
199
|
+
fs.rmSync(profileDir, { recursive: true, force: true });
|
|
200
|
+
throw new Error(`浏览器启动失败:${e.message}`);
|
|
201
|
+
}
|
|
202
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const targets = await cdp.call("Target.getTargets");
|
|
206
|
+
const page = targets.targetInfos.find((t) => t.type === "page");
|
|
207
|
+
if (!page)
|
|
208
|
+
throw new Error("浏览器启动后未找到 page target");
|
|
209
|
+
const { sessionId } = await cdp.call("Target.attachToTarget", { targetId: page.targetId, flatten: true });
|
|
210
|
+
await cdp.call("Page.enable", {}, sessionId);
|
|
211
|
+
// network-layer allowlist enforcement (Qoder's per-hop re-check analog)
|
|
212
|
+
await cdp.call("Fetch.enable", { patterns: [{ urlPattern: "*" }] }, sessionId);
|
|
213
|
+
cdp.onEvent((m) => {
|
|
214
|
+
if (m.method !== "Fetch.requestPaused" || m.sessionId !== sessionId)
|
|
215
|
+
return;
|
|
216
|
+
const requestId = String(m.params.requestId ?? "");
|
|
217
|
+
const url = String(m.params.request?.url ?? "");
|
|
218
|
+
const verdict = checkWebUrl(url, allowlist);
|
|
219
|
+
if (verdict.ok) {
|
|
220
|
+
void cdp.call("Fetch.continueRequest", { requestId }, sessionId, 5000).catch(() => { });
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
traj({ step_id: "browser", event: "blocked", url: url.slice(0, 200) });
|
|
224
|
+
void cdp.call("Fetch.failRequest", { requestId, errorReason: "BlockedByClient" }, sessionId, 5000).catch(() => { });
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
child.on("exit", () => {
|
|
228
|
+
session = null;
|
|
229
|
+
// best-effort: the profile may still be file-locked during shutdown —
|
|
230
|
+
// a leftover temp dir is reclaimed by the OS, never an error for the task
|
|
231
|
+
try {
|
|
232
|
+
rmForceSafe(profileDir, { recursive: true });
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
/* ignore */
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
session = { child, cdp, sessionId, profileDir, currentUrl: "about:blank" };
|
|
239
|
+
return session;
|
|
240
|
+
}
|
|
241
|
+
async function closeSession() {
|
|
242
|
+
if (!session)
|
|
243
|
+
return "没有打开的浏览器会话。";
|
|
244
|
+
const { child, cdp, profileDir } = session;
|
|
245
|
+
session = null;
|
|
246
|
+
await cdp.call("Browser.close", {}, undefined, 3000).catch(() => { });
|
|
247
|
+
if (child.exitCode === null) {
|
|
248
|
+
child.kill();
|
|
249
|
+
}
|
|
250
|
+
// wait briefly for the process to release the profile (Windows file
|
|
251
|
+
// locks linger while the browser is still shutting down)
|
|
252
|
+
await new Promise((res) => {
|
|
253
|
+
if (child.exitCode !== null)
|
|
254
|
+
return res();
|
|
255
|
+
const t = setTimeout(res, 3000);
|
|
256
|
+
child.once("exit", () => {
|
|
257
|
+
clearTimeout(t);
|
|
258
|
+
res();
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
try {
|
|
262
|
+
rmForceSafe(profileDir, { recursive: true });
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
/* a locked leftover temp dir is reclaimed by the OS — never fail close */
|
|
266
|
+
}
|
|
267
|
+
return "浏览器会话已关闭,临时配置目录已清理。";
|
|
268
|
+
}
|
|
269
|
+
const execute = async (rawArgs) => {
|
|
270
|
+
try {
|
|
271
|
+
const args = rawArgs ?? {};
|
|
272
|
+
const action = String(args.action ?? "").trim();
|
|
273
|
+
const url = String(args.url ?? "").trim();
|
|
274
|
+
// allowlist FIRST — a disallowed URL never spawns the browser
|
|
275
|
+
if ((action === "open" || action === "navigate") && url) {
|
|
276
|
+
const verdict = checkWebUrl(url, allowlist);
|
|
277
|
+
if (!verdict.ok)
|
|
278
|
+
return toToolResult(tmError(tool, "permission", verdict.message));
|
|
279
|
+
}
|
|
280
|
+
if (action === "open") {
|
|
281
|
+
if (!url)
|
|
282
|
+
return toToolResult(tmError(tool, "args", "缺少 url 参数"));
|
|
283
|
+
if (session) {
|
|
284
|
+
// already open: navigate instead of spawning a second browser
|
|
285
|
+
return toToolResult(await navigateTo(url));
|
|
286
|
+
}
|
|
287
|
+
const headless = args.headless != null ? Boolean(args.headless) : resolveHeadless(env);
|
|
288
|
+
const s = await ensureSession(headless);
|
|
289
|
+
const out = await navigateTo(url);
|
|
290
|
+
traj({ step_id: "browser", event: "open", headless });
|
|
291
|
+
return toToolResult(`浏览器已启动(${headless ? "无头" : "有头窗口"},隔离临时配置)。${out}`);
|
|
292
|
+
}
|
|
293
|
+
if (action === "navigate") {
|
|
294
|
+
if (!url)
|
|
295
|
+
return toToolResult(tmError(tool, "args", "缺少 url 参数"));
|
|
296
|
+
if (!session)
|
|
297
|
+
return toToolResult(tmError(tool, "args", "没有打开的浏览器会话——先用 action:\"open\""));
|
|
298
|
+
return toToolResult(await navigateTo(url));
|
|
299
|
+
}
|
|
300
|
+
if (action === "read") {
|
|
301
|
+
if (!session)
|
|
302
|
+
return toToolResult(tmError(tool, "args", "没有打开的浏览器会话——先用 action:\"open\""));
|
|
303
|
+
const stepId = pipelines.nextStepId();
|
|
304
|
+
traj({ step_id: stepId, event: "call", url: session.currentUrl.slice(0, 200) });
|
|
305
|
+
const ev = await session.cdp.call("Runtime.evaluate", { expression: "document.body ? document.body.innerText : ''", returnByValue: true }, session.sessionId);
|
|
306
|
+
const text = String(ev.result?.value ?? "");
|
|
307
|
+
traj({ step_id: stepId, event: "result", tokens: Math.ceil(text.length / 4) });
|
|
308
|
+
return toToolResult(`页面文本(${session.currentUrl}):\n${text.slice(0, 20000)}${text.length > 20000 ? "\n…(截断)" : ""}`);
|
|
309
|
+
}
|
|
310
|
+
if (action === "screenshot") {
|
|
311
|
+
if (!session)
|
|
312
|
+
return toToolResult(tmError(tool, "args", "没有打开的浏览器会话——先用 action:\"open\""));
|
|
313
|
+
const stepId = pipelines.nextStepId();
|
|
314
|
+
traj({ step_id: stepId, event: "call", kind: "screenshot", url: session.currentUrl.slice(0, 200) });
|
|
315
|
+
const shot = await session.cdp.call("Page.captureScreenshot", { format: "png" }, session.sessionId);
|
|
316
|
+
const data = String(shot.data ?? "");
|
|
317
|
+
const png = Buffer.from(data, "base64");
|
|
318
|
+
const dir = path.join(pipelines.store.stepsRoot(), stepId);
|
|
319
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
320
|
+
const file = path.join(dir, "screenshot.png");
|
|
321
|
+
fs.writeFileSync(file, png);
|
|
322
|
+
traj({ step_id: stepId, event: "result", bytes: png.length });
|
|
323
|
+
return toToolResult(`截图已保存(${png.length} bytes):${file}\n(PNG 已落 run store;上下文只携带路径,不携带像素。)`);
|
|
324
|
+
}
|
|
325
|
+
if (action === "close") {
|
|
326
|
+
traj({ step_id: "browser", event: "close" });
|
|
327
|
+
return toToolResult(await closeSession());
|
|
328
|
+
}
|
|
329
|
+
return toToolResult(tmError(tool, "args", `未知 action "${String(action).slice(0, 30)}"——可用: open | navigate | read | screenshot | close`));
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
const e = err;
|
|
333
|
+
return toToolResult(tmError(tool, "execute", String(e?.message ?? err ?? "browser 操作失败")));
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
async function navigateTo(url) {
|
|
337
|
+
const s = session;
|
|
338
|
+
await s.cdp.call("Page.navigate", { url }, s.sessionId);
|
|
339
|
+
await s.cdp.waitEvent("Page.loadEventFired", s.sessionId, NAVIGATE_EVENT_TIMEOUT_MS).catch(() => { });
|
|
340
|
+
s.currentUrl = url;
|
|
341
|
+
return `已导航:${url}`;
|
|
342
|
+
}
|
|
343
|
+
const DESCRIPTION = `Interactive browser (governed, Plan C): drives the user's own Chromium-family browser HEADFUL via CDP pipe — a visible window opens on desktops; display-less Linux hosts automatically run headless (TM_BROWSER_HEADLESS=1|0 forces either way). Actions:
|
|
344
|
+
- open: { url } — launch (or reuse) the session and navigate. Isolated temp profile (never your real profile); per-request DOMAIN ALLOWLIST enforced at the network layer (seeded = tm_webfetch's hosts; extend via TM_WEBFETCH_ALLOWED_DOMAINS).
|
|
345
|
+
- navigate: { url } · read: extract page text (threshold-governed like tm_read) · screenshot: save PNG into the run store, only the path enters context · close: kill + cleanup.
|
|
346
|
+
- Fixed priority ladder: ① tm_* governed tools → ② user MCP/plugin tools → ③ reasoning (never fabricate). If no browser is installed (TM_BROWSER_PATH override exists), a structured error tells you to fall back to tm_webfetch / MCP.
|
|
347
|
+
- Network role tool (team + researcher). Non-allowlisted hosts are rejected at open/navigate AND blocked per-request.`;
|
|
348
|
+
return {
|
|
349
|
+
description: DESCRIPTION,
|
|
350
|
+
args: deps.args ?? {
|
|
351
|
+
action: { descriptor: "action: open|navigate|read|screenshot|close (required)" },
|
|
352
|
+
url: { descriptor: "url: string (open/navigate, allowlisted https)" },
|
|
353
|
+
headless: { descriptor: "headless: boolean (open, optional — default auto)" },
|
|
354
|
+
},
|
|
355
|
+
execute,
|
|
356
|
+
dispose: () => {
|
|
357
|
+
void closeSession().catch(() => { });
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/tm/browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm layer — client result unwrapping + best-effort text extraction.
|
|
3
|
+
* Split out of the former tools.ts hub; behavior unchanged.
|
|
4
|
+
*/
|
|
5
|
+
export type Unwrapped = {
|
|
6
|
+
ok: true;
|
|
7
|
+
data: unknown;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
message: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Client result unwrapping — TWO live shapes + the legacy test shape:
|
|
14
|
+
* - 1.18.x REAL host (tester-probed): `{ data: <payload>, request, response }`
|
|
15
|
+
* with NO `ok` field — file.read data = {type:"text", content},
|
|
16
|
+
* find.text data = Match[]. Absent `ok` is NOT a failure; `data`
|
|
17
|
+
* presence decides success.
|
|
18
|
+
* - T0.4 legacy: `{ ok: true, data }` (what the fake clients in tests emit).
|
|
19
|
+
* RequestResult hygiene: ok === true can STILL carry the error envelope
|
|
20
|
+
* {error: {name, data: {message, ref}}} — self-check `data.error`. A
|
|
21
|
+
* top-level error / ok===false fails even when a data payload rides along.
|
|
22
|
+
*/
|
|
23
|
+
export declare function unwrapClientResult(res: unknown): Unwrapped;
|
|
24
|
+
/**
|
|
25
|
+
* One client.find.text match object -> ripgrep-style `path:line: text` lines.
|
|
26
|
+
* Key table (live-probed shape; tester re-verifies each key against real
|
|
27
|
+
* host data):
|
|
28
|
+
* path — file path of the hit (aliases: file, file_path, filePath)
|
|
29
|
+
* lines — matched lines, string[] (aliases: text, content, match, line_text,
|
|
30
|
+
* line-as-string)
|
|
31
|
+
* line — 1-based line number (aliases: line_number, lineNumber; must be
|
|
32
|
+
* numeric — a textual `line` value falls through to the text keys)
|
|
33
|
+
* Returns null when neither a path nor any hit text is found.
|
|
34
|
+
*/
|
|
35
|
+
export declare function matchObjectText(m: Record<string, unknown>): string | null;
|
|
36
|
+
/** Best-effort text extraction from verified client payloads. */
|
|
37
|
+
export declare function extractText(data: unknown): string;
|
|
38
|
+
//# sourceMappingURL=client-unwrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-unwrap.d.ts","sourceRoot":"","sources":["../../src/tm/client-unwrap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpF;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CA4B1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAsBzE;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CA0BjD"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm layer — client result unwrapping + best-effort text extraction.
|
|
3
|
+
* Split out of the former tools.ts hub; behavior unchanged.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Client result unwrapping — TWO live shapes + the legacy test shape:
|
|
7
|
+
* - 1.18.x REAL host (tester-probed): `{ data: <payload>, request, response }`
|
|
8
|
+
* with NO `ok` field — file.read data = {type:"text", content},
|
|
9
|
+
* find.text data = Match[]. Absent `ok` is NOT a failure; `data`
|
|
10
|
+
* presence decides success.
|
|
11
|
+
* - T0.4 legacy: `{ ok: true, data }` (what the fake clients in tests emit).
|
|
12
|
+
* RequestResult hygiene: ok === true can STILL carry the error envelope
|
|
13
|
+
* {error: {name, data: {message, ref}}} — self-check `data.error`. A
|
|
14
|
+
* top-level error / ok===false fails even when a data payload rides along.
|
|
15
|
+
*/
|
|
16
|
+
export function unwrapClientResult(res) {
|
|
17
|
+
if (!res || typeof res !== "object") {
|
|
18
|
+
return { ok: false, message: "客户端返回为空或格式异常" };
|
|
19
|
+
}
|
|
20
|
+
const r = res;
|
|
21
|
+
if (r.ok === false || r.error != null) {
|
|
22
|
+
const e = r.error;
|
|
23
|
+
const msg = e?.message ?? e?.data?.message ?? e?.name;
|
|
24
|
+
return { ok: false, message: msg ? String(msg) : `客户端返回 ok=${String(r.ok)}` };
|
|
25
|
+
}
|
|
26
|
+
if ("data" in r) {
|
|
27
|
+
const data = r.data;
|
|
28
|
+
if (data && typeof data === "object") {
|
|
29
|
+
const errVal = data.error;
|
|
30
|
+
if (errVal != null) {
|
|
31
|
+
if (typeof errVal === "string")
|
|
32
|
+
return { ok: false, message: errVal };
|
|
33
|
+
const envelope = errVal;
|
|
34
|
+
const msg = envelope?.data?.message ?? envelope?.name ?? "unknown client error envelope";
|
|
35
|
+
return { ok: false, message: String(msg) };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return { ok: true, data };
|
|
39
|
+
}
|
|
40
|
+
if (r.ok === true)
|
|
41
|
+
return { ok: true, data: undefined };
|
|
42
|
+
return { ok: false, message: "客户端返回格式异常(缺少 data 字段)" };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* One client.find.text match object -> ripgrep-style `path:line: text` lines.
|
|
46
|
+
* Key table (live-probed shape; tester re-verifies each key against real
|
|
47
|
+
* host data):
|
|
48
|
+
* path — file path of the hit (aliases: file, file_path, filePath)
|
|
49
|
+
* lines — matched lines, string[] (aliases: text, content, match, line_text,
|
|
50
|
+
* line-as-string)
|
|
51
|
+
* line — 1-based line number (aliases: line_number, lineNumber; must be
|
|
52
|
+
* numeric — a textual `line` value falls through to the text keys)
|
|
53
|
+
* Returns null when neither a path nor any hit text is found.
|
|
54
|
+
*/
|
|
55
|
+
export function matchObjectText(m) {
|
|
56
|
+
const p = [m.path, m.file, m.file_path, m.filePath].find((v) => typeof v === "string" && v.length > 0);
|
|
57
|
+
let texts = [];
|
|
58
|
+
for (const key of ["lines", "text", "content", "match", "line_text", "line"]) {
|
|
59
|
+
const v = m[key];
|
|
60
|
+
if (Array.isArray(v)) {
|
|
61
|
+
texts = v.filter((x) => typeof x === "string");
|
|
62
|
+
if (texts.length > 0)
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
else if (typeof v === "string" && v.length > 0) {
|
|
66
|
+
texts = [v];
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const numKeys = ["line_number", "lineNumber", "line"]
|
|
71
|
+
.map((k) => Number(m[k]))
|
|
72
|
+
.find((n) => Number.isInteger(n) && Number.isFinite(n));
|
|
73
|
+
if (!p && texts.length === 0)
|
|
74
|
+
return null;
|
|
75
|
+
const prefix = p ? (typeof numKeys === "number" ? `${p}:${numKeys}` : p) : "";
|
|
76
|
+
if (texts.length === 0)
|
|
77
|
+
return prefix;
|
|
78
|
+
return texts.map((t) => (prefix ? `${prefix}: ${t}` : t)).join("\n");
|
|
79
|
+
}
|
|
80
|
+
/** Best-effort text extraction from verified client payloads. */
|
|
81
|
+
export function extractText(data) {
|
|
82
|
+
if (typeof data === "string")
|
|
83
|
+
return data;
|
|
84
|
+
if (data == null)
|
|
85
|
+
return "";
|
|
86
|
+
if (Array.isArray(data)) {
|
|
87
|
+
// find.text real-host shape: an array of match objects. Render each as
|
|
88
|
+
// `path:line: text` so path/line/hit structure survives into previews
|
|
89
|
+
// (the log branch lifts file:line retrieval clues) and aggregation.
|
|
90
|
+
if (data.length > 0 && data.every((x) => x !== null && typeof x === "object" && !Array.isArray(x))) {
|
|
91
|
+
const rendered = data.map((x) => matchObjectText(x));
|
|
92
|
+
if (rendered.some((s) => s !== null)) {
|
|
93
|
+
return rendered.filter((s) => s !== null).join("\n");
|
|
94
|
+
}
|
|
95
|
+
// Key-table mismatch — fall back to JSON so nothing is silently dropped.
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
return data.map((x) => (typeof x === "string" ? x : JSON.stringify(x))).join("\n");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const o = data;
|
|
102
|
+
for (const key of ["content", "text", "output", "stdout"]) {
|
|
103
|
+
if (typeof o[key] === "string")
|
|
104
|
+
return o[key];
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
return JSON.stringify(data, null, 2);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return String(data);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=client-unwrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-unwrap.js","sourceRoot":"","sources":["../../src/tm/client-unwrap.ts"],"names":[],"mappings":"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"}
|