@cydm/pie 2.5.0 → 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/herdr-agent-state/index.js +39 -3
- package/dist/builtin/extensions/mcp-adapter/index.js +161 -35
- 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-JXY3YLDS.js → chunk-LO2V5DZZ.js} +46 -9
- package/dist/chunks/{chunk-PU7IIEKH.js → chunk-M4OJARWJ.js} +25 -15
- 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 +117 -20
- 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
|
|
|
@@ -136,7 +136,42 @@ function spawnHerdrReport(binPath, args, timeoutMs = REPORT_TIMEOUT_MS) {
|
|
|
136
136
|
} catch {
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
-
|
|
139
|
+
var KILL_GRACE_MS = 1e3;
|
|
140
|
+
async function runHerdrReportBounded(binPath, args, timeoutMs = REPORT_TIMEOUT_MS) {
|
|
141
|
+
let child;
|
|
142
|
+
try {
|
|
143
|
+
child = spawn(binPath, args, { detached: true, stdio: "ignore" });
|
|
144
|
+
} catch {
|
|
145
|
+
return { outcome: "spawn-error", exitCode: null };
|
|
146
|
+
}
|
|
147
|
+
return await new Promise((resolve) => {
|
|
148
|
+
let killTimer;
|
|
149
|
+
let settled = false;
|
|
150
|
+
const finish = (outcome, exitCode) => {
|
|
151
|
+
if (settled) return;
|
|
152
|
+
settled = true;
|
|
153
|
+
clearTimeout(timer);
|
|
154
|
+
if (killTimer) clearTimeout(killTimer);
|
|
155
|
+
resolve({ outcome, exitCode });
|
|
156
|
+
};
|
|
157
|
+
const timer = setTimeout(() => {
|
|
158
|
+
try {
|
|
159
|
+
child.kill("SIGTERM");
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
killTimer = setTimeout(() => {
|
|
163
|
+
try {
|
|
164
|
+
if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
killTimer = setTimeout(() => finish("escalated", child.exitCode), 250);
|
|
168
|
+
}, KILL_GRACE_MS);
|
|
169
|
+
}, timeoutMs);
|
|
170
|
+
child.on("error", () => finish("spawn-error", null));
|
|
171
|
+
child.on("exit", (code) => finish("exited", code));
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
function attachHerdrReporter(host, herdr, transport = (args) => spawnHerdrReport(herdr.binPath, args), sequencer = createReportSequencer(), shutdownTransport = (args) => runHerdrReportBounded(herdr.binPath, args)) {
|
|
140
175
|
const nextSeq = sequencer;
|
|
141
176
|
let agentActive = false;
|
|
142
177
|
const blockingToolCalls = /* @__PURE__ */ new Map();
|
|
@@ -238,10 +273,10 @@ function attachHerdrReporter(host, herdr, transport = (args) => spawnHerdrReport
|
|
|
238
273
|
}
|
|
239
274
|
publishState();
|
|
240
275
|
});
|
|
241
|
-
host.registerCleanup?.((reason) => {
|
|
276
|
+
host.registerCleanup?.(async (reason) => {
|
|
242
277
|
if (reason !== "shutdown") return;
|
|
243
278
|
if (!heldPane) return;
|
|
244
|
-
|
|
279
|
+
await shutdownTransport(
|
|
245
280
|
buildReleaseReportArgs({
|
|
246
281
|
paneId: herdr.paneId,
|
|
247
282
|
source: SOURCE_ID,
|
|
@@ -267,6 +302,7 @@ export {
|
|
|
267
302
|
createReportSequencer,
|
|
268
303
|
herdrAgentStateExtension as default,
|
|
269
304
|
readHerdrEnvironment,
|
|
305
|
+
runHerdrReportBounded,
|
|
270
306
|
spawnHerdrReport,
|
|
271
307
|
summarizeAskUserQuestion
|
|
272
308
|
};
|
|
@@ -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,13 +24776,16 @@ 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
|
-
|
|
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) {
|
|
24728
24784
|
claim2(tool, false);
|
|
24729
24785
|
}
|
|
24730
24786
|
}
|
|
24731
24787
|
for (const runtime of this.runtimes.values()) {
|
|
24788
|
+
if (runtime.definition.disabled) continue;
|
|
24732
24789
|
for (const tool of runtime.tools ?? []) claim2(tool, true);
|
|
24733
24790
|
}
|
|
24734
24791
|
for (const name of conflicts) {
|
|
@@ -24784,7 +24841,10 @@ var McpServerManager = class {
|
|
|
24784
24841
|
if (typeof parsed.updatedAt !== "number" || this.now() - parsed.updatedAt > METADATA_TTL_MS) continue;
|
|
24785
24842
|
if (!Array.isArray(parsed.tools)) continue;
|
|
24786
24843
|
const key = name.slice(0, -".json".length);
|
|
24787
|
-
snapshot[key] =
|
|
24844
|
+
snapshot[key] = {
|
|
24845
|
+
tools: parsed.tools,
|
|
24846
|
+
...typeof parsed.fingerprint === "string" ? { fingerprint: parsed.fingerprint } : {}
|
|
24847
|
+
};
|
|
24788
24848
|
updatedAt[key] = parsed.updatedAt;
|
|
24789
24849
|
} catch {
|
|
24790
24850
|
}
|
|
@@ -24828,12 +24888,16 @@ var McpServerManager = class {
|
|
|
24828
24888
|
} catch (error2) {
|
|
24829
24889
|
const runtimeState = this.runtimes.get(server);
|
|
24830
24890
|
const tail = runtimeState?.stderrTail.trim();
|
|
24891
|
+
const secrets = definitionSecrets(definition);
|
|
24831
24892
|
return {
|
|
24832
24893
|
delivery: "not_sent",
|
|
24833
|
-
error:
|
|
24894
|
+
error: sanitizeDiagnostic(
|
|
24895
|
+
`MCP server "${server}" failed to start: ${error2 instanceof Error ? error2.message : String(error2)}` + (tail ? `
|
|
24834
24896
|
|
|
24835
24897
|
Server stderr tail:
|
|
24836
|
-
${tail}` : "")
|
|
24898
|
+
${tail}` : ""),
|
|
24899
|
+
secrets
|
|
24900
|
+
)
|
|
24837
24901
|
};
|
|
24838
24902
|
}
|
|
24839
24903
|
const client = runtime.client;
|
|
@@ -24849,6 +24913,20 @@ ${tail}` : "")
|
|
|
24849
24913
|
error: `MCP call "${prefixedName}" was cancelled before the request was sent; nothing was executed.`
|
|
24850
24914
|
};
|
|
24851
24915
|
}
|
|
24916
|
+
const postConnectCatalog = this.loadCatalog();
|
|
24917
|
+
if (this.conflictedNames.has(prefixedName)) {
|
|
24918
|
+
return {
|
|
24919
|
+
delivery: "not_sent",
|
|
24920
|
+
error: `MCP tool name "${prefixedName}" became claimed by more than one server during connection. Rename one of the servers so every tool name is unambiguous; the call was NOT sent.`
|
|
24921
|
+
};
|
|
24922
|
+
}
|
|
24923
|
+
const postDescriptor = postConnectCatalog.find((tool) => tool.prefixedName === prefixedName);
|
|
24924
|
+
if (postDescriptor && (postDescriptor.server !== server || postDescriptor.tool !== toolName)) {
|
|
24925
|
+
return {
|
|
24926
|
+
delivery: "not_sent",
|
|
24927
|
+
error: `MCP tool "${prefixedName}" resolved to ${postDescriptor.server}/${postDescriptor.tool} after connecting; refusing to send the stale target ${server}/${toolName}. Retry the call.`
|
|
24928
|
+
};
|
|
24929
|
+
}
|
|
24852
24930
|
try {
|
|
24853
24931
|
const result = await withTimeout(
|
|
24854
24932
|
client.callTool({ name: toolName, arguments: args }, void 0, signal !== void 0 ? { signal } : void 0),
|
|
@@ -24863,7 +24941,7 @@ ${tail}` : "")
|
|
|
24863
24941
|
isError: result.isError === true
|
|
24864
24942
|
};
|
|
24865
24943
|
} catch (error2) {
|
|
24866
|
-
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
24944
|
+
const message = sanitizeDiagnostic(error2 instanceof Error ? error2.message : String(error2), definitionSecrets(definition));
|
|
24867
24945
|
if (error2 instanceof ProtocolError && (error2.code === ProtocolErrorCode.InvalidRequest || error2.code === ProtocolErrorCode.InvalidParams) && /output schema|structured content/i.test(message)) {
|
|
24868
24946
|
return {
|
|
24869
24947
|
delivery: "invalid_result",
|
|
@@ -24898,7 +24976,7 @@ ${tail}` : "")
|
|
|
24898
24976
|
};
|
|
24899
24977
|
|
|
24900
24978
|
// builtin/extensions/mcp-adapter/src/trust.ts
|
|
24901
|
-
import { createHash } from "node:crypto";
|
|
24979
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
24902
24980
|
import * as fs3 from "node:fs";
|
|
24903
24981
|
import * as path3 from "node:path";
|
|
24904
24982
|
function serverFingerprint(cwd, definition) {
|
|
@@ -24917,7 +24995,7 @@ function serverFingerprint(cwd, definition) {
|
|
|
24917
24995
|
inheritEnv: definition.inheritEnv,
|
|
24918
24996
|
headers: definition.headers
|
|
24919
24997
|
});
|
|
24920
|
-
return
|
|
24998
|
+
return createHash2("sha256").update(spec).digest("hex").slice(0, 24);
|
|
24921
24999
|
}
|
|
24922
25000
|
var McpTrustStore = class {
|
|
24923
25001
|
filePath;
|
|
@@ -25018,8 +25096,9 @@ function structuredContentIsMirroredInText(textBlocks, structured) {
|
|
|
25018
25096
|
function mapMcpOutcome(outcome, maxBytes) {
|
|
25019
25097
|
if (outcome.delivery !== "ok") {
|
|
25020
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);
|
|
25021
25100
|
return {
|
|
25022
|
-
content: [{ type: "text", text: `${prefix} ${
|
|
25101
|
+
content: [{ type: "text", text: `${prefix} ${errorText}` }],
|
|
25023
25102
|
details: { mode: "mcp", delivery: outcome.delivery, ...outcome.protocolCode !== void 0 ? { protocolCode: outcome.protocolCode } : {} },
|
|
25024
25103
|
isError: true
|
|
25025
25104
|
};
|
|
@@ -25054,8 +25133,9 @@ ${JSON.stringify(outcome.structuredContent, null, 2)}` });
|
|
|
25054
25133
|
isError: outcome.isError === true
|
|
25055
25134
|
};
|
|
25056
25135
|
}
|
|
25057
|
-
function createMcpProxyTool(getManager, ensureTrusted, options = {}) {
|
|
25058
|
-
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;
|
|
25059
25139
|
return {
|
|
25060
25140
|
name: "mcp",
|
|
25061
25141
|
label: "MCP",
|
|
@@ -25107,7 +25187,8 @@ ${truncate(JSON.stringify(schema ?? {}, null, 2), maxBytes)}` : `unknown MCP too
|
|
|
25107
25187
|
const resolved = getManager().resolvePrefixedName(params.tool);
|
|
25108
25188
|
const server = descriptor?.server ?? resolved?.server ?? "";
|
|
25109
25189
|
if (server) {
|
|
25110
|
-
const
|
|
25190
|
+
const managerAtGate = getManager();
|
|
25191
|
+
const trust = await ensureTrusted(server, managerAtGate);
|
|
25111
25192
|
if (!trust.trusted) {
|
|
25112
25193
|
return {
|
|
25113
25194
|
content: [{ type: "text", text: `[not executed] ${trust.reason ?? "MCP server not trusted"}` }],
|
|
@@ -25115,6 +25196,14 @@ ${truncate(JSON.stringify(schema ?? {}, null, 2), maxBytes)}` : `unknown MCP too
|
|
|
25115
25196
|
isError: true
|
|
25116
25197
|
};
|
|
25117
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
|
+
}
|
|
25118
25207
|
}
|
|
25119
25208
|
let args = {};
|
|
25120
25209
|
if (typeof params.args === "string") {
|
|
@@ -25188,7 +25277,7 @@ function jsonSchemaToTypebox(schema) {
|
|
|
25188
25277
|
// builtin/extensions/mcp-adapter/src/direct-tools.ts
|
|
25189
25278
|
var FALLBACK_PARAMS = Type.Object({}, { description: "MCP tool arguments (schema unknown until first connect)" });
|
|
25190
25279
|
var DEFAULT_DIRECT_OUTPUT_MAX_BYTES = 8192;
|
|
25191
|
-
function registerDirectTools(ctx, getManager, ensureTrusted, outputMaxBytes) {
|
|
25280
|
+
function registerDirectTools(ctx, getManager, ensureTrusted, verifyTrusted, outputMaxBytes) {
|
|
25192
25281
|
const registered = [];
|
|
25193
25282
|
const seenNames = /* @__PURE__ */ new Set();
|
|
25194
25283
|
for (const definition of getManager().listDefinitions()) {
|
|
@@ -25202,13 +25291,13 @@ function registerDirectTools(ctx, getManager, ensureTrusted, outputMaxBytes) {
|
|
|
25202
25291
|
continue;
|
|
25203
25292
|
}
|
|
25204
25293
|
seenNames.add(descriptor.prefixedName);
|
|
25205
|
-
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);
|
|
25206
25295
|
registered.push(descriptor.prefixedName);
|
|
25207
25296
|
}
|
|
25208
25297
|
}
|
|
25209
25298
|
return registered;
|
|
25210
25299
|
}
|
|
25211
|
-
function registerDirectTool(ctx, getManager, ensureTrusted, definition, prefixedName, description, inputSchema, outputMaxBytes) {
|
|
25300
|
+
function registerDirectTool(ctx, getManager, ensureTrusted, verifyTrusted, definition, prefixedName, description, inputSchema, outputMaxBytes) {
|
|
25212
25301
|
const parameters = inputSchema ? jsonSchemaToTypebox(inputSchema) : FALLBACK_PARAMS;
|
|
25213
25302
|
ctx.registerTool({
|
|
25214
25303
|
name: prefixedName,
|
|
@@ -25216,7 +25305,8 @@ function registerDirectTool(ctx, getManager, ensureTrusted, definition, prefixed
|
|
|
25216
25305
|
description: `${(description ?? prefixedName).trim()} (MCP server: ${definition.name})`,
|
|
25217
25306
|
parameters,
|
|
25218
25307
|
async execute(args, toolContext) {
|
|
25219
|
-
const
|
|
25308
|
+
const managerAtGate = getManager();
|
|
25309
|
+
const trust = await ensureTrusted(definition.name, managerAtGate);
|
|
25220
25310
|
if (!trust.trusted) {
|
|
25221
25311
|
return {
|
|
25222
25312
|
content: [{ type: "text", text: `[not executed] ${trust.reason ?? "MCP server not trusted"}` }],
|
|
@@ -25224,7 +25314,15 @@ function registerDirectTool(ctx, getManager, ensureTrusted, definition, prefixed
|
|
|
25224
25314
|
isError: true
|
|
25225
25315
|
};
|
|
25226
25316
|
}
|
|
25227
|
-
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(
|
|
25228
25326
|
prefixedName,
|
|
25229
25327
|
args && typeof args === "object" && !Array.isArray(args) ? args : {},
|
|
25230
25328
|
toolContext.signal
|
|
@@ -25266,19 +25364,26 @@ function mcpAdapter(ctx) {
|
|
|
25266
25364
|
ctx.log
|
|
25267
25365
|
);
|
|
25268
25366
|
async function reloadManager() {
|
|
25269
|
-
|
|
25367
|
+
let replacement;
|
|
25270
25368
|
try {
|
|
25271
|
-
|
|
25272
|
-
|
|
25273
|
-
|
|
25274
|
-
ctx.log
|
|
25275
|
-
|
|
25369
|
+
const resolved = resolveMcpAdapterConfig(ctx.cwd, configDir);
|
|
25370
|
+
if (resolved.problems.length > 0) {
|
|
25371
|
+
const message = `config layers failed to parse: ${resolved.problems.join("; ")}`;
|
|
25372
|
+
ctx.log(`mcp: config reload failed, keeping the previous manager: ${message}`);
|
|
25373
|
+
if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error (previous servers kept): ${message}`, "error");
|
|
25374
|
+
return { ok: false, error: message };
|
|
25375
|
+
}
|
|
25376
|
+
replacement = new McpServerManager(resolved.servers, metadataCacheDir, ctx.log);
|
|
25276
25377
|
} catch (error2) {
|
|
25277
25378
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25278
|
-
ctx.log(`mcp: config reload failed: ${message}`);
|
|
25279
|
-
if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error: ${message}`, "error");
|
|
25280
|
-
|
|
25379
|
+
ctx.log(`mcp: config reload failed, keeping the previous manager: ${message}`);
|
|
25380
|
+
if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error (previous servers kept): ${message}`, "error");
|
|
25381
|
+
return { ok: false, error: message };
|
|
25281
25382
|
}
|
|
25383
|
+
const previous = manager;
|
|
25384
|
+
manager = replacement;
|
|
25385
|
+
await previous.dispose().catch(() => void 0);
|
|
25386
|
+
return { ok: true };
|
|
25282
25387
|
}
|
|
25283
25388
|
ctx.registerCleanup?.(() => manager.dispose().catch(() => void 0));
|
|
25284
25389
|
function readProjectOverride() {
|
|
@@ -25312,8 +25417,8 @@ function mcpAdapter(ctx) {
|
|
|
25312
25417
|
fs4.writeFileSync(filePath, JSON.stringify(parsed, null, 2) + "\n", "utf8");
|
|
25313
25418
|
return filePath;
|
|
25314
25419
|
}
|
|
25315
|
-
async function ensureTrusted(serverName) {
|
|
25316
|
-
const definition =
|
|
25420
|
+
async function ensureTrusted(serverName, managerAtGate = manager) {
|
|
25421
|
+
const definition = managerAtGate.getDefinition(serverName);
|
|
25317
25422
|
if (!definition) return { trusted: false, reason: `unknown MCP server "${serverName}"` };
|
|
25318
25423
|
if (trustStore.isTrusted(ctx.cwd, definition)) return { trusted: true };
|
|
25319
25424
|
if (!ctx.interactions.isAvailable()) {
|
|
@@ -25337,8 +25442,12 @@ function mcpAdapter(ctx) {
|
|
|
25337
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}.`
|
|
25338
25443
|
};
|
|
25339
25444
|
}
|
|
25340
|
-
|
|
25341
|
-
|
|
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);
|
|
25342
25451
|
if (eagerRegistered.length > 0) {
|
|
25343
25452
|
ctx.log(`mcp: registered ${eagerRegistered.length} direct tool(s) from metadata cache: ${eagerRegistered.join(", ")}`);
|
|
25344
25453
|
}
|
|
@@ -25359,6 +25468,7 @@ function mcpAdapter(ctx) {
|
|
|
25359
25468
|
}
|
|
25360
25469
|
const overrides = readProjectOverride().mcpServers;
|
|
25361
25470
|
const forceEnabled = overrides?.[definition.name]?.disabled === false;
|
|
25471
|
+
const previousOverride = overrides?.[definition.name]?.disabled;
|
|
25362
25472
|
const filePath = writeProjectOverride(
|
|
25363
25473
|
definition.name,
|
|
25364
25474
|
// enable must lift a source-level disabled:true with an explicit
|
|
@@ -25367,8 +25477,24 @@ function mcpAdapter(ctx) {
|
|
|
25367
25477
|
// existing force-enable on repeated enable commands too.
|
|
25368
25478
|
sub === "disable" ? true : definition.disabled || forceEnabled ? false : null
|
|
25369
25479
|
);
|
|
25370
|
-
await reloadManager();
|
|
25371
|
-
|
|
25480
|
+
const reload = await reloadManager();
|
|
25481
|
+
if (!reload.ok) {
|
|
25482
|
+
writeProjectOverride(definition.name, previousOverride === void 0 ? null : previousOverride);
|
|
25483
|
+
commandCtx.ui.notify(
|
|
25484
|
+
`MCP server "${definition.name}" NOT ${sub === "disable" ? "disabled" : "enabled"}: config reload failed (${reload.error}); previous servers kept and the override was rolled back.`,
|
|
25485
|
+
"error"
|
|
25486
|
+
);
|
|
25487
|
+
return;
|
|
25488
|
+
}
|
|
25489
|
+
const reloaded = manager.getDefinition(definition.name);
|
|
25490
|
+
if (!reloaded) {
|
|
25491
|
+
commandCtx.ui.notify(
|
|
25492
|
+
`MCP server "${definition.name}" disappeared from the reloaded config (wrote ${filePath}); check project/global config merges.`,
|
|
25493
|
+
"error"
|
|
25494
|
+
);
|
|
25495
|
+
return;
|
|
25496
|
+
}
|
|
25497
|
+
const effectiveDisabled = reloaded.disabled;
|
|
25372
25498
|
const stateLabel = effectiveDisabled ? "disabled" : sub === "disable" ? "still enabled" : "enabled";
|
|
25373
25499
|
commandCtx.ui.notify(
|
|
25374
25500
|
`MCP server "${definition.name}" ${stateLabel} (wrote ${filePath}). ` + (eagerRegistered.length > 0 ? "Restart or /reload to resync direct tools." : "Effective immediately."),
|
|
@@ -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";
|