@cydm/pie 2.6.12 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -2
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +130 -21
- package/dist/builtin/extensions/subagent/index.js +4 -5
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/computer-use-axi/SKILL.md +103 -0
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
- package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-runtime.js} +754 -642
- package/dist/builtin/skills/computer-use-axi/package.json +11 -0
- package/dist/chunks/{chunk-PPEWRUMQ.js → chunk-6RBSTII7.js} +657 -594
- package/dist/chunks/{chunk-AAEBH6KX.js → chunk-IPNAFMOJ.js} +172 -230
- package/dist/chunks/{chunk-7B4IIBVS.js → chunk-R5I2QLF2.js} +1269 -4
- package/dist/chunks/{chunk-HHNOENEH.js → chunk-TWILEFLD.js} +14 -1
- package/dist/chunks/{src-OWQI5M6W.js → src-E7NCXMU5.js} +2 -2
- package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-BWBJTFNI.js} +1 -1
- package/dist/cli.js +463 -232
- package/models.schema.json +52 -0
- package/package.json +3 -3
- package/dist/builtin/extensions/computer-use/package.json +0 -14
- package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +0 -278
- package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +0 -204
- package/dist/chunks/chunk-5353DEEC.js +0 -130
- package/dist/chunks/webapi-MBCKO7ZV.js +0 -2481
- package/dist/code-intel-worker.cjs +0 -211227
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/arm64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/x64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/arm64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/x64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/windows/windows-bridge.exe +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/helper-path.mjs +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/setup-helper.mjs +0 -0
|
@@ -1,27 +1,134 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
classifyShellCommand,
|
|
4
|
-
createCodeIntelTool,
|
|
5
|
-
createLightweightCodeIntelProvider,
|
|
6
4
|
createSharedWebFetchTool,
|
|
7
5
|
createSharedWebResearchTool,
|
|
8
6
|
createSharedWebSearchTool,
|
|
9
7
|
interpretShellExit,
|
|
10
8
|
requestInteraction
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
getBuiltinDir,
|
|
14
|
-
getConfigDir
|
|
15
|
-
} from "./chunk-5353DEEC.js";
|
|
9
|
+
} from "./chunk-6RBSTII7.js";
|
|
16
10
|
import {
|
|
17
11
|
Type
|
|
18
12
|
} from "./chunk-XXGYUYXI.js";
|
|
19
13
|
|
|
14
|
+
// src/config.ts
|
|
15
|
+
import { existsSync, mkdirSync, readFileSync, renameSync } from "fs";
|
|
16
|
+
import { homedir } from "os";
|
|
17
|
+
import { dirname, join } from "path";
|
|
18
|
+
import { fileURLToPath } from "url";
|
|
19
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
var __dirname = dirname(__filename);
|
|
21
|
+
var isBunRuntime = !!process.versions.bun;
|
|
22
|
+
function getPackageDir() {
|
|
23
|
+
const envDir = process.env.PIE_PACKAGE_DIR;
|
|
24
|
+
if (envDir) {
|
|
25
|
+
if (envDir === "~") return homedir();
|
|
26
|
+
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
|
|
27
|
+
return envDir;
|
|
28
|
+
}
|
|
29
|
+
let dir = __dirname;
|
|
30
|
+
while (dir !== dirname(dir)) {
|
|
31
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
32
|
+
return dir;
|
|
33
|
+
}
|
|
34
|
+
dir = dirname(dir);
|
|
35
|
+
}
|
|
36
|
+
return __dirname;
|
|
37
|
+
}
|
|
38
|
+
function getThemesDir() {
|
|
39
|
+
const packageDir = getPackageDir();
|
|
40
|
+
const srcOrDist = existsSync(join(packageDir, "src")) ? "src" : "dist";
|
|
41
|
+
return join(packageDir, srcOrDist, "theme");
|
|
42
|
+
}
|
|
43
|
+
function getBuiltinDir() {
|
|
44
|
+
const packageDir = getPackageDir();
|
|
45
|
+
const distBuiltinDir = join(packageDir, "dist", "builtin");
|
|
46
|
+
if (existsSync(distBuiltinDir)) {
|
|
47
|
+
return distBuiltinDir;
|
|
48
|
+
}
|
|
49
|
+
return join(packageDir, "builtin");
|
|
50
|
+
}
|
|
51
|
+
function getPackageJsonPath() {
|
|
52
|
+
return join(getPackageDir(), "package.json");
|
|
53
|
+
}
|
|
54
|
+
var pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8"));
|
|
55
|
+
var CONFIG_DIR_NAME = ".pie";
|
|
56
|
+
var VERSION = pkg.version;
|
|
57
|
+
var ENV_AGENT_DIR = "PIE_CODING_AGENT_DIR";
|
|
58
|
+
function getConfigDir() {
|
|
59
|
+
const envDir = process.env[ENV_AGENT_DIR];
|
|
60
|
+
if (envDir) {
|
|
61
|
+
if (envDir === "~") return homedir();
|
|
62
|
+
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
|
|
63
|
+
return envDir;
|
|
64
|
+
}
|
|
65
|
+
return join(homedir(), CONFIG_DIR_NAME);
|
|
66
|
+
}
|
|
67
|
+
function getAgentDir() {
|
|
68
|
+
return getConfigDir();
|
|
69
|
+
}
|
|
70
|
+
function getCustomThemesDir() {
|
|
71
|
+
return join(getConfigDir(), "themes");
|
|
72
|
+
}
|
|
73
|
+
function getSettingsPath() {
|
|
74
|
+
return join(getConfigDir(), "settings.json");
|
|
75
|
+
}
|
|
76
|
+
function getProjectSettingsPath(cwd) {
|
|
77
|
+
return join(cwd, CONFIG_DIR_NAME, "settings.json");
|
|
78
|
+
}
|
|
79
|
+
function getSessionsDir() {
|
|
80
|
+
return join(getConfigDir(), "sessions");
|
|
81
|
+
}
|
|
82
|
+
function getLogsDir() {
|
|
83
|
+
return join(getConfigDir(), "logs");
|
|
84
|
+
}
|
|
85
|
+
function getRuntimeLogPath() {
|
|
86
|
+
return join(getLogsDir(), "pie-cli.log");
|
|
87
|
+
}
|
|
88
|
+
function migrateConfigFromAgentDir() {
|
|
89
|
+
const oldAgentDir = join(homedir(), CONFIG_DIR_NAME, "agent");
|
|
90
|
+
const newConfigDir = getConfigDir();
|
|
91
|
+
if (!existsSync(oldAgentDir)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!existsSync(newConfigDir)) {
|
|
95
|
+
mkdirSync(newConfigDir, { recursive: true });
|
|
96
|
+
}
|
|
97
|
+
const filesToMigrate = [
|
|
98
|
+
"keybindings.json",
|
|
99
|
+
"settings.json",
|
|
100
|
+
"pie-debug.log"
|
|
101
|
+
];
|
|
102
|
+
for (const file of filesToMigrate) {
|
|
103
|
+
const oldPath = join(oldAgentDir, file);
|
|
104
|
+
const newPath = file === "pie-debug.log" ? getRuntimeLogPath() : join(newConfigDir, file);
|
|
105
|
+
if (existsSync(oldPath) && !existsSync(newPath)) {
|
|
106
|
+
try {
|
|
107
|
+
if (file === "pie-debug.log") {
|
|
108
|
+
mkdirSync(getLogsDir(), { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
renameSync(oldPath, newPath);
|
|
111
|
+
console.log(`[Config] Migrated ${file} to ${newPath}`);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const oldThemesDir = join(oldAgentDir, "themes");
|
|
117
|
+
const newThemesDir = getCustomThemesDir();
|
|
118
|
+
if (existsSync(oldThemesDir) && !existsSync(newThemesDir)) {
|
|
119
|
+
try {
|
|
120
|
+
renameSync(oldThemesDir, newThemesDir);
|
|
121
|
+
console.log(`[Config] Migrated themes to ${newThemesDir}`);
|
|
122
|
+
} catch (e) {
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
20
127
|
// src/capabilities/bash/index.ts
|
|
21
128
|
import { spawn } from "child_process";
|
|
22
|
-
import { closeSync, createWriteStream, existsSync, openSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
129
|
+
import { closeSync, createWriteStream, existsSync as existsSync2, openSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
23
130
|
import { tmpdir } from "os";
|
|
24
|
-
import { join, resolve } from "path";
|
|
131
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
25
132
|
import { createHash, randomBytes } from "crypto";
|
|
26
133
|
|
|
27
134
|
// src/capabilities/bash/truncate.ts
|
|
@@ -275,7 +382,7 @@ async function requestHighRiskConfirmation(request) {
|
|
|
275
382
|
return response.type === "confirm" && response.confirmed === true;
|
|
276
383
|
}
|
|
277
384
|
function validateWorkingDirectory(cwd) {
|
|
278
|
-
if (!
|
|
385
|
+
if (!existsSync2(cwd)) {
|
|
279
386
|
throw new Error(`Invalid bash cwd: ${cwd} does not exist. Use the current workspace path or pass an existing directory in cwd.`);
|
|
280
387
|
}
|
|
281
388
|
let stat;
|
|
@@ -290,11 +397,11 @@ function validateWorkingDirectory(cwd) {
|
|
|
290
397
|
}
|
|
291
398
|
function normalizeWorkingDirectory(cwd, defaultCwd) {
|
|
292
399
|
const requestedCwd = typeof cwd === "string" && cwd.trim().length > 0 ? cwd.trim() : void 0;
|
|
293
|
-
return
|
|
400
|
+
return resolve2(requestedCwd ?? defaultCwd ?? process.cwd());
|
|
294
401
|
}
|
|
295
402
|
function getTempFilePath() {
|
|
296
403
|
const id = randomBytes(8).toString("hex");
|
|
297
|
-
return
|
|
404
|
+
return join2(tmpdir(), `pie-bash-${id}.log`);
|
|
298
405
|
}
|
|
299
406
|
var retainedOutputArtifacts = /* @__PURE__ */ new Set();
|
|
300
407
|
function getErrorCode(error) {
|
|
@@ -304,15 +411,15 @@ function getErrorCode(error) {
|
|
|
304
411
|
}
|
|
305
412
|
function createPrivateOutputArtifact() {
|
|
306
413
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
307
|
-
const
|
|
414
|
+
const path3 = getTempFilePath();
|
|
308
415
|
try {
|
|
309
|
-
const fd = openSync(
|
|
310
|
-
retainedOutputArtifacts.add(
|
|
416
|
+
const fd = openSync(path3, "wx", 384);
|
|
417
|
+
retainedOutputArtifacts.add(path3);
|
|
311
418
|
try {
|
|
312
|
-
return { path:
|
|
419
|
+
return { path: path3, stream: createWriteStream(path3, { fd, autoClose: true }) };
|
|
313
420
|
} catch (error) {
|
|
314
421
|
closeSync(fd);
|
|
315
|
-
removeOutputArtifact(
|
|
422
|
+
removeOutputArtifact(path3);
|
|
316
423
|
throw error;
|
|
317
424
|
}
|
|
318
425
|
} catch (error) {
|
|
@@ -321,34 +428,34 @@ function createPrivateOutputArtifact() {
|
|
|
321
428
|
}
|
|
322
429
|
throw new Error("Unable to allocate a private bash output artifact.");
|
|
323
430
|
}
|
|
324
|
-
function removeOutputArtifact(
|
|
325
|
-
if (!
|
|
431
|
+
function removeOutputArtifact(path3) {
|
|
432
|
+
if (!path3) return;
|
|
326
433
|
try {
|
|
327
|
-
unlinkSync(
|
|
434
|
+
unlinkSync(path3);
|
|
328
435
|
} catch (error) {
|
|
329
436
|
if (getErrorCode(error) !== "ENOENT") throw error;
|
|
330
437
|
}
|
|
331
|
-
retainedOutputArtifacts.delete(
|
|
438
|
+
retainedOutputArtifacts.delete(path3);
|
|
332
439
|
}
|
|
333
|
-
function discardOutputArtifact(
|
|
440
|
+
function discardOutputArtifact(path3, stream) {
|
|
334
441
|
if (stream && !stream.closed) {
|
|
335
442
|
stream.once("close", () => {
|
|
336
443
|
try {
|
|
337
|
-
removeOutputArtifact(
|
|
444
|
+
removeOutputArtifact(path3);
|
|
338
445
|
} catch {
|
|
339
446
|
}
|
|
340
447
|
});
|
|
341
448
|
stream.destroy();
|
|
342
449
|
}
|
|
343
450
|
try {
|
|
344
|
-
removeOutputArtifact(
|
|
451
|
+
removeOutputArtifact(path3);
|
|
345
452
|
} catch {
|
|
346
453
|
}
|
|
347
454
|
}
|
|
348
455
|
function cleanupBashOutputArtifacts() {
|
|
349
|
-
for (const
|
|
456
|
+
for (const path3 of [...retainedOutputArtifacts]) {
|
|
350
457
|
try {
|
|
351
|
-
removeOutputArtifact(
|
|
458
|
+
removeOutputArtifact(path3);
|
|
352
459
|
} catch {
|
|
353
460
|
}
|
|
354
461
|
}
|
|
@@ -356,7 +463,7 @@ function cleanupBashOutputArtifacts() {
|
|
|
356
463
|
process.once("exit", cleanupBashOutputArtifacts);
|
|
357
464
|
function finishTempFileStream(stream) {
|
|
358
465
|
if (!stream || stream.closed) return Promise.resolve();
|
|
359
|
-
return new Promise((
|
|
466
|
+
return new Promise((resolve3, reject) => {
|
|
360
467
|
let done = false;
|
|
361
468
|
const timer = setTimeout(() => {
|
|
362
469
|
stream.destroy(new Error("Timed out flushing shell output."));
|
|
@@ -370,7 +477,7 @@ function finishTempFileStream(stream) {
|
|
|
370
477
|
if (done) return;
|
|
371
478
|
done = true;
|
|
372
479
|
cleanup();
|
|
373
|
-
|
|
480
|
+
resolve3();
|
|
374
481
|
};
|
|
375
482
|
const onError = (error) => {
|
|
376
483
|
if (done) return;
|
|
@@ -549,7 +656,7 @@ function createBashTool(defaultCwd, options) {
|
|
|
549
656
|
}
|
|
550
657
|
const timeoutPolicy = resolveTimeoutPolicy(timeout, risk.commandClass);
|
|
551
658
|
const timeoutMs = timeoutPolicy.effectiveSeconds * 1e3;
|
|
552
|
-
return new Promise((
|
|
659
|
+
return new Promise((resolve3, reject) => {
|
|
553
660
|
if (signal?.aborted) {
|
|
554
661
|
reject(new Error("Operation aborted"));
|
|
555
662
|
return;
|
|
@@ -763,10 +870,10 @@ ${fullOutput}`;
|
|
|
763
870
|
}
|
|
764
871
|
let outputText = truncation.content || "(no output)";
|
|
765
872
|
if (truncation.truncated && !tempFilePath) {
|
|
766
|
-
const
|
|
767
|
-
const fd = openSync(
|
|
768
|
-
tempFilePath =
|
|
769
|
-
retainedOutputArtifacts.add(
|
|
873
|
+
const path3 = getTempFilePath();
|
|
874
|
+
const fd = openSync(path3, "wx", 384);
|
|
875
|
+
tempFilePath = path3;
|
|
876
|
+
retainedOutputArtifacts.add(path3);
|
|
770
877
|
try {
|
|
771
878
|
writeFileSync(fd, fullOutput, "utf-8");
|
|
772
879
|
} finally {
|
|
@@ -857,7 +964,7 @@ ${commandNonzeroHint}`;
|
|
|
857
964
|
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.]";
|
|
858
965
|
}
|
|
859
966
|
const content = [{ type: "text", text: outputText }];
|
|
860
|
-
|
|
967
|
+
resolve3({ content, details, isError: outcome.toolFailure });
|
|
861
968
|
} catch (error) {
|
|
862
969
|
discardOutputArtifact(tempFilePath, tempFileStream);
|
|
863
970
|
reject(error);
|
|
@@ -883,197 +990,25 @@ ${commandNonzeroHint}`;
|
|
|
883
990
|
};
|
|
884
991
|
}
|
|
885
992
|
|
|
886
|
-
// src/capabilities/code-intel.ts
|
|
887
|
-
import * as fs from "node:fs";
|
|
888
|
-
import * as path from "node:path";
|
|
889
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
890
|
-
import { Worker } from "node:worker_threads";
|
|
891
|
-
var WORKER_TIMEOUT_MS = 3e4;
|
|
892
|
-
var MAX_ACTIVE_CODE_INTEL_WORKERS = 1;
|
|
893
|
-
var MAX_QUEUED_CODE_INTEL_WORKERS = 16;
|
|
894
|
-
var activeCodeIntelWorkers = 0;
|
|
895
|
-
var codeIntelWorkerWaiters = [];
|
|
896
|
-
function releaseWorkerSlot() {
|
|
897
|
-
activeCodeIntelWorkers = Math.max(0, activeCodeIntelWorkers - 1);
|
|
898
|
-
while (activeCodeIntelWorkers < MAX_ACTIVE_CODE_INTEL_WORKERS && codeIntelWorkerWaiters.length > 0) {
|
|
899
|
-
const waiter = codeIntelWorkerWaiters.shift();
|
|
900
|
-
waiter.signal?.removeEventListener("abort", waiter.onAbort);
|
|
901
|
-
if (waiter.timeout) clearTimeout(waiter.timeout);
|
|
902
|
-
if (waiter.signal?.aborted) continue;
|
|
903
|
-
activeCodeIntelWorkers++;
|
|
904
|
-
waiter.resolve();
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
function acquireWorkerSlot(deadline, signal) {
|
|
908
|
-
if (signal?.aborted) return Promise.reject(new Error("Operation aborted"));
|
|
909
|
-
if (Date.now() >= deadline) return Promise.reject(new Error(`TypeScript code intelligence queue wait exceeded ${WORKER_TIMEOUT_MS}ms`));
|
|
910
|
-
if (activeCodeIntelWorkers < MAX_ACTIVE_CODE_INTEL_WORKERS) {
|
|
911
|
-
activeCodeIntelWorkers++;
|
|
912
|
-
return Promise.resolve(releaseWorkerSlot);
|
|
913
|
-
}
|
|
914
|
-
if (codeIntelWorkerWaiters.length >= MAX_QUEUED_CODE_INTEL_WORKERS) {
|
|
915
|
-
return Promise.reject(new Error("TypeScript code intelligence queue is full"));
|
|
916
|
-
}
|
|
917
|
-
return new Promise((resolve2, reject) => {
|
|
918
|
-
const waiter = { resolve: () => resolve2(releaseWorkerSlot), reject, signal };
|
|
919
|
-
waiter.onAbort = () => {
|
|
920
|
-
const index = codeIntelWorkerWaiters.indexOf(waiter);
|
|
921
|
-
if (index >= 0) codeIntelWorkerWaiters.splice(index, 1);
|
|
922
|
-
if (waiter.timeout) clearTimeout(waiter.timeout);
|
|
923
|
-
reject(new Error("Operation aborted"));
|
|
924
|
-
};
|
|
925
|
-
waiter.timeout = setTimeout(() => {
|
|
926
|
-
const index = codeIntelWorkerWaiters.indexOf(waiter);
|
|
927
|
-
if (index >= 0) codeIntelWorkerWaiters.splice(index, 1);
|
|
928
|
-
signal?.removeEventListener("abort", waiter.onAbort);
|
|
929
|
-
reject(new Error(`TypeScript code intelligence queue wait exceeded ${WORKER_TIMEOUT_MS}ms`));
|
|
930
|
-
}, Math.max(1, deadline - Date.now()));
|
|
931
|
-
waiter.timeout.unref?.();
|
|
932
|
-
signal?.addEventListener("abort", waiter.onAbort, { once: true });
|
|
933
|
-
codeIntelWorkerWaiters.push(waiter);
|
|
934
|
-
});
|
|
935
|
-
}
|
|
936
|
-
function resolveWorkerPath() {
|
|
937
|
-
const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
938
|
-
const candidates = [
|
|
939
|
-
path.join(moduleDirectory, "code-intel-worker.cjs"),
|
|
940
|
-
path.join(moduleDirectory, "..", "code-intel-worker.cjs"),
|
|
941
|
-
path.join(moduleDirectory, "..", "..", "dist", "code-intel-worker.cjs")
|
|
942
|
-
];
|
|
943
|
-
const workerPath = candidates.find((candidate) => fs.existsSync(candidate));
|
|
944
|
-
if (!workerPath) throw new Error("compiled code-intel worker is unavailable; rebuild the CLI");
|
|
945
|
-
return workerPath;
|
|
946
|
-
}
|
|
947
|
-
function runWorker(request, timeoutMs, signal) {
|
|
948
|
-
return new Promise((resolve2, reject) => {
|
|
949
|
-
if (signal?.aborted) {
|
|
950
|
-
reject(new Error("Operation aborted"));
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
|
-
const worker = new Worker(pathToFileURL(resolveWorkerPath()), {
|
|
954
|
-
workerData: request,
|
|
955
|
-
execArgv: [],
|
|
956
|
-
resourceLimits: { maxOldGenerationSizeMb: 128, maxYoungGenerationSizeMb: 32, stackSizeMb: 4 }
|
|
957
|
-
});
|
|
958
|
-
let finishing = false;
|
|
959
|
-
let exited = false;
|
|
960
|
-
const finish = (error, result) => {
|
|
961
|
-
if (finishing) return;
|
|
962
|
-
finishing = true;
|
|
963
|
-
clearTimeout(timeout);
|
|
964
|
-
signal?.removeEventListener("abort", onAbort);
|
|
965
|
-
void (async () => {
|
|
966
|
-
if (!exited) {
|
|
967
|
-
try {
|
|
968
|
-
await worker.terminate();
|
|
969
|
-
} catch {
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
if (error) reject(error);
|
|
973
|
-
else resolve2(result);
|
|
974
|
-
})();
|
|
975
|
-
};
|
|
976
|
-
const onAbort = () => finish(new Error("Operation aborted"));
|
|
977
|
-
const timeout = setTimeout(() => finish(new Error(`TypeScript code intelligence worker timed out after ${WORKER_TIMEOUT_MS}ms`)), Math.max(1, timeoutMs));
|
|
978
|
-
timeout.unref?.();
|
|
979
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
980
|
-
worker.once("message", (message) => {
|
|
981
|
-
if (!message || typeof message !== "object" || typeof message.ok !== "boolean") {
|
|
982
|
-
finish(new Error("code-intel worker returned an invalid response"));
|
|
983
|
-
return;
|
|
984
|
-
}
|
|
985
|
-
if ("error" in message) finish(new Error(message.error));
|
|
986
|
-
else finish(void 0, message.result);
|
|
987
|
-
});
|
|
988
|
-
worker.once("error", (error) => finish(error));
|
|
989
|
-
worker.once("exit", (code) => {
|
|
990
|
-
exited = true;
|
|
991
|
-
if (!finishing) finish(new Error(`code-intel worker exited before responding (${code})`));
|
|
992
|
-
});
|
|
993
|
-
});
|
|
994
|
-
}
|
|
995
|
-
async function runWorkerBounded(request, signal) {
|
|
996
|
-
const deadline = Date.now() + WORKER_TIMEOUT_MS;
|
|
997
|
-
const release = await acquireWorkerSlot(deadline, signal);
|
|
998
|
-
try {
|
|
999
|
-
const remaining = deadline - Date.now();
|
|
1000
|
-
if (remaining <= 0) throw new Error(`TypeScript code intelligence exceeded ${WORKER_TIMEOUT_MS}ms including queue wait`);
|
|
1001
|
-
return await runWorker(request, remaining, signal);
|
|
1002
|
-
} finally {
|
|
1003
|
-
release();
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
function createTypeScriptCodeIntelProvider() {
|
|
1007
|
-
return {
|
|
1008
|
-
async run(input, context) {
|
|
1009
|
-
const filePath = context.resolvePath(input.path);
|
|
1010
|
-
if (filePath && !context.isPathAllowed(filePath)) throw new Error(`Path escapes the project root: ${input.path}`);
|
|
1011
|
-
return await runWorkerBounded({ input, projectRoot: context.projectRoot, filePath }, context.signal);
|
|
1012
|
-
}
|
|
1013
|
-
};
|
|
1014
|
-
}
|
|
1015
|
-
function codeIntelErrorMessage(error) {
|
|
1016
|
-
return error instanceof Error ? error.message : String(error);
|
|
1017
|
-
}
|
|
1018
|
-
function shouldFallbackFromTypeScriptProvider(error) {
|
|
1019
|
-
const message = codeIntelErrorMessage(error);
|
|
1020
|
-
if (/aborted/i.test(message)) return false;
|
|
1021
|
-
if (/outside project root|escapes the project root|path escapes/i.test(message)) return false;
|
|
1022
|
-
if (/\bEACCES\b|\bEPERM\b|permission denied/i.test(message)) return false;
|
|
1023
|
-
if (/queue is full|queue wait exceeded/i.test(message)) return false;
|
|
1024
|
-
return /worker|memory limit|compiled code-intel worker/i.test(message);
|
|
1025
|
-
}
|
|
1026
|
-
function createFallbackCodeIntelProvider(primary, fallback = createLightweightCodeIntelProvider()) {
|
|
1027
|
-
return {
|
|
1028
|
-
async run(input, context) {
|
|
1029
|
-
try {
|
|
1030
|
-
return await primary.run(input, context);
|
|
1031
|
-
} catch (error) {
|
|
1032
|
-
const fallbackReason = codeIntelErrorMessage(error);
|
|
1033
|
-
if (!shouldFallbackFromTypeScriptProvider(error)) throw error;
|
|
1034
|
-
const result = await fallback.run(input, context);
|
|
1035
|
-
return {
|
|
1036
|
-
...result,
|
|
1037
|
-
text: `${result.text}
|
|
1038
|
-
|
|
1039
|
-
[code_intel used lightweight fallback: ${fallbackReason}]`,
|
|
1040
|
-
details: {
|
|
1041
|
-
...result.details,
|
|
1042
|
-
provider: "lightweight_fallback",
|
|
1043
|
-
fallbackReason
|
|
1044
|
-
},
|
|
1045
|
-
isError: result.isError
|
|
1046
|
-
};
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
};
|
|
1050
|
-
}
|
|
1051
|
-
function createCodeIntelTool2(options) {
|
|
1052
|
-
return createCodeIntelTool({
|
|
1053
|
-
...options,
|
|
1054
|
-
provider: options.provider ?? createFallbackCodeIntelProvider(createTypeScriptCodeIntelProvider())
|
|
1055
|
-
});
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
993
|
// src/capabilities/rendered-page-reader.ts
|
|
1059
994
|
import { spawn as spawn2 } from "node:child_process";
|
|
1060
995
|
import { createRequire } from "node:module";
|
|
1061
|
-
import * as
|
|
996
|
+
import * as fs from "node:fs";
|
|
1062
997
|
import * as os from "node:os";
|
|
1063
|
-
import * as
|
|
998
|
+
import * as path from "node:path";
|
|
1064
999
|
var require2 = createRequire(import.meta.url);
|
|
1065
1000
|
function resolveAxiCli() {
|
|
1066
|
-
const runtime =
|
|
1067
|
-
if (!
|
|
1001
|
+
const runtime = path.join(getBuiltinDir(), "skills", "chrome-devtools-axi", "chrome-devtools-axi-runtime.js");
|
|
1002
|
+
if (!fs.existsSync(runtime)) throw new Error("Pie's packaged browser runtime is missing. Rebuild or reinstall Pie.");
|
|
1068
1003
|
return runtime;
|
|
1069
1004
|
}
|
|
1070
1005
|
function resolveMcpScript() {
|
|
1071
1006
|
const packageJson = require2.resolve("chrome-devtools-mcp/package.json");
|
|
1072
|
-
return
|
|
1007
|
+
return path.join(path.dirname(packageJson), "build", "src", "bin", "chrome-devtools-mcp.js");
|
|
1073
1008
|
}
|
|
1074
1009
|
function runAxi(args, options = {}) {
|
|
1075
1010
|
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
1076
|
-
return new Promise((
|
|
1011
|
+
return new Promise((resolve3, reject) => {
|
|
1077
1012
|
const child = spawn2(process.execPath, [resolveAxiCli(), ...args], {
|
|
1078
1013
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1079
1014
|
shell: false,
|
|
@@ -1100,7 +1035,7 @@ function runAxi(args, options = {}) {
|
|
|
1100
1035
|
});
|
|
1101
1036
|
child.on("close", (code) => {
|
|
1102
1037
|
clearTimeout(timer);
|
|
1103
|
-
if (code === 0)
|
|
1038
|
+
if (code === 0) resolve3(stdout.trim());
|
|
1104
1039
|
else reject(new Error((stderr || stdout || `chrome-devtools-axi exited with ${code}`).trim()));
|
|
1105
1040
|
});
|
|
1106
1041
|
});
|
|
@@ -1155,11 +1090,11 @@ function cleanStaleScreenshotDirs(retentionMs = 60 * 60 * 1e3) {
|
|
|
1155
1090
|
try {
|
|
1156
1091
|
const tmp = os.tmpdir();
|
|
1157
1092
|
const cutoff = Date.now() - retentionMs;
|
|
1158
|
-
for (const entry of
|
|
1093
|
+
for (const entry of fs.readdirSync(tmp)) {
|
|
1159
1094
|
if (!entry.startsWith("pie-axi-shot-")) continue;
|
|
1160
|
-
const dir =
|
|
1095
|
+
const dir = path.join(tmp, entry);
|
|
1161
1096
|
try {
|
|
1162
|
-
if (
|
|
1097
|
+
if (fs.statSync(dir).mtimeMs < cutoff) fs.rmSync(dir, { recursive: true, force: true });
|
|
1163
1098
|
} catch {
|
|
1164
1099
|
}
|
|
1165
1100
|
}
|
|
@@ -1174,7 +1109,7 @@ function createCliRenderedPageReader() {
|
|
|
1174
1109
|
if (!env.CHROME_DEVTOOLS_AXI_MCP_PATH?.trim()) env.CHROME_DEVTOOLS_AXI_MCP_PATH = resolveMcpScript();
|
|
1175
1110
|
if (!env.CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS) env.CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS = "1";
|
|
1176
1111
|
cleanStaleScreenshotDirs();
|
|
1177
|
-
const screenshotDir =
|
|
1112
|
+
const screenshotDir = fs.mkdtempSync(path.join(os.tmpdir(), "pie-axi-shot-"));
|
|
1178
1113
|
try {
|
|
1179
1114
|
await runAxi(["open", `data:text/html,<title>pie-warm-${session}</title>`], { env });
|
|
1180
1115
|
await runAxi(["open", url], { env });
|
|
@@ -1183,7 +1118,7 @@ function createCliRenderedPageReader() {
|
|
|
1183
1118
|
// --full: eval output is truncated at ~8KB by default, which would
|
|
1184
1119
|
// break JSON parsing and drop title/finalUrl/text on real pages.
|
|
1185
1120
|
runAxi(["eval", "() => JSON.stringify({ title: document.title, href: location.href, text: document.body ? document.body.innerText : '' })", "--full"], { env }),
|
|
1186
|
-
runAxi(["screenshot",
|
|
1121
|
+
runAxi(["screenshot", path.join(screenshotDir, "page.png")], { env }).catch((error) => `screenshot_failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
1187
1122
|
runAxi(["console"], { env }).catch((error) => `console_failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
1188
1123
|
runAxi(["network"], { env }).catch((error) => `network_failed: ${error instanceof Error ? error.message : String(error)}`)
|
|
1189
1124
|
]);
|
|
@@ -1214,8 +1149,8 @@ function createCliRenderedPageReader() {
|
|
|
1214
1149
|
}
|
|
1215
1150
|
|
|
1216
1151
|
// src/capabilities/web-research-health.ts
|
|
1217
|
-
import
|
|
1218
|
-
import
|
|
1152
|
+
import fs2 from "node:fs";
|
|
1153
|
+
import path2 from "node:path";
|
|
1219
1154
|
function isRecord(value) {
|
|
1220
1155
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1221
1156
|
}
|
|
@@ -1237,11 +1172,11 @@ function parseHealthEntry(value) {
|
|
|
1237
1172
|
};
|
|
1238
1173
|
}
|
|
1239
1174
|
function createCliWebResearchHealthStore(configDir) {
|
|
1240
|
-
const filePath =
|
|
1175
|
+
const filePath = path2.join(configDir, "web-research-health.json");
|
|
1241
1176
|
return {
|
|
1242
1177
|
loadProviderHealth: () => {
|
|
1243
1178
|
try {
|
|
1244
|
-
const parsed = JSON.parse(
|
|
1179
|
+
const parsed = JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
1245
1180
|
if (!Array.isArray(parsed)) return [];
|
|
1246
1181
|
return parsed.map(parseHealthEntry).filter((entry) => !!entry);
|
|
1247
1182
|
} catch {
|
|
@@ -1250,8 +1185,8 @@ function createCliWebResearchHealthStore(configDir) {
|
|
|
1250
1185
|
},
|
|
1251
1186
|
saveProviderHealth: (entries) => {
|
|
1252
1187
|
try {
|
|
1253
|
-
|
|
1254
|
-
|
|
1188
|
+
fs2.mkdirSync(path2.dirname(filePath), { recursive: true });
|
|
1189
|
+
fs2.writeFileSync(filePath, JSON.stringify(entries, null, 2));
|
|
1255
1190
|
} catch {
|
|
1256
1191
|
}
|
|
1257
1192
|
}
|
|
@@ -1292,7 +1227,6 @@ function createCliHostCapabilities(cwd, options = {}) {
|
|
|
1292
1227
|
loadProviderHealth: healthStore.loadProviderHealth,
|
|
1293
1228
|
saveProviderHealth: healthStore.saveProviderHealth
|
|
1294
1229
|
});
|
|
1295
|
-
const codeIntelTool = createCodeIntelTool2({ projectRoot: cwd });
|
|
1296
1230
|
const capabilities = [
|
|
1297
1231
|
{
|
|
1298
1232
|
id: "bash",
|
|
@@ -1303,11 +1237,6 @@ function createCliHostCapabilities(cwd, options = {}) {
|
|
|
1303
1237
|
id: "web_research",
|
|
1304
1238
|
description: "Canonical web tool for research, direct URL fetch, and low-level search modes.",
|
|
1305
1239
|
tools: [webResearchTool]
|
|
1306
|
-
},
|
|
1307
|
-
{
|
|
1308
|
-
id: "code_intel",
|
|
1309
|
-
description: "Read-only JS/TS code intelligence for diagnostics, definitions, references, symbols, and hover.",
|
|
1310
|
-
tools: [codeIntelTool]
|
|
1311
1240
|
}
|
|
1312
1241
|
];
|
|
1313
1242
|
return {
|
|
@@ -1317,6 +1246,19 @@ function createCliHostCapabilities(cwd, options = {}) {
|
|
|
1317
1246
|
}
|
|
1318
1247
|
|
|
1319
1248
|
export {
|
|
1249
|
+
getPackageDir,
|
|
1250
|
+
getThemesDir,
|
|
1251
|
+
getBuiltinDir,
|
|
1252
|
+
VERSION,
|
|
1253
|
+
getConfigDir,
|
|
1254
|
+
getAgentDir,
|
|
1255
|
+
getCustomThemesDir,
|
|
1256
|
+
getSettingsPath,
|
|
1257
|
+
getProjectSettingsPath,
|
|
1258
|
+
getSessionsDir,
|
|
1259
|
+
getLogsDir,
|
|
1260
|
+
getRuntimeLogPath,
|
|
1261
|
+
migrateConfigFromAgentDir,
|
|
1320
1262
|
createCliWebResearchHealthStore,
|
|
1321
1263
|
truncateHeadTail,
|
|
1322
1264
|
formatSize,
|