@cydm/pie 1.0.51 → 2.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/README.md +36 -16
- package/dist/builtin/extensions/ask-user/index.js +4 -3
- package/dist/builtin/extensions/ask-user/package.json +8 -7
- package/dist/builtin/extensions/changelog/package.json +9 -9
- package/dist/builtin/extensions/computer-use/index.js +9352 -0
- package/dist/builtin/extensions/computer-use/package.json +11 -0
- package/dist/builtin/extensions/computer-use/prebuilt/linux/arm64/linux-bridge +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/linux/x64/linux-bridge +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/arm64/pie-computer-use +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +24 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +115 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/x64/pie-computer-use +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/windows/windows-bridge.exe +0 -0
- package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +277 -0
- package/dist/builtin/extensions/computer-use/scripts/helper-path.mjs +48 -0
- package/dist/builtin/extensions/computer-use/scripts/setup-helper.mjs +549 -0
- package/dist/builtin/extensions/document-attachments/package.json +9 -9
- package/dist/builtin/extensions/init/package.json +9 -9
- package/dist/builtin/extensions/mcp-adapter/index.js +25250 -0
- package/dist/builtin/extensions/mcp-adapter/package.json +11 -0
- package/dist/builtin/extensions/plan-mode/index.js +4 -3
- package/dist/builtin/extensions/plan-mode/package.json +9 -9
- package/dist/builtin/extensions/subagent/index.js +6 -4
- package/dist/builtin/extensions/subagent/package.json +16 -12
- package/dist/builtin/extensions/todo/index.js +4 -3
- package/dist/builtin/extensions/todo/package.json +9 -9
- package/dist/builtin/skills/chrome-devtools-axi/CHANGELOG.md +5 -0
- package/dist/builtin/skills/chrome-devtools-axi/LICENSE +21 -0
- package/dist/builtin/skills/chrome-devtools-axi/README.md +17 -0
- package/dist/builtin/skills/chrome-devtools-axi/SKILL.md +50 -0
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-bridge.js +20034 -0
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-cli.js +83 -0
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-runtime.js +26 -0
- package/dist/builtin/skills/chrome-devtools-axi/chunk-42SGITKJ.js +11 -0
- package/dist/builtin/skills/chrome-devtools-axi/chunk-OJ6N23UZ.js +47 -0
- package/dist/builtin/skills/chrome-devtools-axi/chunk-UPATXALW.js +215 -0
- package/dist/builtin/skills/chrome-devtools-axi/cli-F2VCSVL4.js +4424 -0
- package/dist/builtin/skills/chrome-devtools-axi/package.json +12 -0
- package/dist/builtin/skills/skill-creator/SKILL.md +5 -2
- package/dist/builtin/skills/skill-creator/eval-viewer/generate_review.mjs +7 -20
- package/dist/builtin/skills/skill-creator/eval-viewer/viewer.html +15 -15
- package/dist/builtin/skills/skill-creator/scripts/aggregate_benchmark.mjs +20 -19
- package/dist/builtin/skills/skill-creator/scripts/generate_report.mjs +3 -3
- package/dist/builtin/skills/skill-creator/scripts/improve_description.mjs +12 -8
- package/dist/builtin/skills/skill-creator/scripts/package_skill.mjs +1 -0
- package/dist/builtin/skills/skill-creator/scripts/pie_runner.mjs +77 -31
- package/dist/builtin/skills/skill-creator/scripts/run_eval.mjs +38 -11
- package/dist/builtin/skills/skill-creator/scripts/run_loop.mjs +12 -6
- package/dist/builtin/skills/skill-creator/scripts/skill_metadata.mjs +12 -1
- package/dist/builtin/skills/tui-use/LICENSE +21 -0
- package/dist/builtin/skills/tui-use/README.md +17 -0
- package/dist/builtin/skills/tui-use/SKILL.md +106 -0
- package/dist/builtin/skills/tui-use/tui-use-cli.cjs +10608 -0
- package/dist/builtin/skills/tui-use/tui-use-cli.js +39 -0
- package/dist/builtin/skills/tui-use/tui-use-daemon.cjs +7916 -0
- package/dist/chunks/chunk-5353DEEC.js +130 -0
- package/dist/chunks/{chunk-S2J3SZZX.js → chunk-IM43UYVV.js} +827 -3385
- package/dist/chunks/{chunk-A644H2XX.js → chunk-LU7RKALH.js} +241 -96
- package/dist/chunks/{chunk-B3SMW2XW.js → chunk-QJH6YN2W.js} +1 -1
- package/dist/chunks/{chunk-KDPAGHYY.js → chunk-TJ2F4FL5.js} +190 -207
- package/dist/chunks/chunk-XXGYUYXI.js +2718 -0
- package/dist/chunks/{src-UKCIAX6F.js → src-QSP2OPHU.js} +3 -2
- package/dist/chunks/{test-stream-NCBFPM2I.js → test-stream-CVGWFLSX.js} +2 -1
- package/dist/chunks/webapi-MBCKO7ZV.js +2481 -0
- package/dist/cli.js +7866 -369
- package/package.json +29 -20
- package/scripts/repair-node-pty.mjs +45 -0
- package/dist/builtin/skills/browser-tools/CHANGELOG.md +0 -5
- package/dist/builtin/skills/browser-tools/README.md +0 -17
- package/dist/builtin/skills/browser-tools/SKILL.md +0 -43
- package/dist/builtin/skills/browser-tools/package.json +0 -12
- package/dist/builtin/skills/browser-tools/playwright-cli.js +0 -45
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
getBuiltinDir,
|
|
4
|
+
getConfigDir
|
|
5
|
+
} from "./chunk-5353DEEC.js";
|
|
2
6
|
import {
|
|
3
7
|
classifyShellCommand,
|
|
4
8
|
createCodeIntelTool,
|
|
@@ -8,129 +12,16 @@ import {
|
|
|
8
12
|
createSharedWebSearchTool,
|
|
9
13
|
interpretShellExit,
|
|
10
14
|
requestInteraction
|
|
11
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-LU7RKALH.js";
|
|
12
16
|
import {
|
|
13
17
|
Type
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
|
|
16
|
-
// src/config.ts
|
|
17
|
-
import { existsSync, mkdirSync, readFileSync, renameSync } from "fs";
|
|
18
|
-
import { homedir } from "os";
|
|
19
|
-
import { dirname, join } from "path";
|
|
20
|
-
import { fileURLToPath } from "url";
|
|
21
|
-
var __filename = fileURLToPath(import.meta.url);
|
|
22
|
-
var __dirname = dirname(__filename);
|
|
23
|
-
var isBunRuntime = !!process.versions.bun;
|
|
24
|
-
function getPackageDir() {
|
|
25
|
-
const envDir = process.env.PIE_PACKAGE_DIR;
|
|
26
|
-
if (envDir) {
|
|
27
|
-
if (envDir === "~") return homedir();
|
|
28
|
-
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
|
|
29
|
-
return envDir;
|
|
30
|
-
}
|
|
31
|
-
let dir = __dirname;
|
|
32
|
-
while (dir !== dirname(dir)) {
|
|
33
|
-
if (existsSync(join(dir, "package.json"))) {
|
|
34
|
-
return dir;
|
|
35
|
-
}
|
|
36
|
-
dir = dirname(dir);
|
|
37
|
-
}
|
|
38
|
-
return __dirname;
|
|
39
|
-
}
|
|
40
|
-
function getThemesDir() {
|
|
41
|
-
const packageDir = getPackageDir();
|
|
42
|
-
const srcOrDist = existsSync(join(packageDir, "src")) ? "src" : "dist";
|
|
43
|
-
return join(packageDir, srcOrDist, "theme");
|
|
44
|
-
}
|
|
45
|
-
function getBuiltinDir() {
|
|
46
|
-
const packageDir = getPackageDir();
|
|
47
|
-
const distBuiltinDir = join(packageDir, "dist", "builtin");
|
|
48
|
-
if (existsSync(distBuiltinDir)) {
|
|
49
|
-
return distBuiltinDir;
|
|
50
|
-
}
|
|
51
|
-
return join(packageDir, "builtin");
|
|
52
|
-
}
|
|
53
|
-
function getPackageJsonPath() {
|
|
54
|
-
return join(getPackageDir(), "package.json");
|
|
55
|
-
}
|
|
56
|
-
var pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8"));
|
|
57
|
-
var CONFIG_DIR_NAME = ".pie";
|
|
58
|
-
var VERSION = pkg.version;
|
|
59
|
-
var ENV_AGENT_DIR = "PIE_CODING_AGENT_DIR";
|
|
60
|
-
function getConfigDir() {
|
|
61
|
-
const envDir = process.env[ENV_AGENT_DIR];
|
|
62
|
-
if (envDir) {
|
|
63
|
-
if (envDir === "~") return homedir();
|
|
64
|
-
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
|
|
65
|
-
return envDir;
|
|
66
|
-
}
|
|
67
|
-
return join(homedir(), CONFIG_DIR_NAME);
|
|
68
|
-
}
|
|
69
|
-
function getAgentDir() {
|
|
70
|
-
return getConfigDir();
|
|
71
|
-
}
|
|
72
|
-
function getCustomThemesDir() {
|
|
73
|
-
return join(getConfigDir(), "themes");
|
|
74
|
-
}
|
|
75
|
-
function getSettingsPath() {
|
|
76
|
-
return join(getConfigDir(), "settings.json");
|
|
77
|
-
}
|
|
78
|
-
function getProjectSettingsPath(cwd) {
|
|
79
|
-
return join(cwd, CONFIG_DIR_NAME, "settings.json");
|
|
80
|
-
}
|
|
81
|
-
function getSessionsDir() {
|
|
82
|
-
return join(getConfigDir(), "sessions");
|
|
83
|
-
}
|
|
84
|
-
function getLogsDir() {
|
|
85
|
-
return join(getConfigDir(), "logs");
|
|
86
|
-
}
|
|
87
|
-
function getRuntimeLogPath() {
|
|
88
|
-
return join(getLogsDir(), "pie-cli.log");
|
|
89
|
-
}
|
|
90
|
-
function migrateConfigFromAgentDir() {
|
|
91
|
-
const oldAgentDir = join(homedir(), CONFIG_DIR_NAME, "agent");
|
|
92
|
-
const newConfigDir = getConfigDir();
|
|
93
|
-
if (!existsSync(oldAgentDir)) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (!existsSync(newConfigDir)) {
|
|
97
|
-
mkdirSync(newConfigDir, { recursive: true });
|
|
98
|
-
}
|
|
99
|
-
const filesToMigrate = [
|
|
100
|
-
"keybindings.json",
|
|
101
|
-
"settings.json",
|
|
102
|
-
"pie-debug.log"
|
|
103
|
-
];
|
|
104
|
-
for (const file of filesToMigrate) {
|
|
105
|
-
const oldPath = join(oldAgentDir, file);
|
|
106
|
-
const newPath = file === "pie-debug.log" ? getRuntimeLogPath() : join(newConfigDir, file);
|
|
107
|
-
if (existsSync(oldPath) && !existsSync(newPath)) {
|
|
108
|
-
try {
|
|
109
|
-
if (file === "pie-debug.log") {
|
|
110
|
-
mkdirSync(getLogsDir(), { recursive: true });
|
|
111
|
-
}
|
|
112
|
-
renameSync(oldPath, newPath);
|
|
113
|
-
console.log(`[Config] Migrated ${file} to ${newPath}`);
|
|
114
|
-
} catch (e) {
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const oldThemesDir = join(oldAgentDir, "themes");
|
|
119
|
-
const newThemesDir = getCustomThemesDir();
|
|
120
|
-
if (existsSync(oldThemesDir) && !existsSync(newThemesDir)) {
|
|
121
|
-
try {
|
|
122
|
-
renameSync(oldThemesDir, newThemesDir);
|
|
123
|
-
console.log(`[Config] Migrated themes to ${newThemesDir}`);
|
|
124
|
-
} catch (e) {
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
18
|
+
} from "./chunk-XXGYUYXI.js";
|
|
128
19
|
|
|
129
20
|
// src/capabilities/bash/index.ts
|
|
130
21
|
import { spawn } from "child_process";
|
|
131
|
-
import { closeSync, createWriteStream, existsSync
|
|
22
|
+
import { closeSync, createWriteStream, existsSync, openSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
132
23
|
import { tmpdir } from "os";
|
|
133
|
-
import { join
|
|
24
|
+
import { join, resolve } from "path";
|
|
134
25
|
import { createHash, randomBytes } from "crypto";
|
|
135
26
|
|
|
136
27
|
// src/capabilities/bash/truncate.ts
|
|
@@ -273,6 +164,7 @@ var bashSchema = Type.Object({
|
|
|
273
164
|
});
|
|
274
165
|
var DEFAULT_TIMEOUT_SECONDS = 120;
|
|
275
166
|
var MAX_GENERIC_TIMEOUT_SECONDS = 120;
|
|
167
|
+
var OUTPUT_DRAIN_TIMEOUT_MS = 1e3;
|
|
276
168
|
function resolveTimeoutPolicy(requestedTimeout, commandClass) {
|
|
277
169
|
const requestedSeconds = requestedTimeout ?? DEFAULT_TIMEOUT_SECONDS;
|
|
278
170
|
if (requestedSeconds > MAX_GENERIC_TIMEOUT_SECONDS && commandClass !== "package_manager" && commandClass !== "test_or_build") {
|
|
@@ -302,12 +194,15 @@ function validateBashCommand(command) {
|
|
|
302
194
|
throw new Error("Invalid bash command. The command argument must be only a real shell command, not tool-call markup.");
|
|
303
195
|
}
|
|
304
196
|
}
|
|
305
|
-
function buildEffectiveCommand(command, options) {
|
|
197
|
+
function buildEffectiveCommand(command, options, shell) {
|
|
306
198
|
const prefix = options?.commandPrefix?.trim();
|
|
307
199
|
if (!prefix) {
|
|
308
200
|
return command;
|
|
309
201
|
}
|
|
310
202
|
validateBashCommand(prefix);
|
|
203
|
+
if (shell === "powershell") {
|
|
204
|
+
return `& { ${prefix} }; if (-not $?) { exit 1 }; ${command}`;
|
|
205
|
+
}
|
|
311
206
|
return `${prefix} && ${command}`;
|
|
312
207
|
}
|
|
313
208
|
function resolveShell(shell) {
|
|
@@ -318,7 +213,8 @@ function resolveShell(shell) {
|
|
|
318
213
|
}
|
|
319
214
|
function buildSpawnCommand(shell, command) {
|
|
320
215
|
if (shell === "powershell") {
|
|
321
|
-
|
|
216
|
+
const utf8Command = `[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding; $OutputEncoding = [Console]::OutputEncoding; ${command}`;
|
|
217
|
+
return { file: process.platform === "win32" ? "powershell.exe" : "pwsh", args: ["-NoProfile", "-NonInteractive", "-Command", utf8Command], shell: false };
|
|
322
218
|
}
|
|
323
219
|
if (shell === "cmd") {
|
|
324
220
|
return { file: "cmd.exe", args: ["/d", "/s", "/c", command], shell: false };
|
|
@@ -341,7 +237,7 @@ async function requestHighRiskConfirmation(request) {
|
|
|
341
237
|
return response.type === "confirm" && response.confirmed === true;
|
|
342
238
|
}
|
|
343
239
|
function validateWorkingDirectory(cwd) {
|
|
344
|
-
if (!
|
|
240
|
+
if (!existsSync(cwd)) {
|
|
345
241
|
throw new Error(`Invalid bash cwd: ${cwd} does not exist. Use the current workspace path or pass an existing directory in cwd.`);
|
|
346
242
|
}
|
|
347
243
|
let stat;
|
|
@@ -356,11 +252,11 @@ function validateWorkingDirectory(cwd) {
|
|
|
356
252
|
}
|
|
357
253
|
function normalizeWorkingDirectory(cwd, defaultCwd) {
|
|
358
254
|
const requestedCwd = typeof cwd === "string" && cwd.trim().length > 0 ? cwd.trim() : void 0;
|
|
359
|
-
return
|
|
255
|
+
return resolve(requestedCwd ?? defaultCwd ?? process.cwd());
|
|
360
256
|
}
|
|
361
257
|
function getTempFilePath() {
|
|
362
258
|
const id = randomBytes(8).toString("hex");
|
|
363
|
-
return
|
|
259
|
+
return join(tmpdir(), `pie-bash-${id}.log`);
|
|
364
260
|
}
|
|
365
261
|
var retainedOutputArtifacts = /* @__PURE__ */ new Set();
|
|
366
262
|
function getErrorCode(error) {
|
|
@@ -370,15 +266,15 @@ function getErrorCode(error) {
|
|
|
370
266
|
}
|
|
371
267
|
function createPrivateOutputArtifact() {
|
|
372
268
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
373
|
-
const
|
|
269
|
+
const path4 = getTempFilePath();
|
|
374
270
|
try {
|
|
375
|
-
const fd = openSync(
|
|
376
|
-
retainedOutputArtifacts.add(
|
|
271
|
+
const fd = openSync(path4, "wx", 384);
|
|
272
|
+
retainedOutputArtifacts.add(path4);
|
|
377
273
|
try {
|
|
378
|
-
return { path:
|
|
274
|
+
return { path: path4, stream: createWriteStream(path4, { fd, autoClose: true }) };
|
|
379
275
|
} catch (error) {
|
|
380
276
|
closeSync(fd);
|
|
381
|
-
removeOutputArtifact(
|
|
277
|
+
removeOutputArtifact(path4);
|
|
382
278
|
throw error;
|
|
383
279
|
}
|
|
384
280
|
} catch (error) {
|
|
@@ -387,34 +283,34 @@ function createPrivateOutputArtifact() {
|
|
|
387
283
|
}
|
|
388
284
|
throw new Error("Unable to allocate a private bash output artifact.");
|
|
389
285
|
}
|
|
390
|
-
function removeOutputArtifact(
|
|
391
|
-
if (!
|
|
286
|
+
function removeOutputArtifact(path4) {
|
|
287
|
+
if (!path4) return;
|
|
392
288
|
try {
|
|
393
|
-
unlinkSync(
|
|
289
|
+
unlinkSync(path4);
|
|
394
290
|
} catch (error) {
|
|
395
291
|
if (getErrorCode(error) !== "ENOENT") throw error;
|
|
396
292
|
}
|
|
397
|
-
retainedOutputArtifacts.delete(
|
|
293
|
+
retainedOutputArtifacts.delete(path4);
|
|
398
294
|
}
|
|
399
|
-
function discardOutputArtifact(
|
|
295
|
+
function discardOutputArtifact(path4, stream) {
|
|
400
296
|
if (stream && !stream.closed) {
|
|
401
297
|
stream.once("close", () => {
|
|
402
298
|
try {
|
|
403
|
-
removeOutputArtifact(
|
|
299
|
+
removeOutputArtifact(path4);
|
|
404
300
|
} catch {
|
|
405
301
|
}
|
|
406
302
|
});
|
|
407
303
|
stream.destroy();
|
|
408
304
|
}
|
|
409
305
|
try {
|
|
410
|
-
removeOutputArtifact(
|
|
306
|
+
removeOutputArtifact(path4);
|
|
411
307
|
} catch {
|
|
412
308
|
}
|
|
413
309
|
}
|
|
414
310
|
function cleanupBashOutputArtifacts() {
|
|
415
|
-
for (const
|
|
311
|
+
for (const path4 of [...retainedOutputArtifacts]) {
|
|
416
312
|
try {
|
|
417
|
-
removeOutputArtifact(
|
|
313
|
+
removeOutputArtifact(path4);
|
|
418
314
|
} catch {
|
|
419
315
|
}
|
|
420
316
|
}
|
|
@@ -422,9 +318,13 @@ function cleanupBashOutputArtifacts() {
|
|
|
422
318
|
process.once("exit", cleanupBashOutputArtifacts);
|
|
423
319
|
function finishTempFileStream(stream) {
|
|
424
320
|
if (!stream || stream.closed) return Promise.resolve();
|
|
425
|
-
return new Promise((
|
|
321
|
+
return new Promise((resolve2, reject) => {
|
|
426
322
|
let done = false;
|
|
323
|
+
const timer = setTimeout(() => {
|
|
324
|
+
stream.destroy(new Error("Timed out flushing shell output."));
|
|
325
|
+
}, OUTPUT_DRAIN_TIMEOUT_MS);
|
|
427
326
|
const cleanup = () => {
|
|
327
|
+
clearTimeout(timer);
|
|
428
328
|
stream.off("close", onClose);
|
|
429
329
|
stream.off("error", onError);
|
|
430
330
|
};
|
|
@@ -432,7 +332,7 @@ function finishTempFileStream(stream) {
|
|
|
432
332
|
if (done) return;
|
|
433
333
|
done = true;
|
|
434
334
|
cleanup();
|
|
435
|
-
|
|
335
|
+
resolve2();
|
|
436
336
|
};
|
|
437
337
|
const onError = (error) => {
|
|
438
338
|
if (done) return;
|
|
@@ -457,7 +357,7 @@ function buildBashRecoveryHint(command, output) {
|
|
|
457
357
|
if (/\bnpm ERR!|\bnpm error\b/i.test(output) && /\b(?:ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|fetch failed|socket hang up|registry|proxy)\b/i.test(output)) {
|
|
458
358
|
return "npm could not reach the registry. Treat this as an environment/network/proxy issue, not a source-code failure; retry npm install/npm ci when network is available or check npm proxy/registry settings.";
|
|
459
359
|
}
|
|
460
|
-
if (/\bnpm\s+run\b/.test(command) && (/(?:^|\n)\s*(?:sh|bash|zsh):\s+[\w@./-]+:\s+command not found\b/i.test(output) || /(?:^|\r?\n)\s*'[^']+'\s+is not recognized as an internal or external command\b/i.test(output))) {
|
|
360
|
+
if (/\bnpm\s+run\b/.test(command) && (/(?:^|\n)\s*(?:sh|bash|zsh):\s+[\w@./-]+:\s+command not found\b/i.test(output) || /(?:^|\r?\n)\s*'[^']+'\s+is not recognized as an internal or external command\b/i.test(output) || /\u4e0d\u662f\u5185\u90e8\u6216\u5916\u90e8\u547d\u4ee4/.test(output))) {
|
|
461
361
|
return "This npm script could not find a local executable. Check whether dependencies were installed successfully in cwd, whether node_modules exists, and whether a prior npm install/npm ci failed before treating this as a code failure.";
|
|
462
362
|
}
|
|
463
363
|
return void 0;
|
|
@@ -506,8 +406,9 @@ function killProcessTree(pid) {
|
|
|
506
406
|
try {
|
|
507
407
|
spawn("taskkill", ["/F", "/T", "/PID", String(pid)], {
|
|
508
408
|
stdio: "ignore",
|
|
509
|
-
|
|
510
|
-
})
|
|
409
|
+
windowsHide: true
|
|
410
|
+
}).on("error", () => {
|
|
411
|
+
}).unref();
|
|
511
412
|
} catch {
|
|
512
413
|
}
|
|
513
414
|
} else {
|
|
@@ -542,7 +443,7 @@ function createBashTool(defaultCwd, options) {
|
|
|
542
443
|
execute: async (_toolCallId, { command, timeout, cwd, shell }, signal, onUpdate) => {
|
|
543
444
|
validateBashCommand(command);
|
|
544
445
|
const resolvedShell = resolveShell(shell);
|
|
545
|
-
const effectiveCommand = buildEffectiveCommand(command, options);
|
|
446
|
+
const effectiveCommand = buildEffectiveCommand(command, options, resolvedShell);
|
|
546
447
|
const workingDir = normalizeWorkingDirectory(cwd, defaultCwd);
|
|
547
448
|
validateWorkingDirectory(workingDir);
|
|
548
449
|
const risk = classifyShellCommand(effectiveCommand, resolvedShell, {
|
|
@@ -581,7 +482,7 @@ function createBashTool(defaultCwd, options) {
|
|
|
581
482
|
}
|
|
582
483
|
const timeoutPolicy = resolveTimeoutPolicy(timeout, risk.commandClass);
|
|
583
484
|
const timeoutMs = timeoutPolicy.effectiveSeconds * 1e3;
|
|
584
|
-
return new Promise((
|
|
485
|
+
return new Promise((resolve2, reject) => {
|
|
585
486
|
if (signal?.aborted) {
|
|
586
487
|
reject(new Error("Operation aborted"));
|
|
587
488
|
return;
|
|
@@ -605,25 +506,42 @@ function createBashTool(defaultCwd, options) {
|
|
|
605
506
|
headBytes += prefix.length;
|
|
606
507
|
};
|
|
607
508
|
let timedOut = false;
|
|
509
|
+
let processExited = false;
|
|
510
|
+
let exitCode = null;
|
|
511
|
+
let exitSignal = null;
|
|
512
|
+
let drainTimer;
|
|
608
513
|
const spawnCommand = buildSpawnCommand(resolvedShell, effectiveCommand);
|
|
609
514
|
const child = (options?.spawnProcess ?? spawn)(spawnCommand.file, spawnCommand.args, {
|
|
610
515
|
shell: spawnCommand.shell,
|
|
611
516
|
cwd: workingDir,
|
|
612
517
|
env: process.env,
|
|
613
|
-
detached: process.platform !== "win32"
|
|
518
|
+
detached: process.platform !== "win32",
|
|
519
|
+
windowsHide: true
|
|
614
520
|
});
|
|
521
|
+
const closePipes = () => {
|
|
522
|
+
child.stdin?.destroy();
|
|
523
|
+
child.stdout?.destroy();
|
|
524
|
+
child.stderr?.destroy();
|
|
525
|
+
};
|
|
615
526
|
const timeoutId = setTimeout(() => {
|
|
527
|
+
if (settled) return;
|
|
616
528
|
timedOut = true;
|
|
617
|
-
if (child.pid) {
|
|
529
|
+
if (child.pid && !processExited) {
|
|
618
530
|
killProcessTree(child.pid);
|
|
619
531
|
}
|
|
532
|
+
closePipes();
|
|
533
|
+
child.unref?.();
|
|
534
|
+
void finishExecution(exitCode, exitSignal, true);
|
|
620
535
|
}, timeoutMs);
|
|
621
536
|
const failExecution = (error) => {
|
|
622
537
|
if (settled) return;
|
|
623
538
|
settled = true;
|
|
624
539
|
clearTimeout(timeoutId);
|
|
540
|
+
if (drainTimer) clearTimeout(drainTimer);
|
|
625
541
|
signal?.removeEventListener("abort", onAbort);
|
|
626
|
-
if (child.pid) killProcessTree(child.pid);
|
|
542
|
+
if (child.pid && !processExited) killProcessTree(child.pid);
|
|
543
|
+
closePipes();
|
|
544
|
+
child.unref?.();
|
|
627
545
|
discardOutputArtifact(tempFilePath, tempFileStream);
|
|
628
546
|
reject(error);
|
|
629
547
|
};
|
|
@@ -715,11 +633,13 @@ function createBashTool(defaultCwd, options) {
|
|
|
715
633
|
chunksBytes -= removed.length;
|
|
716
634
|
}
|
|
717
635
|
});
|
|
718
|
-
|
|
636
|
+
const finishExecution = async (code, sig, stdioIncomplete = false) => {
|
|
637
|
+
if (settled) return;
|
|
638
|
+
settled = true;
|
|
719
639
|
try {
|
|
720
640
|
clearTimeout(timeoutId);
|
|
641
|
+
if (drainTimer) clearTimeout(drainTimer);
|
|
721
642
|
signal?.removeEventListener("abort", onAbort);
|
|
722
|
-
if (settled) return;
|
|
723
643
|
const fullBuffer = Buffer.concat(chunks);
|
|
724
644
|
let fullOutput = fullBuffer.toString("utf-8");
|
|
725
645
|
if (totalBytes > fullBuffer.length) {
|
|
@@ -736,10 +656,10 @@ ${fullOutput}`;
|
|
|
736
656
|
}
|
|
737
657
|
let outputText = truncation.content || "(no output)";
|
|
738
658
|
if (truncation.truncated && !tempFilePath) {
|
|
739
|
-
const
|
|
740
|
-
const fd = openSync(
|
|
741
|
-
tempFilePath =
|
|
742
|
-
retainedOutputArtifacts.add(
|
|
659
|
+
const path4 = getTempFilePath();
|
|
660
|
+
const fd = openSync(path4, "wx", 384);
|
|
661
|
+
tempFilePath = path4;
|
|
662
|
+
retainedOutputArtifacts.add(path4);
|
|
743
663
|
try {
|
|
744
664
|
writeFileSync(fd, fullOutput, "utf-8");
|
|
745
665
|
} finally {
|
|
@@ -751,6 +671,7 @@ ${fullOutput}`;
|
|
|
751
671
|
exitCode: code,
|
|
752
672
|
signal: sig?.toString() ?? null,
|
|
753
673
|
timedOut,
|
|
674
|
+
...stdioIncomplete ? { stdioIncomplete: true } : {},
|
|
754
675
|
shell: resolvedShell,
|
|
755
676
|
commandClass: risk.commandClass,
|
|
756
677
|
riskWarnings: risk.riskWarnings,
|
|
@@ -806,6 +727,9 @@ ${commandNonzeroHint}`;
|
|
|
806
727
|
[Command timed out after ${timeoutPolicy.effectiveSeconds} seconds]`;
|
|
807
728
|
outputText += "\n[Timeout hint: split custom searches or service polls into smaller bounded steps with progress output, inspect partial results/logs, then make a decision. Avoid repeating long waits. Reserve long timeouts for installs, builds, and tests.]";
|
|
808
729
|
}
|
|
730
|
+
if (stdioIncomplete && !timedOut) {
|
|
731
|
+
outputText += "\n\n[Output capture ended after the command exited because a descendant kept stdio open. Captured output may be incomplete.]";
|
|
732
|
+
}
|
|
809
733
|
if (timeoutPolicy.capped) {
|
|
810
734
|
outputText += `
|
|
811
735
|
|
|
@@ -826,13 +750,26 @@ ${commandNonzeroHint}`;
|
|
|
826
750
|
outputText += "\n\n[Repeat hint: this exact command already returned the same result in this session. If it proves the task, stop; otherwise change the command or inspect a different file/range.]";
|
|
827
751
|
}
|
|
828
752
|
const content = [{ type: "text", text: outputText }];
|
|
829
|
-
|
|
830
|
-
resolve3({ content, details, isError: outcome.toolFailure });
|
|
753
|
+
resolve2({ content, details, isError: outcome.toolFailure });
|
|
831
754
|
} catch (error) {
|
|
832
755
|
discardOutputArtifact(tempFilePath, tempFileStream);
|
|
833
|
-
settled = true;
|
|
834
756
|
reject(error);
|
|
835
757
|
}
|
|
758
|
+
};
|
|
759
|
+
child.on("exit", (code, sig) => {
|
|
760
|
+
processExited = true;
|
|
761
|
+
exitCode = code;
|
|
762
|
+
exitSignal = sig;
|
|
763
|
+
if (settled) return;
|
|
764
|
+
drainTimer = setTimeout(() => {
|
|
765
|
+
closePipes();
|
|
766
|
+
child.unref?.();
|
|
767
|
+
void finishExecution(code, sig, true);
|
|
768
|
+
}, OUTPUT_DRAIN_TIMEOUT_MS);
|
|
769
|
+
});
|
|
770
|
+
child.on("close", (code, sig) => {
|
|
771
|
+
processExited = true;
|
|
772
|
+
void finishExecution(code, sig);
|
|
836
773
|
});
|
|
837
774
|
child.on("error", (err) => {
|
|
838
775
|
failExecution(new Error(`Failed to start bash command in ${workingDir}: ${err.message}. Check that the command is executable and cwd exists.`));
|
|
@@ -845,7 +782,7 @@ ${commandNonzeroHint}`;
|
|
|
845
782
|
// src/capabilities/code-intel.ts
|
|
846
783
|
import * as fs from "node:fs";
|
|
847
784
|
import * as path from "node:path";
|
|
848
|
-
import { fileURLToPath
|
|
785
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
849
786
|
import { Worker } from "node:worker_threads";
|
|
850
787
|
var WORKER_TIMEOUT_MS = 3e4;
|
|
851
788
|
var MAX_ACTIVE_CODE_INTEL_WORKERS = 1;
|
|
@@ -873,8 +810,8 @@ function acquireWorkerSlot(deadline, signal) {
|
|
|
873
810
|
if (codeIntelWorkerWaiters.length >= MAX_QUEUED_CODE_INTEL_WORKERS) {
|
|
874
811
|
return Promise.reject(new Error("TypeScript code intelligence queue is full"));
|
|
875
812
|
}
|
|
876
|
-
return new Promise((
|
|
877
|
-
const waiter = { resolve: () =>
|
|
813
|
+
return new Promise((resolve2, reject) => {
|
|
814
|
+
const waiter = { resolve: () => resolve2(releaseWorkerSlot), reject, signal };
|
|
878
815
|
waiter.onAbort = () => {
|
|
879
816
|
const index = codeIntelWorkerWaiters.indexOf(waiter);
|
|
880
817
|
if (index >= 0) codeIntelWorkerWaiters.splice(index, 1);
|
|
@@ -893,7 +830,7 @@ function acquireWorkerSlot(deadline, signal) {
|
|
|
893
830
|
});
|
|
894
831
|
}
|
|
895
832
|
function resolveWorkerPath() {
|
|
896
|
-
const moduleDirectory = path.dirname(
|
|
833
|
+
const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
897
834
|
const candidates = [
|
|
898
835
|
path.join(moduleDirectory, "code-intel-worker.cjs"),
|
|
899
836
|
path.join(moduleDirectory, "..", "code-intel-worker.cjs"),
|
|
@@ -904,7 +841,7 @@ function resolveWorkerPath() {
|
|
|
904
841
|
return workerPath;
|
|
905
842
|
}
|
|
906
843
|
function runWorker(request, timeoutMs, signal) {
|
|
907
|
-
return new Promise((
|
|
844
|
+
return new Promise((resolve2, reject) => {
|
|
908
845
|
if (signal?.aborted) {
|
|
909
846
|
reject(new Error("Operation aborted"));
|
|
910
847
|
return;
|
|
@@ -929,7 +866,7 @@ function runWorker(request, timeoutMs, signal) {
|
|
|
929
866
|
}
|
|
930
867
|
}
|
|
931
868
|
if (error) reject(error);
|
|
932
|
-
else
|
|
869
|
+
else resolve2(result);
|
|
933
870
|
})();
|
|
934
871
|
};
|
|
935
872
|
const onAbort = () => finish(new Error("Operation aborted"));
|
|
@@ -1017,21 +954,33 @@ function createCodeIntelTool2(options) {
|
|
|
1017
954
|
// src/capabilities/rendered-page-reader.ts
|
|
1018
955
|
import { spawn as spawn2 } from "node:child_process";
|
|
1019
956
|
import { createRequire } from "node:module";
|
|
957
|
+
import * as fs2 from "node:fs";
|
|
958
|
+
import * as os from "node:os";
|
|
959
|
+
import * as path2 from "node:path";
|
|
1020
960
|
var require2 = createRequire(import.meta.url);
|
|
1021
|
-
function
|
|
1022
|
-
|
|
961
|
+
function resolveAxiCli() {
|
|
962
|
+
const runtime = path2.join(getBuiltinDir(), "skills", "chrome-devtools-axi", "chrome-devtools-axi-runtime.js");
|
|
963
|
+
if (!fs2.existsSync(runtime)) throw new Error("Pie's packaged browser runtime is missing. Rebuild or reinstall Pie.");
|
|
964
|
+
return runtime;
|
|
965
|
+
}
|
|
966
|
+
function resolveMcpScript() {
|
|
967
|
+
const packageJson = require2.resolve("chrome-devtools-mcp/package.json");
|
|
968
|
+
return path2.join(path2.dirname(packageJson), "build", "src", "bin", "chrome-devtools-mcp.js");
|
|
1023
969
|
}
|
|
1024
|
-
function
|
|
1025
|
-
|
|
1026
|
-
|
|
970
|
+
function runAxi(args, options = {}) {
|
|
971
|
+
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
972
|
+
return new Promise((resolve2, reject) => {
|
|
973
|
+
const child = spawn2(process.execPath, [resolveAxiCli(), ...args], {
|
|
1027
974
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1028
|
-
shell: false
|
|
975
|
+
shell: false,
|
|
976
|
+
env: options.env,
|
|
977
|
+
cwd: options.cwd
|
|
1029
978
|
});
|
|
1030
979
|
let stdout = "";
|
|
1031
980
|
let stderr = "";
|
|
1032
981
|
const timer = setTimeout(() => {
|
|
1033
982
|
child.kill("SIGTERM");
|
|
1034
|
-
reject(new Error(`
|
|
983
|
+
reject(new Error(`chrome-devtools-axi timed out after ${Math.ceil(timeoutMs / 1e3)} seconds`));
|
|
1035
984
|
}, timeoutMs);
|
|
1036
985
|
child.stdout.setEncoding("utf8");
|
|
1037
986
|
child.stderr.setEncoding("utf8");
|
|
@@ -1047,24 +996,40 @@ function runPlaywright(args, timeoutMs = 6e4) {
|
|
|
1047
996
|
});
|
|
1048
997
|
child.on("close", (code) => {
|
|
1049
998
|
clearTimeout(timer);
|
|
1050
|
-
if (code === 0)
|
|
1051
|
-
else reject(new Error((stderr || stdout || `
|
|
999
|
+
if (code === 0) resolve2(stdout.trim());
|
|
1000
|
+
else reject(new Error((stderr || stdout || `chrome-devtools-axi exited with ${code}`).trim()));
|
|
1052
1001
|
});
|
|
1053
1002
|
});
|
|
1054
1003
|
}
|
|
1055
1004
|
function linesOf(output, max = 50) {
|
|
1056
|
-
|
|
1005
|
+
if (/^(console|network)_failed:/i.test(output.trim())) return [];
|
|
1006
|
+
return output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).filter((line) => !/^(console:|network:|##\s|Showing \d|\(\d+ args\)$|<no .+ found>$|no \w+ found\.$)/i.test(line)).slice(0, max);
|
|
1057
1007
|
}
|
|
1058
1008
|
function parseScreenshotPath(output) {
|
|
1059
|
-
|
|
1009
|
+
if (output.startsWith("screenshot_failed:")) return void 0;
|
|
1010
|
+
const match = output.match(/(?:^|\n)screenshot:\s*(\S+)/i) || output.match(/([^\s]+\.(?:png|jpe?g|webp))/i);
|
|
1060
1011
|
return match?.[1];
|
|
1061
1012
|
}
|
|
1013
|
+
function unwrapJsonValue(payload) {
|
|
1014
|
+
let value = payload;
|
|
1015
|
+
for (let depth = 0; depth < 4; depth += 1) {
|
|
1016
|
+
if (typeof value !== "string") break;
|
|
1017
|
+
const text = value.trim();
|
|
1018
|
+
if (!text.startsWith('"') && !text.startsWith("{") && !text.startsWith("[")) break;
|
|
1019
|
+
try {
|
|
1020
|
+
value = JSON.parse(text);
|
|
1021
|
+
} catch {
|
|
1022
|
+
break;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return value;
|
|
1026
|
+
}
|
|
1062
1027
|
function parsePageInfo(raw) {
|
|
1063
1028
|
const trimmed = raw.trim();
|
|
1064
1029
|
if (!trimmed) return {};
|
|
1030
|
+
const payload = trimmed.replace(/^result:\s*/i, "");
|
|
1065
1031
|
try {
|
|
1066
|
-
const
|
|
1067
|
-
const parsed = typeof decoded === "string" ? JSON.parse(decoded) : decoded;
|
|
1032
|
+
const parsed = unwrapJsonValue(payload);
|
|
1068
1033
|
if (!parsed || typeof parsed !== "object") return {};
|
|
1069
1034
|
return {
|
|
1070
1035
|
finalUrl: typeof parsed.href === "string" ? parsed.href : void 0,
|
|
@@ -1075,23 +1040,53 @@ function parsePageInfo(raw) {
|
|
|
1075
1040
|
return {};
|
|
1076
1041
|
}
|
|
1077
1042
|
}
|
|
1043
|
+
function stripHelpHints(output) {
|
|
1044
|
+
return output.replace(/(?:^|\n)help\[\d+\]:[\s\S]*$/i, "").trim();
|
|
1045
|
+
}
|
|
1046
|
+
function parseSnapshot(output) {
|
|
1047
|
+
const match = output.match(/(?:^|\n)snapshot:\n([\s\S]*)$/i);
|
|
1048
|
+
return stripHelpHints(match ? match[1] : output);
|
|
1049
|
+
}
|
|
1050
|
+
function cleanStaleScreenshotDirs(retentionMs = 60 * 60 * 1e3) {
|
|
1051
|
+
try {
|
|
1052
|
+
const tmp = os.tmpdir();
|
|
1053
|
+
const cutoff = Date.now() - retentionMs;
|
|
1054
|
+
for (const entry of fs2.readdirSync(tmp)) {
|
|
1055
|
+
if (!entry.startsWith("pie-axi-shot-")) continue;
|
|
1056
|
+
const dir = path2.join(tmp, entry);
|
|
1057
|
+
try {
|
|
1058
|
+
if (fs2.statSync(dir).mtimeMs < cutoff) fs2.rmSync(dir, { recursive: true, force: true });
|
|
1059
|
+
} catch {
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
} catch {
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1078
1065
|
function createCliRenderedPageReader() {
|
|
1079
1066
|
return async ({ url }) => {
|
|
1080
1067
|
const session = `pie-web-research-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1068
|
+
const env = { ...process.env, CHROME_DEVTOOLS_AXI_SESSION: session };
|
|
1069
|
+
delete env.CHROME_DEVTOOLS_AXI_PORT;
|
|
1070
|
+
if (!env.CHROME_DEVTOOLS_AXI_MCP_PATH?.trim()) env.CHROME_DEVTOOLS_AXI_MCP_PATH = resolveMcpScript();
|
|
1071
|
+
if (!env.CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS) env.CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS = "1";
|
|
1072
|
+
cleanStaleScreenshotDirs();
|
|
1073
|
+
const screenshotDir = fs2.mkdtempSync(path2.join(os.tmpdir(), "pie-axi-shot-"));
|
|
1081
1074
|
try {
|
|
1082
|
-
await
|
|
1083
|
-
await
|
|
1084
|
-
const [
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1075
|
+
await runAxi(["open", `data:text/html,<title>pie-warm-${session}</title>`], { env });
|
|
1076
|
+
await runAxi(["open", url], { env });
|
|
1077
|
+
const [snapshotOutput, pageInfoRaw, screenshotOutput, consoleOutput, networkOutput] = await Promise.all([
|
|
1078
|
+
runAxi(["snapshot"], { env }),
|
|
1079
|
+
// --full: eval output is truncated at ~8KB by default, which would
|
|
1080
|
+
// break JSON parsing and drop title/finalUrl/text on real pages.
|
|
1081
|
+
runAxi(["eval", "() => JSON.stringify({ title: document.title, href: location.href, text: document.body ? document.body.innerText : '' })", "--full"], { env }),
|
|
1082
|
+
runAxi(["screenshot", path2.join(screenshotDir, "page.png")], { env }).catch((error) => `screenshot_failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
1083
|
+
runAxi(["console"], { env }).catch((error) => `console_failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
1084
|
+
runAxi(["network"], { env }).catch((error) => `network_failed: ${error instanceof Error ? error.message : String(error)}`)
|
|
1090
1085
|
]);
|
|
1091
|
-
const pageInfo = parsePageInfo(pageInfoRaw);
|
|
1092
|
-
const text = pageInfo.text?.trim() ||
|
|
1086
|
+
const pageInfo = parsePageInfo(stripHelpHints(pageInfoRaw));
|
|
1087
|
+
const text = pageInfo.text?.trim() || parseSnapshot(snapshotOutput);
|
|
1093
1088
|
if (!text) {
|
|
1094
|
-
throw new Error("
|
|
1089
|
+
throw new Error("chrome-devtools-axi snapshot returned no text.");
|
|
1095
1090
|
}
|
|
1096
1091
|
return {
|
|
1097
1092
|
url,
|
|
@@ -1100,18 +1095,18 @@ function createCliRenderedPageReader() {
|
|
|
1100
1095
|
text,
|
|
1101
1096
|
citationAnchors: [{ url: pageInfo.finalUrl || url, title: pageInfo.title, startOffset: 0, endOffset: Math.min(120, text.length) }],
|
|
1102
1097
|
screenshotPath: parseScreenshotPath(screenshotOutput),
|
|
1103
|
-
consoleMessages: linesOf(consoleOutput),
|
|
1104
|
-
networkRequests: linesOf(
|
|
1098
|
+
consoleMessages: linesOf(stripHelpHints(consoleOutput)),
|
|
1099
|
+
networkRequests: linesOf(stripHelpHints(networkOutput))
|
|
1105
1100
|
};
|
|
1106
1101
|
} finally {
|
|
1107
|
-
|
|
1102
|
+
runAxi(["stop"], { env, timeoutMs: 1e4 }).catch(() => void 0);
|
|
1108
1103
|
}
|
|
1109
1104
|
};
|
|
1110
1105
|
}
|
|
1111
1106
|
|
|
1112
1107
|
// src/capabilities/web-research-health.ts
|
|
1113
|
-
import
|
|
1114
|
-
import
|
|
1108
|
+
import fs3 from "node:fs";
|
|
1109
|
+
import path3 from "node:path";
|
|
1115
1110
|
function isRecord(value) {
|
|
1116
1111
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1117
1112
|
}
|
|
@@ -1133,11 +1128,11 @@ function parseHealthEntry(value) {
|
|
|
1133
1128
|
};
|
|
1134
1129
|
}
|
|
1135
1130
|
function createCliWebResearchHealthStore(configDir) {
|
|
1136
|
-
const filePath =
|
|
1131
|
+
const filePath = path3.join(configDir, "web-research-health.json");
|
|
1137
1132
|
return {
|
|
1138
1133
|
loadProviderHealth: () => {
|
|
1139
1134
|
try {
|
|
1140
|
-
const parsed = JSON.parse(
|
|
1135
|
+
const parsed = JSON.parse(fs3.readFileSync(filePath, "utf8"));
|
|
1141
1136
|
if (!Array.isArray(parsed)) return [];
|
|
1142
1137
|
return parsed.map(parseHealthEntry).filter((entry) => !!entry);
|
|
1143
1138
|
} catch {
|
|
@@ -1146,8 +1141,8 @@ function createCliWebResearchHealthStore(configDir) {
|
|
|
1146
1141
|
},
|
|
1147
1142
|
saveProviderHealth: (entries) => {
|
|
1148
1143
|
try {
|
|
1149
|
-
|
|
1150
|
-
|
|
1144
|
+
fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
|
|
1145
|
+
fs3.writeFileSync(filePath, JSON.stringify(entries, null, 2));
|
|
1151
1146
|
} catch {
|
|
1152
1147
|
}
|
|
1153
1148
|
}
|
|
@@ -1213,22 +1208,10 @@ function createCliHostCapabilities(cwd, options = {}) {
|
|
|
1213
1208
|
}
|
|
1214
1209
|
|
|
1215
1210
|
export {
|
|
1216
|
-
getPackageDir,
|
|
1217
|
-
getThemesDir,
|
|
1218
|
-
getBuiltinDir,
|
|
1219
|
-
VERSION,
|
|
1220
|
-
getConfigDir,
|
|
1221
|
-
getAgentDir,
|
|
1222
|
-
getCustomThemesDir,
|
|
1223
|
-
getSettingsPath,
|
|
1224
|
-
getProjectSettingsPath,
|
|
1225
|
-
getSessionsDir,
|
|
1226
|
-
getLogsDir,
|
|
1227
|
-
getRuntimeLogPath,
|
|
1228
|
-
migrateConfigFromAgentDir,
|
|
1229
1211
|
createCliWebResearchHealthStore,
|
|
1230
1212
|
truncateHeadTail,
|
|
1231
1213
|
formatSize,
|
|
1232
1214
|
cleanupBashOutputArtifacts,
|
|
1215
|
+
createBashTool,
|
|
1233
1216
|
createCliHostCapabilities
|
|
1234
1217
|
};
|