@cydm/pie 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/computer-use/index.js +49 -12
- package/dist/builtin/extensions/computer-use/package.json +3 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/arm64/pie-computer-use +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/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/build-native.mjs +2 -1
- package/dist/builtin/extensions/computer-use/scripts/setup-helper.mjs +2 -2
- package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +204 -0
- package/dist/builtin/extensions/herdr-agent-state/index.js +272 -0
- package/dist/builtin/extensions/herdr-agent-state/package.json +11 -0
- package/dist/builtin/extensions/mcp-adapter/index.js +188 -74
- package/dist/builtin/extensions/plan-mode/index.js +3 -3
- package/dist/builtin/extensions/subagent/index.js +5 -5
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-runtime.js +1 -1
- package/dist/builtin/skills/chrome-devtools-axi/{cli-F2VCSVL4.js → cli-P4VG6ZZG.js} +48 -8
- package/dist/builtin/skills/skill-creator/scripts/pie_runner.mjs +33 -12
- package/dist/builtin/skills/tui-use/tui-use-daemon.cjs +5 -7
- package/dist/chunks/{chunk-HH2Q2SNX.js → chunk-FKUEIYFQ.js} +8213 -7367
- package/dist/chunks/{chunk-G3SE3I2L.js → chunk-XVUV3IM2.js} +112 -40
- package/dist/chunks/{chunk-IM43UYVV.js → chunk-YRXXRLMQ.js} +75 -14
- package/dist/chunks/{chunk-QJH6YN2W.js → chunk-ZKHMNEXL.js} +1 -1
- package/dist/chunks/{src-QSP2OPHU.js → src-SXUQ7OY6.js} +2 -2
- package/dist/chunks/{test-stream-CVGWFLSX.js → test-stream-OD3B57AS.js} +1 -1
- package/dist/cli.js +1321 -894
- package/package.json +2 -2
|
@@ -544,6 +544,7 @@ function normalizeEntry(name, raw, sourcePath, sourceScope, homeDir) {
|
|
|
544
544
|
const hasStdio = typeof raw.command === "string" && raw.command.length > 0;
|
|
545
545
|
const hasHttp = typeof raw.url === "string" && raw.url.length > 0;
|
|
546
546
|
if (!hasStdio && !hasHttp) return null;
|
|
547
|
+
const directTools = normalizeDirectTools(raw.directTools);
|
|
547
548
|
return {
|
|
548
549
|
name,
|
|
549
550
|
command: hasStdio ? expandHome(raw.command, homeDir) : void 0,
|
|
@@ -554,8 +555,8 @@ function normalizeEntry(name, raw, sourcePath, sourceScope, homeDir) {
|
|
|
554
555
|
headers: asStringRecord(raw.headers),
|
|
555
556
|
inheritEnv: raw.inheritEnv !== false,
|
|
556
557
|
connectTimeoutMs: typeof raw.connectTimeoutMs === "number" && Number.isFinite(raw.connectTimeoutMs) && raw.connectTimeoutMs > 0 ? raw.connectTimeoutMs : void 0,
|
|
557
|
-
directTools:
|
|
558
|
-
directToolsWhitelist:
|
|
558
|
+
directTools: directTools.mode,
|
|
559
|
+
directToolsWhitelist: directTools.whitelist,
|
|
559
560
|
disabled: raw.disabled === true,
|
|
560
561
|
sourcePath,
|
|
561
562
|
sourceScope
|
|
@@ -615,8 +616,8 @@ function resolveMcpAdapterConfig(cwd, configDir, homeDir = os.homedir()) {
|
|
|
615
616
|
continue;
|
|
616
617
|
}
|
|
617
618
|
const existing = merged.get(name);
|
|
618
|
-
if (existing && raw.disabled === true) {
|
|
619
|
-
merged.set(name, { ...existing, disabled:
|
|
619
|
+
if (existing && (raw.disabled === true || raw.disabled === false)) {
|
|
620
|
+
merged.set(name, { ...existing, disabled: raw.disabled });
|
|
620
621
|
}
|
|
621
622
|
}
|
|
622
623
|
}
|
|
@@ -24438,6 +24439,7 @@ import * as path2 from "node:path";
|
|
|
24438
24439
|
var CONNECT_TIMEOUT_MS = 3e4;
|
|
24439
24440
|
var PACKAGE_MANAGER_CONNECT_TIMEOUT_MS = 12e4;
|
|
24440
24441
|
var PACKAGE_MANAGER_COMMANDS = /* @__PURE__ */ new Set(["npx", "npm", "bunx", "uvx", "uv", "pnpm", "pnpmx"]);
|
|
24442
|
+
var METADATA_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
24441
24443
|
var CALL_TIMEOUT_MS = 12e4;
|
|
24442
24444
|
var STDERR_TAIL_LIMIT = 4e3;
|
|
24443
24445
|
function connectTimeoutFor(definition) {
|
|
@@ -24445,6 +24447,17 @@ function connectTimeoutFor(definition) {
|
|
|
24445
24447
|
const base = path2.basename(definition.command ?? "");
|
|
24446
24448
|
return PACKAGE_MANAGER_COMMANDS.has(base) ? PACKAGE_MANAGER_CONNECT_TIMEOUT_MS : CONNECT_TIMEOUT_MS;
|
|
24447
24449
|
}
|
|
24450
|
+
function unpinnedWarnings(definitions) {
|
|
24451
|
+
const commandPattern = new RegExp(`(^|\\s)(?:${[...PACKAGE_MANAGER_COMMANDS].join("|")})\\s`);
|
|
24452
|
+
const warnings = [];
|
|
24453
|
+
for (const definition of definitions) {
|
|
24454
|
+
const spec = [definition.command ?? "", ...definition.args].join(" ");
|
|
24455
|
+
if (commandPattern.test(spec) && /@latest\b/.test(spec)) {
|
|
24456
|
+
warnings.push(`${definition.name}: unpinned "@latest" fetch \u2014 pin an exact version (e.g. pkg@1.2.3).`);
|
|
24457
|
+
}
|
|
24458
|
+
}
|
|
24459
|
+
return warnings;
|
|
24460
|
+
}
|
|
24448
24461
|
function appendTail(tail, chunk) {
|
|
24449
24462
|
return (tail + String(chunk)).slice(-STDERR_TAIL_LIMIT);
|
|
24450
24463
|
}
|
|
@@ -24487,15 +24500,8 @@ function withTimeout(promise, timeoutMs, label, signal) {
|
|
|
24487
24500
|
});
|
|
24488
24501
|
}
|
|
24489
24502
|
var McpServerManager = class {
|
|
24490
|
-
|
|
24491
|
-
|
|
24492
|
-
cachePath;
|
|
24493
|
-
log;
|
|
24494
|
-
/** Set by dispose(); after it, no new connects and no late attach. */
|
|
24495
|
-
disposed = false;
|
|
24496
|
-
/** Prefixed names claimed by more than one server in the last loadCatalog(); callTool fail-closes on them. */
|
|
24497
|
-
conflictedNames = /* @__PURE__ */ new Set();
|
|
24498
|
-
constructor(definitions, cachePath, log) {
|
|
24503
|
+
constructor(definitions, cacheDir, log, now = Date.now) {
|
|
24504
|
+
this.now = now;
|
|
24499
24505
|
this.definitions = new Map(definitions.map((definition) => [sanitizeName(definition.name), definition]));
|
|
24500
24506
|
if (this.definitions.size !== definitions.length) {
|
|
24501
24507
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -24510,12 +24516,43 @@ var McpServerManager = class {
|
|
|
24510
24516
|
);
|
|
24511
24517
|
}
|
|
24512
24518
|
}
|
|
24513
|
-
this.
|
|
24519
|
+
this.cacheDir = cacheDir;
|
|
24514
24520
|
this.log = log;
|
|
24515
24521
|
}
|
|
24522
|
+
now;
|
|
24523
|
+
runtimes = /* @__PURE__ */ new Map();
|
|
24524
|
+
definitions;
|
|
24525
|
+
// Cache directory holding one <server>.json shard per connected server. A
|
|
24526
|
+
// legacy pre-sharding single file (<configDir>/mcp-metadata.json) is
|
|
24527
|
+
// deliberately ignored — the cache is disposable and shards rebuild on the
|
|
24528
|
+
// next connect.
|
|
24529
|
+
cacheDir;
|
|
24530
|
+
log;
|
|
24531
|
+
/** Set by dispose(); after it, no new connects and no late attach. */
|
|
24532
|
+
disposed = false;
|
|
24533
|
+
/** Prefixed names claimed by more than one server in the last loadCatalog(); callTool fail-closes on them. */
|
|
24534
|
+
conflictedNames = /* @__PURE__ */ new Set();
|
|
24516
24535
|
getDefinition(server) {
|
|
24517
24536
|
return this.definitions.get(sanitizeName(server));
|
|
24518
24537
|
}
|
|
24538
|
+
/**
|
|
24539
|
+
* Resolve a `<server>_<tool>` prefixed name against CONFIGURED server names.
|
|
24540
|
+
* Splitting at the first underscore breaks servers whose own name contains
|
|
24541
|
+
* underscores (`my_server_echo` would resolve to server "my"), so match the
|
|
24542
|
+
* longest configured server name that prefixes the tool name instead. When
|
|
24543
|
+
* several configured names prefix (e.g. servers `my` and `my_server` both
|
|
24544
|
+
* exist), the longest match wins: that is how toPrefixedName() would have
|
|
24545
|
+
* constructed the deepest claim, and it is deterministic.
|
|
24546
|
+
*/
|
|
24547
|
+
resolvePrefixedName(prefixedName) {
|
|
24548
|
+
let best = null;
|
|
24549
|
+
for (const key of this.definitions.keys()) {
|
|
24550
|
+
if (!prefixedName.startsWith(`${key}_`)) continue;
|
|
24551
|
+
if (best !== null && key.length <= best.server.length) continue;
|
|
24552
|
+
best = { server: key, tool: prefixedName.slice(key.length + 1) };
|
|
24553
|
+
}
|
|
24554
|
+
return best;
|
|
24555
|
+
}
|
|
24519
24556
|
listDefinitions() {
|
|
24520
24557
|
return [...this.definitions.values()];
|
|
24521
24558
|
}
|
|
@@ -24614,13 +24651,11 @@ var McpServerManager = class {
|
|
|
24614
24651
|
}
|
|
24615
24652
|
seen.add(tool.prefixedName);
|
|
24616
24653
|
}
|
|
24617
|
-
for (const
|
|
24654
|
+
for (const otherRuntime of this.runtimes.values()) {
|
|
24618
24655
|
if (otherRuntime === runtime || !otherRuntime.tools) continue;
|
|
24619
24656
|
for (const otherTool of otherRuntime.tools) {
|
|
24620
24657
|
if (seen.has(otherTool.prefixedName)) {
|
|
24621
|
-
|
|
24622
|
-
`tool name collision between "${runtime.definition.name}" and "${otherKey}": ${otherTool.prefixedName}`
|
|
24623
|
-
);
|
|
24658
|
+
this.log(`mcp: tool name "${otherTool.prefixedName}" is claimed by more than one server \u2014 disabled until the servers are renamed (fail-closed)`);
|
|
24624
24659
|
}
|
|
24625
24660
|
}
|
|
24626
24661
|
}
|
|
@@ -24629,23 +24664,45 @@ var McpServerManager = class {
|
|
|
24629
24664
|
}
|
|
24630
24665
|
persistMetadata() {
|
|
24631
24666
|
try {
|
|
24632
|
-
|
|
24667
|
+
fs2.mkdirSync(this.cacheDir, { recursive: true });
|
|
24633
24668
|
for (const [key, runtime] of this.runtimes) {
|
|
24634
|
-
if (runtime.tools)
|
|
24635
|
-
|
|
24636
|
-
|
|
24637
|
-
|
|
24638
|
-
|
|
24639
|
-
|
|
24640
|
-
|
|
24641
|
-
|
|
24642
|
-
|
|
24643
|
-
|
|
24669
|
+
if (!runtime.tools) continue;
|
|
24670
|
+
const shardPath = path2.join(this.cacheDir, `${key}.json`);
|
|
24671
|
+
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");
|
|
24673
|
+
try {
|
|
24674
|
+
fs2.renameSync(tempPath, shardPath);
|
|
24675
|
+
} catch (error2) {
|
|
24676
|
+
fs2.unlinkSync(tempPath);
|
|
24677
|
+
throw error2;
|
|
24678
|
+
}
|
|
24644
24679
|
}
|
|
24680
|
+
this.deleteExpiredShards();
|
|
24645
24681
|
} catch (error2) {
|
|
24646
24682
|
this.log(`mcp: metadata cache write failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
24647
24683
|
}
|
|
24648
24684
|
}
|
|
24685
|
+
/** Delete shard files older than METADATA_TTL_MS (stale entries of offline servers age out). */
|
|
24686
|
+
deleteExpiredShards() {
|
|
24687
|
+
let names;
|
|
24688
|
+
try {
|
|
24689
|
+
names = fs2.readdirSync(this.cacheDir);
|
|
24690
|
+
} catch {
|
|
24691
|
+
return;
|
|
24692
|
+
}
|
|
24693
|
+
for (const name of names) {
|
|
24694
|
+
if (!name.endsWith(".json")) continue;
|
|
24695
|
+
const filePath = path2.join(this.cacheDir, name);
|
|
24696
|
+
try {
|
|
24697
|
+
const mtimeMs = fs2.statSync(filePath).mtimeMs;
|
|
24698
|
+
const parsed = JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
24699
|
+
if (typeof parsed.updatedAt !== "number" || this.now() - parsed.updatedAt > METADATA_TTL_MS) {
|
|
24700
|
+
if (fs2.statSync(filePath).mtimeMs === mtimeMs) fs2.unlinkSync(filePath);
|
|
24701
|
+
}
|
|
24702
|
+
} catch {
|
|
24703
|
+
}
|
|
24704
|
+
}
|
|
24705
|
+
}
|
|
24649
24706
|
/** Cached descriptors for one server (from the metadata cache file). */
|
|
24650
24707
|
cachedToolsFor(server) {
|
|
24651
24708
|
return this.loadCatalog().filter((tool) => tool.server === sanitizeName(server));
|
|
@@ -24681,27 +24738,60 @@ var McpServerManager = class {
|
|
|
24681
24738
|
this.conflictedNames = conflicts;
|
|
24682
24739
|
return [...catalog.values()].sort((a, b) => a.prefixedName.localeCompare(b.prefixedName));
|
|
24683
24740
|
}
|
|
24684
|
-
|
|
24741
|
+
cacheSignature;
|
|
24685
24742
|
cacheSnapshot = {};
|
|
24686
|
-
|
|
24743
|
+
cacheUpdatedAt = {};
|
|
24744
|
+
pruneExpiredSnapshot() {
|
|
24745
|
+
for (const [key, updatedAt] of Object.entries(this.cacheUpdatedAt)) {
|
|
24746
|
+
if (this.now() - updatedAt > METADATA_TTL_MS) {
|
|
24747
|
+
delete this.cacheSnapshot[key];
|
|
24748
|
+
delete this.cacheUpdatedAt[key];
|
|
24749
|
+
}
|
|
24750
|
+
}
|
|
24751
|
+
return this.cacheSnapshot;
|
|
24752
|
+
}
|
|
24753
|
+
/**
|
|
24754
|
+
* Read the sharded metadata cache (<cacheDir>/<server>.json), merging every
|
|
24755
|
+
* shard's tools by server key (the file name is the sanitized server key).
|
|
24756
|
+
* Re-reads only when the signature changed; the signature must cover each
|
|
24757
|
+
* shard's name + mtime — the directory's own mtime is NOT enough, because a
|
|
24758
|
+
* rename replacing an existing shard leaves it unchanged.
|
|
24759
|
+
*/
|
|
24687
24760
|
readCacheFile() {
|
|
24688
|
-
let
|
|
24761
|
+
let names;
|
|
24689
24762
|
try {
|
|
24690
|
-
|
|
24763
|
+
names = fs2.readdirSync(this.cacheDir).sort();
|
|
24691
24764
|
} catch {
|
|
24692
|
-
this.
|
|
24765
|
+
this.cacheSignature = void 0;
|
|
24693
24766
|
this.cacheSnapshot = {};
|
|
24767
|
+
this.cacheUpdatedAt = {};
|
|
24694
24768
|
return this.cacheSnapshot;
|
|
24695
24769
|
}
|
|
24696
|
-
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
24700
|
-
|
|
24701
|
-
|
|
24702
|
-
this.cacheSnapshot = {};
|
|
24703
|
-
this.cacheMtime = mtime;
|
|
24770
|
+
let signature = "";
|
|
24771
|
+
for (const name of names) {
|
|
24772
|
+
try {
|
|
24773
|
+
signature += `${name}:${fs2.statSync(path2.join(this.cacheDir, name)).mtimeMs};`;
|
|
24774
|
+
} catch {
|
|
24775
|
+
}
|
|
24704
24776
|
}
|
|
24777
|
+
if (signature === this.cacheSignature) return this.pruneExpiredSnapshot();
|
|
24778
|
+
const snapshot = {};
|
|
24779
|
+
const updatedAt = {};
|
|
24780
|
+
for (const name of names) {
|
|
24781
|
+
if (!name.endsWith(".json")) continue;
|
|
24782
|
+
try {
|
|
24783
|
+
const parsed = JSON.parse(fs2.readFileSync(path2.join(this.cacheDir, name), "utf8"));
|
|
24784
|
+
if (typeof parsed.updatedAt !== "number" || this.now() - parsed.updatedAt > METADATA_TTL_MS) continue;
|
|
24785
|
+
if (!Array.isArray(parsed.tools)) continue;
|
|
24786
|
+
const key = name.slice(0, -".json".length);
|
|
24787
|
+
snapshot[key] = parsed.tools;
|
|
24788
|
+
updatedAt[key] = parsed.updatedAt;
|
|
24789
|
+
} catch {
|
|
24790
|
+
}
|
|
24791
|
+
}
|
|
24792
|
+
this.cacheSnapshot = snapshot;
|
|
24793
|
+
this.cacheUpdatedAt = updatedAt;
|
|
24794
|
+
this.cacheSignature = signature;
|
|
24705
24795
|
return this.cacheSnapshot;
|
|
24706
24796
|
}
|
|
24707
24797
|
async callTool(prefixedName, args, signal) {
|
|
@@ -24716,13 +24806,10 @@ var McpServerManager = class {
|
|
|
24716
24806
|
let server = descriptor?.server;
|
|
24717
24807
|
let toolName = descriptor?.tool;
|
|
24718
24808
|
if (!server) {
|
|
24719
|
-
const
|
|
24720
|
-
if (
|
|
24721
|
-
|
|
24722
|
-
|
|
24723
|
-
server = candidate;
|
|
24724
|
-
toolName = prefixedName.slice(separator + 1);
|
|
24725
|
-
}
|
|
24809
|
+
const resolved = this.resolvePrefixedName(prefixedName);
|
|
24810
|
+
if (resolved) {
|
|
24811
|
+
server = resolved.server;
|
|
24812
|
+
toolName = resolved.tool;
|
|
24726
24813
|
}
|
|
24727
24814
|
}
|
|
24728
24815
|
if (!server || !toolName) {
|
|
@@ -24756,9 +24843,15 @@ ${tail}` : "")
|
|
|
24756
24843
|
error: `MCP connection to "${server}" closed before the call could start.`
|
|
24757
24844
|
};
|
|
24758
24845
|
}
|
|
24846
|
+
if (signal?.aborted) {
|
|
24847
|
+
return {
|
|
24848
|
+
delivery: "not_sent",
|
|
24849
|
+
error: `MCP call "${prefixedName}" was cancelled before the request was sent; nothing was executed.`
|
|
24850
|
+
};
|
|
24851
|
+
}
|
|
24759
24852
|
try {
|
|
24760
24853
|
const result = await withTimeout(
|
|
24761
|
-
client.callTool({ name: toolName, arguments: args }),
|
|
24854
|
+
client.callTool({ name: toolName, arguments: args }, void 0, signal !== void 0 ? { signal } : void 0),
|
|
24762
24855
|
CALL_TIMEOUT_MS,
|
|
24763
24856
|
`call "${prefixedName}"`,
|
|
24764
24857
|
signal
|
|
@@ -24771,6 +24864,12 @@ ${tail}` : "")
|
|
|
24771
24864
|
};
|
|
24772
24865
|
} catch (error2) {
|
|
24773
24866
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
24867
|
+
if (error2 instanceof ProtocolError && (error2.code === ProtocolErrorCode.InvalidRequest || error2.code === ProtocolErrorCode.InvalidParams) && /output schema|structured content/i.test(message)) {
|
|
24868
|
+
return {
|
|
24869
|
+
delivery: "invalid_result",
|
|
24870
|
+
error: `MCP server "${server}" returned a result that fails its own outputSchema: ${message}. The call DID reach the server and the tool likely executed \u2014 do NOT retry automatically; verify state with a read-only tool first.`
|
|
24871
|
+
};
|
|
24872
|
+
}
|
|
24774
24873
|
if (runtime.client === void 0 || /closed|aborted|timed out|socket|ECONNRESET/i.test(message)) {
|
|
24775
24874
|
return {
|
|
24776
24875
|
delivery: "may_have_run",
|
|
@@ -24918,7 +25017,7 @@ function structuredContentIsMirroredInText(textBlocks, structured) {
|
|
|
24918
25017
|
}
|
|
24919
25018
|
function mapMcpOutcome(outcome, maxBytes) {
|
|
24920
25019
|
if (outcome.delivery !== "ok") {
|
|
24921
|
-
const prefix = outcome.delivery === "may_have_run" ? "[outcome unknown]" : "[not executed]";
|
|
25020
|
+
const prefix = outcome.delivery === "may_have_run" || outcome.delivery === "invalid_result" ? "[outcome unknown]" : "[not executed]";
|
|
24922
25021
|
return {
|
|
24923
25022
|
content: [{ type: "text", text: `${prefix} ${outcome.error ?? "MCP call failed"}` }],
|
|
24924
25023
|
details: { mode: "mcp", delivery: outcome.delivery, ...outcome.protocolCode !== void 0 ? { protocolCode: outcome.protocolCode } : {} },
|
|
@@ -24960,7 +25059,7 @@ function createMcpProxyTool(getManager, ensureTrusted, options = {}) {
|
|
|
24960
25059
|
return {
|
|
24961
25060
|
name: "mcp",
|
|
24962
25061
|
label: "MCP",
|
|
24963
|
-
description: 'Call tools on configured MCP servers without loading their definitions. Discover: mcp({ search: "screenshot" }) lists matching <server>_<tool> names with compact parameter hints (cached metadata; servers do not start for search). Inspect: mcp({ tool: "<name>", describe: true }) returns the full input schema. Call: mcp({ tool: "<name>", args: { ... } }) \u2014 the server starts lazily on first use. args may be a JSON object or JSON string. If a result is marked [outcome unknown], the tool may have executed: do not retry automatically \u2014 verify state with a read-only call first.',
|
|
25062
|
+
description: 'Call tools on configured MCP servers without loading their definitions. Discover: mcp({ search: "screenshot" }) lists matching <server>_<tool> names with compact parameter hints (cached metadata; servers do not start for search). Inspect: mcp({ tool: "<name>", describe: true }) returns the full input schema. Call: mcp({ tool: "<name>", args: { ... } }) \u2014 the server starts lazily on first use. args may be a JSON object or JSON string. Tool lists are a snapshot taken when a server connects: tools added or removed by a running server only appear after /reload refreshes the session. If a result is marked [outcome unknown], the tool may have executed: do not retry automatically \u2014 verify state with a read-only call first.',
|
|
24964
25063
|
parameters: Type.Object({
|
|
24965
25064
|
search: Type.Optional(Type.String({ description: "Query text to discover MCP tools by name/description" })),
|
|
24966
25065
|
tool: Type.Optional(Type.String({ description: "Prefixed tool name <server>_<tool> to describe or call" })),
|
|
@@ -25005,8 +25104,8 @@ ${truncate(JSON.stringify(schema ?? {}, null, 2), maxBytes)}` : `unknown MCP too
|
|
|
25005
25104
|
isError: descriptor === void 0
|
|
25006
25105
|
};
|
|
25007
25106
|
}
|
|
25008
|
-
const
|
|
25009
|
-
const server = descriptor?.server ??
|
|
25107
|
+
const resolved = getManager().resolvePrefixedName(params.tool);
|
|
25108
|
+
const server = descriptor?.server ?? resolved?.server ?? "";
|
|
25010
25109
|
if (server) {
|
|
25011
25110
|
const trust = await ensureTrusted(server);
|
|
25012
25111
|
if (!trust.trusted) {
|
|
@@ -25160,10 +25259,10 @@ function formatServerForTrustPrompt(definition) {
|
|
|
25160
25259
|
function mcpAdapter(ctx) {
|
|
25161
25260
|
const configDir = resolveConfigDir();
|
|
25162
25261
|
const trustStore = new McpTrustStore(path4.join(configDir, "mcp-trust.json"));
|
|
25163
|
-
const
|
|
25262
|
+
const metadataCacheDir = path4.join(configDir, "mcp-metadata");
|
|
25164
25263
|
let manager = new McpServerManager(
|
|
25165
25264
|
resolveMcpAdapterConfig(ctx.cwd, configDir).servers,
|
|
25166
|
-
|
|
25265
|
+
metadataCacheDir,
|
|
25167
25266
|
ctx.log
|
|
25168
25267
|
);
|
|
25169
25268
|
async function reloadManager() {
|
|
@@ -25171,28 +25270,42 @@ function mcpAdapter(ctx) {
|
|
|
25171
25270
|
try {
|
|
25172
25271
|
manager = new McpServerManager(
|
|
25173
25272
|
resolveMcpAdapterConfig(ctx.cwd, configDir).servers,
|
|
25174
|
-
|
|
25273
|
+
metadataCacheDir,
|
|
25175
25274
|
ctx.log
|
|
25176
25275
|
);
|
|
25177
25276
|
} catch (error2) {
|
|
25178
25277
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25179
25278
|
ctx.log(`mcp: config reload failed: ${message}`);
|
|
25180
25279
|
if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error: ${message}`, "error");
|
|
25181
|
-
manager = new McpServerManager([],
|
|
25280
|
+
manager = new McpServerManager([], metadataCacheDir, ctx.log);
|
|
25182
25281
|
}
|
|
25183
25282
|
}
|
|
25184
|
-
|
|
25283
|
+
ctx.registerCleanup?.(() => manager.dispose().catch(() => void 0));
|
|
25284
|
+
function readProjectOverride() {
|
|
25185
25285
|
const filePath = path4.join(ctx.cwd, ".pie", "mcp-adapter.json");
|
|
25186
25286
|
let parsed = {};
|
|
25187
25287
|
try {
|
|
25188
25288
|
parsed = JSON.parse(fs4.readFileSync(filePath, "utf8"));
|
|
25189
25289
|
} catch {
|
|
25190
25290
|
}
|
|
25291
|
+
return parsed;
|
|
25292
|
+
}
|
|
25293
|
+
function writeProjectOverride(serverName, disabled) {
|
|
25294
|
+
const filePath = path4.join(ctx.cwd, ".pie", "mcp-adapter.json");
|
|
25295
|
+
const parsed = readProjectOverride();
|
|
25191
25296
|
const servers = parsed.mcpServers && typeof parsed.mcpServers === "object" && !Array.isArray(parsed.mcpServers) ? { ...parsed.mcpServers } : {};
|
|
25297
|
+
const existing = servers[serverName];
|
|
25298
|
+
const existingObj = existing && typeof existing === "object" && !Array.isArray(existing) ? { ...existing } : {};
|
|
25192
25299
|
if (disabled === null) {
|
|
25193
|
-
delete
|
|
25300
|
+
delete existingObj.disabled;
|
|
25301
|
+
if (Object.keys(existingObj).length === 0) {
|
|
25302
|
+
delete servers[serverName];
|
|
25303
|
+
} else {
|
|
25304
|
+
servers[serverName] = existingObj;
|
|
25305
|
+
}
|
|
25194
25306
|
} else {
|
|
25195
|
-
|
|
25307
|
+
existingObj.disabled = disabled;
|
|
25308
|
+
servers[serverName] = existingObj;
|
|
25196
25309
|
}
|
|
25197
25310
|
parsed.mcpServers = servers;
|
|
25198
25311
|
fs4.mkdirSync(path4.dirname(filePath), { recursive: true });
|
|
@@ -25229,16 +25342,6 @@ function mcpAdapter(ctx) {
|
|
|
25229
25342
|
if (eagerRegistered.length > 0) {
|
|
25230
25343
|
ctx.log(`mcp: registered ${eagerRegistered.length} direct tool(s) from metadata cache: ${eagerRegistered.join(", ")}`);
|
|
25231
25344
|
}
|
|
25232
|
-
function unpinnedWarnings() {
|
|
25233
|
-
const warnings = [];
|
|
25234
|
-
for (const definition of manager.listDefinitions()) {
|
|
25235
|
-
const spec = [definition.command ?? "", ...definition.args].join(" ");
|
|
25236
|
-
if (/(^|\s)(npx|bunx|uvx)\s/.test(spec) && /@latest\b/.test(spec)) {
|
|
25237
|
-
warnings.push(`${definition.name}: unpinned "@latest" fetch \u2014 pin an exact version (e.g. pkg@1.2.3).`);
|
|
25238
|
-
}
|
|
25239
|
-
}
|
|
25240
|
-
return warnings;
|
|
25241
|
-
}
|
|
25242
25345
|
ctx.registerCommand({
|
|
25243
25346
|
name: "mcp",
|
|
25244
25347
|
description: "MCP adapter: status (default), enable/disable <server>",
|
|
@@ -25254,10 +25357,21 @@ function mcpAdapter(ctx) {
|
|
|
25254
25357
|
commandCtx.ui.notify(`Unknown MCP server "${target}". Run /mcp for the configured list.`, "warning");
|
|
25255
25358
|
return;
|
|
25256
25359
|
}
|
|
25257
|
-
const
|
|
25360
|
+
const overrides = readProjectOverride().mcpServers;
|
|
25361
|
+
const forceEnabled = overrides?.[definition.name]?.disabled === false;
|
|
25362
|
+
const filePath = writeProjectOverride(
|
|
25363
|
+
definition.name,
|
|
25364
|
+
// enable must lift a source-level disabled:true with an explicit
|
|
25365
|
+
// {disabled:false} force-override: deleting the override alone
|
|
25366
|
+
// would leave the source-level disable in force. Preserve an
|
|
25367
|
+
// existing force-enable on repeated enable commands too.
|
|
25368
|
+
sub === "disable" ? true : definition.disabled || forceEnabled ? false : null
|
|
25369
|
+
);
|
|
25258
25370
|
await reloadManager();
|
|
25371
|
+
const effectiveDisabled = manager.getDefinition(definition.name)?.disabled ?? false;
|
|
25372
|
+
const stateLabel = effectiveDisabled ? "disabled" : sub === "disable" ? "still enabled" : "enabled";
|
|
25259
25373
|
commandCtx.ui.notify(
|
|
25260
|
-
`MCP server "${definition.name}" ${
|
|
25374
|
+
`MCP server "${definition.name}" ${stateLabel} (wrote ${filePath}). ` + (eagerRegistered.length > 0 ? "Restart or /reload to resync direct tools." : "Effective immediately."),
|
|
25261
25375
|
"info"
|
|
25262
25376
|
);
|
|
25263
25377
|
return;
|
|
@@ -25279,7 +25393,7 @@ function mcpAdapter(ctx) {
|
|
|
25279
25393
|
lines.push(`- ${sanitizeName(definition.name)} [${manager.statusOf(definition.name)}, ${scopeLabel}] ${spec}`);
|
|
25280
25394
|
}
|
|
25281
25395
|
}
|
|
25282
|
-
const warnings = unpinnedWarnings();
|
|
25396
|
+
const warnings = unpinnedWarnings(manager.listDefinitions());
|
|
25283
25397
|
if (warnings.length > 0) lines.push("", "Warnings:", ...warnings.map((warning) => `- ${warning}`));
|
|
25284
25398
|
const config2 = resolveMcpAdapterConfig(commandCtx.cwd, configDir);
|
|
25285
25399
|
if (config2.problems.length > 0) lines.push("", "Config problems:", ...config2.problems.map((problem) => `- ${problem}`));
|
|
@@ -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-FKUEIYFQ.js";
|
|
11
|
+
import "../../../chunks/chunk-ZKHMNEXL.js";
|
|
12
|
+
import "../../../chunks/chunk-YRXXRLMQ.js";
|
|
13
13
|
import {
|
|
14
14
|
Type
|
|
15
15
|
} from "../../../chunks/chunk-XXGYUYXI.js";
|
|
@@ -1,14 +1,14 @@
|
|
|
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-
|
|
5
|
-
import "../../../chunks/chunk-5353DEEC.js";
|
|
4
|
+
} from "../../../chunks/chunk-XVUV3IM2.js";
|
|
6
5
|
import {
|
|
7
6
|
createSharedFileSystemTools,
|
|
8
7
|
createSubagentCapability
|
|
9
|
-
} from "../../../chunks/chunk-
|
|
10
|
-
import "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
8
|
+
} from "../../../chunks/chunk-FKUEIYFQ.js";
|
|
9
|
+
import "../../../chunks/chunk-ZKHMNEXL.js";
|
|
10
|
+
import "../../../chunks/chunk-YRXXRLMQ.js";
|
|
11
|
+
import "../../../chunks/chunk-5353DEEC.js";
|
|
12
12
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
13
13
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
14
14
|
|
|
@@ -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-FKUEIYFQ.js";
|
|
12
|
+
import "../../../chunks/chunk-ZKHMNEXL.js";
|
|
13
|
+
import "../../../chunks/chunk-YRXXRLMQ.js";
|
|
14
14
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
15
15
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
16
16
|
|
|
@@ -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-P4VG6ZZG.js");
|
|
25
25
|
await main(process.argv.slice(2));
|
|
26
26
|
}
|
|
@@ -1612,7 +1612,7 @@ function installSessionStartHooks(options = {}) {
|
|
|
1612
1612
|
|
|
1613
1613
|
// vendor/chrome-devtools-axi/src/client.ts
|
|
1614
1614
|
import { execFileSync, spawn as spawn2 } from "node:child_process";
|
|
1615
|
-
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
|
|
1615
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3, unlinkSync } from "node:fs";
|
|
1616
1616
|
import { request } from "node:http";
|
|
1617
1617
|
import { dirname as dirname3 } from "node:path";
|
|
1618
1618
|
|
|
@@ -1945,6 +1945,39 @@ function isBridgeProcess(pid) {
|
|
|
1945
1945
|
return false;
|
|
1946
1946
|
}
|
|
1947
1947
|
}
|
|
1948
|
+
async function probeBridgeIdentity(port, sessionName) {
|
|
1949
|
+
try {
|
|
1950
|
+
const resp = await httpGet(port, "/health", HEALTH_TIMEOUT_MS);
|
|
1951
|
+
const data = JSON.parse(resp);
|
|
1952
|
+
if (data.status !== "ok") return "unknown";
|
|
1953
|
+
if (typeof data.session === "string" && data.session !== sessionName) {
|
|
1954
|
+
return "other";
|
|
1955
|
+
}
|
|
1956
|
+
return "own";
|
|
1957
|
+
} catch {
|
|
1958
|
+
return "unknown";
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
async function judgeRecordedBridge(pidInfo, sessionName) {
|
|
1962
|
+
const identity = await probeBridgeIdentity(pidInfo.port, sessionName);
|
|
1963
|
+
if (identity === "own") {
|
|
1964
|
+
return {
|
|
1965
|
+
terminate: true,
|
|
1966
|
+
killProcessGroup: isBridgeProcess(pidInfo.pid)
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
if (identity === "other") {
|
|
1970
|
+
return { terminate: false, killProcessGroup: false };
|
|
1971
|
+
}
|
|
1972
|
+
const bridge = isBridgeProcess(pidInfo.pid);
|
|
1973
|
+
return { terminate: bridge, killProcessGroup: bridge };
|
|
1974
|
+
}
|
|
1975
|
+
function removePidFile(pidFile) {
|
|
1976
|
+
try {
|
|
1977
|
+
unlinkSync(pidFile);
|
|
1978
|
+
} catch {
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1948
1981
|
async function terminateBridgeProcess(pid, opts = {}) {
|
|
1949
1982
|
if (!isProcessAlive(pid)) return;
|
|
1950
1983
|
const killProcessGroup = opts.killProcessGroup === true;
|
|
@@ -2065,9 +2098,14 @@ async function ensureBridge(spawnBridge = spawnBridgeProcess, notice) {
|
|
|
2065
2098
|
})) {
|
|
2066
2099
|
return pidInfo.port;
|
|
2067
2100
|
}
|
|
2068
|
-
await
|
|
2069
|
-
|
|
2070
|
-
|
|
2101
|
+
const verdict = await judgeRecordedBridge(pidInfo, sessionName);
|
|
2102
|
+
if (verdict.terminate) {
|
|
2103
|
+
await terminateBridgeProcess(pidInfo.pid, {
|
|
2104
|
+
killProcessGroup: verdict.killProcessGroup
|
|
2105
|
+
});
|
|
2106
|
+
} else {
|
|
2107
|
+
removePidFile(pidFile);
|
|
2108
|
+
}
|
|
2071
2109
|
}
|
|
2072
2110
|
clearSelectedPageId();
|
|
2073
2111
|
const child = spawnBridge(port, sessionName);
|
|
@@ -2338,8 +2376,10 @@ async function stopBridge() {
|
|
|
2338
2376
|
const pidInfo = readPidFile();
|
|
2339
2377
|
if (!pidInfo) return false;
|
|
2340
2378
|
if (!isProcessAlive(pidInfo.pid)) return false;
|
|
2379
|
+
const verdict = await judgeRecordedBridge(pidInfo, resolveSessionName());
|
|
2380
|
+
if (!verdict.terminate) return false;
|
|
2341
2381
|
await terminateBridgeProcess(pidInfo.pid, {
|
|
2342
|
-
killProcessGroup:
|
|
2382
|
+
killProcessGroup: verdict.killProcessGroup
|
|
2343
2383
|
});
|
|
2344
2384
|
clearSelectedPageId();
|
|
2345
2385
|
return true;
|
|
@@ -2350,7 +2390,7 @@ import {
|
|
|
2350
2390
|
existsSync as existsSync4,
|
|
2351
2391
|
mkdirSync as mkdirSync2,
|
|
2352
2392
|
readFileSync as readFileSync4,
|
|
2353
|
-
unlinkSync,
|
|
2393
|
+
unlinkSync as unlinkSync2,
|
|
2354
2394
|
writeFileSync as writeFileSync2
|
|
2355
2395
|
} from "node:fs";
|
|
2356
2396
|
import { dirname as dirname4, join as join3 } from "node:path";
|
|
@@ -2379,7 +2419,7 @@ function bumpGeneration() {
|
|
|
2379
2419
|
}
|
|
2380
2420
|
|
|
2381
2421
|
// vendor/chrome-devtools-axi/src/run.ts
|
|
2382
|
-
import { mkdtempSync, writeFileSync as writeFileSync3, unlinkSync as
|
|
2422
|
+
import { mkdtempSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, rmdirSync } from "node:fs";
|
|
2383
2423
|
import { join as join4 } from "node:path";
|
|
2384
2424
|
import { tmpdir } from "node:os";
|
|
2385
2425
|
import { pathToFileURL } from "node:url";
|
|
@@ -2786,7 +2826,7 @@ async function runScript(content, callTool2) {
|
|
|
2786
2826
|
globalThis.page = prevPage;
|
|
2787
2827
|
}
|
|
2788
2828
|
try {
|
|
2789
|
-
|
|
2829
|
+
unlinkSync3(tmpFile);
|
|
2790
2830
|
rmdirSync(tmpDir);
|
|
2791
2831
|
} catch {
|
|
2792
2832
|
}
|