@cydm/pie 2.5.1 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/computer-use/index.js +17 -2
- 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/MacOS/pie-computer-use +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/x64/pie-computer-use +0 -0
- package/dist/builtin/extensions/computer-use/scripts/setup-helper.mjs +90 -9
- package/dist/builtin/extensions/mcp-adapter/index.js +111 -25
- package/dist/builtin/extensions/plan-mode/index.js +3 -3
- package/dist/builtin/extensions/subagent/index.js +4 -4
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-bridge.js +5 -0
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-cli.js +5 -2
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-runtime.js +1 -1
- package/dist/builtin/skills/chrome-devtools-axi/{cli-P4VG6ZZG.js → cli-EJ5MQZNA.js} +76 -27
- package/dist/builtin/skills/tui-use/tui-use-cli.cjs +25 -9
- package/dist/builtin/skills/tui-use/tui-use-daemon.cjs +7 -1
- package/dist/chunks/{chunk-REP6QANY.js → chunk-LO2V5DZZ.js} +38 -6
- package/dist/chunks/{chunk-N2MK46AE.js → chunk-M4OJARWJ.js} +7 -2
- package/dist/chunks/{chunk-ZKHMNEXL.js → chunk-RTTGO2A6.js} +1 -1
- package/dist/chunks/{chunk-YRXXRLMQ.js → chunk-UD7KYQ6J.js} +9 -0
- package/dist/chunks/{src-SXUQ7OY6.js → src-33WRCQWX.js} +2 -2
- package/dist/chunks/{test-stream-OD3B57AS.js → test-stream-LFR6GSKQ.js} +1 -1
- package/dist/cli.js +62 -14
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createAskUserCapability
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
5
|
-
import "../../../chunks/chunk-
|
|
6
|
-
import "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-LO2V5DZZ.js";
|
|
5
|
+
import "../../../chunks/chunk-RTTGO2A6.js";
|
|
6
|
+
import "../../../chunks/chunk-UD7KYQ6J.js";
|
|
7
7
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
8
8
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
9
9
|
|
|
@@ -3787,8 +3787,23 @@ function wireableInputDescendants(node) {
|
|
|
3787
3787
|
visit(node);
|
|
3788
3788
|
return matches;
|
|
3789
3789
|
}
|
|
3790
|
+
var FOCUS_CHANGING_KEYS = /* @__PURE__ */ new Set(["TAB", "SHIFT+TAB", "ENTER", "RETURN", "SPACE", "UP", "DOWN", "LEFT", "RIGHT", "UP_ARROW", "DOWN_ARROW", "LEFT_ARROW", "RIGHT_ARROW", "ESC", "ESCAPE", "HOME", "END", "PAGE_UP", "PAGE_DOWN", "PAGEDOWN", "PAGEUP"]);
|
|
3791
|
+
function isFocusChangingKey(keys2) {
|
|
3792
|
+
const list = typeof keys2 === "string" ? [keys2] : Array.isArray(keys2) ? keys2 : [];
|
|
3793
|
+
for (const raw of list) {
|
|
3794
|
+
if (typeof raw !== "string") continue;
|
|
3795
|
+
const token = raw.trim().toUpperCase().split("+").pop() ?? "";
|
|
3796
|
+
if (FOCUS_CHANGING_KEYS.has(token) || FOCUS_CHANGING_KEYS.has(raw.trim().toUpperCase())) return true;
|
|
3797
|
+
}
|
|
3798
|
+
return false;
|
|
3799
|
+
}
|
|
3790
3800
|
function recordActionFocus(action, state, node, coordinateFocus = false) {
|
|
3791
|
-
if (
|
|
3801
|
+
if (action.action === "keypress" && !action.ref && isFocusChangingKey(action.keys)) {
|
|
3802
|
+
state.currentFocus = true;
|
|
3803
|
+
state.focusRef = void 0;
|
|
3804
|
+
return;
|
|
3805
|
+
}
|
|
3806
|
+
if (!["click", "press", "keypress", "typeText"].includes(action.action) || !action.ref && action.action !== "click" && action.action !== "press" && !coordinateFocus) return;
|
|
3792
3807
|
state.currentFocus = Boolean(node?.isTextInput && !node.pictureOnly) || coordinateFocus;
|
|
3793
3808
|
state.focusRef = node?.isTextInput && node.wireRef && !node.pictureOnly ? node.ref : void 0;
|
|
3794
3809
|
if (!state.currentFocus && node && !node.pictureOnly && action.ref && (action.action === "click" || action.action === "press") && containsEditable(node)) {
|
|
@@ -8546,7 +8561,7 @@ async function dispatchUiAction(action, target, look, headless, state, signal) {
|
|
|
8546
8561
|
}
|
|
8547
8562
|
const trace = await helperAct(target, prepared, headless, signal);
|
|
8548
8563
|
if (!headless) {
|
|
8549
|
-
const coordinateFocus = prepared.action === "click" && "x" in prepared.target;
|
|
8564
|
+
const coordinateFocus = (prepared.action === "click" || prepared.action === "press") && "x" in prepared.target;
|
|
8550
8565
|
const node = action.ref ? outlineNodeByRef(action.ref.trim()) : coordinateFocus ? editorAtPoint(currentOutlineOrThrow().nodes, action.x, action.y) : void 0;
|
|
8551
8566
|
recordActionFocus(action, state, node, coordinateFocus);
|
|
8552
8567
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -313,19 +313,100 @@ async function installPrebuiltHelperApp(sourceAppPath) {
|
|
|
313
313
|
const existingInfo = await fs.readFile(path.join(helperAppPath, "Contents", "Info.plist"), "utf8").catch(() => undefined);
|
|
314
314
|
const sourceInfo = await fs.readFile(sourceInfoPath, "utf8");
|
|
315
315
|
if (existingExecutable?.equals(sourceExecutable) && existingInfo === sourceInfo) {
|
|
316
|
-
|
|
317
|
-
|
|
316
|
+
// Byte equality alone is NOT sufficient for the no-change shortcut: a
|
|
317
|
+
// damaged/missing _CodeSignature (CodeResources tampered or deleted
|
|
318
|
+
// around an otherwise-identical executable) would otherwise survive
|
|
319
|
+
// every repair invocation. The existing bundle must still verify.
|
|
320
|
+
let existingVerifies = false;
|
|
321
|
+
try {
|
|
322
|
+
await run("codesign", ["--verify", "--strict", helperAppPath]);
|
|
323
|
+
existingVerifies = true;
|
|
324
|
+
} catch {
|
|
325
|
+
// Fall through to the replacement path below, which re-installs (and
|
|
326
|
+
// re-verifies) a complete bundle.
|
|
327
|
+
}
|
|
328
|
+
if (existingVerifies) {
|
|
329
|
+
await registerHelperApp();
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
318
332
|
}
|
|
319
333
|
// The sealed bundle must arrive intact — a broken signature would burn
|
|
320
334
|
// the user's TCC grants on an identity that can never validate.
|
|
321
335
|
await run("codesign", ["--verify", "--strict", sourceAppPath]);
|
|
322
|
-
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
|
|
336
|
+
// Sweep staging directories abandoned by crashed installers (the finally
|
|
337
|
+
// below only runs on ordinary unwinding). Reclaim is ownership-aware:
|
|
338
|
+
// the staging name embeds its creator's PID, and ONLY a demonstrably dead
|
|
339
|
+
// owner (ESRCH on signal-0) plus age beyond a generous slow-install window
|
|
340
|
+
// makes a stage garbage — mtime alone is not ownership evidence, so a
|
|
341
|
+
// live/slow installer's stage is never touched.
|
|
342
|
+
try {
|
|
343
|
+
const parent = path.dirname(helperAppPath);
|
|
344
|
+
const base = path.basename(helperAppPath);
|
|
345
|
+
const entries = await fs.readdir(parent);
|
|
346
|
+
const cutoff = Date.now() - 60 * 60 * 1000;
|
|
347
|
+
for (const entry of entries) {
|
|
348
|
+
// Exact staging format <app>.staged-<pid>-<ts36>: anything else that
|
|
349
|
+
// merely contains ".staged-" is not ours to touch.
|
|
350
|
+
const match = new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\.staged-(\\d+)-[0-9a-z]+$`).exec(entry);
|
|
351
|
+
if (!match) continue;
|
|
352
|
+
const staged = path.join(parent, entry);
|
|
353
|
+
try {
|
|
354
|
+
const stat = await fs.stat(staged);
|
|
355
|
+
if (stat.mtimeMs >= cutoff) continue;
|
|
356
|
+
const ownerPid = Number(match[1]);
|
|
357
|
+
let ownerAlive = false;
|
|
358
|
+
try {
|
|
359
|
+
process.kill(ownerPid, 0);
|
|
360
|
+
ownerAlive = true;
|
|
361
|
+
} catch (error) {
|
|
362
|
+
// ESRCH: dead. EPERM (exists, other user): treat as alive —
|
|
363
|
+
// conservative, never delete on unknown liveness.
|
|
364
|
+
ownerAlive = error && error.code === "EPERM";
|
|
365
|
+
}
|
|
366
|
+
if (!ownerAlive) await fs.rm(staged, { force: true, recursive: true });
|
|
367
|
+
} catch { /* raced away */ }
|
|
368
|
+
}
|
|
369
|
+
} catch { /* no parent dir yet */ }
|
|
370
|
+
// Stage-then-swap: the staged copy is verified before publication and the
|
|
371
|
+
// previous installation survives every failure up to the final swap.
|
|
372
|
+
// NOTE: the swap itself (rm + rename) is NOT atomic — directory bundles
|
|
373
|
+
// have no atomic exchange on stock Node — but the failure window no longer
|
|
374
|
+
// starts before verification, and a crash mid-swap self-heals on the next
|
|
375
|
+
// run (which re-stages from the verified source).
|
|
376
|
+
const stagingPath = `${helperAppPath}.staged-${process.pid}-${Date.now().toString(36)}`;
|
|
377
|
+
await fs.rm(stagingPath, { force: true, recursive: true });
|
|
378
|
+
try {
|
|
379
|
+
// ditto preserves the bundle byte-for-byte (signature + stapled
|
|
380
|
+
// notarization ticket). The sealed app is NEVER re-signed here: its
|
|
381
|
+
// Developer ID designated requirement (identifier + team) is exactly
|
|
382
|
+
// what gives release builds their best chance of retaining TCC grants.
|
|
383
|
+
await run("/usr/bin/ditto", [sourceAppPath, stagingPath]);
|
|
384
|
+
// Verify the STAGED bundle (not just the source): source mutation
|
|
385
|
+
// between the verify above and the copy, or a torn copy, stops here.
|
|
386
|
+
await run("codesign", ["--verify", "--strict", stagingPath]);
|
|
387
|
+
let published = false;
|
|
388
|
+
try {
|
|
389
|
+
await fs.rm(helperAppPath, { force: true, recursive: true });
|
|
390
|
+
await fs.rename(stagingPath, helperAppPath);
|
|
391
|
+
published = true;
|
|
392
|
+
} catch (renameError) {
|
|
393
|
+
// Cross-device or otherwise unrenamable staging: fall back to a
|
|
394
|
+
// second ditto onto the final path, then verify the destination. A
|
|
395
|
+
// VERIFIED fallback is a successful installation — continue to
|
|
396
|
+
// registration instead of failing after doing the work.
|
|
397
|
+
try {
|
|
398
|
+
await run("/usr/bin/ditto", [stagingPath, helperAppPath]);
|
|
399
|
+
await run("codesign", ["--verify", "--strict", helperAppPath]);
|
|
400
|
+
published = true;
|
|
401
|
+
} catch (fallbackError) {
|
|
402
|
+
fallbackError.cause = renameError;
|
|
403
|
+
throw fallbackError;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (published) await registerHelperApp();
|
|
407
|
+
} finally {
|
|
408
|
+
await fs.rm(stagingPath, { force: true, recursive: true }).catch(() => {});
|
|
409
|
+
}
|
|
329
410
|
return true;
|
|
330
411
|
}
|
|
331
412
|
|
|
@@ -24434,6 +24434,7 @@ var StdioClientTransport = class {
|
|
|
24434
24434
|
};
|
|
24435
24435
|
|
|
24436
24436
|
// builtin/extensions/mcp-adapter/src/server-manager.ts
|
|
24437
|
+
import { createHash } from "node:crypto";
|
|
24437
24438
|
import * as fs2 from "node:fs";
|
|
24438
24439
|
import * as path2 from "node:path";
|
|
24439
24440
|
var CONNECT_TIMEOUT_MS = 3e4;
|
|
@@ -24442,6 +24443,41 @@ var PACKAGE_MANAGER_COMMANDS = /* @__PURE__ */ new Set(["npx", "npm", "bunx", "u
|
|
|
24442
24443
|
var METADATA_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
24443
24444
|
var CALL_TIMEOUT_MS = 12e4;
|
|
24444
24445
|
var STDERR_TAIL_LIMIT = 4e3;
|
|
24446
|
+
var DIAGNOSTIC_TEXT_LIMIT = 1500;
|
|
24447
|
+
function definitionSecrets(definition) {
|
|
24448
|
+
const secrets = [];
|
|
24449
|
+
for (const value of Object.values(definition.env ?? {})) {
|
|
24450
|
+
if (typeof value === "string" && value.length > 0) secrets.push(value);
|
|
24451
|
+
}
|
|
24452
|
+
for (const value of Object.values(definition.headers ?? {})) {
|
|
24453
|
+
if (typeof value === "string" && value.length > 0) secrets.push(value);
|
|
24454
|
+
}
|
|
24455
|
+
return secrets.sort((a, b) => b.length - a.length);
|
|
24456
|
+
}
|
|
24457
|
+
function redactSecrets(text, secrets) {
|
|
24458
|
+
let sanitized = text;
|
|
24459
|
+
for (const secret of secrets) {
|
|
24460
|
+
sanitized = sanitized.split(secret).join("[redacted]");
|
|
24461
|
+
}
|
|
24462
|
+
return sanitized;
|
|
24463
|
+
}
|
|
24464
|
+
function sanitizeDiagnostic(text, secrets) {
|
|
24465
|
+
let sanitized = redactSecrets(text, secrets);
|
|
24466
|
+
if (secrets.length > 0 && sanitized.length > 0) {
|
|
24467
|
+
for (const secret of secrets) {
|
|
24468
|
+
for (let keep = Math.min(secret.length - 1, sanitized.length); keep >= 4; keep--) {
|
|
24469
|
+
if (sanitized.startsWith(secret.slice(secret.length - keep))) {
|
|
24470
|
+
sanitized = `[redacted]${sanitized.slice(keep)}`;
|
|
24471
|
+
break;
|
|
24472
|
+
}
|
|
24473
|
+
}
|
|
24474
|
+
}
|
|
24475
|
+
}
|
|
24476
|
+
if (sanitized.length > DIAGNOSTIC_TEXT_LIMIT) {
|
|
24477
|
+
sanitized = `${sanitized.slice(0, DIAGNOSTIC_TEXT_LIMIT)}\u2026[truncated ${sanitized.length - DIAGNOSTIC_TEXT_LIMIT} chars]`;
|
|
24478
|
+
}
|
|
24479
|
+
return sanitized;
|
|
24480
|
+
}
|
|
24445
24481
|
function connectTimeoutFor(definition) {
|
|
24446
24482
|
if (definition.connectTimeoutMs !== void 0) return definition.connectTimeoutMs;
|
|
24447
24483
|
const base = path2.basename(definition.command ?? "");
|
|
@@ -24499,6 +24535,22 @@ function withTimeout(promise, timeoutMs, label, signal) {
|
|
|
24499
24535
|
);
|
|
24500
24536
|
});
|
|
24501
24537
|
}
|
|
24538
|
+
function cacheFingerprint(definition) {
|
|
24539
|
+
return createHash("sha256").update(JSON.stringify({
|
|
24540
|
+
sourceScope: definition.sourceScope,
|
|
24541
|
+
sourcePath: definition.sourcePath,
|
|
24542
|
+
name: definition.name,
|
|
24543
|
+
command: definition.command,
|
|
24544
|
+
args: definition.args,
|
|
24545
|
+
// Canonicalized (key-sorted) so reordering equivalent env/header keys
|
|
24546
|
+
// does not invalidate cached metadata.
|
|
24547
|
+
env: Object.fromEntries(Object.entries(definition.env ?? {}).sort(([a], [b]) => a.localeCompare(b))),
|
|
24548
|
+
serverCwd: definition.cwd,
|
|
24549
|
+
url: definition.url,
|
|
24550
|
+
headers: Object.fromEntries(Object.entries(definition.headers ?? {}).sort(([a], [b]) => a.localeCompare(b))),
|
|
24551
|
+
inheritEnv: definition.inheritEnv
|
|
24552
|
+
})).digest("hex").slice(0, 24);
|
|
24553
|
+
}
|
|
24502
24554
|
var McpServerManager = class {
|
|
24503
24555
|
constructor(definitions, cacheDir, log, now = Date.now) {
|
|
24504
24556
|
this.now = now;
|
|
@@ -24577,8 +24629,9 @@ var McpServerManager = class {
|
|
|
24577
24629
|
stderr: "pipe"
|
|
24578
24630
|
});
|
|
24579
24631
|
if (transport2.stderr) {
|
|
24632
|
+
const captureSecrets = definitionSecrets(definition);
|
|
24580
24633
|
transport2.stderr.on("data", (chunk) => {
|
|
24581
|
-
runtime.stderrTail = appendTail(runtime.stderrTail, chunk);
|
|
24634
|
+
runtime.stderrTail = appendTail(runtime.stderrTail, redactSecrets(String(chunk), captureSecrets));
|
|
24582
24635
|
});
|
|
24583
24636
|
}
|
|
24584
24637
|
return { client, transport: transport2 };
|
|
@@ -24669,7 +24722,7 @@ var McpServerManager = class {
|
|
|
24669
24722
|
if (!runtime.tools) continue;
|
|
24670
24723
|
const shardPath = path2.join(this.cacheDir, `${key}.json`);
|
|
24671
24724
|
const tempPath = `${shardPath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
24672
|
-
fs2.writeFileSync(tempPath, JSON.stringify({ updatedAt: this.now(), tools: runtime.tools }, null, 2), "utf8");
|
|
24725
|
+
fs2.writeFileSync(tempPath, JSON.stringify({ updatedAt: this.now(), fingerprint: cacheFingerprint(runtime.definition), tools: runtime.tools }, null, 2), "utf8");
|
|
24673
24726
|
try {
|
|
24674
24727
|
fs2.renameSync(tempPath, shardPath);
|
|
24675
24728
|
} catch (error2) {
|
|
@@ -24704,6 +24757,7 @@ var McpServerManager = class {
|
|
|
24704
24757
|
}
|
|
24705
24758
|
}
|
|
24706
24759
|
/** Cached descriptors for one server (from the metadata cache file). */
|
|
24760
|
+
/** Cached descriptors for one server (from the metadata cache file). */
|
|
24707
24761
|
cachedToolsFor(server) {
|
|
24708
24762
|
return this.loadCatalog().filter((tool) => tool.server === sanitizeName(server));
|
|
24709
24763
|
}
|
|
@@ -24722,10 +24776,11 @@ var McpServerManager = class {
|
|
|
24722
24776
|
catalog.set(tool.prefixedName, tool);
|
|
24723
24777
|
ownerOf.set(tool.prefixedName, tool.server);
|
|
24724
24778
|
};
|
|
24725
|
-
for (const
|
|
24726
|
-
|
|
24727
|
-
|
|
24728
|
-
|
|
24779
|
+
for (const [key, shard] of Object.entries(this.readCacheFile())) {
|
|
24780
|
+
const definition = this.definitions.get(key);
|
|
24781
|
+
if (!definition || definition.disabled) continue;
|
|
24782
|
+
if (shard.fingerprint !== cacheFingerprint(definition)) continue;
|
|
24783
|
+
for (const tool of shard.tools) {
|
|
24729
24784
|
claim2(tool, false);
|
|
24730
24785
|
}
|
|
24731
24786
|
}
|
|
@@ -24786,7 +24841,10 @@ var McpServerManager = class {
|
|
|
24786
24841
|
if (typeof parsed.updatedAt !== "number" || this.now() - parsed.updatedAt > METADATA_TTL_MS) continue;
|
|
24787
24842
|
if (!Array.isArray(parsed.tools)) continue;
|
|
24788
24843
|
const key = name.slice(0, -".json".length);
|
|
24789
|
-
snapshot[key] =
|
|
24844
|
+
snapshot[key] = {
|
|
24845
|
+
tools: parsed.tools,
|
|
24846
|
+
...typeof parsed.fingerprint === "string" ? { fingerprint: parsed.fingerprint } : {}
|
|
24847
|
+
};
|
|
24790
24848
|
updatedAt[key] = parsed.updatedAt;
|
|
24791
24849
|
} catch {
|
|
24792
24850
|
}
|
|
@@ -24830,12 +24888,16 @@ var McpServerManager = class {
|
|
|
24830
24888
|
} catch (error2) {
|
|
24831
24889
|
const runtimeState = this.runtimes.get(server);
|
|
24832
24890
|
const tail = runtimeState?.stderrTail.trim();
|
|
24891
|
+
const secrets = definitionSecrets(definition);
|
|
24833
24892
|
return {
|
|
24834
24893
|
delivery: "not_sent",
|
|
24835
|
-
error:
|
|
24894
|
+
error: sanitizeDiagnostic(
|
|
24895
|
+
`MCP server "${server}" failed to start: ${error2 instanceof Error ? error2.message : String(error2)}` + (tail ? `
|
|
24836
24896
|
|
|
24837
24897
|
Server stderr tail:
|
|
24838
|
-
${tail}` : "")
|
|
24898
|
+
${tail}` : ""),
|
|
24899
|
+
secrets
|
|
24900
|
+
)
|
|
24839
24901
|
};
|
|
24840
24902
|
}
|
|
24841
24903
|
const client = runtime.client;
|
|
@@ -24879,7 +24941,7 @@ ${tail}` : "")
|
|
|
24879
24941
|
isError: result.isError === true
|
|
24880
24942
|
};
|
|
24881
24943
|
} catch (error2) {
|
|
24882
|
-
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
24944
|
+
const message = sanitizeDiagnostic(error2 instanceof Error ? error2.message : String(error2), definitionSecrets(definition));
|
|
24883
24945
|
if (error2 instanceof ProtocolError && (error2.code === ProtocolErrorCode.InvalidRequest || error2.code === ProtocolErrorCode.InvalidParams) && /output schema|structured content/i.test(message)) {
|
|
24884
24946
|
return {
|
|
24885
24947
|
delivery: "invalid_result",
|
|
@@ -24914,7 +24976,7 @@ ${tail}` : "")
|
|
|
24914
24976
|
};
|
|
24915
24977
|
|
|
24916
24978
|
// builtin/extensions/mcp-adapter/src/trust.ts
|
|
24917
|
-
import { createHash } from "node:crypto";
|
|
24979
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
24918
24980
|
import * as fs3 from "node:fs";
|
|
24919
24981
|
import * as path3 from "node:path";
|
|
24920
24982
|
function serverFingerprint(cwd, definition) {
|
|
@@ -24933,7 +24995,7 @@ function serverFingerprint(cwd, definition) {
|
|
|
24933
24995
|
inheritEnv: definition.inheritEnv,
|
|
24934
24996
|
headers: definition.headers
|
|
24935
24997
|
});
|
|
24936
|
-
return
|
|
24998
|
+
return createHash2("sha256").update(spec).digest("hex").slice(0, 24);
|
|
24937
24999
|
}
|
|
24938
25000
|
var McpTrustStore = class {
|
|
24939
25001
|
filePath;
|
|
@@ -25034,8 +25096,9 @@ function structuredContentIsMirroredInText(textBlocks, structured) {
|
|
|
25034
25096
|
function mapMcpOutcome(outcome, maxBytes) {
|
|
25035
25097
|
if (outcome.delivery !== "ok") {
|
|
25036
25098
|
const prefix = outcome.delivery === "may_have_run" || outcome.delivery === "invalid_result" ? "[outcome unknown]" : "[not executed]";
|
|
25099
|
+
const errorText = truncate(`${outcome.error ?? "MCP call failed"}`, maxBytes);
|
|
25037
25100
|
return {
|
|
25038
|
-
content: [{ type: "text", text: `${prefix} ${
|
|
25101
|
+
content: [{ type: "text", text: `${prefix} ${errorText}` }],
|
|
25039
25102
|
details: { mode: "mcp", delivery: outcome.delivery, ...outcome.protocolCode !== void 0 ? { protocolCode: outcome.protocolCode } : {} },
|
|
25040
25103
|
isError: true
|
|
25041
25104
|
};
|
|
@@ -25070,8 +25133,9 @@ ${JSON.stringify(outcome.structuredContent, null, 2)}` });
|
|
|
25070
25133
|
isError: outcome.isError === true
|
|
25071
25134
|
};
|
|
25072
25135
|
}
|
|
25073
|
-
function createMcpProxyTool(getManager, ensureTrusted, options = {}) {
|
|
25074
|
-
const
|
|
25136
|
+
function createMcpProxyTool(getManager, ensureTrusted, optionsOrVerify = {}, options = {}) {
|
|
25137
|
+
const verifyTrusted = typeof optionsOrVerify === "function" ? optionsOrVerify : void 0;
|
|
25138
|
+
const maxBytes = typeof optionsOrVerify === "object" && optionsOrVerify.outputMaxBytes || options.outputMaxBytes || DEFAULT_OUTPUT_MAX_BYTES;
|
|
25075
25139
|
return {
|
|
25076
25140
|
name: "mcp",
|
|
25077
25141
|
label: "MCP",
|
|
@@ -25123,7 +25187,8 @@ ${truncate(JSON.stringify(schema ?? {}, null, 2), maxBytes)}` : `unknown MCP too
|
|
|
25123
25187
|
const resolved = getManager().resolvePrefixedName(params.tool);
|
|
25124
25188
|
const server = descriptor?.server ?? resolved?.server ?? "";
|
|
25125
25189
|
if (server) {
|
|
25126
|
-
const
|
|
25190
|
+
const managerAtGate = getManager();
|
|
25191
|
+
const trust = await ensureTrusted(server, managerAtGate);
|
|
25127
25192
|
if (!trust.trusted) {
|
|
25128
25193
|
return {
|
|
25129
25194
|
content: [{ type: "text", text: `[not executed] ${trust.reason ?? "MCP server not trusted"}` }],
|
|
@@ -25131,6 +25196,14 @@ ${truncate(JSON.stringify(schema ?? {}, null, 2), maxBytes)}` : `unknown MCP too
|
|
|
25131
25196
|
isError: true
|
|
25132
25197
|
};
|
|
25133
25198
|
}
|
|
25199
|
+
const managerNow = getManager();
|
|
25200
|
+
if (managerNow !== managerAtGate || verifyTrusted !== void 0 && !verifyTrusted(server, managerNow)) {
|
|
25201
|
+
return {
|
|
25202
|
+
content: [{ type: "text", text: `[not executed] MCP config changed during approval for server "${server}" \u2014 the approved definition and the current one differ. Retry the call to approve the new definition.` }],
|
|
25203
|
+
details: { mode: "mcp", delivery: "not_sent" },
|
|
25204
|
+
isError: true
|
|
25205
|
+
};
|
|
25206
|
+
}
|
|
25134
25207
|
}
|
|
25135
25208
|
let args = {};
|
|
25136
25209
|
if (typeof params.args === "string") {
|
|
@@ -25204,7 +25277,7 @@ function jsonSchemaToTypebox(schema) {
|
|
|
25204
25277
|
// builtin/extensions/mcp-adapter/src/direct-tools.ts
|
|
25205
25278
|
var FALLBACK_PARAMS = Type.Object({}, { description: "MCP tool arguments (schema unknown until first connect)" });
|
|
25206
25279
|
var DEFAULT_DIRECT_OUTPUT_MAX_BYTES = 8192;
|
|
25207
|
-
function registerDirectTools(ctx, getManager, ensureTrusted, outputMaxBytes) {
|
|
25280
|
+
function registerDirectTools(ctx, getManager, ensureTrusted, verifyTrusted, outputMaxBytes) {
|
|
25208
25281
|
const registered = [];
|
|
25209
25282
|
const seenNames = /* @__PURE__ */ new Set();
|
|
25210
25283
|
for (const definition of getManager().listDefinitions()) {
|
|
@@ -25218,13 +25291,13 @@ function registerDirectTools(ctx, getManager, ensureTrusted, outputMaxBytes) {
|
|
|
25218
25291
|
continue;
|
|
25219
25292
|
}
|
|
25220
25293
|
seenNames.add(descriptor.prefixedName);
|
|
25221
|
-
registerDirectTool(ctx, getManager, ensureTrusted, definition, descriptor.prefixedName, descriptor.description, descriptor.inputSchema, outputMaxBytes);
|
|
25294
|
+
registerDirectTool(ctx, getManager, ensureTrusted, verifyTrusted, definition, descriptor.prefixedName, descriptor.description, descriptor.inputSchema, outputMaxBytes);
|
|
25222
25295
|
registered.push(descriptor.prefixedName);
|
|
25223
25296
|
}
|
|
25224
25297
|
}
|
|
25225
25298
|
return registered;
|
|
25226
25299
|
}
|
|
25227
|
-
function registerDirectTool(ctx, getManager, ensureTrusted, definition, prefixedName, description, inputSchema, outputMaxBytes) {
|
|
25300
|
+
function registerDirectTool(ctx, getManager, ensureTrusted, verifyTrusted, definition, prefixedName, description, inputSchema, outputMaxBytes) {
|
|
25228
25301
|
const parameters = inputSchema ? jsonSchemaToTypebox(inputSchema) : FALLBACK_PARAMS;
|
|
25229
25302
|
ctx.registerTool({
|
|
25230
25303
|
name: prefixedName,
|
|
@@ -25232,7 +25305,8 @@ function registerDirectTool(ctx, getManager, ensureTrusted, definition, prefixed
|
|
|
25232
25305
|
description: `${(description ?? prefixedName).trim()} (MCP server: ${definition.name})`,
|
|
25233
25306
|
parameters,
|
|
25234
25307
|
async execute(args, toolContext) {
|
|
25235
|
-
const
|
|
25308
|
+
const managerAtGate = getManager();
|
|
25309
|
+
const trust = await ensureTrusted(definition.name, managerAtGate);
|
|
25236
25310
|
if (!trust.trusted) {
|
|
25237
25311
|
return {
|
|
25238
25312
|
content: [{ type: "text", text: `[not executed] ${trust.reason ?? "MCP server not trusted"}` }],
|
|
@@ -25240,7 +25314,15 @@ function registerDirectTool(ctx, getManager, ensureTrusted, definition, prefixed
|
|
|
25240
25314
|
isError: true
|
|
25241
25315
|
};
|
|
25242
25316
|
}
|
|
25243
|
-
const
|
|
25317
|
+
const managerNow = getManager();
|
|
25318
|
+
if (managerNow !== managerAtGate || verifyTrusted !== void 0 && !verifyTrusted(definition.name, managerNow)) {
|
|
25319
|
+
return {
|
|
25320
|
+
content: [{ type: "text", text: `[not executed] MCP config changed during approval for server "${definition.name}" \u2014 retry the call to approve the new definition.` }],
|
|
25321
|
+
details: { delivery: "not_sent" },
|
|
25322
|
+
isError: true
|
|
25323
|
+
};
|
|
25324
|
+
}
|
|
25325
|
+
const outcome = await managerNow.callTool(
|
|
25244
25326
|
prefixedName,
|
|
25245
25327
|
args && typeof args === "object" && !Array.isArray(args) ? args : {},
|
|
25246
25328
|
toolContext.signal
|
|
@@ -25335,8 +25417,8 @@ function mcpAdapter(ctx) {
|
|
|
25335
25417
|
fs4.writeFileSync(filePath, JSON.stringify(parsed, null, 2) + "\n", "utf8");
|
|
25336
25418
|
return filePath;
|
|
25337
25419
|
}
|
|
25338
|
-
async function ensureTrusted(serverName) {
|
|
25339
|
-
const definition =
|
|
25420
|
+
async function ensureTrusted(serverName, managerAtGate = manager) {
|
|
25421
|
+
const definition = managerAtGate.getDefinition(serverName);
|
|
25340
25422
|
if (!definition) return { trusted: false, reason: `unknown MCP server "${serverName}"` };
|
|
25341
25423
|
if (trustStore.isTrusted(ctx.cwd, definition)) return { trusted: true };
|
|
25342
25424
|
if (!ctx.interactions.isAvailable()) {
|
|
@@ -25360,8 +25442,12 @@ function mcpAdapter(ctx) {
|
|
|
25360
25442
|
reason: `MCP server "${definition.name}" was not approved. It was NOT started. Ask the user to approve it, or remove it from ${definition.sourcePath}.`
|
|
25361
25443
|
};
|
|
25362
25444
|
}
|
|
25363
|
-
|
|
25364
|
-
|
|
25445
|
+
function verifyTrusted(serverName, currentManager) {
|
|
25446
|
+
const definition = currentManager.getDefinition(serverName);
|
|
25447
|
+
return !!definition && trustStore.isTrusted(ctx.cwd, definition);
|
|
25448
|
+
}
|
|
25449
|
+
ctx.registerTool(createMcpProxyTool(() => manager, ensureTrusted, verifyTrusted));
|
|
25450
|
+
const eagerRegistered = registerDirectTools(ctx, () => manager, ensureTrusted, verifyTrusted);
|
|
25365
25451
|
if (eagerRegistered.length > 0) {
|
|
25366
25452
|
ctx.log(`mcp: registered ${eagerRegistered.length} direct tool(s) from metadata cache: ${eagerRegistered.join(", ")}`);
|
|
25367
25453
|
}
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
isPlanModeSafeCommand,
|
|
8
8
|
markCompletedPlanSteps,
|
|
9
9
|
restoreExecutionState
|
|
10
|
-
} from "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
10
|
+
} from "../../../chunks/chunk-LO2V5DZZ.js";
|
|
11
|
+
import "../../../chunks/chunk-RTTGO2A6.js";
|
|
12
|
+
import "../../../chunks/chunk-UD7KYQ6J.js";
|
|
13
13
|
import {
|
|
14
14
|
Type
|
|
15
15
|
} from "../../../chunks/chunk-XXGYUYXI.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createCliHostCapabilities
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-M4OJARWJ.js";
|
|
5
5
|
import {
|
|
6
6
|
createSharedFileSystemTools,
|
|
7
7
|
createSubagentCapability
|
|
8
|
-
} from "../../../chunks/chunk-
|
|
9
|
-
import "../../../chunks/chunk-
|
|
10
|
-
import "../../../chunks/chunk-
|
|
8
|
+
} from "../../../chunks/chunk-LO2V5DZZ.js";
|
|
9
|
+
import "../../../chunks/chunk-RTTGO2A6.js";
|
|
10
|
+
import "../../../chunks/chunk-UD7KYQ6J.js";
|
|
11
11
|
import "../../../chunks/chunk-5353DEEC.js";
|
|
12
12
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
13
13
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
executeManageTodoList,
|
|
9
9
|
executionStateToTodos,
|
|
10
10
|
restoreExecutionState
|
|
11
|
-
} from "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
13
|
-
import "../../../chunks/chunk-
|
|
11
|
+
} from "../../../chunks/chunk-LO2V5DZZ.js";
|
|
12
|
+
import "../../../chunks/chunk-RTTGO2A6.js";
|
|
13
|
+
import "../../../chunks/chunk-UD7KYQ6J.js";
|
|
14
14
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
15
15
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
16
16
|
|
|
@@ -19640,6 +19640,11 @@ async function handleBridgeRequest(client, req, res, sessionName, logForbidden,
|
|
|
19640
19640
|
writeJson(res, 200, {
|
|
19641
19641
|
status: "ok",
|
|
19642
19642
|
session: sessionName,
|
|
19643
|
+
// The bridge's own PID so `stop` can verify that the process named
|
|
19644
|
+
// in a (possibly stale) pid file is really THIS bridge before any
|
|
19645
|
+
// signal is sent — a healthy session on the recorded port alone
|
|
19646
|
+
// must not authorize killing an unrelated reused PID.
|
|
19647
|
+
pid: process.pid,
|
|
19643
19648
|
busy: client.isBusy?.() ?? false,
|
|
19644
19649
|
...droppedSelection ? { pageIdentityChanged: true } : {}
|
|
19645
19650
|
});
|
|
@@ -46,8 +46,11 @@ export function runChromeDevtoolsAxiCli(args = process.argv.slice(2), options =
|
|
|
46
46
|
...process.env,
|
|
47
47
|
CHROME_DEVTOOLS_AXI_MCP_PATH: process.env.CHROME_DEVTOOLS_AXI_MCP_PATH?.trim() || resolveChromeDevtoolsMcpScript(),
|
|
48
48
|
// Pie pins chrome-devtools-mcp; its daily background update check
|
|
49
|
-
// (network + ~/.cache write + "install @latest" nag)
|
|
50
|
-
// the
|
|
49
|
+
// (network + ~/.cache write + "install @latest" nag) is UNCONDITIONALLY
|
|
50
|
+
// disabled for the packaged CLI: the upstream treats any nonempty
|
|
51
|
+
// value — including "0" or "false" — as "disable", so this env var
|
|
52
|
+
// cannot re-enable the check. To run the check, invoke the vendored
|
|
53
|
+
// cli outside Pie with the variable unset.
|
|
51
54
|
CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS: process.env.CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS || "1",
|
|
52
55
|
...options.env,
|
|
53
56
|
},
|
|
@@ -21,6 +21,6 @@ function tryFastPath(argv, options) {
|
|
|
21
21
|
|
|
22
22
|
// vendor/chrome-devtools-axi/bin/chrome-devtools-axi.ts
|
|
23
23
|
if (!tryFastPath(process.argv.slice(2), { version: VERSION })) {
|
|
24
|
-
const { main } = await import("./cli-
|
|
24
|
+
const { main } = await import("./cli-EJ5MQZNA.js");
|
|
25
25
|
await main(process.argv.slice(2));
|
|
26
26
|
}
|
|
@@ -1935,6 +1935,23 @@ async function waitForProcessExit(pid, timeoutMs) {
|
|
|
1935
1935
|
return !isProcessAlive(pid);
|
|
1936
1936
|
}
|
|
1937
1937
|
function isBridgeProcess(pid) {
|
|
1938
|
+
if (process.platform === "win32") {
|
|
1939
|
+
try {
|
|
1940
|
+
const command = execFileSync(
|
|
1941
|
+
"powershell",
|
|
1942
|
+
[
|
|
1943
|
+
"-NoProfile",
|
|
1944
|
+
"-NonInteractive",
|
|
1945
|
+
"-Command",
|
|
1946
|
+
`(Get-CimInstance Win32_Process -Filter "ProcessId=${pid}").CommandLine`
|
|
1947
|
+
],
|
|
1948
|
+
{ encoding: "utf-8", timeout: 4e3 }
|
|
1949
|
+
);
|
|
1950
|
+
return command.includes("chrome-devtools-axi-bridge");
|
|
1951
|
+
} catch {
|
|
1952
|
+
return false;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1938
1955
|
try {
|
|
1939
1956
|
const command = execFileSync("ps", ["-p", String(pid), "-o", "command="], {
|
|
1940
1957
|
encoding: "utf-8",
|
|
@@ -1949,28 +1966,43 @@ async function probeBridgeIdentity(port, sessionName) {
|
|
|
1949
1966
|
try {
|
|
1950
1967
|
const resp = await httpGet(port, "/health", HEALTH_TIMEOUT_MS);
|
|
1951
1968
|
const data = JSON.parse(resp);
|
|
1952
|
-
if (data.status !== "ok") return "unknown";
|
|
1969
|
+
if (data.status !== "ok") return { identity: "unknown" };
|
|
1953
1970
|
if (typeof data.session === "string" && data.session !== sessionName) {
|
|
1954
|
-
return "other";
|
|
1971
|
+
return { identity: "other" };
|
|
1955
1972
|
}
|
|
1956
|
-
return
|
|
1973
|
+
return {
|
|
1974
|
+
identity: "own",
|
|
1975
|
+
reportedPid: typeof data.pid === "number" && data.pid > 0 ? data.pid : void 0
|
|
1976
|
+
};
|
|
1957
1977
|
} catch {
|
|
1958
|
-
return "unknown";
|
|
1978
|
+
return { identity: "unknown" };
|
|
1959
1979
|
}
|
|
1960
1980
|
}
|
|
1961
1981
|
async function judgeRecordedBridge(pidInfo, sessionName) {
|
|
1962
|
-
const
|
|
1963
|
-
if (identity === "own") {
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1982
|
+
const probe = await probeBridgeIdentity(pidInfo.port, sessionName);
|
|
1983
|
+
if (probe.identity === "own") {
|
|
1984
|
+
if (probe.reportedPid !== void 0) {
|
|
1985
|
+
if (probe.reportedPid === pidInfo.pid) {
|
|
1986
|
+
return {
|
|
1987
|
+
terminate: true,
|
|
1988
|
+
killProcessGroup: isBridgeProcess(pidInfo.pid),
|
|
1989
|
+
targetPid: pidInfo.pid
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
return {
|
|
1993
|
+
terminate: true,
|
|
1994
|
+
killProcessGroup: isBridgeProcess(probe.reportedPid),
|
|
1995
|
+
targetPid: probe.reportedPid
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
const bridge2 = isBridgeProcess(pidInfo.pid);
|
|
1999
|
+
return { terminate: bridge2, killProcessGroup: bridge2, targetPid: pidInfo.pid };
|
|
1968
2000
|
}
|
|
1969
|
-
if (identity === "other") {
|
|
2001
|
+
if (probe.identity === "other") {
|
|
1970
2002
|
return { terminate: false, killProcessGroup: false };
|
|
1971
2003
|
}
|
|
1972
2004
|
const bridge = isBridgeProcess(pidInfo.pid);
|
|
1973
|
-
return { terminate: bridge, killProcessGroup: bridge };
|
|
2005
|
+
return { terminate: bridge, killProcessGroup: bridge, targetPid: pidInfo.pid };
|
|
1974
2006
|
}
|
|
1975
2007
|
function removePidFile(pidFile) {
|
|
1976
2008
|
try {
|
|
@@ -1978,13 +2010,27 @@ function removePidFile(pidFile) {
|
|
|
1978
2010
|
} catch {
|
|
1979
2011
|
}
|
|
1980
2012
|
}
|
|
2013
|
+
function taskkillTree(pid) {
|
|
2014
|
+
try {
|
|
2015
|
+
execFileSync("taskkill", ["/PID", String(pid), "/T", "/F"], {
|
|
2016
|
+
stdio: "ignore",
|
|
2017
|
+
timeout: 1e4
|
|
2018
|
+
});
|
|
2019
|
+
return true;
|
|
2020
|
+
} catch {
|
|
2021
|
+
return !isProcessAlive(pid);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
1981
2024
|
async function terminateBridgeProcess(pid, opts = {}) {
|
|
1982
|
-
if (!isProcessAlive(pid)) return;
|
|
2025
|
+
if (!isProcessAlive(pid)) return true;
|
|
1983
2026
|
const killProcessGroup = opts.killProcessGroup === true;
|
|
2027
|
+
if (process.platform === "win32") {
|
|
2028
|
+
return taskkillTree(pid) && !await isProcessAlive(pid);
|
|
2029
|
+
}
|
|
1984
2030
|
try {
|
|
1985
2031
|
process.kill(pid, "SIGTERM");
|
|
1986
|
-
} catch {
|
|
1987
|
-
return;
|
|
2032
|
+
} catch (error) {
|
|
2033
|
+
if (error.code === "ESRCH") return true;
|
|
1988
2034
|
}
|
|
1989
2035
|
if (await waitForProcessExit(pid, 2e3)) {
|
|
1990
2036
|
if (killProcessGroup) {
|
|
@@ -1993,7 +2039,7 @@ async function terminateBridgeProcess(pid, opts = {}) {
|
|
|
1993
2039
|
} catch {
|
|
1994
2040
|
}
|
|
1995
2041
|
}
|
|
1996
|
-
return;
|
|
2042
|
+
return true;
|
|
1997
2043
|
}
|
|
1998
2044
|
if (killProcessGroup) {
|
|
1999
2045
|
try {
|
|
@@ -2010,7 +2056,7 @@ async function terminateBridgeProcess(pid, opts = {}) {
|
|
|
2010
2056
|
} catch {
|
|
2011
2057
|
}
|
|
2012
2058
|
}
|
|
2013
|
-
|
|
2059
|
+
return waitForProcessExit(pid, 1e3);
|
|
2014
2060
|
}
|
|
2015
2061
|
function spawnBridgeProcess(port, sessionName) {
|
|
2016
2062
|
const bridgeScript = resolveBridgeScript(import.meta.dirname);
|
|
@@ -2100,7 +2146,7 @@ async function ensureBridge(spawnBridge = spawnBridgeProcess, notice) {
|
|
|
2100
2146
|
}
|
|
2101
2147
|
const verdict = await judgeRecordedBridge(pidInfo, sessionName);
|
|
2102
2148
|
if (verdict.terminate) {
|
|
2103
|
-
await terminateBridgeProcess(pidInfo.pid, {
|
|
2149
|
+
await terminateBridgeProcess(verdict.targetPid ?? pidInfo.pid, {
|
|
2104
2150
|
killProcessGroup: verdict.killProcessGroup
|
|
2105
2151
|
});
|
|
2106
2152
|
} else {
|
|
@@ -2374,15 +2420,15 @@ async function getSessionSnapshotIfRunning() {
|
|
|
2374
2420
|
}
|
|
2375
2421
|
async function stopBridge() {
|
|
2376
2422
|
const pidInfo = readPidFile();
|
|
2377
|
-
if (!pidInfo) return
|
|
2378
|
-
if (!isProcessAlive(pidInfo.pid)) return
|
|
2423
|
+
if (!pidInfo) return "noop";
|
|
2424
|
+
if (!isProcessAlive(pidInfo.pid)) return "noop";
|
|
2379
2425
|
const verdict = await judgeRecordedBridge(pidInfo, resolveSessionName());
|
|
2380
|
-
if (!verdict.terminate) return
|
|
2381
|
-
await terminateBridgeProcess(pidInfo.pid, {
|
|
2426
|
+
if (!verdict.terminate) return "noop";
|
|
2427
|
+
const terminated = await terminateBridgeProcess(verdict.targetPid ?? pidInfo.pid, {
|
|
2382
2428
|
killProcessGroup: verdict.killProcessGroup
|
|
2383
2429
|
});
|
|
2384
2430
|
clearSelectedPageId();
|
|
2385
|
-
return
|
|
2431
|
+
return terminated ? "stopped" : "failed";
|
|
2386
2432
|
}
|
|
2387
2433
|
|
|
2388
2434
|
// vendor/chrome-devtools-axi/src/generation.ts
|
|
@@ -3931,12 +3977,15 @@ async function handleStart() {
|
|
|
3931
3977
|
const port = await ensureBridge();
|
|
3932
3978
|
return encode({ status: "ready", port });
|
|
3933
3979
|
}
|
|
3934
|
-
function formatStopOutput(
|
|
3935
|
-
|
|
3980
|
+
function formatStopOutput(outcome) {
|
|
3981
|
+
if (outcome === "failed") {
|
|
3982
|
+
throw new Error("bridge stop failed: the target survived SIGTERM and SIGKILL escalation");
|
|
3983
|
+
}
|
|
3984
|
+
return encode({ status: outcome === "stopped" ? "stopped" : "stopped (no-op)" });
|
|
3936
3985
|
}
|
|
3937
3986
|
async function handleStop() {
|
|
3938
|
-
const
|
|
3939
|
-
return formatStopOutput(
|
|
3987
|
+
const outcome = await stopBridge();
|
|
3988
|
+
return formatStopOutput(outcome);
|
|
3940
3989
|
}
|
|
3941
3990
|
async function handlePages() {
|
|
3942
3991
|
const result = await callTool("list_pages");
|
|
@@ -9950,7 +9950,13 @@ var import_node_child_process = require("node:child_process");
|
|
|
9950
9950
|
var import_node_crypto = require("node:crypto");
|
|
9951
9951
|
var import_node_os = __toESM(require("node:os"));
|
|
9952
9952
|
var import_node_path = __toESM(require("node:path"));
|
|
9953
|
-
var expandHome = (value) =>
|
|
9953
|
+
var expandHome = (value) => {
|
|
9954
|
+
if (value === "~") return import_node_os.default.homedir();
|
|
9955
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
9956
|
+
return import_node_path.default.join(import_node_os.default.homedir(), value.slice(2).replace(/\\/g, "/"));
|
|
9957
|
+
}
|
|
9958
|
+
return value;
|
|
9959
|
+
};
|
|
9954
9960
|
var STATE_DIR = import_node_path.default.resolve(process.env.PIE_TUI_USE_STATE_DIR ? expandHome(process.env.PIE_TUI_USE_STATE_DIR) : import_node_path.default.join(expandHome(process.env.PIE_CODING_AGENT_DIR || import_node_path.default.join(import_node_os.default.homedir(), ".pie")), "tui-use"));
|
|
9955
9961
|
var LOG_PATH = import_node_path.default.join(STATE_DIR, "daemon.log");
|
|
9956
9962
|
var PID_PATH = import_node_path.default.join(STATE_DIR, "daemon.pid");
|
|
@@ -10139,17 +10145,27 @@ async function startDaemon() {
|
|
|
10139
10145
|
if (error.code !== "EEXIST") throw error;
|
|
10140
10146
|
try {
|
|
10141
10147
|
const contents = import_node_fs.default.readFileSync(LOCK_PATH, "utf8");
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10148
|
+
let reclaim = false;
|
|
10149
|
+
try {
|
|
10150
|
+
const lock = JSON.parse(contents);
|
|
10151
|
+
let alive = true;
|
|
10152
|
+
if (!Number.isInteger(lock.pid) || lock.pid <= 0) alive = false;
|
|
10153
|
+
else {
|
|
10154
|
+
try {
|
|
10155
|
+
process.kill(lock.pid, 0);
|
|
10156
|
+
} catch (e) {
|
|
10157
|
+
if (e.code === "ESRCH") alive = false;
|
|
10158
|
+
}
|
|
10159
|
+
}
|
|
10160
|
+
if (!alive) reclaim = true;
|
|
10161
|
+
} catch {
|
|
10146
10162
|
try {
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10163
|
+
const mtimeMs = import_node_fs.default.statSync(LOCK_PATH).mtimeMs;
|
|
10164
|
+
if (Date.now() - mtimeMs > 5e3) reclaim = true;
|
|
10165
|
+
} catch {
|
|
10150
10166
|
}
|
|
10151
10167
|
}
|
|
10152
|
-
if (
|
|
10168
|
+
if (reclaim && import_node_fs.default.readFileSync(LOCK_PATH, "utf8") === contents) import_node_fs.default.unlinkSync(LOCK_PATH);
|
|
10153
10169
|
} catch {
|
|
10154
10170
|
}
|
|
10155
10171
|
await sleep(100);
|
|
@@ -7661,7 +7661,13 @@ function validateRequest(value) {
|
|
|
7661
7661
|
var import_node_crypto = require("node:crypto");
|
|
7662
7662
|
var import_node_os = __toESM(require("node:os"));
|
|
7663
7663
|
var import_node_path3 = __toESM(require("node:path"));
|
|
7664
|
-
var expandHome = (value) =>
|
|
7664
|
+
var expandHome = (value) => {
|
|
7665
|
+
if (value === "~") return import_node_os.default.homedir();
|
|
7666
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
7667
|
+
return import_node_path3.default.join(import_node_os.default.homedir(), value.slice(2).replace(/\\/g, "/"));
|
|
7668
|
+
}
|
|
7669
|
+
return value;
|
|
7670
|
+
};
|
|
7665
7671
|
var STATE_DIR = import_node_path3.default.resolve(process.env.PIE_TUI_USE_STATE_DIR ? expandHome(process.env.PIE_TUI_USE_STATE_DIR) : import_node_path3.default.join(expandHome(process.env.PIE_CODING_AGENT_DIR || import_node_path3.default.join(import_node_os.default.homedir(), ".pie")), "tui-use"));
|
|
7666
7672
|
var LOG_PATH = import_node_path3.default.join(STATE_DIR, "daemon.log");
|
|
7667
7673
|
var PID_PATH = import_node_path3.default.join(STATE_DIR, "daemon.pid");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
Agent
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RTTGO2A6.js";
|
|
5
5
|
import {
|
|
6
6
|
FileSystemGateway,
|
|
7
7
|
completeSimple,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
getPlatformConfig,
|
|
11
11
|
hashText,
|
|
12
12
|
streamSimple
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-UD7KYQ6J.js";
|
|
14
14
|
import {
|
|
15
15
|
Type
|
|
16
16
|
} from "./chunk-XXGYUYXI.js";
|
|
@@ -5244,6 +5244,16 @@ var AgentSessionQueue = class {
|
|
|
5244
5244
|
}
|
|
5245
5245
|
this.emitQueueChanged();
|
|
5246
5246
|
}
|
|
5247
|
+
/** Promote only an input still owned by this queue, never re-send agent-owned inputs. */
|
|
5248
|
+
promoteLatestFollowUp() {
|
|
5249
|
+
const input = this.queuedInputs.slice().reverse().find((queued) => queued.visibility === "user" && queued.mode === "followUp");
|
|
5250
|
+
if (!input || input.deliveredToAgent) return void 0;
|
|
5251
|
+
input.mode = "steer";
|
|
5252
|
+
input.deliverWhileStreaming = true;
|
|
5253
|
+
if (this.getIsStreaming()) this.deliverToAgent(input);
|
|
5254
|
+
this.emitQueueChanged();
|
|
5255
|
+
return cloneQueuedInput(input);
|
|
5256
|
+
}
|
|
5247
5257
|
deliverToAgent(queuedInput) {
|
|
5248
5258
|
if (queuedInput.deliveredToAgent) {
|
|
5249
5259
|
return;
|
|
@@ -6404,6 +6414,12 @@ var AgentSessionController = class {
|
|
|
6404
6414
|
drainQueuedInputsForEditor() {
|
|
6405
6415
|
return this.queue.drainForEditor();
|
|
6406
6416
|
}
|
|
6417
|
+
/** Upgrade the latest visible follow-up that has not been delivered to the agent. */
|
|
6418
|
+
promoteLatestFollowUpToSteer() {
|
|
6419
|
+
const promoted = this.disposed ? void 0 : this.queue.promoteLatestFollowUp();
|
|
6420
|
+
if (promoted && !this.isStreaming) this.requestQueueDispatch();
|
|
6421
|
+
return promoted;
|
|
6422
|
+
}
|
|
6407
6423
|
replaceQueuedInputText(search, replacement) {
|
|
6408
6424
|
this.queue.replaceText(search, replacement);
|
|
6409
6425
|
}
|
|
@@ -8775,7 +8791,7 @@ function createReadTool(cwd, options) {
|
|
|
8775
8791
|
return {
|
|
8776
8792
|
name: "read",
|
|
8777
8793
|
label: "read",
|
|
8778
|
-
description: `Read a file's contents. Use this before editing, and use offset/limit for large files.
|
|
8794
|
+
description: `Read a file's contents. Use this before editing, and use offset/limit for large files. Images are attached for the current model when it supports vision; otherwise a configured file-understanding service analyzes them. Video, audio, and documents require a configured understanding service. Pass question to specify what to focus on; it does not force a separate model request. Example: read_file path='Scripts/PlayerController.cs' or read_file path='Data/config.json'. ${pathResolutionDescription} For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). When you need the full file, continue with a larger offset until complete.`,
|
|
8779
8795
|
parameters: readSchema,
|
|
8780
8796
|
execute: async (_toolCallId, params, signal) => {
|
|
8781
8797
|
const { path: path4, root, offset, limit, question } = params;
|
|
@@ -8848,7 +8864,7 @@ function createReadTool(cwd, options) {
|
|
|
8848
8864
|
});
|
|
8849
8865
|
return;
|
|
8850
8866
|
}
|
|
8851
|
-
if (magicInfo?.kind === "image" &&
|
|
8867
|
+
if (magicInfo?.kind === "image" && options?.understandFile && (!INLINE_IMAGE_MIME_TYPES.has(magicInfo.mimeType) || stat.size > MAX_INLINE_IMAGE_BYTES)) {
|
|
8852
8868
|
resolve3(await options.understandFile({
|
|
8853
8869
|
absolutePath,
|
|
8854
8870
|
displayPath: path4,
|
|
@@ -8864,7 +8880,7 @@ function createReadTool(cwd, options) {
|
|
|
8864
8880
|
}
|
|
8865
8881
|
const imageInfo = options?.allowBinary === false || magicInfo?.kind !== "image" || !INLINE_IMAGE_MIME_TYPES.has(magicInfo.mimeType) ? void 0 : await readImageInfo(absolutePath, fs2);
|
|
8866
8882
|
if (imageInfo) {
|
|
8867
|
-
if (
|
|
8883
|
+
if (options?.understandFile) {
|
|
8868
8884
|
resolve3(await options.understandFile({
|
|
8869
8885
|
absolutePath,
|
|
8870
8886
|
displayPath: path4,
|
|
@@ -8879,7 +8895,8 @@ function createReadTool(cwd, options) {
|
|
|
8879
8895
|
const dimensionText = imageInfo.width && imageInfo.height ? `, ${imageInfo.width}x${imageInfo.height}` : "";
|
|
8880
8896
|
resolve3({
|
|
8881
8897
|
content: [
|
|
8882
|
-
{ type: "text", text: `Read image file [${imageInfo.mimeType}${dimensionText}]. Original image attached as an image block; for very large images, prefer a smaller crop or resized copy before rereading
|
|
8898
|
+
{ type: "text", text: `Read image file [${imageInfo.mimeType}${dimensionText}]. Original image attached as an image block; for very large images, prefer a smaller crop or resized copy before rereading.${question?.trim() ? `
|
|
8899
|
+
Focus: ${question.trim()}` : ""}` },
|
|
8883
8900
|
{ type: "image", data: imageInfo.base64, mimeType: imageInfo.mimeType }
|
|
8884
8901
|
],
|
|
8885
8902
|
details: {
|
|
@@ -13451,6 +13468,21 @@ function createReadFileUnderstandingHandler(deps) {
|
|
|
13451
13468
|
async function understandFileWithModel(deps, request) {
|
|
13452
13469
|
const purpose = `read_file.${request.kind}`;
|
|
13453
13470
|
const agentModel = deps.getAgentModel();
|
|
13471
|
+
if (request.kind === "image" && request.imageInfo && agentModel?.input.includes("image")) {
|
|
13472
|
+
if (request.signal?.aborted) throw new Error("Operation aborted");
|
|
13473
|
+
return {
|
|
13474
|
+
content: [
|
|
13475
|
+
{ type: "text", text: `Read image file ${request.displayPath} [${request.mimeType}]. Original image attached for the current model.${request.question?.trim() ? `
|
|
13476
|
+
Focus: ${request.question.trim()}` : ""}` },
|
|
13477
|
+
{ type: "image", data: request.imageInfo.base64, mimeType: request.imageInfo.mimeType }
|
|
13478
|
+
],
|
|
13479
|
+
details: {
|
|
13480
|
+
image: { mimeType: request.imageInfo.mimeType, width: request.imageInfo.width, height: request.imageInfo.height },
|
|
13481
|
+
understanding: { purpose, kind: request.kind, mimeType: request.mimeType, agentModel: getModelLabel(agentModel), routeSource: "current_model", inputMode: "nativeAttachment" }
|
|
13482
|
+
},
|
|
13483
|
+
isError: false
|
|
13484
|
+
};
|
|
13485
|
+
}
|
|
13454
13486
|
const singleDecision = deps.resolveToolModel(purpose);
|
|
13455
13487
|
const candidateDecisions = deps.resolveToolModelCandidates?.(purpose) ?? [singleDecision];
|
|
13456
13488
|
const sessionId = deps.getSessionId() || `read-file-${Date.now()}`;
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
createSharedWebSearchTool,
|
|
9
9
|
interpretShellExit,
|
|
10
10
|
requestInteraction
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LO2V5DZZ.js";
|
|
12
12
|
import {
|
|
13
13
|
getBuiltinDir,
|
|
14
14
|
getConfigDir
|
|
@@ -1176,7 +1176,12 @@ function createCliRenderedPageReader() {
|
|
|
1176
1176
|
networkRequests: linesOf(stripHelpHints(networkOutput))
|
|
1177
1177
|
};
|
|
1178
1178
|
} finally {
|
|
1179
|
-
|
|
1179
|
+
try {
|
|
1180
|
+
await runAxi(["stop"], { env, timeoutMs: 15e3 });
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
process.stderr.write(`[rendered-page-reader] axi stop after read failed: ${error instanceof Error ? error.message : String(error)}
|
|
1183
|
+
`);
|
|
1184
|
+
}
|
|
1180
1185
|
}
|
|
1181
1186
|
};
|
|
1182
1187
|
}
|
|
@@ -2960,6 +2960,7 @@ function convertMessages(model, context, compat) {
|
|
|
2960
2960
|
const hasContent = content !== null && content !== void 0 && (typeof content === "string" ? content.length > 0 : Array.isArray(content) && content.length > 0);
|
|
2961
2961
|
if (hasContent || assistantMsg.tool_calls) params.push(assistantMsg);
|
|
2962
2962
|
} else if (msg.role === "toolResult") {
|
|
2963
|
+
const attachments = [];
|
|
2963
2964
|
for (; i < transformedMessages.length && transformedMessages[i].role === "toolResult"; i++) {
|
|
2964
2965
|
const toolMsg = transformedMessages[i];
|
|
2965
2966
|
const textResult = toolMsg.content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
|
|
@@ -2970,7 +2971,15 @@ function convertMessages(model, context, compat) {
|
|
|
2970
2971
|
};
|
|
2971
2972
|
if (compat.requiresToolResultName && toolMsg.toolName) toolResultMsg.name = toolMsg.toolName;
|
|
2972
2973
|
params.push(toolResultMsg);
|
|
2974
|
+
if (model.input.includes("image")) {
|
|
2975
|
+
const images = toolMsg.content.filter((c) => c.type === "image");
|
|
2976
|
+
if (images.length > 0) {
|
|
2977
|
+
attachments.push({ type: "text", text: `Images from tool ${toolMsg.toolName ?? "unknown"} (call ${toolMsg.toolCallId}):` });
|
|
2978
|
+
for (const image of images) attachments.push(...convertUserContentItem(image));
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2973
2981
|
}
|
|
2982
|
+
if (attachments.length > 0) params.push({ role: "user", content: attachments });
|
|
2974
2983
|
i -= 1;
|
|
2975
2984
|
}
|
|
2976
2985
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
EventStream
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UD7KYQ6J.js";
|
|
5
5
|
import "./chunk-XXGYUYXI.js";
|
|
6
6
|
import "./chunk-LZQXQOPJ.js";
|
|
7
7
|
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
createCliWebResearchHealthStore,
|
|
8
8
|
formatSize,
|
|
9
9
|
truncateHeadTail
|
|
10
|
-
} from "./chunks/chunk-
|
|
10
|
+
} from "./chunks/chunk-M4OJARWJ.js";
|
|
11
11
|
import {
|
|
12
12
|
AGENTS_CONTEXT_FILE_NAME,
|
|
13
13
|
AgentSessionController,
|
|
@@ -60,8 +60,8 @@ import {
|
|
|
60
60
|
setExtensionEnabledInSettings,
|
|
61
61
|
shouldPreserveExecutionStateForUserText,
|
|
62
62
|
supersedeExecutionState
|
|
63
|
-
} from "./chunks/chunk-
|
|
64
|
-
import "./chunks/chunk-
|
|
63
|
+
} from "./chunks/chunk-LO2V5DZZ.js";
|
|
64
|
+
import "./chunks/chunk-RTTGO2A6.js";
|
|
65
65
|
import {
|
|
66
66
|
Deref,
|
|
67
67
|
EMPTY_ASSISTANT_CONTENT_ERROR,
|
|
@@ -85,7 +85,7 @@ import {
|
|
|
85
85
|
setLogger,
|
|
86
86
|
sortToolModelCandidatesByCapability,
|
|
87
87
|
type_exports
|
|
88
|
-
} from "./chunks/chunk-
|
|
88
|
+
} from "./chunks/chunk-UD7KYQ6J.js";
|
|
89
89
|
import {
|
|
90
90
|
VERSION,
|
|
91
91
|
getAgentDir,
|
|
@@ -55210,8 +55210,11 @@ function publishJournalPath(sessionsDir, safeTargetId) {
|
|
|
55210
55210
|
return path7.join(sessionsDir, PUBLISH_JOURNAL_DIR, `${safeTargetId}.json`);
|
|
55211
55211
|
}
|
|
55212
55212
|
var FSYNC_UNSUPPORTED_CODES = /* @__PURE__ */ new Set(["EPERM", "EINVAL", "ENOTSUP", "EOPNOTSUPP", "EACCES", "EBADF"]);
|
|
55213
|
+
var fsyncDirectoryFaultForTests = {};
|
|
55213
55214
|
function fsyncDirectory(dirPath) {
|
|
55214
55215
|
try {
|
|
55216
|
+
const injected = fsyncDirectoryFaultForTests.fault?.(dirPath);
|
|
55217
|
+
if (injected) throw injected;
|
|
55215
55218
|
const fd = fs7.openSync(dirPath, "r");
|
|
55216
55219
|
try {
|
|
55217
55220
|
fs7.fsyncSync(fd);
|
|
@@ -55430,11 +55433,21 @@ async function forkStoredSession(params) {
|
|
|
55430
55433
|
if (hadPreviousTarget) {
|
|
55431
55434
|
try {
|
|
55432
55435
|
params.store.moveSession(params.targetSessionId, backupId);
|
|
55433
|
-
if (params.sessionsDir) fsyncDirectory(params.sessionsDir);
|
|
55434
55436
|
} catch (error) {
|
|
55435
55437
|
clearPublishJournal(journalPath);
|
|
55436
55438
|
throw error;
|
|
55437
55439
|
}
|
|
55440
|
+
try {
|
|
55441
|
+
if (params.sessionsDir) fsyncDirectory(params.sessionsDir);
|
|
55442
|
+
} catch (error) {
|
|
55443
|
+
markPublishJournalFailed(journalPath);
|
|
55444
|
+
preserveStagingForRecovery = true;
|
|
55445
|
+
throw new SessionControlError(
|
|
55446
|
+
"session_io_error",
|
|
55447
|
+
`Fork publish durability failure after moving the previous session aside; it is preserved as ${backupId} and startup recovery will restore it: ${String(error)}`,
|
|
55448
|
+
false
|
|
55449
|
+
);
|
|
55450
|
+
}
|
|
55438
55451
|
}
|
|
55439
55452
|
try {
|
|
55440
55453
|
params.store.moveSession(stagingId, params.targetSessionId);
|
|
@@ -70137,22 +70150,40 @@ var SettingsSelectorComponent = class extends Container {
|
|
|
70137
70150
|
};
|
|
70138
70151
|
|
|
70139
70152
|
// src/core/session-display.ts
|
|
70153
|
+
function looksAutoGeneratedSessionName(name) {
|
|
70154
|
+
return /^Session (\d|[a-z0-9]{6,8}$)/i.test(name.trim());
|
|
70155
|
+
}
|
|
70156
|
+
function persistedNameIsAuthoritative(metadata) {
|
|
70157
|
+
if (metadata.nameSource === "derived") return true;
|
|
70158
|
+
if (metadata.nameSource === void 0) return !looksAutoGeneratedSessionName(metadata.name);
|
|
70159
|
+
return false;
|
|
70160
|
+
}
|
|
70140
70161
|
function deriveSessionTitle(options) {
|
|
70141
70162
|
const { activeSession, messages } = options;
|
|
70142
70163
|
if (!activeSession) {
|
|
70143
70164
|
return "No session";
|
|
70144
70165
|
}
|
|
70166
|
+
if (activeSession.metadata.nameSource === "manual") {
|
|
70167
|
+
const manual = normalizeSessionTitle(activeSession.metadata.name);
|
|
70168
|
+
if (manual) return manual;
|
|
70169
|
+
}
|
|
70170
|
+
if (persistedNameIsAuthoritative(activeSession.metadata)) {
|
|
70171
|
+
const persisted = normalizeSessionTitle(activeSession.metadata.name);
|
|
70172
|
+
if (persisted) return persisted;
|
|
70173
|
+
}
|
|
70145
70174
|
for (const msg of messages) {
|
|
70146
70175
|
if (msg.role !== "user") continue;
|
|
70147
70176
|
const text = extractUserText(msg);
|
|
70148
70177
|
if (isCompactSummaryMessage(text.trimStart())) continue;
|
|
70149
70178
|
const normalized = normalizeSessionTitle(text);
|
|
70150
70179
|
if (normalized) {
|
|
70180
|
+
activeSession.metadata.name = normalized;
|
|
70181
|
+
activeSession.metadata.nameSource = "derived";
|
|
70151
70182
|
return normalized;
|
|
70152
70183
|
}
|
|
70153
70184
|
}
|
|
70154
70185
|
const metadataName = normalizeSessionTitle(activeSession.metadata.name);
|
|
70155
|
-
if (metadataName &&
|
|
70186
|
+
if (metadataName && persistedNameIsAuthoritative(activeSession.metadata)) {
|
|
70156
70187
|
return metadataName;
|
|
70157
70188
|
}
|
|
70158
70189
|
return `S:${activeSession.id.slice(-6)}`;
|
|
@@ -77094,7 +77125,9 @@ function updatePendingMessagesDisplay(host) {
|
|
|
77094
77125
|
host.pendingMessagesContainer.addChild(new Text(text, 1, 0));
|
|
77095
77126
|
}
|
|
77096
77127
|
const dequeueHint = host.keybindings.getKeys("dequeue")[0] || "alt+up";
|
|
77097
|
-
const
|
|
77128
|
+
const steerHint = host.keybindings.getKeys("steer")[0];
|
|
77129
|
+
const promotionHint = followUpMessages.length > 0 && !followUpMessages[followUpMessages.length - 1].deliveredToAgent && steerHint ? `${steerHint} with empty editor: steer latest follow-up \xB7 ` : "";
|
|
77130
|
+
const hintText = theme.fg("dim", `\u21B3 ${promotionHint}${dequeueHint}: edit all queued messages`);
|
|
77098
77131
|
host.pendingMessagesContainer.addChild(new Text(hintText, 1, 0));
|
|
77099
77132
|
}
|
|
77100
77133
|
function dequeueMessages(host) {
|
|
@@ -77150,7 +77183,7 @@ function queueMessage(host, text, mode, options = {}) {
|
|
|
77150
77183
|
}
|
|
77151
77184
|
updatePendingMessagesDisplay(host);
|
|
77152
77185
|
host.showStatus(
|
|
77153
|
-
options.statusMessage ||
|
|
77186
|
+
options.statusMessage || (mode === "steer" ? "Queued message for steering" : `Queued for follow-up after the current task.${host.keybindings.getKeys("steer")[0] ? ` With empty editor, press ${host.keybindings.getKeys("steer")[0]} to steer the current task instead.` : ""}`)
|
|
77154
77187
|
);
|
|
77155
77188
|
host.ui.requestRender();
|
|
77156
77189
|
}
|
|
@@ -77169,7 +77202,22 @@ function handleFollowUp(host) {
|
|
|
77169
77202
|
}
|
|
77170
77203
|
function handleSteer(host) {
|
|
77171
77204
|
const text = host.editor.getText().trim();
|
|
77172
|
-
if (!text)
|
|
77205
|
+
if (!text) {
|
|
77206
|
+
const promoted = host.agentSessionController?.promoteLatestFollowUpToSteer();
|
|
77207
|
+
if (!promoted) {
|
|
77208
|
+
host.showStatus("No waiting follow-up to steer (it may already be processing)");
|
|
77209
|
+
return;
|
|
77210
|
+
}
|
|
77211
|
+
if (host.executionState.applyUserTextLifecycle(promoted.displayText)) {
|
|
77212
|
+
host.persistExecutionState();
|
|
77213
|
+
void host.refreshTodoWidget();
|
|
77214
|
+
}
|
|
77215
|
+
host.logDebug("queue:promote", { id: promoted.id, mode: promoted.mode });
|
|
77216
|
+
updatePendingMessagesDisplay(host);
|
|
77217
|
+
host.showStatus("Latest follow-up changed to steer; it will guide the current task at the next message boundary");
|
|
77218
|
+
host.ui.requestRender();
|
|
77219
|
+
return;
|
|
77220
|
+
}
|
|
77173
77221
|
if (isCommandLikeInput(text)) {
|
|
77174
77222
|
host.editor.onSubmit?.(text);
|
|
77175
77223
|
return;
|
|
@@ -79986,7 +80034,7 @@ var InteractiveMode = class {
|
|
|
79986
80034
|
async init() {
|
|
79987
80035
|
const activeSession = this.sessionManager.getActiveSession();
|
|
79988
80036
|
this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
|
|
79989
|
-
const { Agent } = await import("./chunks/src-
|
|
80037
|
+
const { Agent } = await import("./chunks/src-33WRCQWX.js");
|
|
79990
80038
|
this.agent = new Agent({
|
|
79991
80039
|
initialState: {
|
|
79992
80040
|
systemPrompt: this.buildSystemPrompt(),
|
|
@@ -80820,7 +80868,7 @@ async function runPrintMode(params) {
|
|
|
80820
80868
|
`);
|
|
80821
80869
|
console.log("Assistant: ");
|
|
80822
80870
|
}
|
|
80823
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
80871
|
+
const { Agent: AgentClass } = await import("./chunks/src-33WRCQWX.js");
|
|
80824
80872
|
let agent;
|
|
80825
80873
|
const printModeExtensions = await loadPrintModeExtensions({
|
|
80826
80874
|
cwd: runtime.cwd,
|
|
@@ -81681,7 +81729,7 @@ async function runJsonEventsMode(params) {
|
|
|
81681
81729
|
return;
|
|
81682
81730
|
}
|
|
81683
81731
|
const parent = agent;
|
|
81684
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
81732
|
+
const { Agent: AgentClass } = await import("./chunks/src-33WRCQWX.js");
|
|
81685
81733
|
const sideAgent = new AgentClass({
|
|
81686
81734
|
initialState: {
|
|
81687
81735
|
systemPrompt: parent.state.systemPrompt,
|
|
@@ -82025,7 +82073,7 @@ async function runJsonEventsMode(params) {
|
|
|
82025
82073
|
if (runtime.initialModel.unconfigured || controller) {
|
|
82026
82074
|
return;
|
|
82027
82075
|
}
|
|
82028
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
82076
|
+
const { Agent: AgentClass } = await import("./chunks/src-33WRCQWX.js");
|
|
82029
82077
|
const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
|
|
82030
82078
|
extensionRunner = jsonModeExtensions.runner;
|
|
82031
82079
|
const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
|
|
@@ -82614,7 +82662,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
|
|
|
82614
82662
|
}
|
|
82615
82663
|
async function createCliTestStreamFnFromEnv() {
|
|
82616
82664
|
if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
|
|
82617
|
-
return (await import("./chunks/test-stream-
|
|
82665
|
+
return (await import("./chunks/test-stream-LFR6GSKQ.js")).createTestStreamFnFromSequenceEnv();
|
|
82618
82666
|
}
|
|
82619
82667
|
function resolveJsonEventsDetailFlag() {
|
|
82620
82668
|
for (let index = 0; index < process.argv.length; index += 1) {
|