@pasko70/pibo 1.14.0 → 1.15.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/dist/apps/chat-ui/assets/{dist-DmqwP_tM.js → dist-BFwSuVfD.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-ur4yXrlj.js → dist-BYTi90un.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-hoDORUlL.js → dist-Bi74WdBU.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BIwXuAMQ.js → dist-CYMM1_bS.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BG1J2hGI.js → dist-CuIwfDgF.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-LWXXqiGT.js → dist-DS1ScAMf.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-1eQpSfYj.js → dist-DUgrMhHX.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CtsdsIpj.js → dist-Dq3i1LVZ.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DfdQQObC.js → dist-Dy5L1xOD.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BeCHnL7P.js → dist-Zy3KnDp7.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BZO4zpMi.js +237 -0
- package/dist/apps/chat-ui/index.html +1 -1
- package/dist/apps/chat-vscode-web/assets/{index-R_7kgvvD.js → index-V_pKPVAm.js} +3 -3
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/{pibo-vscode-ext-1.14.0.vsix → pibo-vscode-ext-1.15.0.vsix} +0 -0
- package/dist/core/runtime.js +27 -5
- package/dist/plugins/builtin.js +7 -0
- package/dist/session-ui/terminalRows.js +12 -2
- package/dist/tools/browser-use-leases.js +16 -0
- package/dist/tools/codex-browser-node-repl.js +224 -0
- package/dist/tools/codex-browser-node-worker-source.js +403 -0
- package/dist/tools/codex-browser.js +461 -0
- package/package.json +3 -1
- package/dist/apps/chat-ui/assets/index-DLNTzhdh.js +0 -237
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="theme-color" content="#101d22" />
|
|
7
7
|
<title>Pibo</title>
|
|
8
|
-
<script type="module" crossorigin src="/apps/chat-vscode/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/apps/chat-vscode/assets/index-V_pKPVAm.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/apps/chat-vscode/assets/index-Dupu1DzQ.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
Binary file
|
package/dist/apps/vscode-artifacts/{pibo-vscode-ext-1.14.0.vsix → pibo-vscode-ext-1.15.0.vsix}
RENAMED
|
Binary file
|
package/dist/core/runtime.js
CHANGED
|
@@ -25,6 +25,7 @@ import { registerOpenAiGpt56Models } from "../providers/openai-gpt56.js";
|
|
|
25
25
|
import { PIBO_APP_CONTEXT } from "../app-context.js";
|
|
26
26
|
import { createRuntimeToolDefinition } from "../tools/runtime/tool.js";
|
|
27
27
|
import { RuntimeSessionRegistry } from "../tools/runtime/registry.js";
|
|
28
|
+
import { CODEX_BROWSER_TOOL_NAMES, CodexBrowserSessionController, createCodexBrowserToolDefinitions, } from "../tools/codex-browser.js";
|
|
28
29
|
import { compactValidationToolResultForContext } from "./test-output-compaction.js";
|
|
29
30
|
import { installPiboTranscriptIntegrity } from "./transcript-integrity.js";
|
|
30
31
|
function hasOwnRetrySetting(settings, key) {
|
|
@@ -102,12 +103,18 @@ function getEnabledSkillPaths(cwd, profile) {
|
|
|
102
103
|
.filter((skill) => skill.enabled !== false)
|
|
103
104
|
.map((skill) => resolveProfilePath(cwd, skill.path));
|
|
104
105
|
}
|
|
105
|
-
function getEnabledToolDefinitions(profile, options, subagentRunner, runToolController, runtimeToolController) {
|
|
106
|
+
function getEnabledToolDefinitions(profile, options, subagentRunner, runToolController, runtimeToolController, codexBrowserController) {
|
|
106
107
|
const runtimeProfileTool = profile.tools.find(isEnabledRuntimeTool);
|
|
107
108
|
const runtimeTool = runtimeProfileTool && runtimeToolController
|
|
108
109
|
? createRuntimeToolDefinition(runtimeToolController)
|
|
109
110
|
: undefined;
|
|
110
|
-
const
|
|
111
|
+
const selectedCodexBrowserToolNames = profile.tools
|
|
112
|
+
.filter(isEnabledCodexBrowserTool)
|
|
113
|
+
.map((tool) => tool.name);
|
|
114
|
+
const codexBrowserTools = codexBrowserController
|
|
115
|
+
? createCodexBrowserToolDefinitions(codexBrowserController, selectedCodexBrowserToolNames)
|
|
116
|
+
: [];
|
|
117
|
+
const profileTools = profile.tools.filter((tool) => !isRuntimeTool(tool) && !isCodexBrowserTool(tool)).filter(hasEnabledToolDefinition);
|
|
111
118
|
const profileToolDefinitions = profileTools.map((tool) => getToolDefinition(tool, options.toolContext));
|
|
112
119
|
const codexCompatEnabled = profile.toolPackages.codexCompat === true;
|
|
113
120
|
const runControlEnabled = profile.toolPackages.runControl === true;
|
|
@@ -129,6 +136,7 @@ function getEnabledToolDefinitions(profile, options, subagentRunner, runToolCont
|
|
|
129
136
|
...(runControlBashTool ? [runControlBashTool] : []),
|
|
130
137
|
...profileTools.filter((tool) => tool.yieldable !== false).map((tool) => getToolDefinition(tool, options.toolContext)),
|
|
131
138
|
...(runtimeTool && runtimeProfileTool?.yieldable !== false ? [runtimeTool] : []),
|
|
139
|
+
...codexBrowserTools.filter((definition) => profile.tools.find((tool) => tool.name === definition.name)?.yieldable !== false),
|
|
132
140
|
...subagentTools,
|
|
133
141
|
...codexCompatTools,
|
|
134
142
|
];
|
|
@@ -139,6 +147,7 @@ function getEnabledToolDefinitions(profile, options, subagentRunner, runToolCont
|
|
|
139
147
|
...(runControlBashTool ? [runControlBashTool] : []),
|
|
140
148
|
...profileToolDefinitions,
|
|
141
149
|
...(runtimeTool ? [runtimeTool] : []),
|
|
150
|
+
...codexBrowserTools,
|
|
142
151
|
...subagentTools,
|
|
143
152
|
...codexCompatTools,
|
|
144
153
|
...goalTools,
|
|
@@ -159,6 +168,12 @@ function isRuntimeTool(tool) {
|
|
|
159
168
|
function isEnabledRuntimeTool(tool) {
|
|
160
169
|
return tool.enabled !== false && isRuntimeTool(tool);
|
|
161
170
|
}
|
|
171
|
+
function isCodexBrowserTool(tool) {
|
|
172
|
+
return tool.builtInPiboTool === "codex_browser" || CODEX_BROWSER_TOOL_NAMES.includes(tool.name);
|
|
173
|
+
}
|
|
174
|
+
function isEnabledCodexBrowserTool(tool) {
|
|
175
|
+
return tool.enabled !== false && isCodexBrowserTool(tool);
|
|
176
|
+
}
|
|
162
177
|
function isGeneratedPiboTool(name) {
|
|
163
178
|
return name === "runtime" || name.startsWith("pibo_subagent_") || name.startsWith("pibo_run_") || PIBO_GOAL_TOOL_NAMES.includes(name);
|
|
164
179
|
}
|
|
@@ -280,6 +295,12 @@ export async function createPiboRuntime(options = {}) {
|
|
|
280
295
|
const localRuntimeRegistry = ownsLocalRuntimeRegistry ? new RuntimeSessionRegistry({ cwd: runtimeCwd }) : undefined;
|
|
281
296
|
const runtimeToolController = options.runtimeToolController
|
|
282
297
|
?? localRuntimeRegistry?.createController(profile.sessionId ?? "local");
|
|
298
|
+
const codexBrowserController = profile.tools.some(isEnabledCodexBrowserTool)
|
|
299
|
+
? new CodexBrowserSessionController({
|
|
300
|
+
cwd: runtimeCwd,
|
|
301
|
+
piboSessionId: options.sessionContext?.piboSessionId ?? profile.sessionId ?? runtimeSessionManager.getSessionId(),
|
|
302
|
+
})
|
|
303
|
+
: undefined;
|
|
283
304
|
const customTools = getEnabledToolDefinitions(profile, {
|
|
284
305
|
runtimeCwd,
|
|
285
306
|
shellCommandPrefix: services.settingsManager.getShellCommandPrefix(),
|
|
@@ -290,7 +311,7 @@ export async function createPiboRuntime(options = {}) {
|
|
|
290
311
|
profileName: profile.profileName,
|
|
291
312
|
getActiveMessage: options.sessionContext?.getActiveMessage,
|
|
292
313
|
},
|
|
293
|
-
}, options.subagentRunner, options.runToolController, runtimeToolController);
|
|
314
|
+
}, options.subagentRunner, options.runToolController, runtimeToolController, codexBrowserController);
|
|
294
315
|
const modelDefaults = options.modelDefaults ?? loadPiboModelDefaults(runtimeCwd);
|
|
295
316
|
const created = await createAgentSessionFromServices({
|
|
296
317
|
services,
|
|
@@ -324,6 +345,7 @@ export async function createPiboRuntime(options = {}) {
|
|
|
324
345
|
if (localRuntimeRegistry) {
|
|
325
346
|
void localRuntimeRegistry.closeControllerSessions(profile.sessionId ?? "local", { force: true });
|
|
326
347
|
}
|
|
348
|
+
void codexBrowserController?.dispose();
|
|
327
349
|
originalDispose();
|
|
328
350
|
};
|
|
329
351
|
return {
|
|
@@ -444,8 +466,8 @@ export async function inspectPiboProfile(options = {}) {
|
|
|
444
466
|
})),
|
|
445
467
|
tools: profile.tools.map((tool) => ({
|
|
446
468
|
name: tool.name,
|
|
447
|
-
hasDefinition: Boolean(tool.definition) || Boolean(tool.createDefinition) || isRuntimeTool(tool),
|
|
448
|
-
registered: registeredToolNames.has(tool.name) || tool.providerTool !== undefined || isRuntimeTool(tool),
|
|
469
|
+
hasDefinition: Boolean(tool.definition) || Boolean(tool.createDefinition) || isRuntimeTool(tool) || isCodexBrowserTool(tool),
|
|
470
|
+
registered: registeredToolNames.has(tool.name) || tool.providerTool !== undefined || isRuntimeTool(tool) || isCodexBrowserTool(tool),
|
|
449
471
|
active: activeToolNames.has(tool.name) || tool.providerTool !== undefined,
|
|
450
472
|
})).concat(generatedTools),
|
|
451
473
|
subagents: profile.subagents.map((subagent) => {
|
package/dist/plugins/builtin.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createPiboGatewayToolProfiles } from "../gateway/tool.js";
|
|
|
4
4
|
import { InitialSessionContextBuilder } from "../core/profiles.js";
|
|
5
5
|
import { parsePiboThinkingLevel } from "../core/thinking.js";
|
|
6
6
|
import { createWebSearchToolProfile } from "../tools/web-search.js";
|
|
7
|
+
import { CODEX_BROWSER_TOOL_NAMES, createCodexBrowserToolProfiles } from "../tools/codex-browser.js";
|
|
7
8
|
import { createRuntimeToolProfile } from "../tools/runtime/tool.js";
|
|
8
9
|
import { completeLogin, getLoginStatus, removeLogin, setApiKey, startLogin } from "../auth/login-actions.js";
|
|
9
10
|
import { loadModelCatalog } from "../apps/chat/model-catalog.js";
|
|
@@ -166,6 +167,12 @@ export const piboCorePlugin = definePiboPlugin({
|
|
|
166
167
|
});
|
|
167
168
|
api.registerTool(createWebSearchToolProfile());
|
|
168
169
|
api.registerTool(createRuntimeToolProfile());
|
|
170
|
+
api.registerTools(createCodexBrowserToolProfiles());
|
|
171
|
+
api.registerCapabilityPackage({
|
|
172
|
+
name: "codex-browser-interface",
|
|
173
|
+
description: "Expose Browser Use and its persistent browser-bound Node REPL through a Codex-familiar structured tool surface.",
|
|
174
|
+
toolNames: [...CODEX_BROWSER_TOOL_NAMES],
|
|
175
|
+
});
|
|
169
176
|
registerPiboNativeTooling(api);
|
|
170
177
|
api.registerProfile({
|
|
171
178
|
name: DEFAULT_PIBO_PROFILE_NAME,
|
|
@@ -2,6 +2,13 @@ import { compareTraceNodes } from "../shared/trace-engine.js";
|
|
|
2
2
|
import { terminalTextValue } from "./terminalValue.js";
|
|
3
3
|
export const COMPACT_TERMINAL_OUTPUT_PREVIEW_LINES = 5;
|
|
4
4
|
export const COMPACT_TERMINAL_EXPLORING_PREVIEW_LINES = 6;
|
|
5
|
+
const CODEX_COMPATIBLE_TOOL_LABELS = {
|
|
6
|
+
browser_use_open_tabs: "browser_use.open_tabs",
|
|
7
|
+
browser_use_take_screenshot: "browser_use.take_screenshot",
|
|
8
|
+
browser_use_browser_use: "browser_use.browser_use",
|
|
9
|
+
node_repl_js: "node_repl.js",
|
|
10
|
+
node_repl_js_reset: "node_repl.js_reset",
|
|
11
|
+
};
|
|
5
12
|
export function buildCompactTerminalRows(traceView, options) {
|
|
6
13
|
if (!traceView)
|
|
7
14
|
return [];
|
|
@@ -270,7 +277,7 @@ function createToolRowCandidate(node, turnId) {
|
|
|
270
277
|
token(toolVerb(node.status), toneForStatus(node.status), "semibold"),
|
|
271
278
|
token(" "),
|
|
272
279
|
],
|
|
273
|
-
functionCall: { name: node.title, input: node.input },
|
|
280
|
+
functionCall: { name: displayToolName(node.title), input: node.input },
|
|
274
281
|
},
|
|
275
282
|
...preview.lines,
|
|
276
283
|
],
|
|
@@ -359,7 +366,7 @@ function createToolResultRow(node) {
|
|
|
359
366
|
lines: [
|
|
360
367
|
{
|
|
361
368
|
prefix: "bullet",
|
|
362
|
-
tokens: [token(node.status === "error" ? "Tool failed" : "Returned", toneForStatus(node.status), "semibold"), token(` ${node.title}`)],
|
|
369
|
+
tokens: [token(node.status === "error" ? "Tool failed" : "Returned", toneForStatus(node.status), "semibold"), token(` ${displayToolName(node.title)}`)],
|
|
363
370
|
},
|
|
364
371
|
...preview.lines,
|
|
365
372
|
],
|
|
@@ -1030,6 +1037,9 @@ function classifyExploringTool(node) {
|
|
|
1030
1037
|
}
|
|
1031
1038
|
return undefined;
|
|
1032
1039
|
}
|
|
1040
|
+
function displayToolName(name) {
|
|
1041
|
+
return CODEX_COMPATIBLE_TOOL_LABELS[name] ?? name;
|
|
1042
|
+
}
|
|
1033
1043
|
function matchesTool(name, terms) {
|
|
1034
1044
|
return terms.some((term) => name === term || name.startsWith(`${term}_`) || name.endsWith(`_${term}`) || name.includes(term));
|
|
1035
1045
|
}
|
|
@@ -73,6 +73,22 @@ function defaultTemplateDir(status) {
|
|
|
73
73
|
// Create an empty template directory so leases get clean profiles.
|
|
74
74
|
return preferred;
|
|
75
75
|
}
|
|
76
|
+
export function findActiveBrowserUseLeaseForHolder(status, holder, app, now = new Date()) {
|
|
77
|
+
return readRegistry(status).leases.find((lease) => lease.holder === holder &&
|
|
78
|
+
lease.status === 'active' &&
|
|
79
|
+
!isExpired(lease, now) &&
|
|
80
|
+
(app === undefined || lease.app === app));
|
|
81
|
+
}
|
|
82
|
+
export function browserUseLeaseEnvironment(status, lease) {
|
|
83
|
+
return {
|
|
84
|
+
BROWSER_USE_HOME: browserUseHome(status),
|
|
85
|
+
PIBO_BROWSER_USE_LEASE_ID: lease.id,
|
|
86
|
+
PIBO_BROWSER_USE_SESSION: lease.sessionName,
|
|
87
|
+
PIBO_BROWSER_USE_CHROME_USER_DATA_DIR: lease.userDataDir,
|
|
88
|
+
PIBO_BROWSER_USE_DEFAULT_PROFILE: lease.profileName,
|
|
89
|
+
...(lease.browserPoolLeaseId ? { PIBO_BROWSER_POOL_LEASE_ID: lease.browserPoolLeaseId } : {}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
76
92
|
export function readRegistry(status) {
|
|
77
93
|
const path = registryPath(status);
|
|
78
94
|
if (!existsSync(path))
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { createInterface } from "node:readline";
|
|
4
|
+
import { CODEX_BROWSER_NODE_WORKER_SOURCE } from "./codex-browser-node-worker-source.js";
|
|
5
|
+
const packageRequire = createRequire(import.meta.url);
|
|
6
|
+
const ACORN_PATH = packageRequire.resolve("acorn");
|
|
7
|
+
const ACORN_WALK_PATH = packageRequire.resolve("acorn-walk");
|
|
8
|
+
function errorSummary(error, name = "NodeReplError") {
|
|
9
|
+
return error instanceof Error
|
|
10
|
+
? { name: error.name || name, message: error.message, stack: error.stack }
|
|
11
|
+
: { name, message: String(error) };
|
|
12
|
+
}
|
|
13
|
+
export class CodexBrowserNodeRepl {
|
|
14
|
+
bridge;
|
|
15
|
+
child;
|
|
16
|
+
pending = new Map();
|
|
17
|
+
requestCounter = 0;
|
|
18
|
+
executionCount = 0;
|
|
19
|
+
alive = true;
|
|
20
|
+
busy = false;
|
|
21
|
+
diagnostics = "";
|
|
22
|
+
readyPromise;
|
|
23
|
+
readyResolve;
|
|
24
|
+
readyReject;
|
|
25
|
+
constructor(bridge, cwd) {
|
|
26
|
+
this.bridge = bridge;
|
|
27
|
+
this.readyPromise = new Promise((resolve, reject) => {
|
|
28
|
+
this.readyResolve = resolve;
|
|
29
|
+
this.readyReject = reject;
|
|
30
|
+
});
|
|
31
|
+
this.child = spawn("node", ["-e", CODEX_BROWSER_NODE_WORKER_SOURCE, ACORN_PATH, ACORN_WALK_PATH], {
|
|
32
|
+
cwd,
|
|
33
|
+
env: minimalWorkerEnvironment(),
|
|
34
|
+
stdio: "pipe",
|
|
35
|
+
});
|
|
36
|
+
const stdout = createInterface({ input: this.child.stdout });
|
|
37
|
+
stdout.on("line", (line) => this.handleLine(line));
|
|
38
|
+
this.child.stderr.on("data", (chunk) => {
|
|
39
|
+
this.diagnostics += String(chunk);
|
|
40
|
+
});
|
|
41
|
+
this.child.once("error", (error) => {
|
|
42
|
+
this.alive = false;
|
|
43
|
+
this.readyReject(error);
|
|
44
|
+
this.rejectAll(error);
|
|
45
|
+
});
|
|
46
|
+
this.child.once("close", (code, signal) => {
|
|
47
|
+
this.alive = false;
|
|
48
|
+
const error = new Error(`node_repl worker exited with code ${code ?? "null"}${signal ? ` signal ${signal}` : ""}`);
|
|
49
|
+
this.readyReject(error);
|
|
50
|
+
this.rejectAll(error);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
static async start(bridge, cwd, timeoutMs = 10_000) {
|
|
54
|
+
const repl = new CodexBrowserNodeRepl(bridge, cwd);
|
|
55
|
+
await repl.waitReady(timeoutMs);
|
|
56
|
+
return repl;
|
|
57
|
+
}
|
|
58
|
+
isAlive() {
|
|
59
|
+
return this.alive && !this.child.killed;
|
|
60
|
+
}
|
|
61
|
+
async exec(code, timeoutMs = 30_000) {
|
|
62
|
+
const startedAt = Date.now();
|
|
63
|
+
if (this.busy) {
|
|
64
|
+
return {
|
|
65
|
+
status: "failed",
|
|
66
|
+
stdout: "",
|
|
67
|
+
stderr: "",
|
|
68
|
+
durationMs: 0,
|
|
69
|
+
executionCount: this.executionCount,
|
|
70
|
+
error: { name: "NodeReplBusy", message: "node_repl.js is already executing code." },
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
this.busy = true;
|
|
74
|
+
try {
|
|
75
|
+
const response = await this.request("exec", { code, timeoutMs }, timeoutMs + 1_000);
|
|
76
|
+
this.executionCount += 1;
|
|
77
|
+
return {
|
|
78
|
+
status: response.status === "ok" ? "ok" : "error",
|
|
79
|
+
stdout: response.stdout ?? "",
|
|
80
|
+
stderr: response.stderr ?? "",
|
|
81
|
+
result: response.result,
|
|
82
|
+
error: response.error,
|
|
83
|
+
durationMs: Date.now() - startedAt,
|
|
84
|
+
executionCount: this.executionCount,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
status: error instanceof NodeReplTimeoutError ? "timeout" : "failed",
|
|
90
|
+
stdout: "",
|
|
91
|
+
stderr: this.diagnostics,
|
|
92
|
+
durationMs: Date.now() - startedAt,
|
|
93
|
+
executionCount: this.executionCount,
|
|
94
|
+
error: errorSummary(error),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
this.busy = false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async reset(timeoutMs = 10_000) {
|
|
102
|
+
if (this.busy) {
|
|
103
|
+
return {
|
|
104
|
+
status: "failed",
|
|
105
|
+
reset: false,
|
|
106
|
+
error: { name: "NodeReplBusy", message: "node_repl.js cannot reset while code is executing." },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const response = await this.request("reset", {}, timeoutMs);
|
|
111
|
+
this.executionCount = 0;
|
|
112
|
+
return { status: response.status === "ok" ? "ok" : "failed", reset: response.reset === true, error: response.error };
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
return { status: "failed", reset: false, error: errorSummary(error) };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
dispose() {
|
|
119
|
+
if (!this.isAlive())
|
|
120
|
+
return;
|
|
121
|
+
this.alive = false;
|
|
122
|
+
this.child.kill("SIGTERM");
|
|
123
|
+
this.rejectAll(new Error("node_repl worker was disposed"));
|
|
124
|
+
}
|
|
125
|
+
waitReady(timeoutMs) {
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
const timer = setTimeout(() => reject(new Error(`Timed out waiting for node_repl worker. ${this.diagnostics}`)), timeoutMs);
|
|
128
|
+
this.readyPromise.then(() => {
|
|
129
|
+
clearTimeout(timer);
|
|
130
|
+
resolve();
|
|
131
|
+
}, (error) => {
|
|
132
|
+
clearTimeout(timer);
|
|
133
|
+
reject(error);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
request(type, payload, timeoutMs) {
|
|
138
|
+
if (!this.isAlive())
|
|
139
|
+
return Promise.reject(new Error("node_repl worker is not alive"));
|
|
140
|
+
const id = `request_${++this.requestCounter}`;
|
|
141
|
+
return new Promise((resolve, reject) => {
|
|
142
|
+
const timer = setTimeout(() => {
|
|
143
|
+
this.pending.delete(id);
|
|
144
|
+
reject(new NodeReplTimeoutError(`node_repl request ${type} timed out after ${timeoutMs}ms`));
|
|
145
|
+
}, timeoutMs);
|
|
146
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
147
|
+
this.write({ type, id, ...payload });
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
handleLine(line) {
|
|
151
|
+
let message;
|
|
152
|
+
try {
|
|
153
|
+
message = JSON.parse(line);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
this.alive = false;
|
|
157
|
+
this.rejectAll(new Error(`Invalid node_repl worker protocol line: ${line}`));
|
|
158
|
+
this.child.kill("SIGTERM");
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (message.type === "ready" && message.status === "ready") {
|
|
162
|
+
this.readyResolve();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (message.type === "browser_request") {
|
|
166
|
+
void this.handleBrowserRequest(message);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const id = message.id;
|
|
170
|
+
if (!id)
|
|
171
|
+
return;
|
|
172
|
+
const pending = this.pending.get(id);
|
|
173
|
+
if (!pending)
|
|
174
|
+
return;
|
|
175
|
+
this.pending.delete(id);
|
|
176
|
+
clearTimeout(pending.timer);
|
|
177
|
+
pending.resolve(message);
|
|
178
|
+
}
|
|
179
|
+
async handleBrowserRequest(message) {
|
|
180
|
+
if (!message.id)
|
|
181
|
+
return;
|
|
182
|
+
try {
|
|
183
|
+
let result;
|
|
184
|
+
if (message.operation === "open_tabs") {
|
|
185
|
+
result = await this.bridge.openTabs();
|
|
186
|
+
}
|
|
187
|
+
else if (message.operation === "use") {
|
|
188
|
+
if (!message.input || typeof message.input !== "object" || Array.isArray(message.input)) {
|
|
189
|
+
throw new Error("browser.use requires an action object");
|
|
190
|
+
}
|
|
191
|
+
result = await this.bridge.use(message.input);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
throw new Error(`Unknown browser bridge operation ${message.operation ?? ""}`);
|
|
195
|
+
}
|
|
196
|
+
this.write({ type: "browser_response", id: message.id, result });
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
this.write({ type: "browser_response", id: message.id, error: errorSummary(error, "BrowserUseError") });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
write(message) {
|
|
203
|
+
if (!this.isAlive())
|
|
204
|
+
return;
|
|
205
|
+
this.child.stdin.write(`${JSON.stringify(message)}\n`);
|
|
206
|
+
}
|
|
207
|
+
rejectAll(error) {
|
|
208
|
+
for (const [id, pending] of this.pending) {
|
|
209
|
+
this.pending.delete(id);
|
|
210
|
+
clearTimeout(pending.timer);
|
|
211
|
+
pending.reject(error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function minimalWorkerEnvironment() {
|
|
216
|
+
const env = {};
|
|
217
|
+
for (const name of ["PATH", "HOME", "TMPDIR", "TEMP", "TMP", "LANG", "LC_ALL", "TZ"]) {
|
|
218
|
+
if (process.env[name] !== undefined)
|
|
219
|
+
env[name] = process.env[name];
|
|
220
|
+
}
|
|
221
|
+
return env;
|
|
222
|
+
}
|
|
223
|
+
class NodeReplTimeoutError extends Error {
|
|
224
|
+
}
|