terminal-pilot 0.0.19 → 0.0.21

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 (52) hide show
  1. package/dist/cli.js +1076 -496
  2. package/dist/cli.js.map +4 -4
  3. package/dist/commands/close-session.js.map +1 -1
  4. package/dist/commands/create-session.js.map +1 -1
  5. package/dist/commands/fill.js.map +1 -1
  6. package/dist/commands/get-session.js.map +1 -1
  7. package/dist/commands/index.js +481 -163
  8. package/dist/commands/index.js.map +4 -4
  9. package/dist/commands/install.js +448 -130
  10. package/dist/commands/install.js.map +4 -4
  11. package/dist/commands/installer.js +154 -60
  12. package/dist/commands/installer.js.map +4 -4
  13. package/dist/commands/list-sessions.js.map +1 -1
  14. package/dist/commands/press-key.js.map +1 -1
  15. package/dist/commands/read-history.js.map +1 -1
  16. package/dist/commands/read-screen.js.map +1 -1
  17. package/dist/commands/resize.js.map +1 -1
  18. package/dist/commands/runtime.js.map +1 -1
  19. package/dist/commands/screenshot.js.map +1 -1
  20. package/dist/commands/send-signal.js.map +1 -1
  21. package/dist/commands/type.js.map +1 -1
  22. package/dist/commands/uninstall.js +187 -93
  23. package/dist/commands/uninstall.js.map +4 -4
  24. package/dist/commands/wait-for-exit.js.map +1 -1
  25. package/dist/commands/wait-for.js.map +1 -1
  26. package/dist/testing/cli-repl.js +1072 -492
  27. package/dist/testing/cli-repl.js.map +4 -4
  28. package/dist/testing/qa-cli.js +1082 -502
  29. package/dist/testing/qa-cli.js.map +4 -4
  30. package/node_modules/@poe-code/agent-skill-config/README.md +103 -0
  31. package/node_modules/@poe-code/agent-skill-config/dist/apply.d.ts +25 -0
  32. package/node_modules/@poe-code/agent-skill-config/dist/apply.js +159 -0
  33. package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.d.ts +23 -0
  34. package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.js +341 -0
  35. package/node_modules/@poe-code/agent-skill-config/dist/configs.d.ts +16 -0
  36. package/node_modules/@poe-code/agent-skill-config/dist/configs.js +70 -0
  37. package/node_modules/@poe-code/agent-skill-config/dist/exports.compile-check.d.ts +1 -0
  38. package/node_modules/@poe-code/agent-skill-config/dist/exports.compile-check.js +1 -0
  39. package/node_modules/@poe-code/agent-skill-config/dist/git-exclude.d.ts +8 -0
  40. package/node_modules/@poe-code/agent-skill-config/dist/git-exclude.js +159 -0
  41. package/node_modules/@poe-code/agent-skill-config/dist/index.d.ts +11 -0
  42. package/node_modules/@poe-code/agent-skill-config/dist/index.js +6 -0
  43. package/node_modules/@poe-code/agent-skill-config/dist/resolve-skill-reference.d.ts +22 -0
  44. package/node_modules/@poe-code/agent-skill-config/dist/resolve-skill-reference.js +87 -0
  45. package/node_modules/@poe-code/agent-skill-config/dist/templates/poe-generate.md +47 -0
  46. package/node_modules/@poe-code/agent-skill-config/dist/templates/terminal-pilot.md +45 -0
  47. package/node_modules/@poe-code/agent-skill-config/dist/templates.d.ts +3 -0
  48. package/node_modules/@poe-code/agent-skill-config/dist/templates.js +63 -0
  49. package/node_modules/@poe-code/agent-skill-config/dist/types.d.ts +16 -0
  50. package/node_modules/@poe-code/agent-skill-config/dist/types.js +1 -0
  51. package/node_modules/@poe-code/agent-skill-config/package.json +24 -0
  52. package/package.json +4 -2
@@ -78,13 +78,13 @@ function consumeTerminatedString(input, index, allowBellTerminator) {
78
78
  }
79
79
 
80
80
  // src/cli.ts
81
- import { realpath as realpath2 } from "node:fs/promises";
82
- import path22 from "node:path";
81
+ import { realpath as realpath3 } from "node:fs/promises";
82
+ import path23 from "node:path";
83
83
  import { fileURLToPath as fileURLToPath5 } from "node:url";
84
84
 
85
85
  // ../toolcraft/src/cli.ts
86
86
  import { access as access2, lstat as lstat3, readFile as readFile4, rename as rename3, unlink as unlink2, writeFile as writeFile5 } from "node:fs/promises";
87
- import path13 from "node:path";
87
+ import path14 from "node:path";
88
88
  import {
89
89
  Command as CommanderCommand,
90
90
  CommanderError as CommanderError2,
@@ -92,7 +92,7 @@ import {
92
92
  Option
93
93
  } from "commander";
94
94
 
95
- // ../design-system/src/internal/color-support.ts
95
+ // ../toolcraft-design/src/internal/color-support.ts
96
96
  function supportsColor(env = process.env, stream = process.stdout) {
97
97
  if (env.FORCE_COLOR !== void 0 && env.FORCE_COLOR !== "0") {
98
98
  return true;
@@ -106,7 +106,7 @@ function supportsColor(env = process.env, stream = process.stdout) {
106
106
  return typeof env.TERM === "string" && env.TERM.length > 0 && env.TERM !== "dumb";
107
107
  }
108
108
 
109
- // ../design-system/src/components/color.ts
109
+ // ../toolcraft-design/src/components/color.ts
110
110
  var reset = "\x1B[0m";
111
111
  var ansiStyles = {
112
112
  reset: { open: reset },
@@ -208,41 +208,135 @@ function createColor(styles = []) {
208
208
  }
209
209
  var color = createColor();
210
210
 
211
- // ../design-system/src/tokens/colors.ts
212
- var dark = {
213
- header: (text5) => color.magentaBright.bold(text5),
214
- divider: (text5) => color.dim(text5),
215
- prompt: (text5) => color.cyan(text5),
216
- number: (text5) => color.cyanBright(text5),
217
- intro: (text5) => color.bgMagenta.white(` Poe - ${text5} `),
218
- resolvedSymbol: color.magenta("\u25C7"),
219
- errorSymbol: color.red("\u25A0"),
220
- accent: (text5) => color.cyan(text5),
221
- muted: (text5) => color.dim(text5),
222
- success: (text5) => color.green(text5),
223
- warning: (text5) => color.yellow(text5),
224
- error: (text5) => color.red(text5),
225
- info: (text5) => color.magenta(text5),
226
- badge: (text5) => color.bgYellow.black(` ${text5} `)
211
+ // ../toolcraft-design/src/tokens/brand.ts
212
+ var brands = {
213
+ purple: { name: "purple", primary: "#a200ff" },
214
+ blue: { name: "blue", primary: "#2f6fed" },
215
+ green: { name: "green", primary: "#1f9d57" }
227
216
  };
228
- var light = {
229
- header: (text5) => color.hex("#a200ff").bold(text5),
230
- divider: (text5) => color.hex("#666666")(text5),
231
- prompt: (text5) => color.hex("#006699").bold(text5),
232
- number: (text5) => color.hex("#0077cc").bold(text5),
233
- intro: (text5) => color.bgHex("#a200ff").white(` Poe - ${text5} `),
234
- resolvedSymbol: color.hex("#a200ff")("\u25C7"),
235
- errorSymbol: color.hex("#cc0000")("\u25A0"),
236
- accent: (text5) => color.hex("#006699").bold(text5),
237
- muted: (text5) => color.hex("#666666")(text5),
238
- success: (text5) => color.hex("#008800")(text5),
239
- warning: (text5) => color.hex("#cc6600")(text5),
240
- error: (text5) => color.hex("#cc0000")(text5),
241
- info: (text5) => color.hex("#a200ff")(text5),
242
- badge: (text5) => color.bgHex("#cc6600").white(` ${text5} `)
217
+
218
+ // ../toolcraft-design/src/internal/theme-state.ts
219
+ var defaults = {
220
+ brand: "purple",
221
+ label: "Poe"
243
222
  };
223
+ var config = { ...defaults };
224
+ var revision = 0;
225
+ var brandConfigured = false;
226
+ function configureTheme(patch) {
227
+ if (patch.brand !== void 0 && !Object.hasOwn(brands, patch.brand)) {
228
+ throw new Error(`Unknown brand: ${patch.brand}`);
229
+ }
230
+ config = {
231
+ brand: patch.brand ?? config.brand,
232
+ label: patch.label ?? config.label
233
+ };
234
+ if (patch.brand !== void 0) {
235
+ brandConfigured = true;
236
+ }
237
+ revision += 1;
238
+ }
239
+ function getThemeConfig() {
240
+ return { ...config };
241
+ }
242
+ function getThemeRevision() {
243
+ return revision;
244
+ }
245
+ function isThemeBrandConfigured() {
246
+ return brandConfigured;
247
+ }
248
+
249
+ // ../toolcraft-design/src/tokens/colors.ts
250
+ var brand = brands.purple.primary;
251
+ function withStyles(palette, styles) {
252
+ return Object.defineProperty(palette, "styles", {
253
+ value: styles,
254
+ enumerable: false
255
+ });
256
+ }
257
+ function brandColor(activeBrand, purple) {
258
+ return activeBrand.name === "purple" ? purple : color.hex(activeBrand.primary);
259
+ }
260
+ function brandBackground(activeBrand, purple) {
261
+ return activeBrand.name === "purple" ? purple : color.bgHex(activeBrand.primary);
262
+ }
263
+ function createPalette(activeBrand, mode) {
264
+ const isPurple = activeBrand.name === "purple";
265
+ if (mode === "light") {
266
+ const active2 = color.hex(activeBrand.primary);
267
+ const prompt2 = isPurple ? color.hex("#006699") : active2;
268
+ const number2 = isPurple ? color.hex("#0077cc") : active2;
269
+ return withStyles(
270
+ {
271
+ header: (text5) => active2.bold(text5),
272
+ divider: (text5) => color.hex("#666666")(text5),
273
+ prompt: (text5) => prompt2.bold(text5),
274
+ number: (text5) => number2.bold(text5),
275
+ intro: (text5) => color.bgHex(activeBrand.primary).white(` ${getThemeConfig().label} - ${text5} `),
276
+ get resolvedSymbol() {
277
+ return active2("\u25C7");
278
+ },
279
+ get errorSymbol() {
280
+ return color.hex("#cc0000")("\u25A0");
281
+ },
282
+ accent: (text5) => prompt2.bold(text5),
283
+ muted: (text5) => color.hex("#666666")(text5),
284
+ success: (text5) => color.hex("#008800")(text5),
285
+ warning: (text5) => color.hex("#cc6600")(text5),
286
+ error: (text5) => color.hex("#cc0000")(text5),
287
+ info: (text5) => active2(text5),
288
+ badge: (text5) => color.bgHex("#cc6600").white(` ${text5} `)
289
+ },
290
+ {
291
+ accent: { fg: isPurple ? "#006699" : activeBrand.primary, bold: true },
292
+ muted: { fg: "#666666" },
293
+ success: { fg: "#008800" },
294
+ warning: { fg: "#cc6600" },
295
+ error: { fg: "#cc0000" },
296
+ info: { fg: activeBrand.primary }
297
+ }
298
+ );
299
+ }
300
+ const active = brandColor(activeBrand, color.magenta);
301
+ const activeBright = brandColor(activeBrand, color.magentaBright);
302
+ const activeBackground = brandBackground(activeBrand, color.bgMagenta);
303
+ const prompt = isPurple ? color.cyan : active;
304
+ const number = isPurple ? color.cyanBright : active;
305
+ return withStyles(
306
+ {
307
+ header: (text5) => activeBright.bold(text5),
308
+ divider: (text5) => color.dim(text5),
309
+ prompt: (text5) => prompt(text5),
310
+ number: (text5) => number(text5),
311
+ intro: (text5) => activeBackground.white(` ${getThemeConfig().label} - ${text5} `),
312
+ get resolvedSymbol() {
313
+ return active("\u25C7");
314
+ },
315
+ get errorSymbol() {
316
+ return color.red("\u25A0");
317
+ },
318
+ accent: (text5) => prompt(text5),
319
+ muted: (text5) => color.dim(text5),
320
+ success: (text5) => color.green(text5),
321
+ warning: (text5) => color.yellow(text5),
322
+ error: (text5) => color.red(text5),
323
+ info: (text5) => active(text5),
324
+ badge: (text5) => color.bgYellow.black(` ${text5} `)
325
+ },
326
+ {
327
+ accent: { fg: isPurple ? "cyan" : activeBrand.primary, bold: true },
328
+ muted: { dim: true },
329
+ success: { fg: "green" },
330
+ warning: { fg: "yellow" },
331
+ error: { fg: "red" },
332
+ info: { fg: isPurple ? "magenta" : activeBrand.primary }
333
+ }
334
+ );
335
+ }
336
+ var dark = createPalette(brands.purple, "dark");
337
+ var light = createPalette(brands.purple, "light");
244
338
 
245
- // ../design-system/src/tokens/typography.ts
339
+ // ../toolcraft-design/src/tokens/typography.ts
246
340
  var typography = {
247
341
  bold: (text5) => color.bold(text5),
248
342
  dim: (text5) => color.dim(text5),
@@ -251,14 +345,14 @@ var typography = {
251
345
  strikethrough: (text5) => color.strikethrough(text5)
252
346
  };
253
347
 
254
- // ../design-system/src/tokens/widths.ts
348
+ // ../toolcraft-design/src/tokens/widths.ts
255
349
  var widths = {
256
350
  header: 60,
257
351
  helpColumn: 24,
258
352
  maxLine: 80
259
353
  };
260
354
 
261
- // ../design-system/src/internal/output-format.ts
355
+ // ../toolcraft-design/src/internal/output-format.ts
262
356
  import { AsyncLocalStorage } from "node:async_hooks";
263
357
  var VALID_FORMATS = /* @__PURE__ */ new Set(["terminal", "markdown", "json"]);
264
358
  var formatStorage = new AsyncLocalStorage();
@@ -279,7 +373,7 @@ function resetOutputFormatCache() {
279
373
  cached = void 0;
280
374
  }
281
375
 
282
- // ../design-system/src/internal/theme-detect.ts
376
+ // ../toolcraft-design/src/internal/theme-detect.ts
283
377
  function detectThemeFromEnv(env) {
284
378
  const apple = env.APPLE_INTERFACE_STYLE;
285
379
  if (typeof apple === "string") {
@@ -316,17 +410,30 @@ function resolveThemeName(env = process.env) {
316
410
  }
317
411
  return "dark";
318
412
  }
319
- var cachedTheme;
413
+ var themeCache = /* @__PURE__ */ new Map();
414
+ var cachedRevision = -1;
320
415
  function getTheme(env) {
416
+ const themeName = resolveThemeName(env);
417
+ const config2 = getThemeConfig();
418
+ const requestedBrand = env?.POE_BRAND?.toLowerCase();
419
+ const activeBrandName = !isThemeBrandConfigured() && requestedBrand && Object.hasOwn(brands, requestedBrand) ? requestedBrand : config2.brand;
420
+ const revision2 = getThemeRevision();
421
+ if (revision2 !== cachedRevision) {
422
+ themeCache.clear();
423
+ cachedRevision = revision2;
424
+ }
425
+ const cacheKey = `${activeBrandName}:${themeName}`;
426
+ const cachedTheme = themeCache.get(cacheKey);
321
427
  if (cachedTheme) {
322
428
  return cachedTheme;
323
429
  }
324
- const themeName = resolveThemeName(env);
325
- cachedTheme = themeName === "light" ? light : dark;
326
- return cachedTheme;
430
+ const activeBrand = brands[activeBrandName];
431
+ const theme = activeBrandName === "purple" ? themeName === "light" ? light : dark : createPalette(activeBrand, themeName);
432
+ themeCache.set(cacheKey, theme);
433
+ return theme;
327
434
  }
328
435
 
329
- // ../design-system/src/components/text.ts
436
+ // ../toolcraft-design/src/components/text.ts
330
437
  function renderMarkdownInline(content) {
331
438
  return content.replaceAll("\r\n", " ").replaceAll("\n", " ").replaceAll("\r", " ");
332
439
  }
@@ -442,7 +549,7 @@ var text = {
442
549
  }
443
550
  };
444
551
 
445
- // ../design-system/src/components/symbols.ts
552
+ // ../toolcraft-design/src/components/symbols.ts
446
553
  var symbols = {
447
554
  get info() {
448
555
  const format = resolveOutputFormat();
@@ -496,12 +603,12 @@ var symbols = {
496
603
  }
497
604
  };
498
605
 
499
- // ../design-system/src/internal/strip-ansi.ts
606
+ // ../toolcraft-design/src/internal/strip-ansi.ts
500
607
  function stripAnsi2(value) {
501
608
  return value.replace(/\u001b\[[0-9;]*m/g, "");
502
609
  }
503
610
 
504
- // ../design-system/src/prompts/primitives/log.ts
611
+ // ../toolcraft-design/src/prompts/primitives/log.ts
505
612
  function renderMarkdownInline2(value) {
506
613
  return stripAnsi2(value).replaceAll("\r\n", " ").replaceAll("\n", " ").replaceAll("\r", " ");
507
614
  }
@@ -628,7 +735,7 @@ var log = {
628
735
  error
629
736
  };
630
737
 
631
- // ../design-system/src/components/logger.ts
738
+ // ../toolcraft-design/src/components/logger.ts
632
739
  function createLogger(emitter) {
633
740
  const emit = (level, message2) => {
634
741
  if (emitter) {
@@ -689,7 +796,7 @@ function createLogger(emitter) {
689
796
  }
690
797
  var logger = createLogger();
691
798
 
692
- // ../design-system/src/components/help-formatter.ts
799
+ // ../toolcraft-design/src/components/help-formatter.ts
693
800
  var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
694
801
  function normalizeInline(value) {
695
802
  return value.replaceAll("\r\n", " ").replaceAll("\n", " ").replaceAll("\r", " ");
@@ -865,7 +972,7 @@ function formatOptionList(options) {
865
972
  });
866
973
  }
867
974
 
868
- // ../design-system/src/components/help-formatter-plain.ts
975
+ // ../toolcraft-design/src/components/help-formatter-plain.ts
869
976
  var help_formatter_plain_exports = {};
870
977
  __export(help_formatter_plain_exports, {
871
978
  formatColumns: () => formatColumns2,
@@ -1002,7 +1109,7 @@ function formatOptionList2(options) {
1002
1109
  });
1003
1110
  }
1004
1111
 
1005
- // ../design-system/src/components/table.ts
1112
+ // ../toolcraft-design/src/components/table.ts
1006
1113
  var reset2 = "\x1B[0m";
1007
1114
  var ellipsis = "\u2026";
1008
1115
  var graphemeSegmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
@@ -1286,7 +1393,7 @@ function renderTable(options) {
1286
1393
  }
1287
1394
  }
1288
1395
 
1289
- // ../design-system/src/components/detail-card.ts
1396
+ // ../toolcraft-design/src/components/detail-card.ts
1290
1397
  function wrap(value, width) {
1291
1398
  const lines = [];
1292
1399
  for (const paragraph of value.split("\n")) {
@@ -1349,7 +1456,8 @@ ${options.theme.muted(options.badges.map((badge) => badge[0] + badge.slice(1).to
1349
1456
  return blocks.join("\n\n");
1350
1457
  }
1351
1458
 
1352
- // ../design-system/src/components/template.ts
1459
+ // ../toolcraft-design/src/components/template.ts
1460
+ var MAX_PARTIAL_DEPTH = 100;
1353
1461
  var HTML_ESCAPE = {
1354
1462
  "&": "&",
1355
1463
  "<": "&lt;",
@@ -1361,14 +1469,27 @@ var HTML_ESCAPE = {
1361
1469
  "=": "&#x3D;"
1362
1470
  };
1363
1471
  function renderTemplate(template, view, options = {}) {
1364
- const prepared = options.yield === void 0 ? template : template.split("{{yield}}").join(options.yield);
1472
+ const prepared = options.yield === void 0 ? template : resolveTemplatePartials(template, options.partials ?? {}).split("{{yield}}").join(options.yield);
1365
1473
  const tokens = parseTemplate(prepared);
1366
- const escape = options.escape === "none" ? String : escapeHtml;
1367
- const preserveMissing = options.yield !== void 0 && options.escape === "none";
1368
- return renderTokens(tokens, { view }, prepared, escape, preserveMissing);
1474
+ validatePartialReferences(tokens, options.partials ?? {}, []);
1475
+ if (options.validate === true) {
1476
+ const expanded = resolveTemplatePartials(prepared, options.partials ?? {});
1477
+ validateVariables(parseTemplate(expanded), { view });
1478
+ }
1479
+ const state = {
1480
+ escape: options.escape === "none" ? String : escapeHtml,
1481
+ partials: options.partials ?? {},
1482
+ partialStack: [],
1483
+ preserveMissing: options.yield !== void 0 && options.escape === "none",
1484
+ validate: options.validate === true
1485
+ };
1486
+ return renderTokens(tokens, { view }, prepared, state);
1487
+ }
1488
+ function resolveTemplatePartials(template, partials) {
1489
+ return expandTemplatePartials(template, partials, []);
1369
1490
  }
1370
- function renderTemplateInContext(template, context, escape, preserveMissing) {
1371
- return renderTokens(parseTemplate(template), context, template, escape, preserveMissing);
1491
+ function renderTemplateInContext(template, context, state) {
1492
+ return renderTokens(parseTemplate(template), context, template, state);
1372
1493
  }
1373
1494
  function parseTemplate(template) {
1374
1495
  const root = [];
@@ -1391,9 +1512,6 @@ function parseTemplate(template) {
1391
1512
  index = standalone?.nextIndex ?? parsed.end;
1392
1513
  continue;
1393
1514
  }
1394
- if (parsed.kind === "partial") {
1395
- throw new Error(`Partials are not supported: "${parsed.name}"`);
1396
- }
1397
1515
  if (parsed.kind === "delimiter") {
1398
1516
  throw new Error("Custom delimiters are not supported");
1399
1517
  }
@@ -1411,6 +1529,15 @@ function parseTemplate(template) {
1411
1529
  index = standalone?.nextIndex ?? parsed.end;
1412
1530
  continue;
1413
1531
  }
1532
+ if (parsed.kind === "partial") {
1533
+ tokens.push({
1534
+ type: "partial",
1535
+ name: parsed.name,
1536
+ indent: standalone === void 0 ? "" : template.slice(standalone.lineStart, open)
1537
+ });
1538
+ index = standalone?.nextIndex ?? parsed.end;
1539
+ continue;
1540
+ }
1414
1541
  if (parsed.kind === "close") {
1415
1542
  const frame2 = stack.pop();
1416
1543
  if (frame2 === void 0) {
@@ -1481,7 +1608,7 @@ function getStandalone(template, tagStart, tagEnd, kind) {
1481
1608
  }
1482
1609
  return void 0;
1483
1610
  }
1484
- function renderTokens(tokens, context, template, escape, preserveMissing) {
1611
+ function renderTokens(tokens, context, template, state) {
1485
1612
  let output = "";
1486
1613
  for (const token of tokens) {
1487
1614
  switch (token.type) {
@@ -1490,32 +1617,62 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
1490
1617
  continue;
1491
1618
  case "name":
1492
1619
  case "unescaped": {
1493
- const value = lookup(context, token.name);
1494
- if (value == null) {
1495
- if (preserveMissing) {
1620
+ const result = lookup(context, token.name);
1621
+ if (!result.hit || result.value == null) {
1622
+ if (state.validate) {
1623
+ throw new Error(`Template variable "${token.name}" not found.`);
1624
+ }
1625
+ if (state.preserveMissing) {
1496
1626
  output += token.raw;
1497
1627
  }
1498
1628
  continue;
1499
1629
  }
1500
- const rendered = String(value);
1501
- output += token.type === "name" ? escape(rendered) : rendered;
1630
+ const rendered = String(result.value);
1631
+ output += token.type === "name" ? state.escape(rendered) : rendered;
1632
+ continue;
1633
+ }
1634
+ case "partial": {
1635
+ if (!Object.hasOwn(state.partials, token.name)) {
1636
+ throw new Error(`Partial "${token.name}" not found.`);
1637
+ }
1638
+ if (state.partialStack.includes(token.name)) {
1639
+ throw new Error(
1640
+ `Circular partial reference detected: ${[...state.partialStack, token.name].join(" -> ")}.`
1641
+ );
1642
+ }
1643
+ if (state.partialStack.length >= MAX_PARTIAL_DEPTH) {
1644
+ throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
1645
+ }
1646
+ const partial = indentPartial(state.partials[token.name], token.indent);
1647
+ output += renderTokens(parseTemplate(partial), context, partial, {
1648
+ ...state,
1649
+ partialStack: [...state.partialStack, token.name]
1650
+ });
1502
1651
  continue;
1503
1652
  }
1504
1653
  case "inverted": {
1505
- const value = lookup(context, token.name);
1654
+ const result = lookup(context, token.name);
1655
+ if (!result.hit && state.validate) {
1656
+ throw new Error(`Template variable "${token.name}" not found.`);
1657
+ }
1658
+ const value = result.value;
1506
1659
  if (!value || Array.isArray(value) && value.length === 0) {
1507
- output += renderTokens(token.children, context, template, escape, preserveMissing);
1660
+ output += renderTokens(token.children, context, template, state);
1508
1661
  }
1509
1662
  continue;
1510
1663
  }
1511
1664
  case "section": {
1512
- const value = lookup(context, token.name);
1665
+ const result = lookup(context, token.name);
1666
+ if (!result.hit && state.validate) {
1667
+ throw new Error(`Template variable "${token.name}" not found.`);
1668
+ }
1669
+ const value = result.value;
1513
1670
  if (!value) {
1514
1671
  continue;
1515
1672
  }
1516
1673
  if (Array.isArray(value)) {
1517
1674
  for (const item of value) {
1518
- output += renderTokens(token.children, pushContext(context, item), template, escape, preserveMissing);
1675
+ output += renderTokens(token.children, pushContext(context, item), template, state);
1519
1676
  }
1520
1677
  continue;
1521
1678
  }
@@ -1524,7 +1681,7 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
1524
1681
  const rendered = value.call(
1525
1682
  context.view,
1526
1683
  raw,
1527
- (nextTemplate) => renderTemplateInContext(nextTemplate, context, escape, preserveMissing)
1684
+ (nextTemplate) => renderTemplateInContext(nextTemplate, context, state)
1528
1685
  );
1529
1686
  if (rendered != null) {
1530
1687
  output += String(rendered);
@@ -1532,10 +1689,10 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
1532
1689
  continue;
1533
1690
  }
1534
1691
  if (typeof value === "object" || typeof value === "string" || typeof value === "number") {
1535
- output += renderTokens(token.children, pushContext(context, value), template, escape, preserveMissing);
1692
+ output += renderTokens(token.children, pushContext(context, value), template, state);
1536
1693
  continue;
1537
1694
  }
1538
- output += renderTokens(token.children, context, template, escape, preserveMissing);
1695
+ output += renderTokens(token.children, context, template, state);
1539
1696
  }
1540
1697
  }
1541
1698
  }
@@ -1543,17 +1700,115 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
1543
1700
  }
1544
1701
  function lookup(context, name) {
1545
1702
  if (name === ".") {
1546
- return callLambda(context.view, context.view);
1703
+ return { hit: true, value: callLambda(context.view, context.view) };
1547
1704
  }
1548
1705
  let cursor = context;
1549
1706
  while (cursor !== void 0) {
1550
1707
  const result = name.includes(".") ? lookupDotted(cursor.view, name) : lookupName(cursor.view, name);
1551
1708
  if (result.hit) {
1552
- return callLambda(result.value, cursor.view);
1709
+ return { hit: true, value: callLambda(result.value, cursor.view) };
1553
1710
  }
1554
1711
  cursor = cursor.parent;
1555
1712
  }
1556
- return void 0;
1713
+ return { hit: false, value: void 0 };
1714
+ }
1715
+ function validateVariables(tokens, context) {
1716
+ for (const token of tokens) {
1717
+ if (token.type === "text" || token.type === "partial") {
1718
+ continue;
1719
+ }
1720
+ if (token.type === "name" || token.type === "unescaped") {
1721
+ if (!lookup(context, token.name).hit) {
1722
+ throw new Error(`Template variable "${token.name}" not found.`);
1723
+ }
1724
+ continue;
1725
+ }
1726
+ if (token.type !== "section" && token.type !== "inverted") {
1727
+ continue;
1728
+ }
1729
+ const result = lookup(context, token.name);
1730
+ if (!result.hit) {
1731
+ throw new Error(`Template variable "${token.name}" not found.`);
1732
+ }
1733
+ if (Array.isArray(result.value) && result.value.length > 0) {
1734
+ for (const item of result.value) {
1735
+ validateVariables(token.children, pushContext(context, item));
1736
+ }
1737
+ continue;
1738
+ }
1739
+ if (typeof result.value === "object" && result.value !== null || typeof result.value === "string" || typeof result.value === "number") {
1740
+ validateVariables(token.children, pushContext(context, result.value));
1741
+ continue;
1742
+ }
1743
+ validateVariables(token.children, context);
1744
+ }
1745
+ }
1746
+ function validatePartialReferences(tokens, partials, partialStack) {
1747
+ for (const token of tokens) {
1748
+ if (token.type === "section" || token.type === "inverted") {
1749
+ validatePartialReferences(token.children, partials, partialStack);
1750
+ continue;
1751
+ }
1752
+ if (token.type !== "partial") {
1753
+ continue;
1754
+ }
1755
+ if (!Object.hasOwn(partials, token.name)) {
1756
+ throw new Error(`Partial "${token.name}" not found.`);
1757
+ }
1758
+ if (partialStack.includes(token.name)) {
1759
+ throw new Error(
1760
+ `Circular partial reference detected: ${[...partialStack, token.name].join(" -> ")}.`
1761
+ );
1762
+ }
1763
+ if (partialStack.length >= MAX_PARTIAL_DEPTH) {
1764
+ throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
1765
+ }
1766
+ validatePartialReferences(parseTemplate(partials[token.name]), partials, [
1767
+ ...partialStack,
1768
+ token.name
1769
+ ]);
1770
+ }
1771
+ }
1772
+ function indentPartial(partial, indent) {
1773
+ if (indent === "") {
1774
+ return partial;
1775
+ }
1776
+ return partial.split("\n").map((line) => line === "" ? "" : `${indent}${line}`).join("\n");
1777
+ }
1778
+ function expandTemplatePartials(template, partials, partialStack) {
1779
+ let output = "";
1780
+ let index = 0;
1781
+ while (index < template.length) {
1782
+ const open = template.indexOf("{{", index);
1783
+ if (open === -1) {
1784
+ output += template.slice(index);
1785
+ break;
1786
+ }
1787
+ const parsed = parseTag(template, open);
1788
+ if (parsed.kind !== "partial") {
1789
+ output += template.slice(index, parsed.end);
1790
+ index = parsed.end;
1791
+ continue;
1792
+ }
1793
+ if (!Object.hasOwn(partials, parsed.name)) {
1794
+ throw new Error(`Partial "${parsed.name}" not found.`);
1795
+ }
1796
+ if (partialStack.includes(parsed.name)) {
1797
+ throw new Error(
1798
+ `Circular partial reference detected: ${[...partialStack, parsed.name].join(" -> ")}.`
1799
+ );
1800
+ }
1801
+ if (partialStack.length >= MAX_PARTIAL_DEPTH) {
1802
+ throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
1803
+ }
1804
+ const standalone = getStandalone(template, open, parsed.end, parsed.kind);
1805
+ const beforePartial = standalone === void 0 ? template.slice(index, open) : template.slice(index, standalone.lineStart);
1806
+ const indent = standalone === void 0 ? "" : template.slice(standalone.lineStart, open);
1807
+ const partial = indentPartial(partials[parsed.name], indent);
1808
+ output += beforePartial + expandTemplatePartials(partial, partials, [...partialStack, parsed.name]);
1809
+ index = standalone?.nextIndex ?? parsed.end;
1810
+ }
1811
+ return output;
1557
1812
  }
1558
1813
  function lookupName(view, name) {
1559
1814
  if (!isPropertyContainer(view) || !hasProperty(view, name)) {
@@ -1613,22 +1868,22 @@ function hasProperty(value, key2) {
1613
1868
  return Object.prototype.hasOwnProperty.call(value, key2);
1614
1869
  }
1615
1870
 
1616
- // ../design-system/src/components/browser.ts
1871
+ // ../toolcraft-design/src/components/browser.ts
1617
1872
  import { spawn } from "node:child_process";
1618
1873
  import process2 from "node:process";
1619
1874
 
1620
- // ../design-system/src/acp/writer.ts
1875
+ // ../toolcraft-design/src/acp/writer.ts
1621
1876
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
1622
1877
  var storage = new AsyncLocalStorage2();
1623
1878
 
1624
- // ../design-system/src/dashboard/terminal-width.ts
1879
+ // ../toolcraft-design/src/dashboard/terminal-width.ts
1625
1880
  var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1626
1881
 
1627
- // ../design-system/src/dashboard/terminal.ts
1882
+ // ../toolcraft-design/src/dashboard/terminal.ts
1628
1883
  import readline from "node:readline";
1629
1884
  import { PassThrough } from "node:stream";
1630
1885
 
1631
- // ../design-system/src/explorer/state.ts
1886
+ // ../toolcraft-design/src/explorer/state.ts
1632
1887
  var REGION_HEADER = 1 << 0;
1633
1888
  var REGION_LIST = 1 << 1;
1634
1889
  var REGION_DETAIL = 1 << 2;
@@ -1637,10 +1892,10 @@ var REGION_MODAL = 1 << 4;
1637
1892
  var REGION_TOAST = 1 << 5;
1638
1893
  var REGION_ALL = REGION_HEADER | REGION_LIST | REGION_DETAIL | REGION_FOOTER | REGION_MODAL | REGION_TOAST;
1639
1894
 
1640
- // ../design-system/src/prompts/index.ts
1895
+ // ../toolcraft-design/src/prompts/index.ts
1641
1896
  import * as clack from "@clack/prompts";
1642
1897
 
1643
- // ../design-system/src/prompts/primitives/cancel.ts
1898
+ // ../toolcraft-design/src/prompts/primitives/cancel.ts
1644
1899
  import { isCancel } from "@clack/prompts";
1645
1900
  function cancel(msg = "") {
1646
1901
  if (resolveOutputFormat() !== "terminal") {
@@ -1651,7 +1906,7 @@ function cancel(msg = "") {
1651
1906
  `);
1652
1907
  }
1653
1908
 
1654
- // ../design-system/src/prompts/primitives/note.ts
1909
+ // ../toolcraft-design/src/prompts/primitives/note.ts
1655
1910
  function getVisibleWidth(value) {
1656
1911
  return stripAnsi2(value).length;
1657
1912
  }
@@ -1700,10 +1955,10 @@ function note(message2, title) {
1700
1955
  `);
1701
1956
  }
1702
1957
 
1703
- // ../design-system/src/static/spinner.ts
1958
+ // ../toolcraft-design/src/static/spinner.ts
1704
1959
  var SPINNER_FRAMES = Object.freeze(["\u25D2", "\u25D0", "\u25D3", "\u25D1"]);
1705
1960
 
1706
- // ../design-system/src/prompts/index.ts
1961
+ // ../toolcraft-design/src/prompts/index.ts
1707
1962
  async function select2(opts) {
1708
1963
  return clack.select(opts);
1709
1964
  }
@@ -1746,19 +2001,19 @@ var ApprovalDeclinedError = class extends UserError {
1746
2001
  };
1747
2002
 
1748
2003
  // ../toolcraft/src/human-in-loop/config.ts
1749
- function validateHumanInLoopOnDefine(config) {
1750
- const label = Array.isArray(config.children) ? "group" : "command";
1751
- if (config.confirm === true && config.humanInLoop !== void 0 && config.humanInLoop !== null) {
1752
- throw new Error(`${label} '${config.name}': use either confirm or humanInLoop, not both`);
2004
+ function validateHumanInLoopOnDefine(config2) {
2005
+ const label = Array.isArray(config2.children) ? "group" : "command";
2006
+ if (config2.confirm === true && config2.humanInLoop !== void 0 && config2.humanInLoop !== null) {
2007
+ throw new Error(`${label} '${config2.name}': use either confirm or humanInLoop, not both`);
1753
2008
  }
1754
- if (config.humanInLoop === void 0 || config.humanInLoop === null) {
2009
+ if (config2.humanInLoop === void 0 || config2.humanInLoop === null) {
1755
2010
  return;
1756
2011
  }
1757
- if (config.humanInLoop.mode !== "sync" && config.humanInLoop.mode !== "async") {
1758
- throw new Error(`${label} '${config.name}': humanInLoop.mode must be "sync" or "async"`);
2012
+ if (config2.humanInLoop.mode !== "sync" && config2.humanInLoop.mode !== "async") {
2013
+ throw new Error(`${label} '${config2.name}': humanInLoop.mode must be "sync" or "async"`);
1759
2014
  }
1760
- if (typeof config.humanInLoop.message !== "function") {
1761
- throw new Error(`${label} '${config.name}': humanInLoop.message must be a function`);
2015
+ if (typeof config2.humanInLoop.message !== "function") {
2016
+ throw new Error(`${label} '${config2.name}': humanInLoop.message must be a function`);
1762
2017
  }
1763
2018
  }
1764
2019
  function mergeHumanInLoopFromGroup(groupHumanInLoop, childHumanInLoop) {
@@ -1834,12 +2089,12 @@ function assertValidBranches(branches, discriminator) {
1834
2089
  }
1835
2090
  }
1836
2091
  }
1837
- function OneOf(config) {
1838
- assertValidBranches(config.branches, config.discriminator);
2092
+ function OneOf(config2) {
2093
+ assertValidBranches(config2.branches, config2.discriminator);
1839
2094
  return {
1840
2095
  kind: "oneOf",
1841
- discriminator: config.discriminator,
1842
- branches: config.branches
2096
+ discriminator: config2.discriminator,
2097
+ branches: config2.branches
1843
2098
  };
1844
2099
  }
1845
2100
 
@@ -2089,22 +2344,22 @@ function cloneStringArray(values) {
2089
2344
  function cloneStringRecord(values) {
2090
2345
  return values === void 0 ? void 0 : { ...values };
2091
2346
  }
2092
- function cloneMcpServerConfig(config) {
2093
- if (config === void 0) {
2347
+ function cloneMcpServerConfig(config2) {
2348
+ if (config2 === void 0) {
2094
2349
  return void 0;
2095
2350
  }
2096
- if (config.transport === "stdio") {
2351
+ if (config2.transport === "stdio") {
2097
2352
  return {
2098
2353
  transport: "stdio",
2099
- command: config.command,
2100
- args: cloneStringArray(config.args),
2101
- env: cloneStringRecord(config.env)
2354
+ command: config2.command,
2355
+ args: cloneStringArray(config2.args),
2356
+ env: cloneStringRecord(config2.env)
2102
2357
  };
2103
2358
  }
2104
2359
  return {
2105
2360
  transport: "http",
2106
- url: config.url,
2107
- headers: cloneStringRecord(config.headers)
2361
+ url: config2.url,
2362
+ headers: cloneStringRecord(config2.headers)
2108
2363
  };
2109
2364
  }
2110
2365
  function cloneRenameMap(rename5) {
@@ -2345,57 +2600,57 @@ function resolveCommandScope(ownScope, inheritedScope) {
2345
2600
  function resolveGroupScope(ownScope, inheritedScope) {
2346
2601
  return cloneScope(ownScope ?? inheritedScope);
2347
2602
  }
2348
- function createBaseCommand(config) {
2603
+ function createBaseCommand(config2) {
2349
2604
  const command = {
2350
2605
  kind: "command",
2351
- name: config.name,
2352
- description: config.description,
2353
- aliases: [...config.aliases ?? []],
2354
- positional: [...config.positional ?? []],
2355
- params: config.params,
2356
- secrets: cloneSecrets(config.secrets),
2357
- scope: resolveCommandScope(config.scope, void 0),
2358
- confirm: config.confirm ?? false,
2359
- humanInLoop: config.humanInLoop,
2360
- requires: cloneRequires(config.requires),
2361
- handler: config.handler,
2362
- render: config.render
2606
+ name: config2.name,
2607
+ description: config2.description,
2608
+ aliases: [...config2.aliases ?? []],
2609
+ positional: [...config2.positional ?? []],
2610
+ params: config2.params,
2611
+ secrets: cloneSecrets(config2.secrets),
2612
+ scope: resolveCommandScope(config2.scope, void 0),
2613
+ confirm: config2.confirm ?? false,
2614
+ humanInLoop: config2.humanInLoop,
2615
+ requires: cloneRequires(config2.requires),
2616
+ handler: config2.handler,
2617
+ render: config2.render
2363
2618
  };
2364
2619
  Object.defineProperty(command, commandConfigSymbol, {
2365
2620
  value: {
2366
- scope: cloneScope(config.scope),
2367
- humanInLoop: config.humanInLoop,
2368
- secrets: cloneSecrets(config.secrets),
2369
- requires: cloneRequires(config.requires),
2621
+ scope: cloneScope(config2.scope),
2622
+ humanInLoop: config2.humanInLoop,
2623
+ secrets: cloneSecrets(config2.secrets),
2624
+ requires: cloneRequires(config2.requires),
2370
2625
  sourcePath: inferCommandSourcePath()
2371
2626
  }
2372
2627
  });
2373
2628
  return command;
2374
2629
  }
2375
- function createBaseGroup(config) {
2630
+ function createBaseGroup(config2) {
2376
2631
  const group = {
2377
2632
  kind: "group",
2378
- name: config.name,
2379
- description: config.description,
2380
- aliases: [...config.aliases ?? []],
2381
- scope: resolveGroupScope(config.scope, void 0),
2382
- humanInLoop: config.humanInLoop,
2383
- secrets: cloneSecrets(config.secrets),
2384
- requires: cloneRequires(config.requires),
2633
+ name: config2.name,
2634
+ description: config2.description,
2635
+ aliases: [...config2.aliases ?? []],
2636
+ scope: resolveGroupScope(config2.scope, void 0),
2637
+ humanInLoop: config2.humanInLoop,
2638
+ secrets: cloneSecrets(config2.secrets),
2639
+ requires: cloneRequires(config2.requires),
2385
2640
  children: [],
2386
2641
  default: void 0
2387
2642
  };
2388
2643
  Object.defineProperty(group, groupConfigSymbol, {
2389
2644
  value: {
2390
- mcp: cloneMcpServerConfig(config.mcp),
2391
- scope: cloneScope(config.scope),
2392
- humanInLoop: config.humanInLoop,
2393
- secrets: cloneSecrets(config.secrets),
2394
- tools: cloneStringArray(config.tools),
2395
- rename: cloneRenameMap(config.rename),
2396
- requires: cloneRequires(config.requires),
2397
- children: [...config.children],
2398
- default: config.default
2645
+ mcp: cloneMcpServerConfig(config2.mcp),
2646
+ scope: cloneScope(config2.scope),
2647
+ humanInLoop: config2.humanInLoop,
2648
+ secrets: cloneSecrets(config2.secrets),
2649
+ tools: cloneStringArray(config2.tools),
2650
+ rename: cloneRenameMap(config2.rename),
2651
+ requires: cloneRequires(config2.requires),
2652
+ children: [...config2.children],
2653
+ default: config2.default
2399
2654
  }
2400
2655
  });
2401
2656
  return group;
@@ -2498,10 +2753,10 @@ function materializeNode(node, inherited) {
2498
2753
  }
2499
2754
  return materializeGroup(node, inherited);
2500
2755
  }
2501
- function defineCommand(config) {
2502
- validateHumanInLoopOnDefine(config);
2756
+ function defineCommand(config2) {
2757
+ validateHumanInLoopOnDefine(config2);
2503
2758
  return materializeCommand(
2504
- createBaseCommand(config),
2759
+ createBaseCommand(config2),
2505
2760
  {
2506
2761
  scope: void 0,
2507
2762
  humanInLoop: void 0,
@@ -2510,10 +2765,10 @@ function defineCommand(config) {
2510
2765
  }
2511
2766
  );
2512
2767
  }
2513
- function defineGroup(config) {
2514
- validateRenameMap(config.rename);
2515
- validateHumanInLoopOnDefine(config);
2516
- return materializeGroup(createBaseGroup(config), {
2768
+ function defineGroup(config2) {
2769
+ validateRenameMap(config2.rename);
2770
+ validateHumanInLoopOnDefine(config2);
2771
+ return materializeGroup(createBaseGroup(config2), {
2517
2772
  scope: void 0,
2518
2773
  humanInLoop: void 0,
2519
2774
  secrets: {},
@@ -2674,17 +2929,22 @@ import { randomBytes } from "node:crypto";
2674
2929
  // ../process-runner/src/docker/args.ts
2675
2930
  import path2 from "node:path";
2676
2931
 
2932
+ // ../process-runner/src/docker/env-file.ts
2933
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2934
+ import { tmpdir } from "node:os";
2935
+ import path3 from "node:path";
2936
+
2677
2937
  // ../process-runner/src/docker/docker-execution-env.ts
2678
2938
  import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
2679
- import { mkdtempSync, rmSync } from "node:fs";
2680
- import { readdir, readFile, writeFile } from "node:fs/promises";
2681
- import { tmpdir } from "node:os";
2682
- import path4 from "node:path";
2939
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "node:fs";
2940
+ import { readdir, readFile, realpath, writeFile } from "node:fs/promises";
2941
+ import { tmpdir as tmpdir2 } from "node:os";
2942
+ import path5 from "node:path";
2683
2943
 
2684
2944
  // ../process-runner/src/host/host-runner.ts
2685
2945
  import { spawn as spawnChildProcess } from "node:child_process";
2686
2946
  function createHostRunner(options = {}) {
2687
- const detached = options.detached === true;
2947
+ const detachedByDefault = options.detached === true;
2688
2948
  return {
2689
2949
  name: "host",
2690
2950
  exec(spec) {
@@ -2702,18 +2962,19 @@ function createHostRunner(options = {}) {
2702
2962
  const stdinMode = spec.stdin ?? "ignore";
2703
2963
  const stdoutMode = spec.stdout ?? "pipe";
2704
2964
  const stderrMode = spec.stderr ?? "pipe";
2965
+ const killProcessGroup = detachedByDefault || spec.killProcessGroup === true;
2705
2966
  const stdio = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" ? "inherit" : [stdinMode, stdoutMode, stderrMode];
2706
2967
  const child = spawnChildProcess(spec.command, spec.args ?? [], {
2707
2968
  cwd: spec.cwd,
2708
2969
  env: spec.env,
2709
2970
  stdio,
2710
- ...detached ? { detached: true } : {}
2971
+ ...killProcessGroup ? { detached: true } : {}
2711
2972
  });
2712
- if (detached) {
2973
+ if (killProcessGroup) {
2713
2974
  child.unref();
2714
2975
  }
2715
2976
  const kill = (signal) => {
2716
- if (detached && process.platform !== "win32" && child.pid !== void 0) {
2977
+ if (killProcessGroup && process.platform !== "win32" && child.pid !== void 0) {
2717
2978
  process.kill(-child.pid, signal);
2718
2979
  return;
2719
2980
  }
@@ -2771,9 +3032,9 @@ function bindAbortSignal(signal, onAbort) {
2771
3032
  }
2772
3033
 
2773
3034
  // ../process-runner/src/workspace-transfer.ts
2774
- import { createHash } from "node:crypto";
3035
+ import { createHash, randomUUID } from "node:crypto";
2775
3036
  import { promises as nodeFs } from "node:fs";
2776
- import path3 from "node:path";
3037
+ import path4 from "node:path";
2777
3038
 
2778
3039
  // ../process-runner/src/testing/mock-runner.ts
2779
3040
  import { Readable, Writable } from "node:stream";
@@ -2844,7 +3105,7 @@ function resolveEndpoint(options = {}) {
2844
3105
  }
2845
3106
 
2846
3107
  // ../task-list/src/backends/utils.ts
2847
- import path5 from "node:path";
3108
+ import path6 from "node:path";
2848
3109
  function compareCreated(left, right) {
2849
3110
  const leftCreated = typeof left.raw.created === "string" ? left.raw.created : "";
2850
3111
  const rightCreated = typeof right.raw.created === "string" ? right.raw.created : "";
@@ -2894,12 +3155,12 @@ async function statIfExists(fs4, filePath) {
2894
3155
  }
2895
3156
  }
2896
3157
  async function rejectSymbolicLinkComponents(fs4, filePath) {
2897
- const resolvedPath = path5.resolve(filePath);
2898
- const rootPath = path5.parse(resolvedPath).root;
2899
- const components = resolvedPath.slice(rootPath.length).split(path5.sep).filter(Boolean);
3158
+ const resolvedPath = path6.resolve(filePath);
3159
+ const rootPath = path6.parse(resolvedPath).root;
3160
+ const components = resolvedPath.slice(rootPath.length).split(path6.sep).filter(Boolean);
2900
3161
  let currentPath = rootPath;
2901
3162
  for (const component of components) {
2902
- currentPath = path5.join(currentPath, component);
3163
+ currentPath = path6.join(currentPath, component);
2903
3164
  try {
2904
3165
  if ((await fs4.lstat(currentPath)).isSymbolicLink()) {
2905
3166
  throw new Error(`Path "${filePath}" contains a symbolic link.`);
@@ -2915,7 +3176,7 @@ async function rejectSymbolicLinkComponents(fs4, filePath) {
2915
3176
  async function writeAtomically(fs4, filePath, content) {
2916
3177
  const tempPath = `${filePath}.tmp-${process.pid}-${tmpFileCounter}`;
2917
3178
  tmpFileCounter += 1;
2918
- await fs4.mkdir(path5.dirname(filePath), { recursive: true });
3179
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
2919
3180
  try {
2920
3181
  await fs4.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
2921
3182
  await fs4.rename(tempPath, filePath);
@@ -2931,7 +3192,7 @@ async function writeAtomically(fs4, filePath, content) {
2931
3192
  }
2932
3193
  }
2933
3194
  async function withFileLock(fs4, lockPath, operation) {
2934
- await fs4.mkdir(path5.dirname(lockPath), { recursive: true });
3195
+ await fs4.mkdir(path6.dirname(lockPath), { recursive: true });
2935
3196
  for (; ; ) {
2936
3197
  try {
2937
3198
  await fs4.writeFile(lockPath, String(process.pid), { encoding: "utf8", flag: "wx" });
@@ -4018,7 +4279,7 @@ function parseQualifiedId(qualifiedId, listName) {
4018
4279
  }
4019
4280
 
4020
4281
  // ../task-list/src/backends/markdown-dir.ts
4021
- import path6 from "node:path";
4282
+ import path7 from "node:path";
4022
4283
  import { parseDocument, stringify } from "yaml";
4023
4284
 
4024
4285
  // ../task-list/src/schema/task.schema.json
@@ -4137,16 +4398,16 @@ function parseQualifiedId2(qualifiedId) {
4137
4398
  };
4138
4399
  }
4139
4400
  function listPath(rootPath, layout, list) {
4140
- return layout.kind === "single" ? rootPath : path6.join(rootPath, list);
4401
+ return layout.kind === "single" ? rootPath : path7.join(rootPath, list);
4141
4402
  }
4142
4403
  function archiveDirectoryPath(rootPath, layout, list) {
4143
- return layout.kind === "single" ? path6.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path6.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
4404
+ return layout.kind === "single" ? path7.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path7.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
4144
4405
  }
4145
4406
  function activeTaskFilename(id, order, width) {
4146
4407
  return `${String(order).padStart(width, "0")}-${id}${MARKDOWN_EXTENSION}`;
4147
4408
  }
4148
4409
  function archivedTaskPath(rootPath, layout, list, id) {
4149
- return path6.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
4410
+ return path7.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
4150
4411
  }
4151
4412
  function isMarkdownFile(entryName) {
4152
4413
  return entryName.endsWith(MARKDOWN_EXTENSION);
@@ -4272,7 +4533,7 @@ function createTask(list, id, frontmatter, body, mode, sourcePath) {
4272
4533
  state: frontmatter.state,
4273
4534
  description: body,
4274
4535
  metadata: metadataFromFrontmatter(frontmatter, mode),
4275
- ...sourcePath !== void 0 && { sourcePath: path6.resolve(sourcePath) }
4536
+ ...sourcePath !== void 0 && { sourcePath: path7.resolve(sourcePath) }
4276
4537
  };
4277
4538
  }
4278
4539
  function serializeTaskDocument(frontmatter, description) {
@@ -4312,7 +4573,7 @@ async function readTaskFile(fs4, list, id, filePath, validStates, initialState,
4312
4573
  task: createTask(list, id, frontmatter, document.body, mode, filePath)
4313
4574
  };
4314
4575
  }
4315
- const parsedFilename = parseActiveFilename(path6.basename(filePath));
4576
+ const parsedFilename = parseActiveFilename(path7.basename(filePath));
4316
4577
  const defaultName = parsedFilename?.id ?? id;
4317
4578
  const effectiveFrontmatter = {
4318
4579
  ...frontmatter,
@@ -4341,7 +4602,7 @@ async function findTaskLocation(fs4, rootPath, layout, list, id) {
4341
4602
  await rejectSymbolicLinkComponents(fs4, listDirectoryPath);
4342
4603
  const activeName = await findActiveTaskFilename(fs4, listDirectoryPath, id);
4343
4604
  if (activeName) {
4344
- const activePath = path6.join(listDirectoryPath, activeName);
4605
+ const activePath = path7.join(listDirectoryPath, activeName);
4345
4606
  await rejectSymbolicLinkComponents(fs4, activePath);
4346
4607
  const activeStat = await statIfExists(fs4, activePath);
4347
4608
  if (activeStat?.isFile()) {
@@ -4364,7 +4625,7 @@ async function readTaskAtLocation(fs4, rootPath, layout, list, id, validStates,
4364
4625
  }
4365
4626
  return readTaskFile(fs4, list, id, location.path, validStates, initialState, mode);
4366
4627
  }
4367
- function createdFrontmatter(defaults, input, initialState, mode) {
4628
+ function createdFrontmatter(defaults2, input, initialState, mode) {
4368
4629
  const frontmatter = mode !== "passthrough" ? {
4369
4630
  $schema: TASK_SCHEMA_ID,
4370
4631
  kind: TASK_KIND,
@@ -4376,7 +4637,7 @@ function createdFrontmatter(defaults, input, initialState, mode) {
4376
4637
  state: initialState
4377
4638
  };
4378
4639
  const reservedKeys = reservedFrontmatterKeys(mode);
4379
- for (const [key2, value] of Object.entries(defaults.metadata)) {
4640
+ for (const [key2, value] of Object.entries(defaults2.metadata)) {
4380
4641
  if (!reservedKeys.has(key2)) {
4381
4642
  setOwnValue(frontmatter, key2, value);
4382
4643
  }
@@ -4463,7 +4724,7 @@ function createTasksView2(deps, layout, list) {
4463
4724
  if (isHiddenEntry(entryName)) continue;
4464
4725
  const parsed = parseActiveFilename(entryName);
4465
4726
  if (!parsed) continue;
4466
- const entryPath = path6.join(listDirectoryPath, entryName);
4727
+ const entryPath = path7.join(listDirectoryPath, entryName);
4467
4728
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
4468
4729
  const entryStat = await statIfExists(deps.fs, entryPath);
4469
4730
  if (!entryStat?.isFile()) continue;
@@ -4481,7 +4742,7 @@ function createTasksView2(deps, layout, list) {
4481
4742
  const entries = await readActiveEntries();
4482
4743
  const tasks = /* @__PURE__ */ new Map();
4483
4744
  for (const entry of entries) {
4484
- const filePath = path6.join(listDirectoryPath, entry.filename);
4745
+ const filePath = path7.join(listDirectoryPath, entry.filename);
4485
4746
  const file = await readTaskFile(
4486
4747
  deps.fs,
4487
4748
  list,
@@ -4502,7 +4763,7 @@ function createTasksView2(deps, layout, list) {
4502
4763
  const result = [];
4503
4764
  for (const entryName of entries) {
4504
4765
  if (isHiddenEntry(entryName) || !isMarkdownFile(entryName)) continue;
4505
- const entryPath = path6.join(archivePath, entryName);
4766
+ const entryPath = path7.join(archivePath, entryName);
4506
4767
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
4507
4768
  const entryStat = await statIfExists(deps.fs, entryPath);
4508
4769
  if (!entryStat?.isFile()) continue;
@@ -4532,12 +4793,12 @@ function createTasksView2(deps, layout, list) {
4532
4793
  if (desiredOrder === void 0) continue;
4533
4794
  const desiredFilename = activeTaskFilename(entry.id, desiredOrder, width);
4534
4795
  if (entry.filename !== desiredFilename) {
4535
- const fromPath = path6.join(listDirectoryPath, entry.filename);
4536
- const stagingPath = path6.join(
4796
+ const fromPath = path7.join(listDirectoryPath, entry.filename);
4797
+ const stagingPath = path7.join(
4537
4798
  listDirectoryPath,
4538
4799
  `${desiredFilename}.staging-${process.pid}-${index}`
4539
4800
  );
4540
- const targetPath = path6.join(listDirectoryPath, desiredFilename);
4801
+ const targetPath = path7.join(listDirectoryPath, desiredFilename);
4541
4802
  try {
4542
4803
  await deps.fs.rename(fromPath, stagingPath);
4543
4804
  staged.push({ original: fromPath, staging: stagingPath, target: targetPath, finalized: false });
@@ -4686,7 +4947,7 @@ function createTasksView2(deps, layout, list) {
4686
4947
  assertCreateHasId(input);
4687
4948
  validateTaskId(input.id);
4688
4949
  await rejectSymbolicLinkComponents(deps.fs, listDirectoryPath);
4689
- return withFileLock(deps.fs, path6.join(listDirectoryPath, ".transition.lock"), async () => {
4950
+ return withFileLock(deps.fs, path7.join(listDirectoryPath, ".transition.lock"), async () => {
4690
4951
  const existing = await findTaskLocation(deps.fs, deps.path, layout, list, input.id);
4691
4952
  if (existing) {
4692
4953
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
@@ -4699,7 +4960,7 @@ function createTasksView2(deps, layout, list) {
4699
4960
  const nextOrder = maxOrder + 1;
4700
4961
  const width = padWidthForCount(activeEntries.length + 1);
4701
4962
  const filename = activeTaskFilename(input.id, nextOrder, width);
4702
- const targetPath = path6.join(listDirectoryPath, filename);
4963
+ const targetPath = path7.join(listDirectoryPath, filename);
4703
4964
  const frontmatter = createdFrontmatter(
4704
4965
  deps.defaults,
4705
4966
  input,
@@ -4807,7 +5068,7 @@ function createTasksView2(deps, layout, list) {
4807
5068
  validateTaskId(id);
4808
5069
  const { event, nextTask } = await withFileLock(
4809
5070
  deps.fs,
4810
- path6.join(listDirectoryPath, ".transition.lock"),
5071
+ path7.join(listDirectoryPath, ".transition.lock"),
4811
5072
  fireTask
4812
5073
  );
4813
5074
  await event.onEnter?.(nextTask);
@@ -4900,7 +5161,7 @@ async function markdownDirBackend(deps) {
4900
5161
  if (entryName === ARCHIVE_DIRECTORY_NAME || isHiddenEntry(entryName)) {
4901
5162
  continue;
4902
5163
  }
4903
- const entryPath = path6.join(deps.path, entryName);
5164
+ const entryPath = path7.join(deps.path, entryName);
4904
5165
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
4905
5166
  const entryStat = await statIfExists(deps.fs, entryPath);
4906
5167
  if (entryStat?.isDirectory()) {
@@ -4942,7 +5203,7 @@ async function markdownDirBackend(deps) {
4942
5203
  }
4943
5204
  const targetListDir = listPath(deps.path, layout, targetListName);
4944
5205
  await rejectSymbolicLinkComponents(deps.fs, targetListDir);
4945
- return withFileLock(deps.fs, path6.join(targetListDir, ".transition.lock"), async () => {
5206
+ return withFileLock(deps.fs, path7.join(targetListDir, ".transition.lock"), async () => {
4946
5207
  const targetExisting = await findTaskLocation(deps.fs, deps.path, layout, targetListName, id);
4947
5208
  if (targetExisting) {
4948
5209
  throw new TaskAlreadyExistsError(`Task "${targetListName}/${id}" already exists.`);
@@ -4992,7 +5253,7 @@ async function markdownDirBackend(deps) {
4992
5253
  );
4993
5254
  const width = padWidthForCount(targetEntries.length + 1);
4994
5255
  const targetFilename = activeTaskFilename(id, maxOrder + 1, width);
4995
- const targetPath = path6.join(targetListDir, targetFilename);
5256
+ const targetPath = path7.join(targetListDir, targetFilename);
4996
5257
  await deps.fs.rename(sourceLocation.path, targetPath);
4997
5258
  return createTask(
4998
5259
  targetListName,
@@ -5014,7 +5275,7 @@ async function markdownDirBackend(deps) {
5014
5275
  }
5015
5276
 
5016
5277
  // ../task-list/src/backends/yaml-file.ts
5017
- import path7 from "node:path";
5278
+ import path8 from "node:path";
5018
5279
  import { isMap, parseDocument as parseDocument2 } from "yaml";
5019
5280
 
5020
5281
  // ../task-list/src/schema/store.schema.json
@@ -5110,7 +5371,7 @@ function createTask2(list, id, taskRecord, sourcePath) {
5110
5371
  state: taskRecord.state,
5111
5372
  description: descriptionFromTaskRecord(taskRecord),
5112
5373
  metadata: metadataFromTaskRecord(taskRecord),
5113
- ...sourcePath !== void 0 && { sourcePath: path7.resolve(sourcePath) }
5374
+ ...sourcePath !== void 0 && { sourcePath: path8.resolve(sourcePath) }
5114
5375
  };
5115
5376
  }
5116
5377
  function matchesFilter(task, filter) {
@@ -5122,13 +5383,13 @@ function matchesFilter(task, filter) {
5122
5383
  }
5123
5384
  return true;
5124
5385
  }
5125
- function createTaskRecord(defaults, input, initialState) {
5386
+ function createTaskRecord(defaults2, input, initialState) {
5126
5387
  const taskRecord = Object.assign(/* @__PURE__ */ Object.create(null), {
5127
5388
  name: input.name,
5128
5389
  state: initialState,
5129
5390
  description: input.description ?? ""
5130
5391
  });
5131
- for (const [key2, value] of Object.entries(defaults.metadata)) {
5392
+ for (const [key2, value] of Object.entries(defaults2.metadata)) {
5132
5393
  if (!RESERVED_TASK_KEYS.has(key2)) {
5133
5394
  taskRecord[key2] = value;
5134
5395
  }
@@ -5675,7 +5936,7 @@ async function openGhIssuesBackend(options) {
5675
5936
 
5676
5937
  // ../task-list/src/move.ts
5677
5938
  import * as fsPromises2 from "node:fs/promises";
5678
- import path8 from "node:path";
5939
+ import path9 from "node:path";
5679
5940
 
5680
5941
  // ../toolcraft/src/human-in-loop/approval-tasks.ts
5681
5942
  import { randomBytes as randomBytes3 } from "node:crypto";
@@ -6171,13 +6432,13 @@ function formatAvailableApprovalCommandPaths(root) {
6171
6432
  }
6172
6433
  function enumerateApprovalCommandPaths(root) {
6173
6434
  const paths = [];
6174
- const visit = (node, path23) => {
6435
+ const visit = (node, path24) => {
6175
6436
  if (node.kind === "command") {
6176
- paths.push(path23.join("."));
6437
+ paths.push(path24.join("."));
6177
6438
  return;
6178
6439
  }
6179
6440
  for (const child of getVisibleCliChildren(node)) {
6180
- visit(child, [...path23, child.name]);
6441
+ visit(child, [...path24, child.name]);
6181
6442
  }
6182
6443
  };
6183
6444
  if (root.kind === "command") {
@@ -6212,21 +6473,21 @@ function createHandlerContext(command, params17) {
6212
6473
  }
6213
6474
  function createFs() {
6214
6475
  return {
6215
- readFile: async (path23, encoding = "utf8") => readFile2(path23, { encoding }),
6216
- writeFile: async (path23, contents) => {
6217
- await writeFile2(path23, contents);
6476
+ readFile: async (path24, encoding = "utf8") => readFile2(path24, { encoding }),
6477
+ writeFile: async (path24, contents) => {
6478
+ await writeFile2(path24, contents);
6218
6479
  },
6219
- exists: async (path23) => {
6480
+ exists: async (path24) => {
6220
6481
  try {
6221
- await access(path23);
6482
+ await access(path24);
6222
6483
  return true;
6223
6484
  } catch {
6224
6485
  return false;
6225
6486
  }
6226
6487
  },
6227
- lstat: async (path23) => lstat(path23),
6488
+ lstat: async (path24) => lstat(path24),
6228
6489
  rename: async (fromPath, toPath) => rename(fromPath, toPath),
6229
- unlink: async (path23) => unlink(path23)
6490
+ unlink: async (path24) => unlink(path24)
6230
6491
  };
6231
6492
  }
6232
6493
  function createEnv(values = process.env) {
@@ -6502,17 +6763,17 @@ function isMissingStateError(error3) {
6502
6763
  }
6503
6764
 
6504
6765
  // ../toolcraft/src/error-report.ts
6505
- import { mkdir as mkdir2, realpath, writeFile as writeFile4 } from "node:fs/promises";
6506
- import { randomUUID as randomUUID2 } from "node:crypto";
6766
+ import { mkdir as mkdir2, realpath as realpath2, writeFile as writeFile4 } from "node:fs/promises";
6767
+ import { randomUUID as randomUUID3 } from "node:crypto";
6507
6768
  import os from "node:os";
6508
- import path12 from "node:path";
6769
+ import path13 from "node:path";
6509
6770
  import { CommanderError } from "commander";
6510
6771
 
6511
6772
  // ../toolcraft/src/mcp-proxy.ts
6512
6773
  import { existsSync as existsSync2 } from "node:fs";
6513
6774
  import { lstat as lstat2, mkdir, readFile as readFile3, rename as rename2, writeFile as writeFile3 } from "node:fs/promises";
6514
- import path11 from "node:path";
6515
- import { createHash as createHash3, randomUUID } from "node:crypto";
6775
+ import path12 from "node:path";
6776
+ import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
6516
6777
 
6517
6778
  // ../tiny-mcp-client/src/internal.ts
6518
6779
  import { spawn as spawn5 } from "node:child_process";
@@ -6520,13 +6781,13 @@ import { PassThrough as PassThrough2 } from "node:stream";
6520
6781
 
6521
6782
  // ../mcp-oauth/src/client/auth-store-session-store.ts
6522
6783
  import crypto from "node:crypto";
6523
- import path10 from "node:path";
6784
+ import path11 from "node:path";
6524
6785
 
6525
6786
  // ../auth-store/src/encrypted-file-store.ts
6526
6787
  import { createCipheriv, createDecipheriv, randomBytes as randomBytes4, scrypt } from "node:crypto";
6527
6788
  import { promises as fs } from "node:fs";
6528
6789
  import { homedir, hostname, userInfo } from "node:os";
6529
- import path9 from "node:path";
6790
+ import path10 from "node:path";
6530
6791
  var derivedKeyCache = /* @__PURE__ */ new Map();
6531
6792
  var ENCRYPTION_ALGORITHM = "aes-256-gcm";
6532
6793
  var ENCRYPTION_VERSION = 1;
@@ -6538,6 +6799,7 @@ var temporaryFileSequence = 0;
6538
6799
  var EncryptedFileStore = class {
6539
6800
  fs;
6540
6801
  filePath;
6802
+ symbolicLinkCheckStartPath;
6541
6803
  salt;
6542
6804
  getMachineIdentity;
6543
6805
  getRandomBytes;
@@ -6545,11 +6807,22 @@ var EncryptedFileStore = class {
6545
6807
  constructor(input) {
6546
6808
  this.fs = input.fs ?? fs;
6547
6809
  this.salt = input.salt;
6548
- this.filePath = input.filePath ?? path9.join(
6549
- (input.getHomeDirectory ?? homedir)(),
6550
- input.defaultDirectory ?? ".auth-store",
6551
- input.defaultFileName ?? "credentials.enc"
6552
- );
6810
+ if (input.filePath === void 0) {
6811
+ const homeDirectory = (input.getHomeDirectory ?? homedir)();
6812
+ const defaultDirectory = input.defaultDirectory ?? ".auth-store";
6813
+ this.filePath = path10.join(
6814
+ homeDirectory,
6815
+ defaultDirectory,
6816
+ input.defaultFileName ?? "credentials.enc"
6817
+ );
6818
+ this.symbolicLinkCheckStartPath = resolveDefaultDirectoryCheckStart(
6819
+ homeDirectory,
6820
+ defaultDirectory
6821
+ );
6822
+ } else {
6823
+ this.filePath = input.filePath;
6824
+ this.symbolicLinkCheckStartPath = null;
6825
+ }
6553
6826
  this.getMachineIdentity = input.getMachineIdentity ?? defaultMachineIdentity;
6554
6827
  this.getRandomBytes = input.getRandomBytes ?? randomBytes4;
6555
6828
  }
@@ -6600,7 +6873,7 @@ var EncryptedFileStore = class {
6600
6873
  authTag: authTag.toString("base64"),
6601
6874
  ciphertext: ciphertext.toString("base64")
6602
6875
  };
6603
- await this.fs.mkdir(path9.dirname(this.filePath), { recursive: true });
6876
+ await this.fs.mkdir(path10.dirname(this.filePath), { recursive: true });
6604
6877
  await this.assertRegularCredentialPath();
6605
6878
  const temporaryPath = `${this.filePath}.${process.pid}.${temporaryFileSequence++}.tmp`;
6606
6879
  try {
@@ -6629,8 +6902,11 @@ var EncryptedFileStore = class {
6629
6902
  }
6630
6903
  }
6631
6904
  async assertRegularCredentialPath() {
6632
- const resolvedPath = path9.resolve(this.filePath);
6633
- const protectedPaths = [path9.dirname(resolvedPath), resolvedPath];
6905
+ const resolvedPath = path10.resolve(this.filePath);
6906
+ const protectedPaths = getProtectedCredentialPaths(
6907
+ resolvedPath,
6908
+ this.symbolicLinkCheckStartPath
6909
+ );
6634
6910
  for (const currentPath of protectedPaths) {
6635
6911
  try {
6636
6912
  const stats = await this.fs.lstat(currentPath);
@@ -6658,6 +6934,30 @@ var EncryptedFileStore = class {
6658
6934
  return this.keyPromise;
6659
6935
  }
6660
6936
  };
6937
+ function resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory) {
6938
+ const [firstSegment] = defaultDirectory.split(/[\\/]+/).filter(Boolean);
6939
+ return path10.resolve(homeDirectory, firstSegment ?? ".");
6940
+ }
6941
+ function getProtectedCredentialPaths(resolvedPath, symbolicLinkCheckStartPath) {
6942
+ if (symbolicLinkCheckStartPath === null) {
6943
+ return [path10.dirname(resolvedPath), resolvedPath];
6944
+ }
6945
+ const resolvedStartPath = path10.resolve(symbolicLinkCheckStartPath);
6946
+ if (!isPathInsideOrEqual(resolvedPath, resolvedStartPath)) {
6947
+ return [path10.dirname(resolvedPath), resolvedPath];
6948
+ }
6949
+ const protectedPaths = [resolvedStartPath];
6950
+ let currentPath = resolvedStartPath;
6951
+ for (const segment of path10.relative(resolvedStartPath, resolvedPath).split(path10.sep).filter(Boolean)) {
6952
+ currentPath = path10.join(currentPath, segment);
6953
+ protectedPaths.push(currentPath);
6954
+ }
6955
+ return protectedPaths;
6956
+ }
6957
+ function isPathInsideOrEqual(childPath, parentPath) {
6958
+ const relativePath = path10.relative(parentPath, childPath);
6959
+ return relativePath === "" || !relativePath.startsWith("..") && !path10.isAbsolute(relativePath);
6960
+ }
6661
6961
  async function removeIfPresent(fileSystem, filePath) {
6662
6962
  try {
6663
6963
  await fileSystem.unlink(filePath);
@@ -6808,6 +7108,17 @@ function runSecurityCommand(command, args, options) {
6808
7108
  });
6809
7109
  let stdout = "";
6810
7110
  let stderr = "";
7111
+ let stdinErrorMessage;
7112
+ const appendStderr = (message2) => {
7113
+ stderr = stderr.length === 0 ? message2 : `${stderr}${stderr.endsWith("\n") ? "" : "\n"}${message2}`;
7114
+ };
7115
+ const appendStdinError = () => {
7116
+ if (stdinErrorMessage === void 0) {
7117
+ return;
7118
+ }
7119
+ appendStderr(stdinErrorMessage);
7120
+ stdinErrorMessage = void 0;
7121
+ };
6811
7122
  child.stdout?.setEncoding("utf8");
6812
7123
  child.stdout?.on("data", (chunk) => {
6813
7124
  stdout += chunk.toString();
@@ -6817,17 +7128,23 @@ function runSecurityCommand(command, args, options) {
6817
7128
  stderr += chunk.toString();
6818
7129
  });
6819
7130
  if (options?.stdin !== void 0) {
7131
+ child.stdin?.once("error", (error3) => {
7132
+ stdinErrorMessage = error3 instanceof Error ? error3.message : String(error3);
7133
+ });
6820
7134
  child.stdin?.end(options.stdin);
6821
7135
  }
6822
7136
  child.on("error", (error3) => {
6823
7137
  const message2 = error3 instanceof Error ? error3.message : String(error3 ?? "Unknown error");
7138
+ appendStdinError();
7139
+ appendStderr(message2);
6824
7140
  resolve({
6825
7141
  stdout,
6826
- stderr: stderr ? `${stderr}${message2}` : message2,
7142
+ stderr,
6827
7143
  exitCode: 127
6828
7144
  });
6829
7145
  });
6830
7146
  child.on("close", (code) => {
7147
+ appendStdinError();
6831
7148
  resolve({
6832
7149
  stdout,
6833
7150
  stderr,
@@ -6965,19 +7282,24 @@ function createAuthStoreClientStore(options) {
6965
7282
  }
6966
7283
  };
6967
7284
  }
6968
- function createNamedSecretStore(key2, options, defaults) {
7285
+ function createNamedSecretStore(key2, options, defaults2) {
6969
7286
  const hash = crypto.createHash("sha256").update(key2).digest("hex");
6970
- const parsedFilePath = options.fileStore?.filePath === void 0 ? null : path10.parse(options.fileStore.filePath);
7287
+ const configuredFilePath = options.fileStore?.filePath;
7288
+ const parsedFilePath = configuredFilePath === void 0 ? null : path11.parse(configuredFilePath);
6971
7289
  const fileStore = {
6972
7290
  ...options.fileStore,
6973
- salt: options.fileStore?.salt ?? defaults.salt,
6974
- defaultDirectory: parsedFilePath?.dir || options.fileStore?.defaultDirectory || defaults.directory,
7291
+ filePath: parsedFilePath === null ? void 0 : path11.join(
7292
+ parsedFilePath.dir,
7293
+ `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
7294
+ ),
7295
+ salt: options.fileStore?.salt ?? defaults2.salt,
7296
+ defaultDirectory: options.fileStore?.defaultDirectory || defaults2.directory,
6975
7297
  defaultFileName: parsedFilePath === null ? `${hash}.enc` : `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
6976
7298
  };
6977
7299
  const keychainStore = {
6978
7300
  ...options.keychainStore,
6979
- service: options.keychainStore?.service ?? defaults.service,
6980
- account: `${options.keychainStore?.account ?? defaults.accountPrefix}:${hash}`
7301
+ service: options.keychainStore?.service ?? defaults2.service,
7302
+ account: `${options.keychainStore?.account ?? defaults2.accountPrefix}:${hash}`
6981
7303
  };
6982
7304
  return createSecretStore({ ...options, fileStore, keychainStore }).store;
6983
7305
  }
@@ -8550,10 +8872,19 @@ var McpClient = class {
8550
8872
  }
8551
8873
  try {
8552
8874
  let requestId;
8875
+ let cancellationSent = false;
8876
+ const sendCancellationNotification = () => {
8877
+ if (requestId === void 0 || cancellationSent) {
8878
+ return;
8879
+ }
8880
+ cancellationSent = true;
8881
+ messageLayer.sendNotification("notifications/cancelled", { requestId });
8882
+ };
8553
8883
  const requestPromise = messageLayer.sendRequest("tools/call", requestParams, {
8554
8884
  onRequestId: (nextRequestId) => {
8555
8885
  requestId = nextRequestId;
8556
- }
8886
+ },
8887
+ onTimeout: sendCancellationNotification
8557
8888
  }).then((result) => {
8558
8889
  if (!isCallToolResult(result)) {
8559
8890
  throw new McpError(ERROR_INVALID_REQUEST, "Invalid tool result");
@@ -8567,8 +8898,9 @@ var McpClient = class {
8567
8898
  let abortListener;
8568
8899
  const abortPromise = new Promise((_, reject) => {
8569
8900
  const rejectWithAbortReason = () => {
8901
+ sendCancellationNotification();
8570
8902
  if (requestId !== void 0) {
8571
- messageLayer.sendNotification("notifications/cancelled", { requestId });
8903
+ messageLayer.cancelRequest(requestId, signal.reason);
8572
8904
  }
8573
8905
  reject(signal.reason);
8574
8906
  };
@@ -8744,11 +9076,13 @@ var StdioTransport = class _StdioTransport {
8744
9076
  const child = this.child;
8745
9077
  this.readable = child.stdout;
8746
9078
  this.writable = child.stdin;
9079
+ const stderrDecoder = new TextDecoder();
8747
9080
  child.stderr.on("data", (chunk) => {
8748
- this.stderrOutput += chunkToString(chunk);
8749
- if (this.stderrOutput.length > _StdioTransport.STDERR_MAX_LENGTH) {
8750
- this.stderrOutput = this.stderrOutput.slice(-_StdioTransport.STDERR_MAX_LENGTH);
8751
- }
9081
+ const decoded = chunk instanceof Uint8Array ? stderrDecoder.decode(chunk, { stream: true }) : `${stderrDecoder.decode()}${String(chunk)}`;
9082
+ this.appendStderrOutput(decoded);
9083
+ });
9084
+ child.stderr.once("end", () => {
9085
+ this.appendStderrOutput(stderrDecoder.decode());
8752
9086
  });
8753
9087
  this.closed = new Promise((resolve) => {
8754
9088
  let settled = false;
@@ -8788,6 +9122,15 @@ var StdioTransport = class _StdioTransport {
8788
9122
  getStderrOutput() {
8789
9123
  return this.stderrOutput;
8790
9124
  }
9125
+ appendStderrOutput(chunk) {
9126
+ if (chunk.length === 0) {
9127
+ return;
9128
+ }
9129
+ this.stderrOutput += chunk;
9130
+ if (this.stderrOutput.length > _StdioTransport.STDERR_MAX_LENGTH) {
9131
+ this.stderrOutput = this.stderrOutput.slice(-_StdioTransport.STDERR_MAX_LENGTH);
9132
+ }
9133
+ }
8791
9134
  dispose(reason = new Error("Stdio transport disposed")) {
8792
9135
  void reason;
8793
9136
  if (this.disposed) {
@@ -9195,15 +9538,6 @@ function serializeJsonRpcMessage(message2) {
9195
9538
  return `${JSON.stringify(message2)}
9196
9539
  `;
9197
9540
  }
9198
- function chunkToString(chunk) {
9199
- if (typeof chunk === "string") {
9200
- return chunk;
9201
- }
9202
- if (chunk instanceof Uint8Array) {
9203
- return Buffer.from(chunk).toString("utf8");
9204
- }
9205
- return String(chunk);
9206
- }
9207
9541
  function normalizeLine(line) {
9208
9542
  return line.endsWith("\r") ? line.slice(0, -1) : line;
9209
9543
  }
@@ -9380,6 +9714,7 @@ var JsonRpcMessageLayer = class {
9380
9714
  return new Promise((resolve, reject) => {
9381
9715
  const timeout = setTimeout(() => {
9382
9716
  this.pendingRequests.delete(id);
9717
+ options.onTimeout?.(id);
9383
9718
  reject(new Error(`JSON-RPC request "${method}" timed out after ${timeoutMs}ms`));
9384
9719
  }, timeoutMs);
9385
9720
  this.pendingRequests.set(id, { resolve, reject, timeout });
@@ -9392,6 +9727,16 @@ var JsonRpcMessageLayer = class {
9392
9727
  }
9393
9728
  });
9394
9729
  }
9730
+ cancelRequest(requestId, reason) {
9731
+ const pending = this.pendingRequests.get(requestId);
9732
+ if (pending === void 0) {
9733
+ return false;
9734
+ }
9735
+ this.pendingRequests.delete(requestId);
9736
+ clearTimeout(pending.timeout);
9737
+ pending.reject(reason);
9738
+ return true;
9739
+ }
9395
9740
  dispose(reason = new Error("JSON-RPC message layer disposed")) {
9396
9741
  if (this.disposedError !== void 0) {
9397
9742
  return;
@@ -9792,13 +10137,13 @@ function convertJsonSchema(schema) {
9792
10137
  }
9793
10138
  return convertSchema(schema, schema, []);
9794
10139
  }
9795
- function convertSchema(schema, root, path23) {
9796
- const resolvedSchema = resolveReferencedSchema(schema, root, path23);
10140
+ function convertSchema(schema, root, path24) {
10141
+ const resolvedSchema = resolveReferencedSchema(schema, root, path24);
9797
10142
  const normalizedSchema = normalizeNullability(resolvedSchema);
9798
10143
  const composition = getComposition(normalizedSchema.schema);
9799
10144
  if (Array.isArray(normalizedSchema.schema.type)) {
9800
10145
  throw new Error(
9801
- `JSON Schema "${formatJsonSchemaPath(path23)}" has an unsupported type "${formatJsonSchemaType(
10146
+ `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
9802
10147
  normalizedSchema.schema.type
9803
10148
  )}". Supported: string, number, integer, boolean, array, object.`
9804
10149
  );
@@ -9810,13 +10155,13 @@ function convertSchema(schema, root, path23) {
9810
10155
  return convertEnumSchema(resolvedSchema, normalizedSchema.nullable);
9811
10156
  }
9812
10157
  if (composition !== void 0) {
9813
- return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path23);
10158
+ return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path24);
9814
10159
  }
9815
10160
  if (isRecordSchema(normalizedSchema.schema)) {
9816
10161
  return applyMetadata(
9817
10162
  S.Record(
9818
10163
  convertSchema(normalizedSchema.schema.additionalProperties, root, [
9819
- ...path23,
10164
+ ...path24,
9820
10165
  "additionalProperties"
9821
10166
  ])
9822
10167
  ),
@@ -9865,12 +10210,12 @@ function convertSchema(schema, root, path23) {
9865
10210
  if (normalizedSchema.schema.items === void 0) {
9866
10211
  throw new Error(
9867
10212
  `JSON Schema "${formatJsonSchemaPath(
9868
- path23
10213
+ path24
9869
10214
  )}" is an array but is missing the "items" field. Add "items": { ... } to declare the element type.`
9870
10215
  );
9871
10216
  }
9872
10217
  return S.Array(
9873
- convertSchema(normalizedSchema.schema.items, root, [...path23, "items"]),
10218
+ convertSchema(normalizedSchema.schema.items, root, [...path24, "items"]),
9874
10219
  createCommonOptions(
9875
10220
  normalizedSchema.schema,
9876
10221
  normalizedSchema.nullable,
@@ -9880,7 +10225,7 @@ function convertSchema(schema, root, path23) {
9880
10225
  case "object":
9881
10226
  return convertObjectSchema(normalizedSchema.schema, root, {
9882
10227
  nullable: normalizedSchema.nullable,
9883
- path: path23
10228
+ path: path24
9884
10229
  });
9885
10230
  case "null":
9886
10231
  return applyMetadata(S.Json(), normalizedSchema.schema, {
@@ -9895,12 +10240,12 @@ function convertSchema(schema, root, path23) {
9895
10240
  }
9896
10241
  throw new Error(
9897
10242
  `JSON Schema "${formatJsonSchemaPath(
9898
- path23
10243
+ path24
9899
10244
  )}" must declare one of: "type", "enum", "const", "oneOf", "anyOf", or "allOf".`
9900
10245
  );
9901
10246
  }
9902
10247
  throw new Error(
9903
- `JSON Schema "${formatJsonSchemaPath(path23)}" has an unsupported type "${formatJsonSchemaType(
10248
+ `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
9904
10249
  normalizedSchema.schema.type
9905
10250
  )}". Supported: string, number, integer, boolean, array, object.`
9906
10251
  );
@@ -9944,21 +10289,21 @@ function convertEnumSchema(schema, nullable) {
9944
10289
  )
9945
10290
  });
9946
10291
  }
9947
- function convertCompositionSchema(schema, root, nullable, path23) {
10292
+ function convertCompositionSchema(schema, root, nullable, path24) {
9948
10293
  const composition = getComposition(schema);
9949
10294
  const branchSchemas = composition?.branches ?? [];
9950
10295
  const keyword = composition?.keyword ?? "oneOf";
9951
10296
  const branches = branchSchemas.map(
9952
- (branch, index) => resolveReferencedSchema(branch, root, [...path23, keyword, String(index)])
10297
+ (branch, index) => resolveReferencedSchema(branch, root, [...path24, keyword, String(index)])
9953
10298
  );
9954
- const discriminator = findDiscriminator(branches, root, path23);
10299
+ const discriminator = findDiscriminator(branches, root, path24);
9955
10300
  if (discriminator !== void 0) {
9956
10301
  const convertedBranches = Object.fromEntries(
9957
10302
  branches.map((branch, index) => [
9958
10303
  getDiscriminatorLiteral(branch, discriminator, root),
9959
10304
  convertObjectSchema(branch, root, {
9960
10305
  omitProperty: discriminator,
9961
- path: [...path23, keyword, String(index)]
10306
+ path: [...path24, keyword, String(index)]
9962
10307
  })
9963
10308
  ])
9964
10309
  );
@@ -9977,7 +10322,7 @@ function convertCompositionSchema(schema, root, nullable, path23) {
9977
10322
  S.Union(
9978
10323
  branches.map(
9979
10324
  (branch, index) => convertObjectSchema(branch, root, {
9980
- path: [...path23, keyword, String(index)]
10325
+ path: [...path24, keyword, String(index)]
9981
10326
  })
9982
10327
  )
9983
10328
  ),
@@ -10079,11 +10424,11 @@ function getComposition(schema) {
10079
10424
  }
10080
10425
  return void 0;
10081
10426
  }
10082
- function formatJsonSchemaPath(path23) {
10083
- if (path23.length === 0) {
10427
+ function formatJsonSchemaPath(path24) {
10428
+ if (path24.length === 0) {
10084
10429
  return "#";
10085
10430
  }
10086
- return `#/${path23.map(escapeJsonPointerSegment).join("/")}`;
10431
+ return `#/${path24.map(escapeJsonPointerSegment).join("/")}`;
10087
10432
  }
10088
10433
  function formatJsonSchemaType(type2) {
10089
10434
  return Array.isArray(type2) ? JSON.stringify(type2) : String(type2);
@@ -10099,11 +10444,11 @@ function isRecordSchema(schema) {
10099
10444
  const propertyKeys = Object.keys(schema.properties ?? {});
10100
10445
  return schema.type === "object" && propertyKeys.length === 0 && typeof schema.additionalProperties === "object" && schema.additionalProperties !== null;
10101
10446
  }
10102
- function findDiscriminator(branches, root, path23) {
10447
+ function findDiscriminator(branches, root, path24) {
10103
10448
  const [firstBranch] = branches;
10104
10449
  if (firstBranch === void 0) {
10105
10450
  throw new Error(
10106
- `JSON Schema "${formatJsonSchemaPath(path23)}" uses oneOf/anyOf/allOf but has no branches.`
10451
+ `JSON Schema "${formatJsonSchemaPath(path24)}" uses oneOf/anyOf/allOf but has no branches.`
10107
10452
  );
10108
10453
  }
10109
10454
  const candidateKeys = Object.keys(firstBranch.properties ?? {});
@@ -10143,19 +10488,19 @@ function getDiscriminatorLiteral(branch, key2, root) {
10143
10488
  }
10144
10489
  return void 0;
10145
10490
  }
10146
- function resolveReferencedSchema(schema, root, path23) {
10491
+ function resolveReferencedSchema(schema, root, path24) {
10147
10492
  if (schema.$ref === void 0) {
10148
10493
  return schema;
10149
10494
  }
10150
10495
  const resolvedTarget = resolveLocalRef(root, schema.$ref);
10151
10496
  if (resolvedTarget === void 0) {
10152
10497
  throw new Error(
10153
- `JSON Schema "${formatJsonSchemaPath(path23)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
10498
+ `JSON Schema "${formatJsonSchemaPath(path24)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
10154
10499
  );
10155
10500
  }
10156
10501
  const { $ref: ignoredRef, ...siblingKeywords } = schema;
10157
10502
  void ignoredRef;
10158
- const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path23);
10503
+ const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path24);
10159
10504
  if (Object.keys(siblingKeywords).length === 0) {
10160
10505
  return resolvedSchema;
10161
10506
  }
@@ -10179,9 +10524,9 @@ function mergeJsonSchemas(base, overlay) {
10179
10524
  ...mergedRequired === void 0 ? {} : { required: mergedRequired }
10180
10525
  };
10181
10526
  }
10182
- function hasSelfReferencingRef(schema, root, path23 = "#", activePaths = /* @__PURE__ */ new Set()) {
10527
+ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__PURE__ */ new Set()) {
10183
10528
  const nextActivePaths = new Set(activePaths);
10184
- nextActivePaths.add(path23);
10529
+ nextActivePaths.add(path24);
10185
10530
  const localRefPath = getLocalRefPath(schema.$ref);
10186
10531
  if (localRefPath !== void 0) {
10187
10532
  if (nextActivePaths.has(localRefPath)) {
@@ -10192,13 +10537,13 @@ function hasSelfReferencingRef(schema, root, path23 = "#", activePaths = /* @__P
10192
10537
  return true;
10193
10538
  }
10194
10539
  }
10195
- if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path23}/items`, nextActivePaths)) {
10540
+ if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path24}/items`, nextActivePaths)) {
10196
10541
  return true;
10197
10542
  }
10198
10543
  if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null && hasSelfReferencingRef(
10199
10544
  schema.additionalProperties,
10200
10545
  root,
10201
- `${path23}/additionalProperties`,
10546
+ `${path24}/additionalProperties`,
10202
10547
  nextActivePaths
10203
10548
  )) {
10204
10549
  return true;
@@ -10207,7 +10552,7 @@ function hasSelfReferencingRef(schema, root, path23 = "#", activePaths = /* @__P
10207
10552
  if (hasSelfReferencingRef(
10208
10553
  childSchema,
10209
10554
  root,
10210
- `${path23}/properties/${escapeJsonPointerSegment(key2)}`,
10555
+ `${path24}/properties/${escapeJsonPointerSegment(key2)}`,
10211
10556
  nextActivePaths
10212
10557
  )) {
10213
10558
  return true;
@@ -10217,24 +10562,24 @@ function hasSelfReferencingRef(schema, root, path23 = "#", activePaths = /* @__P
10217
10562
  if (hasSelfReferencingRef(
10218
10563
  childSchema,
10219
10564
  root,
10220
- `${path23}/$defs/${escapeJsonPointerSegment(key2)}`,
10565
+ `${path24}/$defs/${escapeJsonPointerSegment(key2)}`,
10221
10566
  nextActivePaths
10222
10567
  )) {
10223
10568
  return true;
10224
10569
  }
10225
10570
  }
10226
10571
  for (const [index, childSchema] of (schema.oneOf ?? []).entries()) {
10227
- if (hasSelfReferencingRef(childSchema, root, `${path23}/oneOf/${index}`, nextActivePaths)) {
10572
+ if (hasSelfReferencingRef(childSchema, root, `${path24}/oneOf/${index}`, nextActivePaths)) {
10228
10573
  return true;
10229
10574
  }
10230
10575
  }
10231
10576
  for (const [index, childSchema] of (schema.anyOf ?? []).entries()) {
10232
- if (hasSelfReferencingRef(childSchema, root, `${path23}/anyOf/${index}`, nextActivePaths)) {
10577
+ if (hasSelfReferencingRef(childSchema, root, `${path24}/anyOf/${index}`, nextActivePaths)) {
10233
10578
  return true;
10234
10579
  }
10235
10580
  }
10236
10581
  for (const [index, childSchema] of (schema.allOf ?? []).entries()) {
10237
- if (hasSelfReferencingRef(childSchema, root, `${path23}/allOf/${index}`, nextActivePaths)) {
10582
+ if (hasSelfReferencingRef(childSchema, root, `${path24}/allOf/${index}`, nextActivePaths)) {
10238
10583
  return true;
10239
10584
  }
10240
10585
  }
@@ -10250,14 +10595,14 @@ function getLocalRefPath(ref) {
10250
10595
  return ref.startsWith("#/") ? ref : void 0;
10251
10596
  }
10252
10597
  function resolveLocalRef(root, ref) {
10253
- const path23 = getLocalRefPath(ref);
10254
- if (path23 === void 0) {
10598
+ const path24 = getLocalRefPath(ref);
10599
+ if (path24 === void 0) {
10255
10600
  return void 0;
10256
10601
  }
10257
- if (path23 === "#") {
10602
+ if (path24 === "#") {
10258
10603
  return root;
10259
10604
  }
10260
- const segments = path23.slice(2).split("/").map(unescapeJsonPointerSegment);
10605
+ const segments = path24.slice(2).split("/").map(unescapeJsonPointerSegment);
10261
10606
  let current = root;
10262
10607
  for (const segment of segments) {
10263
10608
  if (Array.isArray(current)) {
@@ -10460,10 +10805,10 @@ function validateRenameMap2(name, tools, rename5) {
10460
10805
  }
10461
10806
  }
10462
10807
  }
10463
- function createConnection(name, config) {
10808
+ function createConnection(name, config2) {
10464
10809
  const connection = {
10465
10810
  name,
10466
- config,
10811
+ config: config2,
10467
10812
  async dispose() {
10468
10813
  shutdownDisposers.delete(connection.dispose);
10469
10814
  connection.connecting = void 0;
@@ -10518,8 +10863,8 @@ async function readCache(cachePath) {
10518
10863
  }
10519
10864
  }
10520
10865
  async function writeCache(cachePath, cache) {
10521
- const directory = path11.dirname(cachePath);
10522
- const tempPath = `${cachePath}.tmp-${randomUUID()}`;
10866
+ const directory = path12.dirname(cachePath);
10867
+ const tempPath = `${cachePath}.tmp-${randomUUID2()}`;
10523
10868
  await assertCachePathHasNoSymlinks(cachePath);
10524
10869
  await assertCachePathHasNoSymlinks(tempPath);
10525
10870
  await mkdir(directory, { recursive: true });
@@ -10530,13 +10875,13 @@ async function writeCache(cachePath, cache) {
10530
10875
  await assertCachePathHasNoSymlinks(cachePath);
10531
10876
  await rename2(tempPath, cachePath);
10532
10877
  }
10533
- async function fetchCache(name, config) {
10878
+ async function fetchCache(name, config2) {
10534
10879
  const logger2 = createLogger((message2) => {
10535
10880
  process.stderr.write(`${message2}
10536
10881
  `);
10537
10882
  });
10538
10883
  logger2.info(`MCP ${name}: connecting`);
10539
- const client = await dialUpstream(name, config);
10884
+ const client = await dialUpstream(name, config2);
10540
10885
  try {
10541
10886
  logger2.info(`MCP ${name}: listing tools`);
10542
10887
  const tools = [];
@@ -10555,7 +10900,7 @@ async function fetchCache(name, config) {
10555
10900
  $schema: MCP_PROXY_SCHEMA_URL,
10556
10901
  version: 1,
10557
10902
  upstream,
10558
- configFingerprint: fingerprintMcpServerConfig(config),
10903
+ configFingerprint: fingerprintMcpServerConfig(config2),
10559
10904
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
10560
10905
  tools
10561
10906
  };
@@ -10625,8 +10970,8 @@ function isRefreshRequested(name, refresh) {
10625
10970
  }
10626
10971
  async function resolveSingleProxy(group, options) {
10627
10972
  const internal = getInternalGroupConfig2(group);
10628
- const config = internal.mcp;
10629
- if (config === void 0) {
10973
+ const config2 = internal.mcp;
10974
+ if (config2 === void 0) {
10630
10975
  return;
10631
10976
  }
10632
10977
  const name = group.name;
@@ -10636,21 +10981,21 @@ async function resolveSingleProxy(group, options) {
10636
10981
  let cache;
10637
10982
  let shouldWriteCache = false;
10638
10983
  if (isRefreshRequested(name, refresh)) {
10639
- cache = await fetchCache(name, config);
10984
+ cache = await fetchCache(name, config2);
10640
10985
  shouldWriteCache = true;
10641
10986
  } else {
10642
10987
  const storedCache = await readCache(cachePath);
10643
- if (storedCache && cacheMatchesConfig(storedCache, config)) {
10988
+ if (storedCache && cacheMatchesConfig(storedCache, config2)) {
10644
10989
  cache = storedCache;
10645
10990
  } else {
10646
- cache = await fetchCache(name, config);
10991
+ cache = await fetchCache(name, config2);
10647
10992
  shouldWriteCache = true;
10648
10993
  }
10649
10994
  }
10650
10995
  const tools = filterAllowlistedTools(cache.tools, internal.tools);
10651
10996
  validateRenameMap2(name, tools, internal.rename);
10652
10997
  const previousConnection = getProxyConnection(group);
10653
- const nextConnection = createConnection(name, config);
10998
+ const nextConnection = createConnection(name, config2);
10654
10999
  try {
10655
11000
  replaceProxyChildrenSafely(group, tools, internal.rename, nextConnection);
10656
11001
  if (shouldWriteCache) {
@@ -10675,11 +11020,11 @@ async function resolveSingleProxy(group, options) {
10675
11020
  );
10676
11021
  }
10677
11022
  }
10678
- function cacheMatchesConfig(cache, config) {
10679
- return cache.configFingerprint === fingerprintMcpServerConfig(config);
11023
+ function cacheMatchesConfig(cache, config2) {
11024
+ return cache.configFingerprint === fingerprintMcpServerConfig(config2);
10680
11025
  }
10681
- function fingerprintMcpServerConfig(config) {
10682
- return createHash3("sha256").update(JSON.stringify(config)).digest("hex");
11026
+ function fingerprintMcpServerConfig(config2) {
11027
+ return createHash3("sha256").update(JSON.stringify(config2)).digest("hex");
10683
11028
  }
10684
11029
  function collectProxyGroups(root) {
10685
11030
  const groups = [];
@@ -10699,13 +11044,13 @@ function collectProxyGroups(root) {
10699
11044
  function findProjectRoot(from = process.cwd()) {
10700
11045
  let current = process.cwd();
10701
11046
  if (from !== current) {
10702
- current = path11.resolve(from);
11047
+ current = path12.resolve(from);
10703
11048
  }
10704
11049
  while (true) {
10705
- if (existsSync2(path11.join(current, "package.json"))) {
11050
+ if (existsSync2(path12.join(current, "package.json"))) {
10706
11051
  return current;
10707
11052
  }
10708
- const parent = path11.dirname(current);
11053
+ const parent = path12.dirname(current);
10709
11054
  if (parent === current) {
10710
11055
  return void 0;
10711
11056
  }
@@ -10722,7 +11067,7 @@ function resolveCachePath(name, projectRoot) {
10722
11067
  if (name.length === 0 || name === "." || name === ".." || name.includes("/") || name.includes("\\")) {
10723
11068
  throw new Error(`MCP proxy group name must be a file-safe name: "${name}".`);
10724
11069
  }
10725
- return path11.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
11070
+ return path12.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
10726
11071
  }
10727
11072
  async function assertCachePathHasNoSymlinks(filePath) {
10728
11073
  let currentPath = filePath;
@@ -10736,10 +11081,10 @@ async function assertCachePathHasNoSymlinks(filePath) {
10736
11081
  throw error3;
10737
11082
  }
10738
11083
  }
10739
- if (path11.basename(currentPath) === ".toolcraft") {
11084
+ if (path12.basename(currentPath) === ".toolcraft") {
10740
11085
  return;
10741
11086
  }
10742
- const parentPath = path11.dirname(currentPath);
11087
+ const parentPath = path12.dirname(currentPath);
10743
11088
  if (parentPath === currentPath) {
10744
11089
  return;
10745
11090
  }
@@ -10757,20 +11102,20 @@ function parseRefreshEnv(value) {
10757
11102
  const names = trimmed.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
10758
11103
  return names.length === 0 ? void 0 : new Set(names);
10759
11104
  }
10760
- async function dialUpstream(name, config) {
11105
+ async function dialUpstream(name, config2) {
10761
11106
  const client = new McpClient({
10762
11107
  clientInfo: {
10763
11108
  name: `${DEFAULT_CLIENT_INFO.name}-${name}`,
10764
11109
  version: DEFAULT_CLIENT_INFO.version
10765
11110
  }
10766
11111
  });
10767
- const transport = config.transport === "stdio" ? new StdioTransport({
10768
- command: config.command,
10769
- ...config.args === void 0 ? {} : { args: config.args },
10770
- ...config.env === void 0 ? {} : { env: config.env }
11112
+ const transport = config2.transport === "stdio" ? new StdioTransport({
11113
+ command: config2.command,
11114
+ ...config2.args === void 0 ? {} : { args: config2.args },
11115
+ ...config2.env === void 0 ? {} : { env: config2.env }
10771
11116
  }) : new HttpTransport({
10772
- url: config.url,
10773
- ...config.headers === void 0 ? {} : { headers: config.headers }
11117
+ url: config2.url,
11118
+ ...config2.headers === void 0 ? {} : { headers: config2.headers }
10774
11119
  });
10775
11120
  await client.connect(transport);
10776
11121
  return client;
@@ -10780,10 +11125,82 @@ async function resolveMcpProxies(root, options = {}) {
10780
11125
  await Promise.all(groups.map((group) => resolveSingleProxy(group, options)));
10781
11126
  }
10782
11127
 
11128
+ // ../toolcraft/src/redaction.ts
11129
+ var REDACTED_VALUE = "<redacted>";
11130
+ var SENSITIVE_NAME_PARTS = ["password", "token", "apikey", "secret"];
11131
+ var AUTHORIZATION_HEADER_NAMES = /* @__PURE__ */ new Set(["authorization", "proxyauthorization"]);
11132
+ var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set(["cookie", "setcookie"]);
11133
+ function isPlainObject2(value) {
11134
+ return typeof value === "object" && value !== null && !Array.isArray(value);
11135
+ }
11136
+ function normalizeName(name) {
11137
+ return name.toLowerCase().replace(/[^a-z0-9]/g, "");
11138
+ }
11139
+ function isSensitiveName(name) {
11140
+ const normalized = normalizeName(name);
11141
+ return SENSITIVE_NAME_PARTS.some((candidate) => normalized.includes(candidate));
11142
+ }
11143
+ function redactSecretLikeFieldsValue(value, name, seen) {
11144
+ if (name.length > 0 && isSensitiveName(name)) {
11145
+ return REDACTED_VALUE;
11146
+ }
11147
+ if (Array.isArray(value)) {
11148
+ if (seen.has(value)) {
11149
+ return "[Circular]";
11150
+ }
11151
+ seen.add(value);
11152
+ return value.map((entry) => redactSecretLikeFieldsValue(entry, name, seen));
11153
+ }
11154
+ if (isPlainObject2(value)) {
11155
+ if (seen.has(value)) {
11156
+ return "[Circular]";
11157
+ }
11158
+ seen.add(value);
11159
+ return Object.fromEntries(
11160
+ Object.entries(value).map(([key2, entry]) => [
11161
+ key2,
11162
+ redactSecretLikeFieldsValue(entry, key2, seen)
11163
+ ])
11164
+ );
11165
+ }
11166
+ return value;
11167
+ }
11168
+ function redactSecretLikeFields(value, name = "") {
11169
+ return redactSecretLikeFieldsValue(value, name, /* @__PURE__ */ new WeakSet());
11170
+ }
11171
+ function parseJsonObjectOrArray(value) {
11172
+ const trimmed = value.trim();
11173
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
11174
+ return void 0;
11175
+ }
11176
+ try {
11177
+ const parsed = JSON.parse(trimmed);
11178
+ return isPlainObject2(parsed) || Array.isArray(parsed) ? parsed : void 0;
11179
+ } catch {
11180
+ return void 0;
11181
+ }
11182
+ }
11183
+ function redactHttpBody(body) {
11184
+ if (typeof body === "string") {
11185
+ const parsed = parseJsonObjectOrArray(body);
11186
+ return parsed === void 0 ? body : redactSecretLikeFields(parsed);
11187
+ }
11188
+ return redactSecretLikeFields(body);
11189
+ }
11190
+ function redactHttpHeaderValue(name, value) {
11191
+ const normalized = normalizeName(name);
11192
+ if (AUTHORIZATION_HEADER_NAMES.has(normalized)) {
11193
+ return "Bearer ****";
11194
+ }
11195
+ if (SECRET_HEADER_NAMES.has(normalized) || isSensitiveName(name)) {
11196
+ return REDACTED_VALUE;
11197
+ }
11198
+ return value;
11199
+ }
11200
+
10783
11201
  // ../toolcraft/src/error-report.ts
10784
11202
  var ERROR_REPORTS_ENV = "TOOLCRAFT_ERROR_REPORTS";
10785
- var DEFAULT_SENSITIVE_NAMES = ["password", "token", "apikey", "secret"];
10786
- function isPlainObject2(value) {
11203
+ function isPlainObject3(value) {
10787
11204
  return typeof value === "object" && value !== null && !Array.isArray(value);
10788
11205
  }
10789
11206
  function unwrapOptional(schema) {
@@ -10793,7 +11210,7 @@ function unwrapOptional(schema) {
10793
11210
  return schema;
10794
11211
  }
10795
11212
  function hasHttpContext(error3) {
10796
- return error3 instanceof Error && error3.name === "HttpError" && isPlainObject2(error3.request) && isPlainObject2(error3.response);
11213
+ return error3 instanceof Error && error3.name === "HttpError" && isPlainObject3(error3.request) && isPlainObject3(error3.response);
10797
11214
  }
10798
11215
  function isSkippedError(error3) {
10799
11216
  if (error3 instanceof ApprovalDeclinedError) {
@@ -10813,25 +11230,25 @@ function reportsEnabled(option, env) {
10813
11230
  function resolveReportDir(option, projectRoot) {
10814
11231
  const configuredDir = typeof option === "object" ? option.dir : void 0;
10815
11232
  if (configuredDir === void 0 || configuredDir.length === 0) {
10816
- return path12.join(projectRoot, ".toolcraft", "errors");
11233
+ return path13.join(projectRoot, ".toolcraft", "errors");
10817
11234
  }
10818
- return path12.isAbsolute(configuredDir) ? configuredDir : path12.join(projectRoot, configuredDir);
11235
+ return path13.isAbsolute(configuredDir) ? configuredDir : path13.join(projectRoot, configuredDir);
10819
11236
  }
10820
11237
  function reportDirMustStayWithinProject(option) {
10821
11238
  const configuredDir = typeof option === "object" ? option.dir : void 0;
10822
- return configuredDir === void 0 || configuredDir.length === 0 || !path12.isAbsolute(configuredDir);
11239
+ return configuredDir === void 0 || configuredDir.length === 0 || !path13.isAbsolute(configuredDir);
10823
11240
  }
10824
11241
  function isWithinDirectory(parent, child) {
10825
- const relative = path12.relative(parent, child);
10826
- return relative === "" || !path12.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path12.sep}`);
11242
+ const relative = path13.relative(parent, child);
11243
+ return relative === "" || !path13.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path13.sep}`);
10827
11244
  }
10828
11245
  async function assertReportDirWithinProject(projectRoot, reportDir) {
10829
- if (!isWithinDirectory(path12.resolve(projectRoot), path12.resolve(reportDir))) {
11246
+ if (!isWithinDirectory(path13.resolve(projectRoot), path13.resolve(reportDir))) {
10830
11247
  throw new Error("Error report directory resolves outside project root.");
10831
11248
  }
10832
11249
  const [canonicalProjectRoot, canonicalReportDir] = await Promise.all([
10833
- realpath(projectRoot),
10834
- realpath(reportDir)
11250
+ realpath2(projectRoot),
11251
+ realpath2(reportDir)
10835
11252
  ]);
10836
11253
  if (!isWithinDirectory(canonicalProjectRoot, canonicalReportDir)) {
10837
11254
  throw new Error("Error report directory resolves outside project root.");
@@ -10877,7 +11294,7 @@ function slugifyCommandPath(commandPath) {
10877
11294
  return output.length === 0 ? "root" : output;
10878
11295
  }
10879
11296
  function relativeDisplayPath(projectRoot, absolutePath) {
10880
- const relative = path12.relative(projectRoot, absolutePath);
11297
+ const relative = path13.relative(projectRoot, absolutePath);
10881
11298
  return relative.length === 0 || relative.startsWith("..") ? absolutePath : relative;
10882
11299
  }
10883
11300
  function redactValue(value) {
@@ -10886,9 +11303,24 @@ function redactValue(value) {
10886
11303
  }
10887
11304
  return `<set, ${value.length} chars>`;
10888
11305
  }
10889
- function isSensitiveName(name) {
10890
- const normalized = name.toLowerCase();
10891
- return DEFAULT_SENSITIVE_NAMES.some((candidate) => normalized.includes(candidate));
11306
+ function collectStringLeaves(value, output) {
11307
+ if (typeof value === "string") {
11308
+ if (value.length > 0) {
11309
+ output.add(value);
11310
+ }
11311
+ return;
11312
+ }
11313
+ if (Array.isArray(value)) {
11314
+ for (const entry of value) {
11315
+ collectStringLeaves(entry, output);
11316
+ }
11317
+ return;
11318
+ }
11319
+ if (isPlainObject3(value)) {
11320
+ for (const entry of Object.values(value)) {
11321
+ collectStringLeaves(entry, output);
11322
+ }
11323
+ }
10892
11324
  }
10893
11325
  function schemaSecretValue(schema) {
10894
11326
  const unwrapped = unwrapOptional(schema);
@@ -10909,7 +11341,7 @@ function redactParamsValue(value, schema, name) {
10909
11341
  return "<redacted>";
10910
11342
  }
10911
11343
  const unwrapped = unwrapOptional(schema);
10912
- if (unwrapped.kind === "object" && isPlainObject2(value)) {
11344
+ if (unwrapped.kind === "object" && isPlainObject3(value)) {
10913
11345
  return Object.fromEntries(
10914
11346
  Object.entries(value).map(([key2, childValue]) => {
10915
11347
  const childSchema = unwrapped.shape[key2];
@@ -10931,6 +11363,52 @@ function redactParams(params17, command) {
10931
11363
  }
10932
11364
  return redactParamsValue(params17, command.params, "");
10933
11365
  }
11366
+ function collectSensitiveParamValues(value, schema, name, output) {
11367
+ if (shouldRedactParam(name, schema)) {
11368
+ collectStringLeaves(value, output);
11369
+ return;
11370
+ }
11371
+ const unwrapped = unwrapOptional(schema);
11372
+ if (unwrapped.kind === "object" && isPlainObject3(value)) {
11373
+ for (const [key2, childValue] of Object.entries(value)) {
11374
+ const childSchema = unwrapped.shape[key2];
11375
+ if (childSchema !== void 0) {
11376
+ collectSensitiveParamValues(childValue, childSchema, key2, output);
11377
+ }
11378
+ }
11379
+ return;
11380
+ }
11381
+ if (unwrapped.kind === "array" && Array.isArray(value)) {
11382
+ for (const entry of value) {
11383
+ collectSensitiveParamValues(entry, unwrapped.item, name, output);
11384
+ }
11385
+ }
11386
+ }
11387
+ function createReportStringRedactor(context, env) {
11388
+ const values = /* @__PURE__ */ new Set();
11389
+ for (const value of Object.values(context.secrets ?? {})) {
11390
+ if (value !== void 0 && value.length > 0) {
11391
+ values.add(value);
11392
+ }
11393
+ }
11394
+ for (const [name, secret] of Object.entries(context.command?.secrets ?? {})) {
11395
+ const value = context.secrets?.[name] ?? env[secret.env];
11396
+ if (value !== void 0 && value.length > 0) {
11397
+ values.add(value);
11398
+ }
11399
+ }
11400
+ if (context.command !== void 0) {
11401
+ collectSensitiveParamValues(context.params, context.command.params, "", values);
11402
+ }
11403
+ const orderedValues = [...values].sort((left, right) => right.length - left.length);
11404
+ return (value) => {
11405
+ let redacted = value;
11406
+ for (const secretValue of orderedValues) {
11407
+ redacted = redacted.split(secretValue).join("<redacted>");
11408
+ }
11409
+ return redacted;
11410
+ };
11411
+ }
10934
11412
  function commandSecretEnvNames(secrets) {
10935
11413
  if (secrets === void 0) {
10936
11414
  return [];
@@ -10984,28 +11462,42 @@ function redactArgv(argv, options) {
10984
11462
  function stableJson(value) {
10985
11463
  return JSON.stringify(value, null, 2) ?? "undefined";
10986
11464
  }
10987
- function redactStructuredErrorField(name, value) {
10988
- if (typeof value === "string" && name.toLowerCase() === "authorization") {
10989
- return "Bearer ****";
11465
+ function redactStructuredErrorField(name, value, redactString) {
11466
+ if (typeof value === "string") {
11467
+ const redactedHeaderValue = redactHttpHeaderValue(name, value);
11468
+ if (redactedHeaderValue !== value) {
11469
+ return redactedHeaderValue;
11470
+ }
11471
+ if (isSensitiveName(name)) {
11472
+ return "<redacted>";
11473
+ }
11474
+ return redactString(value);
10990
11475
  }
10991
11476
  if (Array.isArray(value)) {
10992
- return value.map((entry) => redactStructuredErrorField(name, entry));
11477
+ return value.map((entry) => redactStructuredErrorField(name, entry, redactString));
10993
11478
  }
10994
- if (isPlainObject2(value)) {
11479
+ if (isPlainObject3(value)) {
10995
11480
  return Object.fromEntries(
10996
- Object.entries(value).map(([key2, entry]) => [key2, redactStructuredErrorField(key2, entry)])
11481
+ Object.entries(value).map(([key2, entry]) => [
11482
+ key2,
11483
+ redactStructuredErrorField(key2, entry, redactString)
11484
+ ])
10997
11485
  );
10998
11486
  }
10999
11487
  return value;
11000
11488
  }
11001
- function ownStructuredFields(error3) {
11489
+ function ownStructuredFields(error3, redactString) {
11002
11490
  const fields = {};
11003
11491
  for (const key2 of Object.keys(error3)) {
11004
11492
  if (key2 === "name" || key2 === "message" || key2 === "stack" || key2 === "cause") {
11005
11493
  continue;
11006
11494
  }
11007
11495
  Object.defineProperty(fields, key2, {
11008
- value: redactStructuredErrorField(key2, error3[key2]),
11496
+ value: redactStructuredErrorField(
11497
+ key2,
11498
+ error3[key2],
11499
+ redactString
11500
+ ),
11009
11501
  enumerable: true,
11010
11502
  configurable: true,
11011
11503
  writable: true
@@ -11013,43 +11505,44 @@ function ownStructuredFields(error3) {
11013
11505
  }
11014
11506
  return fields;
11015
11507
  }
11016
- function formatStackChain(error3) {
11508
+ function formatStackChain(error3, redactString) {
11017
11509
  const lines = [];
11018
11510
  let current = error3;
11019
11511
  let index = 0;
11020
11512
  while (current !== void 0) {
11021
11513
  if (current instanceof Error) {
11022
- lines.push(
11023
- index === 0 ? current.stack ?? String(current) : `Caused by: ${current.stack ?? String(current)}`
11024
- );
11514
+ const stack = current.stack ?? String(current);
11515
+ lines.push(redactString(index === 0 ? stack : `Caused by: ${stack}`));
11025
11516
  current = current.cause;
11026
11517
  } else {
11027
- lines.push(index === 0 ? String(current) : `Caused by: ${String(current)}`);
11518
+ const message2 = String(current);
11519
+ lines.push(redactString(index === 0 ? message2 : `Caused by: ${message2}`));
11028
11520
  current = void 0;
11029
11521
  }
11030
11522
  index += 1;
11031
11523
  }
11032
11524
  return lines.join("\n");
11033
11525
  }
11034
- function formatHeaderValue(name, value) {
11035
- return name.toLowerCase() === "authorization" ? "Bearer ****" : value;
11526
+ function formatHeaderValue(name, value, redactString) {
11527
+ return redactString(redactHttpHeaderValue(name, value));
11036
11528
  }
11037
- function formatHeaders(headers) {
11038
- return Object.entries(headers).map(([name, value]) => `${name}: ${formatHeaderValue(name, value)}`).join("\n");
11529
+ function formatHeaders(headers, redactString) {
11530
+ return Object.entries(headers).map(([name, value]) => `${name}: ${formatHeaderValue(name, value, redactString)}`).join("\n");
11039
11531
  }
11040
- function formatBody(body) {
11041
- if (typeof body === "string") {
11042
- return body;
11532
+ function formatBody(body, redactString) {
11533
+ const redactedBody = redactHttpBody(body);
11534
+ if (typeof redactedBody === "string") {
11535
+ return redactString(redactedBody);
11043
11536
  }
11044
- return stableJson(body);
11537
+ return redactString(stableJson(redactedBody));
11045
11538
  }
11046
- function formatHttpTranscript(error3) {
11539
+ function formatHttpTranscript(error3, redactString) {
11047
11540
  const requestLines = [
11048
11541
  `${error3.request.method} ${error3.request.url}`,
11049
- formatHeaders(error3.request.headers)
11542
+ formatHeaders(error3.request.headers, redactString)
11050
11543
  ].filter((line) => line.length > 0);
11051
11544
  if (error3.request.body !== void 0) {
11052
- requestLines.push("", formatBody(error3.request.body));
11545
+ requestLines.push("", formatBody(error3.request.body, redactString));
11053
11546
  }
11054
11547
  return [
11055
11548
  "Request:",
@@ -11057,9 +11550,9 @@ function formatHttpTranscript(error3) {
11057
11550
  "",
11058
11551
  "Response:",
11059
11552
  `${error3.response.status} ${error3.response.statusText}`,
11060
- formatHeaders(error3.response.headers),
11553
+ formatHeaders(error3.response.headers, redactString),
11061
11554
  "",
11062
- formatBody(error3.response.body)
11555
+ formatBody(error3.response.body, redactString)
11063
11556
  ].join("\n");
11064
11557
  }
11065
11558
  function resolveToolcraftVersion(version) {
@@ -11068,9 +11561,10 @@ function resolveToolcraftVersion(version) {
11068
11561
  function buildReport(context) {
11069
11562
  const env = context.env ?? process.env;
11070
11563
  const error3 = context.error;
11564
+ const redactString = createReportStringRedactor(context, env);
11071
11565
  const errorName = error3 instanceof Error ? error3.name : typeof error3;
11072
- const errorMessage = error3 instanceof Error ? error3.message : String(error3);
11073
- const structuredFields = error3 instanceof Error ? ownStructuredFields(error3) : {};
11566
+ const errorMessage = redactString(error3 instanceof Error ? error3.message : String(error3));
11567
+ const structuredFields = error3 instanceof Error ? ownStructuredFields(error3, redactString) : {};
11074
11568
  const secretLines = Object.entries(context.command?.secrets ?? {}).map(([name, secret]) => {
11075
11569
  const value = context.secrets?.[name] ?? env[secret.env];
11076
11570
  return `${secret.env}=${redactValue(value)}`;
@@ -11084,7 +11578,9 @@ function buildReport(context) {
11084
11578
  `platform: ${process.platform} ${process.arch}`,
11085
11579
  "",
11086
11580
  "Argv",
11087
- stableJson(redactArgv(context.argv, { command: context.command, secrets: context.secrets })),
11581
+ redactString(
11582
+ stableJson(redactArgv(context.argv, { command: context.command, secrets: context.secrets }))
11583
+ ),
11088
11584
  "",
11089
11585
  "Resolved Secrets",
11090
11586
  ...secretLines.length === 0 ? ["<none>"] : secretLines,
@@ -11093,19 +11589,19 @@ function buildReport(context) {
11093
11589
  context.commandPath === void 0 || context.commandPath.length === 0 ? "root" : context.commandPath,
11094
11590
  "",
11095
11591
  "Parsed Params",
11096
- stableJson(redactParams(context.params, context.command)),
11592
+ redactString(stableJson(redactParams(context.params, context.command))),
11097
11593
  "",
11098
11594
  "Error",
11099
11595
  `name: ${errorName}`,
11100
11596
  `message: ${errorMessage}`,
11101
11597
  "structured fields:",
11102
- stableJson(structuredFields),
11598
+ redactString(stableJson(structuredFields)),
11103
11599
  "",
11104
11600
  "Stack",
11105
- formatStackChain(error3)
11601
+ formatStackChain(error3, redactString)
11106
11602
  ];
11107
11603
  if (hasHttpContext(error3)) {
11108
- lines.push("", "HTTP Transcript", formatHttpTranscript(error3));
11604
+ lines.push("", "HTTP Transcript", formatHttpTranscript(error3, redactString));
11109
11605
  }
11110
11606
  return `${lines.join("\n")}
11111
11607
  `;
@@ -11117,8 +11613,8 @@ async function writeErrorReport(context) {
11117
11613
  }
11118
11614
  const projectRoot = resolveProjectRoot(context.projectRoot);
11119
11615
  const reportDir = resolveReportDir(context.errorReports, projectRoot);
11120
- const fileName = `${formatTimestamp(/* @__PURE__ */ new Date())}-${slugifyCommandPath(context.commandPath)}-${randomUUID2()}.log`;
11121
- const absolutePath = path12.join(reportDir, fileName);
11616
+ const fileName = `${formatTimestamp(/* @__PURE__ */ new Date())}-${slugifyCommandPath(context.commandPath)}-${randomUUID3()}.log`;
11617
+ const absolutePath = path13.join(reportDir, fileName);
11122
11618
  await mkdir2(reportDir, { recursive: true });
11123
11619
  if (reportDirMustStayWithinProject(context.errorReports)) {
11124
11620
  await assertReportDirWithinProject(projectRoot, reportDir);
@@ -11565,6 +12061,7 @@ ${rendered.join("\n")}`);
11565
12061
  }
11566
12062
 
11567
12063
  // ../toolcraft/src/cli.ts
12064
+ configureTheme({ brand: "blue", label: "Toolcraft" });
11568
12065
  var RESERVED_SERVICE_NAMES = /* @__PURE__ */ new Set([
11569
12066
  "params",
11570
12067
  "secrets",
@@ -11582,7 +12079,7 @@ function inferProgramName(argv) {
11582
12079
  if (typeof entrypoint !== "string" || entrypoint.length === 0) {
11583
12080
  return "toolcraft";
11584
12081
  }
11585
- const parsed = path13.parse(entrypoint);
12082
+ const parsed = path14.parse(entrypoint);
11586
12083
  return parsed.name.length > 0 ? parsed.name : "toolcraft";
11587
12084
  }
11588
12085
  function normalizeRoots(roots, argv) {
@@ -11640,11 +12137,11 @@ function formatSegment(segment, casing) {
11640
12137
  const separator = casing === "snake" ? "_" : "-";
11641
12138
  return splitWords3(segment).join(separator);
11642
12139
  }
11643
- function toOptionFlag(path23, casing) {
11644
- return `--${path23.map((segment) => formatSegment(segment, casing)).join(".")}`;
12140
+ function toOptionFlag(path24, casing) {
12141
+ return `--${path24.map((segment) => formatSegment(segment, casing)).join(".")}`;
11645
12142
  }
11646
- function toOptionAttribute(path23, casing) {
11647
- return path23.map((segment) => {
12143
+ function toOptionAttribute(path24, casing) {
12144
+ return path24.map((segment) => {
11648
12145
  const formatted = formatSegment(segment, casing);
11649
12146
  if (casing === "snake") {
11650
12147
  return formatted;
@@ -11655,23 +12152,23 @@ function toOptionAttribute(path23, casing) {
11655
12152
  ).join("");
11656
12153
  }).join(".");
11657
12154
  }
11658
- function toDisplayPath(path23) {
11659
- return path23.join(".");
12155
+ function toDisplayPath(path24) {
12156
+ return path24.join(".");
11660
12157
  }
11661
- function toUnionKindControlPath(path23) {
11662
- if (path23.length === 0) {
12158
+ function toUnionKindControlPath(path24) {
12159
+ if (path24.length === 0) {
11663
12160
  return ["kind"];
11664
12161
  }
11665
- const head = path23.slice(0, -1);
11666
- const tail = path23[path23.length - 1] ?? "";
12162
+ const head = path24.slice(0, -1);
12163
+ const tail = path24[path24.length - 1] ?? "";
11667
12164
  return [...head, `${tail}Kind`];
11668
12165
  }
11669
- function toUnionKindDisplayPath(path23) {
11670
- if (path23.length === 0) {
12166
+ function toUnionKindDisplayPath(path24) {
12167
+ if (path24.length === 0) {
11671
12168
  return "kind";
11672
12169
  }
11673
- const head = path23.slice(0, -1);
11674
- const tail = path23[path23.length - 1] ?? "";
12170
+ const head = path24.slice(0, -1);
12171
+ const tail = path24[path24.length - 1] ?? "";
11675
12172
  return [...head, `${tail}-kind`].join(".");
11676
12173
  }
11677
12174
  function createSyntheticEnumSchema(values) {
@@ -11687,14 +12184,14 @@ function getRequiredBranchFingerprint(branch, casing) {
11687
12184
  const requiredKeys = Object.entries(branch.shape).filter(([, schema]) => schema.kind !== "optional").map(([key2]) => formatSegment(key2, casing)).sort();
11688
12185
  return requiredKeys.join("+");
11689
12186
  }
11690
- function collectFields(schema, casing, globalLongOptionFlags, path23 = [], inheritedOptional = false, variantContext) {
12187
+ function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inheritedOptional = false, variantContext) {
11691
12188
  const collected = {
11692
12189
  dynamicFields: [],
11693
12190
  fields: [],
11694
12191
  variants: []
11695
12192
  };
11696
12193
  for (const [key2, rawChildSchema] of Object.entries(schema.shape)) {
11697
- const nextPath = [...path23, key2];
12194
+ const nextPath = [...path24, key2];
11698
12195
  const runtimeOptional = inheritedOptional || rawChildSchema.kind === "optional";
11699
12196
  const childSchema = unwrapOptional2(rawChildSchema);
11700
12197
  const requiredWhenActive = rawChildSchema.kind !== "optional" && childSchema.default === void 0;
@@ -11875,9 +12372,9 @@ function collectFields(schema, casing, globalLongOptionFlags, path23 = [], inher
11875
12372
  }
11876
12373
  return collected;
11877
12374
  }
11878
- function toCommanderOptionAttribute(path23, casing, globalLongOptionFlags) {
11879
- const optionAttribute = toOptionAttribute(path23, casing);
11880
- const optionFlag = toOptionFlag(path23, casing);
12375
+ function toCommanderOptionAttribute(path24, casing, globalLongOptionFlags) {
12376
+ const optionAttribute = toOptionAttribute(path24, casing);
12377
+ const optionFlag = toOptionFlag(path24, casing);
11881
12378
  if (!globalLongOptionFlags.has(optionFlag)) {
11882
12379
  return optionAttribute;
11883
12380
  }
@@ -12846,10 +13343,10 @@ function parseDebugStackMode(value) {
12846
13343
  formatInvalidEnumMessage("--debug", String(value), ["raw"], { candidates: ["raw"] })
12847
13344
  );
12848
13345
  }
12849
- function setNestedValue(target, path23, value) {
13346
+ function setNestedValue(target, path24, value) {
12850
13347
  let cursor = target;
12851
- for (let index = 0; index < path23.length - 1; index += 1) {
12852
- const segment = path23[index] ?? "";
13348
+ for (let index = 0; index < path24.length - 1; index += 1) {
13349
+ const segment = path24[index] ?? "";
12853
13350
  const existing = Object.prototype.hasOwnProperty.call(cursor, segment) ? cursor[segment] : void 0;
12854
13351
  if (typeof existing === "object" && existing !== null) {
12855
13352
  cursor = existing;
@@ -12864,7 +13361,7 @@ function setNestedValue(target, path23, value) {
12864
13361
  });
12865
13362
  cursor = next;
12866
13363
  }
12867
- const leaf = path23[path23.length - 1];
13364
+ const leaf = path24[path24.length - 1];
12868
13365
  if (leaf !== void 0) {
12869
13366
  Object.defineProperty(cursor, leaf, {
12870
13367
  value,
@@ -12974,21 +13471,21 @@ async function withOutputFormat2(output, fn) {
12974
13471
  }
12975
13472
  function createFs2() {
12976
13473
  return {
12977
- readFile: async (path23, encoding = "utf8") => readFile4(path23, { encoding }),
12978
- writeFile: async (path23, contents) => {
12979
- await writeFile5(path23, contents);
13474
+ readFile: async (path24, encoding = "utf8") => readFile4(path24, { encoding }),
13475
+ writeFile: async (path24, contents) => {
13476
+ await writeFile5(path24, contents);
12980
13477
  },
12981
- exists: async (path23) => {
13478
+ exists: async (path24) => {
12982
13479
  try {
12983
- await access2(path23);
13480
+ await access2(path24);
12984
13481
  return true;
12985
13482
  } catch {
12986
13483
  return false;
12987
13484
  }
12988
13485
  },
12989
- lstat: async (path23) => lstat3(path23),
13486
+ lstat: async (path24) => lstat3(path24),
12990
13487
  rename: async (fromPath, toPath) => rename3(fromPath, toPath),
12991
- unlink: async (path23) => unlink2(path23)
13488
+ unlink: async (path24) => unlink2(path24)
12992
13489
  };
12993
13490
  }
12994
13491
  function createEnv2(values = process.env) {
@@ -12998,15 +13495,15 @@ function createEnv2(values = process.env) {
12998
13495
  }
12999
13496
  };
13000
13497
  }
13001
- function isPlainObject3(value) {
13498
+ function isPlainObject4(value) {
13002
13499
  return typeof value === "object" && value !== null && !Array.isArray(value);
13003
13500
  }
13004
13501
  function hasFieldValue(value) {
13005
13502
  return value !== void 0;
13006
13503
  }
13007
- function hasNestedField(fields, path23) {
13504
+ function hasNestedField(fields, path24) {
13008
13505
  return fields.some(
13009
- (field) => path23.length < field.path.length && path23.every((segment, index) => field.path[index] === segment)
13506
+ (field) => path24.length < field.path.length && path24.every((segment, index) => field.path[index] === segment)
13010
13507
  );
13011
13508
  }
13012
13509
  function describeExpectedPresetValue(schema) {
@@ -13107,14 +13604,14 @@ async function loadPresetValues(fields, presetPath) {
13107
13604
  { cause: error3 }
13108
13605
  );
13109
13606
  }
13110
- if (!isPlainObject3(parsedPreset)) {
13607
+ if (!isPlainObject4(parsedPreset)) {
13111
13608
  throw new UserError(`Preset file "${presetPath}" must contain a JSON object.`);
13112
13609
  }
13113
13610
  const fieldByPath = new Map(fields.map((field) => [field.displayPath, field]));
13114
13611
  const presetValues = {};
13115
- function visitObject(current, path23) {
13612
+ function visitObject(current, path24) {
13116
13613
  for (const [key2, value] of Object.entries(current)) {
13117
- const nextPath = [...path23, key2];
13614
+ const nextPath = [...path24, key2];
13118
13615
  const displayPath = toDisplayPath(nextPath);
13119
13616
  const field = fieldByPath.get(displayPath);
13120
13617
  if (field !== void 0) {
@@ -13126,7 +13623,7 @@ async function loadPresetValues(fields, presetPath) {
13126
13623
  `Preset file "${presetPath}" contains unknown parameter "${displayPath}".`
13127
13624
  );
13128
13625
  }
13129
- if (!isPlainObject3(value)) {
13626
+ if (!isPlainObject4(value)) {
13130
13627
  throw new UserError(
13131
13628
  `Preset file "${presetPath}" has an invalid value for "${displayPath}". Expected an object, got ${describeReceived(value)}.`
13132
13629
  );
@@ -13169,8 +13666,8 @@ function matchesFixtureValue(expected, actual) {
13169
13666
  }
13170
13667
  return expected.every((item, index) => matchesFixtureValue(item, actual[index]));
13171
13668
  }
13172
- if (isPlainObject3(expected)) {
13173
- if (!isPlainObject3(actual)) {
13669
+ if (isPlainObject4(expected)) {
13670
+ if (!isPlainObject4(actual)) {
13174
13671
  return false;
13175
13672
  }
13176
13673
  return Object.entries(expected).every(
@@ -13233,9 +13730,9 @@ function createFixtureFetch(entries) {
13233
13730
  };
13234
13731
  }
13235
13732
  function createFixtureFs(definition) {
13236
- const fsDefinition = isPlainObject3(definition) ? definition : {};
13237
- const readFileEntries = isPlainObject3(fsDefinition.readFile) ? fsDefinition.readFile : {};
13238
- const existsEntries = isPlainObject3(fsDefinition.exists) ? fsDefinition.exists : {};
13733
+ const fsDefinition = isPlainObject4(definition) ? definition : {};
13734
+ const readFileEntries = isPlainObject4(fsDefinition.readFile) ? fsDefinition.readFile : {};
13735
+ const existsEntries = isPlainObject4(fsDefinition.exists) ? fsDefinition.exists : {};
13239
13736
  return {
13240
13737
  readFile: async (filePath) => {
13241
13738
  if (Object.prototype.hasOwnProperty.call(readFileEntries, filePath)) {
@@ -13258,10 +13755,10 @@ function createFixtureFs(definition) {
13258
13755
  function resolveFixtureMethodResult(methodName, definition, args) {
13259
13756
  if (Array.isArray(definition)) {
13260
13757
  for (const entry of definition) {
13261
- if (!isPlainObject3(entry)) {
13758
+ if (!isPlainObject4(entry)) {
13262
13759
  continue;
13263
13760
  }
13264
- const explicitMatcher = isPlainObject3(entry.request) ? entry.request : void 0;
13761
+ const explicitMatcher = isPlainObject4(entry.request) ? entry.request : void 0;
13265
13762
  const matcher = explicitMatcher ?? Object.fromEntries(
13266
13763
  Object.entries(entry).filter(
13267
13764
  ([key2]) => key2 !== "result" && key2 !== "response" && key2 !== "error"
@@ -13273,7 +13770,7 @@ function resolveFixtureMethodResult(methodName, definition, args) {
13273
13770
  matched = matchesFixtureValue(matcher.args, args);
13274
13771
  } else if (Object.keys(matcher).length === 0) {
13275
13772
  matched = true;
13276
- } else if (isPlainObject3(firstArg)) {
13773
+ } else if (isPlainObject4(firstArg)) {
13277
13774
  matched = matchesFixtureValue(matcher, firstArg);
13278
13775
  } else if (args.length === 1 && Object.keys(matcher).length === 1) {
13279
13776
  const [[, expectedValue]] = Object.entries(matcher);
@@ -13294,7 +13791,7 @@ function resolveFixtureMethodResult(methodName, definition, args) {
13294
13791
  return Promise.resolve(null);
13295
13792
  }
13296
13793
  }
13297
- if (isPlainObject3(definition)) {
13794
+ if (isPlainObject4(definition)) {
13298
13795
  const firstArg = args[0];
13299
13796
  if (typeof firstArg === "string" && Object.prototype.hasOwnProperty.call(definition, firstArg)) {
13300
13797
  return Promise.resolve(definition[firstArg]);
@@ -13306,7 +13803,7 @@ function resolveFixtureMethodResult(methodName, definition, args) {
13306
13803
  return Promise.resolve(null);
13307
13804
  }
13308
13805
  function createFixtureService(definition) {
13309
- const methods = isPlainObject3(definition) ? definition : {};
13806
+ const methods = isPlainObject4(definition) ? definition : {};
13310
13807
  return new Proxy(
13311
13808
  {},
13312
13809
  {
@@ -13321,8 +13818,8 @@ function createFixtureService(definition) {
13321
13818
  );
13322
13819
  }
13323
13820
  function resolveFixturePath(commandPath) {
13324
- const parsed = path13.parse(commandPath);
13325
- return path13.join(parsed.dir, `${parsed.name}.fixture.json`);
13821
+ const parsed = path14.parse(commandPath);
13822
+ return path14.join(parsed.dir, `${parsed.name}.fixture.json`);
13326
13823
  }
13327
13824
  function selectFixtureScenario(scenarios, selector, fixturePath) {
13328
13825
  if (isNumericFixtureSelector(selector)) {
@@ -13404,7 +13901,7 @@ async function resolveFixtureRuntime(command, services, requirementOptions) {
13404
13901
  };
13405
13902
  }
13406
13903
  const scenario = await loadFixtureScenario(command, selector);
13407
- const scenarioServices = isPlainObject3(scenario.services) ? scenario.services : {};
13904
+ const scenarioServices = isPlainObject4(scenario.services) ? scenario.services : {};
13408
13905
  const customServiceNames = /* @__PURE__ */ new Set([
13409
13906
  ...Object.keys(services),
13410
13907
  ...Object.keys(scenarioServices).filter((name) => !RESERVED_SERVICE_NAMES.has(name))
@@ -13456,8 +13953,8 @@ function validateServices(services) {
13456
13953
  }
13457
13954
  }
13458
13955
  }
13459
- function getNestedValue(target, path23) {
13460
- return path23.reduce(
13956
+ function getNestedValue(target, path24) {
13957
+ return path24.reduce(
13461
13958
  (current, segment) => current !== null && typeof current === "object" ? current[segment] : void 0,
13462
13959
  target
13463
13960
  );
@@ -13686,7 +14183,7 @@ function finalizeDynamicValue(schema, value, displayPath, errors2) {
13686
14183
  if (itemSchema.kind !== "object") {
13687
14184
  return value;
13688
14185
  }
13689
- if (!isPlainObject3(value)) {
14186
+ if (!isPlainObject4(value)) {
13690
14187
  errors2.push({
13691
14188
  path: displayPath,
13692
14189
  message: `Invalid value for "${displayPath}". Expected indexed object entries, got ${describeReceived(value)}.`
@@ -13721,7 +14218,7 @@ function finalizeDynamicValue(schema, value, displayPath, errors2) {
13721
14218
  );
13722
14219
  }
13723
14220
  case "object": {
13724
- if (!isPlainObject3(value)) {
14221
+ if (!isPlainObject4(value)) {
13725
14222
  errors2.push({
13726
14223
  path: displayPath,
13727
14224
  message: `Invalid value for "${displayPath}". Expected an object, got ${describeReceived(value)}.`
@@ -13752,7 +14249,7 @@ function finalizeDynamicValue(schema, value, displayPath, errors2) {
13752
14249
  return result;
13753
14250
  }
13754
14251
  case "record": {
13755
- if (!isPlainObject3(value)) {
14252
+ if (!isPlainObject4(value)) {
13756
14253
  errors2.push({
13757
14254
  path: displayPath,
13758
14255
  message: `Invalid value for "${displayPath}". Expected an object, got ${describeReceived(value)}.`
@@ -14178,10 +14675,10 @@ async function executeCommand(state, services, requirementOptions, runtimeOption
14178
14675
  }
14179
14676
  }
14180
14677
  function isStringRecord(value) {
14181
- return isPlainObject3(value) && Object.values(value).every((entry) => typeof entry === "string");
14678
+ return isPlainObject4(value) && Object.values(value).every((entry) => typeof entry === "string");
14182
14679
  }
14183
14680
  function isHttpErrorLike(error3) {
14184
- if (!isPlainObject3(error3)) {
14681
+ if (!isPlainObject4(error3)) {
14185
14682
  return false;
14186
14683
  }
14187
14684
  if (error3.name !== "HttpError" || typeof error3.message !== "string") {
@@ -14189,7 +14686,7 @@ function isHttpErrorLike(error3) {
14189
14686
  }
14190
14687
  const request = error3.request;
14191
14688
  const response = error3.response;
14192
- return isPlainObject3(request) && typeof request.method === "string" && typeof request.url === "string" && isStringRecord(request.headers) && isPlainObject3(response) && typeof response.status === "number" && typeof response.statusText === "string" && isStringRecord(response.headers) && "body" in response;
14689
+ return isPlainObject4(request) && typeof request.method === "string" && typeof request.url === "string" && isStringRecord(request.headers) && isPlainObject4(response) && typeof response.status === "number" && typeof response.statusText === "string" && isStringRecord(response.headers) && "body" in response;
14193
14690
  }
14194
14691
  function hasTypedOptionalField(value, field, type2) {
14195
14692
  return !(field in value) || typeof value[field] === type2;
@@ -14198,7 +14695,7 @@ function isNonEmptyString(value) {
14198
14695
  return typeof value === "string" && value.trim().length > 0;
14199
14696
  }
14200
14697
  function isProblemDetailsLike(body) {
14201
- if (!isPlainObject3(body)) {
14698
+ if (!isPlainObject4(body)) {
14202
14699
  return false;
14203
14700
  }
14204
14701
  if (!hasTypedOptionalField(body, "type", "string")) {
@@ -14219,11 +14716,11 @@ function isProblemDetailsLike(body) {
14219
14716
  return isNonEmptyString(body.title) || isNonEmptyString(body.detail);
14220
14717
  }
14221
14718
  function isGraphQLErrorEnvelopeLike(body) {
14222
- if (!isPlainObject3(body) || !Array.isArray(body.errors) || body.errors.length === 0) {
14719
+ if (!isPlainObject4(body) || !Array.isArray(body.errors) || body.errors.length === 0) {
14223
14720
  return false;
14224
14721
  }
14225
14722
  return body.errors.every((error3) => {
14226
- if (!isPlainObject3(error3) || typeof error3.message !== "string") {
14723
+ if (!isPlainObject4(error3) || typeof error3.message !== "string") {
14227
14724
  return false;
14228
14725
  }
14229
14726
  if ("path" in error3) {
@@ -14233,7 +14730,7 @@ function isGraphQLErrorEnvelopeLike(body) {
14233
14730
  }
14234
14731
  }
14235
14732
  if ("extensions" in error3) {
14236
- if (!isPlainObject3(error3.extensions)) {
14733
+ if (!isPlainObject4(error3.extensions)) {
14237
14734
  return false;
14238
14735
  }
14239
14736
  if ("code" in error3.extensions && typeof error3.extensions.code !== "string") {
@@ -14281,23 +14778,24 @@ function formatGraphQLErrorEnvelopeBody(body) {
14281
14778
  }).join("\n\n");
14282
14779
  }
14283
14780
  function formatHttpErrorBody(body) {
14284
- if (typeof body === "string") {
14285
- return body;
14781
+ const redactedBody = redactHttpBody(body);
14782
+ if (typeof redactedBody === "string") {
14783
+ return redactedBody;
14286
14784
  }
14287
- if (isProblemDetailsLike(body)) {
14288
- return formatProblemDetailsBody(body);
14785
+ if (isProblemDetailsLike(redactedBody)) {
14786
+ return formatProblemDetailsBody(redactedBody);
14289
14787
  }
14290
- if (isGraphQLErrorEnvelopeLike(body)) {
14291
- return formatGraphQLErrorEnvelopeBody(body);
14788
+ if (isGraphQLErrorEnvelopeLike(redactedBody)) {
14789
+ return formatGraphQLErrorEnvelopeBody(redactedBody);
14292
14790
  }
14293
- const serialized = JSON.stringify(body, null, 2);
14294
- return serialized === void 0 ? String(body) : serialized;
14791
+ const serialized = JSON.stringify(redactedBody, null, 2);
14792
+ return serialized === void 0 ? String(redactedBody) : serialized;
14295
14793
  }
14296
14794
  function indentHttpErrorBlock(value) {
14297
14795
  return value.split("\n").map((line) => ` ${line}`).join("\n");
14298
14796
  }
14299
14797
  function formatHttpHeaderValue(name, value) {
14300
- return name.toLowerCase() === "authorization" ? "Bearer ****" : value;
14798
+ return redactHttpHeaderValue(name, value);
14301
14799
  }
14302
14800
  function formatHttpErrorHeaders(headers) {
14303
14801
  return Object.entries(headers).map(
@@ -14315,7 +14813,11 @@ function renderHttpError(error3, options) {
14315
14813
  if (detailed) {
14316
14814
  lines.push("", "Request headers:", ...formatHttpErrorHeaders(error3.request.headers), "");
14317
14815
  if (error3.request.body !== void 0) {
14318
- lines.push("Request body:", indentHttpErrorBlock(formatHttpErrorBody(error3.request.body)), "");
14816
+ lines.push(
14817
+ "Request body:",
14818
+ indentHttpErrorBlock(formatHttpErrorBody(error3.request.body)),
14819
+ ""
14820
+ );
14319
14821
  }
14320
14822
  }
14321
14823
  lines.push(
@@ -14608,7 +15110,8 @@ function configureCommanderSuggestionOutput(command) {
14608
15110
  }
14609
15111
  async function runCLI(roots, options = {}) {
14610
15112
  enableSourceMaps();
14611
- const root = mergeApprovalsGroup(normalizeRoots(roots, process.argv));
15113
+ const normalizedRoot = normalizeRoots(roots, process.argv);
15114
+ const root = options.approvals === false ? normalizedRoot : mergeApprovalsGroup(normalizedRoot);
14612
15115
  await resolveMcpProxies(root, { projectRoot: options.projectRoot });
14613
15116
  const casing = options.casing ?? "kebab";
14614
15117
  const services = options.services ?? {};
@@ -14720,7 +15223,7 @@ async function runCLI(roots, options = {}) {
14720
15223
  }
14721
15224
 
14722
15225
  // src/terminal-pilot.ts
14723
- import { randomUUID as randomUUID3 } from "node:crypto";
15226
+ import { randomUUID as randomUUID4 } from "node:crypto";
14724
15227
 
14725
15228
  // src/terminal-session.ts
14726
15229
  import { EventEmitter } from "node:events";
@@ -15922,7 +16425,7 @@ var TerminalPilot = class _TerminalPilot {
15922
16425
  }
15923
16426
  async newSession(opts) {
15924
16427
  const session = new TerminalSession({
15925
- id: randomUUID3(),
16428
+ id: randomUUID4(),
15926
16429
  command: opts.command,
15927
16430
  args: opts.args,
15928
16431
  cwd: opts.cwd,
@@ -16197,7 +16700,7 @@ var getSession = defineCommand({
16197
16700
 
16198
16701
  // ../agent-skill-config/src/configs.ts
16199
16702
  import os2 from "node:os";
16200
- import path14 from "node:path";
16703
+ import path15 from "node:path";
16201
16704
 
16202
16705
  // ../agent-defs/src/agents/claude-code.ts
16203
16706
  var claudeCodeAgent = {
@@ -16403,11 +16906,11 @@ function resolveAgentSupport(input, registry = agentSkillConfigs) {
16403
16906
  if (!resolvedId) {
16404
16907
  return { status: "unknown", input };
16405
16908
  }
16406
- const config = registry[resolvedId];
16407
- if (!config) {
16909
+ const config2 = registry[resolvedId];
16910
+ if (!config2) {
16408
16911
  return { status: "unsupported", input, id: resolvedId };
16409
16912
  }
16410
- return { status: "supported", input, id: resolvedId, config: { ...config } };
16913
+ return { status: "supported", input, id: resolvedId, config: { ...config2 } };
16411
16914
  }
16412
16915
  function getAgentConfig(agentId) {
16413
16916
  const support = resolveAgentSupport(agentId);
@@ -16506,7 +17009,7 @@ var templateMutation = {
16506
17009
  };
16507
17010
 
16508
17011
  // ../config-mutations/src/execution/apply-mutation.ts
16509
- import path16 from "node:path";
17012
+ import path17 from "node:path";
16510
17013
 
16511
17014
  // ../config-mutations/src/formats/json.ts
16512
17015
  import * as jsonc from "jsonc-parser";
@@ -16544,6 +17047,13 @@ function cloneConfigValue(value) {
16544
17047
  function isConfigObject(value) {
16545
17048
  return typeof value === "object" && value !== null && !Array.isArray(value);
16546
17049
  }
17050
+ function detectIndent(content) {
17051
+ const match = content.match(/^[\t ]+/m);
17052
+ if (match) {
17053
+ return match[0];
17054
+ }
17055
+ return " ";
17056
+ }
16547
17057
  function parse3(content) {
16548
17058
  if (!content || content.trim() === "") {
16549
17059
  return {};
@@ -16583,6 +17093,9 @@ function merge(base, patch) {
16583
17093
  }
16584
17094
  return result;
16585
17095
  }
17096
+ function configValuesEqual(left, right) {
17097
+ return JSON.stringify(left) === JSON.stringify(right);
17098
+ }
16586
17099
  function prune(obj, shape) {
16587
17100
  let changed = false;
16588
17101
  const result = cloneConfigObject(obj);
@@ -16619,9 +17132,56 @@ function prune(obj, shape) {
16619
17132
  }
16620
17133
  return { changed, result };
16621
17134
  }
17135
+ function modifyAtPath(content, path24, value) {
17136
+ const indent = detectIndent(content);
17137
+ const formattingOptions = {
17138
+ tabSize: indent === " " ? 1 : indent.length,
17139
+ insertSpaces: indent !== " ",
17140
+ eol: "\n"
17141
+ };
17142
+ const edits = jsonc.modify(content, path24, value, { formattingOptions });
17143
+ let result = jsonc.applyEdits(content, edits);
17144
+ if (!result.endsWith("\n")) {
17145
+ result += "\n";
17146
+ }
17147
+ return result;
17148
+ }
17149
+ function removeAtPath(content, path24) {
17150
+ return modifyAtPath(content, path24, void 0);
17151
+ }
17152
+ function serializeUpdate(content, current, next) {
17153
+ let result = content || "{}";
17154
+ result = applyObjectUpdate(result, [], current, next);
17155
+ if (!result.endsWith("\n")) {
17156
+ result += "\n";
17157
+ }
17158
+ return result;
17159
+ }
17160
+ function applyObjectUpdate(content, path24, current, next) {
17161
+ let result = content;
17162
+ for (const key2 of Object.keys(current)) {
17163
+ if (!hasConfigEntry(next, key2)) {
17164
+ result = removeAtPath(result, [...path24, key2]);
17165
+ }
17166
+ }
17167
+ for (const [key2, nextValue] of Object.entries(next)) {
17168
+ const nextPath = [...path24, key2];
17169
+ const hasCurrent = hasConfigEntry(current, key2);
17170
+ const currentValue = hasCurrent ? current[key2] : void 0;
17171
+ if (hasCurrent && isConfigObject(currentValue) && isConfigObject(nextValue)) {
17172
+ result = applyObjectUpdate(result, nextPath, currentValue, nextValue);
17173
+ continue;
17174
+ }
17175
+ if (!hasCurrent || !configValuesEqual(currentValue, nextValue)) {
17176
+ result = modifyAtPath(result, nextPath, nextValue);
17177
+ }
17178
+ }
17179
+ return result;
17180
+ }
16622
17181
  var jsonFormat = {
16623
17182
  parse: parse3,
16624
17183
  serialize,
17184
+ serializeUpdate,
16625
17185
  merge,
16626
17186
  prune
16627
17187
  };
@@ -16805,20 +17365,20 @@ function getConfigFormat(pathOrFormat) {
16805
17365
  }
16806
17366
  return formatRegistry[formatName];
16807
17367
  }
16808
- function detectFormat(path23) {
16809
- const ext = getExtension(path23);
17368
+ function detectFormat(path24) {
17369
+ const ext = getExtension(path24);
16810
17370
  return extensionMap[ext];
16811
17371
  }
16812
- function getExtension(path23) {
16813
- const lastDot = path23.lastIndexOf(".");
17372
+ function getExtension(path24) {
17373
+ const lastDot = path24.lastIndexOf(".");
16814
17374
  if (lastDot === -1) {
16815
17375
  return "";
16816
17376
  }
16817
- return path23.slice(lastDot).toLowerCase();
17377
+ return path24.slice(lastDot).toLowerCase();
16818
17378
  }
16819
17379
 
16820
17380
  // ../config-mutations/src/execution/path-utils.ts
16821
- import path15 from "node:path";
17381
+ import path16 from "node:path";
16822
17382
  function expandHome(targetPath, homeDir) {
16823
17383
  if (!targetPath?.startsWith("~")) {
16824
17384
  return targetPath;
@@ -16835,7 +17395,7 @@ function expandHome(targetPath, homeDir) {
16835
17395
  remainder = remainder.slice(1);
16836
17396
  }
16837
17397
  }
16838
- return remainder.length === 0 ? homeDir : path15.join(homeDir, remainder);
17398
+ return remainder.length === 0 ? homeDir : path16.join(homeDir, remainder);
16839
17399
  }
16840
17400
  function validateHomePath(targetPath) {
16841
17401
  if (typeof targetPath !== "string" || targetPath.length === 0) {
@@ -16850,21 +17410,21 @@ function validateHomePath(targetPath) {
16850
17410
  function resolvePath(rawPath, homeDir, pathMapper) {
16851
17411
  validateHomePath(rawPath);
16852
17412
  const expanded = expandHome(rawPath, homeDir);
16853
- const canonicalHome = path15.resolve(homeDir);
16854
- const canonicalExpanded = path15.resolve(expanded);
16855
- const relative = path15.relative(canonicalHome, canonicalExpanded);
16856
- if (relative === ".." || relative.startsWith(`..${path15.sep}`) || path15.isAbsolute(relative)) {
17413
+ const canonicalHome = path16.resolve(homeDir);
17414
+ const canonicalExpanded = path16.resolve(expanded);
17415
+ const relative = path16.relative(canonicalHome, canonicalExpanded);
17416
+ if (relative === ".." || relative.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative)) {
16857
17417
  throw new Error(`Target path resolves outside home directory: "${rawPath}"`);
16858
17418
  }
16859
17419
  if (!pathMapper) {
16860
17420
  return canonicalExpanded;
16861
17421
  }
16862
- const rawDirectory = path15.dirname(expanded);
17422
+ const rawDirectory = path16.dirname(expanded);
16863
17423
  const mappedDirectory = pathMapper.mapTargetDirectory({
16864
17424
  targetDirectory: rawDirectory
16865
17425
  });
16866
- const filename = path15.basename(expanded);
16867
- return filename.length === 0 ? mappedDirectory : path15.join(mappedDirectory, filename);
17426
+ const filename = path16.basename(expanded);
17427
+ return filename.length === 0 ? mappedDirectory : path16.join(mappedDirectory, filename);
16868
17428
  }
16869
17429
 
16870
17430
  // ../config-mutations/src/fs-utils.ts
@@ -16928,8 +17488,8 @@ function isAlreadyExists(error3) {
16928
17488
  return Boolean(error3 && typeof error3 === "object" && "code" in error3 && error3.code === "EEXIST");
16929
17489
  }
16930
17490
  async function assertRegularWriteTarget(context, targetPath) {
16931
- const boundary = path16.dirname(path16.resolve(context.homeDir));
16932
- let currentPath = path16.resolve(targetPath);
17491
+ const boundary = path17.dirname(path17.resolve(context.homeDir));
17492
+ let currentPath = path17.resolve(targetPath);
16933
17493
  while (currentPath !== boundary) {
16934
17494
  try {
16935
17495
  if ((await context.fs.lstat(currentPath)).isSymbolicLink()) {
@@ -16940,7 +17500,7 @@ async function assertRegularWriteTarget(context, targetPath) {
16940
17500
  throw error3;
16941
17501
  }
16942
17502
  }
16943
- const parentPath = path16.dirname(currentPath);
17503
+ const parentPath = path17.dirname(currentPath);
16944
17504
  if (parentPath === currentPath) {
16945
17505
  return;
16946
17506
  }
@@ -17003,7 +17563,7 @@ function pruneKeysByPrefix(table, prefix) {
17003
17563
  const result = {};
17004
17564
  for (const [key2, value] of Object.entries(table)) {
17005
17565
  if (!key2.startsWith(prefix)) {
17006
- result[key2] = value;
17566
+ setConfigEntry(result, key2, value);
17007
17567
  }
17008
17568
  }
17009
17569
  return result;
@@ -17012,28 +17572,43 @@ function isConfigObject4(value) {
17012
17572
  return typeof value === "object" && value !== null && !Array.isArray(value);
17013
17573
  }
17014
17574
  function mergeWithPruneByPrefix(base, patch, pruneByPrefix) {
17015
- const result = { ...base };
17575
+ const result = cloneConfigObject(base);
17016
17576
  const prefixMap = pruneByPrefix ?? {};
17017
17577
  for (const [key2, value] of Object.entries(patch)) {
17578
+ if (value === void 0) {
17579
+ continue;
17580
+ }
17018
17581
  const current = result[key2];
17019
17582
  const prefix = prefixMap[key2];
17020
17583
  if (isConfigObject4(current) && isConfigObject4(value)) {
17021
17584
  if (prefix) {
17022
17585
  const pruned = pruneKeysByPrefix(current, prefix);
17023
- result[key2] = { ...pruned, ...value };
17586
+ setConfigEntry(result, key2, mergePrunedConfigObject(pruned, value));
17024
17587
  } else {
17025
- result[key2] = mergeWithPruneByPrefix(
17026
- current,
17027
- value,
17028
- prefixMap
17029
- );
17588
+ setConfigEntry(result, key2, mergeWithPruneByPrefix(current, value, prefixMap));
17030
17589
  }
17031
17590
  continue;
17032
17591
  }
17033
- result[key2] = value;
17592
+ setConfigEntry(result, key2, value);
17034
17593
  }
17035
17594
  return result;
17036
17595
  }
17596
+ function mergePrunedConfigObject(base, patch) {
17597
+ const result = cloneConfigObject(base);
17598
+ for (const [key2, value] of Object.entries(patch)) {
17599
+ if (value === void 0) {
17600
+ continue;
17601
+ }
17602
+ setConfigEntry(result, key2, value);
17603
+ }
17604
+ return result;
17605
+ }
17606
+ function serializeConfigUpdate(format, rawContent, current, next) {
17607
+ if (rawContent !== null && format.serializeUpdate) {
17608
+ return format.serializeUpdate(rawContent, current, next);
17609
+ }
17610
+ return format.serialize(next);
17611
+ }
17037
17612
  async function applyMutation(mutation, context, options) {
17038
17613
  switch (mutation.kind) {
17039
17614
  case "ensureDirectory":
@@ -17346,6 +17921,7 @@ async function applyConfigMerge(mutation, context, options) {
17346
17921
  }
17347
17922
  const format = getConfigFormat(formatName);
17348
17923
  const rawContent = await readFileIfExists(context.fs, targetPath);
17924
+ let preserveContent = rawContent;
17349
17925
  let current;
17350
17926
  try {
17351
17927
  current = rawContent === null ? {} : format.parse(rawContent);
@@ -17354,6 +17930,7 @@ async function applyConfigMerge(mutation, context, options) {
17354
17930
  await backupInvalidDocument(context, targetPath, rawContent);
17355
17931
  }
17356
17932
  current = {};
17933
+ preserveContent = null;
17357
17934
  }
17358
17935
  const value = resolveValue(mutation.value, options);
17359
17936
  let merged;
@@ -17362,7 +17939,7 @@ async function applyConfigMerge(mutation, context, options) {
17362
17939
  } else {
17363
17940
  merged = format.merge(current, value);
17364
17941
  }
17365
- const serialized = format.serialize(merged);
17942
+ const serialized = serializeConfigUpdate(format, preserveContent, current, merged);
17366
17943
  const changed = serialized !== rawContent;
17367
17944
  if (changed && !context.dryRun) {
17368
17945
  await writeAtomically2(context, targetPath, serialized);
@@ -17430,7 +18007,7 @@ async function applyConfigPrune(mutation, context, options) {
17430
18007
  details
17431
18008
  };
17432
18009
  }
17433
- const serialized = format.serialize(result);
18010
+ const serialized = serializeConfigUpdate(format, rawContent, current, result);
17434
18011
  if (!context.dryRun) {
17435
18012
  await writeAtomically2(context, targetPath, serialized);
17436
18013
  }
@@ -17455,6 +18032,7 @@ async function applyConfigTransform(mutation, context, options) {
17455
18032
  }
17456
18033
  const format = getConfigFormat(formatName);
17457
18034
  const rawContent = await readFileIfExists(context.fs, targetPath);
18035
+ let preserveContent = rawContent;
17458
18036
  let current;
17459
18037
  try {
17460
18038
  current = rawContent === null ? {} : format.parse(rawContent);
@@ -17463,6 +18041,7 @@ async function applyConfigTransform(mutation, context, options) {
17463
18041
  await backupInvalidDocument(context, targetPath, rawContent);
17464
18042
  }
17465
18043
  current = {};
18044
+ preserveContent = null;
17466
18045
  }
17467
18046
  const { content: transformed, changed } = mutation.transform(current, options);
17468
18047
  if (!changed) {
@@ -17486,7 +18065,7 @@ async function applyConfigTransform(mutation, context, options) {
17486
18065
  details
17487
18066
  };
17488
18067
  }
17489
- const serialized = format.serialize(transformed);
18068
+ const serialized = serializeConfigUpdate(format, preserveContent, current, transformed);
17490
18069
  if (!context.dryRun) {
17491
18070
  await writeAtomically2(context, targetPath, serialized);
17492
18071
  }
@@ -17628,7 +18207,7 @@ async function executeMutation(mutation, context, options) {
17628
18207
 
17629
18208
  // ../agent-skill-config/src/templates.ts
17630
18209
  import { readFile as readFile5, stat } from "node:fs/promises";
17631
- import path17 from "node:path";
18210
+ import path18 from "node:path";
17632
18211
  import { fileURLToPath as fileURLToPath3 } from "node:url";
17633
18212
 
17634
18213
  // ../agent-skill-config/src/apply.ts
@@ -17663,14 +18242,14 @@ async function installSkill(agentId, skill, options) {
17663
18242
  throw new UnsupportedAgentError(agentId);
17664
18243
  }
17665
18244
  const scope = options.scope ?? "local";
17666
- const config = support.config;
18245
+ const config2 = support.config;
17667
18246
  if (skill.name.length === 0 || skill.name === "." || skill.name === ".." || skill.name.includes("/") || skill.name.includes("\\") || skill.name.includes("\n") || skill.name.includes("\r")) {
17668
18247
  throw new Error(`Invalid skill name: ${skill.name}`);
17669
18248
  }
17670
- const skillDir = scope === "global" ? config.globalSkillDir : toHomeRelative(config.localSkillDir);
18249
+ const skillDir = scope === "global" ? config2.globalSkillDir : toHomeRelative(config2.localSkillDir);
17671
18250
  const skillFolderPath = `${skillDir}/${skill.name}`;
17672
18251
  const skillFilePath = `${skillFolderPath}/SKILL.md`;
17673
- const displayPath = `${scope === "global" ? config.globalSkillDir : config.localSkillDir}/${skill.name}/SKILL.md`;
18252
+ const displayPath = `${scope === "global" ? config2.globalSkillDir : config2.localSkillDir}/${skill.name}/SKILL.md`;
17674
18253
  const absoluteSkillPath = `${scope === "global" ? options.homeDir : options.cwd}/${skillFilePath.slice(2)}`;
17675
18254
  if (await pathExists2(options.fs, absoluteSkillPath)) {
17676
18255
  throw new Error(`Skill already exists: ${displayPath}`);
@@ -17705,21 +18284,21 @@ async function installSkill(agentId, skill, options) {
17705
18284
 
17706
18285
  // ../agent-skill-config/src/resolve-skill-reference.ts
17707
18286
  import { statSync as statSync2 } from "node:fs";
17708
- import path18 from "node:path";
18287
+ import path19 from "node:path";
17709
18288
 
17710
18289
  // ../agent-skill-config/src/git-exclude.ts
17711
18290
  import { execFileSync } from "node:child_process";
17712
18291
  import * as fs2 from "node:fs";
17713
- import path19 from "node:path";
18292
+ import path20 from "node:path";
17714
18293
 
17715
18294
  // ../agent-skill-config/src/bridge-active-skills.ts
17716
18295
  import * as fs3 from "node:fs";
17717
- import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
17718
- import path20 from "node:path";
18296
+ import { createHash as createHash4, randomUUID as randomUUID5 } from "node:crypto";
18297
+ import path21 from "node:path";
17719
18298
 
17720
18299
  // src/commands/installer.ts
17721
18300
  import os3 from "node:os";
17722
- import path21 from "node:path";
18301
+ import path22 from "node:path";
17723
18302
  import * as nodeFs2 from "node:fs/promises";
17724
18303
  import { readFile as readFile6 } from "node:fs/promises";
17725
18304
  var DEFAULT_INSTALL_AGENT = "claude-code";
@@ -17786,28 +18365,28 @@ function resolveHomeRelativePath(targetPath, homeDir) {
17786
18365
  return homeDir;
17787
18366
  }
17788
18367
  if (targetPath.startsWith("~/")) {
17789
- return path21.join(homeDir, targetPath.slice(2));
18368
+ return path22.join(homeDir, targetPath.slice(2));
17790
18369
  }
17791
18370
  return targetPath;
17792
18371
  }
17793
18372
  function getSkillFolderWithHome(agent, scope, cwd, homeDir) {
17794
- const config = getAgentConfig(agent);
17795
- if (!config) {
18373
+ const config2 = getAgentConfig(agent);
18374
+ if (!config2) {
17796
18375
  throwUnsupportedAgent(agent);
17797
18376
  }
17798
18377
  return {
17799
- displayPath: path21.join(
17800
- scope === "global" ? config.globalSkillDir : config.localSkillDir,
18378
+ displayPath: path22.join(
18379
+ scope === "global" ? config2.globalSkillDir : config2.localSkillDir,
17801
18380
  TERMINAL_PILOT_SKILL_NAME
17802
18381
  ),
17803
- fullPath: path21.join(
17804
- scope === "global" ? resolveHomeRelativePath(config.globalSkillDir, homeDir) : path21.resolve(cwd, config.localSkillDir),
18382
+ fullPath: path22.join(
18383
+ scope === "global" ? resolveHomeRelativePath(config2.globalSkillDir, homeDir) : path22.resolve(cwd, config2.localSkillDir),
17805
18384
  TERMINAL_PILOT_SKILL_NAME
17806
18385
  )
17807
18386
  };
17808
18387
  }
17809
18388
  async function assertNoSymbolicLinkPath(fs4, targetPath) {
17810
- const rootPath = path21.parse(targetPath).root;
18389
+ const rootPath = path22.parse(targetPath).root;
17811
18390
  let currentPath = targetPath;
17812
18391
  while (currentPath !== rootPath) {
17813
18392
  try {
@@ -17819,7 +18398,7 @@ async function assertNoSymbolicLinkPath(fs4, targetPath) {
17819
18398
  throw error3;
17820
18399
  }
17821
18400
  }
17822
- currentPath = path21.dirname(currentPath);
18401
+ currentPath = path22.dirname(currentPath);
17823
18402
  }
17824
18403
  }
17825
18404
 
@@ -17958,7 +18537,7 @@ var resize = defineCommand({
17958
18537
  });
17959
18538
 
17960
18539
  // ../terminal-png/src/index.ts
17961
- import { randomUUID as randomUUID5 } from "node:crypto";
18540
+ import { randomUUID as randomUUID6 } from "node:crypto";
17962
18541
  import { rename as rename4, rm, writeFile as writeFile6 } from "node:fs/promises";
17963
18542
 
17964
18543
  // ../terminal-png/src/ansi-parser.ts
@@ -18898,7 +19477,7 @@ async function renderTerminalPng(ansiText, options = {}) {
18898
19477
  });
18899
19478
  const png = renderPng(svg);
18900
19479
  if (options.output) {
18901
- const temporaryPath = `${options.output}.${randomUUID5()}.tmp`;
19480
+ const temporaryPath = `${options.output}.${randomUUID6()}.tmp`;
18902
19481
  try {
18903
19482
  await writeFile6(temporaryPath, png, { flag: "wx" });
18904
19483
  await rename4(temporaryPath, options.output);
@@ -18975,7 +19554,7 @@ var type = defineCommand({
18975
19554
  });
18976
19555
 
18977
19556
  // src/commands/uninstall.ts
18978
- import { randomUUID as randomUUID6 } from "node:crypto";
19557
+ import { randomUUID as randomUUID7 } from "node:crypto";
18979
19558
  var params14 = S.Object({
18980
19559
  agent: S.Enum(installableAgents, {
18981
19560
  description: "Agent to uninstall terminal-pilot from",
@@ -19011,7 +19590,7 @@ var uninstall = defineCommand({
19011
19590
  if (!await folderExists(services.fs, skill.fullPath)) {
19012
19591
  continue;
19013
19592
  }
19014
- const stagingPath = `${skill.fullPath}.removing-${randomUUID6()}`;
19593
+ const stagingPath = `${skill.fullPath}.removing-${randomUUID7()}`;
19015
19594
  await services.fs.rename(skill.fullPath, stagingPath);
19016
19595
  staged.push({ ...skill, stagingPath });
19017
19596
  }
@@ -19118,6 +19697,7 @@ function createTerminalPilotGroup() {
19118
19697
  var terminalPilotGroup = Object.freeze(createTerminalPilotGroup());
19119
19698
 
19120
19699
  // src/cli.ts
19700
+ configureTheme({ brand: "green", label: "Terminal Pilot" });
19121
19701
  function normalizeArgv(argv) {
19122
19702
  if (argv.includes("--json") && !argv.some((argument) => argument === "--output" || argument.startsWith("--output="))) {
19123
19703
  return argv.flatMap((argument) => argument === "--json" ? ["--output", "json"] : [argument]);
@@ -19141,8 +19721,8 @@ async function isDirectExecution(argv) {
19141
19721
  try {
19142
19722
  const modulePath = fileURLToPath5(import.meta.url);
19143
19723
  const [resolvedEntryPoint, resolvedModulePath] = await Promise.all([
19144
- realpath2(path22.resolve(entryPoint)),
19145
- realpath2(modulePath)
19724
+ realpath3(path23.resolve(entryPoint)),
19725
+ realpath3(modulePath)
19146
19726
  ]);
19147
19727
  return resolvedEntryPoint === resolvedModulePath;
19148
19728
  } catch {