@cydm/pie 2.6.12 → 2.7.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 +85 -3
- 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 +15 -6
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/computer-use-axi/SKILL.md +172 -0
- package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-broker.js} +2122 -708
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-runtime.js +728 -0
- package/dist/builtin/skills/computer-use-axi/package.json +11 -0
- package/dist/chunks/{chunk-PPEWRUMQ.js → chunk-M44CWVDZ.js} +1249 -752
- package/dist/chunks/{chunk-HHNOENEH.js → chunk-NJFPBU36.js} +14 -1
- package/dist/chunks/{chunk-AAEBH6KX.js → chunk-W74NRSRV.js} +239 -231
- package/dist/chunks/{chunk-7B4IIBVS.js → chunk-XUROMYTT.js} +1747 -14
- package/dist/chunks/{src-OWQI5M6W.js → src-C4KA4G75.js} +2 -2
- package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-A5ZELKNG.js} +1 -1
- package/dist/cli.js +863 -305
- package/models.schema.json +57 -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,196 @@
|
|
|
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-
|
|
9
|
+
} from "./chunk-M44CWVDZ.js";
|
|
12
10
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "./chunk-5353DEEC.js";
|
|
11
|
+
getLogger
|
|
12
|
+
} from "./chunk-XUROMYTT.js";
|
|
16
13
|
import {
|
|
17
14
|
Type
|
|
18
15
|
} from "./chunk-XXGYUYXI.js";
|
|
19
16
|
|
|
17
|
+
// src/config.ts
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, renameSync } from "fs";
|
|
19
|
+
import { homedir } from "os";
|
|
20
|
+
import { dirname, join } from "path";
|
|
21
|
+
import { fileURLToPath } from "url";
|
|
22
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
23
|
+
var __dirname = dirname(__filename);
|
|
24
|
+
var isBunRuntime = !!process.versions.bun;
|
|
25
|
+
function getPackageDir() {
|
|
26
|
+
const envDir = process.env.PIE_PACKAGE_DIR;
|
|
27
|
+
if (envDir) {
|
|
28
|
+
if (envDir === "~") return homedir();
|
|
29
|
+
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
|
|
30
|
+
return envDir;
|
|
31
|
+
}
|
|
32
|
+
let dir = __dirname;
|
|
33
|
+
while (dir !== dirname(dir)) {
|
|
34
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
35
|
+
return dir;
|
|
36
|
+
}
|
|
37
|
+
dir = dirname(dir);
|
|
38
|
+
}
|
|
39
|
+
return __dirname;
|
|
40
|
+
}
|
|
41
|
+
function getThemesDir() {
|
|
42
|
+
const packageDir = getPackageDir();
|
|
43
|
+
const srcOrDist = existsSync(join(packageDir, "src")) ? "src" : "dist";
|
|
44
|
+
return join(packageDir, srcOrDist, "theme");
|
|
45
|
+
}
|
|
46
|
+
function getBuiltinDir() {
|
|
47
|
+
const packageDir = getPackageDir();
|
|
48
|
+
const distBuiltinDir = join(packageDir, "dist", "builtin");
|
|
49
|
+
if (existsSync(distBuiltinDir)) {
|
|
50
|
+
return distBuiltinDir;
|
|
51
|
+
}
|
|
52
|
+
return join(packageDir, "builtin");
|
|
53
|
+
}
|
|
54
|
+
function getPackageJsonPath() {
|
|
55
|
+
return join(getPackageDir(), "package.json");
|
|
56
|
+
}
|
|
57
|
+
var pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8"));
|
|
58
|
+
var CONFIG_DIR_NAME = ".pie";
|
|
59
|
+
var VERSION = pkg.version;
|
|
60
|
+
var ENV_AGENT_DIR = "PIE_CODING_AGENT_DIR";
|
|
61
|
+
function getConfigDir() {
|
|
62
|
+
const envDir = process.env[ENV_AGENT_DIR];
|
|
63
|
+
if (envDir) {
|
|
64
|
+
if (envDir === "~") return homedir();
|
|
65
|
+
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
|
|
66
|
+
return envDir;
|
|
67
|
+
}
|
|
68
|
+
return join(homedir(), CONFIG_DIR_NAME);
|
|
69
|
+
}
|
|
70
|
+
function getAgentDir() {
|
|
71
|
+
return getConfigDir();
|
|
72
|
+
}
|
|
73
|
+
function getCustomThemesDir() {
|
|
74
|
+
return join(getConfigDir(), "themes");
|
|
75
|
+
}
|
|
76
|
+
function getSettingsPath() {
|
|
77
|
+
return join(getConfigDir(), "settings.json");
|
|
78
|
+
}
|
|
79
|
+
function getProjectSettingsPath(cwd) {
|
|
80
|
+
return join(cwd, CONFIG_DIR_NAME, "settings.json");
|
|
81
|
+
}
|
|
82
|
+
function getSessionsDir() {
|
|
83
|
+
return join(getConfigDir(), "sessions");
|
|
84
|
+
}
|
|
85
|
+
function getLogsDir() {
|
|
86
|
+
return join(getConfigDir(), "logs");
|
|
87
|
+
}
|
|
88
|
+
function getRuntimeLogPath() {
|
|
89
|
+
return join(getLogsDir(), "pie-cli.log");
|
|
90
|
+
}
|
|
91
|
+
function migrateConfigFromAgentDir() {
|
|
92
|
+
const oldAgentDir = join(homedir(), CONFIG_DIR_NAME, "agent");
|
|
93
|
+
const newConfigDir = getConfigDir();
|
|
94
|
+
if (!existsSync(oldAgentDir)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!existsSync(newConfigDir)) {
|
|
98
|
+
mkdirSync(newConfigDir, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
const filesToMigrate = [
|
|
101
|
+
"keybindings.json",
|
|
102
|
+
"settings.json",
|
|
103
|
+
"pie-debug.log"
|
|
104
|
+
];
|
|
105
|
+
for (const file of filesToMigrate) {
|
|
106
|
+
const oldPath = join(oldAgentDir, file);
|
|
107
|
+
const newPath = file === "pie-debug.log" ? getRuntimeLogPath() : join(newConfigDir, file);
|
|
108
|
+
if (existsSync(oldPath) && !existsSync(newPath)) {
|
|
109
|
+
try {
|
|
110
|
+
if (file === "pie-debug.log") {
|
|
111
|
+
mkdirSync(getLogsDir(), { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
renameSync(oldPath, newPath);
|
|
114
|
+
console.log(`[Config] Migrated ${file} to ${newPath}`);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const oldThemesDir = join(oldAgentDir, "themes");
|
|
120
|
+
const newThemesDir = getCustomThemesDir();
|
|
121
|
+
if (existsSync(oldThemesDir) && !existsSync(newThemesDir)) {
|
|
122
|
+
try {
|
|
123
|
+
renameSync(oldThemesDir, newThemesDir);
|
|
124
|
+
console.log(`[Config] Migrated themes to ${newThemesDir}`);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/runtime/transport-diagnostics.ts
|
|
131
|
+
function numberOrDash(value) {
|
|
132
|
+
return typeof value === "number" ? String(value) : "-";
|
|
133
|
+
}
|
|
134
|
+
function formatTransportLifecycle(event) {
|
|
135
|
+
const parts = [
|
|
136
|
+
`transport=${event.transport}`,
|
|
137
|
+
`id=${event.localRequestId}`,
|
|
138
|
+
`phase=${event.phase}`,
|
|
139
|
+
`gen=${event.requestGeneration}${event.connectionGeneration !== void 0 ? `/c${event.connectionGeneration}` : ""}`,
|
|
140
|
+
`reused=${event.reusedConnection ? "yes" : "no"}`,
|
|
141
|
+
`ageMs=${numberOrDash(event.requestAgeMs)}`,
|
|
142
|
+
`lastReceiveAgeMs=${numberOrDash(event.lastReceiveAgeMs)}`
|
|
143
|
+
];
|
|
144
|
+
if (event.timeoutKind) parts.push(`timeoutKind=${event.timeoutKind}`);
|
|
145
|
+
if (event.budgets) {
|
|
146
|
+
const budgets = Object.entries(event.budgets).filter(([, value]) => typeof value === "number").map(([key, value]) => `${key}=${value}`);
|
|
147
|
+
if (budgets.length > 0) parts.push(`budgets(${budgets.join(",")})`);
|
|
148
|
+
}
|
|
149
|
+
if (event.receivedMessageCount !== void 0) parts.push(`messages=${event.receivedMessageCount}`);
|
|
150
|
+
if (event.sawResponseCreated !== void 0) parts.push(`sawCreated=${event.sawResponseCreated ? "yes" : "no"}`);
|
|
151
|
+
if (event.sawModelContent !== void 0) parts.push(`sawContent=${event.sawModelContent ? "yes" : "no"}`);
|
|
152
|
+
if (event.submissionAttempted !== void 0) parts.push(`submitted=${event.submissionAttempted ? "yes" : "no"}`);
|
|
153
|
+
if (event.terminalAccepted !== void 0) parts.push(`terminal=${event.terminalAccepted ? "yes" : "no"}`);
|
|
154
|
+
if (event.retryAllowed !== void 0) parts.push(`retryAllowed=${event.retryAllowed ? "yes" : "no"}`);
|
|
155
|
+
if (event.retryDecision) parts.push(`retryDecision=${event.retryDecision}`);
|
|
156
|
+
if (event.cancelSource) parts.push(`cancelSource=${event.cancelSource}`);
|
|
157
|
+
if (event.cleanupOutcome) parts.push(`cleanup=${event.cleanupOutcome}`);
|
|
158
|
+
if (event.singleAttempt) parts.push(`singleAttempt=${event.singleAttempt}`);
|
|
159
|
+
return `[transport] ${parts.join(" ")}`;
|
|
160
|
+
}
|
|
161
|
+
function createTransportDiagnosticsStreamFn(base, sink) {
|
|
162
|
+
return (model, context, options) => base(model, context, {
|
|
163
|
+
...options,
|
|
164
|
+
onTransportLifecycle: (event) => {
|
|
165
|
+
try {
|
|
166
|
+
options?.onTransportLifecycle?.(event);
|
|
167
|
+
sink(event);
|
|
168
|
+
} catch {
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
var logTransportLifecycle = (event) => {
|
|
174
|
+
const logger = getLogger().child({ module: "cli.transport" });
|
|
175
|
+
const line = formatTransportLifecycle(event);
|
|
176
|
+
if (event.phase === "timeout" || event.cleanupOutcome === "request_abandoned") {
|
|
177
|
+
logger.warn(line, { transportLifecycle: event });
|
|
178
|
+
} else {
|
|
179
|
+
logger.debug(line, { transportLifecycle: event });
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
function createTraceTransportSink(noteRuntimeEvent) {
|
|
183
|
+
return (event) => {
|
|
184
|
+
noteRuntimeEvent("transport_lifecycle", event);
|
|
185
|
+
logTransportLifecycle(event);
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
20
189
|
// src/capabilities/bash/index.ts
|
|
21
190
|
import { spawn } from "child_process";
|
|
22
|
-
import { closeSync, createWriteStream, existsSync, openSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
191
|
+
import { closeSync, createWriteStream, existsSync as existsSync2, openSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
23
192
|
import { tmpdir } from "os";
|
|
24
|
-
import { join, resolve } from "path";
|
|
193
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
25
194
|
import { createHash, randomBytes } from "crypto";
|
|
26
195
|
|
|
27
196
|
// src/capabilities/bash/truncate.ts
|
|
@@ -275,7 +444,7 @@ async function requestHighRiskConfirmation(request) {
|
|
|
275
444
|
return response.type === "confirm" && response.confirmed === true;
|
|
276
445
|
}
|
|
277
446
|
function validateWorkingDirectory(cwd) {
|
|
278
|
-
if (!
|
|
447
|
+
if (!existsSync2(cwd)) {
|
|
279
448
|
throw new Error(`Invalid bash cwd: ${cwd} does not exist. Use the current workspace path or pass an existing directory in cwd.`);
|
|
280
449
|
}
|
|
281
450
|
let stat;
|
|
@@ -290,11 +459,11 @@ function validateWorkingDirectory(cwd) {
|
|
|
290
459
|
}
|
|
291
460
|
function normalizeWorkingDirectory(cwd, defaultCwd) {
|
|
292
461
|
const requestedCwd = typeof cwd === "string" && cwd.trim().length > 0 ? cwd.trim() : void 0;
|
|
293
|
-
return
|
|
462
|
+
return resolve2(requestedCwd ?? defaultCwd ?? process.cwd());
|
|
294
463
|
}
|
|
295
464
|
function getTempFilePath() {
|
|
296
465
|
const id = randomBytes(8).toString("hex");
|
|
297
|
-
return
|
|
466
|
+
return join2(tmpdir(), `pie-bash-${id}.log`);
|
|
298
467
|
}
|
|
299
468
|
var retainedOutputArtifacts = /* @__PURE__ */ new Set();
|
|
300
469
|
function getErrorCode(error) {
|
|
@@ -304,15 +473,15 @@ function getErrorCode(error) {
|
|
|
304
473
|
}
|
|
305
474
|
function createPrivateOutputArtifact() {
|
|
306
475
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
307
|
-
const
|
|
476
|
+
const path3 = getTempFilePath();
|
|
308
477
|
try {
|
|
309
|
-
const fd = openSync(
|
|
310
|
-
retainedOutputArtifacts.add(
|
|
478
|
+
const fd = openSync(path3, "wx", 384);
|
|
479
|
+
retainedOutputArtifacts.add(path3);
|
|
311
480
|
try {
|
|
312
|
-
return { path:
|
|
481
|
+
return { path: path3, stream: createWriteStream(path3, { fd, autoClose: true }) };
|
|
313
482
|
} catch (error) {
|
|
314
483
|
closeSync(fd);
|
|
315
|
-
removeOutputArtifact(
|
|
484
|
+
removeOutputArtifact(path3);
|
|
316
485
|
throw error;
|
|
317
486
|
}
|
|
318
487
|
} catch (error) {
|
|
@@ -321,34 +490,34 @@ function createPrivateOutputArtifact() {
|
|
|
321
490
|
}
|
|
322
491
|
throw new Error("Unable to allocate a private bash output artifact.");
|
|
323
492
|
}
|
|
324
|
-
function removeOutputArtifact(
|
|
325
|
-
if (!
|
|
493
|
+
function removeOutputArtifact(path3) {
|
|
494
|
+
if (!path3) return;
|
|
326
495
|
try {
|
|
327
|
-
unlinkSync(
|
|
496
|
+
unlinkSync(path3);
|
|
328
497
|
} catch (error) {
|
|
329
498
|
if (getErrorCode(error) !== "ENOENT") throw error;
|
|
330
499
|
}
|
|
331
|
-
retainedOutputArtifacts.delete(
|
|
500
|
+
retainedOutputArtifacts.delete(path3);
|
|
332
501
|
}
|
|
333
|
-
function discardOutputArtifact(
|
|
502
|
+
function discardOutputArtifact(path3, stream) {
|
|
334
503
|
if (stream && !stream.closed) {
|
|
335
504
|
stream.once("close", () => {
|
|
336
505
|
try {
|
|
337
|
-
removeOutputArtifact(
|
|
506
|
+
removeOutputArtifact(path3);
|
|
338
507
|
} catch {
|
|
339
508
|
}
|
|
340
509
|
});
|
|
341
510
|
stream.destroy();
|
|
342
511
|
}
|
|
343
512
|
try {
|
|
344
|
-
removeOutputArtifact(
|
|
513
|
+
removeOutputArtifact(path3);
|
|
345
514
|
} catch {
|
|
346
515
|
}
|
|
347
516
|
}
|
|
348
517
|
function cleanupBashOutputArtifacts() {
|
|
349
|
-
for (const
|
|
518
|
+
for (const path3 of [...retainedOutputArtifacts]) {
|
|
350
519
|
try {
|
|
351
|
-
removeOutputArtifact(
|
|
520
|
+
removeOutputArtifact(path3);
|
|
352
521
|
} catch {
|
|
353
522
|
}
|
|
354
523
|
}
|
|
@@ -356,7 +525,7 @@ function cleanupBashOutputArtifacts() {
|
|
|
356
525
|
process.once("exit", cleanupBashOutputArtifacts);
|
|
357
526
|
function finishTempFileStream(stream) {
|
|
358
527
|
if (!stream || stream.closed) return Promise.resolve();
|
|
359
|
-
return new Promise((
|
|
528
|
+
return new Promise((resolve3, reject) => {
|
|
360
529
|
let done = false;
|
|
361
530
|
const timer = setTimeout(() => {
|
|
362
531
|
stream.destroy(new Error("Timed out flushing shell output."));
|
|
@@ -370,7 +539,7 @@ function finishTempFileStream(stream) {
|
|
|
370
539
|
if (done) return;
|
|
371
540
|
done = true;
|
|
372
541
|
cleanup();
|
|
373
|
-
|
|
542
|
+
resolve3();
|
|
374
543
|
};
|
|
375
544
|
const onError = (error) => {
|
|
376
545
|
if (done) return;
|
|
@@ -549,7 +718,7 @@ function createBashTool(defaultCwd, options) {
|
|
|
549
718
|
}
|
|
550
719
|
const timeoutPolicy = resolveTimeoutPolicy(timeout, risk.commandClass);
|
|
551
720
|
const timeoutMs = timeoutPolicy.effectiveSeconds * 1e3;
|
|
552
|
-
return new Promise((
|
|
721
|
+
return new Promise((resolve3, reject) => {
|
|
553
722
|
if (signal?.aborted) {
|
|
554
723
|
reject(new Error("Operation aborted"));
|
|
555
724
|
return;
|
|
@@ -599,7 +768,7 @@ function createBashTool(defaultCwd, options) {
|
|
|
599
768
|
const child = (options?.spawnProcess ?? spawn)(spawnCommand.file, spawnCommand.args, {
|
|
600
769
|
shell: spawnCommand.shell,
|
|
601
770
|
cwd: workingDir,
|
|
602
|
-
env: process.env,
|
|
771
|
+
env: { ...process.env, ...options?.getEnv?.() ?? {} },
|
|
603
772
|
detached: process.platform !== "win32",
|
|
604
773
|
windowsHide: true
|
|
605
774
|
});
|
|
@@ -763,10 +932,10 @@ ${fullOutput}`;
|
|
|
763
932
|
}
|
|
764
933
|
let outputText = truncation.content || "(no output)";
|
|
765
934
|
if (truncation.truncated && !tempFilePath) {
|
|
766
|
-
const
|
|
767
|
-
const fd = openSync(
|
|
768
|
-
tempFilePath =
|
|
769
|
-
retainedOutputArtifacts.add(
|
|
935
|
+
const path3 = getTempFilePath();
|
|
936
|
+
const fd = openSync(path3, "wx", 384);
|
|
937
|
+
tempFilePath = path3;
|
|
938
|
+
retainedOutputArtifacts.add(path3);
|
|
770
939
|
try {
|
|
771
940
|
writeFileSync(fd, fullOutput, "utf-8");
|
|
772
941
|
} finally {
|
|
@@ -857,7 +1026,7 @@ ${commandNonzeroHint}`;
|
|
|
857
1026
|
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
1027
|
}
|
|
859
1028
|
const content = [{ type: "text", text: outputText }];
|
|
860
|
-
|
|
1029
|
+
resolve3({ content, details, isError: outcome.toolFailure });
|
|
861
1030
|
} catch (error) {
|
|
862
1031
|
discardOutputArtifact(tempFilePath, tempFileStream);
|
|
863
1032
|
reject(error);
|
|
@@ -883,197 +1052,25 @@ ${commandNonzeroHint}`;
|
|
|
883
1052
|
};
|
|
884
1053
|
}
|
|
885
1054
|
|
|
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
1055
|
// src/capabilities/rendered-page-reader.ts
|
|
1059
1056
|
import { spawn as spawn2 } from "node:child_process";
|
|
1060
1057
|
import { createRequire } from "node:module";
|
|
1061
|
-
import * as
|
|
1058
|
+
import * as fs from "node:fs";
|
|
1062
1059
|
import * as os from "node:os";
|
|
1063
|
-
import * as
|
|
1060
|
+
import * as path from "node:path";
|
|
1064
1061
|
var require2 = createRequire(import.meta.url);
|
|
1065
1062
|
function resolveAxiCli() {
|
|
1066
|
-
const runtime =
|
|
1067
|
-
if (!
|
|
1063
|
+
const runtime = path.join(getBuiltinDir(), "skills", "chrome-devtools-axi", "chrome-devtools-axi-runtime.js");
|
|
1064
|
+
if (!fs.existsSync(runtime)) throw new Error("Pie's packaged browser runtime is missing. Rebuild or reinstall Pie.");
|
|
1068
1065
|
return runtime;
|
|
1069
1066
|
}
|
|
1070
1067
|
function resolveMcpScript() {
|
|
1071
1068
|
const packageJson = require2.resolve("chrome-devtools-mcp/package.json");
|
|
1072
|
-
return
|
|
1069
|
+
return path.join(path.dirname(packageJson), "build", "src", "bin", "chrome-devtools-mcp.js");
|
|
1073
1070
|
}
|
|
1074
1071
|
function runAxi(args, options = {}) {
|
|
1075
1072
|
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
1076
|
-
return new Promise((
|
|
1073
|
+
return new Promise((resolve3, reject) => {
|
|
1077
1074
|
const child = spawn2(process.execPath, [resolveAxiCli(), ...args], {
|
|
1078
1075
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1079
1076
|
shell: false,
|
|
@@ -1100,7 +1097,7 @@ function runAxi(args, options = {}) {
|
|
|
1100
1097
|
});
|
|
1101
1098
|
child.on("close", (code) => {
|
|
1102
1099
|
clearTimeout(timer);
|
|
1103
|
-
if (code === 0)
|
|
1100
|
+
if (code === 0) resolve3(stdout.trim());
|
|
1104
1101
|
else reject(new Error((stderr || stdout || `chrome-devtools-axi exited with ${code}`).trim()));
|
|
1105
1102
|
});
|
|
1106
1103
|
});
|
|
@@ -1155,11 +1152,11 @@ function cleanStaleScreenshotDirs(retentionMs = 60 * 60 * 1e3) {
|
|
|
1155
1152
|
try {
|
|
1156
1153
|
const tmp = os.tmpdir();
|
|
1157
1154
|
const cutoff = Date.now() - retentionMs;
|
|
1158
|
-
for (const entry of
|
|
1155
|
+
for (const entry of fs.readdirSync(tmp)) {
|
|
1159
1156
|
if (!entry.startsWith("pie-axi-shot-")) continue;
|
|
1160
|
-
const dir =
|
|
1157
|
+
const dir = path.join(tmp, entry);
|
|
1161
1158
|
try {
|
|
1162
|
-
if (
|
|
1159
|
+
if (fs.statSync(dir).mtimeMs < cutoff) fs.rmSync(dir, { recursive: true, force: true });
|
|
1163
1160
|
} catch {
|
|
1164
1161
|
}
|
|
1165
1162
|
}
|
|
@@ -1174,7 +1171,7 @@ function createCliRenderedPageReader() {
|
|
|
1174
1171
|
if (!env.CHROME_DEVTOOLS_AXI_MCP_PATH?.trim()) env.CHROME_DEVTOOLS_AXI_MCP_PATH = resolveMcpScript();
|
|
1175
1172
|
if (!env.CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS) env.CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS = "1";
|
|
1176
1173
|
cleanStaleScreenshotDirs();
|
|
1177
|
-
const screenshotDir =
|
|
1174
|
+
const screenshotDir = fs.mkdtempSync(path.join(os.tmpdir(), "pie-axi-shot-"));
|
|
1178
1175
|
try {
|
|
1179
1176
|
await runAxi(["open", `data:text/html,<title>pie-warm-${session}</title>`], { env });
|
|
1180
1177
|
await runAxi(["open", url], { env });
|
|
@@ -1183,7 +1180,7 @@ function createCliRenderedPageReader() {
|
|
|
1183
1180
|
// --full: eval output is truncated at ~8KB by default, which would
|
|
1184
1181
|
// break JSON parsing and drop title/finalUrl/text on real pages.
|
|
1185
1182
|
runAxi(["eval", "() => JSON.stringify({ title: document.title, href: location.href, text: document.body ? document.body.innerText : '' })", "--full"], { env }),
|
|
1186
|
-
runAxi(["screenshot",
|
|
1183
|
+
runAxi(["screenshot", path.join(screenshotDir, "page.png")], { env }).catch((error) => `screenshot_failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
1187
1184
|
runAxi(["console"], { env }).catch((error) => `console_failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
1188
1185
|
runAxi(["network"], { env }).catch((error) => `network_failed: ${error instanceof Error ? error.message : String(error)}`)
|
|
1189
1186
|
]);
|
|
@@ -1214,8 +1211,8 @@ function createCliRenderedPageReader() {
|
|
|
1214
1211
|
}
|
|
1215
1212
|
|
|
1216
1213
|
// src/capabilities/web-research-health.ts
|
|
1217
|
-
import
|
|
1218
|
-
import
|
|
1214
|
+
import fs2 from "node:fs";
|
|
1215
|
+
import path2 from "node:path";
|
|
1219
1216
|
function isRecord(value) {
|
|
1220
1217
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1221
1218
|
}
|
|
@@ -1237,11 +1234,11 @@ function parseHealthEntry(value) {
|
|
|
1237
1234
|
};
|
|
1238
1235
|
}
|
|
1239
1236
|
function createCliWebResearchHealthStore(configDir) {
|
|
1240
|
-
const filePath =
|
|
1237
|
+
const filePath = path2.join(configDir, "web-research-health.json");
|
|
1241
1238
|
return {
|
|
1242
1239
|
loadProviderHealth: () => {
|
|
1243
1240
|
try {
|
|
1244
|
-
const parsed = JSON.parse(
|
|
1241
|
+
const parsed = JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
1245
1242
|
if (!Array.isArray(parsed)) return [];
|
|
1246
1243
|
return parsed.map(parseHealthEntry).filter((entry) => !!entry);
|
|
1247
1244
|
} catch {
|
|
@@ -1250,8 +1247,8 @@ function createCliWebResearchHealthStore(configDir) {
|
|
|
1250
1247
|
},
|
|
1251
1248
|
saveProviderHealth: (entries) => {
|
|
1252
1249
|
try {
|
|
1253
|
-
|
|
1254
|
-
|
|
1250
|
+
fs2.mkdirSync(path2.dirname(filePath), { recursive: true });
|
|
1251
|
+
fs2.writeFileSync(filePath, JSON.stringify(entries, null, 2));
|
|
1255
1252
|
} catch {
|
|
1256
1253
|
}
|
|
1257
1254
|
}
|
|
@@ -1260,7 +1257,7 @@ function createCliWebResearchHealthStore(configDir) {
|
|
|
1260
1257
|
|
|
1261
1258
|
// src/capabilities/index.ts
|
|
1262
1259
|
function createCliHostCapabilities(cwd, options = {}) {
|
|
1263
|
-
const bashTool = createBashTool(cwd);
|
|
1260
|
+
const bashTool = createBashTool(cwd, options.getBashEnv ? { getEnv: options.getBashEnv } : void 0);
|
|
1264
1261
|
const healthStore = createCliWebResearchHealthStore(options.configDir ?? getConfigDir());
|
|
1265
1262
|
const webSearchTool = createSharedWebSearchTool({
|
|
1266
1263
|
getModel: options.getModel ?? (() => void 0),
|
|
@@ -1292,7 +1289,6 @@ function createCliHostCapabilities(cwd, options = {}) {
|
|
|
1292
1289
|
loadProviderHealth: healthStore.loadProviderHealth,
|
|
1293
1290
|
saveProviderHealth: healthStore.saveProviderHealth
|
|
1294
1291
|
});
|
|
1295
|
-
const codeIntelTool = createCodeIntelTool2({ projectRoot: cwd });
|
|
1296
1292
|
const capabilities = [
|
|
1297
1293
|
{
|
|
1298
1294
|
id: "bash",
|
|
@@ -1303,11 +1299,6 @@ function createCliHostCapabilities(cwd, options = {}) {
|
|
|
1303
1299
|
id: "web_research",
|
|
1304
1300
|
description: "Canonical web tool for research, direct URL fetch, and low-level search modes.",
|
|
1305
1301
|
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
1302
|
}
|
|
1312
1303
|
];
|
|
1313
1304
|
return {
|
|
@@ -1317,10 +1308,27 @@ function createCliHostCapabilities(cwd, options = {}) {
|
|
|
1317
1308
|
}
|
|
1318
1309
|
|
|
1319
1310
|
export {
|
|
1311
|
+
getPackageDir,
|
|
1312
|
+
getThemesDir,
|
|
1313
|
+
getBuiltinDir,
|
|
1314
|
+
VERSION,
|
|
1315
|
+
getConfigDir,
|
|
1316
|
+
getAgentDir,
|
|
1317
|
+
getCustomThemesDir,
|
|
1318
|
+
getSettingsPath,
|
|
1319
|
+
getProjectSettingsPath,
|
|
1320
|
+
getSessionsDir,
|
|
1321
|
+
getLogsDir,
|
|
1322
|
+
getRuntimeLogPath,
|
|
1323
|
+
migrateConfigFromAgentDir,
|
|
1320
1324
|
createCliWebResearchHealthStore,
|
|
1321
1325
|
truncateHeadTail,
|
|
1322
1326
|
formatSize,
|
|
1323
1327
|
cleanupBashOutputArtifacts,
|
|
1324
1328
|
createBashTool,
|
|
1329
|
+
formatTransportLifecycle,
|
|
1330
|
+
createTransportDiagnosticsStreamFn,
|
|
1331
|
+
logTransportLifecycle,
|
|
1332
|
+
createTraceTransportSink,
|
|
1325
1333
|
createCliHostCapabilities
|
|
1326
1334
|
};
|