deepseek-web-retrieval 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +187 -1
  2. package/README.md +13 -9
  3. package/dist/cli.js +4228 -178
  4. package/docs/adr/0001-refuse-drift-between-plan-and-apply.md +29 -0
  5. package/docs/agents/codex.md +193 -0
  6. package/docs/agents/domain.md +51 -0
  7. package/docs/agents/issue-tracker.md +45 -0
  8. package/docs/{opencode-v2.md → agents/opencode-v2.md} +30 -7
  9. package/docs/{pi.md → agents/pi.md} +35 -7
  10. package/docs/agents/triage-labels.md +15 -0
  11. package/docs/design/installer-design.md +184 -0
  12. package/docs/hosts.jsonc +59 -33
  13. package/docs/integration.md +45 -52
  14. package/docs/research/control-matrix.md +257 -0
  15. package/docs/{mcp-compatibility.md → research/mcp-compatibility.md} +39 -108
  16. package/package.json +5 -3
  17. package/src/core/auth.ts +1 -1
  18. package/src/core/client.ts +42 -249
  19. package/src/core/constants.ts +5 -0
  20. package/src/core/descriptions.ts +19 -0
  21. package/src/core/format.ts +31 -1
  22. package/src/core/jsonc.ts +16 -0
  23. package/src/core/options.ts +2 -3
  24. package/src/core/search.ts +5 -7
  25. package/src/core/transport.ts +253 -0
  26. package/src/core/types.ts +13 -11
  27. package/src/installer/apply.ts +176 -0
  28. package/src/installer/cli.ts +215 -0
  29. package/src/installer/detect.ts +85 -0
  30. package/src/installer/formats/index.ts +58 -0
  31. package/src/installer/formats/json.ts +151 -0
  32. package/src/installer/formats/rules.ts +62 -0
  33. package/src/installer/formats/toml.ts +163 -0
  34. package/src/installer/formats/value.ts +57 -0
  35. package/src/installer/hosts/codex.ts +128 -0
  36. package/src/installer/hosts/index.ts +134 -0
  37. package/src/installer/hosts/opencode.ts +118 -0
  38. package/src/installer/hosts/pi.ts +115 -0
  39. package/src/installer/hosts/shared.ts +31 -0
  40. package/src/installer/paths.ts +18 -0
  41. package/src/installer/render.ts +62 -0
  42. package/src/installer/revert.ts +61 -0
  43. package/src/installer/rulesContent.ts +32 -0
  44. package/src/installer/state.ts +63 -0
  45. package/src/installer/types.ts +126 -0
  46. package/src/installer/uninstall.ts +33 -0
  47. package/src/mcp/auth.ts +2 -1
  48. package/src/mcp/cli.ts +21 -5
  49. package/src/mcp/config.ts +70 -27
  50. package/src/mcp/server.ts +81 -65
  51. package/src/opencode/auth.ts +3 -2
  52. package/src/opencode/plugin.ts +93 -56
  53. package/src/mcp/format.ts +0 -31
package/dist/cli.js CHANGED
@@ -1,17 +1,3998 @@
1
1
  #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
+
18
+ // src/core/constants.ts
19
+ var SEARCH_ENDPOINT = "https://api.deepseek.com/v1/tools/search", FETCH_ENDPOINT = "https://api.deepseek.com/v1/tools/fetch", DEFAULT_SEARCH_COUNT = 10, DEFAULT_MAX_RESULTS = 5, DEFAULT_MIN_RERANK = 1.5, DEFAULT_MIN_AUTHORITY = 2, DEFAULT_MAX_SUMMARY_CHARS = 1200, DEFAULT_FETCH_MAX_CHARS = 16000, DEFAULT_TIMEOUT_MS = 30000, MIN_TIMEOUT_MS = 1000, MAX_TIMEOUT_MS = 120000, MAX_QUERY_CHARS = 128, MAX_URL_CHARS = 8192, MAX_ERROR_BODY_CHARS = 2000, MAX_RESPONSE_BYTES, FETCH_TRUNCATION_MARKER = `
20
+
21
+ [content truncated]`, DEFAULT_API_KEY_SOURCE = "auto", DEFAULT_MAX_RETRIES = 0, MAX_RETRIES = 5, DEFAULT_RETRY_BASE_DELAY_MS = 250, MAX_RETRY_DELAY_MS = 1e4, API_KEY_ENV = "DEEPSEEK_API_KEY", ENABLE_SEARCH_ENV = "DEEPSEEK_ENABLE_SEARCH", ENABLE_FETCH_ENV = "DEEPSEEK_ENABLE_FETCH";
22
+ var init_constants = __esm(() => {
23
+ MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
24
+ });
25
+
26
+ // node_modules/jsonc-parser/lib/esm/impl/scanner.js
27
+ function createScanner(text, ignoreTrivia = false) {
28
+ const len = text.length;
29
+ let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
30
+ function scanHexDigits(count, exact) {
31
+ let digits = 0;
32
+ let value2 = 0;
33
+ while (digits < count || !exact) {
34
+ let ch = text.charCodeAt(pos);
35
+ if (ch >= 48 && ch <= 57) {
36
+ value2 = value2 * 16 + ch - 48;
37
+ } else if (ch >= 65 && ch <= 70) {
38
+ value2 = value2 * 16 + ch - 65 + 10;
39
+ } else if (ch >= 97 && ch <= 102) {
40
+ value2 = value2 * 16 + ch - 97 + 10;
41
+ } else {
42
+ break;
43
+ }
44
+ pos++;
45
+ digits++;
46
+ }
47
+ if (digits < count) {
48
+ value2 = -1;
49
+ }
50
+ return value2;
51
+ }
52
+ function setPosition(newPosition) {
53
+ pos = newPosition;
54
+ value = "";
55
+ tokenOffset = 0;
56
+ token = 16;
57
+ scanError = 0;
58
+ }
59
+ function scanNumber() {
60
+ let start = pos;
61
+ if (text.charCodeAt(pos) === 48) {
62
+ pos++;
63
+ } else {
64
+ pos++;
65
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
66
+ pos++;
67
+ }
68
+ }
69
+ if (pos < text.length && text.charCodeAt(pos) === 46) {
70
+ pos++;
71
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
72
+ pos++;
73
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
74
+ pos++;
75
+ }
76
+ } else {
77
+ scanError = 3;
78
+ return text.substring(start, pos);
79
+ }
80
+ }
81
+ let end = pos;
82
+ if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
83
+ pos++;
84
+ if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
85
+ pos++;
86
+ }
87
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
88
+ pos++;
89
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
90
+ pos++;
91
+ }
92
+ end = pos;
93
+ } else {
94
+ scanError = 3;
95
+ }
96
+ }
97
+ return text.substring(start, end);
98
+ }
99
+ function scanString() {
100
+ let result = "", start = pos;
101
+ while (true) {
102
+ if (pos >= len) {
103
+ result += text.substring(start, pos);
104
+ scanError = 2;
105
+ break;
106
+ }
107
+ const ch = text.charCodeAt(pos);
108
+ if (ch === 34) {
109
+ result += text.substring(start, pos);
110
+ pos++;
111
+ break;
112
+ }
113
+ if (ch === 92) {
114
+ result += text.substring(start, pos);
115
+ pos++;
116
+ if (pos >= len) {
117
+ scanError = 2;
118
+ break;
119
+ }
120
+ const ch2 = text.charCodeAt(pos++);
121
+ switch (ch2) {
122
+ case 34:
123
+ result += '"';
124
+ break;
125
+ case 92:
126
+ result += "\\";
127
+ break;
128
+ case 47:
129
+ result += "/";
130
+ break;
131
+ case 98:
132
+ result += "\b";
133
+ break;
134
+ case 102:
135
+ result += "\f";
136
+ break;
137
+ case 110:
138
+ result += `
139
+ `;
140
+ break;
141
+ case 114:
142
+ result += "\r";
143
+ break;
144
+ case 116:
145
+ result += "\t";
146
+ break;
147
+ case 117:
148
+ const ch3 = scanHexDigits(4, true);
149
+ if (ch3 >= 0) {
150
+ result += String.fromCharCode(ch3);
151
+ } else {
152
+ scanError = 4;
153
+ }
154
+ break;
155
+ default:
156
+ scanError = 5;
157
+ }
158
+ start = pos;
159
+ continue;
160
+ }
161
+ if (ch >= 0 && ch <= 31) {
162
+ if (isLineBreak(ch)) {
163
+ result += text.substring(start, pos);
164
+ scanError = 2;
165
+ break;
166
+ } else {
167
+ scanError = 6;
168
+ }
169
+ }
170
+ pos++;
171
+ }
172
+ return result;
173
+ }
174
+ function scanNext() {
175
+ value = "";
176
+ scanError = 0;
177
+ tokenOffset = pos;
178
+ lineStartOffset = lineNumber;
179
+ prevTokenLineStartOffset = tokenLineStartOffset;
180
+ if (pos >= len) {
181
+ tokenOffset = len;
182
+ return token = 17;
183
+ }
184
+ let code = text.charCodeAt(pos);
185
+ if (isWhiteSpace(code)) {
186
+ do {
187
+ pos++;
188
+ value += String.fromCharCode(code);
189
+ code = text.charCodeAt(pos);
190
+ } while (isWhiteSpace(code));
191
+ return token = 15;
192
+ }
193
+ if (isLineBreak(code)) {
194
+ pos++;
195
+ value += String.fromCharCode(code);
196
+ if (code === 13 && text.charCodeAt(pos) === 10) {
197
+ pos++;
198
+ value += `
199
+ `;
200
+ }
201
+ lineNumber++;
202
+ tokenLineStartOffset = pos;
203
+ return token = 14;
204
+ }
205
+ switch (code) {
206
+ case 123:
207
+ pos++;
208
+ return token = 1;
209
+ case 125:
210
+ pos++;
211
+ return token = 2;
212
+ case 91:
213
+ pos++;
214
+ return token = 3;
215
+ case 93:
216
+ pos++;
217
+ return token = 4;
218
+ case 58:
219
+ pos++;
220
+ return token = 6;
221
+ case 44:
222
+ pos++;
223
+ return token = 5;
224
+ case 34:
225
+ pos++;
226
+ value = scanString();
227
+ return token = 10;
228
+ case 47:
229
+ const start = pos - 1;
230
+ if (text.charCodeAt(pos + 1) === 47) {
231
+ pos += 2;
232
+ while (pos < len) {
233
+ if (isLineBreak(text.charCodeAt(pos))) {
234
+ break;
235
+ }
236
+ pos++;
237
+ }
238
+ value = text.substring(start, pos);
239
+ return token = 12;
240
+ }
241
+ if (text.charCodeAt(pos + 1) === 42) {
242
+ pos += 2;
243
+ const safeLength = len - 1;
244
+ let commentClosed = false;
245
+ while (pos < safeLength) {
246
+ const ch = text.charCodeAt(pos);
247
+ if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
248
+ pos += 2;
249
+ commentClosed = true;
250
+ break;
251
+ }
252
+ pos++;
253
+ if (isLineBreak(ch)) {
254
+ if (ch === 13 && text.charCodeAt(pos) === 10) {
255
+ pos++;
256
+ }
257
+ lineNumber++;
258
+ tokenLineStartOffset = pos;
259
+ }
260
+ }
261
+ if (!commentClosed) {
262
+ pos++;
263
+ scanError = 1;
264
+ }
265
+ value = text.substring(start, pos);
266
+ return token = 13;
267
+ }
268
+ value += String.fromCharCode(code);
269
+ pos++;
270
+ return token = 16;
271
+ case 45:
272
+ value += String.fromCharCode(code);
273
+ pos++;
274
+ if (pos === len || !isDigit(text.charCodeAt(pos))) {
275
+ return token = 16;
276
+ }
277
+ case 48:
278
+ case 49:
279
+ case 50:
280
+ case 51:
281
+ case 52:
282
+ case 53:
283
+ case 54:
284
+ case 55:
285
+ case 56:
286
+ case 57:
287
+ value += scanNumber();
288
+ return token = 11;
289
+ default:
290
+ while (pos < len && isUnknownContentCharacter(code)) {
291
+ pos++;
292
+ code = text.charCodeAt(pos);
293
+ }
294
+ if (tokenOffset !== pos) {
295
+ value = text.substring(tokenOffset, pos);
296
+ switch (value) {
297
+ case "true":
298
+ return token = 8;
299
+ case "false":
300
+ return token = 9;
301
+ case "null":
302
+ return token = 7;
303
+ }
304
+ return token = 16;
305
+ }
306
+ value += String.fromCharCode(code);
307
+ pos++;
308
+ return token = 16;
309
+ }
310
+ }
311
+ function isUnknownContentCharacter(code) {
312
+ if (isWhiteSpace(code) || isLineBreak(code)) {
313
+ return false;
314
+ }
315
+ switch (code) {
316
+ case 125:
317
+ case 93:
318
+ case 123:
319
+ case 91:
320
+ case 34:
321
+ case 58:
322
+ case 44:
323
+ case 47:
324
+ return false;
325
+ }
326
+ return true;
327
+ }
328
+ function scanNextNonTrivia() {
329
+ let result;
330
+ do {
331
+ result = scanNext();
332
+ } while (result >= 12 && result <= 15);
333
+ return result;
334
+ }
335
+ return {
336
+ setPosition,
337
+ getPosition: () => pos,
338
+ scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
339
+ getToken: () => token,
340
+ getTokenValue: () => value,
341
+ getTokenOffset: () => tokenOffset,
342
+ getTokenLength: () => pos - tokenOffset,
343
+ getTokenStartLine: () => lineStartOffset,
344
+ getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
345
+ getTokenError: () => scanError
346
+ };
347
+ }
348
+ function isWhiteSpace(ch) {
349
+ return ch === 32 || ch === 9;
350
+ }
351
+ function isLineBreak(ch) {
352
+ return ch === 10 || ch === 13;
353
+ }
354
+ function isDigit(ch) {
355
+ return ch >= 48 && ch <= 57;
356
+ }
357
+ var CharacterCodes;
358
+ var init_scanner = __esm(() => {
359
+ (function(CharacterCodes2) {
360
+ CharacterCodes2[CharacterCodes2["lineFeed"] = 10] = "lineFeed";
361
+ CharacterCodes2[CharacterCodes2["carriageReturn"] = 13] = "carriageReturn";
362
+ CharacterCodes2[CharacterCodes2["space"] = 32] = "space";
363
+ CharacterCodes2[CharacterCodes2["_0"] = 48] = "_0";
364
+ CharacterCodes2[CharacterCodes2["_1"] = 49] = "_1";
365
+ CharacterCodes2[CharacterCodes2["_2"] = 50] = "_2";
366
+ CharacterCodes2[CharacterCodes2["_3"] = 51] = "_3";
367
+ CharacterCodes2[CharacterCodes2["_4"] = 52] = "_4";
368
+ CharacterCodes2[CharacterCodes2["_5"] = 53] = "_5";
369
+ CharacterCodes2[CharacterCodes2["_6"] = 54] = "_6";
370
+ CharacterCodes2[CharacterCodes2["_7"] = 55] = "_7";
371
+ CharacterCodes2[CharacterCodes2["_8"] = 56] = "_8";
372
+ CharacterCodes2[CharacterCodes2["_9"] = 57] = "_9";
373
+ CharacterCodes2[CharacterCodes2["a"] = 97] = "a";
374
+ CharacterCodes2[CharacterCodes2["b"] = 98] = "b";
375
+ CharacterCodes2[CharacterCodes2["c"] = 99] = "c";
376
+ CharacterCodes2[CharacterCodes2["d"] = 100] = "d";
377
+ CharacterCodes2[CharacterCodes2["e"] = 101] = "e";
378
+ CharacterCodes2[CharacterCodes2["f"] = 102] = "f";
379
+ CharacterCodes2[CharacterCodes2["g"] = 103] = "g";
380
+ CharacterCodes2[CharacterCodes2["h"] = 104] = "h";
381
+ CharacterCodes2[CharacterCodes2["i"] = 105] = "i";
382
+ CharacterCodes2[CharacterCodes2["j"] = 106] = "j";
383
+ CharacterCodes2[CharacterCodes2["k"] = 107] = "k";
384
+ CharacterCodes2[CharacterCodes2["l"] = 108] = "l";
385
+ CharacterCodes2[CharacterCodes2["m"] = 109] = "m";
386
+ CharacterCodes2[CharacterCodes2["n"] = 110] = "n";
387
+ CharacterCodes2[CharacterCodes2["o"] = 111] = "o";
388
+ CharacterCodes2[CharacterCodes2["p"] = 112] = "p";
389
+ CharacterCodes2[CharacterCodes2["q"] = 113] = "q";
390
+ CharacterCodes2[CharacterCodes2["r"] = 114] = "r";
391
+ CharacterCodes2[CharacterCodes2["s"] = 115] = "s";
392
+ CharacterCodes2[CharacterCodes2["t"] = 116] = "t";
393
+ CharacterCodes2[CharacterCodes2["u"] = 117] = "u";
394
+ CharacterCodes2[CharacterCodes2["v"] = 118] = "v";
395
+ CharacterCodes2[CharacterCodes2["w"] = 119] = "w";
396
+ CharacterCodes2[CharacterCodes2["x"] = 120] = "x";
397
+ CharacterCodes2[CharacterCodes2["y"] = 121] = "y";
398
+ CharacterCodes2[CharacterCodes2["z"] = 122] = "z";
399
+ CharacterCodes2[CharacterCodes2["A"] = 65] = "A";
400
+ CharacterCodes2[CharacterCodes2["B"] = 66] = "B";
401
+ CharacterCodes2[CharacterCodes2["C"] = 67] = "C";
402
+ CharacterCodes2[CharacterCodes2["D"] = 68] = "D";
403
+ CharacterCodes2[CharacterCodes2["E"] = 69] = "E";
404
+ CharacterCodes2[CharacterCodes2["F"] = 70] = "F";
405
+ CharacterCodes2[CharacterCodes2["G"] = 71] = "G";
406
+ CharacterCodes2[CharacterCodes2["H"] = 72] = "H";
407
+ CharacterCodes2[CharacterCodes2["I"] = 73] = "I";
408
+ CharacterCodes2[CharacterCodes2["J"] = 74] = "J";
409
+ CharacterCodes2[CharacterCodes2["K"] = 75] = "K";
410
+ CharacterCodes2[CharacterCodes2["L"] = 76] = "L";
411
+ CharacterCodes2[CharacterCodes2["M"] = 77] = "M";
412
+ CharacterCodes2[CharacterCodes2["N"] = 78] = "N";
413
+ CharacterCodes2[CharacterCodes2["O"] = 79] = "O";
414
+ CharacterCodes2[CharacterCodes2["P"] = 80] = "P";
415
+ CharacterCodes2[CharacterCodes2["Q"] = 81] = "Q";
416
+ CharacterCodes2[CharacterCodes2["R"] = 82] = "R";
417
+ CharacterCodes2[CharacterCodes2["S"] = 83] = "S";
418
+ CharacterCodes2[CharacterCodes2["T"] = 84] = "T";
419
+ CharacterCodes2[CharacterCodes2["U"] = 85] = "U";
420
+ CharacterCodes2[CharacterCodes2["V"] = 86] = "V";
421
+ CharacterCodes2[CharacterCodes2["W"] = 87] = "W";
422
+ CharacterCodes2[CharacterCodes2["X"] = 88] = "X";
423
+ CharacterCodes2[CharacterCodes2["Y"] = 89] = "Y";
424
+ CharacterCodes2[CharacterCodes2["Z"] = 90] = "Z";
425
+ CharacterCodes2[CharacterCodes2["asterisk"] = 42] = "asterisk";
426
+ CharacterCodes2[CharacterCodes2["backslash"] = 92] = "backslash";
427
+ CharacterCodes2[CharacterCodes2["closeBrace"] = 125] = "closeBrace";
428
+ CharacterCodes2[CharacterCodes2["closeBracket"] = 93] = "closeBracket";
429
+ CharacterCodes2[CharacterCodes2["colon"] = 58] = "colon";
430
+ CharacterCodes2[CharacterCodes2["comma"] = 44] = "comma";
431
+ CharacterCodes2[CharacterCodes2["dot"] = 46] = "dot";
432
+ CharacterCodes2[CharacterCodes2["doubleQuote"] = 34] = "doubleQuote";
433
+ CharacterCodes2[CharacterCodes2["minus"] = 45] = "minus";
434
+ CharacterCodes2[CharacterCodes2["openBrace"] = 123] = "openBrace";
435
+ CharacterCodes2[CharacterCodes2["openBracket"] = 91] = "openBracket";
436
+ CharacterCodes2[CharacterCodes2["plus"] = 43] = "plus";
437
+ CharacterCodes2[CharacterCodes2["slash"] = 47] = "slash";
438
+ CharacterCodes2[CharacterCodes2["formFeed"] = 12] = "formFeed";
439
+ CharacterCodes2[CharacterCodes2["tab"] = 9] = "tab";
440
+ })(CharacterCodes || (CharacterCodes = {}));
441
+ });
442
+
443
+ // node_modules/jsonc-parser/lib/esm/impl/string-intern.js
444
+ var cachedSpaces, maxCachedValues = 200, cachedBreakLinesWithSpaces, supportedEols;
445
+ var init_string_intern = __esm(() => {
446
+ cachedSpaces = new Array(20).fill(0).map((_, index) => {
447
+ return " ".repeat(index);
448
+ });
449
+ cachedBreakLinesWithSpaces = {
450
+ " ": {
451
+ "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
452
+ return `
453
+ ` + " ".repeat(index);
454
+ }),
455
+ "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
456
+ return "\r" + " ".repeat(index);
457
+ }),
458
+ "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
459
+ return `\r
460
+ ` + " ".repeat(index);
461
+ })
462
+ },
463
+ "\t": {
464
+ "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
465
+ return `
466
+ ` + "\t".repeat(index);
467
+ }),
468
+ "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
469
+ return "\r" + "\t".repeat(index);
470
+ }),
471
+ "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
472
+ return `\r
473
+ ` + "\t".repeat(index);
474
+ })
475
+ }
476
+ };
477
+ supportedEols = [`
478
+ `, "\r", `\r
479
+ `];
480
+ });
481
+
482
+ // node_modules/jsonc-parser/lib/esm/impl/format.js
483
+ function format(documentText, range, options) {
484
+ let initialIndentLevel;
485
+ let formatText;
486
+ let formatTextStart;
487
+ let rangeStart;
488
+ let rangeEnd;
489
+ if (range) {
490
+ rangeStart = range.offset;
491
+ rangeEnd = rangeStart + range.length;
492
+ formatTextStart = rangeStart;
493
+ while (formatTextStart > 0 && !isEOL(documentText, formatTextStart - 1)) {
494
+ formatTextStart--;
495
+ }
496
+ let endOffset = rangeEnd;
497
+ while (endOffset < documentText.length && !isEOL(documentText, endOffset)) {
498
+ endOffset++;
499
+ }
500
+ formatText = documentText.substring(formatTextStart, endOffset);
501
+ initialIndentLevel = computeIndentLevel(formatText, options);
502
+ } else {
503
+ formatText = documentText;
504
+ initialIndentLevel = 0;
505
+ formatTextStart = 0;
506
+ rangeStart = 0;
507
+ rangeEnd = documentText.length;
508
+ }
509
+ const eol = getEOL(options, documentText);
510
+ const eolFastPathSupported = supportedEols.includes(eol);
511
+ let numberLineBreaks = 0;
512
+ let indentLevel = 0;
513
+ let indentValue;
514
+ if (options.insertSpaces) {
515
+ indentValue = cachedSpaces[options.tabSize || 4] ?? repeat(cachedSpaces[1], options.tabSize || 4);
516
+ } else {
517
+ indentValue = "\t";
518
+ }
519
+ const indentType = indentValue === "\t" ? "\t" : " ";
520
+ let scanner = createScanner(formatText, false);
521
+ let hasError = false;
522
+ function newLinesAndIndent() {
523
+ if (numberLineBreaks > 1) {
524
+ return repeat(eol, numberLineBreaks) + repeat(indentValue, initialIndentLevel + indentLevel);
525
+ }
526
+ const amountOfSpaces = indentValue.length * (initialIndentLevel + indentLevel);
527
+ if (!eolFastPathSupported || amountOfSpaces > cachedBreakLinesWithSpaces[indentType][eol].length) {
528
+ return eol + repeat(indentValue, initialIndentLevel + indentLevel);
529
+ }
530
+ if (amountOfSpaces <= 0) {
531
+ return eol;
532
+ }
533
+ return cachedBreakLinesWithSpaces[indentType][eol][amountOfSpaces];
534
+ }
535
+ function scanNext() {
536
+ let token = scanner.scan();
537
+ numberLineBreaks = 0;
538
+ while (token === 15 || token === 14) {
539
+ if (token === 14 && options.keepLines) {
540
+ numberLineBreaks += 1;
541
+ } else if (token === 14) {
542
+ numberLineBreaks = 1;
543
+ }
544
+ token = scanner.scan();
545
+ }
546
+ hasError = token === 16 || scanner.getTokenError() !== 0;
547
+ return token;
548
+ }
549
+ const editOperations = [];
550
+ function addEdit(text, startOffset, endOffset) {
551
+ if (!hasError && (!range || startOffset < rangeEnd && endOffset > rangeStart) && documentText.substring(startOffset, endOffset) !== text) {
552
+ editOperations.push({ offset: startOffset, length: endOffset - startOffset, content: text });
553
+ }
554
+ }
555
+ let firstToken = scanNext();
556
+ if (options.keepLines && numberLineBreaks > 0) {
557
+ addEdit(repeat(eol, numberLineBreaks), 0, 0);
558
+ }
559
+ if (firstToken !== 17) {
560
+ let firstTokenStart = scanner.getTokenOffset() + formatTextStart;
561
+ let initialIndent = indentValue.length * initialIndentLevel < 20 && options.insertSpaces ? cachedSpaces[indentValue.length * initialIndentLevel] : repeat(indentValue, initialIndentLevel);
562
+ addEdit(initialIndent, formatTextStart, firstTokenStart);
563
+ }
564
+ while (firstToken !== 17) {
565
+ let firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
566
+ let secondToken = scanNext();
567
+ let replaceContent = "";
568
+ let needsLineBreak = false;
569
+ while (numberLineBreaks === 0 && (secondToken === 12 || secondToken === 13)) {
570
+ let commentTokenStart = scanner.getTokenOffset() + formatTextStart;
571
+ addEdit(cachedSpaces[1], firstTokenEnd, commentTokenStart);
572
+ firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
573
+ needsLineBreak = secondToken === 12;
574
+ replaceContent = needsLineBreak ? newLinesAndIndent() : "";
575
+ secondToken = scanNext();
576
+ }
577
+ if (secondToken === 2) {
578
+ if (firstToken !== 1) {
579
+ indentLevel--;
580
+ }
581
+ if (options.keepLines && numberLineBreaks > 0 || !options.keepLines && firstToken !== 1) {
582
+ replaceContent = newLinesAndIndent();
583
+ } else if (options.keepLines) {
584
+ replaceContent = cachedSpaces[1];
585
+ }
586
+ } else if (secondToken === 4) {
587
+ if (firstToken !== 3) {
588
+ indentLevel--;
589
+ }
590
+ if (options.keepLines && numberLineBreaks > 0 || !options.keepLines && firstToken !== 3) {
591
+ replaceContent = newLinesAndIndent();
592
+ } else if (options.keepLines) {
593
+ replaceContent = cachedSpaces[1];
594
+ }
595
+ } else {
596
+ switch (firstToken) {
597
+ case 3:
598
+ case 1:
599
+ indentLevel++;
600
+ if (options.keepLines && numberLineBreaks > 0 || !options.keepLines) {
601
+ replaceContent = newLinesAndIndent();
602
+ } else {
603
+ replaceContent = cachedSpaces[1];
604
+ }
605
+ break;
606
+ case 5:
607
+ if (options.keepLines && numberLineBreaks > 0 || !options.keepLines) {
608
+ replaceContent = newLinesAndIndent();
609
+ } else {
610
+ replaceContent = cachedSpaces[1];
611
+ }
612
+ break;
613
+ case 12:
614
+ replaceContent = newLinesAndIndent();
615
+ break;
616
+ case 13:
617
+ if (numberLineBreaks > 0) {
618
+ replaceContent = newLinesAndIndent();
619
+ } else if (!needsLineBreak) {
620
+ replaceContent = cachedSpaces[1];
621
+ }
622
+ break;
623
+ case 6:
624
+ if (options.keepLines && numberLineBreaks > 0) {
625
+ replaceContent = newLinesAndIndent();
626
+ } else if (!needsLineBreak) {
627
+ replaceContent = cachedSpaces[1];
628
+ }
629
+ break;
630
+ case 10:
631
+ if (options.keepLines && numberLineBreaks > 0) {
632
+ replaceContent = newLinesAndIndent();
633
+ } else if (secondToken === 6 && !needsLineBreak) {
634
+ replaceContent = "";
635
+ }
636
+ break;
637
+ case 7:
638
+ case 8:
639
+ case 9:
640
+ case 11:
641
+ case 2:
642
+ case 4:
643
+ if (options.keepLines && numberLineBreaks > 0) {
644
+ replaceContent = newLinesAndIndent();
645
+ } else {
646
+ if ((secondToken === 12 || secondToken === 13) && !needsLineBreak) {
647
+ replaceContent = cachedSpaces[1];
648
+ } else if (secondToken !== 5 && secondToken !== 17) {
649
+ hasError = true;
650
+ }
651
+ }
652
+ break;
653
+ case 16:
654
+ hasError = true;
655
+ break;
656
+ }
657
+ if (numberLineBreaks > 0 && (secondToken === 12 || secondToken === 13)) {
658
+ replaceContent = newLinesAndIndent();
659
+ }
660
+ }
661
+ if (secondToken === 17) {
662
+ if (options.keepLines && numberLineBreaks > 0) {
663
+ replaceContent = newLinesAndIndent();
664
+ } else {
665
+ replaceContent = options.insertFinalNewline ? eol : "";
666
+ }
667
+ }
668
+ const secondTokenStart = scanner.getTokenOffset() + formatTextStart;
669
+ addEdit(replaceContent, firstTokenEnd, secondTokenStart);
670
+ firstToken = secondToken;
671
+ }
672
+ return editOperations;
673
+ }
674
+ function repeat(s, count) {
675
+ let result = "";
676
+ for (let i = 0;i < count; i++) {
677
+ result += s;
678
+ }
679
+ return result;
680
+ }
681
+ function computeIndentLevel(content, options) {
682
+ let i = 0;
683
+ let nChars = 0;
684
+ const tabSize = options.tabSize || 4;
685
+ while (i < content.length) {
686
+ let ch = content.charAt(i);
687
+ if (ch === cachedSpaces[1]) {
688
+ nChars++;
689
+ } else if (ch === "\t") {
690
+ nChars += tabSize;
691
+ } else {
692
+ break;
693
+ }
694
+ i++;
695
+ }
696
+ return Math.floor(nChars / tabSize);
697
+ }
698
+ function getEOL(options, text) {
699
+ for (let i = 0;i < text.length; i++) {
700
+ const ch = text.charAt(i);
701
+ if (ch === "\r") {
702
+ if (i + 1 < text.length && text.charAt(i + 1) === `
703
+ `) {
704
+ return `\r
705
+ `;
706
+ }
707
+ return "\r";
708
+ } else if (ch === `
709
+ `) {
710
+ return `
711
+ `;
712
+ }
713
+ }
714
+ return options && options.eol || `
715
+ `;
716
+ }
717
+ function isEOL(text, offset) {
718
+ return `\r
719
+ `.indexOf(text.charAt(offset)) !== -1;
720
+ }
721
+ var init_format = __esm(() => {
722
+ init_scanner();
723
+ init_string_intern();
724
+ });
725
+
726
+ // node_modules/jsonc-parser/lib/esm/impl/parser.js
727
+ function parse(text, errors = [], options = ParseOptions.DEFAULT) {
728
+ let currentProperty = null;
729
+ let currentParent = [];
730
+ const previousParents = [];
731
+ function onValue(value) {
732
+ if (Array.isArray(currentParent)) {
733
+ currentParent.push(value);
734
+ } else if (currentProperty !== null) {
735
+ currentParent[currentProperty] = value;
736
+ }
737
+ }
738
+ const visitor = {
739
+ onObjectBegin: () => {
740
+ const object2 = {};
741
+ onValue(object2);
742
+ previousParents.push(currentParent);
743
+ currentParent = object2;
744
+ currentProperty = null;
745
+ },
746
+ onObjectProperty: (name) => {
747
+ currentProperty = name;
748
+ },
749
+ onObjectEnd: () => {
750
+ currentParent = previousParents.pop();
751
+ },
752
+ onArrayBegin: () => {
753
+ const array2 = [];
754
+ onValue(array2);
755
+ previousParents.push(currentParent);
756
+ currentParent = array2;
757
+ currentProperty = null;
758
+ },
759
+ onArrayEnd: () => {
760
+ currentParent = previousParents.pop();
761
+ },
762
+ onLiteralValue: onValue,
763
+ onError: (error, offset, length) => {
764
+ errors.push({ error, offset, length });
765
+ }
766
+ };
767
+ visit(text, visitor, options);
768
+ return currentParent[0];
769
+ }
770
+ function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
771
+ let currentParent = { type: "array", offset: -1, length: -1, children: [], parent: undefined };
772
+ function ensurePropertyComplete(endOffset) {
773
+ if (currentParent.type === "property") {
774
+ currentParent.length = endOffset - currentParent.offset;
775
+ currentParent = currentParent.parent;
776
+ }
777
+ }
778
+ function onValue(valueNode) {
779
+ currentParent.children.push(valueNode);
780
+ return valueNode;
781
+ }
782
+ const visitor = {
783
+ onObjectBegin: (offset) => {
784
+ currentParent = onValue({ type: "object", offset, length: -1, parent: currentParent, children: [] });
785
+ },
786
+ onObjectProperty: (name, offset, length) => {
787
+ currentParent = onValue({ type: "property", offset, length: -1, parent: currentParent, children: [] });
788
+ currentParent.children.push({ type: "string", value: name, offset, length, parent: currentParent });
789
+ },
790
+ onObjectEnd: (offset, length) => {
791
+ ensurePropertyComplete(offset + length);
792
+ currentParent.length = offset + length - currentParent.offset;
793
+ currentParent = currentParent.parent;
794
+ ensurePropertyComplete(offset + length);
795
+ },
796
+ onArrayBegin: (offset, length) => {
797
+ currentParent = onValue({ type: "array", offset, length: -1, parent: currentParent, children: [] });
798
+ },
799
+ onArrayEnd: (offset, length) => {
800
+ currentParent.length = offset + length - currentParent.offset;
801
+ currentParent = currentParent.parent;
802
+ ensurePropertyComplete(offset + length);
803
+ },
804
+ onLiteralValue: (value, offset, length) => {
805
+ onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });
806
+ ensurePropertyComplete(offset + length);
807
+ },
808
+ onSeparator: (sep, offset, length) => {
809
+ if (currentParent.type === "property") {
810
+ if (sep === ":") {
811
+ currentParent.colonOffset = offset;
812
+ } else if (sep === ",") {
813
+ ensurePropertyComplete(offset);
814
+ }
815
+ }
816
+ },
817
+ onError: (error, offset, length) => {
818
+ errors.push({ error, offset, length });
819
+ }
820
+ };
821
+ visit(text, visitor, options);
822
+ const result = currentParent.children[0];
823
+ if (result) {
824
+ delete result.parent;
825
+ }
826
+ return result;
827
+ }
828
+ function findNodeAtLocation(root, path) {
829
+ if (!root) {
830
+ return;
831
+ }
832
+ let node = root;
833
+ for (let segment of path) {
834
+ if (typeof segment === "string") {
835
+ if (node.type !== "object" || !Array.isArray(node.children)) {
836
+ return;
837
+ }
838
+ let found = false;
839
+ for (const propertyNode of node.children) {
840
+ if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {
841
+ node = propertyNode.children[1];
842
+ found = true;
843
+ break;
844
+ }
845
+ }
846
+ if (!found) {
847
+ return;
848
+ }
849
+ } else {
850
+ const index = segment;
851
+ if (node.type !== "array" || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {
852
+ return;
853
+ }
854
+ node = node.children[index];
855
+ }
856
+ }
857
+ return node;
858
+ }
859
+ function visit(text, visitor, options = ParseOptions.DEFAULT) {
860
+ const _scanner = createScanner(text, false);
861
+ const _jsonPath = [];
862
+ let suppressedCallbacks = 0;
863
+ function toNoArgVisit(visitFunction) {
864
+ return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
865
+ }
866
+ function toOneArgVisit(visitFunction) {
867
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
868
+ }
869
+ function toOneArgVisitWithPath(visitFunction) {
870
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;
871
+ }
872
+ function toBeginVisit(visitFunction) {
873
+ return visitFunction ? () => {
874
+ if (suppressedCallbacks > 0) {
875
+ suppressedCallbacks++;
876
+ } else {
877
+ let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());
878
+ if (cbReturn === false) {
879
+ suppressedCallbacks = 1;
880
+ }
881
+ }
882
+ } : () => true;
883
+ }
884
+ function toEndVisit(visitFunction) {
885
+ return visitFunction ? () => {
886
+ if (suppressedCallbacks > 0) {
887
+ suppressedCallbacks--;
888
+ }
889
+ if (suppressedCallbacks === 0) {
890
+ visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
891
+ }
892
+ } : () => true;
893
+ }
894
+ const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
895
+ const disallowComments = options && options.disallowComments;
896
+ const allowTrailingComma = options && options.allowTrailingComma;
897
+ function scanNext() {
898
+ while (true) {
899
+ const token = _scanner.scan();
900
+ switch (_scanner.getTokenError()) {
901
+ case 4:
902
+ handleError(14);
903
+ break;
904
+ case 5:
905
+ handleError(15);
906
+ break;
907
+ case 3:
908
+ handleError(13);
909
+ break;
910
+ case 1:
911
+ if (!disallowComments) {
912
+ handleError(11);
913
+ }
914
+ break;
915
+ case 2:
916
+ handleError(12);
917
+ break;
918
+ case 6:
919
+ handleError(16);
920
+ break;
921
+ }
922
+ switch (token) {
923
+ case 12:
924
+ case 13:
925
+ if (disallowComments) {
926
+ handleError(10);
927
+ } else {
928
+ onComment();
929
+ }
930
+ break;
931
+ case 16:
932
+ handleError(1);
933
+ break;
934
+ case 15:
935
+ case 14:
936
+ break;
937
+ default:
938
+ return token;
939
+ }
940
+ }
941
+ }
942
+ function handleError(error, skipUntilAfter = [], skipUntil = []) {
943
+ onError(error);
944
+ if (skipUntilAfter.length + skipUntil.length > 0) {
945
+ let token = _scanner.getToken();
946
+ while (token !== 17) {
947
+ if (skipUntilAfter.indexOf(token) !== -1) {
948
+ scanNext();
949
+ break;
950
+ } else if (skipUntil.indexOf(token) !== -1) {
951
+ break;
952
+ }
953
+ token = scanNext();
954
+ }
955
+ }
956
+ }
957
+ function parseString(isValue) {
958
+ const value = _scanner.getTokenValue();
959
+ if (isValue) {
960
+ onLiteralValue(value);
961
+ } else {
962
+ onObjectProperty(value);
963
+ _jsonPath.push(value);
964
+ }
965
+ scanNext();
966
+ return true;
967
+ }
968
+ function parseLiteral() {
969
+ switch (_scanner.getToken()) {
970
+ case 11:
971
+ const tokenValue = _scanner.getTokenValue();
972
+ let value = Number(tokenValue);
973
+ if (isNaN(value)) {
974
+ handleError(2);
975
+ value = 0;
976
+ }
977
+ onLiteralValue(value);
978
+ break;
979
+ case 7:
980
+ onLiteralValue(null);
981
+ break;
982
+ case 8:
983
+ onLiteralValue(true);
984
+ break;
985
+ case 9:
986
+ onLiteralValue(false);
987
+ break;
988
+ default:
989
+ return false;
990
+ }
991
+ scanNext();
992
+ return true;
993
+ }
994
+ function parseProperty() {
995
+ if (_scanner.getToken() !== 10) {
996
+ handleError(3, [], [2, 5]);
997
+ return false;
998
+ }
999
+ parseString(false);
1000
+ if (_scanner.getToken() === 6) {
1001
+ onSeparator(":");
1002
+ scanNext();
1003
+ if (!parseValue()) {
1004
+ handleError(4, [], [2, 5]);
1005
+ }
1006
+ } else {
1007
+ handleError(5, [], [2, 5]);
1008
+ }
1009
+ _jsonPath.pop();
1010
+ return true;
1011
+ }
1012
+ function parseObject() {
1013
+ onObjectBegin();
1014
+ scanNext();
1015
+ let needsComma = false;
1016
+ while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
1017
+ if (_scanner.getToken() === 5) {
1018
+ if (!needsComma) {
1019
+ handleError(4, [], []);
1020
+ }
1021
+ onSeparator(",");
1022
+ scanNext();
1023
+ if (_scanner.getToken() === 2 && allowTrailingComma) {
1024
+ break;
1025
+ }
1026
+ } else if (needsComma) {
1027
+ handleError(6, [], []);
1028
+ }
1029
+ if (!parseProperty()) {
1030
+ handleError(4, [], [2, 5]);
1031
+ }
1032
+ needsComma = true;
1033
+ }
1034
+ onObjectEnd();
1035
+ if (_scanner.getToken() !== 2) {
1036
+ handleError(7, [2], []);
1037
+ } else {
1038
+ scanNext();
1039
+ }
1040
+ return true;
1041
+ }
1042
+ function parseArray() {
1043
+ onArrayBegin();
1044
+ scanNext();
1045
+ let isFirstElement = true;
1046
+ let needsComma = false;
1047
+ while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
1048
+ if (_scanner.getToken() === 5) {
1049
+ if (!needsComma) {
1050
+ handleError(4, [], []);
1051
+ }
1052
+ onSeparator(",");
1053
+ scanNext();
1054
+ if (_scanner.getToken() === 4 && allowTrailingComma) {
1055
+ break;
1056
+ }
1057
+ } else if (needsComma) {
1058
+ handleError(6, [], []);
1059
+ }
1060
+ if (isFirstElement) {
1061
+ _jsonPath.push(0);
1062
+ isFirstElement = false;
1063
+ } else {
1064
+ _jsonPath[_jsonPath.length - 1]++;
1065
+ }
1066
+ if (!parseValue()) {
1067
+ handleError(4, [], [4, 5]);
1068
+ }
1069
+ needsComma = true;
1070
+ }
1071
+ onArrayEnd();
1072
+ if (!isFirstElement) {
1073
+ _jsonPath.pop();
1074
+ }
1075
+ if (_scanner.getToken() !== 4) {
1076
+ handleError(8, [4], []);
1077
+ } else {
1078
+ scanNext();
1079
+ }
1080
+ return true;
1081
+ }
1082
+ function parseValue() {
1083
+ switch (_scanner.getToken()) {
1084
+ case 3:
1085
+ return parseArray();
1086
+ case 1:
1087
+ return parseObject();
1088
+ case 10:
1089
+ return parseString(true);
1090
+ default:
1091
+ return parseLiteral();
1092
+ }
1093
+ }
1094
+ scanNext();
1095
+ if (_scanner.getToken() === 17) {
1096
+ if (options.allowEmptyContent) {
1097
+ return true;
1098
+ }
1099
+ handleError(4, [], []);
1100
+ return false;
1101
+ }
1102
+ if (!parseValue()) {
1103
+ handleError(4, [], []);
1104
+ return false;
1105
+ }
1106
+ if (_scanner.getToken() !== 17) {
1107
+ handleError(9, [], []);
1108
+ }
1109
+ return true;
1110
+ }
1111
+ function getNodeType(value) {
1112
+ switch (typeof value) {
1113
+ case "boolean":
1114
+ return "boolean";
1115
+ case "number":
1116
+ return "number";
1117
+ case "string":
1118
+ return "string";
1119
+ case "object": {
1120
+ if (!value) {
1121
+ return "null";
1122
+ } else if (Array.isArray(value)) {
1123
+ return "array";
1124
+ }
1125
+ return "object";
1126
+ }
1127
+ default:
1128
+ return "null";
1129
+ }
1130
+ }
1131
+ var ParseOptions;
1132
+ var init_parser = __esm(() => {
1133
+ init_scanner();
1134
+ (function(ParseOptions2) {
1135
+ ParseOptions2.DEFAULT = {
1136
+ allowTrailingComma: false
1137
+ };
1138
+ })(ParseOptions || (ParseOptions = {}));
1139
+ });
1140
+
1141
+ // node_modules/jsonc-parser/lib/esm/impl/edit.js
1142
+ function setProperty(text, originalPath, value, options) {
1143
+ const path = originalPath.slice();
1144
+ const errors = [];
1145
+ const root = parseTree(text, errors);
1146
+ let parent = undefined;
1147
+ let lastSegment = undefined;
1148
+ while (path.length > 0) {
1149
+ lastSegment = path.pop();
1150
+ parent = findNodeAtLocation(root, path);
1151
+ if (parent === undefined && value !== undefined) {
1152
+ if (typeof lastSegment === "string") {
1153
+ value = { [lastSegment]: value };
1154
+ } else {
1155
+ value = [value];
1156
+ }
1157
+ } else {
1158
+ break;
1159
+ }
1160
+ }
1161
+ if (!parent) {
1162
+ if (value === undefined) {
1163
+ throw new Error("Can not delete in empty document");
1164
+ }
1165
+ return withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, options);
1166
+ } else if (parent.type === "object" && typeof lastSegment === "string" && Array.isArray(parent.children)) {
1167
+ const existing = findNodeAtLocation(parent, [lastSegment]);
1168
+ if (existing !== undefined) {
1169
+ if (value === undefined) {
1170
+ if (!existing.parent) {
1171
+ throw new Error("Malformed AST");
1172
+ }
1173
+ const propertyIndex = parent.children.indexOf(existing.parent);
1174
+ let removeBegin;
1175
+ let removeEnd = existing.parent.offset + existing.parent.length;
1176
+ if (propertyIndex > 0) {
1177
+ let previous = parent.children[propertyIndex - 1];
1178
+ removeBegin = previous.offset + previous.length;
1179
+ } else {
1180
+ removeBegin = parent.offset + 1;
1181
+ if (parent.children.length > 1) {
1182
+ let next = parent.children[1];
1183
+ removeEnd = next.offset;
1184
+ }
1185
+ }
1186
+ return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: "" }, options);
1187
+ } else {
1188
+ return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, options);
1189
+ }
1190
+ } else {
1191
+ if (value === undefined) {
1192
+ return [];
1193
+ }
1194
+ const newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
1195
+ const index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map((p) => p.children[0].value)) : parent.children.length;
1196
+ let edit;
1197
+ if (index > 0) {
1198
+ let previous = parent.children[index - 1];
1199
+ edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
1200
+ } else if (parent.children.length === 0) {
1201
+ edit = { offset: parent.offset + 1, length: 0, content: newProperty };
1202
+ } else {
1203
+ edit = { offset: parent.offset + 1, length: 0, content: newProperty + "," };
1204
+ }
1205
+ return withFormatting(text, edit, options);
1206
+ }
1207
+ } else if (parent.type === "array" && typeof lastSegment === "number" && Array.isArray(parent.children)) {
1208
+ const insertIndex = lastSegment;
1209
+ if (insertIndex === -1) {
1210
+ const newProperty = `${JSON.stringify(value)}`;
1211
+ let edit;
1212
+ if (parent.children.length === 0) {
1213
+ edit = { offset: parent.offset + 1, length: 0, content: newProperty };
1214
+ } else {
1215
+ const previous = parent.children[parent.children.length - 1];
1216
+ edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
1217
+ }
1218
+ return withFormatting(text, edit, options);
1219
+ } else if (value === undefined && parent.children.length >= 0) {
1220
+ const removalIndex = lastSegment;
1221
+ const toRemove = parent.children[removalIndex];
1222
+ let edit;
1223
+ if (parent.children.length === 1) {
1224
+ edit = { offset: parent.offset + 1, length: parent.length - 2, content: "" };
1225
+ } else if (parent.children.length - 1 === removalIndex) {
1226
+ let previous = parent.children[removalIndex - 1];
1227
+ let offset = previous.offset + previous.length;
1228
+ let parentEndOffset = parent.offset + parent.length;
1229
+ edit = { offset, length: parentEndOffset - 2 - offset, content: "" };
1230
+ } else {
1231
+ edit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: "" };
1232
+ }
1233
+ return withFormatting(text, edit, options);
1234
+ } else if (value !== undefined) {
1235
+ let edit;
1236
+ const newProperty = `${JSON.stringify(value)}`;
1237
+ if (!options.isArrayInsertion && parent.children.length > lastSegment) {
1238
+ const toModify = parent.children[lastSegment];
1239
+ edit = { offset: toModify.offset, length: toModify.length, content: newProperty };
1240
+ } else if (parent.children.length === 0 || lastSegment === 0) {
1241
+ edit = { offset: parent.offset + 1, length: 0, content: parent.children.length === 0 ? newProperty : newProperty + "," };
1242
+ } else {
1243
+ const index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
1244
+ const previous = parent.children[index - 1];
1245
+ edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
1246
+ }
1247
+ return withFormatting(text, edit, options);
1248
+ } else {
1249
+ throw new Error(`Can not ${value === undefined ? "remove" : options.isArrayInsertion ? "insert" : "modify"} Array index ${insertIndex} as length is not sufficient`);
1250
+ }
1251
+ } else {
1252
+ throw new Error(`Can not add ${typeof lastSegment !== "number" ? "index" : "property"} to parent of type ${parent.type}`);
1253
+ }
1254
+ }
1255
+ function withFormatting(text, edit, options) {
1256
+ if (!options.formattingOptions) {
1257
+ return [edit];
1258
+ }
1259
+ let newText = applyEdit(text, edit);
1260
+ let begin = edit.offset;
1261
+ let end = edit.offset + edit.content.length;
1262
+ if (edit.length === 0 || edit.content.length === 0) {
1263
+ while (begin > 0 && !isEOL(newText, begin - 1)) {
1264
+ begin--;
1265
+ }
1266
+ while (end < newText.length && !isEOL(newText, end)) {
1267
+ end++;
1268
+ }
1269
+ }
1270
+ const edits = format(newText, { offset: begin, length: end - begin }, { ...options.formattingOptions, keepLines: false });
1271
+ for (let i = edits.length - 1;i >= 0; i--) {
1272
+ const edit2 = edits[i];
1273
+ newText = applyEdit(newText, edit2);
1274
+ begin = Math.min(begin, edit2.offset);
1275
+ end = Math.max(end, edit2.offset + edit2.length);
1276
+ end += edit2.content.length - edit2.length;
1277
+ }
1278
+ const editLength = text.length - (newText.length - end) - begin;
1279
+ return [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];
1280
+ }
1281
+ function applyEdit(text, edit) {
1282
+ return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
1283
+ }
1284
+ var init_edit = __esm(() => {
1285
+ init_format();
1286
+ init_parser();
1287
+ });
1288
+
1289
+ // node_modules/jsonc-parser/lib/esm/main.js
1290
+ function modify(text, path, value, options) {
1291
+ return setProperty(text, path, value, options);
1292
+ }
1293
+ function applyEdits(text, edits) {
1294
+ let sortedEdits = edits.slice(0).sort((a, b) => {
1295
+ const diff = a.offset - b.offset;
1296
+ if (diff === 0) {
1297
+ return a.length - b.length;
1298
+ }
1299
+ return diff;
1300
+ });
1301
+ let lastModifiedOffset = text.length;
1302
+ for (let i = sortedEdits.length - 1;i >= 0; i--) {
1303
+ let e = sortedEdits[i];
1304
+ if (e.offset + e.length <= lastModifiedOffset) {
1305
+ text = applyEdit(text, e);
1306
+ } else {
1307
+ throw new Error("Overlapping edit");
1308
+ }
1309
+ lastModifiedOffset = e.offset;
1310
+ }
1311
+ return text;
1312
+ }
1313
+ var ScanError, SyntaxKind, parse2, ParseErrorCode;
1314
+ var init_main = __esm(() => {
1315
+ init_format();
1316
+ init_edit();
1317
+ init_scanner();
1318
+ init_parser();
1319
+ (function(ScanError2) {
1320
+ ScanError2[ScanError2["None"] = 0] = "None";
1321
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
1322
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
1323
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
1324
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
1325
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
1326
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
1327
+ })(ScanError || (ScanError = {}));
1328
+ (function(SyntaxKind2) {
1329
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
1330
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
1331
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
1332
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
1333
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
1334
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
1335
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
1336
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
1337
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
1338
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
1339
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
1340
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
1341
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
1342
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
1343
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
1344
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
1345
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
1346
+ })(SyntaxKind || (SyntaxKind = {}));
1347
+ parse2 = parse;
1348
+ (function(ParseErrorCode2) {
1349
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
1350
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
1351
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
1352
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
1353
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
1354
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
1355
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
1356
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
1357
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
1358
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
1359
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
1360
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
1361
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
1362
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
1363
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
1364
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
1365
+ })(ParseErrorCode || (ParseErrorCode = {}));
1366
+ });
1367
+
1368
+ // src/core/jsonc.ts
1369
+ function parseJsonc(text) {
1370
+ const errors = [];
1371
+ const value = parse2(text, errors, { allowTrailingComma: true });
1372
+ if (errors.length > 0) {
1373
+ const first = errors[0];
1374
+ throw new SyntaxError(`JSONC parse error at offset ${first.offset} (code ${first.error})`);
1375
+ }
1376
+ return value;
1377
+ }
1378
+ var init_jsonc = __esm(() => {
1379
+ init_main();
1380
+ });
1381
+
1382
+ // src/installer/formats/value.ts
1383
+ function isPlainObject(value) {
1384
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1385
+ }
1386
+ function deepEqual(a, b) {
1387
+ if (a === b)
1388
+ return true;
1389
+ if (a === null || b === null || typeof a !== "object" || typeof b !== "object")
1390
+ return false;
1391
+ const aArray = Array.isArray(a);
1392
+ const bArray = Array.isArray(b);
1393
+ if (aArray !== bArray)
1394
+ return false;
1395
+ if (aArray && bArray) {
1396
+ const x2 = a;
1397
+ const y2 = b;
1398
+ return x2.length === y2.length && x2.every((item, index) => deepEqual(item, y2[index]));
1399
+ }
1400
+ const x = a;
1401
+ const y = b;
1402
+ const xKeys = Object.keys(x);
1403
+ const yKeys = Object.keys(y);
1404
+ return xKeys.length === yKeys.length && xKeys.every((key) => deepEqual(x[key], y[key]));
1405
+ }
1406
+ function valueAt(value, path) {
1407
+ let node = value;
1408
+ for (const key of path) {
1409
+ if (Array.isArray(node)) {
1410
+ const index = Number(key);
1411
+ node = Number.isInteger(index) ? node[index] : undefined;
1412
+ } else if (isPlainObject(node)) {
1413
+ node = node[key];
1414
+ } else {
1415
+ return;
1416
+ }
1417
+ if (node === undefined)
1418
+ return;
1419
+ }
1420
+ return node;
1421
+ }
1422
+ function removeAt(value, path) {
1423
+ const parent = valueAt(value, path.slice(0, -1));
1424
+ if (isPlainObject(parent))
1425
+ delete parent[path[path.length - 1]];
1426
+ }
1427
+ function appendEntries(existing, entries, path) {
1428
+ if (existing !== undefined && !Array.isArray(existing)) {
1429
+ throw new Error(`cannot append to ${path.join(".")}: it is a ${typeof existing}, not an array`);
1430
+ }
1431
+ const list = Array.isArray(existing) ? existing : [];
1432
+ const appended = entries.filter((entry) => !list.some((item) => deepEqual(item, entry)));
1433
+ return { list, appended };
1434
+ }
1435
+
1436
+ // src/installer/formats/json.ts
1437
+ import { existsSync, readFileSync } from "node:fs";
1438
+ function loadJson(file) {
1439
+ if (!existsSync(file))
1440
+ return { exists: false, text: "", value: {}, lossy: false };
1441
+ const text = readFileSync(file, "utf8");
1442
+ try {
1443
+ return { exists: true, text, value: parseJsonc(text), lossy: false };
1444
+ } catch (error) {
1445
+ const parseError = error instanceof Error ? error.message : String(error);
1446
+ return { exists: true, text, value: {}, lossy: false, parseError };
1447
+ }
1448
+ }
1449
+ function jsonGet(text, path) {
1450
+ const root = parse2(text, undefined, { allowTrailingComma: true });
1451
+ return valueAt(root, path);
1452
+ }
1453
+ function applyJsonOps(text, ops) {
1454
+ let current = text.trim().length > 0 ? text : `{}
1455
+ `;
1456
+ const recorded = [];
1457
+ const createdParents = [];
1458
+ for (const op of ops) {
1459
+ const path = op.path;
1460
+ if (op.op === "set") {
1461
+ current = ensureParents(current, op.path, createdParents);
1462
+ const previous = jsonGet(current, op.path);
1463
+ current = edit(current, path, op.value);
1464
+ recorded.push({ op: "set", path: op.path, applied: structuredClone(op.value), previous });
1465
+ continue;
1466
+ }
1467
+ current = ensureParents(current, op.path, createdParents);
1468
+ const existing = jsonGet(current, op.path);
1469
+ const { list, appended } = appendEntries(existing, op.entries ?? [], op.path);
1470
+ if (existing === undefined) {
1471
+ current = edit(current, path, []);
1472
+ createdParents.push(op.path);
1473
+ }
1474
+ let index = list.length;
1475
+ for (const entry of appended) {
1476
+ current = edit(current, [...path, index], entry);
1477
+ index += 1;
1478
+ }
1479
+ recorded.push({ op: "append-array", path: op.path, applied: appended, previous: undefined });
1480
+ }
1481
+ return { text: current, recorded, createdParents };
1482
+ }
1483
+ function revertJsonOps(text, ops, createdParents) {
1484
+ let current = text;
1485
+ const notes = [];
1486
+ for (const record of [...ops].reverse()) {
1487
+ const path = record.path;
1488
+ if (record.op === "set") {
1489
+ const now = jsonGet(current, record.path);
1490
+ if (now === undefined)
1491
+ continue;
1492
+ if (!deepEqual(now, record.applied)) {
1493
+ notes.push(`${record.path.join(".")}: current value differs from what the installer wrote; left untouched`);
1494
+ continue;
1495
+ }
1496
+ current = record.previous === undefined ? edit(current, path, undefined) : edit(current, path, record.previous);
1497
+ } else {
1498
+ const entries = Array.isArray(record.applied) ? record.applied : [];
1499
+ for (const entry of [...entries].reverse()) {
1500
+ const list = jsonGet(current, record.path);
1501
+ if (!Array.isArray(list))
1502
+ continue;
1503
+ const index = list.findIndex((item) => deepEqual(item, entry));
1504
+ if (index === -1)
1505
+ continue;
1506
+ current = edit(current, [...path, index], undefined);
1507
+ }
1508
+ }
1509
+ }
1510
+ for (const parent of [...createdParents].reverse()) {
1511
+ const value = jsonGet(current, parent);
1512
+ const isEmptyObject = isPlainObject(value) && Object.keys(value).length === 0;
1513
+ const isEmptyArray = Array.isArray(value) && value.length === 0;
1514
+ if (isEmptyObject || isEmptyArray) {
1515
+ current = edit(current, parent, undefined);
1516
+ }
1517
+ }
1518
+ return { text: current, notes };
1519
+ }
1520
+ function edit(text, path, value) {
1521
+ return applyEdits(text, modify(text, path, value, { formattingOptions: JSON_FORMATTING }));
1522
+ }
1523
+ function ensureParents(text, path, created) {
1524
+ let current = text;
1525
+ for (let depth = 0;depth < path.length - 1; depth += 1) {
1526
+ const prefix = path.slice(0, depth + 1);
1527
+ const existing = jsonGet(current, prefix);
1528
+ if (existing !== undefined && typeof existing !== "object") {
1529
+ throw new Error(`cannot descend into ${prefix.join(".")}: it is a ${typeof existing}, not an object`);
1530
+ }
1531
+ if (existing !== undefined)
1532
+ continue;
1533
+ const nextSegmentIsIndex = Number.isInteger(Number(path[depth + 1]));
1534
+ const placeholder = nextSegmentIsIndex ? [] : {};
1535
+ current = edit(current, prefix, placeholder);
1536
+ created.push(prefix);
1537
+ }
1538
+ return current;
1539
+ }
1540
+ function jsonOpHolds(text, op) {
1541
+ if (op.op === "set")
1542
+ return deepEqual(jsonGet(text, op.path), op.value);
1543
+ const list = jsonGet(text, op.path);
1544
+ return Array.isArray(list) && (op.entries ?? []).every((entry) => list.some((item) => deepEqual(item, entry)));
1545
+ }
1546
+ var JSON_FORMATTING, jsonCodec;
1547
+ var init_json = __esm(() => {
1548
+ init_main();
1549
+ init_jsonc();
1550
+ JSON_FORMATTING = { insertSpaces: true, tabSize: 2, insertFinalNewline: false };
1551
+ jsonCodec = {
1552
+ format: "json",
1553
+ load: loadJson,
1554
+ apply: (text, edit2) => {
1555
+ if (edit2.format !== "json")
1556
+ throw new Error(`json codec cannot apply a ${edit2.format} edit`);
1557
+ const result = applyJsonOps(text, edit2.ops);
1558
+ return { text: result.text, recorded: result.recorded, createdParents: result.createdParents };
1559
+ },
1560
+ verify: (text, edit2, op) => {
1561
+ if (edit2.format !== "json")
1562
+ throw new Error(`json codec cannot verify a ${edit2.format} edit`);
1563
+ const ops = op === undefined ? edit2.ops : [op];
1564
+ return ops.every((candidate) => jsonOpHolds(text, candidate));
1565
+ },
1566
+ revert: (text, recorded) => revertJsonOps(text, recorded.ops, recorded.createdParents ?? []),
1567
+ isEffectivelyEmpty: (text) => text.replace(/[{}\s]/g, "").length === 0
1568
+ };
1569
+ });
1570
+
1571
+ // src/installer/formats/rules.ts
1572
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
1573
+ function rulesMarkers(host) {
1574
+ return {
1575
+ begin: `<!-- deepseek-web-retrieval:${host}:rules:begin -->`,
1576
+ end: `<!-- deepseek-web-retrieval:${host}:rules:end -->`
1577
+ };
1578
+ }
1579
+ function buildRulesBlock(host, lines) {
1580
+ const markers = rulesMarkers(host);
1581
+ return [markers.begin, ...lines, markers.end].join(`
1582
+ `);
1583
+ }
1584
+ function upsertBlock(host, text, block) {
1585
+ const without = removeBlock(host, text);
1586
+ const trimmed = without.trimEnd();
1587
+ return trimmed ? `${trimmed}
1588
+
1589
+ ${block}
1590
+ ` : `${block}
1591
+ `;
1592
+ }
1593
+ function removeBlock(host, text) {
1594
+ const markers = rulesMarkers(host);
1595
+ const start = text.indexOf(markers.begin);
1596
+ if (start === -1)
1597
+ return text;
1598
+ const end = text.indexOf(markers.end);
1599
+ if (end === -1)
1600
+ return text.slice(0, start);
1601
+ let after = text.slice(end + markers.end.length);
1602
+ after = after.replace(/^\n{1,2}/, "");
1603
+ const before = text.slice(0, start);
1604
+ return before.endsWith(`
1605
+
1606
+ `) ? `${before.slice(0, -1)}${after}` : before + after;
1607
+ }
1608
+ function hasBlock(host, text) {
1609
+ const markers = rulesMarkers(host);
1610
+ return text.includes(markers.begin) && text.includes(markers.end);
1611
+ }
1612
+ function rulesCodec(host) {
1613
+ return {
1614
+ format: "rules",
1615
+ load: (file) => existsSync2(file) ? { exists: true, text: readFileSync2(file, "utf8"), value: {}, lossy: false } : { exists: false, text: "", value: {}, lossy: false },
1616
+ apply: (text, edit2) => {
1617
+ if (edit2.format !== "rules")
1618
+ throw new Error(`rules codec cannot apply a ${edit2.format} edit`);
1619
+ return { text: upsertBlock(host, text, edit2.block), recorded: [], createdParents: [] };
1620
+ },
1621
+ verify: (text) => hasBlock(host, text),
1622
+ revert: (text) => ({ text: removeBlock(host, text), notes: [] }),
1623
+ isEffectivelyEmpty: (text) => text.trim().length === 0
1624
+ };
1625
+ }
1626
+ var init_rules = () => {};
1627
+
1628
+ // node_modules/smol-toml/dist/error.js
1629
+ function getLineColFromPtr(string2, ptr) {
1630
+ let lines = string2.slice(0, ptr).split(/\r?\n/);
1631
+ return [lines.length, lines.pop().length + 1];
1632
+ }
1633
+ function makeCodeBlock(string2, line, column) {
1634
+ let lines = string2.split(/\r?\n/);
1635
+ let codeblock = "";
1636
+ let numberLen = (Math.log10(line + 1) | 0) + 1;
1637
+ for (let i = line - 1;i <= line + 1; i++) {
1638
+ let l = lines[i - 1];
1639
+ if (!l)
1640
+ continue;
1641
+ codeblock += i.toString().padEnd(numberLen, " ");
1642
+ codeblock += ": ";
1643
+ codeblock += l;
1644
+ codeblock += `
1645
+ `;
1646
+ if (i === line) {
1647
+ codeblock += " ".repeat(numberLen + column + 2);
1648
+ codeblock += `^
1649
+ `;
1650
+ }
1651
+ }
1652
+ return codeblock;
1653
+ }
1654
+ var TomlError;
1655
+ var init_error = __esm(() => {
1656
+ /*!
1657
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
1658
+ * SPDX-License-Identifier: BSD-3-Clause
1659
+ *
1660
+ * Redistribution and use in source and binary forms, with or without
1661
+ * modification, are permitted provided that the following conditions are met:
1662
+ *
1663
+ * 1. Redistributions of source code must retain the above copyright notice, this
1664
+ * list of conditions and the following disclaimer.
1665
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
1666
+ * this list of conditions and the following disclaimer in the
1667
+ * documentation and/or other materials provided with the distribution.
1668
+ * 3. Neither the name of the copyright holder nor the names of its contributors
1669
+ * may be used to endorse or promote products derived from this software without
1670
+ * specific prior written permission.
1671
+ *
1672
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1673
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1674
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1675
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1676
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1677
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1678
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1679
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1680
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1681
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1682
+ */
1683
+ TomlError = class TomlError extends Error {
1684
+ line;
1685
+ column;
1686
+ codeblock;
1687
+ constructor(message, options) {
1688
+ const [line, column] = getLineColFromPtr(options.toml, options.ptr);
1689
+ const codeblock = makeCodeBlock(options.toml, line, column);
1690
+ super(`Invalid TOML document: ${message}
1691
+
1692
+ ${codeblock}`, options);
1693
+ this.line = line;
1694
+ this.column = column;
1695
+ this.codeblock = codeblock;
1696
+ }
1697
+ static x(message, ctx, ptr) {
1698
+ throw new TomlError(message, { toml: ctx.s, ptr: ptr ?? ctx.p });
1699
+ }
1700
+ };
1701
+ });
1702
+
1703
+ // node_modules/smol-toml/dist/primitive.js
1704
+ function parseString(ctx) {
1705
+ let startPtr = ctx.p;
1706
+ let c = ctx.s.charCodeAt(ctx.p++);
1707
+ let first = c;
1708
+ let isLiteral = c === 39;
1709
+ let isMultiline = c === ctx.s.charCodeAt(ctx.p) && c === ctx.s.charCodeAt(ctx.p + 1);
1710
+ if (isMultiline) {
1711
+ if ((c = ctx.s.charCodeAt(ctx.p += 2)) === 10)
1712
+ ctx.p++;
1713
+ else if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)
1714
+ ctx.p += 2;
1715
+ }
1716
+ let parsed = "";
1717
+ let sliceStart = ctx.p;
1718
+ let state = 0;
1719
+ for (;ctx.p < ctx.s.length; ctx.p++) {
1720
+ c = ctx.s.charCodeAt(ctx.p);
1721
+ if (isMultiline && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)) {
1722
+ state = state && 3;
1723
+ } else if (c < 32 && c !== 9 || c === 127) {
1724
+ TomlError.x("control characters are not allowed in strings", ctx);
1725
+ } else if ((!state || state === 3) && c === first && (!isMultiline || ctx.s.charCodeAt(ctx.p + 1) === first && ctx.s.charCodeAt(ctx.p + 2) === first)) {
1726
+ if (isMultiline) {
1727
+ if (ctx.s.charCodeAt(ctx.p + 3) === first)
1728
+ ctx.p++;
1729
+ if (ctx.s.charCodeAt(ctx.p + 3) === first)
1730
+ ctx.p++;
1731
+ }
1732
+ if (!state) {
1733
+ let s = ctx.s.slice(sliceStart, ctx.p);
1734
+ parsed = parsed ? parsed + s : s;
1735
+ }
1736
+ ctx.p += isMultiline ? 3 : 1;
1737
+ return parsed;
1738
+ } else if (!state) {
1739
+ if (!isLiteral && c === 92) {
1740
+ parsed += ctx.s.slice(sliceStart, sliceStart = ctx.p);
1741
+ state = 1;
1742
+ }
1743
+ } else if (state === 1) {
1744
+ if (c === 120 || c === 117 || c === 85) {
1745
+ let errPtr = ctx.p++ - 1;
1746
+ let value = 0;
1747
+ let len = c === 120 ? 2 : c === 117 ? 4 : 8;
1748
+ for (let j = 0;j < len; j++, ctx.p++) {
1749
+ let hex = ctx.s.charCodeAt(ctx.p);
1750
+ let digit = hex >= 48 && hex <= 57 ? hex - 48 : hex >= 65 && hex <= 70 ? hex - 65 + 10 : hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1;
1751
+ if (digit < 0)
1752
+ TomlError.x("invalid non-hex character in unicode escape", ctx);
1753
+ value = value << 4 | digit;
1754
+ }
1755
+ if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) {
1756
+ TomlError.x("invalid unicode escape", ctx, errPtr);
1757
+ }
1758
+ parsed += String.fromCodePoint(value);
1759
+ sliceStart = ctx.p--;
1760
+ state = 0;
1761
+ } else if (isMultiline && (c === 32 || c === 9)) {
1762
+ state = 2;
1763
+ } else {
1764
+ if (c === 98)
1765
+ parsed += "\b";
1766
+ else if (c === 116)
1767
+ parsed += "\t";
1768
+ else if (c === 110)
1769
+ parsed += `
1770
+ `;
1771
+ else if (c === 102)
1772
+ parsed += "\f";
1773
+ else if (c === 114)
1774
+ parsed += "\r";
1775
+ else if (c === 101)
1776
+ parsed += "\x1B";
1777
+ else if (c === 34)
1778
+ parsed += '"';
1779
+ else if (c === 92)
1780
+ parsed += "\\";
1781
+ else
1782
+ TomlError.x("unrecognised escape sequence", ctx);
1783
+ sliceStart = ctx.p + 1;
1784
+ state = 0;
1785
+ }
1786
+ } else if (c !== 32 && c !== 9) {
1787
+ if (state === 2)
1788
+ TomlError.x("invalid escape: only line-ending whitespace may be escaped", ctx, sliceStart);
1789
+ state = !isLiteral && c === 92 ? 1 : 0;
1790
+ sliceStart = ctx.p;
1791
+ }
1792
+ }
1793
+ TomlError.x("unfinished string", ctx, startPtr);
1794
+ }
1795
+ var init_primitive = __esm(() => {
1796
+ init_error();
1797
+ /*!
1798
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
1799
+ * SPDX-License-Identifier: BSD-3-Clause
1800
+ *
1801
+ * Redistribution and use in source and binary forms, with or without
1802
+ * modification, are permitted provided that the following conditions are met:
1803
+ *
1804
+ * 1. Redistributions of source code must retain the above copyright notice, this
1805
+ * list of conditions and the following disclaimer.
1806
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
1807
+ * this list of conditions and the following disclaimer in the
1808
+ * documentation and/or other materials provided with the distribution.
1809
+ * 3. Neither the name of the copyright holder nor the names of its contributors
1810
+ * may be used to endorse or promote products derived from this software without
1811
+ * specific prior written permission.
1812
+ *
1813
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1814
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1815
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1816
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1817
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1818
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1819
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1820
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1821
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1822
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1823
+ */
1824
+ });
1825
+
1826
+ // node_modules/smol-toml/dist/date.js
1827
+ var DATE_TIME_RE, TomlDate;
1828
+ var init_date = __esm(() => {
1829
+ /*!
1830
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
1831
+ * SPDX-License-Identifier: BSD-3-Clause
1832
+ *
1833
+ * Redistribution and use in source and binary forms, with or without
1834
+ * modification, are permitted provided that the following conditions are met:
1835
+ *
1836
+ * 1. Redistributions of source code must retain the above copyright notice, this
1837
+ * list of conditions and the following disclaimer.
1838
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
1839
+ * this list of conditions and the following disclaimer in the
1840
+ * documentation and/or other materials provided with the distribution.
1841
+ * 3. Neither the name of the copyright holder nor the names of its contributors
1842
+ * may be used to endorse or promote products derived from this software without
1843
+ * specific prior written permission.
1844
+ *
1845
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1846
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1847
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1848
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1849
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1850
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1851
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1852
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1853
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1854
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1855
+ */
1856
+ DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[Tt ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|z|[-+]\d{2}:\d{2})?$/i;
1857
+ TomlDate = class TomlDate extends Date {
1858
+ #hasDate = false;
1859
+ #hasTime = false;
1860
+ #offset = null;
1861
+ constructor(date, fasttype, unsafeDelim) {
1862
+ let hasDate = true;
1863
+ let hasTime = true;
1864
+ let offset = "Z";
1865
+ let c;
1866
+ if (typeof date === "string") {
1867
+ if (fasttype)
1868
+ prep: {
1869
+ if (fasttype < 3) {
1870
+ if (+date.slice(11, 13) > 23) {
1871
+ date = "";
1872
+ break prep;
1873
+ }
1874
+ if (fasttype === 2) {
1875
+ offset = null;
1876
+ date += "Z";
1877
+ } else if ((c = date.charCodeAt(date.length - 1)) !== 90 && c !== 122) {
1878
+ offset = date.slice(date.length - 6);
1879
+ }
1880
+ if (unsafeDelim)
1881
+ date = date.slice(0, 10) + "T" + date.slice(11);
1882
+ } else if (fasttype === 4) {
1883
+ date = +date.slice(0, 2) > 23 ? "" : `0000-01-01T${date}Z`;
1884
+ }
1885
+ hasDate = fasttype !== 4;
1886
+ hasTime = fasttype !== 3;
1887
+ }
1888
+ else {
1889
+ let match = date.match(DATE_TIME_RE);
1890
+ if (match) {
1891
+ if (!match[1]) {
1892
+ hasDate = false;
1893
+ date = `0000-01-01T${date}`;
1894
+ }
1895
+ hasTime = !!match[2];
1896
+ hasTime && date[10] === " " && (date = date.replace(" ", "T"));
1897
+ if (match[2] && +match[2] > 23) {
1898
+ date = "";
1899
+ } else {
1900
+ offset = match[3] || null;
1901
+ if (!offset && hasTime)
1902
+ date += "Z";
1903
+ }
1904
+ } else {
1905
+ date = "";
1906
+ }
1907
+ }
1908
+ }
1909
+ super(date);
1910
+ if (!isNaN(this.getTime())) {
1911
+ this.#hasDate = hasDate;
1912
+ this.#hasTime = hasTime;
1913
+ this.#offset = offset;
1914
+ }
1915
+ }
1916
+ isDateTime() {
1917
+ return this.#hasDate && this.#hasTime;
1918
+ }
1919
+ isLocal() {
1920
+ return !this.#hasDate || !this.#hasTime || !this.#offset;
1921
+ }
1922
+ isDate() {
1923
+ return this.#hasDate && !this.#hasTime;
1924
+ }
1925
+ isTime() {
1926
+ return this.#hasTime && !this.#hasDate;
1927
+ }
1928
+ isValid() {
1929
+ return this.#hasDate || this.#hasTime;
1930
+ }
1931
+ toISOString() {
1932
+ let iso = super.toISOString();
1933
+ if (this.isDate())
1934
+ return iso.slice(0, 10);
1935
+ if (this.isTime())
1936
+ return iso.slice(11, 23);
1937
+ if (this.#offset === null)
1938
+ return iso.slice(0, -1);
1939
+ if (this.#offset === "Z" || this.#offset === "z")
1940
+ return iso;
1941
+ let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
1942
+ offset = this.#offset[0] === "-" ? offset : -offset;
1943
+ let offsetDate = new Date(this.getTime() - offset * 60000);
1944
+ return offsetDate.toISOString().slice(0, -1) + this.#offset;
1945
+ }
1946
+ static wrapAsOffsetDateTime(jsDate, offset = "Z") {
1947
+ let date = new TomlDate(jsDate);
1948
+ date.#offset = offset;
1949
+ return date;
1950
+ }
1951
+ static wrapAsLocalDateTime(jsDate) {
1952
+ let date = new TomlDate(jsDate);
1953
+ date.#offset = null;
1954
+ return date;
1955
+ }
1956
+ static wrapAsLocalDate(jsDate) {
1957
+ let date = new TomlDate(jsDate);
1958
+ date.#hasTime = false;
1959
+ date.#offset = null;
1960
+ return date;
1961
+ }
1962
+ static wrapAsLocalTime(jsDate) {
1963
+ let date = new TomlDate(jsDate);
1964
+ date.#hasDate = false;
1965
+ date.#offset = null;
1966
+ return date;
1967
+ }
1968
+ };
1969
+ });
1970
+
1971
+ // node_modules/smol-toml/dist/extract.js
1972
+ function isDigit2(char, base = 10) {
1973
+ return base === 16 ? char > 47 && char < 58 || char > 64 && char < 71 || char > 96 && char < 103 : char > 47 && char < 48 + base;
1974
+ }
1975
+ function isEndOfValue(char, delim) {
1976
+ return char === 32 || char === 9 || char === 10 || char === 13 || delim && (char === delim || char === 44) || char === 35;
1977
+ }
1978
+ function extractValue(ctx, end) {
1979
+ let errPtr = ctx.p;
1980
+ let c = ctx.s.charCodeAt(ctx.p);
1981
+ if (c === 91 || c === 123) {
1982
+ ctx.d-- || TomlError.x("document contains excessively nested structures. aborting.", ctx);
1983
+ let value = c === 91 ? parseArray(ctx) : parseInlineTable(ctx);
1984
+ ctx.d++;
1985
+ return value;
1986
+ }
1987
+ if (c === 34 || c === 39) {
1988
+ return parseString(ctx);
1989
+ }
1990
+ if (c === 116) {
1991
+ if (ctx.s.charCodeAt(++ctx.p) !== 114 || ctx.s.charCodeAt(++ctx.p) !== 117 || ctx.s.charCodeAt(++ctx.p) !== 101)
1992
+ TomlError.x("invalid value", ctx, errPtr);
1993
+ return ctx.p++, true;
1994
+ }
1995
+ if (c === 102) {
1996
+ if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 108 || ctx.s.charCodeAt(++ctx.p) !== 115 || ctx.s.charCodeAt(++ctx.p) !== 101)
1997
+ TomlError.x("invalid value", ctx, errPtr);
1998
+ return ctx.p++, false;
1999
+ }
2000
+ if (c === 43 || c === 45) {
2001
+ return parseNumber(ctx, ctx.p, ctx.s.charCodeAt(++ctx.p), 44 - c, end);
2002
+ }
2003
+ if (ctx.s.charCodeAt(ctx.p + 4) === 45 && ctx.s.charCodeAt(ctx.p + 7) === 45) {
2004
+ return parseDate(ctx, c, end);
2005
+ }
2006
+ if (ctx.s.charCodeAt(ctx.p + 2) === 58) {
2007
+ return parseTime(ctx, c, end);
2008
+ }
2009
+ return parseNumber(ctx, ctx.p, c, 0, end);
2010
+ }
2011
+ function parseNumber(ctx, startPtr, startChr, sign, endChr) {
2012
+ let c = startChr;
2013
+ let state = 0;
2014
+ let hasUnderscores = false;
2015
+ if (c === 105) {
2016
+ if (ctx.s.charCodeAt(++ctx.p) !== 110 || ctx.s.charCodeAt(++ctx.p) !== 102)
2017
+ TomlError.x("invalid value", ctx, startPtr);
2018
+ return ctx.p++, (sign || 1) / 0;
2019
+ }
2020
+ if (c === 110) {
2021
+ if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 110)
2022
+ TomlError.x("invalid value", ctx, startPtr);
2023
+ return ctx.p++, NaN;
2024
+ }
2025
+ if (c === 48) {
2026
+ if (++ctx.p >= ctx.s.length || isEndOfValue(c = ctx.s.charCodeAt(ctx.p), endChr))
2027
+ return ctx.bi === true ? 0n : 0;
2028
+ if (!sign) {
2029
+ if (c === 120)
2030
+ return parseIntegerBaseN(ctx, startPtr, 16, endChr);
2031
+ else if (c === 98)
2032
+ return parseIntegerBaseN(ctx, startPtr, 2, endChr);
2033
+ else if (c === 111)
2034
+ return parseIntegerBaseN(ctx, startPtr, 8, endChr);
2035
+ }
2036
+ if (c === 46)
2037
+ state = 2;
2038
+ else if (c === 101 || c === 69)
2039
+ state = 4;
2040
+ else
2041
+ TomlError.x("illegal leading zero", ctx, startPtr);
2042
+ } else if (!isDigit2(c))
2043
+ TomlError.x("invalid value", ctx, startPtr);
2044
+ while (++ctx.p < ctx.s.length && (c = ctx.s.charCodeAt(ctx.p), !isEndOfValue(c, endChr))) {
2045
+ if (!state)
2046
+ state = 1;
2047
+ if (c === 95) {
2048
+ if (!(state & 1))
2049
+ TomlError.x("illegal underscore", ctx);
2050
+ state += 11;
2051
+ hasUnderscores = true;
2052
+ } else if (state === 1 && c === 46)
2053
+ state = 2;
2054
+ else if ((state === 1 || state === 3) && (c === 101 || c === 69))
2055
+ state = 4;
2056
+ else if (state === 4 && (c === 43 || c === 45)) {
2057
+ state = 6;
2058
+ } else if (!isDigit2(c))
2059
+ TomlError.x(`illegal character in numeric literal`, ctx);
2060
+ else if (state > 9)
2061
+ state -= 11;
2062
+ else if (!(state & 1))
2063
+ state++;
2064
+ }
2065
+ if (!state) {
2066
+ let val = (startChr - 48) * (sign || 1);
2067
+ return ctx.bi === true ? BigInt(val) : val;
2068
+ }
2069
+ if (!(state & 1))
2070
+ TomlError.x("unfinished numeric value", ctx, startPtr);
2071
+ let str = ctx.s.slice(startPtr, ctx.p);
2072
+ if (hasUnderscores)
2073
+ str = str.replaceAll("_", "");
2074
+ return state > 1 ? parseFloat(str) : parseInteger(ctx, str, 10, startPtr);
2075
+ }
2076
+ function parseIntegerBaseN(ctx, startPtr, base, endChr) {
2077
+ let c, underscore = 1;
2078
+ while (++ctx.p < ctx.s.length && (c = ctx.s.charCodeAt(ctx.p), !isEndOfValue(c, endChr))) {
2079
+ if (c === 95) {
2080
+ if (underscore & 1)
2081
+ TomlError.x("illegal underscore", ctx);
2082
+ underscore = 3;
2083
+ } else if (!isDigit2(c, base))
2084
+ TomlError.x(`illegal character in numeric literal`, ctx);
2085
+ else if (underscore & 1)
2086
+ underscore--;
2087
+ }
2088
+ if (underscore & 1)
2089
+ TomlError.x("unfinished numeric value", ctx);
2090
+ let str = ctx.s.slice(startPtr + 2, ctx.p);
2091
+ if (underscore)
2092
+ str = str.replaceAll("_", "");
2093
+ return parseInteger(ctx, str, base, startPtr);
2094
+ }
2095
+ function parseInteger(ctx, str, base, startPtr) {
2096
+ if (ctx.bi !== true)
2097
+ int: {
2098
+ let val = parseInt(str, base);
2099
+ if (!Number.isSafeInteger(val)) {
2100
+ if (ctx.bi)
2101
+ break int;
2102
+ TomlError.x("integer value cannot be represented losslessly", ctx, startPtr);
2103
+ }
2104
+ return val;
2105
+ }
2106
+ return base === 10 ? BigInt(str) : BigInt((base === 2 ? "0b" : base === 8 ? "0o" : "0x") + str);
2107
+ }
2108
+ function parseDate(ctx, c, endChr) {
2109
+ let startPtr = ctx.p++, unsafeSeparator;
2110
+ if (!isDigit2(c) || !isDigit2(ctx.s.charCodeAt(ctx.p++)) || !isDigit2(ctx.s.charCodeAt(ctx.p++)) || !isDigit2(ctx.s.charCodeAt(ctx.p++))) {
2111
+ return parseNumber(ctx, ctx.p = startPtr, c, 0, endChr);
2112
+ }
2113
+ ctx.p += 5;
2114
+ if (!isDigit2(ctx.s.charCodeAt(ctx.p++)))
2115
+ TomlError.x("invalid date-time: date part is malformed", ctx, startPtr);
2116
+ if (ctx.p >= ctx.s.length || ((c = ctx.s.charCodeAt(ctx.p)) !== 32 || (unsafeSeparator = true, !isDigit2(ctx.s.charCodeAt(ctx.p + 1)))) && c !== 84 && c !== 116) {
2117
+ let t2 = ctx.s.slice(startPtr, ctx.p);
2118
+ return readDate(ctx, t2, 3, false, startPtr);
2119
+ }
2120
+ if (ctx.s.charCodeAt(ctx.p += 3) !== 58)
2121
+ TomlError.x("invalid date-time: time part is malformed", ctx, startPtr);
2122
+ if (ctx.s.charCodeAt(ctx.p += 3) === 58)
2123
+ ctx.p += 3;
2124
+ if (ctx.s.charCodeAt(ctx.p) === 46)
2125
+ while (isDigit2(ctx.s.charCodeAt(++ctx.p)))
2126
+ ;
2127
+ if (c = ctx.s.charCodeAt(ctx.p)) {
2128
+ if (c === 90 || c === 122) {
2129
+ let t2 = ctx.s.slice(startPtr, ++ctx.p);
2130
+ return readDate(ctx, t2, 1, unsafeSeparator, startPtr, "[+00:00]");
2131
+ }
2132
+ if (c === 43 || c === 45) {
2133
+ let t2 = ctx.s.slice(startPtr, ctx.p += 6);
2134
+ return readDate(ctx, t2, 1, unsafeSeparator, startPtr, !ctx.ld && "[" + ctx.s.slice(ctx.p - 6, ctx.p) + "]");
2135
+ }
2136
+ }
2137
+ let t = ctx.s.slice(startPtr, ctx.p);
2138
+ return readDate(ctx, t, 2, unsafeSeparator, startPtr);
2139
+ }
2140
+ function parseTime(ctx, c, endChr) {
2141
+ let start = ctx.p;
2142
+ if (!isDigit2(c) || !isDigit2(ctx.s.charCodeAt(++ctx.p))) {
2143
+ return parseNumber(ctx, --ctx.p, c, 0, endChr);
2144
+ }
2145
+ if (ctx.s.charCodeAt(ctx.p += 4) === 58)
2146
+ ctx.p += 3;
2147
+ if (ctx.s.charCodeAt(ctx.p) === 46)
2148
+ while (isDigit2(ctx.s.charCodeAt(++ctx.p)))
2149
+ ;
2150
+ let t = ctx.s.slice(start, ctx.p);
2151
+ return readDate(ctx, t, 4, false, start);
2152
+ }
2153
+ function readDate(ctx, str, type, unsafeDelim, errPtr, temporalSuffix) {
2154
+ if (ctx.ld) {
2155
+ let date = new TomlDate(str, type, unsafeDelim);
2156
+ if (!date.isValid())
2157
+ TomlError.x("invalid date", ctx, errPtr);
2158
+ return date;
2159
+ }
2160
+ try {
2161
+ if (temporalSuffix)
2162
+ str += temporalSuffix;
2163
+ switch (type) {
2164
+ case 1:
2165
+ return Temporal.ZonedDateTime.from(str);
2166
+ case 2:
2167
+ return Temporal.PlainDateTime.from(str);
2168
+ case 3:
2169
+ return Temporal.PlainDate.from(str);
2170
+ case 4:
2171
+ return Temporal.PlainTime.from(str);
2172
+ }
2173
+ } catch (e) {
2174
+ TomlError.x(e instanceof Error ? e.message : "" + e, ctx, errPtr);
2175
+ }
2176
+ }
2177
+ var init_extract = __esm(() => {
2178
+ init_primitive();
2179
+ init_struct();
2180
+ init_error();
2181
+ init_date();
2182
+ /*!
2183
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2184
+ * SPDX-License-Identifier: BSD-3-Clause
2185
+ *
2186
+ * Redistribution and use in source and binary forms, with or without
2187
+ * modification, are permitted provided that the following conditions are met:
2188
+ *
2189
+ * 1. Redistributions of source code must retain the above copyright notice, this
2190
+ * list of conditions and the following disclaimer.
2191
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2192
+ * this list of conditions and the following disclaimer in the
2193
+ * documentation and/or other materials provided with the distribution.
2194
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2195
+ * may be used to endorse or promote products derived from this software without
2196
+ * specific prior written permission.
2197
+ *
2198
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2199
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2200
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2201
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2202
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2203
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2204
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2205
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2206
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2207
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2208
+ */
2209
+ });
2210
+
2211
+ // node_modules/smol-toml/dist/util.js
2212
+ function skipComment(ctx) {
2213
+ for (;ctx.p < ctx.s.length; ctx.p++) {
2214
+ let c = ctx.s.charCodeAt(ctx.p);
2215
+ if (c === 10)
2216
+ break;
2217
+ if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10) {
2218
+ ctx.p++;
2219
+ break;
2220
+ }
2221
+ if (c < 32 && c !== 9 || c === 127) {
2222
+ TomlError.x("control characters are not allowed in comments", ctx);
2223
+ }
2224
+ }
2225
+ }
2226
+ function skipVoid(ctx, banNewLines, banComments) {
2227
+ let c;
2228
+ while (ctx.p < ctx.s.length) {
2229
+ while (ctx.p < ctx.s.length && ((c = ctx.s.charCodeAt(ctx.p)) === 32 || c === 9 || !banNewLines && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)))
2230
+ ctx.p++;
2231
+ if (banComments || c !== 35)
2232
+ break;
2233
+ skipComment(ctx);
2234
+ }
2235
+ }
2236
+ var init_util = __esm(() => {
2237
+ init_error();
2238
+ /*!
2239
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2240
+ * SPDX-License-Identifier: BSD-3-Clause
2241
+ *
2242
+ * Redistribution and use in source and binary forms, with or without
2243
+ * modification, are permitted provided that the following conditions are met:
2244
+ *
2245
+ * 1. Redistributions of source code must retain the above copyright notice, this
2246
+ * list of conditions and the following disclaimer.
2247
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2248
+ * this list of conditions and the following disclaimer in the
2249
+ * documentation and/or other materials provided with the distribution.
2250
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2251
+ * may be used to endorse or promote products derived from this software without
2252
+ * specific prior written permission.
2253
+ *
2254
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2255
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2256
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2257
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2258
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2259
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2260
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2261
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2262
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2263
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2264
+ */
2265
+ });
2266
+
2267
+ // node_modules/smol-toml/dist/struct.js
2268
+ function parseKey(ctx, end = 61) {
2269
+ let startPtr;
2270
+ let state = 0;
2271
+ let parsed = [];
2272
+ let sliceStart;
2273
+ let c = ctx.s.charCodeAt(startPtr = ctx.p);
2274
+ do {
2275
+ if (c === end) {
2276
+ if (!state)
2277
+ TomlError.x("unexpected end of key", ctx);
2278
+ if (state === 1)
2279
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
2280
+ return ctx.p++, parsed;
2281
+ } else if (c === 46) {
2282
+ if (!state)
2283
+ TomlError.x("illegal empty bare key", ctx);
2284
+ if (state === 1)
2285
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
2286
+ state = 0;
2287
+ } else if (!state && (c === 34 || c === 39)) {
2288
+ if (c === ctx.s.charCodeAt(ctx.p + 1) && c === ctx.s.charCodeAt(ctx.p + 2))
2289
+ TomlError.x("illegal quoted key: multiline strings are not allowed", ctx);
2290
+ parsed.push(parseString(ctx));
2291
+ state = 2;
2292
+ ctx.p--;
2293
+ } else if (c === 32 || c === 9) {
2294
+ if (state === 1) {
2295
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
2296
+ state = 2;
2297
+ }
2298
+ } else if (state === 2 || c < 48 && c !== 45 || c > 57 && c < 65 || c > 90 && c < 97 && c !== 95 || c > 122) {
2299
+ TomlError.x("illegal character in key", ctx);
2300
+ } else if (!state) {
2301
+ state = 1;
2302
+ sliceStart = ctx.p;
2303
+ }
2304
+ } while (c = ctx.s.charCodeAt(++ctx.p));
2305
+ TomlError.x("incomplete key-value: cannot find end of key", ctx, startPtr);
2306
+ }
2307
+ function parseInlineTable(ctx) {
2308
+ let startPtr = ctx.p++;
2309
+ let res = Object.create(null);
2310
+ let seen = new Set;
2311
+ let c;
2312
+ while (ctx.p < ctx.s.length) {
2313
+ skipVoid(ctx);
2314
+ if ((c = ctx.s.charCodeAt(ctx.p)) === 125) {
2315
+ ctx.p++;
2316
+ return res;
2317
+ }
2318
+ let k;
2319
+ let t = res;
2320
+ let hasOwn = false;
2321
+ let errPtr = ctx.p;
2322
+ let key = parseKey(ctx);
2323
+ for (let i = 0;i < key.length; i++) {
2324
+ if (i)
2325
+ t = hasOwn ? t[k] : t[k] = Object.create(null);
2326
+ k = key[i];
2327
+ if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
2328
+ TomlError.x("trying to redefine an already defined value", ctx, errPtr);
2329
+ }
2330
+ let unsafe = k === "__proto__";
2331
+ if (ctx.uk && (unsafe || k === "constructor")) {
2332
+ t = ctx.uk !== 1 && TomlError.x("document contains an unsafe property", ctx, errPtr);
2333
+ break;
2334
+ }
2335
+ if (!hasOwn && unsafe) {
2336
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
2337
+ }
2338
+ }
2339
+ if (hasOwn) {
2340
+ TomlError.x("trying to redefine an already defined value", ctx, errPtr);
2341
+ }
2342
+ skipVoid(ctx, true, true);
2343
+ let value = extractValue(ctx, 125);
2344
+ if (t && typeof (t[k] = value) === "object")
2345
+ seen.add(value);
2346
+ skipVoid(ctx);
2347
+ if ((c = ctx.s.charCodeAt(ctx.p++)) === 125) {
2348
+ return res;
2349
+ }
2350
+ if (c !== 44)
2351
+ TomlError.x("expected comma or end of structure", ctx, ctx.p - 1);
2352
+ }
2353
+ TomlError.x("unfinished table", ctx, startPtr);
2354
+ }
2355
+ function parseArray(ctx) {
2356
+ let startPtr = ctx.p++;
2357
+ let res = [];
2358
+ let c;
2359
+ while (ctx.p < ctx.s.length) {
2360
+ skipVoid(ctx);
2361
+ if ((c = ctx.s.charCodeAt(ctx.p)) === 93) {
2362
+ ctx.p++;
2363
+ return res;
2364
+ }
2365
+ res.push(extractValue(ctx, 93));
2366
+ skipVoid(ctx);
2367
+ if ((c = ctx.s.charCodeAt(ctx.p++)) === 93) {
2368
+ return res;
2369
+ }
2370
+ if (c !== 44)
2371
+ TomlError.x("expected comma or end of structure", ctx, ctx.p - 1);
2372
+ }
2373
+ TomlError.x("unfinished array", ctx, startPtr);
2374
+ }
2375
+ var init_struct = __esm(() => {
2376
+ init_primitive();
2377
+ init_extract();
2378
+ init_util();
2379
+ init_error();
2380
+ /*!
2381
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2382
+ * SPDX-License-Identifier: BSD-3-Clause
2383
+ *
2384
+ * Redistribution and use in source and binary forms, with or without
2385
+ * modification, are permitted provided that the following conditions are met:
2386
+ *
2387
+ * 1. Redistributions of source code must retain the above copyright notice, this
2388
+ * list of conditions and the following disclaimer.
2389
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2390
+ * this list of conditions and the following disclaimer in the
2391
+ * documentation and/or other materials provided with the distribution.
2392
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2393
+ * may be used to endorse or promote products derived from this software without
2394
+ * specific prior written permission.
2395
+ *
2396
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2397
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2398
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2399
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2400
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2401
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2402
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2403
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2404
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2405
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2406
+ */
2407
+ });
2408
+
2409
+ // node_modules/smol-toml/dist/parse.js
2410
+ function peekTable(ctx, key, table, meta, type) {
2411
+ let t = table;
2412
+ let m = meta;
2413
+ let k;
2414
+ let hasOwn = false;
2415
+ let state;
2416
+ for (let i = 0;i < key.length; i++) {
2417
+ if (i) {
2418
+ t = hasOwn ? t[k] : t[k] = Object.create(null);
2419
+ m = (state = m[k]).c;
2420
+ if (type === 0 && (state.t === 1 || state.t === 2)) {
2421
+ return null;
2422
+ }
2423
+ if (state.t === 2) {
2424
+ let l = t.length - 1;
2425
+ t = t[l];
2426
+ m = m[l].c;
2427
+ }
2428
+ }
2429
+ k = key[i];
2430
+ if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
2431
+ return null;
2432
+ }
2433
+ if (!hasOwn) {
2434
+ let unsafe = k === "__proto__";
2435
+ if (ctx.uk && (unsafe || k === "constructor"))
2436
+ return false;
2437
+ if (unsafe) {
2438
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
2439
+ Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
2440
+ }
2441
+ m[k] = {
2442
+ t: i < key.length - 1 && type === 2 ? 3 : type,
2443
+ d: false,
2444
+ i: 0,
2445
+ c: Object.create(null)
2446
+ };
2447
+ }
2448
+ }
2449
+ state = m[k];
2450
+ if (state.t !== type && !(type === 1 && state.t === 3)) {
2451
+ return null;
2452
+ }
2453
+ if (type === 2) {
2454
+ if (!state.d) {
2455
+ state.d = true;
2456
+ t[k] = [];
2457
+ }
2458
+ t[k].push(t = Object.create(null));
2459
+ state.c[state.i++] = state = { t: 1, d: false, i: 0, c: Object.create(null) };
2460
+ }
2461
+ if (state.d) {
2462
+ return null;
2463
+ }
2464
+ state.d = true;
2465
+ if (type === 1) {
2466
+ t = hasOwn ? t[k] : t[k] = Object.create(null);
2467
+ } else if (type === 0 && hasOwn) {
2468
+ return null;
2469
+ }
2470
+ return [k, t, state.c];
2471
+ }
2472
+ function validateTablePeek(ctx, peek, ptr) {
2473
+ if (peek === null || ctx.uk === 2)
2474
+ TomlError.x(peek === null ? "trying to redefine an already defined table or value" : "document contains an unsafe property", ctx, ptr);
2475
+ }
2476
+ function parse3(toml, options = {}) {
2477
+ let ctx = {
2478
+ s: toml,
2479
+ p: 0,
2480
+ d: options.maxDepth ?? 1000,
2481
+ bi: options.integersAsBigInt ?? false,
2482
+ ld: options.useLegacyDate ?? true,
2483
+ uk: options.unsafeKeyBehaviour === "throw" ? 2 : options.unsafeKeyBehaviour === "drop" ? 1 : 0
2484
+ };
2485
+ let res = Object.create(null);
2486
+ let meta = Object.create(null);
2487
+ let tmp;
2488
+ let skipping = false;
2489
+ let tbl = res;
2490
+ let m = meta;
2491
+ if (toml.charCodeAt(0) === 65279)
2492
+ ctx.p++;
2493
+ skipVoid(ctx);
2494
+ while (ctx.p < toml.length) {
2495
+ if (toml.charCodeAt(ctx.p) === 91) {
2496
+ let isTableArray = toml.charCodeAt(++ctx.p) === 91;
2497
+ tmp = ctx.p += +isTableArray;
2498
+ skipping = false;
2499
+ let k = parseKey(ctx, 93);
2500
+ if (isTableArray) {
2501
+ if (toml.charCodeAt(ctx.p) !== 93) {
2502
+ TomlError.x("expected end of table array declaration", ctx);
2503
+ }
2504
+ ctx.p++;
2505
+ }
2506
+ let p = peekTable(ctx, k, res, meta, isTableArray ? 2 : 1);
2507
+ if (!p) {
2508
+ validateTablePeek(ctx, p, tmp);
2509
+ skipping = true;
2510
+ } else {
2511
+ m = p[2];
2512
+ tbl = p[1];
2513
+ }
2514
+ } else {
2515
+ tmp = ctx.p;
2516
+ let k = parseKey(ctx);
2517
+ let p = peekTable(ctx, k, tbl, m, 0);
2518
+ if (!p && !skipping)
2519
+ validateTablePeek(ctx, p, tmp);
2520
+ skipVoid(ctx, true, true);
2521
+ let v = extractValue(ctx, undefined);
2522
+ if (p && !skipping)
2523
+ p[1][p[0]] = v;
2524
+ }
2525
+ skipVoid(ctx, true);
2526
+ if (ctx.p < toml.length && (tmp = toml.charCodeAt(ctx.p)) !== 10 && (tmp !== 13 || toml.charCodeAt(ctx.p + 1) !== 10)) {
2527
+ TomlError.x("each key-value declaration must be followed by an end-of-line", ctx);
2528
+ }
2529
+ skipVoid(ctx);
2530
+ }
2531
+ return res;
2532
+ }
2533
+ var init_parse = __esm(() => {
2534
+ init_struct();
2535
+ init_extract();
2536
+ init_util();
2537
+ init_error();
2538
+ /*!
2539
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2540
+ * SPDX-License-Identifier: BSD-3-Clause
2541
+ *
2542
+ * Redistribution and use in source and binary forms, with or without
2543
+ * modification, are permitted provided that the following conditions are met:
2544
+ *
2545
+ * 1. Redistributions of source code must retain the above copyright notice, this
2546
+ * list of conditions and the following disclaimer.
2547
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2548
+ * this list of conditions and the following disclaimer in the
2549
+ * documentation and/or other materials provided with the distribution.
2550
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2551
+ * may be used to endorse or promote products derived from this software without
2552
+ * specific prior written permission.
2553
+ *
2554
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2555
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2556
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2557
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2558
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2559
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2560
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2561
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2562
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2563
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2564
+ */
2565
+ });
2566
+
2567
+ // node_modules/smol-toml/dist/stringify.js
2568
+ function extendedTypeOf(obj) {
2569
+ let type = typeof obj;
2570
+ if (type === "object") {
2571
+ if (Array.isArray(obj))
2572
+ return "array";
2573
+ if (typeof obj.getUTCDate === "function" && obj instanceof Date)
2574
+ return "date";
2575
+ if (globalThis.Temporal) {
2576
+ if (obj.until) {
2577
+ if (obj instanceof Temporal.ZonedDateTime)
2578
+ return "temporal/tz+uc";
2579
+ if (obj instanceof Temporal.PlainDateTime || obj instanceof Temporal.PlainDate)
2580
+ return "temporal/uc";
2581
+ if (obj instanceof Temporal.PlainTime || obj instanceof Temporal.Instant)
2582
+ return "temporal";
2583
+ if (obj instanceof Temporal.PlainYearMonth)
2584
+ return "temporal/x";
2585
+ } else if (obj.toPlainDate && obj instanceof Temporal.PlainMonthDay || obj.negated && obj instanceof Temporal.Duration) {
2586
+ return "temporal/x";
2587
+ }
2588
+ }
2589
+ }
2590
+ return type;
2591
+ }
2592
+ function isArrayOfTables(obj) {
2593
+ for (let i = 0;i < obj.length; i++) {
2594
+ if (extendedTypeOf(obj[i]) !== "object")
2595
+ return false;
2596
+ }
2597
+ return obj.length != 0;
2598
+ }
2599
+ function formatWellFormedStringUnchecked(s) {
2600
+ return JSON.stringify(s).replaceAll("", "\\u007f");
2601
+ }
2602
+ function formatString(s) {
2603
+ return formatWellFormedStringUnchecked(HAS_WELLFORMED ? s.toWellFormed() : s);
2604
+ }
2605
+ function formatKey(s) {
2606
+ if (BARE_KEY.test(s))
2607
+ return s;
2608
+ if (HAS_WELLFORMED && !s.isWellFormed())
2609
+ throw new RangeError("key contains illegal lone surrogates");
2610
+ return formatWellFormedStringUnchecked(s);
2611
+ }
2612
+ function stringifyValue(val, type, depth, numberAsFloat, strictTemporal) {
2613
+ if (depth === 0) {
2614
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
2615
+ }
2616
+ switch (type) {
2617
+ case "number":
2618
+ if (isNaN(val))
2619
+ return "nan";
2620
+ if (val === Infinity)
2621
+ return "inf";
2622
+ if (val === -Infinity)
2623
+ return "-inf";
2624
+ if (Number.isInteger(val) && (numberAsFloat || !Number.isSafeInteger(val)))
2625
+ return val.toFixed(1);
2626
+ case "bigint":
2627
+ case "boolean":
2628
+ case "temporal":
2629
+ return val.toString();
2630
+ case "string":
2631
+ return formatString(val);
2632
+ case "date":
2633
+ if (isNaN(val.getTime()))
2634
+ throw new TypeError("cannot serialize invalid date");
2635
+ return val.toISOString();
2636
+ case "object":
2637
+ return stringifyInlineTable(val, depth, numberAsFloat, strictTemporal);
2638
+ case "array":
2639
+ return stringifyArray(val, depth, numberAsFloat, strictTemporal);
2640
+ case "temporal/tz+uc":
2641
+ if (strictTemporal) {
2642
+ let tz = val.timeZoneId;
2643
+ let tzc = tz.charCodeAt(0);
2644
+ if (tzc !== 43 && tzc !== 45 && (tzc !== 85 && tzc !== 71 && tzc !== 90 && tzc !== 69 || tz !== "UTC" && tz !== "UCT" && tz !== "Universal" && tz !== "Zulu" && !tz.startsWith("GMT") && tz !== "Greenwich" && !tz.startsWith("Etc/"))) {
2645
+ throw new TypeError("Temporal objects with an IANA timezone are not allowed in Temporal strict mode");
2646
+ }
2647
+ }
2648
+ case "temporal/uc":
2649
+ if (strictTemporal && val.calendarId !== "iso8601")
2650
+ throw new TypeError("Temporal objects with a non-default calendar are not allowed in Temporal strict mode");
2651
+ return val.toString({
2652
+ calendarName: "never",
2653
+ timeZoneName: "never"
2654
+ });
2655
+ case "temporal/x":
2656
+ throw new TypeError("Unsupported " + val[Symbol.toStringTag]);
2657
+ }
2658
+ }
2659
+ function stringifyInlineTable(obj, depth, numberAsFloat, strictTemporal) {
2660
+ let keys = Object.keys(obj);
2661
+ if (keys.length === 0)
2662
+ return "{}";
2663
+ let res = "{ ";
2664
+ for (let i = 0;i < keys.length; i++) {
2665
+ let k = keys[i];
2666
+ if (i)
2667
+ res += ", ";
2668
+ res += formatKey(k) + " = " + stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat, strictTemporal);
2669
+ }
2670
+ return res + " }";
2671
+ }
2672
+ function stringifyArray(array2, depth, numberAsFloat, strictTemporal) {
2673
+ if (array2.length === 0)
2674
+ return "[]";
2675
+ let res = "[ ";
2676
+ for (let i = 0;i < array2.length; i++) {
2677
+ if (i)
2678
+ res += ", ";
2679
+ if (array2[i] === null || array2[i] === undefined) {
2680
+ throw new TypeError("arrays cannot contain null or undefined values");
2681
+ }
2682
+ res += stringifyValue(array2[i], extendedTypeOf(array2[i]), depth - 1, numberAsFloat, strictTemporal);
2683
+ }
2684
+ return res + " ]";
2685
+ }
2686
+ function stringifyArrayTable(array2, key, depth, numberAsFloat, strictTemporal) {
2687
+ if (depth === 0) {
2688
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
2689
+ }
2690
+ let res = "";
2691
+ for (let i = 0;i < array2.length; i++) {
2692
+ res += `${res && `
2693
+ `}[[${key}]]
2694
+ `;
2695
+ res += stringifyTable(0, array2[i], key, depth, numberAsFloat, strictTemporal);
2696
+ }
2697
+ return res;
2698
+ }
2699
+ function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat, strictTemporal) {
2700
+ if (depth === 0) {
2701
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
2702
+ }
2703
+ let preamble = "";
2704
+ let tables = "";
2705
+ let keys = Object.keys(obj);
2706
+ for (let i = 0;i < keys.length; i++) {
2707
+ let k = keys[i];
2708
+ if (obj[k] !== null && obj[k] !== undefined) {
2709
+ let type = extendedTypeOf(obj[k]);
2710
+ if (type === "symbol" || type === "function") {
2711
+ throw new TypeError(`cannot serialize values of type '${type}'`);
2712
+ }
2713
+ let key = formatKey(k);
2714
+ if (type === "array" && isArrayOfTables(obj[k])) {
2715
+ tables += (tables && `
2716
+ `) + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat, strictTemporal);
2717
+ } else if (type === "object") {
2718
+ let tblKey = prefix ? `${prefix}.${key}` : key;
2719
+ tables += (tables && `
2720
+ `) + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat, strictTemporal);
2721
+ } else {
2722
+ preamble += key;
2723
+ preamble += " = ";
2724
+ preamble += stringifyValue(obj[k], type, depth, numberAsFloat, strictTemporal);
2725
+ preamble += `
2726
+ `;
2727
+ }
2728
+ }
2729
+ }
2730
+ if (tableKey && (preamble || !tables))
2731
+ preamble = preamble ? `[${tableKey}]
2732
+ ${preamble}` : `[${tableKey}]`;
2733
+ return preamble && tables ? `${preamble}
2734
+ ${tables}` : preamble || tables;
2735
+ }
2736
+ function stringify(obj, { maxDepth = 1000, numbersAsFloat = false, strictTemporal = false } = {}) {
2737
+ if (extendedTypeOf(obj) !== "object") {
2738
+ throw new TypeError("stringify can only be called with an object");
2739
+ }
2740
+ let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat, strictTemporal);
2741
+ if (str[str.length - 1] !== `
2742
+ `)
2743
+ return str + `
2744
+ `;
2745
+ return str;
2746
+ }
2747
+ var BARE_KEY, HAS_WELLFORMED;
2748
+ var init_stringify = __esm(() => {
2749
+ /*!
2750
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2751
+ * SPDX-License-Identifier: BSD-3-Clause
2752
+ *
2753
+ * Redistribution and use in source and binary forms, with or without
2754
+ * modification, are permitted provided that the following conditions are met:
2755
+ *
2756
+ * 1. Redistributions of source code must retain the above copyright notice, this
2757
+ * list of conditions and the following disclaimer.
2758
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2759
+ * this list of conditions and the following disclaimer in the
2760
+ * documentation and/or other materials provided with the distribution.
2761
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2762
+ * may be used to endorse or promote products derived from this software without
2763
+ * specific prior written permission.
2764
+ *
2765
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2766
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2767
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2768
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2769
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2770
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2771
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2772
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2773
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2774
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2775
+ */
2776
+ BARE_KEY = /^[a-z0-9-_]+$/i;
2777
+ HAS_WELLFORMED = !!"".isWellFormed;
2778
+ });
2779
+
2780
+ // node_modules/smol-toml/dist/index.js
2781
+ var init_dist = __esm(() => {
2782
+ init_parse();
2783
+ init_stringify();
2784
+ init_date();
2785
+ init_error();
2786
+ /*!
2787
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2788
+ * SPDX-License-Identifier: BSD-3-Clause
2789
+ *
2790
+ * Redistribution and use in source and binary forms, with or without
2791
+ * modification, are permitted provided that the following conditions are met:
2792
+ *
2793
+ * 1. Redistributions of source code must retain the above copyright notice, this
2794
+ * list of conditions and the following disclaimer.
2795
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2796
+ * this list of conditions and the following disclaimer in the
2797
+ * documentation and/or other materials provided with the distribution.
2798
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2799
+ * may be used to endorse or promote products derived from this software without
2800
+ * specific prior written permission.
2801
+ *
2802
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2803
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2804
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2805
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2806
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2807
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2808
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2809
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2810
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2811
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2812
+ */
2813
+ });
2814
+
2815
+ // src/installer/formats/toml.ts
2816
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
2817
+ function loadToml(file) {
2818
+ if (!existsSync3(file))
2819
+ return { exists: false, text: "", value: {}, lossy: false };
2820
+ const text = readFileSync3(file, "utf8");
2821
+ try {
2822
+ return { exists: true, text, value: parse3(text), lossy: hasTomlComment(text) };
2823
+ } catch (error) {
2824
+ const parseError = error instanceof Error ? error.message : String(error);
2825
+ return { exists: true, text, value: {}, lossy: false, parseError };
2826
+ }
2827
+ }
2828
+ function hasTomlComment(text) {
2829
+ let inBasic = false;
2830
+ let inLiteral = false;
2831
+ for (let i = 0;i < text.length; i += 1) {
2832
+ const ch = text[i];
2833
+ if (inBasic) {
2834
+ if (ch === "\\")
2835
+ i += 1;
2836
+ else if (ch === '"')
2837
+ inBasic = false;
2838
+ continue;
2839
+ }
2840
+ if (inLiteral) {
2841
+ if (ch === "'")
2842
+ inLiteral = false;
2843
+ continue;
2844
+ }
2845
+ if (ch === '"')
2846
+ inBasic = true;
2847
+ else if (ch === "'")
2848
+ inLiteral = true;
2849
+ else if (ch === "#")
2850
+ return true;
2851
+ }
2852
+ return false;
2853
+ }
2854
+ function serializeToml(value) {
2855
+ return `${stringify(value)}
2856
+ `;
2857
+ }
2858
+ function applyTomlOps(value, ops) {
2859
+ const target = structuredClone(value);
2860
+ const recorded = [];
2861
+ const createdParents = [];
2862
+ for (const op of ops) {
2863
+ const parent = navigate(target, op.path, createdParents);
2864
+ const key = op.path[op.path.length - 1];
2865
+ if (op.op === "set") {
2866
+ const previous = Object.prototype.hasOwnProperty.call(parent, key) ? parent[key] : undefined;
2867
+ parent[key] = structuredClone(op.value);
2868
+ recorded.push({ op: "set", path: op.path, applied: structuredClone(op.value), previous });
2869
+ continue;
2870
+ }
2871
+ const existing = parent[key];
2872
+ if (existing === undefined)
2873
+ createdParents.push(op.path);
2874
+ const { list, appended } = appendEntries(existing, op.entries ?? [], op.path);
2875
+ parent[key] = [...list, ...appended.map((entry) => structuredClone(entry))];
2876
+ recorded.push({ op: "append-array", path: op.path, applied: appended, previous: undefined });
2877
+ }
2878
+ return { value: target, recorded, createdParents };
2879
+ }
2880
+ function navigate(root, path, created) {
2881
+ let node = root;
2882
+ for (let depth = 0;depth < path.length - 1; depth += 1) {
2883
+ const key = path[depth];
2884
+ const next = node[key];
2885
+ if (next === undefined) {
2886
+ node[key] = {};
2887
+ created.push(path.slice(0, depth + 1));
2888
+ } else if (!isPlainObject(next)) {
2889
+ throw new Error(`cannot descend into ${path.slice(0, depth + 1).join(".")}: it is ${Array.isArray(next) ? "an array" : `a ${typeof next}`}, not a table`);
2890
+ }
2891
+ node = node[key];
2892
+ }
2893
+ return node;
2894
+ }
2895
+ function revertTomlOps(value, ops) {
2896
+ const notes = [];
2897
+ for (const record of [...ops].reverse()) {
2898
+ if (record.op === "set") {
2899
+ const now = valueAt(value, record.path);
2900
+ if (now === undefined)
2901
+ continue;
2902
+ if (!deepEqual(now, record.applied)) {
2903
+ notes.push(`${record.path.join(".")}: current value differs from what the installer wrote; left untouched`);
2904
+ continue;
2905
+ }
2906
+ if (record.previous === undefined) {
2907
+ removeAt(value, record.path);
2908
+ } else {
2909
+ setValueAt(value, record.path, record.previous);
2910
+ }
2911
+ } else {
2912
+ const entries = Array.isArray(record.applied) ? record.applied : [];
2913
+ for (const entry of entries) {
2914
+ const list = valueAt(value, record.path);
2915
+ if (!Array.isArray(list))
2916
+ continue;
2917
+ const index = list.findIndex((item) => deepEqual(item, entry));
2918
+ if (index === -1)
2919
+ continue;
2920
+ list.splice(index, 1);
2921
+ }
2922
+ }
2923
+ }
2924
+ return notes;
2925
+ }
2926
+ function pruneCreatedParents(value, parents) {
2927
+ for (const parent of [...parents].reverse()) {
2928
+ const current = valueAt(value, parent);
2929
+ if (isPlainObject(current) && Object.keys(current).length === 0)
2930
+ removeAt(value, parent);
2931
+ }
2932
+ }
2933
+ function setValueAt(value, path, replacement) {
2934
+ const parent = valueAt(value, path.slice(0, -1));
2935
+ if (isPlainObject(parent))
2936
+ parent[path[path.length - 1]] = replacement;
2937
+ }
2938
+ function tomlOpHolds(text, op) {
2939
+ const value = parse3(text);
2940
+ const current = valueAt(value, op.path);
2941
+ if (op.op === "set")
2942
+ return deepEqual(current, op.value);
2943
+ return Array.isArray(current) && (op.entries ?? []).every((entry) => current.some((item) => deepEqual(item, entry)));
2944
+ }
2945
+ var tomlCodec;
2946
+ var init_toml = __esm(() => {
2947
+ init_dist();
2948
+ tomlCodec = {
2949
+ format: "toml",
2950
+ load: loadToml,
2951
+ apply: (text, edit2) => {
2952
+ if (edit2.format !== "toml")
2953
+ throw new Error(`toml codec cannot apply a ${edit2.format} edit`);
2954
+ const result = applyTomlOps(parse3(text), edit2.ops);
2955
+ return { text: serializeToml(result.value), recorded: result.recorded, createdParents: result.createdParents };
2956
+ },
2957
+ verify: (text, edit2, op) => {
2958
+ if (edit2.format !== "toml")
2959
+ throw new Error(`toml codec cannot verify a ${edit2.format} edit`);
2960
+ const ops = op === undefined ? edit2.ops : [op];
2961
+ return ops.every((candidate) => tomlOpHolds(text, candidate));
2962
+ },
2963
+ revert: (text, recorded) => {
2964
+ const value = parse3(text);
2965
+ const notes = revertTomlOps(value, recorded.ops);
2966
+ pruneCreatedParents(value, recorded.createdParents ?? []);
2967
+ return { text: serializeToml(value), notes };
2968
+ },
2969
+ isEffectivelyEmpty: (text) => Object.keys(parse3(text)).length === 0
2970
+ };
2971
+ });
2972
+
2973
+ // src/installer/formats/index.ts
2974
+ import { mkdirSync, writeFileSync } from "node:fs";
2975
+ import { dirname } from "node:path";
2976
+ function writeConfig(file, serialized) {
2977
+ mkdirSync(dirname(file), { recursive: true });
2978
+ writeFileSync(file, serialized);
2979
+ }
2980
+ function codecFor(format2, host) {
2981
+ if (format2 === "json")
2982
+ return jsonCodec;
2983
+ if (format2 === "toml")
2984
+ return tomlCodec;
2985
+ return rulesCodec(host);
2986
+ }
2987
+ var init_formats = __esm(() => {
2988
+ init_json();
2989
+ init_rules();
2990
+ init_toml();
2991
+ });
2992
+
2993
+ // src/installer/detect.ts
2994
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
2995
+ function replacingExistingEntryNote(path) {
2996
+ return `An existing ${path} entry is being replaced; its previous form is recorded for uninstall.`;
2997
+ }
2998
+ function othersStayRegisteredNote(others) {
2999
+ return `Other MCP servers stay registered (${others.join(", ")}); routing to DeepSeek is not exclusive while they offer web tools.`;
3000
+ }
3001
+ function looksWebCapable(name, entry) {
3002
+ if (WEB_TOOL_HINT.test(name))
3003
+ return true;
3004
+ if (!isPlainObject(entry))
3005
+ return false;
3006
+ const command = typeof entry.command === "string" ? entry.command : "";
3007
+ const url = typeof entry.url === "string" ? entry.url : "";
3008
+ const args = Array.isArray(entry.args) ? entry.args.filter((arg) => typeof arg === "string").join(" ") : "";
3009
+ return WEB_TOOL_HINT.test(`${command} ${args} ${url}`);
3010
+ }
3011
+ function findCompetitorSteering(host, file) {
3012
+ if (!existsSync4(file))
3013
+ return [];
3014
+ let text;
3015
+ try {
3016
+ text = readFileSync4(file, "utf8");
3017
+ } catch {
3018
+ return [];
3019
+ }
3020
+ return removeBlock(host, text).split(`
3021
+ `).map((line) => line.trim()).filter((line) => line.length > 0 && STEERING_HINT.test(line) && !line.includes("deepseek")).slice(0, 2);
3022
+ }
3023
+ function competitorSteeringNote(file, lines) {
3024
+ const quoted = lines.map((line) => `"${line}"`).join(", ");
3025
+ return `Existing rules in ${file} steer toward other web tools (${quoted}); the plan surfaces this conflict — it does not resolve it.`;
3026
+ }
3027
+ function splitCompetitors(servers) {
3028
+ const competitors = [];
3029
+ const bystanders = [];
3030
+ for (const [name, entry] of Object.entries(servers)) {
3031
+ if (name === "deepseek")
3032
+ continue;
3033
+ (looksWebCapable(name, entry) ? competitors : bystanders).push(name);
3034
+ }
3035
+ return { competitors, bystanders };
3036
+ }
3037
+ var BOTH_CAPABILITIES_OFF = "Both capabilities are off; nothing would be installed.", FORCED_COST_NOTE, WEB_TOOL_HINT, STEERING_HINT;
3038
+ var init_detect = __esm(() => {
3039
+ init_rules();
3040
+ FORCED_COST_NOTE = "Forced routing is deterministic, and Search and Fetch are billed per successful request — " + `see the README's "Privacy and cost" section before applying.`;
3041
+ WEB_TOOL_HINT = /(web[_ -]?(search|fetch)|search|fetch|browse|scrape|crawl|tavily|brave|exa|perplexity|firecrawl|jina|serp|duckduckgo|reader)/i;
3042
+ STEERING_HINT = /(web[_ ]?(search|fetch)|websearch|webfetch|tavily|exa|brave|perplexity|firecrawl|jina|serp|duckduckgo|google|bing)/i;
3043
+ });
3044
+
3045
+ // src/installer/paths.ts
3046
+ function join(...parts) {
3047
+ return parts.filter((part) => part.length > 0).join("/");
3048
+ }
3049
+ function configHome(roots) {
3050
+ return roots.configHome ?? join(roots.home, ".config");
3051
+ }
3052
+ function stateDir(roots, scope) {
3053
+ return scope === "global" ? join(configHome(roots), "deepseek-web-retrieval") : join(roots.cwd, ".deepseek-web-retrieval");
3054
+ }
3055
+
3056
+ // src/installer/rulesContent.ts
3057
+ function rulesLines(ids, search, fetch) {
3058
+ const lines = ["DeepSeek retrieval guidance:"];
3059
+ if (search !== "off") {
3060
+ lines.push(`- Use ${ids.search} when the task needs fresh external information: current docs, version numbers,`, " changelogs, or anything you cannot know from the repository alone. Do not search for facts already", " present locally.");
3061
+ }
3062
+ if (fetch !== "off") {
3063
+ lines.push(`- Use ${ids.fetch} to read a specific public web page as Markdown when its content is needed.`);
3064
+ }
3065
+ lines.push("- Never send localhost or private-network URLs to the DeepSeek tools; use local tools for those (the", " server blocks private hosts by default).", "- DeepSeek requests are billed per successful call; retrieve only what the task needs.");
3066
+ return lines;
3067
+ }
3068
+ var MCP_TOOL_IDS;
3069
+ var init_rulesContent = __esm(() => {
3070
+ MCP_TOOL_IDS = { search: "mcp__deepseek__deepseek_web_search", fetch: "mcp__deepseek__deepseek_fetch" };
3071
+ });
3072
+
3073
+ // src/installer/hosts/shared.ts
3074
+ function planHeader(input, paths, loaded, dialect) {
3075
+ const notes = [];
3076
+ const errors = [];
3077
+ if (loaded.parseError) {
3078
+ errors.push({ message: `${paths.config} exists but does not parse as ${dialect}: ${loaded.parseError}` });
3079
+ return { notes, errors, abort: true };
3080
+ }
3081
+ if (input.search === "off" && input.fetch === "off") {
3082
+ errors.push({ message: BOTH_CAPABILITIES_OFF });
3083
+ }
3084
+ const steering = findCompetitorSteering(input.host, paths.rules);
3085
+ if (steering.length > 0)
3086
+ notes.push(competitorSteeringNote(paths.rules, steering));
3087
+ return { notes, errors, abort: false };
3088
+ }
3089
+ var init_shared = __esm(() => {
3090
+ init_detect();
3091
+ });
3092
+
3093
+ // src/installer/hosts/codex.ts
3094
+ function codexPaths(input) {
3095
+ return {
3096
+ config: join(input.home, ".codex/config.toml"),
3097
+ rules: input.scope === "global" ? join(input.home, ".codex/AGENTS.md") : join(input.cwd, "AGENTS.md")
3098
+ };
3099
+ }
3100
+ function planCodex(input, _previous) {
3101
+ const paths = codexPaths(input);
3102
+ const loaded = codecFor("toml", input.host).load(paths.config);
3103
+ const tiers = { search: input.search, fetch: input.fetch };
3104
+ const header = planHeader(input, paths, loaded, "TOML");
3105
+ if (header.abort) {
3106
+ return { host: "codex", scope: input.scope, tiers, edits: [], notes: header.notes, errors: header.errors };
3107
+ }
3108
+ const notes = [...header.notes];
3109
+ const errors = [...header.errors];
3110
+ const edits = [];
3111
+ const tools = loaded.value.tools;
3112
+ if (isPlainObject(tools) && "web_search" in tools) {
3113
+ errors.push({
3114
+ message: `${paths.config} sets [tools] web_search, which is a silent no-op at Codex 0.163.0 (only the top-level ` + "web_search key controls the tool). Remove it first so the config cannot mislead."
3115
+ });
3116
+ }
3117
+ const servers = loaded.value.mcp_servers;
3118
+ if (isPlainObject(servers)) {
3119
+ if ("deepseek" in servers)
3120
+ notes.push(replacingExistingEntryNote("mcp_servers.deepseek"));
3121
+ const { competitors, bystanders } = splitCompetitors(servers);
3122
+ if ((input.search === "forced" || input.fetch === "forced") && competitors.length > 0) {
3123
+ errors.push({
3124
+ message: `Forced cannot deliver exclusive routing: [mcp_servers.${competitors.join("], [mcp_servers.")}] look(s) web-capable, ` + "and Codex offers no per-server kill switch. Remove the server(s), disable their tools by hand via their " + "disabled_tools key, or choose a lower tier."
3125
+ });
3126
+ }
3127
+ const stayRegistered = input.search === "forced" || input.fetch === "forced" ? bystanders : [...competitors, ...bystanders];
3128
+ if (stayRegistered.length > 0)
3129
+ notes.push(othersStayRegisteredNote(stayRegistered));
3130
+ }
3131
+ const env = {};
3132
+ if (input.search === "off")
3133
+ env[ENABLE_SEARCH_ENV] = "false";
3134
+ if (input.fetch === "off")
3135
+ env[ENABLE_FETCH_ENV] = "false";
3136
+ const entry = {
3137
+ command: "npx",
3138
+ args: ["-y", input.packageRef],
3139
+ ...Object.keys(env).length > 0 ? { env } : {},
3140
+ env_vars: [API_KEY_ENV]
3141
+ };
3142
+ const existingEntry = isPlainObject(servers) ? servers.deepseek : undefined;
3143
+ const ops = [
3144
+ { op: "set", path: ["mcp_servers", "deepseek"], value: entry, previous: existingEntry }
3145
+ ];
3146
+ if (input.search === "forced") {
3147
+ const previous = typeof loaded.value.web_search === "string" ? loaded.value.web_search : undefined;
3148
+ ops.push({ op: "set", path: ["web_search"], value: "disabled", previous });
3149
+ notes.push(previous === undefined ? 'web_search is being set to "disabled" (no previous value existed; the default is "cached").' : `web_search is being set to "disabled"; the previous value "${previous}" is snapshotted for uninstall.`);
3150
+ }
3151
+ edits.push({ file: paths.config, format: "toml", ops });
3152
+ notes.push(`Codex stdio children do not inherit the parent environment, so the entry forwards ${API_KEY_ENV} explicitly ` + "via env_vars; the key must be set in the shell that launches Codex.");
3153
+ if (input.scope === "project") {
3154
+ notes.push("Codex config lives in ~/.codex/config.toml only (user level), so the server registration and kill switch are " + "written there even for a project-scope install; the rules file stays project-local.");
3155
+ }
3156
+ if (loaded.lossy) {
3157
+ notes.push(`${paths.config} contains comments; the TOML rewrite will drop them.`);
3158
+ }
3159
+ if (input.search === "forced" || input.fetch === "forced") {
3160
+ notes.push('Forced search is exclusion: the built-in web_search tool is disabled ("disabled" mode). ' + FORCED_COST_NOTE);
3161
+ }
3162
+ if (input.search === "optional" || input.fetch === "optional") {
3163
+ notes.push('Note: Codex ships a built-in web_search tool (default "cached" mode, an OpenAI index) that stays available ' + "alongside the DeepSeek tools under the optional tier.");
3164
+ }
3165
+ if (input.search === "preferred" || input.fetch === "preferred") {
3166
+ edits.push({
3167
+ file: paths.rules,
3168
+ format: "rules",
3169
+ block: buildRulesBlock(input.host, rulesLines(MCP_TOOL_IDS, input.search, input.fetch))
3170
+ });
3171
+ notes.push(input.scope === "global" ? `Rules block upserted in ${paths.rules}; Codex reads ~/.codex/AGENTS.md plus every AGENTS.md from the project root to the cwd.` : `Rules block upserted in ${paths.rules}; Codex reads every AGENTS.md from the project root to the cwd.`);
3172
+ }
3173
+ return { host: "codex", scope: input.scope, tiers, edits, notes, errors };
3174
+ }
3175
+ var init_codex = __esm(() => {
3176
+ init_formats();
3177
+ init_detect();
3178
+ init_constants();
3179
+ init_rules();
3180
+ init_rulesContent();
3181
+ init_shared();
3182
+ });
3183
+
3184
+ // src/installer/hosts/opencode.ts
3185
+ function opencodePaths(input) {
3186
+ return input.scope === "global" ? { config: join(configHome(input), "opencode/opencode.jsonc"), rules: join(configHome(input), "opencode/AGENTS.md") } : { config: join(input.cwd, "opencode.jsonc"), rules: join(input.cwd, "AGENTS.md") };
3187
+ }
3188
+ function planOpenCode(input, previous) {
3189
+ const paths = opencodePaths(input);
3190
+ const loaded = codecFor("json", input.host).load(paths.config);
3191
+ const tiers = { search: input.search, fetch: input.fetch };
3192
+ const header = planHeader(input, paths, loaded, "JSONC");
3193
+ if (header.abort) {
3194
+ return { host: "opencode", scope: input.scope, tiers, edits: [], notes: header.notes, errors: header.errors };
3195
+ }
3196
+ const notes = [...header.notes];
3197
+ const errors = [...header.errors];
3198
+ const edits = [];
3199
+ if (input.search === "preferred") {
3200
+ errors.push({
3201
+ message: "OpenCode search has no preferred tier: the websearch provider is host-level config, so the model never " + "chooses between engines. Use --search optional (provider registered, built-in stays default), " + "--search forced (replace the engine), or --search off."
3202
+ });
3203
+ }
3204
+ const plugins = Array.isArray(loaded.value.plugins) ? loaded.value.plugins : [];
3205
+ const alreadyInstalled = plugins.some((entry) => isPlainObject(entry) && typeof entry.package === "string" && entry.package.includes("deepseek-web-retrieval"));
3206
+ if (alreadyInstalled && previous === undefined) {
3207
+ errors.push({
3208
+ message: `${paths.config} already has a plugins entry referencing deepseek-web-retrieval that this installer did not ` + "write. Remove it (or run uninstall if it came from a previous init), then retry."
3209
+ });
3210
+ }
3211
+ if (alreadyInstalled && errors.length === 0) {
3212
+ notes.push("A previous init wrote the plugins entry; re-applying updates it and carries the original snapshots over.");
3213
+ }
3214
+ if (errors.length > 0) {
3215
+ return { host: "opencode", scope: input.scope, tiers, edits, notes, errors };
3216
+ }
3217
+ const options = {};
3218
+ if (input.search === "forced")
3219
+ options.setDefaultWebsearch = true;
3220
+ if (input.search === "off")
3221
+ options.searchEnabled = false;
3222
+ if (input.fetch === "forced")
3223
+ options.fetchOverrideWebfetch = true;
3224
+ if (input.fetch === "off")
3225
+ options.fetchEnabled = false;
3226
+ const ops = [
3227
+ {
3228
+ op: "append-array",
3229
+ path: ["plugins"],
3230
+ entries: [{ package: input.packageRef, options }],
3231
+ existingCount: plugins.length
3232
+ }
3233
+ ];
3234
+ const permissions = [];
3235
+ if (input.search !== "off")
3236
+ permissions.push({ action: "websearch", resource: "*", effect: "allow" });
3237
+ if (input.fetch !== "off")
3238
+ permissions.push({ action: "deepseek_fetch", resource: "*", effect: "allow" });
3239
+ if (input.fetch === "forced")
3240
+ permissions.push({ action: "webfetch", resource: "*", effect: "allow" });
3241
+ const existingPermissions = Array.isArray(loaded.value.permissions) ? loaded.value.permissions.length : 0;
3242
+ if (permissions.length > 0) {
3243
+ ops.push({ op: "append-array", path: ["permissions"], entries: permissions, existingCount: existingPermissions });
3244
+ }
3245
+ if (input.search === "forced") {
3246
+ const currentProvider = isPlainObject(loaded.value.websearch) ? loaded.value.websearch.provider : undefined;
3247
+ ops.push({ op: "set", path: ["websearch", "provider"], value: "deepseek", previous: currentProvider });
3248
+ notes.push(currentProvider === undefined ? "websearch.provider is being set to deepseek (no previous value existed)." : `websearch.provider is being set to deepseek; the previous value "${String(currentProvider)}" is snapshotted for uninstall.`);
3249
+ }
3250
+ edits.push({ file: paths.config, format: "json", ops });
3251
+ notes.push("The plugin entry uses the object form so options are honored; auto-discovered plugins cannot receive options.");
3252
+ if (input.search === "optional") {
3253
+ notes.push("Search tier optional: the deepseek provider is registered but the built-in provider stays the default engine; " + "set websearch.provider to deepseek (or rerun with --search forced) to route search through DeepSeek.");
3254
+ }
3255
+ if (input.search === "forced" || input.fetch === "forced") {
3256
+ notes.push("Forced tier replaces built-in routing. " + FORCED_COST_NOTE);
3257
+ }
3258
+ if (input.fetch === "preferred") {
3259
+ edits.push({
3260
+ file: paths.rules,
3261
+ format: "rules",
3262
+ block: buildRulesBlock(input.host, rulesLines(OPENCODE_TOOL_IDS, input.search, input.fetch))
3263
+ });
3264
+ notes.push(`Rules block upserted in ${paths.rules}; OpenCode loads AGENTS.md only (no CLAUDE.md fallback in v2).`);
3265
+ }
3266
+ return { host: "opencode", scope: input.scope, tiers, edits, notes, errors };
3267
+ }
3268
+ var OPENCODE_TOOL_IDS;
3269
+ var init_opencode = __esm(() => {
3270
+ init_formats();
3271
+ init_detect();
3272
+ init_rules();
3273
+ init_rulesContent();
3274
+ init_shared();
3275
+ OPENCODE_TOOL_IDS = { search: "websearch (provider deepseek)", fetch: "deepseek_fetch" };
3276
+ });
3277
+
3278
+ // src/installer/hosts/pi.ts
3279
+ function piPaths(input) {
3280
+ return input.scope === "global" ? { config: join(input.home, ".pi/agent/mcp.json"), rules: join(input.home, ".pi/agent/AGENTS.md") } : { config: join(input.cwd, ".pi/mcp.json"), rules: join(input.cwd, "AGENTS.md") };
3281
+ }
3282
+ function planPi(input, _previous) {
3283
+ const paths = piPaths(input);
3284
+ const loaded = codecFor("json", input.host).load(paths.config);
3285
+ const tiers = { search: input.search, fetch: input.fetch };
3286
+ const header = planHeader(input, paths, loaded, "JSON");
3287
+ if (header.abort) {
3288
+ return { host: "pi", scope: input.scope, tiers, edits: [], notes: header.notes, errors: header.errors };
3289
+ }
3290
+ const notes = [...header.notes];
3291
+ const errors = [...header.errors];
3292
+ const edits = [];
3293
+ const env = { [API_KEY_ENV]: `\${${API_KEY_ENV}}` };
3294
+ if (input.search === "off")
3295
+ env[ENABLE_SEARCH_ENV] = "false";
3296
+ if (input.fetch === "off")
3297
+ env[ENABLE_FETCH_ENV] = "false";
3298
+ const entry = {
3299
+ command: "npx",
3300
+ args: ["-y", input.packageRef],
3301
+ env,
3302
+ exposure: "direct",
3303
+ enabled: true
3304
+ };
3305
+ const servers = loaded.value.mcpServers;
3306
+ const existingEntry = isPlainObject(servers) ? servers.deepseek : undefined;
3307
+ const ops = [
3308
+ { op: "set", path: ["mcpServers", "deepseek"], value: entry, previous: existingEntry }
3309
+ ];
3310
+ edits.push({ file: paths.config, format: "json", ops });
3311
+ if (isPlainObject(servers)) {
3312
+ if (servers.deepseek !== undefined)
3313
+ notes.push(replacingExistingEntryNote("mcpServers.deepseek"));
3314
+ const { competitors, bystanders } = splitCompetitors(servers);
3315
+ const forced = input.search === "forced" || input.fetch === "forced";
3316
+ if (forced) {
3317
+ const excluded = [];
3318
+ const unexcludable = [];
3319
+ for (const name of competitors) {
3320
+ const current = servers[name];
3321
+ if (!isPlainObject(current)) {
3322
+ unexcludable.push(name);
3323
+ continue;
3324
+ }
3325
+ const previous = typeof current.enabled === "boolean" ? current.enabled : undefined;
3326
+ if (previous === false)
3327
+ continue;
3328
+ ops.push({ op: "set", path: ["mcpServers", name, "enabled"], value: false, previous });
3329
+ excluded.push(name);
3330
+ }
3331
+ if (excluded.length > 0) {
3332
+ notes.push(`Forced tier: web-capable MCP servers are disabled so DeepSeek routing is exclusive (${excluded.join(", ")}; ` + "prior enabled values are snapshotted for uninstall).");
3333
+ }
3334
+ if (unexcludable.length > 0) {
3335
+ errors.push({
3336
+ message: `Forced cannot deliver exclusive routing: mcpServers entries ${unexcludable.join(", ")} look web-capable ` + "but are not objects, so the plan cannot set their enabled key. Fix or remove them, or choose a lower tier."
3337
+ });
3338
+ }
3339
+ }
3340
+ const stayRegistered = forced ? bystanders : [...competitors, ...bystanders];
3341
+ if (stayRegistered.length > 0)
3342
+ notes.push(othersStayRegisteredNote(stayRegistered));
3343
+ }
3344
+ notes.push('"exposure": "direct" is required: Pi 1.3.0 defaults MCP tools to codemode, which hides them from the model.');
3345
+ notes.push(`\`${API_KEY_ENV}\` is written as "\${${API_KEY_ENV}}" so the key expands from the shell that launches Pi and stays out of the file.`);
3346
+ if (loaded.lossy) {
3347
+ notes.push(`${paths.config} contains comments; the JSON edit preserves them.`);
3348
+ }
3349
+ if (input.search === "preferred" || input.fetch === "preferred") {
3350
+ edits.push({
3351
+ file: paths.rules,
3352
+ format: "rules",
3353
+ block: buildRulesBlock(input.host, rulesLines(MCP_TOOL_IDS, input.search, input.fetch))
3354
+ });
3355
+ notes.push(`Rules block upserted in ${paths.rules}; Pi loads AGENTS.md context files from the working directory and its parents.`);
3356
+ }
3357
+ if (input.search === "forced" || input.fetch === "forced") {
3358
+ notes.push("Forced tier: Pi 1.3.0 ships no built-in web tool, so the registered tools are the only web path (de-facto). " + FORCED_COST_NOTE);
3359
+ }
3360
+ return { host: "pi", scope: input.scope, tiers, edits, notes, errors };
3361
+ }
3362
+ var init_pi = __esm(() => {
3363
+ init_formats();
3364
+ init_detect();
3365
+ init_constants();
3366
+ init_rules();
3367
+ init_rulesContent();
3368
+ init_shared();
3369
+ });
3370
+
3371
+ // src/installer/state.ts
3372
+ import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5, readdirSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
3373
+ import { join as join2 } from "node:path";
3374
+ function statePathFor(input) {
3375
+ return join2(stateDir(input, input.scope), `install.${input.host}.json`);
3376
+ }
3377
+ function readRecord(input) {
3378
+ const file = statePathFor(input);
3379
+ if (!existsSync5(file))
3380
+ return;
3381
+ try {
3382
+ return JSON.parse(readFileSync5(file, "utf8"));
3383
+ } catch {
3384
+ return;
3385
+ }
3386
+ }
3387
+ function claimedByOtherScope(input, files) {
3388
+ const other = input.scope === "global" ? "project" : "global";
3389
+ const record = readRecord({ ...input, scope: other });
3390
+ if (record === undefined)
3391
+ return [];
3392
+ return files.filter((file) => record.files.some((candidate) => candidate.file === file));
3393
+ }
3394
+ function writeRecord(input, record) {
3395
+ const file = statePathFor(input);
3396
+ mkdirSync2(join2(file, ".."), { recursive: true });
3397
+ writeFileSync2(file, `${JSON.stringify(record, null, 2)}
3398
+ `, { mode: 384 });
3399
+ chmodSync(file, 384);
3400
+ }
3401
+ function deleteRecord(input) {
3402
+ const file = statePathFor(input);
3403
+ if (existsSync5(file))
3404
+ rmSync(file);
3405
+ }
3406
+ function listRecords(roots) {
3407
+ const records = [];
3408
+ for (const scope of ["global", "project"]) {
3409
+ const dir = stateDir(roots, scope);
3410
+ if (!existsSync5(dir))
3411
+ continue;
3412
+ for (const name of readdirSync(dir)) {
3413
+ if (!name.startsWith("install.") || !name.endsWith(".json"))
3414
+ continue;
3415
+ try {
3416
+ records.push(JSON.parse(readFileSync5(join2(dir, name), "utf8")));
3417
+ } catch {}
3418
+ }
3419
+ }
3420
+ return records;
3421
+ }
3422
+ var init_state = () => {};
3423
+
3424
+ // src/installer/hosts/index.ts
3425
+ function planForHost(host, input) {
3426
+ const previous = readRecord(input);
3427
+ const planned = withCrossScopeGuard(HOST_PLANNERS[host](input, previous), input);
3428
+ return withSecretGuard(withOrphanReverts(planned, input, previous));
3429
+ }
3430
+ function withCrossScopeGuard(plan, input) {
3431
+ if (plan.errors.length > 0)
3432
+ return plan;
3433
+ const other = input.scope === "global" ? "project" : "global";
3434
+ const overlap = claimedByOtherScope(input, plan.edits.map((edit2) => edit2.file));
3435
+ if (overlap.length === 0)
3436
+ return plan;
3437
+ return {
3438
+ ...plan,
3439
+ edits: [],
3440
+ reverts: undefined,
3441
+ errors: [
3442
+ {
3443
+ message: `A ${plan.host} install is already recorded at the ${other} scope and claims the same file(s): ${overlap.join(", ")}. ` + `Uninstall it first (deepseek-web-retrieval uninstall --host ${plan.host} --scope ${other}), ` + `or re-run with --scope ${other} to update it in place — two scopes must not edit one file.`
3444
+ }
3445
+ ]
3446
+ };
3447
+ }
3448
+ function withSecretGuard(plan) {
3449
+ for (const edit2 of plan.edits) {
3450
+ if (edit2.format === "rules")
3451
+ continue;
3452
+ for (const op of edit2.ops) {
3453
+ if (op.op !== "set" || op.previous === undefined)
3454
+ continue;
3455
+ const offender = findSecretLike(op.previous, op.path.join("."));
3456
+ if (offender !== undefined) {
3457
+ return {
3458
+ ...plan,
3459
+ edits: [],
3460
+ reverts: undefined,
3461
+ errors: [
3462
+ {
3463
+ message: `${edit2.file}: the existing value at ${op.path.join(".")} contains a credential-looking key ` + `(${offender}). The installer refuses to snapshot secrets into its state file. Move the key to ` + `environment indirection ("\${${API_KEY_ENV}}" expansion or env_vars) and re-run.`
3464
+ }
3465
+ ]
3466
+ };
3467
+ }
3468
+ }
3469
+ }
3470
+ return plan;
3471
+ }
3472
+ function findSecretLike(value, at) {
3473
+ if (typeof value !== "object" || value === null)
3474
+ return;
3475
+ for (const [key, child] of Object.entries(value)) {
3476
+ const path = `${at}.${key}`;
3477
+ if (/(api[_-]?key|token|secret|password|credential)/i.test(key) && typeof child === "string" && child.length > 0 && !/^\$\{[^}]+\}$/.test(child)) {
3478
+ return path;
3479
+ }
3480
+ const nested = findSecretLike(child, path);
3481
+ if (nested !== undefined)
3482
+ return nested;
3483
+ }
3484
+ return;
3485
+ }
3486
+ function withOrphanReverts(plan, input, previous) {
3487
+ if (plan.errors.length > 0)
3488
+ return plan;
3489
+ if (previous === undefined)
3490
+ return plan;
3491
+ const reverts = [];
3492
+ for (const file of previous.files) {
3493
+ const edit2 = plan.edits.find((candidate) => candidate.file === file.file);
3494
+ if (edit2 === undefined) {
3495
+ reverts.push(file);
3496
+ continue;
3497
+ }
3498
+ if (edit2.format === "rules" || file.format === "rules")
3499
+ continue;
3500
+ const orphanOps = file.ops.filter((op) => !edit2.ops.some((candidate) => candidate.op === op.op && candidate.path.join("\x00") === op.path.join("\x00")));
3501
+ if (orphanOps.length > 0)
3502
+ reverts.push({ ...file, ops: orphanOps });
3503
+ }
3504
+ if (reverts.length === 0)
3505
+ return plan;
3506
+ return { ...plan, reverts };
3507
+ }
3508
+ var HOST_PLANNERS;
3509
+ var init_hosts = __esm(() => {
3510
+ init_codex();
3511
+ init_opencode();
3512
+ init_pi();
3513
+ init_constants();
3514
+ init_state();
3515
+ HOST_PLANNERS = {
3516
+ opencode: planOpenCode,
3517
+ pi: planPi,
3518
+ codex: planCodex
3519
+ };
3520
+ });
3521
+
3522
+ // src/installer/revert.ts
3523
+ import { existsSync as existsSync6, readFileSync as readFileSync6, rmdirSync, unlinkSync } from "node:fs";
3524
+ import { dirname as dirname2 } from "node:path";
3525
+ function pruneEmptyDir(dir) {
3526
+ try {
3527
+ rmdirSync(dir);
3528
+ } catch {}
3529
+ }
3530
+ function revertRecordedFile(file, host, opts) {
3531
+ const lines = [];
3532
+ if (!existsSync6(file.file)) {
3533
+ lines.push(`already absent: ${file.file}${opts.label}`);
3534
+ return lines;
3535
+ }
3536
+ const codec = codecFor(file.format, host);
3537
+ const text = readFileSync6(file.file, "utf8");
3538
+ if (file.format === "rules") {
3539
+ const edit2 = { file: file.file, format: "rules", block: file.blockApplied ?? "" };
3540
+ if (!codec.verify(text, edit2)) {
3541
+ lines.push(`no rules block${opts.label} in ${file.file}; left untouched`);
3542
+ return lines;
3543
+ }
3544
+ const updated = codec.revert(text, file).text;
3545
+ if (opts.whole && codec.isEffectivelyEmpty(updated)) {
3546
+ unlinkSync(file.file);
3547
+ pruneEmptyDir(dirname2(file.file));
3548
+ lines.push(`deleted ${file.file} (installer-created, now empty)`);
3549
+ } else {
3550
+ writeConfig(file.file, updated);
3551
+ lines.push(`removed rules block${opts.label} from ${file.file}`);
3552
+ }
3553
+ return lines;
3554
+ }
3555
+ const reverted = codec.revert(text, file);
3556
+ if (opts.whole && file.created && codec.isEffectivelyEmpty(reverted.text)) {
3557
+ unlinkSync(file.file);
3558
+ pruneEmptyDir(dirname2(file.file));
3559
+ lines.push(`deleted ${file.file} (installer-created, now empty)`);
3560
+ } else {
3561
+ writeConfig(file.file, reverted.text);
3562
+ lines.push(`reverted artifacts${opts.label} in ${file.file}`);
3563
+ }
3564
+ lines.push(...reverted.notes.map((note) => ` note: ${note}`));
3565
+ return lines;
3566
+ }
3567
+ var init_revert = __esm(() => {
3568
+ init_formats();
3569
+ });
3570
+
3571
+ // src/installer/apply.ts
3572
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
3573
+ function applyPlan(plan, input) {
3574
+ if (plan.errors.length > 0) {
3575
+ throw new Error(`refusing to apply a plan with errors: ${plan.errors.map((error) => error.message).join("; ")}`);
3576
+ }
3577
+ assertNoDrift(plan);
3578
+ const previous = readRecord(input);
3579
+ const prepared = plan.edits.map((edit2) => prepareEdit(edit2, plan.host));
3580
+ const files = [];
3581
+ const lines = [];
3582
+ for (const item of prepared) {
3583
+ item.write();
3584
+ files.push(mergeRecorded(item.recorded, previous?.files.find((file) => file.file === item.edit.file)));
3585
+ lines.push(`${item.recorded.created ? "created" : "updated"} ${item.edit.file}`);
3586
+ }
3587
+ if ((plan.reverts ?? []).length > 0) {
3588
+ lines.push(...applyReverts(plan));
3589
+ }
3590
+ const record = {
3591
+ version: 1,
3592
+ host: plan.host,
3593
+ scope: plan.scope,
3594
+ tiers: plan.tiers,
3595
+ createdAt: new Date().toISOString(),
3596
+ files
3597
+ };
3598
+ writeRecord(input, record);
3599
+ const verification = verifyEdits(plan.edits, plan.host);
3600
+ lines.push(...verification.lines);
3601
+ return { lines, ok: verification.ok };
3602
+ }
3603
+ function assertNoDrift(plan) {
3604
+ const drifts = [];
3605
+ for (const edit2 of plan.edits) {
3606
+ if (edit2.format === "rules")
3607
+ continue;
3608
+ const loaded = codecFor(edit2.format, plan.host).load(edit2.file);
3609
+ if (loaded.parseError) {
3610
+ drifts.push(`${edit2.file} no longer parses (${loaded.parseError})`);
3611
+ continue;
3612
+ }
3613
+ for (const op of edit2.ops) {
3614
+ if (op.op !== "set")
3615
+ continue;
3616
+ const current = valueAt(loaded.value, op.path);
3617
+ if (!deepEqual(current, op.previous)) {
3618
+ drifts.push(`${edit2.file}: ${op.path.join(".")} changed since the plan was rendered`);
3619
+ }
3620
+ }
3621
+ }
3622
+ if (drifts.length > 0) {
3623
+ throw new Error(`refusing to apply — the config changed since the plan was rendered: ${drifts.join("; ")}. ` + "Re-run init to re-plan against the current files.");
3624
+ }
3625
+ }
3626
+ function prepareEdit(edit2, host) {
3627
+ const codec = codecFor(edit2.format, host);
3628
+ const loaded = codec.load(edit2.file);
3629
+ if (loaded.parseError) {
3630
+ throw new Error(`${edit2.file} does not parse: ${loaded.parseError}`);
3631
+ }
3632
+ const applied = codec.apply(loaded.text, edit2);
3633
+ const recorded = edit2.format === "rules" ? { file: edit2.file, format: "rules", created: !loaded.exists, ops: [], blockApplied: edit2.block } : { file: edit2.file, format: edit2.format, created: !loaded.exists, ops: applied.recorded, createdParents: applied.createdParents };
3634
+ return {
3635
+ edit: edit2,
3636
+ recorded,
3637
+ write: () => writeConfig(edit2.file, applied.text)
3638
+ };
3639
+ }
3640
+ function applyReverts(plan) {
3641
+ const lines = [];
3642
+ for (const revert of plan.reverts ?? []) {
3643
+ const whole = !plan.edits.some((edit2) => edit2.file === revert.file);
3644
+ lines.push(...revertRecordedFile(revert, plan.host, { label: " (previous init)", whole }));
3645
+ }
3646
+ return lines;
3647
+ }
3648
+ function mergeRecorded(current, before) {
3649
+ if (before === undefined)
3650
+ return current;
3651
+ const ops = current.ops.map((op) => {
3652
+ const old = before.ops.find((candidate) => candidate.op === op.op && candidate.path.join("\x00") === op.path.join("\x00"));
3653
+ if (old === undefined)
3654
+ return op;
3655
+ if (op.op === "set" && old.op === "set" && deepEqual(op.previous, old.applied)) {
3656
+ return { ...op, previous: old.previous };
3657
+ }
3658
+ if (op.op === "append-array" && old.op === "append-array") {
3659
+ return { ...op, applied: [...old.applied, ...op.applied] };
3660
+ }
3661
+ return op;
3662
+ });
3663
+ return {
3664
+ ...current,
3665
+ created: before.created,
3666
+ ops,
3667
+ createdParents: [...before.createdParents ?? [], ...current.createdParents ?? []]
3668
+ };
3669
+ }
3670
+ function verifyEdits(edits, host) {
3671
+ const lines = [];
3672
+ let ok = true;
3673
+ for (const edit2 of edits) {
3674
+ if (!existsSync7(edit2.file)) {
3675
+ lines.push(`FAIL ${edit2.file} does not exist after apply`);
3676
+ ok = false;
3677
+ continue;
3678
+ }
3679
+ const codec = codecFor(edit2.format, host);
3680
+ const text = readFileSync7(edit2.file, "utf8");
3681
+ if (edit2.format === "rules") {
3682
+ const good = codec.verify(text, edit2);
3683
+ lines.push(`${good ? "pass" : "FAIL"} ${edit2.file}: rules block ${good ? "present" : "missing"}`);
3684
+ ok = ok && good;
3685
+ continue;
3686
+ }
3687
+ for (const op of edit2.ops) {
3688
+ const good = codec.verify(text, edit2, op);
3689
+ lines.push(`${good ? "pass" : "FAIL"} ${edit2.file}: ${describeOp(op)} ${good ? "holds" : "missing"}`);
3690
+ ok = ok && good;
3691
+ }
3692
+ }
3693
+ return { lines, ok };
3694
+ }
3695
+ function describeOp(op) {
3696
+ if (op.op === "set")
3697
+ return `set ${op.path.join(".")}`;
3698
+ return `append ${op.path.join(".")}`;
3699
+ }
3700
+ var init_apply = __esm(() => {
3701
+ init_formats();
3702
+ init_revert();
3703
+ init_state();
3704
+ });
3705
+
3706
+ // src/installer/render.ts
3707
+ function renderPlan(plan) {
3708
+ const lines = [];
3709
+ lines.push(`Install plan: ${plan.host} (${plan.scope} scope)`);
3710
+ lines.push(`Tiers: search=${plan.tiers.search}, fetch=${plan.tiers.fetch}`);
3711
+ lines.push("");
3712
+ lines.push("Files:");
3713
+ for (const edit2 of plan.edits) {
3714
+ lines.push(` ${edit2.file}`);
3715
+ if (edit2.format === "rules") {
3716
+ lines.push(" upsert marked rules block");
3717
+ continue;
3718
+ }
3719
+ for (const op of edit2.ops) {
3720
+ if (op.op === "set") {
3721
+ const was = op.previous === undefined ? "(absent)" : preview(op.previous);
3722
+ lines.push(` set ${op.path.join(".")} = ${preview(op.value)} (was ${was})`);
3723
+ } else {
3724
+ const count = (op.entries ?? []).length;
3725
+ const kept = op.existingCount !== undefined ? ` (${op.existingCount} existing kept)` : "";
3726
+ lines.push(` append ${count} entr${count === 1 ? "y" : "ies"} to ${op.path.join(".")}${kept}`);
3727
+ for (const entry of op.entries ?? [])
3728
+ lines.push(` + ${preview(entry)}`);
3729
+ }
3730
+ }
3731
+ }
3732
+ if (plan.reverts && plan.reverts.length > 0) {
3733
+ lines.push("");
3734
+ lines.push("Reverts (artifacts from the previous init that this plan no longer wants):");
3735
+ for (const revert of plan.reverts) {
3736
+ lines.push(` ${revert.file}`);
3737
+ if (revert.format === "rules") {
3738
+ lines.push(" remove rules block");
3739
+ continue;
3740
+ }
3741
+ for (const op of revert.ops) {
3742
+ if (op.op === "set") {
3743
+ lines.push(op.previous === undefined ? ` remove ${op.path.join(".")} (was not set before this install)` : ` restore ${op.path.join(".")} = ${preview(op.previous)}`);
3744
+ } else {
3745
+ const count = Array.isArray(op.applied) ? op.applied.length : 0;
3746
+ lines.push(` remove ${count} appended entr${count === 1 ? "y" : "ies"} from ${op.path.join(".")}`);
3747
+ }
3748
+ }
3749
+ }
3750
+ }
3751
+ if (plan.notes.length > 0) {
3752
+ lines.push("");
3753
+ lines.push("Notes:");
3754
+ for (const note of plan.notes)
3755
+ lines.push(` - ${note}`);
3756
+ }
3757
+ return lines.join(`
3758
+ `);
3759
+ }
3760
+ function preview(value) {
3761
+ const text = JSON.stringify(value) ?? String(value);
3762
+ return text.length > 100 ? `${text.slice(0, 97)}...` : text;
3763
+ }
3764
+
3765
+ // src/installer/uninstall.ts
3766
+ function uninstall(input) {
3767
+ const record = readRecord(input);
3768
+ if (record === undefined) {
3769
+ throw new Error(`No ${input.host} install is recorded for the ${input.scope} scope.`);
3770
+ }
3771
+ const other = input.scope === "global" ? "project" : "global";
3772
+ const overlap = claimedByOtherScope(input, record.files.map((file) => file.file));
3773
+ if (overlap.length > 0) {
3774
+ throw new Error(`A ${input.host} install is also recorded at the ${other} scope and claims the same file(s): ${overlap.join(", ")}. ` + `Uninstall the ${other}-scope install first so this rollback cannot clobber its entries.`);
3775
+ }
3776
+ const lines = [];
3777
+ for (const file of [...record.files].reverse()) {
3778
+ lines.push(...revertRecordedFile(file, record.host, { label: "", whole: true }));
3779
+ }
3780
+ deleteRecord(input);
3781
+ pruneEmptyDir(stateDir(input, input.scope));
3782
+ lines.push(`removed install record (${input.host}, ${input.scope})`);
3783
+ return lines;
3784
+ }
3785
+ var init_uninstall = __esm(() => {
3786
+ init_revert();
3787
+ init_state();
3788
+ });
3789
+
3790
+ // src/installer/cli.ts
3791
+ var exports_cli = {};
3792
+ __export(exports_cli, {
3793
+ runInstallerCli: () => runInstallerCli
3794
+ });
3795
+ import { homedir } from "node:os";
3796
+ import { resolve } from "node:path";
3797
+ function parseFlags(args) {
3798
+ const values = new Map;
3799
+ const booleans = new Set;
3800
+ const problems = [];
3801
+ for (let i = 0;i < args.length; i += 1) {
3802
+ const arg = args[i];
3803
+ if (!arg.startsWith("--")) {
3804
+ problems.push(`unexpected argument "${arg}" (flags only)`);
3805
+ continue;
3806
+ }
3807
+ const eq = arg.indexOf("=");
3808
+ const name = eq === -1 ? arg.slice(2) : arg.slice(2, eq);
3809
+ if (BOOLEAN_FLAGS.has(name)) {
3810
+ booleans.add(name);
3811
+ continue;
3812
+ }
3813
+ if (!VALUE_FLAGS.has(name)) {
3814
+ problems.push(`unknown flag --${name}`);
3815
+ continue;
3816
+ }
3817
+ if (eq !== -1) {
3818
+ values.set(name, arg.slice(eq + 1));
3819
+ continue;
3820
+ }
3821
+ const next = args[i + 1];
3822
+ if (next === undefined || next.startsWith("--")) {
3823
+ problems.push(`--${name} requires a value`);
3824
+ continue;
3825
+ }
3826
+ values.set(name, next);
3827
+ i += 1;
3828
+ }
3829
+ return { values, booleans, problems };
3830
+ }
3831
+ async function runInstallerCli(argv, io = {}) {
3832
+ const out = io.out ?? ((line) => console.log(line));
3833
+ const err = io.err ?? ((line) => console.error(line));
3834
+ const [command, ...rest] = argv;
3835
+ if (command === undefined || command === "help" || command === "--help") {
3836
+ out(USAGE);
3837
+ return command === undefined ? 1 : 0;
3838
+ }
3839
+ const flags = parseFlags(rest);
3840
+ if (flags.problems.length > 0) {
3841
+ for (const problem of flags.problems)
3842
+ err(`error: ${problem}`);
3843
+ err(`
3844
+ ${USAGE}`);
3845
+ return 1;
3846
+ }
3847
+ const cwd = resolve(flags.values.get("cwd") ?? process.cwd());
3848
+ const home = process.env.HOME ?? homedir();
3849
+ const configHome2 = resolveConfigHome(home);
3850
+ if (command === "list") {
3851
+ const records = listRecords({ home, cwd, configHome: configHome2 });
3852
+ if (records.length === 0) {
3853
+ out("No installs recorded.");
3854
+ return 0;
3855
+ }
3856
+ for (const record of records) {
3857
+ out(`${record.host} (${record.scope}) — search=${record.tiers.search}, fetch=${record.tiers.fetch}, installed ${record.createdAt}`);
3858
+ for (const file of record.files)
3859
+ out(` ${file.created ? "created" : "modified"} ${file.file}`);
3860
+ }
3861
+ return 0;
3862
+ }
3863
+ if (command === "uninstall") {
3864
+ const required2 = requireInput(flags, cwd, home, configHome2, false);
3865
+ if (!required2.ok)
3866
+ return usageError(required2.problems, err);
3867
+ try {
3868
+ for (const line of uninstall(required2.input))
3869
+ out(line);
3870
+ return 0;
3871
+ } catch (error) {
3872
+ err(error instanceof Error ? error.message : String(error));
3873
+ return 1;
3874
+ }
3875
+ }
3876
+ if (command !== "init") {
3877
+ err(`Unknown command "${command}".
3878
+
3879
+ ${USAGE}`);
3880
+ return 1;
3881
+ }
3882
+ const required = requireInput(flags, cwd, home, configHome2, true);
3883
+ if (!required.ok)
3884
+ return usageError(required.problems, err);
3885
+ const { input } = required;
3886
+ const plan = planForHost(input.host, input);
3887
+ if (plan.errors.length > 0) {
3888
+ for (const error of plan.errors)
3889
+ err(`error: ${error.message}`);
3890
+ err("Nothing was written.");
3891
+ return 1;
3892
+ }
3893
+ out(renderPlan(plan));
3894
+ if (!flags.booleans.has("apply")) {
3895
+ out(`
3896
+ Plan only — re-run with --apply to write these changes.`);
3897
+ return 0;
3898
+ }
3899
+ try {
3900
+ const result = applyPlan(plan, input);
3901
+ for (const line of result.lines)
3902
+ out(line);
3903
+ return result.ok ? 0 : 1;
3904
+ } catch (error) {
3905
+ err(error instanceof Error ? error.message : String(error));
3906
+ return 1;
3907
+ }
3908
+ }
3909
+ function usageError(problems, err) {
3910
+ for (const problem of problems)
3911
+ err(`error: ${problem}`);
3912
+ err(`
3913
+ ${USAGE}`);
3914
+ return 1;
3915
+ }
3916
+ function resolveConfigHome(home) {
3917
+ const xdg = process.env.XDG_CONFIG_HOME;
3918
+ if (xdg && home === (process.env.HOME ?? ""))
3919
+ return xdg;
3920
+ return;
3921
+ }
3922
+ function requireInput(flags, cwd, home, configHome2, needsTiers) {
3923
+ const problems = [];
3924
+ const host = flags.values.get("host");
3925
+ const scope = flags.values.get("scope");
3926
+ const search = needsTiers ? flags.values.get("search") ?? "" : "optional";
3927
+ const fetch = needsTiers ? flags.values.get("fetch") ?? "" : "optional";
3928
+ if (host === undefined)
3929
+ problems.push(`--host is required (one of: ${HOSTS.join(", ")})`);
3930
+ else if (!HOSTS.includes(host))
3931
+ problems.push(`invalid --host value "${host}" (one of: ${HOSTS.join(", ")})`);
3932
+ if (scope === undefined)
3933
+ problems.push(`--scope is required (one of: ${SCOPES.join(", ")})`);
3934
+ else if (!SCOPES.includes(scope))
3935
+ problems.push(`invalid --scope value "${scope}" (one of: ${SCOPES.join(", ")})`);
3936
+ if (needsTiers) {
3937
+ if (!TIERS.includes(search)) {
3938
+ problems.push(flags.values.has("search") ? `invalid --search value "${search}" (one of: ${TIERS.join(", ")})` : `--search is required (one of: ${TIERS.join(", ")})`);
3939
+ }
3940
+ if (!TIERS.includes(fetch)) {
3941
+ problems.push(flags.values.has("fetch") ? `invalid --fetch value "${fetch}" (one of: ${TIERS.join(", ")})` : `--fetch is required (one of: ${TIERS.join(", ")})`);
3942
+ }
3943
+ }
3944
+ if (home === "")
3945
+ problems.push("HOME is not set and the user home cannot be resolved; cannot proceed");
3946
+ if (problems.length > 0)
3947
+ return { ok: false, problems };
3948
+ return {
3949
+ ok: true,
3950
+ input: {
3951
+ host,
3952
+ scope,
3953
+ search,
3954
+ fetch,
3955
+ packageRef: flags.values.get("package") ?? "deepseek-web-retrieval",
3956
+ home,
3957
+ cwd,
3958
+ configHome: configHome2
3959
+ }
3960
+ };
3961
+ }
3962
+ var HOSTS, HOST_CHOICES, SCOPES, TIERS, USAGE, VALUE_FLAGS, BOOLEAN_FLAGS;
3963
+ var init_cli = __esm(() => {
3964
+ init_hosts();
3965
+ init_apply();
3966
+ init_state();
3967
+ init_uninstall();
3968
+ HOSTS = Object.keys(HOST_PLANNERS);
3969
+ HOST_CHOICES = `<${HOSTS.join("|")}>`;
3970
+ SCOPES = ["project", "global"];
3971
+ TIERS = ["optional", "preferred", "forced", "off"];
3972
+ USAGE = `Usage:
3973
+ deepseek-web-retrieval init --host ${HOST_CHOICES} --scope <project|global> --search <optional|preferred|forced|off> --fetch <optional|preferred|forced|off> [--package <npm ref>] [--cwd <dir>] [--apply]
3974
+ deepseek-web-retrieval uninstall --host ${HOST_CHOICES} --scope <project|global> [--cwd <dir>]
3975
+ deepseek-web-retrieval list [--cwd <dir>]
3976
+
3977
+ init prints the full plan (every file, old value → new value) and writes nothing
3978
+ until --apply is passed. uninstall restores what the plan applied.`;
3979
+ VALUE_FLAGS = new Set(["host", "scope", "search", "fetch", "package", "cwd"]);
3980
+ BOOLEAN_FLAGS = new Set(["apply"]);
3981
+ });
2
3982
 
3
3983
  // src/mcp/cli.ts
4
3984
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
5
3985
 
6
3986
  // src/core/auth.ts
7
- var API_KEY_ENV = "DEEPSEEK_API_KEY";
3987
+ init_constants();
8
3988
  function apiKeyFromEnv(env = process.env) {
9
3989
  const key = env[API_KEY_ENV]?.trim();
10
3990
  return key ? key : undefined;
11
3991
  }
12
3992
 
13
3993
  // src/mcp/auth.ts
14
- var MISSING_API_KEY_MESSAGE = "DeepSeek API key not found. Set DEEPSEEK_API_KEY in the MCP server's env configuration.";
3994
+ init_constants();
3995
+ var MISSING_API_KEY_MESSAGE = `DeepSeek API key not found. Set ${API_KEY_ENV} in the MCP server's env configuration.`;
15
3996
  function requireApiKey(env) {
16
3997
  const apiKey = apiKeyFromEnv(env);
17
3998
  if (!apiKey)
@@ -19,30 +4000,11 @@ function requireApiKey(env) {
19
4000
  return apiKey;
20
4001
  }
21
4002
 
22
- // src/core/constants.ts
23
- var SEARCH_ENDPOINT = "https://api.deepseek.com/v1/tools/search";
24
- var FETCH_ENDPOINT = "https://api.deepseek.com/v1/tools/fetch";
25
- var DEFAULT_SEARCH_COUNT = 10;
26
- var DEFAULT_MAX_RESULTS = 5;
27
- var DEFAULT_MIN_RERANK = 1.5;
28
- var DEFAULT_MIN_AUTHORITY = 2;
29
- var DEFAULT_MAX_SUMMARY_CHARS = 1200;
30
- var DEFAULT_FETCH_MAX_CHARS = 16000;
31
- var DEFAULT_TIMEOUT_MS = 30000;
32
- var MIN_TIMEOUT_MS = 1000;
33
- var MAX_TIMEOUT_MS = 120000;
34
- var MAX_QUERY_CHARS = 128;
35
- var MAX_URL_CHARS = 8192;
36
- var MAX_ERROR_BODY_CHARS = 2000;
37
- var MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
38
- var FETCH_TRUNCATION_MARKER = `
39
-
40
- [content truncated]`;
41
- var DEFAULT_API_KEY_SOURCE = "auto";
42
- var DEFAULT_MAX_RETRIES = 0;
43
- var MAX_RETRIES = 5;
44
- var DEFAULT_RETRY_BASE_DELAY_MS = 250;
45
- var MAX_RETRY_DELAY_MS = 1e4;
4003
+ // src/mcp/config.ts
4004
+ init_constants();
4005
+
4006
+ // src/core/options.ts
4007
+ init_constants();
46
4008
 
47
4009
  // src/core/domains.ts
48
4010
  import { isIP } from "node:net";
@@ -172,7 +4134,7 @@ function resolveSearchOptions(input) {
172
4134
  language: optionalText(input?.language),
173
4135
  maxSummaryChars: clampInt(input?.maxSummaryChars, DEFAULT_MAX_SUMMARY_CHARS, 0, 1e6),
174
4136
  timeoutMs: clampInt(input?.searchTimeoutMs, DEFAULT_TIMEOUT_MS, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS),
175
- setDefault: input?.setDefaultWebsearch === true
4137
+ enabled: input?.searchEnabled !== false
176
4138
  };
177
4139
  }
178
4140
  function resolveFetchOptions(input) {
@@ -181,9 +4143,8 @@ function resolveFetchOptions(input) {
181
4143
  allowedDomains: normalizeDomains(input?.fetchAllowedDomains),
182
4144
  blockedDomains: normalizeDomains(input?.fetchBlockedDomains),
183
4145
  timeoutMs: clampInt(input?.fetchTimeoutMs, DEFAULT_TIMEOUT_MS, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS),
184
- overrideWebfetch: input?.fetchOverrideWebfetch === true,
185
- registerTool: input?.fetchRegisterTool !== false,
186
- blockPrivateHosts: input?.fetchBlockPrivateHosts !== false
4146
+ blockPrivateHosts: input?.fetchBlockPrivateHosts !== false,
4147
+ enabled: input?.fetchEnabled !== false
187
4148
  };
188
4149
  }
189
4150
  function resolveAuthOptions(input) {
@@ -213,33 +4174,63 @@ function clampInt(value, fallback, min, max) {
213
4174
  }
214
4175
 
215
4176
  // src/mcp/config.ts
4177
+ var NUMBER_ENV = {
4178
+ count: "DEEPSEEK_SEARCH_COUNT",
4179
+ maxResults: "DEEPSEEK_SEARCH_MAX_RESULTS",
4180
+ minRerank: "DEEPSEEK_SEARCH_MIN_RERANK",
4181
+ minAuthority: "DEEPSEEK_SEARCH_MIN_AUTHORITY",
4182
+ maxSummaryChars: "DEEPSEEK_SEARCH_MAX_SUMMARY_CHARS",
4183
+ searchTimeoutMs: "DEEPSEEK_SEARCH_TIMEOUT_MS",
4184
+ fetchMaxChars: "DEEPSEEK_FETCH_MAX_CHARS",
4185
+ fetchTimeoutMs: "DEEPSEEK_FETCH_TIMEOUT_MS",
4186
+ maxRetries: "DEEPSEEK_MAX_RETRIES",
4187
+ retryBaseDelayMs: "DEEPSEEK_RETRY_BASE_DELAY_MS"
4188
+ };
4189
+ var TEXT_ENV = {
4190
+ language: "DEEPSEEK_SEARCH_LANGUAGE"
4191
+ };
4192
+ var DOMAINS_ENV = {
4193
+ blockedDomains: "DEEPSEEK_SEARCH_BLOCKED_DOMAINS",
4194
+ includeDomains: "DEEPSEEK_SEARCH_INCLUDE_DOMAINS",
4195
+ fetchAllowedDomains: "DEEPSEEK_FETCH_ALLOWED_DOMAINS",
4196
+ fetchBlockedDomains: "DEEPSEEK_FETCH_BLOCKED_DOMAINS"
4197
+ };
4198
+ var FLAG_ENV = {
4199
+ allowUnknownAuthority: "DEEPSEEK_SEARCH_ALLOW_UNKNOWN_AUTHORITY"
4200
+ };
4201
+ var FALSE_ONLY_ENV = {
4202
+ fetchBlockPrivateHosts: "DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS",
4203
+ searchEnabled: ENABLE_SEARCH_ENV,
4204
+ fetchEnabled: ENABLE_FETCH_ENV
4205
+ };
216
4206
  function resolveEnvOptions(env = process.env) {
217
4207
  return resolvePluginOptions(pluginOptionsFromEnv(env));
218
4208
  }
219
4209
  function pluginOptionsFromEnv(env) {
220
4210
  const options = {};
221
- putNumber(options, "count", env.DEEPSEEK_SEARCH_COUNT);
222
- putNumber(options, "maxResults", env.DEEPSEEK_SEARCH_MAX_RESULTS);
223
- putNumber(options, "minRerank", env.DEEPSEEK_SEARCH_MIN_RERANK);
224
- putNumber(options, "minAuthority", env.DEEPSEEK_SEARCH_MIN_AUTHORITY);
225
- putBoolean(options, "allowUnknownAuthority", env.DEEPSEEK_SEARCH_ALLOW_UNKNOWN_AUTHORITY);
226
- putDomains(options, "blockedDomains", env.DEEPSEEK_SEARCH_BLOCKED_DOMAINS);
227
- putDomains(options, "includeDomains", env.DEEPSEEK_SEARCH_INCLUDE_DOMAINS);
228
- putText(options, "language", env.DEEPSEEK_SEARCH_LANGUAGE);
229
- putNumber(options, "maxSummaryChars", env.DEEPSEEK_SEARCH_MAX_SUMMARY_CHARS);
230
- putNumber(options, "searchTimeoutMs", env.DEEPSEEK_SEARCH_TIMEOUT_MS);
231
- putNumber(options, "fetchMaxChars", env.DEEPSEEK_FETCH_MAX_CHARS);
232
- putDomains(options, "fetchAllowedDomains", env.DEEPSEEK_FETCH_ALLOWED_DOMAINS);
233
- putDomains(options, "fetchBlockedDomains", env.DEEPSEEK_FETCH_BLOCKED_DOMAINS);
234
- putNumber(options, "fetchTimeoutMs", env.DEEPSEEK_FETCH_TIMEOUT_MS);
235
- if (isFalseValue(env.DEEPSEEK_FETCH_BLOCK_PRIVATE_HOSTS)) {
236
- options.fetchBlockPrivateHosts = false;
237
- }
238
- putNumber(options, "maxRetries", env.DEEPSEEK_MAX_RETRIES);
239
- putNumber(options, "retryBaseDelayMs", env.DEEPSEEK_RETRY_BASE_DELAY_MS);
4211
+ putNumber(options, "count", env);
4212
+ putNumber(options, "maxResults", env);
4213
+ putNumber(options, "minRerank", env);
4214
+ putNumber(options, "minAuthority", env);
4215
+ putBoolean(options, "allowUnknownAuthority", env);
4216
+ putDomains(options, "blockedDomains", env);
4217
+ putDomains(options, "includeDomains", env);
4218
+ putText(options, "language", env);
4219
+ putNumber(options, "maxSummaryChars", env);
4220
+ putNumber(options, "searchTimeoutMs", env);
4221
+ putNumber(options, "fetchMaxChars", env);
4222
+ putDomains(options, "fetchAllowedDomains", env);
4223
+ putDomains(options, "fetchBlockedDomains", env);
4224
+ putNumber(options, "fetchTimeoutMs", env);
4225
+ putFalseOnly(options, "fetchBlockPrivateHosts", env);
4226
+ putFalseOnly(options, "searchEnabled", env);
4227
+ putFalseOnly(options, "fetchEnabled", env);
4228
+ putNumber(options, "maxRetries", env);
4229
+ putNumber(options, "retryBaseDelayMs", env);
240
4230
  return options;
241
4231
  }
242
- function putNumber(target, key, value) {
4232
+ function putNumber(target, key, env) {
4233
+ const value = env[NUMBER_ENV[key]];
243
4234
  if (value === undefined)
244
4235
  return;
245
4236
  const trimmed = value.trim();
@@ -249,18 +4240,24 @@ function putNumber(target, key, value) {
249
4240
  if (Number.isFinite(parsed))
250
4241
  target[key] = parsed;
251
4242
  }
252
- function putText(target, key, value) {
4243
+ function putText(target, key, env) {
4244
+ const value = env[TEXT_ENV[key]];
253
4245
  if (value === undefined)
254
4246
  return;
255
4247
  const trimmed = value.trim();
256
4248
  if (trimmed)
257
4249
  target[key] = trimmed;
258
4250
  }
259
- function putBoolean(target, key, value) {
260
- if (isTrueValue(value))
4251
+ function putBoolean(target, key, env) {
4252
+ if (isTrueValue(env[FLAG_ENV[key]]))
261
4253
  target[key] = true;
262
4254
  }
263
- function putDomains(target, key, value) {
4255
+ function putFalseOnly(target, key, env) {
4256
+ if (isFalseValue(env[FALSE_ONLY_ENV[key]]))
4257
+ target[key] = false;
4258
+ }
4259
+ function putDomains(target, key, env) {
4260
+ const value = env[DOMAINS_ENV[key]];
264
4261
  if (value === undefined || !value.trim())
265
4262
  return;
266
4263
  const domains = value.split(",").map((domain) => domain.trim()).filter((domain) => domain.length > 0);
@@ -280,7 +4277,11 @@ function isFalseValue(value) {
280
4277
  import { McpServer } from "@modelcontextprotocol/server";
281
4278
  import * as z from "zod/v4";
282
4279
 
4280
+ // src/core/client.ts
4281
+ init_constants();
4282
+
283
4283
  // src/core/format.ts
4284
+ init_constants();
284
4285
  function truncate(value, maxChars) {
285
4286
  if (maxChars <= 0)
286
4287
  return "";
@@ -337,8 +4338,34 @@ function formatApiError(operation, status, body) {
337
4338
  function formatTimeoutError(operation, timeoutMs) {
338
4339
  return `${operation} timed out after ${timeoutMs} ms`;
339
4340
  }
4341
+ function formatSearchResults(results) {
4342
+ if (results.length === 0)
4343
+ return "No results found.";
4344
+ return results.map((result, index) => {
4345
+ const title = result.title?.trim() || result.url;
4346
+ const lines = [`${index + 1}. [${escapeBrackets(title)}](${result.url})`];
4347
+ if (result.content) {
4348
+ lines.push(` ${result.content.replaceAll(`
4349
+ `, " ")}`);
4350
+ }
4351
+ if (result.published !== undefined) {
4352
+ lines.push(` Published: ${formatPublished(result.published)}`);
4353
+ }
4354
+ return lines.join(`
4355
+ `);
4356
+ }).join(`
4357
+
4358
+ `);
4359
+ }
4360
+ function escapeBrackets(value) {
4361
+ return value.replaceAll("[", "\\[").replaceAll("]", "\\]");
4362
+ }
4363
+ function formatPublished(epochMs) {
4364
+ return new Date(epochMs).toISOString().slice(0, 10);
4365
+ }
340
4366
 
341
4367
  // src/core/url.ts
4368
+ init_constants();
342
4369
  function parseFetchUrl(value) {
343
4370
  const input = value.trim();
344
4371
  if (!input)
@@ -424,16 +4451,13 @@ function processResults(raw, options) {
424
4451
  }
425
4452
  seen.add(url);
426
4453
  const content = truncate(optionalText2(item.summary) ?? optionalText2(item.snippet) ?? "", options.maxSummaryChars);
427
- const time = {};
428
4454
  const published = parsePublished(item.date);
429
- if (published !== undefined)
430
- time.published = published;
431
4455
  const title = optionalText2(item.title);
432
4456
  results.push({
433
4457
  url,
434
4458
  ...title ? { title } : {},
435
4459
  ...content ? { content } : {},
436
- time
4460
+ ...published !== undefined ? { published } : {}
437
4461
  });
438
4462
  }
439
4463
  return results;
@@ -445,7 +4469,8 @@ function optionalText2(value) {
445
4469
  return trimmed ? trimmed : undefined;
446
4470
  }
447
4471
 
448
- // src/core/client.ts
4472
+ // src/core/transport.ts
4473
+ init_constants();
449
4474
  class DeepSeekApiError extends Error {
450
4475
  operation;
451
4476
  status;
@@ -463,63 +4488,32 @@ class DeepSeekApiError extends Error {
463
4488
  this.retryAfterMs = input.retryAfterMs;
464
4489
  }
465
4490
  }
466
- async function searchWeb(query, options, request) {
467
- const trimmed = query.trim();
468
- if (!trimmed)
469
- throw new Error("DeepSeek search query must not be empty");
470
- if (Array.from(trimmed).length > MAX_QUERY_CHARS) {
471
- throw new Error(`DeepSeek search query must be ${MAX_QUERY_CHARS} characters or fewer`);
472
- }
473
- const builtQuery = buildQuery(trimmed, options);
474
- const builtQueryLength = Array.from(builtQuery).length;
475
- if (builtQueryLength > MAX_QUERY_CHARS) {
476
- throw new Error(`DeepSeek search query must be ${MAX_QUERY_CHARS} characters or fewer after applying ` + `blockedDomains, includeDomains, and language ` + `(built query is ${builtQueryLength} characters)`);
477
- }
478
- const payload = await postJson(SEARCH_ENDPOINT, {
479
- query: builtQuery,
480
- count: options.count,
481
- need_content: false
482
- }, "DeepSeek Search", request, options.timeoutMs);
483
- if (!Array.isArray(payload.results)) {
484
- throw new Error("DeepSeek Search returned a response without a results array");
485
- }
486
- return processResults(payload.results, options);
487
- }
488
- async function fetchPage(url, options, request) {
489
- assertFetchHostPolicy(url, options);
490
- const payload = await postJson(FETCH_ENDPOINT, { url: url.href }, "DeepSeek Fetch", request, options.timeoutMs);
491
- const title = typeof payload.title === "string" ? payload.title.trim() : "";
492
- const content = typeof payload.content === "string" ? payload.content : "";
493
- if (!content.trim()) {
494
- throw new Error("DeepSeek Fetch returned no page content (the page may be empty or unavailable)");
495
- }
496
- return { url: url.href, title, content };
497
- }
498
- async function postJson(endpoint, body, operation, options, timeoutMs) {
499
- const attempts = options.retry.maxRetries + 1;
4491
+ async function postJson(endpoint, body, operation, opts) {
4492
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
4493
+ const attempts = opts.retry.maxRetries + 1;
500
4494
  let lastError;
501
4495
  for (let attempt = 0;attempt < attempts; attempt++) {
502
4496
  try {
503
- return await requestOnce(endpoint, body, operation, options, timeoutMs);
4497
+ return await requestOnce(endpoint, body, operation, opts, fetchImpl);
504
4498
  } catch (error) {
505
4499
  lastError = error;
506
4500
  if (!(error instanceof DeepSeekApiError) || !error.retryable || attempt === attempts - 1) {
507
4501
  throw error;
508
4502
  }
509
- await sleep(retryDelay(error.retryAfterMs, options.retry.baseDelayMs, attempt), options.signal);
4503
+ await sleep(retryDelay(error.retryAfterMs, opts.retry.baseDelayMs, attempt), opts.signal);
510
4504
  }
511
4505
  }
512
4506
  throw lastError;
513
4507
  }
514
- async function requestOnce(endpoint, body, operation, options, timeoutMs) {
4508
+ async function requestOnce(endpoint, body, operation, opts, fetchImpl) {
515
4509
  return fetchWithTimeout(endpoint, {
516
4510
  method: "POST",
517
4511
  headers: {
518
- Authorization: `Bearer ${options.auth.apiKey}`,
4512
+ Authorization: `Bearer ${opts.auth.apiKey}`,
519
4513
  "Content-Type": "application/json"
520
4514
  },
521
4515
  body: JSON.stringify(body)
522
- }, options.signal, timeoutMs, operation, async (response) => {
4516
+ }, opts.signal, opts.timeoutMs, operation, fetchImpl, async (response) => {
523
4517
  if (!response.ok) {
524
4518
  const text2 = await readBoundedText(response, MAX_ERROR_BODY_CHARS);
525
4519
  throw new DeepSeekApiError({
@@ -539,7 +4533,7 @@ async function requestOnce(endpoint, body, operation, options, timeoutMs) {
539
4533
  }
540
4534
  });
541
4535
  }
542
- async function fetchWithTimeout(endpoint, init, signal, timeoutMs, operation, handleResponse) {
4536
+ async function fetchWithTimeout(endpoint, init, signal, timeoutMs, operation, fetchImpl, handleResponse) {
543
4537
  const controller = new AbortController;
544
4538
  let timedOut = false;
545
4539
  const forwardAbort = () => controller.abort(signal.reason);
@@ -552,7 +4546,7 @@ async function fetchWithTimeout(endpoint, init, signal, timeoutMs, operation, ha
552
4546
  controller.abort(new Error("timeout"));
553
4547
  }, timeoutMs);
554
4548
  try {
555
- const response = await fetch(endpoint, { ...init, signal: controller.signal });
4549
+ const response = await fetchImpl(endpoint, { ...init, signal: controller.signal });
556
4550
  return await handleResponse(response);
557
4551
  } catch (error) {
558
4552
  if (timedOut)
@@ -666,11 +4660,72 @@ async function readResponseText(response, maxBytes, operation) {
666
4660
  }
667
4661
  return text;
668
4662
  }
4663
+
4664
+ // src/core/client.ts
4665
+ function effectiveTimeout(configuredMs, perCallMs) {
4666
+ return perCallMs === undefined ? configuredMs : Math.min(configuredMs, perCallMs);
4667
+ }
4668
+ async function searchWeb(query, options, request) {
4669
+ const trimmed = query.trim();
4670
+ if (!trimmed)
4671
+ throw new Error("DeepSeek search query must not be empty");
4672
+ if (Array.from(trimmed).length > MAX_QUERY_CHARS) {
4673
+ throw new Error(`DeepSeek search query must be ${MAX_QUERY_CHARS} characters or fewer`);
4674
+ }
4675
+ const builtQuery = buildQuery(trimmed, options);
4676
+ const builtQueryLength = Array.from(builtQuery).length;
4677
+ if (builtQueryLength > MAX_QUERY_CHARS) {
4678
+ throw new Error(`DeepSeek search query must be ${MAX_QUERY_CHARS} characters or fewer after applying ` + `blockedDomains, includeDomains, and language ` + `(built query is ${builtQueryLength} characters)`);
4679
+ }
4680
+ const timeout = effectiveTimeout(options.timeoutMs, request.timeoutMs);
4681
+ const payload = await postJson(SEARCH_ENDPOINT, {
4682
+ query: builtQuery,
4683
+ count: options.count,
4684
+ need_content: false
4685
+ }, "DeepSeek Search", { signal: request.signal, auth: request.auth, retry: request.retry, timeoutMs: timeout });
4686
+ if (!Array.isArray(payload.results)) {
4687
+ throw new Error("DeepSeek Search returned a response without a results array");
4688
+ }
4689
+ return processResults(payload.results, options);
4690
+ }
4691
+ async function fetchPage(url, options, request) {
4692
+ assertFetchHostPolicy(url, options);
4693
+ const timeout = effectiveTimeout(options.timeoutMs, request.timeoutMs);
4694
+ const payload = await postJson(FETCH_ENDPOINT, { url: url.href }, "DeepSeek Fetch", { signal: request.signal, auth: request.auth, retry: request.retry, timeoutMs: timeout });
4695
+ const title = typeof payload.title === "string" ? payload.title.trim() : "";
4696
+ const content = typeof payload.content === "string" ? payload.content : "";
4697
+ if (!content.trim()) {
4698
+ throw new Error("DeepSeek Fetch returned no page content (the page may be empty or unavailable)");
4699
+ }
4700
+ return { url: url.href, title, content };
4701
+ }
4702
+ async function fetchDocument(url, options, request) {
4703
+ if (typeof url !== "string" && !(url instanceof URL))
4704
+ throw new Error('"url" must be a string or URL');
4705
+ const page = await fetchPage(url instanceof URL ? url : parseFetchUrl(url), options, request);
4706
+ const formatted = formatFetchedContent(page.title, page.content, options.maxChars);
4707
+ return {
4708
+ url: page.url,
4709
+ title: page.title,
4710
+ content: formatted.content,
4711
+ truncated: formatted.truncated
4712
+ };
4713
+ }
4714
+
4715
+ // src/mcp/server.ts
4716
+ init_constants();
4717
+
4718
+ // src/core/descriptions.ts
4719
+ var FETCH_SERVICE_LIMITS = "DeepSeek does not render JavaScript and cannot reach private networks; PDFs, images, and other binary files are unsupported.";
4720
+ var FETCH_OUTPUT_TRUNCATED = "Output is truncated to the configured size.";
4721
+ var SEARCH_RANKED_FILTERED = "Results are ranked by relevance and source authority, deduplicated by URL, and capped at the configured maximum.";
4722
+ var SEARCH_EMPTY_IS_NORMAL = "An empty result list is normal, not an error.";
4723
+ var SEARCH_QUERY_OPERATORS = "Use site:/-site: operators in the query to include or exclude domains; the full query must stay within 128 characters.";
669
4724
  // package.json
670
4725
  var package_default = {
671
4726
  $schema: "https://json.schemastore.org/package.json",
672
4727
  name: "deepseek-web-retrieval",
673
- version: "0.2.0",
4728
+ version: "0.3.0",
674
4729
  description: "Token-efficient DeepSeek Search and Fetch for coding agents, starting with OpenCode v2.",
675
4730
  type: "module",
676
4731
  license: "MIT",
@@ -695,7 +4750,7 @@ var package_default = {
695
4750
  "./mcp": "./src/mcp/server.ts"
696
4751
  },
697
4752
  bin: {
698
- "deepseek-web-retrieval": "./dist/cli.js"
4753
+ "deepseek-web-retrieval": "dist/cli.js"
699
4754
  },
700
4755
  files: [
701
4756
  "index.ts",
@@ -715,7 +4770,7 @@ var package_default = {
715
4770
  "test:e2e": "bun run test/e2e/run.ts",
716
4771
  "docs:matrix": "bun run scripts/render-matrix.ts",
717
4772
  "test:coverage": "bun test --coverage",
718
- check: "bun run typecheck && bun run build && bun test"
4773
+ check: "bun run typecheck && bun run docs:matrix --check && bun run build && bun test"
719
4774
  },
720
4775
  peerDependencies: {
721
4776
  "@opencode/plugin": "^2.0.32"
@@ -733,37 +4788,12 @@ var package_default = {
733
4788
  },
734
4789
  dependencies: {
735
4790
  "@modelcontextprotocol/server": "^2.3.1",
4791
+ "jsonc-parser": "^3.3.1",
4792
+ "smol-toml": "^1.9.1",
736
4793
  zod: "^4"
737
4794
  }
738
4795
  };
739
4796
 
740
- // src/mcp/format.ts
741
- function formatSearchResults(results) {
742
- if (results.length === 0)
743
- return "No results found.";
744
- return results.map((result, index) => {
745
- const title = result.title?.trim() || result.url;
746
- const lines = [`${index + 1}. [${escapeBrackets(title)}](${result.url})`];
747
- if (result.content) {
748
- lines.push(` ${result.content.replaceAll(`
749
- `, " ")}`);
750
- }
751
- if (result.time.published !== undefined) {
752
- lines.push(` Published: ${formatPublished(result.time.published)}`);
753
- }
754
- return lines.join(`
755
- `);
756
- }).join(`
757
-
758
- `);
759
- }
760
- function escapeBrackets(value) {
761
- return value.replaceAll("[", "\\[").replaceAll("]", "\\]");
762
- }
763
- function formatPublished(epochMs) {
764
- return new Date(epochMs).toISOString().slice(0, 10);
765
- }
766
-
767
4797
  // src/mcp/server.ts
768
4798
  var MCP_SERVER_NAME = "deepseek-web-retrieval";
769
4799
  var SEARCH_INPUT = z.object({
@@ -786,54 +4816,55 @@ var FETCH_OUTPUT = z.object({
786
4816
  content: z.string(),
787
4817
  truncated: z.boolean()
788
4818
  });
789
- var SEARCH_DESCRIPTION = "Search the web with DeepSeek's in-house search engine and return a short, filtered result " + "list (title, URL, summary). Results are ranked by relevance and source authority, deduplicated " + "by URL, and capped at the configured maximum. An empty result list is normal, not an error. " + "Use site:/-site: operators in the query to include or exclude domains; the full query must stay " + "within 128 characters. To read a full page, pass a result URL to the deepseek_fetch tool.";
790
- var FETCH_DESCRIPTION = "Fetch one web page as clean Markdown through DeepSeek's Fetch API. DeepSeek does not render " + "JavaScript and cannot reach private networks; PDFs, images, and other binary files are " + "unsupported. Output is truncated to the configured size.";
4819
+ var SEARCH_DESCRIPTION = "Search the web with DeepSeek's in-house search engine and return a short, filtered result " + "list (title, URL, summary). " + `${SEARCH_RANKED_FILTERED} ` + `${SEARCH_EMPTY_IS_NORMAL} ` + `${SEARCH_QUERY_OPERATORS} ` + "To read a full page, pass a result URL to the deepseek_fetch tool.";
4820
+ var FETCH_DESCRIPTION = "Fetch one web page as clean Markdown through DeepSeek's Fetch API. " + `${FETCH_SERVICE_LIMITS} ` + `${FETCH_OUTPUT_TRUNCATED}`;
791
4821
  function createDeepSeekServer(config, env = process.env) {
792
4822
  const server = new McpServer({ name: MCP_SERVER_NAME, version: package_default.version });
793
- server.registerTool("deepseek_web_search", {
794
- title: "DeepSeek Web Search",
795
- description: SEARCH_DESCRIPTION,
796
- inputSchema: SEARCH_INPUT,
797
- outputSchema: SEARCH_OUTPUT,
798
- annotations: { readOnlyHint: true }
799
- }, async ({ query }, ctx) => {
800
- try {
801
- const request = requestContext(config, env, ctx.mcpReq.signal);
802
- const results = await searchWeb(query, config.search, request);
803
- return {
804
- content: [{ type: "text", text: formatSearchResults(results) }],
805
- structuredContent: { results: results.map(toStructuredResult) }
806
- };
807
- } catch (error) {
808
- return toErrorResult(error);
809
- }
810
- });
811
- server.registerTool("deepseek_fetch", {
812
- title: "DeepSeek Fetch",
813
- description: FETCH_DESCRIPTION,
814
- inputSchema: FETCH_INPUT,
815
- outputSchema: FETCH_OUTPUT,
816
- annotations: { readOnlyHint: true }
817
- }, async ({ url }, ctx) => {
818
- try {
819
- const request = requestContext(config, env, ctx.mcpReq.signal);
820
- const target = parseFetchUrl(url);
821
- assertFetchHostPolicy(target, config.fetch);
822
- const page = await fetchPage(target, config.fetch, request);
823
- const formatted = formatFetchedContent(page.title, page.content, config.fetch.maxChars);
824
- return {
825
- content: [{ type: "text", text: formatted.content }],
826
- structuredContent: {
827
- url: page.url,
828
- title: page.title,
829
- content: formatted.content,
830
- truncated: formatted.truncated
831
- }
832
- };
833
- } catch (error) {
834
- return toErrorResult(error);
835
- }
836
- });
4823
+ if (config.search.enabled) {
4824
+ server.registerTool("deepseek_web_search", {
4825
+ title: "DeepSeek Web Search",
4826
+ description: SEARCH_DESCRIPTION,
4827
+ inputSchema: SEARCH_INPUT,
4828
+ outputSchema: SEARCH_OUTPUT,
4829
+ annotations: { readOnlyHint: true }
4830
+ }, async ({ query }, ctx) => {
4831
+ try {
4832
+ const request = requestContext(config, env, ctx.mcpReq.signal);
4833
+ const results = await searchWeb(query, config.search, request);
4834
+ return {
4835
+ content: [{ type: "text", text: formatSearchResults(results) }],
4836
+ structuredContent: { results: results.map(toStructuredResult) }
4837
+ };
4838
+ } catch (error) {
4839
+ return toErrorResult(error);
4840
+ }
4841
+ });
4842
+ }
4843
+ if (config.fetch.enabled) {
4844
+ server.registerTool("deepseek_fetch", {
4845
+ title: "DeepSeek Fetch",
4846
+ description: FETCH_DESCRIPTION,
4847
+ inputSchema: FETCH_INPUT,
4848
+ outputSchema: FETCH_OUTPUT,
4849
+ annotations: { readOnlyHint: true }
4850
+ }, async ({ url }, ctx) => {
4851
+ try {
4852
+ const request = requestContext(config, env, ctx.mcpReq.signal);
4853
+ const page = await fetchDocument(url, config.fetch, request);
4854
+ return {
4855
+ content: [{ type: "text", text: page.content }],
4856
+ structuredContent: {
4857
+ url: page.url,
4858
+ title: page.title,
4859
+ content: page.content,
4860
+ truncated: page.truncated
4861
+ }
4862
+ };
4863
+ } catch (error) {
4864
+ return toErrorResult(error);
4865
+ }
4866
+ });
4867
+ }
837
4868
  return server;
838
4869
  }
839
4870
  function requestContext(config, env, signal) {
@@ -844,22 +4875,41 @@ function toStructuredResult(result) {
844
4875
  url: result.url,
845
4876
  ...result.title ? { title: result.title } : {},
846
4877
  ...result.content ? { content: result.content } : {},
847
- ...result.time.published !== undefined ? { published: result.time.published } : {}
4878
+ ...result.published !== undefined ? { published: result.published } : {}
848
4879
  };
849
4880
  }
4881
+ function servePrecheck(config) {
4882
+ if (config.search.enabled || config.fetch.enabled)
4883
+ return;
4884
+ return `Both tools are disabled (${ENABLE_SEARCH_ENV} and ${ENABLE_FETCH_ENV} are false); ` + "at least one must stay enabled.";
4885
+ }
850
4886
  function toErrorResult(error) {
851
4887
  const message = error instanceof Error ? error.message : String(error);
852
4888
  return { content: [{ type: "text", text: message }], isError: true };
853
4889
  }
854
4890
 
855
4891
  // src/mcp/cli.ts
4892
+ var subcommand = process.argv[2];
4893
+ if (subcommand === "init" || subcommand === "uninstall" || subcommand === "list") {
4894
+ const { runInstallerCli: runInstallerCli2 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
4895
+ process.exit(await runInstallerCli2(process.argv.slice(2)));
4896
+ }
856
4897
  var env = process.env;
857
4898
  if (!apiKeyFromEnv(env)) {
858
4899
  console.error(MISSING_API_KEY_MESSAGE);
859
4900
  process.exit(1);
860
4901
  }
861
4902
  var config = resolveEnvOptions(env);
4903
+ var precheck = servePrecheck(config);
4904
+ if (precheck) {
4905
+ console.error(precheck);
4906
+ process.exit(1);
4907
+ }
862
4908
  var handle = serveStdio(() => createDeepSeekServer(config, env));
863
- console.error(`deepseek-web-retrieval MCP server on stdio ` + `(search: max ${config.search.maxResults} results, fetch: max ${config.fetch.maxChars} chars)`);
4909
+ var tools = [
4910
+ config.search.enabled ? `search (max ${config.search.maxResults} results)` : null,
4911
+ config.fetch.enabled ? `fetch (max ${config.fetch.maxChars} chars)` : null
4912
+ ].filter(Boolean).join(", ");
4913
+ console.error(`deepseek-web-retrieval MCP server on stdio (${tools})`);
864
4914
  process.on("SIGINT", () => void handle.close());
865
4915
  process.on("SIGTERM", () => void handle.close());