replicas-engine 0.1.744 → 0.1.745
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/src/{asp-host-FCGPBXUC.js → asp-host-H2VMVKW2.js} +3 -2
- package/dist/src/chunk-5KSXSK7Y.js +47 -0
- package/dist/src/{chunk-PY7C2DWR.js → chunk-IRO4TDFM.js} +2 -2
- package/dist/src/chunk-NZRMKTVA.js +8028 -0
- package/dist/src/chunk-SFWEF25L.js +34 -0
- package/dist/src/chunk-WYE7EXGQ.js +2258 -0
- package/dist/src/chunk-Y6VZZNT3.js +371 -0
- package/dist/src/{chunk-XQM2BWLW.js → chunk-ZDBGX4MA.js} +1 -1
- package/dist/src/command-protection-hook.js +1 -0
- package/dist/src/deepseek-command-protection-plugin.js +1 -0
- package/dist/src/headless-agent.js +2 -1
- package/dist/src/index.js +58202 -9413
- package/dist/src/mcp-panel-U4U3G7EU.js +916 -0
- package/dist/src/mcp-setup-panel-TSN2X3T7.js +603 -0
- package/dist/src/post-tool-pr-hook.js +1 -0
- package/dist/src/webapi-FTLM32C4.js +3779 -0
- package/package.json +6 -3
|
@@ -0,0 +1,2258 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getAgentDir,
|
|
4
|
+
getAgentPath,
|
|
5
|
+
getConfigDirName,
|
|
6
|
+
isServerDisabled,
|
|
7
|
+
toStringRecord
|
|
8
|
+
} from "./chunk-NZRMKTVA.js";
|
|
9
|
+
|
|
10
|
+
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/config.ts
|
|
11
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync, mkdirSync, renameSync } from "fs";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { dirname, join as join2, resolve as resolve3 } from "path";
|
|
14
|
+
|
|
15
|
+
// ../node_modules/.bun/smol-toml@1.7.0/node_modules/smol-toml/dist/date.js
|
|
16
|
+
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
|
17
|
+
var TomlDate = class _TomlDate extends Date {
|
|
18
|
+
#hasDate = false;
|
|
19
|
+
#hasTime = false;
|
|
20
|
+
#offset = null;
|
|
21
|
+
constructor(date) {
|
|
22
|
+
let hasDate = true;
|
|
23
|
+
let hasTime = true;
|
|
24
|
+
let offset = "Z";
|
|
25
|
+
if (typeof date === "string") {
|
|
26
|
+
let match = date.match(DATE_TIME_RE);
|
|
27
|
+
if (match) {
|
|
28
|
+
if (!match[1]) {
|
|
29
|
+
hasDate = false;
|
|
30
|
+
date = `0000-01-01T${date}`;
|
|
31
|
+
}
|
|
32
|
+
hasTime = !!match[2];
|
|
33
|
+
hasTime && date[10] === " " && (date = date.replace(" ", "T"));
|
|
34
|
+
if (match[2] && +match[2] > 23) {
|
|
35
|
+
date = "";
|
|
36
|
+
} else {
|
|
37
|
+
offset = match[3] || null;
|
|
38
|
+
date = date.toUpperCase();
|
|
39
|
+
if (!offset && hasTime)
|
|
40
|
+
date += "Z";
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
date = "";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
super(date);
|
|
47
|
+
if (!isNaN(this.getTime())) {
|
|
48
|
+
this.#hasDate = hasDate;
|
|
49
|
+
this.#hasTime = hasTime;
|
|
50
|
+
this.#offset = offset;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
isDateTime() {
|
|
54
|
+
return this.#hasDate && this.#hasTime;
|
|
55
|
+
}
|
|
56
|
+
isLocal() {
|
|
57
|
+
return !this.#hasDate || !this.#hasTime || !this.#offset;
|
|
58
|
+
}
|
|
59
|
+
isDate() {
|
|
60
|
+
return this.#hasDate && !this.#hasTime;
|
|
61
|
+
}
|
|
62
|
+
isTime() {
|
|
63
|
+
return this.#hasTime && !this.#hasDate;
|
|
64
|
+
}
|
|
65
|
+
isValid() {
|
|
66
|
+
return this.#hasDate || this.#hasTime;
|
|
67
|
+
}
|
|
68
|
+
toISOString() {
|
|
69
|
+
let iso = super.toISOString();
|
|
70
|
+
if (this.isDate())
|
|
71
|
+
return iso.slice(0, 10);
|
|
72
|
+
if (this.isTime())
|
|
73
|
+
return iso.slice(11, 23);
|
|
74
|
+
if (this.#offset === null)
|
|
75
|
+
return iso.slice(0, -1);
|
|
76
|
+
if (this.#offset === "Z")
|
|
77
|
+
return iso;
|
|
78
|
+
let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
|
|
79
|
+
offset = this.#offset[0] === "-" ? offset : -offset;
|
|
80
|
+
let offsetDate = new Date(this.getTime() - offset * 6e4);
|
|
81
|
+
return offsetDate.toISOString().slice(0, -1) + this.#offset;
|
|
82
|
+
}
|
|
83
|
+
static wrapAsOffsetDateTime(jsDate, offset = "Z") {
|
|
84
|
+
let date = new _TomlDate(jsDate);
|
|
85
|
+
date.#offset = offset;
|
|
86
|
+
return date;
|
|
87
|
+
}
|
|
88
|
+
static wrapAsLocalDateTime(jsDate) {
|
|
89
|
+
let date = new _TomlDate(jsDate);
|
|
90
|
+
date.#offset = null;
|
|
91
|
+
return date;
|
|
92
|
+
}
|
|
93
|
+
static wrapAsLocalDate(jsDate) {
|
|
94
|
+
let date = new _TomlDate(jsDate);
|
|
95
|
+
date.#hasTime = false;
|
|
96
|
+
date.#offset = null;
|
|
97
|
+
return date;
|
|
98
|
+
}
|
|
99
|
+
static wrapAsLocalTime(jsDate) {
|
|
100
|
+
let date = new _TomlDate(jsDate);
|
|
101
|
+
date.#hasDate = false;
|
|
102
|
+
date.#offset = null;
|
|
103
|
+
return date;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// ../node_modules/.bun/smol-toml@1.7.0/node_modules/smol-toml/dist/error.js
|
|
108
|
+
function getLineColFromPtr(string, ptr) {
|
|
109
|
+
let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
|
|
110
|
+
return [lines.length, lines.pop().length + 1];
|
|
111
|
+
}
|
|
112
|
+
function makeCodeBlock(string, line, column) {
|
|
113
|
+
let lines = string.split(/\r\n|\n|\r/g);
|
|
114
|
+
let codeblock = "";
|
|
115
|
+
let numberLen = (Math.log10(line + 1) | 0) + 1;
|
|
116
|
+
for (let i = line - 1; i <= line + 1; i++) {
|
|
117
|
+
let l = lines[i - 1];
|
|
118
|
+
if (!l)
|
|
119
|
+
continue;
|
|
120
|
+
codeblock += i.toString().padEnd(numberLen, " ");
|
|
121
|
+
codeblock += ": ";
|
|
122
|
+
codeblock += l;
|
|
123
|
+
codeblock += "\n";
|
|
124
|
+
if (i === line) {
|
|
125
|
+
codeblock += " ".repeat(numberLen + column + 2);
|
|
126
|
+
codeblock += "^\n";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return codeblock;
|
|
130
|
+
}
|
|
131
|
+
var TomlError = class extends Error {
|
|
132
|
+
line;
|
|
133
|
+
column;
|
|
134
|
+
codeblock;
|
|
135
|
+
constructor(message, options) {
|
|
136
|
+
const [line, column] = getLineColFromPtr(options.toml, options.ptr);
|
|
137
|
+
const codeblock = makeCodeBlock(options.toml, line, column);
|
|
138
|
+
super(`Invalid TOML document: ${message}
|
|
139
|
+
|
|
140
|
+
${codeblock}`, options);
|
|
141
|
+
this.line = line;
|
|
142
|
+
this.column = column;
|
|
143
|
+
this.codeblock = codeblock;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// ../node_modules/.bun/smol-toml@1.7.0/node_modules/smol-toml/dist/primitive.js
|
|
148
|
+
var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
|
|
149
|
+
var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
|
|
150
|
+
var LEADING_ZERO = /^[+-]?0[0-9_]/;
|
|
151
|
+
function parseString(str, ptr) {
|
|
152
|
+
let c = str[ptr++];
|
|
153
|
+
let first = c;
|
|
154
|
+
let isLiteral = c === "'";
|
|
155
|
+
let isMultiline = c === str[ptr] && c === str[ptr + 1];
|
|
156
|
+
if (isMultiline) {
|
|
157
|
+
if (str[ptr += 2] === "\n")
|
|
158
|
+
ptr++;
|
|
159
|
+
else if (str[ptr] === "\r" && str[ptr + 1] === "\n")
|
|
160
|
+
ptr += 2;
|
|
161
|
+
}
|
|
162
|
+
let parsed = "";
|
|
163
|
+
let sliceStart = ptr;
|
|
164
|
+
let state = 0;
|
|
165
|
+
for (let i = ptr; i < str.length; i++) {
|
|
166
|
+
c = str[i];
|
|
167
|
+
if (isMultiline && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
|
|
168
|
+
state = state && 3;
|
|
169
|
+
} else if (c < " " && c !== " " || c === "\x7F") {
|
|
170
|
+
throw new TomlError("control characters are not allowed in strings", {
|
|
171
|
+
toml: str,
|
|
172
|
+
ptr: i
|
|
173
|
+
});
|
|
174
|
+
} else if ((!state || state === 3) && c === first && (!isMultiline || str[i + 1] === first && str[i + 2] === first)) {
|
|
175
|
+
if (isMultiline) {
|
|
176
|
+
if (str[i + 3] === first)
|
|
177
|
+
i++;
|
|
178
|
+
if (str[i + 3] === first)
|
|
179
|
+
i++;
|
|
180
|
+
}
|
|
181
|
+
return [
|
|
182
|
+
// If we're in a newline escape still, then there's nothing to add.
|
|
183
|
+
// Also try to avoid concat if there's nothing to add to parsed, or nothing has been added to parsed.
|
|
184
|
+
state ? parsed : parsed + str.slice(sliceStart, i),
|
|
185
|
+
i + (isMultiline ? 3 : 1)
|
|
186
|
+
];
|
|
187
|
+
} else if (!state) {
|
|
188
|
+
if (!isLiteral && c === "\\") {
|
|
189
|
+
parsed += str.slice(sliceStart, sliceStart = i);
|
|
190
|
+
state = 1;
|
|
191
|
+
}
|
|
192
|
+
} else if (state === 1) {
|
|
193
|
+
if (c === "x" || c === "u" || c === "U") {
|
|
194
|
+
let value = 0;
|
|
195
|
+
let len = c === "x" ? 2 : c === "u" ? 4 : 8;
|
|
196
|
+
for (let j = 0; j < len; j++, i++) {
|
|
197
|
+
let hex = str.charCodeAt(i + 1);
|
|
198
|
+
let digit = (
|
|
199
|
+
/* 0-9 */
|
|
200
|
+
hex >= 48 && hex <= 57 ? hex - 48 : (
|
|
201
|
+
/* A-F */
|
|
202
|
+
hex >= 65 && hex <= 70 ? hex - 65 + 10 : (
|
|
203
|
+
/* a-f */
|
|
204
|
+
hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
);
|
|
208
|
+
if (digit < 0)
|
|
209
|
+
throw new TomlError("invalid non-hex character in unicode escape", { toml: str, ptr: i + 1 });
|
|
210
|
+
value = value << 4 | digit;
|
|
211
|
+
}
|
|
212
|
+
if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) {
|
|
213
|
+
throw new TomlError("invalid unicode escape", { toml: str, ptr: i });
|
|
214
|
+
}
|
|
215
|
+
parsed += String.fromCodePoint(value);
|
|
216
|
+
sliceStart = i + 1;
|
|
217
|
+
state = 0;
|
|
218
|
+
} else if (c === " " || c === " ") {
|
|
219
|
+
state = 2;
|
|
220
|
+
} else {
|
|
221
|
+
if (c === "b")
|
|
222
|
+
parsed += "\b";
|
|
223
|
+
else if (c === "t")
|
|
224
|
+
parsed += " ";
|
|
225
|
+
else if (c === "n")
|
|
226
|
+
parsed += "\n";
|
|
227
|
+
else if (c === "f")
|
|
228
|
+
parsed += "\f";
|
|
229
|
+
else if (c === "r")
|
|
230
|
+
parsed += "\r";
|
|
231
|
+
else if (c === "e")
|
|
232
|
+
parsed += "\x1B";
|
|
233
|
+
else if (c === '"')
|
|
234
|
+
parsed += '"';
|
|
235
|
+
else if (c === "\\")
|
|
236
|
+
parsed += "\\";
|
|
237
|
+
else
|
|
238
|
+
throw new TomlError("unrecognized escape sequence", { toml: str, ptr: i });
|
|
239
|
+
sliceStart = i + 1;
|
|
240
|
+
state = 0;
|
|
241
|
+
}
|
|
242
|
+
} else if (c !== " " && c !== " ") {
|
|
243
|
+
if (state === 2) {
|
|
244
|
+
throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
|
|
245
|
+
toml: str,
|
|
246
|
+
ptr: sliceStart
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
state = !isLiteral && c === "\\" ? 1 : 0;
|
|
250
|
+
sliceStart = i;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
throw new TomlError("unfinished string", { toml: str, ptr });
|
|
254
|
+
}
|
|
255
|
+
function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
256
|
+
if (value === "true")
|
|
257
|
+
return true;
|
|
258
|
+
if (value === "false")
|
|
259
|
+
return false;
|
|
260
|
+
if (value === "-inf")
|
|
261
|
+
return -Infinity;
|
|
262
|
+
if (value === "inf" || value === "+inf")
|
|
263
|
+
return Infinity;
|
|
264
|
+
if (value === "nan" || value === "+nan" || value === "-nan")
|
|
265
|
+
return NaN;
|
|
266
|
+
if (value === "-0")
|
|
267
|
+
return integersAsBigInt ? 0n : 0;
|
|
268
|
+
let isInt = INT_REGEX.test(value);
|
|
269
|
+
if (isInt || FLOAT_REGEX.test(value)) {
|
|
270
|
+
if (LEADING_ZERO.test(value)) {
|
|
271
|
+
throw new TomlError("leading zeroes are not allowed", {
|
|
272
|
+
toml,
|
|
273
|
+
ptr
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
value = value.replace(/_/g, "");
|
|
277
|
+
let numeric = +value;
|
|
278
|
+
if (isNaN(numeric)) {
|
|
279
|
+
throw new TomlError("invalid number", {
|
|
280
|
+
toml,
|
|
281
|
+
ptr
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (isInt) {
|
|
285
|
+
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
|
|
286
|
+
throw new TomlError("integer value cannot be represented losslessly", {
|
|
287
|
+
toml,
|
|
288
|
+
ptr
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
if (isInt || integersAsBigInt === true)
|
|
292
|
+
numeric = BigInt(value);
|
|
293
|
+
}
|
|
294
|
+
return numeric;
|
|
295
|
+
}
|
|
296
|
+
const date = new TomlDate(value);
|
|
297
|
+
if (!date.isValid()) {
|
|
298
|
+
throw new TomlError("invalid value", {
|
|
299
|
+
toml,
|
|
300
|
+
ptr
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
return date;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ../node_modules/.bun/smol-toml@1.7.0/node_modules/smol-toml/dist/util.js
|
|
307
|
+
function indexOfNewline(str, start = 0, end = str.length) {
|
|
308
|
+
let idx = str.indexOf("\n", start);
|
|
309
|
+
if (str[idx - 1] === "\r")
|
|
310
|
+
idx--;
|
|
311
|
+
return idx <= end ? idx : -1;
|
|
312
|
+
}
|
|
313
|
+
function skipComment(str, ptr) {
|
|
314
|
+
for (let i = ptr; i < str.length; i++) {
|
|
315
|
+
let c = str[i];
|
|
316
|
+
if (c === "\n")
|
|
317
|
+
return i;
|
|
318
|
+
if (c === "\r" && str[i + 1] === "\n")
|
|
319
|
+
return i + 1;
|
|
320
|
+
if (c < " " && c !== " " || c === "\x7F") {
|
|
321
|
+
throw new TomlError("control characters are not allowed in comments", {
|
|
322
|
+
toml: str,
|
|
323
|
+
ptr
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return str.length;
|
|
328
|
+
}
|
|
329
|
+
function skipVoid(str, ptr, banNewLines, banComments) {
|
|
330
|
+
let c;
|
|
331
|
+
while (1) {
|
|
332
|
+
while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
|
|
333
|
+
ptr++;
|
|
334
|
+
if (banComments || c !== "#")
|
|
335
|
+
break;
|
|
336
|
+
ptr = skipComment(str, ptr);
|
|
337
|
+
}
|
|
338
|
+
return ptr;
|
|
339
|
+
}
|
|
340
|
+
function skipUntil(str, ptr, sep3, end, banNewLines = false) {
|
|
341
|
+
if (!end) {
|
|
342
|
+
ptr = indexOfNewline(str, ptr);
|
|
343
|
+
return ptr < 0 ? str.length : ptr;
|
|
344
|
+
}
|
|
345
|
+
for (let i = ptr; i < str.length; i++) {
|
|
346
|
+
let c = str[i];
|
|
347
|
+
if (c === "#") {
|
|
348
|
+
i = indexOfNewline(str, i);
|
|
349
|
+
} else if (c === sep3) {
|
|
350
|
+
return i + 1;
|
|
351
|
+
} else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
|
|
352
|
+
return i;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
throw new TomlError("cannot find end of structure", {
|
|
356
|
+
toml: str,
|
|
357
|
+
ptr
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ../node_modules/.bun/smol-toml@1.7.0/node_modules/smol-toml/dist/extract.js
|
|
362
|
+
function sliceAndTrimEndOf(str, startPtr, endPtr) {
|
|
363
|
+
let value = str.slice(startPtr, endPtr);
|
|
364
|
+
let commentIdx = value.indexOf("#");
|
|
365
|
+
if (commentIdx > -1) {
|
|
366
|
+
skipComment(str, commentIdx);
|
|
367
|
+
value = value.slice(0, commentIdx);
|
|
368
|
+
}
|
|
369
|
+
return [value.trimEnd(), commentIdx];
|
|
370
|
+
}
|
|
371
|
+
function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
372
|
+
if (depth === 0) {
|
|
373
|
+
throw new TomlError("document contains excessively nested structures. aborting.", {
|
|
374
|
+
toml: str,
|
|
375
|
+
ptr
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
let c = str[ptr];
|
|
379
|
+
if (c === "[" || c === "{") {
|
|
380
|
+
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
|
381
|
+
if (end) {
|
|
382
|
+
endPtr2 = skipVoid(str, endPtr2);
|
|
383
|
+
if (str[endPtr2] === ",")
|
|
384
|
+
endPtr2++;
|
|
385
|
+
else if (str[endPtr2] !== end) {
|
|
386
|
+
throw new TomlError("expected comma or end of structure", {
|
|
387
|
+
toml: str,
|
|
388
|
+
ptr: endPtr2
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return [value, endPtr2];
|
|
393
|
+
}
|
|
394
|
+
if (c === '"' || c === "'") {
|
|
395
|
+
let [parsed, endPtr2] = parseString(str, ptr);
|
|
396
|
+
if (end) {
|
|
397
|
+
endPtr2 = skipVoid(str, endPtr2);
|
|
398
|
+
if (str[endPtr2] && str[endPtr2] !== "," && str[endPtr2] !== end && str[endPtr2] !== "\n" && str[endPtr2] !== "\r") {
|
|
399
|
+
throw new TomlError("unexpected character encountered", {
|
|
400
|
+
toml: str,
|
|
401
|
+
ptr: endPtr2
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
if (str[endPtr2] === ",")
|
|
405
|
+
endPtr2++;
|
|
406
|
+
}
|
|
407
|
+
return [parsed, endPtr2];
|
|
408
|
+
}
|
|
409
|
+
let endPtr = skipUntil(str, ptr, ",", end);
|
|
410
|
+
let slice = sliceAndTrimEndOf(str, ptr, endPtr - (str[endPtr - 1] === "," ? 1 : 0));
|
|
411
|
+
if (!slice[0]) {
|
|
412
|
+
throw new TomlError("incomplete key-value declaration: no value specified", {
|
|
413
|
+
toml: str,
|
|
414
|
+
ptr
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
if (end && slice[1] > -1) {
|
|
418
|
+
endPtr = skipVoid(str, ptr + slice[1]);
|
|
419
|
+
if (str[endPtr] === ",")
|
|
420
|
+
endPtr++;
|
|
421
|
+
}
|
|
422
|
+
return [
|
|
423
|
+
parseValue(slice[0], str, ptr, integersAsBigInt),
|
|
424
|
+
endPtr
|
|
425
|
+
];
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ../node_modules/.bun/smol-toml@1.7.0/node_modules/smol-toml/dist/struct.js
|
|
429
|
+
var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
|
|
430
|
+
function parseKey(str, ptr, end = "=") {
|
|
431
|
+
let dot = ptr - 1;
|
|
432
|
+
let parsed = [];
|
|
433
|
+
let endPtr = str.indexOf(end, ptr);
|
|
434
|
+
if (endPtr < 0) {
|
|
435
|
+
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
436
|
+
toml: str,
|
|
437
|
+
ptr
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
do {
|
|
441
|
+
let c = str[ptr = ++dot];
|
|
442
|
+
if (c !== " " && c !== " ") {
|
|
443
|
+
if (c === '"' || c === "'") {
|
|
444
|
+
if (c === str[ptr + 1] && c === str[ptr + 2]) {
|
|
445
|
+
throw new TomlError("multiline strings are not allowed in keys", {
|
|
446
|
+
toml: str,
|
|
447
|
+
ptr
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
let [part, eos] = parseString(str, ptr);
|
|
451
|
+
dot = str.indexOf(".", eos);
|
|
452
|
+
let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
453
|
+
let newLine = indexOfNewline(strEnd);
|
|
454
|
+
if (newLine > -1) {
|
|
455
|
+
throw new TomlError("newlines are not allowed in keys", {
|
|
456
|
+
toml: str,
|
|
457
|
+
ptr: ptr + dot + newLine
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
if (strEnd.trimStart()) {
|
|
461
|
+
throw new TomlError("found extra tokens after the string part", {
|
|
462
|
+
toml: str,
|
|
463
|
+
ptr: eos
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
if (endPtr < eos) {
|
|
467
|
+
endPtr = str.indexOf(end, eos);
|
|
468
|
+
if (endPtr < 0) {
|
|
469
|
+
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
470
|
+
toml: str,
|
|
471
|
+
ptr
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
parsed.push(part);
|
|
476
|
+
} else {
|
|
477
|
+
dot = str.indexOf(".", ptr);
|
|
478
|
+
let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
479
|
+
if (!KEY_PART_RE.test(part)) {
|
|
480
|
+
throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
|
|
481
|
+
toml: str,
|
|
482
|
+
ptr
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
parsed.push(part.trimEnd());
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
} while (dot + 1 && dot < endPtr);
|
|
489
|
+
return [parsed, skipVoid(str, endPtr + 1, true, true)];
|
|
490
|
+
}
|
|
491
|
+
function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
492
|
+
let res = {};
|
|
493
|
+
let seen = /* @__PURE__ */ new Set();
|
|
494
|
+
let c;
|
|
495
|
+
ptr++;
|
|
496
|
+
while ((c = str[ptr++]) !== "}" && c) {
|
|
497
|
+
if (c === ",") {
|
|
498
|
+
throw new TomlError("expected value, found comma", {
|
|
499
|
+
toml: str,
|
|
500
|
+
ptr: ptr - 1
|
|
501
|
+
});
|
|
502
|
+
} else if (c === "#")
|
|
503
|
+
ptr = skipComment(str, ptr);
|
|
504
|
+
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
505
|
+
let k;
|
|
506
|
+
let t = res;
|
|
507
|
+
let hasOwn = false;
|
|
508
|
+
let [key, keyEndPtr] = parseKey(str, ptr - 1);
|
|
509
|
+
for (let i = 0; i < key.length; i++) {
|
|
510
|
+
if (i)
|
|
511
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
512
|
+
k = key[i];
|
|
513
|
+
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
|
|
514
|
+
throw new TomlError("trying to redefine an already defined value", {
|
|
515
|
+
toml: str,
|
|
516
|
+
ptr
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
if (!hasOwn && k === "__proto__") {
|
|
520
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (hasOwn) {
|
|
524
|
+
throw new TomlError("trying to redefine an already defined value", {
|
|
525
|
+
toml: str,
|
|
526
|
+
ptr
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
|
|
530
|
+
seen.add(value);
|
|
531
|
+
t[k] = value;
|
|
532
|
+
ptr = valueEndPtr;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (!c) {
|
|
536
|
+
throw new TomlError("unfinished table encountered", {
|
|
537
|
+
toml: str,
|
|
538
|
+
ptr
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
return [res, ptr];
|
|
542
|
+
}
|
|
543
|
+
function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
544
|
+
let res = [];
|
|
545
|
+
let c;
|
|
546
|
+
ptr++;
|
|
547
|
+
while ((c = str[ptr++]) !== "]" && c) {
|
|
548
|
+
if (c === ",") {
|
|
549
|
+
throw new TomlError("expected value, found comma", {
|
|
550
|
+
toml: str,
|
|
551
|
+
ptr: ptr - 1
|
|
552
|
+
});
|
|
553
|
+
} else if (c === "#")
|
|
554
|
+
ptr = skipComment(str, ptr);
|
|
555
|
+
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
556
|
+
let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
|
|
557
|
+
res.push(e[0]);
|
|
558
|
+
ptr = e[1];
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (!c) {
|
|
562
|
+
throw new TomlError("unfinished array encountered", {
|
|
563
|
+
toml: str,
|
|
564
|
+
ptr
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
return [res, ptr];
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// ../node_modules/.bun/smol-toml@1.7.0/node_modules/smol-toml/dist/parse.js
|
|
571
|
+
function peekTable(key, table, meta, type) {
|
|
572
|
+
let t = table;
|
|
573
|
+
let m = meta;
|
|
574
|
+
let k;
|
|
575
|
+
let hasOwn = false;
|
|
576
|
+
let state;
|
|
577
|
+
for (let i = 0; i < key.length; i++) {
|
|
578
|
+
if (i) {
|
|
579
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
580
|
+
m = (state = m[k]).c;
|
|
581
|
+
if (type === 0 && (state.t === 1 || state.t === 2)) {
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
if (state.t === 2) {
|
|
585
|
+
let l = t.length - 1;
|
|
586
|
+
t = t[l];
|
|
587
|
+
m = m[l].c;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
k = key[i];
|
|
591
|
+
if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
if (!hasOwn) {
|
|
595
|
+
if (k === "__proto__") {
|
|
596
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
597
|
+
Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
|
|
598
|
+
}
|
|
599
|
+
m[k] = {
|
|
600
|
+
t: i < key.length - 1 && type === 2 ? 3 : type,
|
|
601
|
+
d: false,
|
|
602
|
+
i: 0,
|
|
603
|
+
c: {}
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
state = m[k];
|
|
608
|
+
if (state.t !== type && !(type === 1 && state.t === 3)) {
|
|
609
|
+
return null;
|
|
610
|
+
}
|
|
611
|
+
if (type === 2) {
|
|
612
|
+
if (!state.d) {
|
|
613
|
+
state.d = true;
|
|
614
|
+
t[k] = [];
|
|
615
|
+
}
|
|
616
|
+
t[k].push(t = {});
|
|
617
|
+
state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
|
|
618
|
+
}
|
|
619
|
+
if (state.d) {
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
622
|
+
state.d = true;
|
|
623
|
+
if (type === 1) {
|
|
624
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
625
|
+
} else if (type === 0 && hasOwn) {
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
return [k, t, state.c];
|
|
629
|
+
}
|
|
630
|
+
function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
631
|
+
let res = {};
|
|
632
|
+
let meta = {};
|
|
633
|
+
let tbl = res;
|
|
634
|
+
let m = meta;
|
|
635
|
+
for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
|
|
636
|
+
if (toml[ptr] === "[") {
|
|
637
|
+
let isTableArray = toml[++ptr] === "[";
|
|
638
|
+
let k = parseKey(toml, ptr += +isTableArray, "]");
|
|
639
|
+
if (isTableArray) {
|
|
640
|
+
if (toml[k[1] - 1] !== "]") {
|
|
641
|
+
throw new TomlError("expected end of table declaration", {
|
|
642
|
+
toml,
|
|
643
|
+
ptr: k[1] - 1
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
k[1]++;
|
|
647
|
+
}
|
|
648
|
+
let p = peekTable(
|
|
649
|
+
k[0],
|
|
650
|
+
res,
|
|
651
|
+
meta,
|
|
652
|
+
isTableArray ? 2 : 1
|
|
653
|
+
/* Type.EXPLICIT */
|
|
654
|
+
);
|
|
655
|
+
if (!p) {
|
|
656
|
+
throw new TomlError("trying to redefine an already defined table or value", {
|
|
657
|
+
toml,
|
|
658
|
+
ptr
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
m = p[2];
|
|
662
|
+
tbl = p[1];
|
|
663
|
+
ptr = k[1];
|
|
664
|
+
} else {
|
|
665
|
+
let k = parseKey(toml, ptr);
|
|
666
|
+
let p = peekTable(
|
|
667
|
+
k[0],
|
|
668
|
+
tbl,
|
|
669
|
+
m,
|
|
670
|
+
0
|
|
671
|
+
/* Type.DOTTED */
|
|
672
|
+
);
|
|
673
|
+
if (!p) {
|
|
674
|
+
throw new TomlError("trying to redefine an already defined table or value", {
|
|
675
|
+
toml,
|
|
676
|
+
ptr
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
|
|
680
|
+
p[1][p[0]] = v[0];
|
|
681
|
+
ptr = v[1];
|
|
682
|
+
}
|
|
683
|
+
ptr = skipVoid(toml, ptr, true);
|
|
684
|
+
if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
|
|
685
|
+
throw new TomlError("each key-value declaration must be followed by an end-of-line", {
|
|
686
|
+
toml,
|
|
687
|
+
ptr
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
ptr = skipVoid(toml, ptr);
|
|
691
|
+
}
|
|
692
|
+
return res;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// ../node_modules/.bun/strip-json-comments@5.0.3/node_modules/strip-json-comments/index.js
|
|
696
|
+
var singleComment = /* @__PURE__ */ Symbol("singleComment");
|
|
697
|
+
var multiComment = /* @__PURE__ */ Symbol("multiComment");
|
|
698
|
+
var stripWithoutWhitespace = () => "";
|
|
699
|
+
var stripWithWhitespace = (string, start, end) => string.slice(start, end).replace(/[^ \t\r\n]/g, " ");
|
|
700
|
+
var isEscaped = (jsonString, quotePosition) => {
|
|
701
|
+
let index = quotePosition - 1;
|
|
702
|
+
let backslashCount = 0;
|
|
703
|
+
while (jsonString[index] === "\\") {
|
|
704
|
+
index -= 1;
|
|
705
|
+
backslashCount += 1;
|
|
706
|
+
}
|
|
707
|
+
return Boolean(backslashCount % 2);
|
|
708
|
+
};
|
|
709
|
+
function stripJsonComments(jsonString, { whitespace = true, trailingCommas = false } = {}) {
|
|
710
|
+
if (typeof jsonString !== "string") {
|
|
711
|
+
throw new TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``);
|
|
712
|
+
}
|
|
713
|
+
const strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace;
|
|
714
|
+
let isInsideString = false;
|
|
715
|
+
let isInsideComment = false;
|
|
716
|
+
let offset = 0;
|
|
717
|
+
let buffer = "";
|
|
718
|
+
let result = "";
|
|
719
|
+
let commaIndex = -1;
|
|
720
|
+
for (let index = 0; index < jsonString.length; index++) {
|
|
721
|
+
const currentCharacter = jsonString[index];
|
|
722
|
+
const nextCharacter = jsonString[index + 1];
|
|
723
|
+
if (!isInsideComment && currentCharacter === '"') {
|
|
724
|
+
const escaped = isEscaped(jsonString, index);
|
|
725
|
+
if (!escaped) {
|
|
726
|
+
isInsideString = !isInsideString;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (isInsideString) {
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
if (!isInsideComment && currentCharacter + nextCharacter === "//") {
|
|
733
|
+
buffer += jsonString.slice(offset, index);
|
|
734
|
+
offset = index;
|
|
735
|
+
isInsideComment = singleComment;
|
|
736
|
+
index++;
|
|
737
|
+
} else if (isInsideComment === singleComment && currentCharacter + nextCharacter === "\r\n") {
|
|
738
|
+
index++;
|
|
739
|
+
isInsideComment = false;
|
|
740
|
+
buffer += strip(jsonString, offset, index);
|
|
741
|
+
offset = index;
|
|
742
|
+
continue;
|
|
743
|
+
} else if (isInsideComment === singleComment && currentCharacter === "\n") {
|
|
744
|
+
isInsideComment = false;
|
|
745
|
+
buffer += strip(jsonString, offset, index);
|
|
746
|
+
offset = index;
|
|
747
|
+
} else if (!isInsideComment && currentCharacter + nextCharacter === "/*") {
|
|
748
|
+
buffer += jsonString.slice(offset, index);
|
|
749
|
+
offset = index;
|
|
750
|
+
isInsideComment = multiComment;
|
|
751
|
+
index++;
|
|
752
|
+
continue;
|
|
753
|
+
} else if (isInsideComment === multiComment && currentCharacter + nextCharacter === "*/") {
|
|
754
|
+
index++;
|
|
755
|
+
isInsideComment = false;
|
|
756
|
+
buffer += strip(jsonString, offset, index + 1);
|
|
757
|
+
offset = index + 1;
|
|
758
|
+
continue;
|
|
759
|
+
} else if (trailingCommas && !isInsideComment) {
|
|
760
|
+
if (commaIndex !== -1) {
|
|
761
|
+
if (currentCharacter === "}" || currentCharacter === "]") {
|
|
762
|
+
buffer += jsonString.slice(offset, index);
|
|
763
|
+
result += strip(buffer, 0, 1) + buffer.slice(1);
|
|
764
|
+
buffer = "";
|
|
765
|
+
offset = index;
|
|
766
|
+
commaIndex = -1;
|
|
767
|
+
} else if (currentCharacter !== " " && currentCharacter !== " " && currentCharacter !== "\r" && currentCharacter !== "\n") {
|
|
768
|
+
buffer += jsonString.slice(offset, index);
|
|
769
|
+
offset = index;
|
|
770
|
+
commaIndex = -1;
|
|
771
|
+
}
|
|
772
|
+
} else if (currentCharacter === ",") {
|
|
773
|
+
result += buffer + jsonString.slice(offset, index);
|
|
774
|
+
buffer = "";
|
|
775
|
+
offset = index;
|
|
776
|
+
commaIndex = index;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
const remaining = isInsideComment === singleComment ? strip(jsonString, offset) : jsonString.slice(offset);
|
|
781
|
+
return result + buffer + remaining;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/agent-plugin-loader.ts
|
|
785
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
786
|
+
import { isAbsolute, relative, resolve, sep } from "path";
|
|
787
|
+
var PLUGIN_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json";
|
|
788
|
+
var MCP_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json";
|
|
789
|
+
var PLUGIN_NAME_PATTERN = /^(?!.*(?:--|\.\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
|
|
790
|
+
var PLUGIN_MANIFEST_FIELDS = /* @__PURE__ */ new Set([
|
|
791
|
+
"$schema",
|
|
792
|
+
"name",
|
|
793
|
+
"version",
|
|
794
|
+
"description",
|
|
795
|
+
"author",
|
|
796
|
+
"homepage",
|
|
797
|
+
"repository",
|
|
798
|
+
"license",
|
|
799
|
+
"keywords",
|
|
800
|
+
"extensions"
|
|
801
|
+
]);
|
|
802
|
+
var MCP_CONFIG_FIELDS = /* @__PURE__ */ new Set(["$schema", "mcpServers"]);
|
|
803
|
+
var STDIO_FIELDS = /* @__PURE__ */ new Set(["type", "command", "args", "env", "cwd"]);
|
|
804
|
+
var HTTP_FIELDS = /* @__PURE__ */ new Set(["type", "url", "headers"]);
|
|
805
|
+
function loadAgentPluginConfigs(paths, cwd = process.cwd()) {
|
|
806
|
+
const mcpServers = {};
|
|
807
|
+
for (const pluginPath of getPluginPaths(paths)) {
|
|
808
|
+
const loaded = loadAgentPluginMcpConfig(pluginPath, cwd);
|
|
809
|
+
if (!loaded) continue;
|
|
810
|
+
for (const [serverName, server] of Object.entries(loaded.mcpServers)) {
|
|
811
|
+
if (mcpServers[serverName]) {
|
|
812
|
+
console.warn(`Agent Plugin at ${resolvePluginPath(pluginPath, cwd)} skips duplicate normalized MCP server ${serverName}`);
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
mcpServers[serverName] = server;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
return { mcpServers };
|
|
819
|
+
}
|
|
820
|
+
function getAgentPluginSummaries(paths, cwd = process.cwd()) {
|
|
821
|
+
return getPluginPaths(paths).map((path) => {
|
|
822
|
+
const pluginRoot = resolvePluginPath(path, cwd);
|
|
823
|
+
const loaded = loadAgentPluginMcpConfig(path, cwd);
|
|
824
|
+
const manifest = loaded ? readPluginManifest(pluginRoot, false) : null;
|
|
825
|
+
return {
|
|
826
|
+
path: pluginRoot,
|
|
827
|
+
...manifest?.name ? { name: manifest.name } : {},
|
|
828
|
+
serverCount: loaded ? Object.keys(loaded.mcpServers).length : 0
|
|
829
|
+
};
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
function getPluginPaths(paths) {
|
|
833
|
+
return Array.isArray(paths) ? paths.filter((path) => typeof path === "string") : [];
|
|
834
|
+
}
|
|
835
|
+
function loadAgentPluginMcpConfig(path, cwd) {
|
|
836
|
+
const pluginRoot = resolvePluginPath(path, cwd);
|
|
837
|
+
const manifest = readPluginManifest(pluginRoot, true);
|
|
838
|
+
if (!manifest) return null;
|
|
839
|
+
const mcpPath = resolve(pluginRoot, "mcp.json");
|
|
840
|
+
if (!existsSync(mcpPath)) return { mcpServers: {} };
|
|
841
|
+
if (!statSync(mcpPath).isFile()) {
|
|
842
|
+
console.warn(`Agent Plugin ${manifest.name} has invalid MCP config: mcp.json is not a regular file`);
|
|
843
|
+
return { mcpServers: {} };
|
|
844
|
+
}
|
|
845
|
+
let raw;
|
|
846
|
+
try {
|
|
847
|
+
raw = JSON.parse(readFileSync(mcpPath, "utf8"));
|
|
848
|
+
} catch (error) {
|
|
849
|
+
console.warn(`Agent Plugin ${manifest.name} has invalid MCP config: failed to parse mcp.json`, error);
|
|
850
|
+
return { mcpServers: {} };
|
|
851
|
+
}
|
|
852
|
+
return translateAgentPluginMcpConfig(raw, manifest, pluginRoot);
|
|
853
|
+
}
|
|
854
|
+
function readPluginManifest(pluginRoot, report) {
|
|
855
|
+
const manifestPath = resolve(pluginRoot, "plugin.json");
|
|
856
|
+
if (!existsSync(manifestPath)) {
|
|
857
|
+
if (report) console.warn(`Agent Plugin at ${pluginRoot} is invalid: missing plugin.json`);
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
860
|
+
if (!statSync(manifestPath).isFile()) {
|
|
861
|
+
if (report) console.warn(`Agent Plugin at ${pluginRoot} is invalid: plugin.json is not a regular file`);
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
let raw;
|
|
865
|
+
try {
|
|
866
|
+
raw = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
867
|
+
} catch (error) {
|
|
868
|
+
if (report) console.warn(`Agent Plugin at ${pluginRoot} is invalid: failed to parse plugin.json`, error);
|
|
869
|
+
return null;
|
|
870
|
+
}
|
|
871
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
872
|
+
if (report) console.warn(`Agent Plugin at ${pluginRoot} is invalid: plugin.json must be an object`);
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
const manifest = raw;
|
|
876
|
+
for (const key of Object.keys(manifest)) {
|
|
877
|
+
if (!PLUGIN_MANIFEST_FIELDS.has(key) && report) {
|
|
878
|
+
console.warn(`Agent Plugin at ${pluginRoot} ignores unknown plugin.json field: ${key}`);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
if (manifest.$schema !== PLUGIN_SCHEMA) {
|
|
882
|
+
if (report) console.warn(`Agent Plugin at ${pluginRoot} is invalid: unsupported plugin.json $schema`);
|
|
883
|
+
return null;
|
|
884
|
+
}
|
|
885
|
+
if (typeof manifest.name !== "string" || manifest.name.length < 1 || manifest.name.length > 64 || !PLUGIN_NAME_PATTERN.test(manifest.name)) {
|
|
886
|
+
if (report) console.warn(`Agent Plugin at ${pluginRoot} is invalid: plugin.json name is invalid`);
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
if (manifest.extensions !== void 0 && (!manifest.extensions || typeof manifest.extensions !== "object" || Array.isArray(manifest.extensions))) {
|
|
890
|
+
if (report) console.warn(`Agent Plugin ${manifest.name} ignores non-object plugin.json extensions`);
|
|
891
|
+
}
|
|
892
|
+
return { name: manifest.name };
|
|
893
|
+
}
|
|
894
|
+
function translateAgentPluginMcpConfig(raw, manifest, pluginRoot) {
|
|
895
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
896
|
+
console.warn(`Agent Plugin ${manifest.name} has invalid MCP config: mcp.json must be an object`);
|
|
897
|
+
return { mcpServers: {} };
|
|
898
|
+
}
|
|
899
|
+
const mcpConfig = raw;
|
|
900
|
+
for (const key of Object.keys(mcpConfig)) {
|
|
901
|
+
if (!MCP_CONFIG_FIELDS.has(key)) {
|
|
902
|
+
console.warn(`Agent Plugin ${manifest.name} has invalid MCP config: unknown top-level field ${key}`);
|
|
903
|
+
return { mcpServers: {} };
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
if (mcpConfig.$schema !== MCP_SCHEMA) {
|
|
907
|
+
console.warn(`Agent Plugin ${manifest.name} has invalid MCP config: unsupported mcp.json $schema`);
|
|
908
|
+
return { mcpServers: {} };
|
|
909
|
+
}
|
|
910
|
+
if (!mcpConfig.mcpServers || typeof mcpConfig.mcpServers !== "object" || Array.isArray(mcpConfig.mcpServers)) {
|
|
911
|
+
console.warn(`Agent Plugin ${manifest.name} has invalid MCP config: mcpServers must be an object`);
|
|
912
|
+
return { mcpServers: {} };
|
|
913
|
+
}
|
|
914
|
+
const mcpServers = {};
|
|
915
|
+
for (const [serverName, entry] of Object.entries(mcpConfig.mcpServers)) {
|
|
916
|
+
const translated = translateAgentPluginServer(manifest, pluginRoot, serverName, entry);
|
|
917
|
+
if (!translated) continue;
|
|
918
|
+
const normalizedName = formatAgentPluginServerName(manifest.name, serverName);
|
|
919
|
+
if (mcpServers[normalizedName]) {
|
|
920
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: normalized server name ${normalizedName} already exists`);
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
mcpServers[normalizedName] = translated;
|
|
924
|
+
}
|
|
925
|
+
return { mcpServers };
|
|
926
|
+
}
|
|
927
|
+
function translateAgentPluginServer(manifest, pluginRoot, serverName, entry) {
|
|
928
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
929
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: entry must be an object`);
|
|
930
|
+
return null;
|
|
931
|
+
}
|
|
932
|
+
const raw = entry;
|
|
933
|
+
if (raw.type === "stdio") return translateStdioServer(manifest, pluginRoot, serverName, raw);
|
|
934
|
+
if (raw.type === "streamable-http" || raw.type === "sse") return translateHttpServer(manifest, serverName, raw, raw.type);
|
|
935
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: unsupported type`);
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
function translateStdioServer(manifest, pluginRoot, serverName, raw) {
|
|
939
|
+
for (const key of Object.keys(raw)) {
|
|
940
|
+
if (!STDIO_FIELDS.has(key)) return skipServer(manifest, serverName, `unknown field ${key}`);
|
|
941
|
+
}
|
|
942
|
+
if (typeof raw.command !== "string" || raw.command.length === 0) return skipServer(manifest, serverName, "command must be a non-empty string");
|
|
943
|
+
if (!isBareCommand(raw.command) && !raw.command.startsWith("./")) return skipServer(manifest, serverName, "command must be bare or plugin-relative");
|
|
944
|
+
const args = translateStringArray(raw.args, manifest, serverName, "args");
|
|
945
|
+
if (args === null) return null;
|
|
946
|
+
const env = translateEnv(raw.env, manifest, serverName);
|
|
947
|
+
if (env === null) return null;
|
|
948
|
+
const command = raw.command.startsWith("./") ? resolveContainedPath(pluginRoot, raw.command, pluginRoot) : raw.command;
|
|
949
|
+
if (command === null) return skipServer(manifest, serverName, "command must stay inside the plugin directory");
|
|
950
|
+
const pluginDataDir = getAgentPath("agent-plugin-data", manifest.name);
|
|
951
|
+
const cwd = resolvePluginCwd(raw.cwd, pluginRoot, pluginDataDir);
|
|
952
|
+
if (cwd === null) return skipServer(manifest, serverName, "cwd must be plugin-relative, PLUGIN_ROOT-rooted, or PLUGIN_DATA-rooted");
|
|
953
|
+
return {
|
|
954
|
+
command,
|
|
955
|
+
args: args.map((value) => expandPluginPlaceholders(value, pluginRoot, pluginDataDir)),
|
|
956
|
+
env: {
|
|
957
|
+
...Object.fromEntries(Object.entries(env).map(([key, value]) => [key, expandPluginPlaceholders(value, pluginRoot, pluginDataDir)])),
|
|
958
|
+
PLUGIN_ROOT: pluginRoot,
|
|
959
|
+
PLUGIN_DATA: pluginDataDir
|
|
960
|
+
},
|
|
961
|
+
cwd,
|
|
962
|
+
pluginDataDir,
|
|
963
|
+
literalEnv: true
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
function translateHttpServer(manifest, serverName, raw, type) {
|
|
967
|
+
for (const key of Object.keys(raw)) {
|
|
968
|
+
if (!HTTP_FIELDS.has(key)) return skipServer(manifest, serverName, `unknown field ${key}`);
|
|
969
|
+
}
|
|
970
|
+
if (typeof raw.url !== "string" || raw.url.length === 0) return skipServer(manifest, serverName, "url must be a non-empty string");
|
|
971
|
+
if (!isValidAgentPluginUrl(raw.url)) return skipServer(manifest, serverName, "url must be an allowed absolute HTTP(S) URL");
|
|
972
|
+
const headers = translateHeaders(raw.headers, manifest, serverName);
|
|
973
|
+
if (headers === null) return null;
|
|
974
|
+
return {
|
|
975
|
+
url: raw.url,
|
|
976
|
+
httpTransport: type,
|
|
977
|
+
...headers ? { headers } : {}
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
function formatAgentPluginServerName(pluginName, serverName) {
|
|
981
|
+
const pluginPart = pluginName.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "plugin";
|
|
982
|
+
const serverPart = serverName.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "server";
|
|
983
|
+
return `${pluginPart}__${serverPart}`;
|
|
984
|
+
}
|
|
985
|
+
function skipServer(manifest, serverName, reason) {
|
|
986
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: ${reason}`);
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
function translateStringArray(value, manifest, serverName, field) {
|
|
990
|
+
if (value === void 0) return [];
|
|
991
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
992
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: ${field} must be an array of strings`);
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
995
|
+
return value;
|
|
996
|
+
}
|
|
997
|
+
function translateEnv(value, manifest, serverName) {
|
|
998
|
+
if (value === void 0) return {};
|
|
999
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1000
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: env must be an object of strings`);
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
const env = {};
|
|
1004
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
1005
|
+
if (key === "PLUGIN_ROOT" || key === "PLUGIN_DATA") {
|
|
1006
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: env must not define ${key}`);
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
if (typeof entry !== "string") {
|
|
1010
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: env values must be strings`);
|
|
1011
|
+
return null;
|
|
1012
|
+
}
|
|
1013
|
+
env[key] = entry;
|
|
1014
|
+
}
|
|
1015
|
+
return env;
|
|
1016
|
+
}
|
|
1017
|
+
function translateHeaders(value, manifest, serverName) {
|
|
1018
|
+
if (value === void 0) return void 0;
|
|
1019
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1020
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: headers must be an object of strings`);
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1023
|
+
const headers = {};
|
|
1024
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1025
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
1026
|
+
if (typeof entry !== "string") {
|
|
1027
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: header values must be strings`);
|
|
1028
|
+
return null;
|
|
1029
|
+
}
|
|
1030
|
+
const normalized = key.toLowerCase();
|
|
1031
|
+
if (seen.has(normalized)) {
|
|
1032
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: duplicate header ${key}`);
|
|
1033
|
+
return null;
|
|
1034
|
+
}
|
|
1035
|
+
seen.add(normalized);
|
|
1036
|
+
headers[key] = entry;
|
|
1037
|
+
}
|
|
1038
|
+
try {
|
|
1039
|
+
new Headers(headers);
|
|
1040
|
+
} catch {
|
|
1041
|
+
console.warn(`Agent Plugin ${manifest.name} skips invalid MCP server ${serverName}: headers are not valid HTTP fields`);
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
1045
|
+
}
|
|
1046
|
+
function resolvePluginPath(path, cwd) {
|
|
1047
|
+
if (path === "~") return resolve(process.env.HOME ?? "", ".");
|
|
1048
|
+
if (path.startsWith("~/")) return resolve(process.env.HOME ?? "", path.slice(2));
|
|
1049
|
+
return isAbsolute(path) ? resolve(path) : resolve(cwd, path);
|
|
1050
|
+
}
|
|
1051
|
+
function isBareCommand(command) {
|
|
1052
|
+
return !command.includes("/") && !command.includes("\\") && !command.includes("${PLUGIN_ROOT}") && !command.includes("${PLUGIN_DATA}");
|
|
1053
|
+
}
|
|
1054
|
+
function resolvePluginCwd(value, pluginRoot, pluginDataDir) {
|
|
1055
|
+
if (value === void 0) return pluginRoot;
|
|
1056
|
+
if (typeof value !== "string") return null;
|
|
1057
|
+
if (value.startsWith("./")) return resolveContainedPath(pluginRoot, value, pluginRoot);
|
|
1058
|
+
if (value === "${PLUGIN_ROOT}" || value.startsWith("${PLUGIN_ROOT}/")) {
|
|
1059
|
+
return resolveContainedPath(pluginRoot, value.replace("${PLUGIN_ROOT}", "."), pluginRoot);
|
|
1060
|
+
}
|
|
1061
|
+
if (value === "${PLUGIN_DATA}" || value.startsWith("${PLUGIN_DATA}/")) {
|
|
1062
|
+
return resolveContainedPath(pluginDataDir, value.replace("${PLUGIN_DATA}", "."), pluginDataDir);
|
|
1063
|
+
}
|
|
1064
|
+
return null;
|
|
1065
|
+
}
|
|
1066
|
+
function resolveContainedPath(root, value, containmentRoot) {
|
|
1067
|
+
const resolved = resolve(root, value);
|
|
1068
|
+
const rel = relative(containmentRoot, resolved);
|
|
1069
|
+
if (rel === "" || !rel.startsWith("..") && !rel.startsWith(sep) && !isAbsolute(rel)) return resolved;
|
|
1070
|
+
return null;
|
|
1071
|
+
}
|
|
1072
|
+
function expandPluginPlaceholders(value, pluginRoot, pluginDataDir) {
|
|
1073
|
+
return value.replaceAll("${PLUGIN_ROOT}", pluginRoot).replaceAll("${PLUGIN_DATA}", pluginDataDir);
|
|
1074
|
+
}
|
|
1075
|
+
function isValidAgentPluginUrl(value) {
|
|
1076
|
+
if (value.includes("${") || value.includes("$env:") || value.includes("{env:")) return false;
|
|
1077
|
+
let url;
|
|
1078
|
+
try {
|
|
1079
|
+
url = new URL(value);
|
|
1080
|
+
} catch {
|
|
1081
|
+
return false;
|
|
1082
|
+
}
|
|
1083
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
1084
|
+
if (url.username || url.password || url.hash) return false;
|
|
1085
|
+
if (url.protocol === "https:") return true;
|
|
1086
|
+
return isLoopbackHost(url.hostname);
|
|
1087
|
+
}
|
|
1088
|
+
function isLoopbackHost(hostname) {
|
|
1089
|
+
const host = hostname.toLowerCase();
|
|
1090
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]") return true;
|
|
1091
|
+
if (/^127(?:\.\d{1,3}){3}$/.test(host)) return true;
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/package-mcp-loader.ts
|
|
1096
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync, statSync as statSync2 } from "fs";
|
|
1097
|
+
import { isAbsolute as isAbsolute2, join, relative as relative2, resolve as resolve2, sep as sep2 } from "path";
|
|
1098
|
+
function loadPackageMcpConfigs(cwd = process.cwd()) {
|
|
1099
|
+
const mcpServers = {};
|
|
1100
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1101
|
+
for (const packageRoot of getConfiguredPackageRoots(cwd)) {
|
|
1102
|
+
const manifest = readPackageManifest(packageRoot);
|
|
1103
|
+
if (!manifest || typeof manifest.name !== "string" || !manifest.name) continue;
|
|
1104
|
+
const paths = getManifestMcpPaths(manifest.pi?.mcp, manifest.name);
|
|
1105
|
+
if (!paths) continue;
|
|
1106
|
+
const packagePrefix = formatPackageName(manifest.name);
|
|
1107
|
+
const packageServers = /* @__PURE__ */ new Set();
|
|
1108
|
+
for (const path of paths) {
|
|
1109
|
+
const configPath = resolvePackageConfigPath(packageRoot, path);
|
|
1110
|
+
if (!configPath) {
|
|
1111
|
+
console.warn(`Pi package ${manifest.name} skips MCP config ${path}: file must stay inside the package`);
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1114
|
+
const config = readMcpConfig(configPath, manifest.name);
|
|
1115
|
+
if (!config) continue;
|
|
1116
|
+
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
1117
|
+
const normalizedName = `${packagePrefix}__${formatServerName(serverName)}`;
|
|
1118
|
+
if (packageServers.has(normalizedName) || seen.has(normalizedName)) {
|
|
1119
|
+
console.warn(`Pi package ${manifest.name} skips duplicate normalized MCP server ${normalizedName}`);
|
|
1120
|
+
continue;
|
|
1121
|
+
}
|
|
1122
|
+
packageServers.add(normalizedName);
|
|
1123
|
+
seen.add(normalizedName);
|
|
1124
|
+
mcpServers[normalizedName] = server;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
return { mcpServers };
|
|
1129
|
+
}
|
|
1130
|
+
function getConfiguredPackageRoots(cwd) {
|
|
1131
|
+
const roots = [];
|
|
1132
|
+
for (const [settingsPath, scope] of [
|
|
1133
|
+
[join(cwd, getConfigDirName(), "settings.json"), "project"],
|
|
1134
|
+
[join(getAgentDir(), "settings.json"), "user"]
|
|
1135
|
+
]) {
|
|
1136
|
+
const settings = readOptionalJson(settingsPath, `${scope} Pi settings`);
|
|
1137
|
+
if (settings === void 0) continue;
|
|
1138
|
+
if (typeof settings !== "object" || settings === null || Array.isArray(settings)) {
|
|
1139
|
+
throw new Error(`${scope} Pi settings ${settingsPath} must be a JSON object`);
|
|
1140
|
+
}
|
|
1141
|
+
const packages = settings.packages;
|
|
1142
|
+
if (packages === void 0) continue;
|
|
1143
|
+
if (!Array.isArray(packages)) throw new Error(`${scope} Pi settings ${settingsPath} packages must be an array`);
|
|
1144
|
+
for (const entry of packages) {
|
|
1145
|
+
const source = typeof entry === "string" ? entry : entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.source === "string" ? entry.source : void 0;
|
|
1146
|
+
if (!source) throw new Error(`${scope} Pi settings ${settingsPath} package entries must be strings or objects with a string source`);
|
|
1147
|
+
const root = resolvePackageRoot(source, scope, cwd);
|
|
1148
|
+
if (root && !roots.includes(root)) roots.push(root);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
return roots;
|
|
1152
|
+
}
|
|
1153
|
+
function resolvePackageRoot(source, scope, cwd) {
|
|
1154
|
+
const baseDir = scope === "user" ? getAgentDir() : join(cwd, getConfigDirName());
|
|
1155
|
+
if (source.startsWith("npm:")) {
|
|
1156
|
+
const name = source.slice(4).trim().match(/^(@?[^@]+(?:\/[^@]+)?)/)?.[1];
|
|
1157
|
+
return name ? resolveContainedPath2(join(baseDir, "npm", "node_modules"), name) : null;
|
|
1158
|
+
}
|
|
1159
|
+
const gitSource = source.startsWith("git:") ? source.slice(4).trim() : /^(?:(?:https?|ssh):\/\/|git@[^:]+:)/.test(source) ? source : null;
|
|
1160
|
+
if (gitSource) {
|
|
1161
|
+
const value = gitSource.replace(/^ssh:\/\/git@/, "").replace(/^git@([^:]+):/, "$1/").replace(/^[a-z]+:\/\//i, "");
|
|
1162
|
+
const path = value.replace(/@[^/]+$/, "").replace(/\.git$/, "");
|
|
1163
|
+
return path && !path.startsWith("/") ? resolveContainedPath2(join(baseDir, "git"), path) : null;
|
|
1164
|
+
}
|
|
1165
|
+
return isAbsolute2(source) ? resolve2(source) : resolve2(baseDir, source);
|
|
1166
|
+
}
|
|
1167
|
+
function readPackageManifest(packageRoot) {
|
|
1168
|
+
const manifest = readOptionalJson(join(packageRoot, "package.json"), `Pi package manifest ${packageRoot}`);
|
|
1169
|
+
return manifest && typeof manifest === "object" && !Array.isArray(manifest) ? manifest : null;
|
|
1170
|
+
}
|
|
1171
|
+
function getManifestMcpPaths(value, packageName) {
|
|
1172
|
+
const paths = typeof value === "string" ? [value] : Array.isArray(value) && value.every((path) => typeof path === "string") ? value : null;
|
|
1173
|
+
if (value !== void 0 && !paths) console.warn(`Pi package ${packageName} ignores invalid pi.mcp manifest entry`);
|
|
1174
|
+
return paths;
|
|
1175
|
+
}
|
|
1176
|
+
function readMcpConfig(path, packageName) {
|
|
1177
|
+
const config = readRequiredJson(path, `Pi package ${packageName} MCP config`);
|
|
1178
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
1179
|
+
throw new Error(`Pi package ${packageName} MCP config ${path} must be a JSON object`);
|
|
1180
|
+
}
|
|
1181
|
+
const servers = config.mcpServers;
|
|
1182
|
+
if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
|
|
1183
|
+
throw new Error(`Pi package ${packageName} MCP config ${path} must contain a JSON object mcpServers field`);
|
|
1184
|
+
}
|
|
1185
|
+
const mcpServers = {};
|
|
1186
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
1187
|
+
if (!server || typeof server !== "object" || Array.isArray(server)) {
|
|
1188
|
+
throw new Error(`Pi package ${packageName} MCP config ${path} server ${name} must be a JSON object`);
|
|
1189
|
+
}
|
|
1190
|
+
mcpServers[name] = server;
|
|
1191
|
+
}
|
|
1192
|
+
return { mcpServers };
|
|
1193
|
+
}
|
|
1194
|
+
function readRequiredJson(path, description) {
|
|
1195
|
+
try {
|
|
1196
|
+
return JSON.parse(stripJsonComments(readFileSync2(path, "utf8"), { trailingCommas: true }));
|
|
1197
|
+
} catch (error) {
|
|
1198
|
+
throw new Error(`${description} ${path} contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
function readOptionalJson(path, description) {
|
|
1202
|
+
if (!existsSync2(path)) return void 0;
|
|
1203
|
+
return readRequiredJson(path, description);
|
|
1204
|
+
}
|
|
1205
|
+
function resolveContainedPath2(root, path) {
|
|
1206
|
+
const resolved = resolve2(root, path);
|
|
1207
|
+
const rel = relative2(root, resolved);
|
|
1208
|
+
return rel === "" || !rel.startsWith("..") && !rel.startsWith(sep2) && !isAbsolute2(rel) ? resolved : null;
|
|
1209
|
+
}
|
|
1210
|
+
function resolvePackageConfigPath(packageRoot, path) {
|
|
1211
|
+
const lexicalPath = resolveContainedPath2(packageRoot, path);
|
|
1212
|
+
if (!lexicalPath || !existsSync2(lexicalPath) || !statSync2(lexicalPath).isFile()) return null;
|
|
1213
|
+
try {
|
|
1214
|
+
const realPackageRoot = realpathSync(packageRoot);
|
|
1215
|
+
const realConfigPath = realpathSync(lexicalPath);
|
|
1216
|
+
return resolveContainedPath2(realPackageRoot, realConfigPath);
|
|
1217
|
+
} catch {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
function formatPackageName(name) {
|
|
1222
|
+
return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "package";
|
|
1223
|
+
}
|
|
1224
|
+
function formatServerName(name) {
|
|
1225
|
+
return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "server";
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/config.ts
|
|
1229
|
+
var GENERIC_GLOBAL_CONFIG_PATH = join2(homedir(), ".config", "mcp", "mcp.json");
|
|
1230
|
+
var AGENTS_GLOBAL_CONFIG_PATHS = [
|
|
1231
|
+
join2(homedir(), ".agents", "mcp.json"),
|
|
1232
|
+
join2(homedir(), ".agents", "mcp", "mcp.json")
|
|
1233
|
+
];
|
|
1234
|
+
var PROJECT_CONFIG_NAME = ".mcp.json";
|
|
1235
|
+
var PROJECT_PI_CONFIG_NAME = "mcp.json";
|
|
1236
|
+
var REPOPROMPT_BINARY_CANDIDATES = [
|
|
1237
|
+
join2(homedir(), "RepoPrompt", "repoprompt_cli"),
|
|
1238
|
+
"/Applications/Repo Prompt.app/Contents/MacOS/repoprompt-mcp"
|
|
1239
|
+
];
|
|
1240
|
+
var KNOWN_SERVER_PRESETS = [
|
|
1241
|
+
{
|
|
1242
|
+
id: "deepwiki",
|
|
1243
|
+
name: "DeepWiki",
|
|
1244
|
+
summary: "Ask questions about public GitHub repositories.",
|
|
1245
|
+
entry: { url: "https://mcp.deepwiki.com/mcp", protocolVersion: "auto" }
|
|
1246
|
+
},
|
|
1247
|
+
{
|
|
1248
|
+
id: "context7",
|
|
1249
|
+
name: "Context7",
|
|
1250
|
+
summary: "Look up current library documentation and examples.",
|
|
1251
|
+
entry: { url: "https://mcp.context7.com/mcp", protocolVersion: "auto" }
|
|
1252
|
+
},
|
|
1253
|
+
{
|
|
1254
|
+
id: "parallel-search",
|
|
1255
|
+
name: "Parallel Search",
|
|
1256
|
+
summary: "Search the web and fetch pages without an API key.",
|
|
1257
|
+
entry: {
|
|
1258
|
+
url: "https://search.parallel.ai/mcp",
|
|
1259
|
+
protocolVersion: "auto",
|
|
1260
|
+
directTools: true
|
|
1261
|
+
}
|
|
1262
|
+
},
|
|
1263
|
+
{
|
|
1264
|
+
id: "notion",
|
|
1265
|
+
name: "Notion",
|
|
1266
|
+
summary: "Search and work with your Notion workspace.",
|
|
1267
|
+
entry: { url: "https://mcp.notion.com/mcp", auth: "oauth", protocolVersion: "auto" }
|
|
1268
|
+
},
|
|
1269
|
+
{
|
|
1270
|
+
id: "github",
|
|
1271
|
+
name: "GitHub",
|
|
1272
|
+
summary: "Work with GitHub through your Copilot account.",
|
|
1273
|
+
entry: { url: "https://api.githubcopilot.com/mcp", auth: "oauth", protocolVersion: "auto" }
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
id: "chrome-devtools",
|
|
1277
|
+
name: "Chrome DevTools",
|
|
1278
|
+
summary: "Inspect and automate a local Chrome browser.",
|
|
1279
|
+
entry: { command: "npx", args: ["-y", "chrome-devtools-mcp@1.6.0"] }
|
|
1280
|
+
}
|
|
1281
|
+
];
|
|
1282
|
+
var IMPORT_PATHS = {
|
|
1283
|
+
cursor: [join2(homedir(), ".cursor", "mcp.json")],
|
|
1284
|
+
"claude-code": [
|
|
1285
|
+
join2(homedir(), ".claude", "mcp.json"),
|
|
1286
|
+
join2(homedir(), ".claude.json"),
|
|
1287
|
+
join2(homedir(), ".claude", "claude_desktop_config.json")
|
|
1288
|
+
],
|
|
1289
|
+
"claude-desktop": [join2(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json")],
|
|
1290
|
+
codex: [
|
|
1291
|
+
join2(homedir(), ".codex", "config.toml"),
|
|
1292
|
+
join2(homedir(), ".codex", "config.json")
|
|
1293
|
+
],
|
|
1294
|
+
opencode: [
|
|
1295
|
+
join2(homedir(), ".config", "opencode", "opencode.json"),
|
|
1296
|
+
"./opencode.json"
|
|
1297
|
+
],
|
|
1298
|
+
windsurf: [join2(homedir(), ".windsurf", "mcp.json")],
|
|
1299
|
+
vscode: [".vscode/mcp.json"]
|
|
1300
|
+
};
|
|
1301
|
+
function getPiGlobalConfigPath(overridePath) {
|
|
1302
|
+
return overridePath ? resolve3(overridePath) : getAgentPath("mcp.json");
|
|
1303
|
+
}
|
|
1304
|
+
function getGenericGlobalConfigPath() {
|
|
1305
|
+
return GENERIC_GLOBAL_CONFIG_PATH;
|
|
1306
|
+
}
|
|
1307
|
+
function getProjectConfigPath(cwd = process.cwd()) {
|
|
1308
|
+
return resolve3(cwd, PROJECT_CONFIG_NAME);
|
|
1309
|
+
}
|
|
1310
|
+
function getProjectPiConfigPath(cwd = process.cwd()) {
|
|
1311
|
+
return resolve3(cwd, getConfigDirName(), PROJECT_PI_CONFIG_NAME);
|
|
1312
|
+
}
|
|
1313
|
+
function getSharedConfigPath(target, cwd = process.cwd()) {
|
|
1314
|
+
return target === "project" ? getProjectConfigPath(cwd) : getGenericGlobalConfigPath();
|
|
1315
|
+
}
|
|
1316
|
+
function getConfigSourceSummaries(sourceSpecs) {
|
|
1317
|
+
return sourceSpecs.map((source) => {
|
|
1318
|
+
const loaded = readValidatedConfig(source.readPath, `MCP config from ${source.readPath}`);
|
|
1319
|
+
return {
|
|
1320
|
+
id: source.id,
|
|
1321
|
+
label: source.label,
|
|
1322
|
+
path: source.readPath,
|
|
1323
|
+
exists: existsSync3(source.readPath),
|
|
1324
|
+
scope: source.scope,
|
|
1325
|
+
kind: source.shared ? "shared" : "pi",
|
|
1326
|
+
serverCount: loaded ? Object.keys(loaded.mcpServers).length : 0
|
|
1327
|
+
};
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
function getMcpStandardConfigSummary(overridePath, cwd = process.cwd()) {
|
|
1331
|
+
const sources = getConfigSourceSummaries(getConfigSources(overridePath, cwd));
|
|
1332
|
+
return {
|
|
1333
|
+
sources,
|
|
1334
|
+
hasSharedServers: sources.some((source) => source.kind === "shared" && source.serverCount > 0),
|
|
1335
|
+
fingerprint: JSON.stringify({ sources: sources.map((source) => [source.id, source.exists, source.serverCount]) })
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
function getMcpDiscoverySummary(overridePath, cwd = process.cwd(), options = {}) {
|
|
1339
|
+
const sourceSpecs = getConfigSources(overridePath, cwd);
|
|
1340
|
+
const sources = getConfigSourceSummaries(sourceSpecs);
|
|
1341
|
+
const includeHostConfigs = options.includeHostConfigs !== false;
|
|
1342
|
+
const importKinds = isExclusiveConfigMode() ? readValidatedConfig(getEffectivePiGlobalConfigPath(overridePath), "MCP exclusive config")?.imports ?? [] : Object.keys(IMPORT_PATHS);
|
|
1343
|
+
const imports = includeHostConfigs ? importKinds.map((kind) => {
|
|
1344
|
+
const imported = loadImportedConfig(kind, cwd, `Failed to inspect imported MCP config from ${kind}:`);
|
|
1345
|
+
if (!imported) return null;
|
|
1346
|
+
return {
|
|
1347
|
+
kind,
|
|
1348
|
+
path: imported.path,
|
|
1349
|
+
serverCount: Object.keys(extractServers(imported.value, kind)).length
|
|
1350
|
+
};
|
|
1351
|
+
}).filter((value) => value !== null) : [];
|
|
1352
|
+
const hostConfigDiscovery = isExclusiveConfigMode() ? "off" : getConfiguredHostConfigDiscovery(overridePath, cwd);
|
|
1353
|
+
const hostConfigs = imports.map((entry) => ({ ...entry, active: hostConfigDiscovery === "on" }));
|
|
1354
|
+
const settings = getMergedSettings(overridePath, cwd);
|
|
1355
|
+
const agentPlugins = isExclusiveConfigMode() ? [] : getAgentPluginSummaries(settings?.agentPluginPaths, cwd);
|
|
1356
|
+
const totalServerCount = sources.reduce((sum, source) => sum + source.serverCount, 0) + agentPlugins.reduce((sum, plugin) => sum + plugin.serverCount, 0);
|
|
1357
|
+
const hasSharedServers = sources.some((source) => source.kind === "shared" && source.serverCount > 0) || agentPlugins.some((plugin) => plugin.serverCount > 0);
|
|
1358
|
+
const hasPiOwnedServers = sources.some((source) => source.kind === "pi" && source.serverCount > 0);
|
|
1359
|
+
const hasAnyDetectedPaths = sources.some((source) => source.exists) || imports.length > 0 || agentPlugins.length > 0;
|
|
1360
|
+
const hasAnyConfig = totalServerCount > 0 || imports.some((entry) => entry.serverCount > 0) || hasAnyDetectedPaths;
|
|
1361
|
+
const summaryWithoutRepoPrompt = {
|
|
1362
|
+
sources,
|
|
1363
|
+
imports,
|
|
1364
|
+
hostConfigs,
|
|
1365
|
+
hostConfigDiscovery,
|
|
1366
|
+
agentPlugins,
|
|
1367
|
+
conflicts: getConfigConflicts(sourceSpecs, imports, cwd),
|
|
1368
|
+
hasAnyConfig,
|
|
1369
|
+
hasAnyDetectedPaths,
|
|
1370
|
+
hasSharedServers,
|
|
1371
|
+
hasPiOwnedServers,
|
|
1372
|
+
totalServerCount
|
|
1373
|
+
};
|
|
1374
|
+
const fingerprint = JSON.stringify({
|
|
1375
|
+
sources: sources.map((source) => [source.id, source.exists, source.serverCount]),
|
|
1376
|
+
imports: imports.map((entry) => [entry.kind, entry.path, entry.serverCount]),
|
|
1377
|
+
agentPlugins: agentPlugins.map((entry) => [entry.path, entry.name, entry.serverCount]),
|
|
1378
|
+
hostConfigDiscovery,
|
|
1379
|
+
conflicts: summaryWithoutRepoPrompt.conflicts
|
|
1380
|
+
});
|
|
1381
|
+
return {
|
|
1382
|
+
...summaryWithoutRepoPrompt,
|
|
1383
|
+
fingerprint,
|
|
1384
|
+
repoPrompt: detectRepoPrompt(summaryWithoutRepoPrompt, cwd)
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
function cloneMcpConfig(config) {
|
|
1388
|
+
return structuredClone(config);
|
|
1389
|
+
}
|
|
1390
|
+
function loadMcpConfig(overridePath, cwd = process.cwd()) {
|
|
1391
|
+
const sourceSpecs = getConfigSources(overridePath, cwd);
|
|
1392
|
+
const hostConfigDiscovery = getConfiguredHostConfigDiscovery(overridePath, cwd);
|
|
1393
|
+
let config = !isExclusiveConfigMode() && hostConfigDiscovery === "on" ? loadDiscoveredHostConfigs(cwd) : { mcpServers: {} };
|
|
1394
|
+
for (const source of sourceSpecs) {
|
|
1395
|
+
const loaded = readValidatedConfig(source.readPath, `MCP config from ${source.readPath}`);
|
|
1396
|
+
if (!loaded) continue;
|
|
1397
|
+
config = mergeConfigs(config, expandImports(loaded, cwd));
|
|
1398
|
+
}
|
|
1399
|
+
if (isExclusiveConfigMode()) return config;
|
|
1400
|
+
const packageConfig = loadPackageMcpConfigs(cwd);
|
|
1401
|
+
const pluginConfig = loadAgentPluginConfigs(config.settings?.agentPluginPaths, cwd);
|
|
1402
|
+
const packageServers = Object.fromEntries(
|
|
1403
|
+
Object.entries(packageConfig.mcpServers).filter(([name]) => !Object.hasOwn(pluginConfig.mcpServers, name))
|
|
1404
|
+
);
|
|
1405
|
+
return mergeConfigs({ mcpServers: packageServers }, mergeConfigs(pluginConfig, config));
|
|
1406
|
+
}
|
|
1407
|
+
function getMergedSettings(overridePath, cwd = process.cwd()) {
|
|
1408
|
+
let settings;
|
|
1409
|
+
for (const source of getConfigSources(overridePath, cwd)) {
|
|
1410
|
+
const loaded = readValidatedConfig(source.readPath, `MCP config from ${source.readPath}`);
|
|
1411
|
+
if (loaded?.settings) settings = { ...settings, ...loaded.settings };
|
|
1412
|
+
}
|
|
1413
|
+
return settings;
|
|
1414
|
+
}
|
|
1415
|
+
function getConfiguredHostConfigDiscovery(overridePath, cwd = process.cwd()) {
|
|
1416
|
+
let configured = "off";
|
|
1417
|
+
const settings = getMergedSettings(overridePath, cwd);
|
|
1418
|
+
const value = settings?.hostConfigDiscovery;
|
|
1419
|
+
if (value === "off" || value === "prompt" || value === "on") configured = value;
|
|
1420
|
+
return configured;
|
|
1421
|
+
}
|
|
1422
|
+
function loadDiscoveredHostConfigs(cwd) {
|
|
1423
|
+
let config = { mcpServers: {} };
|
|
1424
|
+
for (const importKind of Object.keys(IMPORT_PATHS)) {
|
|
1425
|
+
const imported = loadImportedConfig(importKind, cwd, `Failed to discover imported MCP config from ${importKind}:`);
|
|
1426
|
+
if (!imported) continue;
|
|
1427
|
+
config = mergeConfigs(config, {
|
|
1428
|
+
mcpServers: extractServers(imported.value, importKind)
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
return config;
|
|
1432
|
+
}
|
|
1433
|
+
function getConfigConflicts(sourceSpecs, imports, cwd) {
|
|
1434
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1435
|
+
const record = (name, source) => {
|
|
1436
|
+
const entries = seen.get(name) ?? [];
|
|
1437
|
+
if (!entries.some((entry) => entry.kind === source.kind && entry.path === source.path)) entries.push(source);
|
|
1438
|
+
seen.set(name, entries);
|
|
1439
|
+
};
|
|
1440
|
+
for (const entry of imports) {
|
|
1441
|
+
const imported = loadImportedConfig(entry.kind, cwd, `Failed to inspect imported MCP config from ${entry.kind}:`);
|
|
1442
|
+
if (!imported) continue;
|
|
1443
|
+
for (const name of Object.keys(extractServers(imported.value, entry.kind))) {
|
|
1444
|
+
record(name, { kind: "host", path: imported.path });
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
for (const source of sourceSpecs) {
|
|
1448
|
+
const loaded = readValidatedConfig(source.readPath, `MCP config from ${source.readPath}`);
|
|
1449
|
+
if (!loaded) continue;
|
|
1450
|
+
if (loaded.imports?.length) {
|
|
1451
|
+
for (const importKind of loaded.imports) {
|
|
1452
|
+
const imported = loadImportedConfig(importKind, cwd, `Failed to inspect imported MCP config from ${importKind}:`);
|
|
1453
|
+
if (!imported) continue;
|
|
1454
|
+
for (const name of Object.keys(extractServers(imported.value, importKind))) {
|
|
1455
|
+
record(name, { kind: "host", path: imported.path });
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
for (const name of Object.keys(loaded.mcpServers)) {
|
|
1460
|
+
record(name, {
|
|
1461
|
+
kind: source.shared ? "shared" : "pi",
|
|
1462
|
+
path: source.readPath
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
return [...seen.entries()].filter(([, sources]) => sources.length > 1).map(([serverName, sources]) => ({ serverName, sources, winner: sources[sources.length - 1] })).sort((left, right) => left.serverName.localeCompare(right.serverName));
|
|
1467
|
+
}
|
|
1468
|
+
function getConfigSources(overridePath, cwd = process.cwd()) {
|
|
1469
|
+
const userPath = getEffectivePiGlobalConfigPath(overridePath);
|
|
1470
|
+
const projectPath = getProjectConfigPath(cwd);
|
|
1471
|
+
const projectPiPath = getProjectPiConfigPath(cwd);
|
|
1472
|
+
const sources = [];
|
|
1473
|
+
if (isExclusiveConfigMode()) {
|
|
1474
|
+
return [{
|
|
1475
|
+
id: "pi-global",
|
|
1476
|
+
label: "Pi exclusive config",
|
|
1477
|
+
readPath: userPath,
|
|
1478
|
+
writePath: userPath,
|
|
1479
|
+
kind: "user",
|
|
1480
|
+
shared: false,
|
|
1481
|
+
scope: "global"
|
|
1482
|
+
}];
|
|
1483
|
+
}
|
|
1484
|
+
if (GENERIC_GLOBAL_CONFIG_PATH !== userPath) {
|
|
1485
|
+
sources.push({
|
|
1486
|
+
id: "shared-global",
|
|
1487
|
+
label: "user-global standard MCP",
|
|
1488
|
+
readPath: GENERIC_GLOBAL_CONFIG_PATH,
|
|
1489
|
+
writePath: userPath,
|
|
1490
|
+
kind: "import",
|
|
1491
|
+
importKind: "global MCP config",
|
|
1492
|
+
shared: true,
|
|
1493
|
+
scope: "global"
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
for (const [index, agentsPath] of AGENTS_GLOBAL_CONFIG_PATHS.entries()) {
|
|
1497
|
+
if (agentsPath === userPath || agentsPath === GENERIC_GLOBAL_CONFIG_PATH) continue;
|
|
1498
|
+
sources.push({
|
|
1499
|
+
id: index === 0 ? "agents-global" : "agents-nested-global",
|
|
1500
|
+
label: index === 0 ? "user-global .agents MCP" : "user-global .agents nested MCP",
|
|
1501
|
+
readPath: agentsPath,
|
|
1502
|
+
writePath: userPath,
|
|
1503
|
+
kind: "import",
|
|
1504
|
+
importKind: index === 0 ? ".agents MCP config" : ".agents/mcp MCP config",
|
|
1505
|
+
shared: true,
|
|
1506
|
+
scope: "global"
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
sources.push({
|
|
1510
|
+
id: "pi-global",
|
|
1511
|
+
label: "Pi global override",
|
|
1512
|
+
readPath: userPath,
|
|
1513
|
+
writePath: userPath,
|
|
1514
|
+
kind: "user",
|
|
1515
|
+
shared: false,
|
|
1516
|
+
scope: "global"
|
|
1517
|
+
});
|
|
1518
|
+
if (projectPath !== userPath) {
|
|
1519
|
+
sources.push({
|
|
1520
|
+
id: "shared-project",
|
|
1521
|
+
label: "project standard MCP",
|
|
1522
|
+
readPath: projectPath,
|
|
1523
|
+
writePath: projectPath,
|
|
1524
|
+
kind: "project",
|
|
1525
|
+
shared: true,
|
|
1526
|
+
scope: "project"
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
if (projectPiPath !== userPath && projectPiPath !== projectPath) {
|
|
1530
|
+
sources.push({
|
|
1531
|
+
id: "pi-project",
|
|
1532
|
+
label: "project Pi override",
|
|
1533
|
+
readPath: projectPiPath,
|
|
1534
|
+
writePath: projectPiPath,
|
|
1535
|
+
kind: "project",
|
|
1536
|
+
shared: false,
|
|
1537
|
+
scope: "project"
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1540
|
+
return sources;
|
|
1541
|
+
}
|
|
1542
|
+
function isExclusiveConfigMode() {
|
|
1543
|
+
return process.env.PI_MCP_CONFIG_MODE?.trim().toLowerCase() === "exclusive";
|
|
1544
|
+
}
|
|
1545
|
+
function getEffectivePiGlobalConfigPath(overridePath) {
|
|
1546
|
+
return getPiGlobalConfigPath(isExclusiveConfigMode() ? void 0 : overridePath);
|
|
1547
|
+
}
|
|
1548
|
+
function mergeConfigs(base, next) {
|
|
1549
|
+
const imports = mergeImports(base.imports, next.imports);
|
|
1550
|
+
const settings = next.settings ? { ...base.settings, ...next.settings } : base.settings;
|
|
1551
|
+
return {
|
|
1552
|
+
mcpServers: mergeServerMaps(base.mcpServers, next.mcpServers),
|
|
1553
|
+
...imports !== void 0 ? { imports } : {},
|
|
1554
|
+
...settings !== void 0 ? { settings } : {}
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
var URL_BOUND_AUTH_FIELDS = ["headers", "bearerToken", "bearerTokenEnv", "bearerTokenStore", "requestHeadersCommand"];
|
|
1558
|
+
function mergeServerMaps(base, next) {
|
|
1559
|
+
const merged = { ...base };
|
|
1560
|
+
for (const [name, definition] of Object.entries(next)) {
|
|
1561
|
+
const existing = merged[name];
|
|
1562
|
+
let baseEntry = existing ?? {};
|
|
1563
|
+
if (existing && typeof definition.command === "string") {
|
|
1564
|
+
baseEntry = { ...existing };
|
|
1565
|
+
for (const field of [
|
|
1566
|
+
"url",
|
|
1567
|
+
"headers",
|
|
1568
|
+
"requestHeadersCommand",
|
|
1569
|
+
"auth",
|
|
1570
|
+
"bearerToken",
|
|
1571
|
+
"bearerTokenEnv",
|
|
1572
|
+
"oauth",
|
|
1573
|
+
"httpTransport",
|
|
1574
|
+
"socket"
|
|
1575
|
+
]) {
|
|
1576
|
+
delete baseEntry[field];
|
|
1577
|
+
}
|
|
1578
|
+
} else if (existing && typeof definition.url === "string") {
|
|
1579
|
+
baseEntry = { ...existing };
|
|
1580
|
+
for (const field of [
|
|
1581
|
+
"command",
|
|
1582
|
+
"args",
|
|
1583
|
+
"env",
|
|
1584
|
+
"cwd",
|
|
1585
|
+
"pluginDataDir",
|
|
1586
|
+
"literalEnv",
|
|
1587
|
+
"socket"
|
|
1588
|
+
]) {
|
|
1589
|
+
delete baseEntry[field];
|
|
1590
|
+
}
|
|
1591
|
+
} else if (existing && typeof definition.socket === "string") {
|
|
1592
|
+
baseEntry = { ...existing };
|
|
1593
|
+
for (const field of [
|
|
1594
|
+
"command",
|
|
1595
|
+
"args",
|
|
1596
|
+
"env",
|
|
1597
|
+
"cwd",
|
|
1598
|
+
"pluginDataDir",
|
|
1599
|
+
"literalEnv",
|
|
1600
|
+
"url",
|
|
1601
|
+
"headers",
|
|
1602
|
+
"requestHeadersCommand",
|
|
1603
|
+
"auth",
|
|
1604
|
+
"bearerToken",
|
|
1605
|
+
"bearerTokenEnv",
|
|
1606
|
+
"oauth",
|
|
1607
|
+
"httpTransport"
|
|
1608
|
+
]) {
|
|
1609
|
+
delete baseEntry[field];
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
if (existing && typeof definition.url === "string" && definition.url !== existing.url) {
|
|
1613
|
+
if (baseEntry === existing) baseEntry = { ...existing };
|
|
1614
|
+
for (const field of URL_BOUND_AUTH_FIELDS) {
|
|
1615
|
+
delete baseEntry[field];
|
|
1616
|
+
}
|
|
1617
|
+
if (baseEntry.oauth !== false) {
|
|
1618
|
+
delete baseEntry.oauth;
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
merged[name] = { ...baseEntry, ...definition };
|
|
1622
|
+
}
|
|
1623
|
+
return merged;
|
|
1624
|
+
}
|
|
1625
|
+
function mergeImports(left, right) {
|
|
1626
|
+
const merged = [...left ?? [], ...right ?? []];
|
|
1627
|
+
if (merged.length === 0) return void 0;
|
|
1628
|
+
return [...new Set(merged)];
|
|
1629
|
+
}
|
|
1630
|
+
function expandImports(config, cwd = process.cwd()) {
|
|
1631
|
+
if (!config.imports?.length) return config;
|
|
1632
|
+
const importedServers = {};
|
|
1633
|
+
for (const importKind of config.imports) {
|
|
1634
|
+
const imported = loadImportedConfig(importKind, cwd, `Failed to import MCP config from ${importKind}:`);
|
|
1635
|
+
if (!imported) continue;
|
|
1636
|
+
const servers = extractServers(imported.value, importKind);
|
|
1637
|
+
for (const [name, definition] of Object.entries(servers)) {
|
|
1638
|
+
if (!importedServers[name]) {
|
|
1639
|
+
importedServers[name] = definition;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
return {
|
|
1644
|
+
imports: config.imports,
|
|
1645
|
+
...config.settings !== void 0 ? { settings: config.settings } : {},
|
|
1646
|
+
mcpServers: mergeServerMaps(importedServers, config.mcpServers)
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
function resolveImportCandidates(importKind, cwd) {
|
|
1650
|
+
return (IMPORT_PATHS[importKind] ?? []).map((candidate) => {
|
|
1651
|
+
if (importKind === "opencode" && candidate === "./opencode.json") {
|
|
1652
|
+
const start = resolve3(cwd);
|
|
1653
|
+
let gitRoot;
|
|
1654
|
+
let current = start;
|
|
1655
|
+
while (true) {
|
|
1656
|
+
if (existsSync3(join2(current, ".git"))) {
|
|
1657
|
+
gitRoot = current;
|
|
1658
|
+
break;
|
|
1659
|
+
}
|
|
1660
|
+
const parent = dirname(current);
|
|
1661
|
+
if (parent === current) break;
|
|
1662
|
+
current = parent;
|
|
1663
|
+
}
|
|
1664
|
+
if (!gitRoot) return join2(start, "opencode.json");
|
|
1665
|
+
current = start;
|
|
1666
|
+
while (true) {
|
|
1667
|
+
const projectConfig = join2(current, "opencode.json");
|
|
1668
|
+
if (existsSync3(projectConfig) || current === gitRoot) return projectConfig;
|
|
1669
|
+
current = dirname(current);
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
return candidate.startsWith(".") ? resolve3(cwd, candidate) : candidate;
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
function parseJsonConfig(raw) {
|
|
1676
|
+
return JSON.parse(stripJsonComments(raw, { trailingCommas: true }));
|
|
1677
|
+
}
|
|
1678
|
+
function readImportedConfig(path) {
|
|
1679
|
+
const raw = readFileSync3(path, "utf-8");
|
|
1680
|
+
return path.endsWith(".toml") ? parse(raw) : parseJsonConfig(raw);
|
|
1681
|
+
}
|
|
1682
|
+
function loadImportedConfig(importKind, cwd, warningPrefix) {
|
|
1683
|
+
if (importKind === "opencode") {
|
|
1684
|
+
let merged = {};
|
|
1685
|
+
let highestPrecedencePath;
|
|
1686
|
+
for (const path of resolveImportCandidates(importKind, cwd)) {
|
|
1687
|
+
if (!existsSync3(path)) continue;
|
|
1688
|
+
try {
|
|
1689
|
+
const value = readImportedConfig(path);
|
|
1690
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1691
|
+
merged = mergeOpenCodeConfigs(merged, value);
|
|
1692
|
+
highestPrecedencePath = path;
|
|
1693
|
+
}
|
|
1694
|
+
} catch (error) {
|
|
1695
|
+
console.warn(warningPrefix, error);
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return highestPrecedencePath ? { path: highestPrecedencePath, value: merged } : null;
|
|
1699
|
+
}
|
|
1700
|
+
for (const path of resolveImportCandidates(importKind, cwd)) {
|
|
1701
|
+
if (!existsSync3(path)) continue;
|
|
1702
|
+
try {
|
|
1703
|
+
return { path, value: readImportedConfig(path) };
|
|
1704
|
+
} catch (error) {
|
|
1705
|
+
console.warn(warningPrefix, error);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
return null;
|
|
1709
|
+
}
|
|
1710
|
+
function readValidatedConfig(path, label) {
|
|
1711
|
+
if (!existsSync3(path)) return null;
|
|
1712
|
+
try {
|
|
1713
|
+
return validateConfig(parseJsonConfig(readFileSync3(path, "utf-8")));
|
|
1714
|
+
} catch (error) {
|
|
1715
|
+
console.warn(`Failed to load ${label}:`, error);
|
|
1716
|
+
return null;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
function validateConfig(raw) {
|
|
1720
|
+
if (!isRecord(raw)) {
|
|
1721
|
+
return { mcpServers: {} };
|
|
1722
|
+
}
|
|
1723
|
+
return {
|
|
1724
|
+
mcpServers: toServerEntries(raw.mcpServers ?? raw["mcp-servers"]),
|
|
1725
|
+
...Array.isArray(raw.imports) ? { imports: raw.imports } : {},
|
|
1726
|
+
...raw.settings !== void 0 ? { settings: raw.settings } : {}
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
function toServerEntries(servers) {
|
|
1730
|
+
if (!isRecord(servers)) return {};
|
|
1731
|
+
const entries = {};
|
|
1732
|
+
for (const [name, entry] of Object.entries(servers)) {
|
|
1733
|
+
if (isServerEntry(entry)) entries[name] = entry;
|
|
1734
|
+
}
|
|
1735
|
+
return entries;
|
|
1736
|
+
}
|
|
1737
|
+
function isServerEntry(value) {
|
|
1738
|
+
return isRecord(value);
|
|
1739
|
+
}
|
|
1740
|
+
function isRecord(value) {
|
|
1741
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1742
|
+
}
|
|
1743
|
+
function mergeOpenCodeConfigs(base, next) {
|
|
1744
|
+
const baseMcp = base.mcp;
|
|
1745
|
+
const nextMcp = next.mcp;
|
|
1746
|
+
const mergedMcp = {
|
|
1747
|
+
...baseMcp && typeof baseMcp === "object" && !Array.isArray(baseMcp) ? baseMcp : {}
|
|
1748
|
+
};
|
|
1749
|
+
if (nextMcp && typeof nextMcp === "object" && !Array.isArray(nextMcp)) {
|
|
1750
|
+
for (const [name, nextEntry] of Object.entries(nextMcp)) {
|
|
1751
|
+
const baseEntry = mergedMcp[name];
|
|
1752
|
+
if (baseEntry && typeof baseEntry === "object" && !Array.isArray(baseEntry) && nextEntry && typeof nextEntry === "object" && !Array.isArray(nextEntry)) {
|
|
1753
|
+
const safeBase = { ...baseEntry };
|
|
1754
|
+
const override = nextEntry;
|
|
1755
|
+
if (typeof override.type === "string" && override.type !== safeBase.type) {
|
|
1756
|
+
for (const field of ["command", "environment", "cwd", "url", "headers", "oauth"]) delete safeBase[field];
|
|
1757
|
+
}
|
|
1758
|
+
if (typeof override.url === "string" && override.url !== safeBase.url) {
|
|
1759
|
+
delete safeBase.headers;
|
|
1760
|
+
delete safeBase.oauth;
|
|
1761
|
+
}
|
|
1762
|
+
if (Array.isArray(override.command)) {
|
|
1763
|
+
const baseCommand = safeBase.command;
|
|
1764
|
+
const commandChanged = !Array.isArray(baseCommand) || override.command.length !== baseCommand.length || override.command.some((value, index) => value !== baseCommand[index]);
|
|
1765
|
+
if (commandChanged) {
|
|
1766
|
+
delete safeBase.environment;
|
|
1767
|
+
delete safeBase.cwd;
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
const mergedEntry = { ...safeBase, ...override };
|
|
1771
|
+
for (const field of ["environment", "headers", "oauth"]) {
|
|
1772
|
+
const baseField = safeBase[field];
|
|
1773
|
+
const nextField = override[field];
|
|
1774
|
+
if (baseField && typeof baseField === "object" && !Array.isArray(baseField) && nextField && typeof nextField === "object" && !Array.isArray(nextField)) {
|
|
1775
|
+
mergedEntry[field] = { ...baseField, ...nextField };
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
mergedMcp[name] = mergedEntry;
|
|
1779
|
+
} else {
|
|
1780
|
+
mergedMcp[name] = nextEntry;
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
return { ...base, ...next, mcp: mergedMcp };
|
|
1785
|
+
}
|
|
1786
|
+
function extractServers(config, kind) {
|
|
1787
|
+
if (!config || typeof config !== "object") return {};
|
|
1788
|
+
const obj = config;
|
|
1789
|
+
let servers;
|
|
1790
|
+
switch (kind) {
|
|
1791
|
+
case "claude-desktop":
|
|
1792
|
+
case "claude-code":
|
|
1793
|
+
servers = obj.mcpServers;
|
|
1794
|
+
break;
|
|
1795
|
+
case "codex":
|
|
1796
|
+
servers = obj.mcp_servers ?? obj.mcpServers;
|
|
1797
|
+
break;
|
|
1798
|
+
case "cursor":
|
|
1799
|
+
case "windsurf":
|
|
1800
|
+
case "vscode":
|
|
1801
|
+
servers = obj.mcpServers ?? obj["mcp-servers"];
|
|
1802
|
+
break;
|
|
1803
|
+
case "opencode":
|
|
1804
|
+
servers = obj.mcp;
|
|
1805
|
+
break;
|
|
1806
|
+
default:
|
|
1807
|
+
return {};
|
|
1808
|
+
}
|
|
1809
|
+
if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
|
|
1810
|
+
return {};
|
|
1811
|
+
}
|
|
1812
|
+
const mappedServers = {};
|
|
1813
|
+
for (const [name, entry] of Object.entries(servers)) {
|
|
1814
|
+
if (kind === "opencode") {
|
|
1815
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
1816
|
+
const raw = entry;
|
|
1817
|
+
if (raw.enabled === false) continue;
|
|
1818
|
+
if (raw.type === "local" && Array.isArray(raw.command) && raw.command.length > 0 && raw.command.every((value) => typeof value === "string")) {
|
|
1819
|
+
const env = toStringRecord(raw.environment);
|
|
1820
|
+
const command = raw.command[0];
|
|
1821
|
+
if (command === void 0) continue;
|
|
1822
|
+
const mapped2 = {
|
|
1823
|
+
command,
|
|
1824
|
+
args: raw.command.slice(1),
|
|
1825
|
+
...env ? { env } : {},
|
|
1826
|
+
...typeof raw.cwd === "string" ? { cwd: raw.cwd } : {}
|
|
1827
|
+
};
|
|
1828
|
+
mappedServers[name] = mapped2;
|
|
1829
|
+
continue;
|
|
1830
|
+
}
|
|
1831
|
+
if (raw.type === "remote" && typeof raw.url === "string") {
|
|
1832
|
+
const headers = toStringRecord(raw.headers);
|
|
1833
|
+
const mapped2 = {
|
|
1834
|
+
url: raw.url,
|
|
1835
|
+
...headers ? { headers } : {}
|
|
1836
|
+
};
|
|
1837
|
+
if (raw.oauth === false) {
|
|
1838
|
+
mapped2.oauth = false;
|
|
1839
|
+
} else if (raw.oauth && typeof raw.oauth === "object" && !Array.isArray(raw.oauth)) {
|
|
1840
|
+
const oauth = raw.oauth;
|
|
1841
|
+
mapped2.auth = "oauth";
|
|
1842
|
+
mapped2.oauth = {
|
|
1843
|
+
...typeof oauth.clientId === "string" ? { clientId: oauth.clientId } : {},
|
|
1844
|
+
...typeof oauth.clientSecret === "string" ? { clientSecret: oauth.clientSecret } : {},
|
|
1845
|
+
...typeof oauth.scope === "string" ? { scope: oauth.scope } : {},
|
|
1846
|
+
...typeof oauth.authServerMetadataUrl === "string" ? { authServerMetadataUrl: oauth.authServerMetadataUrl } : {},
|
|
1847
|
+
...typeof oauth.skipIssuerMetadataValidation === "boolean" ? { skipIssuerMetadataValidation: oauth.skipIssuerMetadataValidation } : {}
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
mappedServers[name] = mapped2;
|
|
1851
|
+
}
|
|
1852
|
+
continue;
|
|
1853
|
+
}
|
|
1854
|
+
if (!isRecord(entry)) continue;
|
|
1855
|
+
if (kind !== "codex") {
|
|
1856
|
+
mappedServers[name] = entry;
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1859
|
+
const mapped = { ...entry };
|
|
1860
|
+
const bearerTokenEnv = mapped.bearer_token_env_var;
|
|
1861
|
+
const httpHeaders = mapped.http_headers;
|
|
1862
|
+
const envHttpHeaders = mapped.env_http_headers;
|
|
1863
|
+
if (typeof bearerTokenEnv === "string") {
|
|
1864
|
+
mapped.bearerTokenEnv = bearerTokenEnv;
|
|
1865
|
+
if (mapped.auth === void 0) mapped.auth = "bearer";
|
|
1866
|
+
}
|
|
1867
|
+
if (httpHeaders && typeof httpHeaders === "object" && !Array.isArray(httpHeaders)) {
|
|
1868
|
+
mapped.headers = { ...mapped.headers, ...httpHeaders };
|
|
1869
|
+
}
|
|
1870
|
+
if (envHttpHeaders && typeof envHttpHeaders === "object" && !Array.isArray(envHttpHeaders)) {
|
|
1871
|
+
const headers = { ...mapped.headers };
|
|
1872
|
+
for (const [header, envVar] of Object.entries(envHttpHeaders)) {
|
|
1873
|
+
if (typeof envVar === "string" && headers[header] === void 0) headers[header] = `$env:${envVar}`;
|
|
1874
|
+
}
|
|
1875
|
+
mapped.headers = headers;
|
|
1876
|
+
}
|
|
1877
|
+
delete mapped.bearer_token_env_var;
|
|
1878
|
+
delete mapped.http_headers;
|
|
1879
|
+
delete mapped.env_http_headers;
|
|
1880
|
+
mappedServers[name] = mapped;
|
|
1881
|
+
}
|
|
1882
|
+
return mappedServers;
|
|
1883
|
+
}
|
|
1884
|
+
function serializeRawConfig(raw) {
|
|
1885
|
+
return `${JSON.stringify(raw, null, 2)}
|
|
1886
|
+
`;
|
|
1887
|
+
}
|
|
1888
|
+
function buildUnifiedDiff(beforeText, afterText) {
|
|
1889
|
+
if (beforeText === afterText) return "(no changes)";
|
|
1890
|
+
const before = beforeText.split("\n");
|
|
1891
|
+
const after = afterText.split("\n");
|
|
1892
|
+
const rows = before.length;
|
|
1893
|
+
const cols = after.length;
|
|
1894
|
+
const lcs = Array.from({ length: rows + 1 }, () => Array(cols + 1).fill(0));
|
|
1895
|
+
for (let i2 = rows - 1; i2 >= 0; i2--) {
|
|
1896
|
+
for (let j2 = cols - 1; j2 >= 0; j2--) {
|
|
1897
|
+
const row = lcs[i2];
|
|
1898
|
+
const nextRow = lcs[i2 + 1];
|
|
1899
|
+
if (!row || !nextRow) continue;
|
|
1900
|
+
row[j2] = before[i2] === after[j2] ? (nextRow[j2 + 1] ?? 0) + 1 : Math.max(nextRow[j2] ?? 0, row[j2 + 1] ?? 0);
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
const lines = ["--- before", "+++ after"];
|
|
1904
|
+
let i = 0;
|
|
1905
|
+
let j = 0;
|
|
1906
|
+
while (i < rows || j < cols) {
|
|
1907
|
+
if (i < rows && j < cols && before[i] === after[j]) {
|
|
1908
|
+
lines.push(` ${before[i]}`);
|
|
1909
|
+
i++;
|
|
1910
|
+
j++;
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1913
|
+
if (j < cols && (i === rows || (lcs[i]?.[j + 1] ?? 0) >= (lcs[i + 1]?.[j] ?? 0))) {
|
|
1914
|
+
lines.push(`+ ${after[j]}`);
|
|
1915
|
+
j++;
|
|
1916
|
+
continue;
|
|
1917
|
+
}
|
|
1918
|
+
if (i < rows) {
|
|
1919
|
+
lines.push(`- ${before[i]}`);
|
|
1920
|
+
i++;
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
return lines.join("\n");
|
|
1924
|
+
}
|
|
1925
|
+
function buildConfigWritePreview(filePath, nextRaw) {
|
|
1926
|
+
const existed = existsSync3(filePath);
|
|
1927
|
+
const beforeRaw = readRawConfigObject(filePath);
|
|
1928
|
+
const beforeText = existed ? serializeRawConfig(beforeRaw) : "";
|
|
1929
|
+
const afterText = serializeRawConfig(nextRaw);
|
|
1930
|
+
return {
|
|
1931
|
+
path: filePath,
|
|
1932
|
+
existed,
|
|
1933
|
+
changed: beforeText !== afterText,
|
|
1934
|
+
beforeText,
|
|
1935
|
+
afterText,
|
|
1936
|
+
diffText: buildUnifiedDiff(beforeText, afterText)
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
function readRawConfigObject(filePath) {
|
|
1940
|
+
if (!existsSync3(filePath)) return {};
|
|
1941
|
+
try {
|
|
1942
|
+
const raw = parseJsonConfig(readFileSync3(filePath, "utf-8"));
|
|
1943
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
1944
|
+
} catch {
|
|
1945
|
+
return {};
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
function writeRawConfigObject(filePath, raw) {
|
|
1949
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
1950
|
+
const tmpPath = `${filePath}.${process.pid}.tmp`;
|
|
1951
|
+
writeFileSync(tmpPath, `${JSON.stringify(raw, null, 2)}
|
|
1952
|
+
`, "utf-8");
|
|
1953
|
+
renameSync(tmpPath, filePath);
|
|
1954
|
+
}
|
|
1955
|
+
function getServersObject(raw) {
|
|
1956
|
+
const existing = raw.mcpServers ?? raw["mcp-servers"] ?? {};
|
|
1957
|
+
if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
|
|
1958
|
+
return {};
|
|
1959
|
+
}
|
|
1960
|
+
return existing;
|
|
1961
|
+
}
|
|
1962
|
+
function setServersObject(raw, servers) {
|
|
1963
|
+
delete raw["mcp-servers"];
|
|
1964
|
+
raw.mcpServers = servers;
|
|
1965
|
+
}
|
|
1966
|
+
function writeProjectServerDisabledOverride(overridePath, cwd, serverName, disabled) {
|
|
1967
|
+
const filePath = getProjectPiConfigPath(cwd);
|
|
1968
|
+
let raw = {};
|
|
1969
|
+
if (existsSync3(filePath)) {
|
|
1970
|
+
try {
|
|
1971
|
+
const parsed = parseJsonConfig(readFileSync3(filePath, "utf-8"));
|
|
1972
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1973
|
+
throw new Error("root value must be an object");
|
|
1974
|
+
}
|
|
1975
|
+
raw = parsed;
|
|
1976
|
+
} catch (error) {
|
|
1977
|
+
throw new Error(`Failed to read project MCP override at ${filePath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
const serverKey = raw.mcpServers !== void 0 ? "mcpServers" : raw["mcp-servers"] !== void 0 ? "mcp-servers" : "mcpServers";
|
|
1981
|
+
const rawServers = raw[serverKey];
|
|
1982
|
+
if (rawServers !== void 0 && (!rawServers || typeof rawServers !== "object" || Array.isArray(rawServers))) {
|
|
1983
|
+
throw new Error(`Failed to update project MCP override at ${filePath}: ${serverKey} must be an object`);
|
|
1984
|
+
}
|
|
1985
|
+
const servers = rawServers ?? {};
|
|
1986
|
+
const previous = servers[serverName];
|
|
1987
|
+
if (previous !== void 0 && (!previous || typeof previous !== "object" || Array.isArray(previous))) {
|
|
1988
|
+
throw new Error(`Failed to update project MCP override at ${filePath}: server "${serverName}" must be an object`);
|
|
1989
|
+
}
|
|
1990
|
+
const existing = previous;
|
|
1991
|
+
let next;
|
|
1992
|
+
if (disabled) {
|
|
1993
|
+
next = { ...existing, disabled: true };
|
|
1994
|
+
} else {
|
|
1995
|
+
next = Object.fromEntries(Object.entries(existing ?? {}).filter(([key]) => key !== "disabled"));
|
|
1996
|
+
let lowerConfig = { mcpServers: {} };
|
|
1997
|
+
for (const source of getConfigSources(overridePath, cwd)) {
|
|
1998
|
+
if (source.readPath === filePath) continue;
|
|
1999
|
+
const loaded = readValidatedConfig(source.readPath, `MCP config from ${source.readPath}`);
|
|
2000
|
+
if (loaded) lowerConfig = mergeConfigs(lowerConfig, expandImports(loaded, cwd));
|
|
2001
|
+
}
|
|
2002
|
+
if (raw.imports !== void 0) {
|
|
2003
|
+
if (!Array.isArray(raw.imports) || raw.imports.some((kind) => typeof kind !== "string" || !Object.hasOwn(IMPORT_PATHS, kind))) {
|
|
2004
|
+
throw new Error(`Failed to update project MCP override at ${filePath}: imports contains an unsupported config kind`);
|
|
2005
|
+
}
|
|
2006
|
+
lowerConfig = mergeConfigs(lowerConfig, expandImports({ mcpServers: {}, imports: raw.imports }, cwd));
|
|
2007
|
+
}
|
|
2008
|
+
if (isServerDisabled(lowerConfig.mcpServers[serverName])) next.disabled = false;
|
|
2009
|
+
}
|
|
2010
|
+
if (!existing && Object.keys(next).length === 0 || JSON.stringify(existing) === JSON.stringify(next)) {
|
|
2011
|
+
return { path: filePath, changed: false };
|
|
2012
|
+
}
|
|
2013
|
+
if (Object.keys(next).length === 0) delete servers[serverName];
|
|
2014
|
+
else servers[serverName] = next;
|
|
2015
|
+
raw[serverKey] = servers;
|
|
2016
|
+
writeRawConfigObject(filePath, raw);
|
|
2017
|
+
return { path: filePath, changed: true };
|
|
2018
|
+
}
|
|
2019
|
+
function isRepoPromptServer(name, entry) {
|
|
2020
|
+
const normalizedName = name.toLowerCase();
|
|
2021
|
+
if (normalizedName.includes("repoprompt") || normalizedName === "rp") {
|
|
2022
|
+
return true;
|
|
2023
|
+
}
|
|
2024
|
+
const command = entry.command?.toLowerCase() ?? "";
|
|
2025
|
+
if (command.includes("repoprompt") || command.includes("rp-mcp") || command.endsWith("repoprompt_cli")) {
|
|
2026
|
+
return true;
|
|
2027
|
+
}
|
|
2028
|
+
return (entry.args ?? []).some((arg) => typeof arg === "string" && arg.toLowerCase().includes("repoprompt"));
|
|
2029
|
+
}
|
|
2030
|
+
function findProjectRoot(cwd = process.cwd()) {
|
|
2031
|
+
let current = resolve3(cwd);
|
|
2032
|
+
while (true) {
|
|
2033
|
+
if (existsSync3(join2(current, ".git")) || existsSync3(join2(current, "package.json")) || existsSync3(join2(current, PROJECT_CONFIG_NAME)) || existsSync3(join2(current, ".pi"))) {
|
|
2034
|
+
return current;
|
|
2035
|
+
}
|
|
2036
|
+
const parent = dirname(current);
|
|
2037
|
+
if (parent === current) return null;
|
|
2038
|
+
current = parent;
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
function buildRepoPromptEntry(executablePath) {
|
|
2042
|
+
return {
|
|
2043
|
+
command: executablePath,
|
|
2044
|
+
args: [],
|
|
2045
|
+
lifecycle: "lazy"
|
|
2046
|
+
};
|
|
2047
|
+
}
|
|
2048
|
+
function detectRepoPrompt(summary, cwd = process.cwd()) {
|
|
2049
|
+
for (const source of summary.sources) {
|
|
2050
|
+
if (source.kind !== "shared" || source.serverCount === 0) continue;
|
|
2051
|
+
const config = readValidatedConfig(source.path, `MCP config from ${source.path}`);
|
|
2052
|
+
if (!config) continue;
|
|
2053
|
+
for (const [name, entry] of Object.entries(config.mcpServers)) {
|
|
2054
|
+
if (isRepoPromptServer(name, entry)) {
|
|
2055
|
+
return { configured: true, configuredPath: source.path };
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
const executablePath = REPOPROMPT_BINARY_CANDIDATES.find((candidate) => existsSync3(candidate));
|
|
2060
|
+
if (!executablePath) {
|
|
2061
|
+
return { configured: false };
|
|
2062
|
+
}
|
|
2063
|
+
const projectRoot = findProjectRoot(cwd);
|
|
2064
|
+
const targetPath = projectRoot ? join2(projectRoot, PROJECT_CONFIG_NAME) : GENERIC_GLOBAL_CONFIG_PATH;
|
|
2065
|
+
return {
|
|
2066
|
+
configured: false,
|
|
2067
|
+
executablePath,
|
|
2068
|
+
targetPath,
|
|
2069
|
+
serverName: "repoprompt",
|
|
2070
|
+
entry: buildRepoPromptEntry(executablePath)
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
function previewCompatibilityImports(importKinds, overridePath) {
|
|
2074
|
+
const targetPath = getPiGlobalConfigPath(overridePath);
|
|
2075
|
+
const raw = readRawConfigObject(targetPath);
|
|
2076
|
+
const currentImports = Array.isArray(raw.imports) ? raw.imports.filter((value) => typeof value === "string") : [];
|
|
2077
|
+
const merged = [.../* @__PURE__ */ new Set([...currentImports, ...importKinds])];
|
|
2078
|
+
const nextRaw = { ...raw, imports: merged };
|
|
2079
|
+
setServersObject(nextRaw, getServersObject(nextRaw));
|
|
2080
|
+
return buildConfigWritePreview(targetPath, nextRaw);
|
|
2081
|
+
}
|
|
2082
|
+
function ensureCompatibilityImports(importKinds, overridePath) {
|
|
2083
|
+
const targetPath = getPiGlobalConfigPath(overridePath);
|
|
2084
|
+
const raw = readRawConfigObject(targetPath);
|
|
2085
|
+
const currentImports = Array.isArray(raw.imports) ? raw.imports.filter((value) => typeof value === "string") : [];
|
|
2086
|
+
const merged = [.../* @__PURE__ */ new Set([...currentImports, ...importKinds])];
|
|
2087
|
+
const added = merged.filter((kind) => !currentImports.includes(kind));
|
|
2088
|
+
if (added.length === 0) {
|
|
2089
|
+
return { path: targetPath, added: [] };
|
|
2090
|
+
}
|
|
2091
|
+
raw.imports = merged;
|
|
2092
|
+
const servers = getServersObject(raw);
|
|
2093
|
+
setServersObject(raw, servers);
|
|
2094
|
+
writeRawConfigObject(targetPath, raw);
|
|
2095
|
+
return { path: targetPath, added };
|
|
2096
|
+
}
|
|
2097
|
+
function buildStarterProjectConfig() {
|
|
2098
|
+
return {
|
|
2099
|
+
mcpServers: {}
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
2102
|
+
function previewStarterSharedConfig(target, cwd = process.cwd()) {
|
|
2103
|
+
const targetPath = getSharedConfigPath(target, cwd);
|
|
2104
|
+
const nextRaw = { mcpServers: buildStarterProjectConfig().mcpServers };
|
|
2105
|
+
return buildConfigWritePreview(targetPath, nextRaw);
|
|
2106
|
+
}
|
|
2107
|
+
function writeStarterSharedConfig(target, cwd = process.cwd()) {
|
|
2108
|
+
const targetPath = getSharedConfigPath(target, cwd);
|
|
2109
|
+
const raw = { mcpServers: buildStarterProjectConfig().mcpServers };
|
|
2110
|
+
writeRawConfigObject(targetPath, raw);
|
|
2111
|
+
return targetPath;
|
|
2112
|
+
}
|
|
2113
|
+
function previewSharedServerEntry(filePath, serverName, entry) {
|
|
2114
|
+
const raw = readRawConfigObject(filePath);
|
|
2115
|
+
const nextRaw = { ...raw };
|
|
2116
|
+
const servers = getServersObject(nextRaw);
|
|
2117
|
+
servers[serverName] = entry;
|
|
2118
|
+
setServersObject(nextRaw, servers);
|
|
2119
|
+
return buildConfigWritePreview(filePath, nextRaw);
|
|
2120
|
+
}
|
|
2121
|
+
function writeSharedServerEntry(filePath, serverName, entry) {
|
|
2122
|
+
const raw = readRawConfigObject(filePath);
|
|
2123
|
+
const servers = getServersObject(raw);
|
|
2124
|
+
servers[serverName] = entry;
|
|
2125
|
+
setServersObject(raw, servers);
|
|
2126
|
+
writeRawConfigObject(filePath, raw);
|
|
2127
|
+
return filePath;
|
|
2128
|
+
}
|
|
2129
|
+
function getServerProvenance(overridePath, cwd = process.cwd()) {
|
|
2130
|
+
const provenance = /* @__PURE__ */ new Map();
|
|
2131
|
+
const userPath = getPiGlobalConfigPath(overridePath);
|
|
2132
|
+
if (getConfiguredHostConfigDiscovery(overridePath, cwd) === "on") {
|
|
2133
|
+
for (const importKind of Object.keys(IMPORT_PATHS)) {
|
|
2134
|
+
const imported = loadImportedConfig(importKind, cwd, `Failed to inspect imported MCP config from ${importKind}:`);
|
|
2135
|
+
if (!imported) continue;
|
|
2136
|
+
for (const name of Object.keys(extractServers(imported.value, importKind))) {
|
|
2137
|
+
provenance.set(name, { path: userPath, kind: "import", importKind });
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
for (const source of getConfigSources(overridePath, cwd)) {
|
|
2142
|
+
const loaded = readValidatedConfig(source.readPath, `MCP config from ${source.readPath}`);
|
|
2143
|
+
if (!loaded) continue;
|
|
2144
|
+
if (loaded.imports?.length) {
|
|
2145
|
+
for (const importKind of loaded.imports) {
|
|
2146
|
+
const imported = loadImportedConfig(importKind, cwd, `Failed to inspect imported MCP config from ${importKind}:`);
|
|
2147
|
+
if (!imported) continue;
|
|
2148
|
+
const servers = extractServers(imported.value, importKind);
|
|
2149
|
+
for (const name of Object.keys(servers)) {
|
|
2150
|
+
if (!provenance.has(name)) {
|
|
2151
|
+
provenance.set(name, { path: userPath, kind: "import", importKind });
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
for (const name of Object.keys(loaded.mcpServers)) {
|
|
2157
|
+
provenance.set(name, {
|
|
2158
|
+
path: source.writePath,
|
|
2159
|
+
kind: source.kind,
|
|
2160
|
+
...source.importKind !== void 0 ? { importKind: source.importKind } : {}
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
return provenance;
|
|
2165
|
+
}
|
|
2166
|
+
function writeDirectToolsConfig(changes, provenance, fullConfig) {
|
|
2167
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
2168
|
+
for (const [serverName, value] of changes) {
|
|
2169
|
+
const prov = provenance.get(serverName);
|
|
2170
|
+
if (!prov) continue;
|
|
2171
|
+
const targetPath = prov.path;
|
|
2172
|
+
if (!byPath.has(targetPath)) byPath.set(targetPath, []);
|
|
2173
|
+
byPath.get(targetPath).push({ name: serverName, value, prov });
|
|
2174
|
+
}
|
|
2175
|
+
for (const [filePath, entries] of byPath) {
|
|
2176
|
+
const raw = readRawConfigObject(filePath);
|
|
2177
|
+
const servers = getServersObject(raw);
|
|
2178
|
+
for (const { name, value, prov } of entries) {
|
|
2179
|
+
if (prov.kind === "import") {
|
|
2180
|
+
const fullDef = fullConfig.mcpServers[name];
|
|
2181
|
+
if (fullDef) {
|
|
2182
|
+
servers[name] = { ...fullDef, directTools: value };
|
|
2183
|
+
}
|
|
2184
|
+
} else if (servers[name]) {
|
|
2185
|
+
servers[name] = { ...servers[name], directTools: value };
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
setServersObject(raw, servers);
|
|
2189
|
+
writeRawConfigObject(filePath, raw);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
function resolveConfiguredOAuthDir(raw, cwd = process.cwd()) {
|
|
2193
|
+
if (raw === void 0 || raw === null) return void 0;
|
|
2194
|
+
if (typeof raw !== "string") {
|
|
2195
|
+
throw new Error("settings.oauthDir must be a string");
|
|
2196
|
+
}
|
|
2197
|
+
const trimmed = raw.trim();
|
|
2198
|
+
if (!trimmed) return void 0;
|
|
2199
|
+
return resolve3(cwd, trimmed);
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
export {
|
|
2203
|
+
KNOWN_SERVER_PRESETS,
|
|
2204
|
+
getSharedConfigPath,
|
|
2205
|
+
getMcpStandardConfigSummary,
|
|
2206
|
+
getMcpDiscoverySummary,
|
|
2207
|
+
cloneMcpConfig,
|
|
2208
|
+
loadMcpConfig,
|
|
2209
|
+
writeProjectServerDisabledOverride,
|
|
2210
|
+
previewCompatibilityImports,
|
|
2211
|
+
ensureCompatibilityImports,
|
|
2212
|
+
previewStarterSharedConfig,
|
|
2213
|
+
writeStarterSharedConfig,
|
|
2214
|
+
previewSharedServerEntry,
|
|
2215
|
+
writeSharedServerEntry,
|
|
2216
|
+
getServerProvenance,
|
|
2217
|
+
writeDirectToolsConfig,
|
|
2218
|
+
resolveConfiguredOAuthDir
|
|
2219
|
+
};
|
|
2220
|
+
/*! Bundled license information:
|
|
2221
|
+
|
|
2222
|
+
smol-toml/dist/date.js:
|
|
2223
|
+
smol-toml/dist/error.js:
|
|
2224
|
+
smol-toml/dist/primitive.js:
|
|
2225
|
+
smol-toml/dist/util.js:
|
|
2226
|
+
smol-toml/dist/extract.js:
|
|
2227
|
+
smol-toml/dist/struct.js:
|
|
2228
|
+
smol-toml/dist/parse.js:
|
|
2229
|
+
smol-toml/dist/stringify.js:
|
|
2230
|
+
smol-toml/dist/index.js:
|
|
2231
|
+
(*!
|
|
2232
|
+
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
2233
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
2234
|
+
*
|
|
2235
|
+
* Redistribution and use in source and binary forms, with or without
|
|
2236
|
+
* modification, are permitted provided that the following conditions are met:
|
|
2237
|
+
*
|
|
2238
|
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
2239
|
+
* list of conditions and the following disclaimer.
|
|
2240
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
2241
|
+
* this list of conditions and the following disclaimer in the
|
|
2242
|
+
* documentation and/or other materials provided with the distribution.
|
|
2243
|
+
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
2244
|
+
* may be used to endorse or promote products derived from this software without
|
|
2245
|
+
* specific prior written permission.
|
|
2246
|
+
*
|
|
2247
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
2248
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
2249
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
2250
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
2251
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
2252
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
2253
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
2254
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
2255
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
2256
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
2257
|
+
*)
|
|
2258
|
+
*/
|