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
@@ -8,7 +8,7 @@ var __export = (target, all) => {
8
8
  import assert from "node:assert/strict";
9
9
  import { rm as rm2 } from "node:fs/promises";
10
10
  import os4 from "node:os";
11
- import path23 from "node:path";
11
+ import path24 from "node:path";
12
12
  import { fileURLToPath as fileURLToPath6 } from "node:url";
13
13
 
14
14
  // src/ansi.ts
@@ -85,13 +85,13 @@ function consumeTerminatedString(input, index, allowBellTerminator) {
85
85
  }
86
86
 
87
87
  // src/cli.ts
88
- import { realpath as realpath2 } from "node:fs/promises";
89
- import path22 from "node:path";
88
+ import { realpath as realpath3 } from "node:fs/promises";
89
+ import path23 from "node:path";
90
90
  import { fileURLToPath as fileURLToPath5 } from "node:url";
91
91
 
92
92
  // ../toolcraft/src/cli.ts
93
93
  import { access as access2, lstat as lstat3, readFile as readFile4, rename as rename3, unlink as unlink2, writeFile as writeFile5 } from "node:fs/promises";
94
- import path13 from "node:path";
94
+ import path14 from "node:path";
95
95
  import {
96
96
  Command as CommanderCommand,
97
97
  CommanderError as CommanderError2,
@@ -99,7 +99,7 @@ import {
99
99
  Option
100
100
  } from "commander";
101
101
 
102
- // ../design-system/src/internal/color-support.ts
102
+ // ../toolcraft-design/src/internal/color-support.ts
103
103
  function supportsColor(env = process.env, stream = process.stdout) {
104
104
  if (env.FORCE_COLOR !== void 0 && env.FORCE_COLOR !== "0") {
105
105
  return true;
@@ -113,7 +113,7 @@ function supportsColor(env = process.env, stream = process.stdout) {
113
113
  return typeof env.TERM === "string" && env.TERM.length > 0 && env.TERM !== "dumb";
114
114
  }
115
115
 
116
- // ../design-system/src/components/color.ts
116
+ // ../toolcraft-design/src/components/color.ts
117
117
  var reset = "\x1B[0m";
118
118
  var ansiStyles = {
119
119
  reset: { open: reset },
@@ -215,41 +215,135 @@ function createColor(styles = []) {
215
215
  }
216
216
  var color = createColor();
217
217
 
218
- // ../design-system/src/tokens/colors.ts
219
- var dark = {
220
- header: (text5) => color.magentaBright.bold(text5),
221
- divider: (text5) => color.dim(text5),
222
- prompt: (text5) => color.cyan(text5),
223
- number: (text5) => color.cyanBright(text5),
224
- intro: (text5) => color.bgMagenta.white(` Poe - ${text5} `),
225
- resolvedSymbol: color.magenta("\u25C7"),
226
- errorSymbol: color.red("\u25A0"),
227
- accent: (text5) => color.cyan(text5),
228
- muted: (text5) => color.dim(text5),
229
- success: (text5) => color.green(text5),
230
- warning: (text5) => color.yellow(text5),
231
- error: (text5) => color.red(text5),
232
- info: (text5) => color.magenta(text5),
233
- badge: (text5) => color.bgYellow.black(` ${text5} `)
218
+ // ../toolcraft-design/src/tokens/brand.ts
219
+ var brands = {
220
+ purple: { name: "purple", primary: "#a200ff" },
221
+ blue: { name: "blue", primary: "#2f6fed" },
222
+ green: { name: "green", primary: "#1f9d57" }
234
223
  };
235
- var light = {
236
- header: (text5) => color.hex("#a200ff").bold(text5),
237
- divider: (text5) => color.hex("#666666")(text5),
238
- prompt: (text5) => color.hex("#006699").bold(text5),
239
- number: (text5) => color.hex("#0077cc").bold(text5),
240
- intro: (text5) => color.bgHex("#a200ff").white(` Poe - ${text5} `),
241
- resolvedSymbol: color.hex("#a200ff")("\u25C7"),
242
- errorSymbol: color.hex("#cc0000")("\u25A0"),
243
- accent: (text5) => color.hex("#006699").bold(text5),
244
- muted: (text5) => color.hex("#666666")(text5),
245
- success: (text5) => color.hex("#008800")(text5),
246
- warning: (text5) => color.hex("#cc6600")(text5),
247
- error: (text5) => color.hex("#cc0000")(text5),
248
- info: (text5) => color.hex("#a200ff")(text5),
249
- badge: (text5) => color.bgHex("#cc6600").white(` ${text5} `)
224
+
225
+ // ../toolcraft-design/src/internal/theme-state.ts
226
+ var defaults = {
227
+ brand: "purple",
228
+ label: "Poe"
250
229
  };
230
+ var config = { ...defaults };
231
+ var revision = 0;
232
+ var brandConfigured = false;
233
+ function configureTheme(patch) {
234
+ if (patch.brand !== void 0 && !Object.hasOwn(brands, patch.brand)) {
235
+ throw new Error(`Unknown brand: ${patch.brand}`);
236
+ }
237
+ config = {
238
+ brand: patch.brand ?? config.brand,
239
+ label: patch.label ?? config.label
240
+ };
241
+ if (patch.brand !== void 0) {
242
+ brandConfigured = true;
243
+ }
244
+ revision += 1;
245
+ }
246
+ function getThemeConfig() {
247
+ return { ...config };
248
+ }
249
+ function getThemeRevision() {
250
+ return revision;
251
+ }
252
+ function isThemeBrandConfigured() {
253
+ return brandConfigured;
254
+ }
255
+
256
+ // ../toolcraft-design/src/tokens/colors.ts
257
+ var brand = brands.purple.primary;
258
+ function withStyles(palette, styles) {
259
+ return Object.defineProperty(palette, "styles", {
260
+ value: styles,
261
+ enumerable: false
262
+ });
263
+ }
264
+ function brandColor(activeBrand, purple) {
265
+ return activeBrand.name === "purple" ? purple : color.hex(activeBrand.primary);
266
+ }
267
+ function brandBackground(activeBrand, purple) {
268
+ return activeBrand.name === "purple" ? purple : color.bgHex(activeBrand.primary);
269
+ }
270
+ function createPalette(activeBrand, mode) {
271
+ const isPurple = activeBrand.name === "purple";
272
+ if (mode === "light") {
273
+ const active2 = color.hex(activeBrand.primary);
274
+ const prompt2 = isPurple ? color.hex("#006699") : active2;
275
+ const number2 = isPurple ? color.hex("#0077cc") : active2;
276
+ return withStyles(
277
+ {
278
+ header: (text5) => active2.bold(text5),
279
+ divider: (text5) => color.hex("#666666")(text5),
280
+ prompt: (text5) => prompt2.bold(text5),
281
+ number: (text5) => number2.bold(text5),
282
+ intro: (text5) => color.bgHex(activeBrand.primary).white(` ${getThemeConfig().label} - ${text5} `),
283
+ get resolvedSymbol() {
284
+ return active2("\u25C7");
285
+ },
286
+ get errorSymbol() {
287
+ return color.hex("#cc0000")("\u25A0");
288
+ },
289
+ accent: (text5) => prompt2.bold(text5),
290
+ muted: (text5) => color.hex("#666666")(text5),
291
+ success: (text5) => color.hex("#008800")(text5),
292
+ warning: (text5) => color.hex("#cc6600")(text5),
293
+ error: (text5) => color.hex("#cc0000")(text5),
294
+ info: (text5) => active2(text5),
295
+ badge: (text5) => color.bgHex("#cc6600").white(` ${text5} `)
296
+ },
297
+ {
298
+ accent: { fg: isPurple ? "#006699" : activeBrand.primary, bold: true },
299
+ muted: { fg: "#666666" },
300
+ success: { fg: "#008800" },
301
+ warning: { fg: "#cc6600" },
302
+ error: { fg: "#cc0000" },
303
+ info: { fg: activeBrand.primary }
304
+ }
305
+ );
306
+ }
307
+ const active = brandColor(activeBrand, color.magenta);
308
+ const activeBright = brandColor(activeBrand, color.magentaBright);
309
+ const activeBackground = brandBackground(activeBrand, color.bgMagenta);
310
+ const prompt = isPurple ? color.cyan : active;
311
+ const number = isPurple ? color.cyanBright : active;
312
+ return withStyles(
313
+ {
314
+ header: (text5) => activeBright.bold(text5),
315
+ divider: (text5) => color.dim(text5),
316
+ prompt: (text5) => prompt(text5),
317
+ number: (text5) => number(text5),
318
+ intro: (text5) => activeBackground.white(` ${getThemeConfig().label} - ${text5} `),
319
+ get resolvedSymbol() {
320
+ return active("\u25C7");
321
+ },
322
+ get errorSymbol() {
323
+ return color.red("\u25A0");
324
+ },
325
+ accent: (text5) => prompt(text5),
326
+ muted: (text5) => color.dim(text5),
327
+ success: (text5) => color.green(text5),
328
+ warning: (text5) => color.yellow(text5),
329
+ error: (text5) => color.red(text5),
330
+ info: (text5) => active(text5),
331
+ badge: (text5) => color.bgYellow.black(` ${text5} `)
332
+ },
333
+ {
334
+ accent: { fg: isPurple ? "cyan" : activeBrand.primary, bold: true },
335
+ muted: { dim: true },
336
+ success: { fg: "green" },
337
+ warning: { fg: "yellow" },
338
+ error: { fg: "red" },
339
+ info: { fg: isPurple ? "magenta" : activeBrand.primary }
340
+ }
341
+ );
342
+ }
343
+ var dark = createPalette(brands.purple, "dark");
344
+ var light = createPalette(brands.purple, "light");
251
345
 
252
- // ../design-system/src/tokens/typography.ts
346
+ // ../toolcraft-design/src/tokens/typography.ts
253
347
  var typography = {
254
348
  bold: (text5) => color.bold(text5),
255
349
  dim: (text5) => color.dim(text5),
@@ -258,14 +352,14 @@ var typography = {
258
352
  strikethrough: (text5) => color.strikethrough(text5)
259
353
  };
260
354
 
261
- // ../design-system/src/tokens/widths.ts
355
+ // ../toolcraft-design/src/tokens/widths.ts
262
356
  var widths = {
263
357
  header: 60,
264
358
  helpColumn: 24,
265
359
  maxLine: 80
266
360
  };
267
361
 
268
- // ../design-system/src/internal/output-format.ts
362
+ // ../toolcraft-design/src/internal/output-format.ts
269
363
  import { AsyncLocalStorage } from "node:async_hooks";
270
364
  var VALID_FORMATS = /* @__PURE__ */ new Set(["terminal", "markdown", "json"]);
271
365
  var formatStorage = new AsyncLocalStorage();
@@ -286,7 +380,7 @@ function resetOutputFormatCache() {
286
380
  cached = void 0;
287
381
  }
288
382
 
289
- // ../design-system/src/internal/theme-detect.ts
383
+ // ../toolcraft-design/src/internal/theme-detect.ts
290
384
  function detectThemeFromEnv(env) {
291
385
  const apple = env.APPLE_INTERFACE_STYLE;
292
386
  if (typeof apple === "string") {
@@ -323,17 +417,30 @@ function resolveThemeName(env = process.env) {
323
417
  }
324
418
  return "dark";
325
419
  }
326
- var cachedTheme;
420
+ var themeCache = /* @__PURE__ */ new Map();
421
+ var cachedRevision = -1;
327
422
  function getTheme(env) {
423
+ const themeName = resolveThemeName(env);
424
+ const config2 = getThemeConfig();
425
+ const requestedBrand = env?.POE_BRAND?.toLowerCase();
426
+ const activeBrandName = !isThemeBrandConfigured() && requestedBrand && Object.hasOwn(brands, requestedBrand) ? requestedBrand : config2.brand;
427
+ const revision2 = getThemeRevision();
428
+ if (revision2 !== cachedRevision) {
429
+ themeCache.clear();
430
+ cachedRevision = revision2;
431
+ }
432
+ const cacheKey = `${activeBrandName}:${themeName}`;
433
+ const cachedTheme = themeCache.get(cacheKey);
328
434
  if (cachedTheme) {
329
435
  return cachedTheme;
330
436
  }
331
- const themeName = resolveThemeName(env);
332
- cachedTheme = themeName === "light" ? light : dark;
333
- return cachedTheme;
437
+ const activeBrand = brands[activeBrandName];
438
+ const theme = activeBrandName === "purple" ? themeName === "light" ? light : dark : createPalette(activeBrand, themeName);
439
+ themeCache.set(cacheKey, theme);
440
+ return theme;
334
441
  }
335
442
 
336
- // ../design-system/src/components/text.ts
443
+ // ../toolcraft-design/src/components/text.ts
337
444
  function renderMarkdownInline(content) {
338
445
  return content.replaceAll("\r\n", " ").replaceAll("\n", " ").replaceAll("\r", " ");
339
446
  }
@@ -449,7 +556,7 @@ var text = {
449
556
  }
450
557
  };
451
558
 
452
- // ../design-system/src/components/symbols.ts
559
+ // ../toolcraft-design/src/components/symbols.ts
453
560
  var symbols = {
454
561
  get info() {
455
562
  const format = resolveOutputFormat();
@@ -503,12 +610,12 @@ var symbols = {
503
610
  }
504
611
  };
505
612
 
506
- // ../design-system/src/internal/strip-ansi.ts
613
+ // ../toolcraft-design/src/internal/strip-ansi.ts
507
614
  function stripAnsi2(value) {
508
615
  return value.replace(/\u001b\[[0-9;]*m/g, "");
509
616
  }
510
617
 
511
- // ../design-system/src/prompts/primitives/log.ts
618
+ // ../toolcraft-design/src/prompts/primitives/log.ts
512
619
  function renderMarkdownInline2(value) {
513
620
  return stripAnsi2(value).replaceAll("\r\n", " ").replaceAll("\n", " ").replaceAll("\r", " ");
514
621
  }
@@ -635,7 +742,7 @@ var log = {
635
742
  error
636
743
  };
637
744
 
638
- // ../design-system/src/components/logger.ts
745
+ // ../toolcraft-design/src/components/logger.ts
639
746
  function createLogger(emitter) {
640
747
  const emit = (level, message2) => {
641
748
  if (emitter) {
@@ -696,7 +803,7 @@ function createLogger(emitter) {
696
803
  }
697
804
  var logger = createLogger();
698
805
 
699
- // ../design-system/src/components/help-formatter.ts
806
+ // ../toolcraft-design/src/components/help-formatter.ts
700
807
  var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
701
808
  function normalizeInline(value) {
702
809
  return value.replaceAll("\r\n", " ").replaceAll("\n", " ").replaceAll("\r", " ");
@@ -872,7 +979,7 @@ function formatOptionList(options) {
872
979
  });
873
980
  }
874
981
 
875
- // ../design-system/src/components/help-formatter-plain.ts
982
+ // ../toolcraft-design/src/components/help-formatter-plain.ts
876
983
  var help_formatter_plain_exports = {};
877
984
  __export(help_formatter_plain_exports, {
878
985
  formatColumns: () => formatColumns2,
@@ -1009,7 +1116,7 @@ function formatOptionList2(options) {
1009
1116
  });
1010
1117
  }
1011
1118
 
1012
- // ../design-system/src/components/table.ts
1119
+ // ../toolcraft-design/src/components/table.ts
1013
1120
  var reset2 = "\x1B[0m";
1014
1121
  var ellipsis = "\u2026";
1015
1122
  var graphemeSegmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
@@ -1293,7 +1400,7 @@ function renderTable(options) {
1293
1400
  }
1294
1401
  }
1295
1402
 
1296
- // ../design-system/src/components/detail-card.ts
1403
+ // ../toolcraft-design/src/components/detail-card.ts
1297
1404
  function wrap(value, width) {
1298
1405
  const lines = [];
1299
1406
  for (const paragraph of value.split("\n")) {
@@ -1356,7 +1463,8 @@ ${options.theme.muted(options.badges.map((badge) => badge[0] + badge.slice(1).to
1356
1463
  return blocks.join("\n\n");
1357
1464
  }
1358
1465
 
1359
- // ../design-system/src/components/template.ts
1466
+ // ../toolcraft-design/src/components/template.ts
1467
+ var MAX_PARTIAL_DEPTH = 100;
1360
1468
  var HTML_ESCAPE = {
1361
1469
  "&": "&",
1362
1470
  "<": "&lt;",
@@ -1368,14 +1476,27 @@ var HTML_ESCAPE = {
1368
1476
  "=": "&#x3D;"
1369
1477
  };
1370
1478
  function renderTemplate(template, view, options = {}) {
1371
- const prepared = options.yield === void 0 ? template : template.split("{{yield}}").join(options.yield);
1479
+ const prepared = options.yield === void 0 ? template : resolveTemplatePartials(template, options.partials ?? {}).split("{{yield}}").join(options.yield);
1372
1480
  const tokens = parseTemplate(prepared);
1373
- const escape = options.escape === "none" ? String : escapeHtml;
1374
- const preserveMissing = options.yield !== void 0 && options.escape === "none";
1375
- return renderTokens(tokens, { view }, prepared, escape, preserveMissing);
1481
+ validatePartialReferences(tokens, options.partials ?? {}, []);
1482
+ if (options.validate === true) {
1483
+ const expanded = resolveTemplatePartials(prepared, options.partials ?? {});
1484
+ validateVariables(parseTemplate(expanded), { view });
1485
+ }
1486
+ const state = {
1487
+ escape: options.escape === "none" ? String : escapeHtml,
1488
+ partials: options.partials ?? {},
1489
+ partialStack: [],
1490
+ preserveMissing: options.yield !== void 0 && options.escape === "none",
1491
+ validate: options.validate === true
1492
+ };
1493
+ return renderTokens(tokens, { view }, prepared, state);
1494
+ }
1495
+ function resolveTemplatePartials(template, partials) {
1496
+ return expandTemplatePartials(template, partials, []);
1376
1497
  }
1377
- function renderTemplateInContext(template, context, escape, preserveMissing) {
1378
- return renderTokens(parseTemplate(template), context, template, escape, preserveMissing);
1498
+ function renderTemplateInContext(template, context, state) {
1499
+ return renderTokens(parseTemplate(template), context, template, state);
1379
1500
  }
1380
1501
  function parseTemplate(template) {
1381
1502
  const root = [];
@@ -1398,9 +1519,6 @@ function parseTemplate(template) {
1398
1519
  index = standalone?.nextIndex ?? parsed.end;
1399
1520
  continue;
1400
1521
  }
1401
- if (parsed.kind === "partial") {
1402
- throw new Error(`Partials are not supported: "${parsed.name}"`);
1403
- }
1404
1522
  if (parsed.kind === "delimiter") {
1405
1523
  throw new Error("Custom delimiters are not supported");
1406
1524
  }
@@ -1418,6 +1536,15 @@ function parseTemplate(template) {
1418
1536
  index = standalone?.nextIndex ?? parsed.end;
1419
1537
  continue;
1420
1538
  }
1539
+ if (parsed.kind === "partial") {
1540
+ tokens.push({
1541
+ type: "partial",
1542
+ name: parsed.name,
1543
+ indent: standalone === void 0 ? "" : template.slice(standalone.lineStart, open)
1544
+ });
1545
+ index = standalone?.nextIndex ?? parsed.end;
1546
+ continue;
1547
+ }
1421
1548
  if (parsed.kind === "close") {
1422
1549
  const frame2 = stack.pop();
1423
1550
  if (frame2 === void 0) {
@@ -1488,7 +1615,7 @@ function getStandalone(template, tagStart, tagEnd, kind) {
1488
1615
  }
1489
1616
  return void 0;
1490
1617
  }
1491
- function renderTokens(tokens, context, template, escape, preserveMissing) {
1618
+ function renderTokens(tokens, context, template, state) {
1492
1619
  let output = "";
1493
1620
  for (const token of tokens) {
1494
1621
  switch (token.type) {
@@ -1497,32 +1624,62 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
1497
1624
  continue;
1498
1625
  case "name":
1499
1626
  case "unescaped": {
1500
- const value = lookup(context, token.name);
1501
- if (value == null) {
1502
- if (preserveMissing) {
1627
+ const result = lookup(context, token.name);
1628
+ if (!result.hit || result.value == null) {
1629
+ if (state.validate) {
1630
+ throw new Error(`Template variable "${token.name}" not found.`);
1631
+ }
1632
+ if (state.preserveMissing) {
1503
1633
  output += token.raw;
1504
1634
  }
1505
1635
  continue;
1506
1636
  }
1507
- const rendered = String(value);
1508
- output += token.type === "name" ? escape(rendered) : rendered;
1637
+ const rendered = String(result.value);
1638
+ output += token.type === "name" ? state.escape(rendered) : rendered;
1639
+ continue;
1640
+ }
1641
+ case "partial": {
1642
+ if (!Object.hasOwn(state.partials, token.name)) {
1643
+ throw new Error(`Partial "${token.name}" not found.`);
1644
+ }
1645
+ if (state.partialStack.includes(token.name)) {
1646
+ throw new Error(
1647
+ `Circular partial reference detected: ${[...state.partialStack, token.name].join(" -> ")}.`
1648
+ );
1649
+ }
1650
+ if (state.partialStack.length >= MAX_PARTIAL_DEPTH) {
1651
+ throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
1652
+ }
1653
+ const partial = indentPartial(state.partials[token.name], token.indent);
1654
+ output += renderTokens(parseTemplate(partial), context, partial, {
1655
+ ...state,
1656
+ partialStack: [...state.partialStack, token.name]
1657
+ });
1509
1658
  continue;
1510
1659
  }
1511
1660
  case "inverted": {
1512
- const value = lookup(context, token.name);
1661
+ const result = lookup(context, token.name);
1662
+ if (!result.hit && state.validate) {
1663
+ throw new Error(`Template variable "${token.name}" not found.`);
1664
+ }
1665
+ const value = result.value;
1513
1666
  if (!value || Array.isArray(value) && value.length === 0) {
1514
- output += renderTokens(token.children, context, template, escape, preserveMissing);
1667
+ output += renderTokens(token.children, context, template, state);
1515
1668
  }
1516
1669
  continue;
1517
1670
  }
1518
1671
  case "section": {
1519
- const value = lookup(context, token.name);
1672
+ const result = lookup(context, token.name);
1673
+ if (!result.hit && state.validate) {
1674
+ throw new Error(`Template variable "${token.name}" not found.`);
1675
+ }
1676
+ const value = result.value;
1520
1677
  if (!value) {
1521
1678
  continue;
1522
1679
  }
1523
1680
  if (Array.isArray(value)) {
1524
1681
  for (const item of value) {
1525
- output += renderTokens(token.children, pushContext(context, item), template, escape, preserveMissing);
1682
+ output += renderTokens(token.children, pushContext(context, item), template, state);
1526
1683
  }
1527
1684
  continue;
1528
1685
  }
@@ -1531,7 +1688,7 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
1531
1688
  const rendered = value.call(
1532
1689
  context.view,
1533
1690
  raw,
1534
- (nextTemplate) => renderTemplateInContext(nextTemplate, context, escape, preserveMissing)
1691
+ (nextTemplate) => renderTemplateInContext(nextTemplate, context, state)
1535
1692
  );
1536
1693
  if (rendered != null) {
1537
1694
  output += String(rendered);
@@ -1539,10 +1696,10 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
1539
1696
  continue;
1540
1697
  }
1541
1698
  if (typeof value === "object" || typeof value === "string" || typeof value === "number") {
1542
- output += renderTokens(token.children, pushContext(context, value), template, escape, preserveMissing);
1699
+ output += renderTokens(token.children, pushContext(context, value), template, state);
1543
1700
  continue;
1544
1701
  }
1545
- output += renderTokens(token.children, context, template, escape, preserveMissing);
1702
+ output += renderTokens(token.children, context, template, state);
1546
1703
  }
1547
1704
  }
1548
1705
  }
@@ -1550,17 +1707,115 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
1550
1707
  }
1551
1708
  function lookup(context, name) {
1552
1709
  if (name === ".") {
1553
- return callLambda(context.view, context.view);
1710
+ return { hit: true, value: callLambda(context.view, context.view) };
1554
1711
  }
1555
1712
  let cursor = context;
1556
1713
  while (cursor !== void 0) {
1557
1714
  const result = name.includes(".") ? lookupDotted(cursor.view, name) : lookupName(cursor.view, name);
1558
1715
  if (result.hit) {
1559
- return callLambda(result.value, cursor.view);
1716
+ return { hit: true, value: callLambda(result.value, cursor.view) };
1560
1717
  }
1561
1718
  cursor = cursor.parent;
1562
1719
  }
1563
- return void 0;
1720
+ return { hit: false, value: void 0 };
1721
+ }
1722
+ function validateVariables(tokens, context) {
1723
+ for (const token of tokens) {
1724
+ if (token.type === "text" || token.type === "partial") {
1725
+ continue;
1726
+ }
1727
+ if (token.type === "name" || token.type === "unescaped") {
1728
+ if (!lookup(context, token.name).hit) {
1729
+ throw new Error(`Template variable "${token.name}" not found.`);
1730
+ }
1731
+ continue;
1732
+ }
1733
+ if (token.type !== "section" && token.type !== "inverted") {
1734
+ continue;
1735
+ }
1736
+ const result = lookup(context, token.name);
1737
+ if (!result.hit) {
1738
+ throw new Error(`Template variable "${token.name}" not found.`);
1739
+ }
1740
+ if (Array.isArray(result.value) && result.value.length > 0) {
1741
+ for (const item of result.value) {
1742
+ validateVariables(token.children, pushContext(context, item));
1743
+ }
1744
+ continue;
1745
+ }
1746
+ if (typeof result.value === "object" && result.value !== null || typeof result.value === "string" || typeof result.value === "number") {
1747
+ validateVariables(token.children, pushContext(context, result.value));
1748
+ continue;
1749
+ }
1750
+ validateVariables(token.children, context);
1751
+ }
1752
+ }
1753
+ function validatePartialReferences(tokens, partials, partialStack) {
1754
+ for (const token of tokens) {
1755
+ if (token.type === "section" || token.type === "inverted") {
1756
+ validatePartialReferences(token.children, partials, partialStack);
1757
+ continue;
1758
+ }
1759
+ if (token.type !== "partial") {
1760
+ continue;
1761
+ }
1762
+ if (!Object.hasOwn(partials, token.name)) {
1763
+ throw new Error(`Partial "${token.name}" not found.`);
1764
+ }
1765
+ if (partialStack.includes(token.name)) {
1766
+ throw new Error(
1767
+ `Circular partial reference detected: ${[...partialStack, token.name].join(" -> ")}.`
1768
+ );
1769
+ }
1770
+ if (partialStack.length >= MAX_PARTIAL_DEPTH) {
1771
+ throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
1772
+ }
1773
+ validatePartialReferences(parseTemplate(partials[token.name]), partials, [
1774
+ ...partialStack,
1775
+ token.name
1776
+ ]);
1777
+ }
1778
+ }
1779
+ function indentPartial(partial, indent) {
1780
+ if (indent === "") {
1781
+ return partial;
1782
+ }
1783
+ return partial.split("\n").map((line) => line === "" ? "" : `${indent}${line}`).join("\n");
1784
+ }
1785
+ function expandTemplatePartials(template, partials, partialStack) {
1786
+ let output = "";
1787
+ let index = 0;
1788
+ while (index < template.length) {
1789
+ const open = template.indexOf("{{", index);
1790
+ if (open === -1) {
1791
+ output += template.slice(index);
1792
+ break;
1793
+ }
1794
+ const parsed = parseTag(template, open);
1795
+ if (parsed.kind !== "partial") {
1796
+ output += template.slice(index, parsed.end);
1797
+ index = parsed.end;
1798
+ continue;
1799
+ }
1800
+ if (!Object.hasOwn(partials, parsed.name)) {
1801
+ throw new Error(`Partial "${parsed.name}" not found.`);
1802
+ }
1803
+ if (partialStack.includes(parsed.name)) {
1804
+ throw new Error(
1805
+ `Circular partial reference detected: ${[...partialStack, parsed.name].join(" -> ")}.`
1806
+ );
1807
+ }
1808
+ if (partialStack.length >= MAX_PARTIAL_DEPTH) {
1809
+ throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
1810
+ }
1811
+ const standalone = getStandalone(template, open, parsed.end, parsed.kind);
1812
+ const beforePartial = standalone === void 0 ? template.slice(index, open) : template.slice(index, standalone.lineStart);
1813
+ const indent = standalone === void 0 ? "" : template.slice(standalone.lineStart, open);
1814
+ const partial = indentPartial(partials[parsed.name], indent);
1815
+ output += beforePartial + expandTemplatePartials(partial, partials, [...partialStack, parsed.name]);
1816
+ index = standalone?.nextIndex ?? parsed.end;
1817
+ }
1818
+ return output;
1564
1819
  }
1565
1820
  function lookupName(view, name) {
1566
1821
  if (!isPropertyContainer(view) || !hasProperty(view, name)) {
@@ -1620,22 +1875,22 @@ function hasProperty(value, key2) {
1620
1875
  return Object.prototype.hasOwnProperty.call(value, key2);
1621
1876
  }
1622
1877
 
1623
- // ../design-system/src/components/browser.ts
1878
+ // ../toolcraft-design/src/components/browser.ts
1624
1879
  import { spawn } from "node:child_process";
1625
1880
  import process2 from "node:process";
1626
1881
 
1627
- // ../design-system/src/acp/writer.ts
1882
+ // ../toolcraft-design/src/acp/writer.ts
1628
1883
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
1629
1884
  var storage = new AsyncLocalStorage2();
1630
1885
 
1631
- // ../design-system/src/dashboard/terminal-width.ts
1886
+ // ../toolcraft-design/src/dashboard/terminal-width.ts
1632
1887
  var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1633
1888
 
1634
- // ../design-system/src/dashboard/terminal.ts
1889
+ // ../toolcraft-design/src/dashboard/terminal.ts
1635
1890
  import readline from "node:readline";
1636
1891
  import { PassThrough } from "node:stream";
1637
1892
 
1638
- // ../design-system/src/explorer/state.ts
1893
+ // ../toolcraft-design/src/explorer/state.ts
1639
1894
  var REGION_HEADER = 1 << 0;
1640
1895
  var REGION_LIST = 1 << 1;
1641
1896
  var REGION_DETAIL = 1 << 2;
@@ -1644,10 +1899,10 @@ var REGION_MODAL = 1 << 4;
1644
1899
  var REGION_TOAST = 1 << 5;
1645
1900
  var REGION_ALL = REGION_HEADER | REGION_LIST | REGION_DETAIL | REGION_FOOTER | REGION_MODAL | REGION_TOAST;
1646
1901
 
1647
- // ../design-system/src/prompts/index.ts
1902
+ // ../toolcraft-design/src/prompts/index.ts
1648
1903
  import * as clack from "@clack/prompts";
1649
1904
 
1650
- // ../design-system/src/prompts/primitives/cancel.ts
1905
+ // ../toolcraft-design/src/prompts/primitives/cancel.ts
1651
1906
  import { isCancel } from "@clack/prompts";
1652
1907
  function cancel(msg = "") {
1653
1908
  if (resolveOutputFormat() !== "terminal") {
@@ -1658,7 +1913,7 @@ function cancel(msg = "") {
1658
1913
  `);
1659
1914
  }
1660
1915
 
1661
- // ../design-system/src/prompts/primitives/note.ts
1916
+ // ../toolcraft-design/src/prompts/primitives/note.ts
1662
1917
  function getVisibleWidth(value) {
1663
1918
  return stripAnsi2(value).length;
1664
1919
  }
@@ -1707,10 +1962,10 @@ function note(message2, title) {
1707
1962
  `);
1708
1963
  }
1709
1964
 
1710
- // ../design-system/src/static/spinner.ts
1965
+ // ../toolcraft-design/src/static/spinner.ts
1711
1966
  var SPINNER_FRAMES = Object.freeze(["\u25D2", "\u25D0", "\u25D3", "\u25D1"]);
1712
1967
 
1713
- // ../design-system/src/prompts/index.ts
1968
+ // ../toolcraft-design/src/prompts/index.ts
1714
1969
  async function select2(opts) {
1715
1970
  return clack.select(opts);
1716
1971
  }
@@ -1753,19 +2008,19 @@ var ApprovalDeclinedError = class extends UserError {
1753
2008
  };
1754
2009
 
1755
2010
  // ../toolcraft/src/human-in-loop/config.ts
1756
- function validateHumanInLoopOnDefine(config) {
1757
- const label = Array.isArray(config.children) ? "group" : "command";
1758
- if (config.confirm === true && config.humanInLoop !== void 0 && config.humanInLoop !== null) {
1759
- throw new Error(`${label} '${config.name}': use either confirm or humanInLoop, not both`);
2011
+ function validateHumanInLoopOnDefine(config2) {
2012
+ const label = Array.isArray(config2.children) ? "group" : "command";
2013
+ if (config2.confirm === true && config2.humanInLoop !== void 0 && config2.humanInLoop !== null) {
2014
+ throw new Error(`${label} '${config2.name}': use either confirm or humanInLoop, not both`);
1760
2015
  }
1761
- if (config.humanInLoop === void 0 || config.humanInLoop === null) {
2016
+ if (config2.humanInLoop === void 0 || config2.humanInLoop === null) {
1762
2017
  return;
1763
2018
  }
1764
- if (config.humanInLoop.mode !== "sync" && config.humanInLoop.mode !== "async") {
1765
- throw new Error(`${label} '${config.name}': humanInLoop.mode must be "sync" or "async"`);
2019
+ if (config2.humanInLoop.mode !== "sync" && config2.humanInLoop.mode !== "async") {
2020
+ throw new Error(`${label} '${config2.name}': humanInLoop.mode must be "sync" or "async"`);
1766
2021
  }
1767
- if (typeof config.humanInLoop.message !== "function") {
1768
- throw new Error(`${label} '${config.name}': humanInLoop.message must be a function`);
2022
+ if (typeof config2.humanInLoop.message !== "function") {
2023
+ throw new Error(`${label} '${config2.name}': humanInLoop.message must be a function`);
1769
2024
  }
1770
2025
  }
1771
2026
  function mergeHumanInLoopFromGroup(groupHumanInLoop, childHumanInLoop) {
@@ -1841,12 +2096,12 @@ function assertValidBranches(branches, discriminator) {
1841
2096
  }
1842
2097
  }
1843
2098
  }
1844
- function OneOf(config) {
1845
- assertValidBranches(config.branches, config.discriminator);
2099
+ function OneOf(config2) {
2100
+ assertValidBranches(config2.branches, config2.discriminator);
1846
2101
  return {
1847
2102
  kind: "oneOf",
1848
- discriminator: config.discriminator,
1849
- branches: config.branches
2103
+ discriminator: config2.discriminator,
2104
+ branches: config2.branches
1850
2105
  };
1851
2106
  }
1852
2107
 
@@ -2096,22 +2351,22 @@ function cloneStringArray(values) {
2096
2351
  function cloneStringRecord(values) {
2097
2352
  return values === void 0 ? void 0 : { ...values };
2098
2353
  }
2099
- function cloneMcpServerConfig(config) {
2100
- if (config === void 0) {
2354
+ function cloneMcpServerConfig(config2) {
2355
+ if (config2 === void 0) {
2101
2356
  return void 0;
2102
2357
  }
2103
- if (config.transport === "stdio") {
2358
+ if (config2.transport === "stdio") {
2104
2359
  return {
2105
2360
  transport: "stdio",
2106
- command: config.command,
2107
- args: cloneStringArray(config.args),
2108
- env: cloneStringRecord(config.env)
2361
+ command: config2.command,
2362
+ args: cloneStringArray(config2.args),
2363
+ env: cloneStringRecord(config2.env)
2109
2364
  };
2110
2365
  }
2111
2366
  return {
2112
2367
  transport: "http",
2113
- url: config.url,
2114
- headers: cloneStringRecord(config.headers)
2368
+ url: config2.url,
2369
+ headers: cloneStringRecord(config2.headers)
2115
2370
  };
2116
2371
  }
2117
2372
  function cloneRenameMap(rename5) {
@@ -2352,57 +2607,57 @@ function resolveCommandScope(ownScope, inheritedScope) {
2352
2607
  function resolveGroupScope(ownScope, inheritedScope) {
2353
2608
  return cloneScope(ownScope ?? inheritedScope);
2354
2609
  }
2355
- function createBaseCommand(config) {
2610
+ function createBaseCommand(config2) {
2356
2611
  const command = {
2357
2612
  kind: "command",
2358
- name: config.name,
2359
- description: config.description,
2360
- aliases: [...config.aliases ?? []],
2361
- positional: [...config.positional ?? []],
2362
- params: config.params,
2363
- secrets: cloneSecrets(config.secrets),
2364
- scope: resolveCommandScope(config.scope, void 0),
2365
- confirm: config.confirm ?? false,
2366
- humanInLoop: config.humanInLoop,
2367
- requires: cloneRequires(config.requires),
2368
- handler: config.handler,
2369
- render: config.render
2613
+ name: config2.name,
2614
+ description: config2.description,
2615
+ aliases: [...config2.aliases ?? []],
2616
+ positional: [...config2.positional ?? []],
2617
+ params: config2.params,
2618
+ secrets: cloneSecrets(config2.secrets),
2619
+ scope: resolveCommandScope(config2.scope, void 0),
2620
+ confirm: config2.confirm ?? false,
2621
+ humanInLoop: config2.humanInLoop,
2622
+ requires: cloneRequires(config2.requires),
2623
+ handler: config2.handler,
2624
+ render: config2.render
2370
2625
  };
2371
2626
  Object.defineProperty(command, commandConfigSymbol, {
2372
2627
  value: {
2373
- scope: cloneScope(config.scope),
2374
- humanInLoop: config.humanInLoop,
2375
- secrets: cloneSecrets(config.secrets),
2376
- requires: cloneRequires(config.requires),
2628
+ scope: cloneScope(config2.scope),
2629
+ humanInLoop: config2.humanInLoop,
2630
+ secrets: cloneSecrets(config2.secrets),
2631
+ requires: cloneRequires(config2.requires),
2377
2632
  sourcePath: inferCommandSourcePath()
2378
2633
  }
2379
2634
  });
2380
2635
  return command;
2381
2636
  }
2382
- function createBaseGroup(config) {
2637
+ function createBaseGroup(config2) {
2383
2638
  const group = {
2384
2639
  kind: "group",
2385
- name: config.name,
2386
- description: config.description,
2387
- aliases: [...config.aliases ?? []],
2388
- scope: resolveGroupScope(config.scope, void 0),
2389
- humanInLoop: config.humanInLoop,
2390
- secrets: cloneSecrets(config.secrets),
2391
- requires: cloneRequires(config.requires),
2640
+ name: config2.name,
2641
+ description: config2.description,
2642
+ aliases: [...config2.aliases ?? []],
2643
+ scope: resolveGroupScope(config2.scope, void 0),
2644
+ humanInLoop: config2.humanInLoop,
2645
+ secrets: cloneSecrets(config2.secrets),
2646
+ requires: cloneRequires(config2.requires),
2392
2647
  children: [],
2393
2648
  default: void 0
2394
2649
  };
2395
2650
  Object.defineProperty(group, groupConfigSymbol, {
2396
2651
  value: {
2397
- mcp: cloneMcpServerConfig(config.mcp),
2398
- scope: cloneScope(config.scope),
2399
- humanInLoop: config.humanInLoop,
2400
- secrets: cloneSecrets(config.secrets),
2401
- tools: cloneStringArray(config.tools),
2402
- rename: cloneRenameMap(config.rename),
2403
- requires: cloneRequires(config.requires),
2404
- children: [...config.children],
2405
- default: config.default
2652
+ mcp: cloneMcpServerConfig(config2.mcp),
2653
+ scope: cloneScope(config2.scope),
2654
+ humanInLoop: config2.humanInLoop,
2655
+ secrets: cloneSecrets(config2.secrets),
2656
+ tools: cloneStringArray(config2.tools),
2657
+ rename: cloneRenameMap(config2.rename),
2658
+ requires: cloneRequires(config2.requires),
2659
+ children: [...config2.children],
2660
+ default: config2.default
2406
2661
  }
2407
2662
  });
2408
2663
  return group;
@@ -2505,10 +2760,10 @@ function materializeNode(node, inherited) {
2505
2760
  }
2506
2761
  return materializeGroup(node, inherited);
2507
2762
  }
2508
- function defineCommand(config) {
2509
- validateHumanInLoopOnDefine(config);
2763
+ function defineCommand(config2) {
2764
+ validateHumanInLoopOnDefine(config2);
2510
2765
  return materializeCommand(
2511
- createBaseCommand(config),
2766
+ createBaseCommand(config2),
2512
2767
  {
2513
2768
  scope: void 0,
2514
2769
  humanInLoop: void 0,
@@ -2517,10 +2772,10 @@ function defineCommand(config) {
2517
2772
  }
2518
2773
  );
2519
2774
  }
2520
- function defineGroup(config) {
2521
- validateRenameMap(config.rename);
2522
- validateHumanInLoopOnDefine(config);
2523
- return materializeGroup(createBaseGroup(config), {
2775
+ function defineGroup(config2) {
2776
+ validateRenameMap(config2.rename);
2777
+ validateHumanInLoopOnDefine(config2);
2778
+ return materializeGroup(createBaseGroup(config2), {
2524
2779
  scope: void 0,
2525
2780
  humanInLoop: void 0,
2526
2781
  secrets: {},
@@ -2681,17 +2936,22 @@ import { randomBytes } from "node:crypto";
2681
2936
  // ../process-runner/src/docker/args.ts
2682
2937
  import path2 from "node:path";
2683
2938
 
2939
+ // ../process-runner/src/docker/env-file.ts
2940
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2941
+ import { tmpdir } from "node:os";
2942
+ import path3 from "node:path";
2943
+
2684
2944
  // ../process-runner/src/docker/docker-execution-env.ts
2685
2945
  import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
2686
- import { mkdtempSync, rmSync } from "node:fs";
2687
- import { readdir, readFile, writeFile } from "node:fs/promises";
2688
- import { tmpdir } from "node:os";
2689
- import path4 from "node:path";
2946
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "node:fs";
2947
+ import { readdir, readFile, realpath, writeFile } from "node:fs/promises";
2948
+ import { tmpdir as tmpdir2 } from "node:os";
2949
+ import path5 from "node:path";
2690
2950
 
2691
2951
  // ../process-runner/src/host/host-runner.ts
2692
2952
  import { spawn as spawnChildProcess } from "node:child_process";
2693
2953
  function createHostRunner(options = {}) {
2694
- const detached = options.detached === true;
2954
+ const detachedByDefault = options.detached === true;
2695
2955
  return {
2696
2956
  name: "host",
2697
2957
  exec(spec) {
@@ -2709,18 +2969,19 @@ function createHostRunner(options = {}) {
2709
2969
  const stdinMode = spec.stdin ?? "ignore";
2710
2970
  const stdoutMode = spec.stdout ?? "pipe";
2711
2971
  const stderrMode = spec.stderr ?? "pipe";
2972
+ const killProcessGroup = detachedByDefault || spec.killProcessGroup === true;
2712
2973
  const stdio = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" ? "inherit" : [stdinMode, stdoutMode, stderrMode];
2713
2974
  const child = spawnChildProcess(spec.command, spec.args ?? [], {
2714
2975
  cwd: spec.cwd,
2715
2976
  env: spec.env,
2716
2977
  stdio,
2717
- ...detached ? { detached: true } : {}
2978
+ ...killProcessGroup ? { detached: true } : {}
2718
2979
  });
2719
- if (detached) {
2980
+ if (killProcessGroup) {
2720
2981
  child.unref();
2721
2982
  }
2722
2983
  const kill = (signal) => {
2723
- if (detached && process.platform !== "win32" && child.pid !== void 0) {
2984
+ if (killProcessGroup && process.platform !== "win32" && child.pid !== void 0) {
2724
2985
  process.kill(-child.pid, signal);
2725
2986
  return;
2726
2987
  }
@@ -2778,9 +3039,9 @@ function bindAbortSignal(signal, onAbort) {
2778
3039
  }
2779
3040
 
2780
3041
  // ../process-runner/src/workspace-transfer.ts
2781
- import { createHash } from "node:crypto";
3042
+ import { createHash, randomUUID } from "node:crypto";
2782
3043
  import { promises as nodeFs } from "node:fs";
2783
- import path3 from "node:path";
3044
+ import path4 from "node:path";
2784
3045
 
2785
3046
  // ../process-runner/src/testing/mock-runner.ts
2786
3047
  import { Readable, Writable } from "node:stream";
@@ -2851,7 +3112,7 @@ function resolveEndpoint(options = {}) {
2851
3112
  }
2852
3113
 
2853
3114
  // ../task-list/src/backends/utils.ts
2854
- import path5 from "node:path";
3115
+ import path6 from "node:path";
2855
3116
  function compareCreated(left, right) {
2856
3117
  const leftCreated = typeof left.raw.created === "string" ? left.raw.created : "";
2857
3118
  const rightCreated = typeof right.raw.created === "string" ? right.raw.created : "";
@@ -2901,12 +3162,12 @@ async function statIfExists(fs4, filePath) {
2901
3162
  }
2902
3163
  }
2903
3164
  async function rejectSymbolicLinkComponents(fs4, filePath) {
2904
- const resolvedPath = path5.resolve(filePath);
2905
- const rootPath = path5.parse(resolvedPath).root;
2906
- const components = resolvedPath.slice(rootPath.length).split(path5.sep).filter(Boolean);
3165
+ const resolvedPath = path6.resolve(filePath);
3166
+ const rootPath = path6.parse(resolvedPath).root;
3167
+ const components = resolvedPath.slice(rootPath.length).split(path6.sep).filter(Boolean);
2907
3168
  let currentPath = rootPath;
2908
3169
  for (const component of components) {
2909
- currentPath = path5.join(currentPath, component);
3170
+ currentPath = path6.join(currentPath, component);
2910
3171
  try {
2911
3172
  if ((await fs4.lstat(currentPath)).isSymbolicLink()) {
2912
3173
  throw new Error(`Path "${filePath}" contains a symbolic link.`);
@@ -2922,7 +3183,7 @@ async function rejectSymbolicLinkComponents(fs4, filePath) {
2922
3183
  async function writeAtomically(fs4, filePath, content) {
2923
3184
  const tempPath = `${filePath}.tmp-${process.pid}-${tmpFileCounter}`;
2924
3185
  tmpFileCounter += 1;
2925
- await fs4.mkdir(path5.dirname(filePath), { recursive: true });
3186
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
2926
3187
  try {
2927
3188
  await fs4.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
2928
3189
  await fs4.rename(tempPath, filePath);
@@ -2938,7 +3199,7 @@ async function writeAtomically(fs4, filePath, content) {
2938
3199
  }
2939
3200
  }
2940
3201
  async function withFileLock(fs4, lockPath, operation) {
2941
- await fs4.mkdir(path5.dirname(lockPath), { recursive: true });
3202
+ await fs4.mkdir(path6.dirname(lockPath), { recursive: true });
2942
3203
  for (; ; ) {
2943
3204
  try {
2944
3205
  await fs4.writeFile(lockPath, String(process.pid), { encoding: "utf8", flag: "wx" });
@@ -4025,7 +4286,7 @@ function parseQualifiedId(qualifiedId, listName) {
4025
4286
  }
4026
4287
 
4027
4288
  // ../task-list/src/backends/markdown-dir.ts
4028
- import path6 from "node:path";
4289
+ import path7 from "node:path";
4029
4290
  import { parseDocument, stringify } from "yaml";
4030
4291
 
4031
4292
  // ../task-list/src/schema/task.schema.json
@@ -4144,16 +4405,16 @@ function parseQualifiedId2(qualifiedId) {
4144
4405
  };
4145
4406
  }
4146
4407
  function listPath(rootPath, layout, list) {
4147
- return layout.kind === "single" ? rootPath : path6.join(rootPath, list);
4408
+ return layout.kind === "single" ? rootPath : path7.join(rootPath, list);
4148
4409
  }
4149
4410
  function archiveDirectoryPath(rootPath, layout, list) {
4150
- return layout.kind === "single" ? path6.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path6.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
4411
+ return layout.kind === "single" ? path7.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path7.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
4151
4412
  }
4152
4413
  function activeTaskFilename(id, order, width) {
4153
4414
  return `${String(order).padStart(width, "0")}-${id}${MARKDOWN_EXTENSION}`;
4154
4415
  }
4155
4416
  function archivedTaskPath(rootPath, layout, list, id) {
4156
- return path6.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
4417
+ return path7.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
4157
4418
  }
4158
4419
  function isMarkdownFile(entryName) {
4159
4420
  return entryName.endsWith(MARKDOWN_EXTENSION);
@@ -4279,7 +4540,7 @@ function createTask(list, id, frontmatter, body, mode, sourcePath) {
4279
4540
  state: frontmatter.state,
4280
4541
  description: body,
4281
4542
  metadata: metadataFromFrontmatter(frontmatter, mode),
4282
- ...sourcePath !== void 0 && { sourcePath: path6.resolve(sourcePath) }
4543
+ ...sourcePath !== void 0 && { sourcePath: path7.resolve(sourcePath) }
4283
4544
  };
4284
4545
  }
4285
4546
  function serializeTaskDocument(frontmatter, description) {
@@ -4319,7 +4580,7 @@ async function readTaskFile(fs4, list, id, filePath, validStates, initialState,
4319
4580
  task: createTask(list, id, frontmatter, document.body, mode, filePath)
4320
4581
  };
4321
4582
  }
4322
- const parsedFilename = parseActiveFilename(path6.basename(filePath));
4583
+ const parsedFilename = parseActiveFilename(path7.basename(filePath));
4323
4584
  const defaultName = parsedFilename?.id ?? id;
4324
4585
  const effectiveFrontmatter = {
4325
4586
  ...frontmatter,
@@ -4348,7 +4609,7 @@ async function findTaskLocation(fs4, rootPath, layout, list, id) {
4348
4609
  await rejectSymbolicLinkComponents(fs4, listDirectoryPath);
4349
4610
  const activeName = await findActiveTaskFilename(fs4, listDirectoryPath, id);
4350
4611
  if (activeName) {
4351
- const activePath = path6.join(listDirectoryPath, activeName);
4612
+ const activePath = path7.join(listDirectoryPath, activeName);
4352
4613
  await rejectSymbolicLinkComponents(fs4, activePath);
4353
4614
  const activeStat = await statIfExists(fs4, activePath);
4354
4615
  if (activeStat?.isFile()) {
@@ -4371,7 +4632,7 @@ async function readTaskAtLocation(fs4, rootPath, layout, list, id, validStates,
4371
4632
  }
4372
4633
  return readTaskFile(fs4, list, id, location.path, validStates, initialState, mode);
4373
4634
  }
4374
- function createdFrontmatter(defaults, input, initialState, mode) {
4635
+ function createdFrontmatter(defaults2, input, initialState, mode) {
4375
4636
  const frontmatter = mode !== "passthrough" ? {
4376
4637
  $schema: TASK_SCHEMA_ID,
4377
4638
  kind: TASK_KIND,
@@ -4383,7 +4644,7 @@ function createdFrontmatter(defaults, input, initialState, mode) {
4383
4644
  state: initialState
4384
4645
  };
4385
4646
  const reservedKeys = reservedFrontmatterKeys(mode);
4386
- for (const [key2, value] of Object.entries(defaults.metadata)) {
4647
+ for (const [key2, value] of Object.entries(defaults2.metadata)) {
4387
4648
  if (!reservedKeys.has(key2)) {
4388
4649
  setOwnValue(frontmatter, key2, value);
4389
4650
  }
@@ -4470,7 +4731,7 @@ function createTasksView2(deps, layout, list) {
4470
4731
  if (isHiddenEntry(entryName)) continue;
4471
4732
  const parsed = parseActiveFilename(entryName);
4472
4733
  if (!parsed) continue;
4473
- const entryPath = path6.join(listDirectoryPath, entryName);
4734
+ const entryPath = path7.join(listDirectoryPath, entryName);
4474
4735
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
4475
4736
  const entryStat = await statIfExists(deps.fs, entryPath);
4476
4737
  if (!entryStat?.isFile()) continue;
@@ -4488,7 +4749,7 @@ function createTasksView2(deps, layout, list) {
4488
4749
  const entries = await readActiveEntries();
4489
4750
  const tasks = /* @__PURE__ */ new Map();
4490
4751
  for (const entry of entries) {
4491
- const filePath = path6.join(listDirectoryPath, entry.filename);
4752
+ const filePath = path7.join(listDirectoryPath, entry.filename);
4492
4753
  const file = await readTaskFile(
4493
4754
  deps.fs,
4494
4755
  list,
@@ -4509,7 +4770,7 @@ function createTasksView2(deps, layout, list) {
4509
4770
  const result = [];
4510
4771
  for (const entryName of entries) {
4511
4772
  if (isHiddenEntry(entryName) || !isMarkdownFile(entryName)) continue;
4512
- const entryPath = path6.join(archivePath, entryName);
4773
+ const entryPath = path7.join(archivePath, entryName);
4513
4774
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
4514
4775
  const entryStat = await statIfExists(deps.fs, entryPath);
4515
4776
  if (!entryStat?.isFile()) continue;
@@ -4539,12 +4800,12 @@ function createTasksView2(deps, layout, list) {
4539
4800
  if (desiredOrder === void 0) continue;
4540
4801
  const desiredFilename = activeTaskFilename(entry.id, desiredOrder, width);
4541
4802
  if (entry.filename !== desiredFilename) {
4542
- const fromPath = path6.join(listDirectoryPath, entry.filename);
4543
- const stagingPath = path6.join(
4803
+ const fromPath = path7.join(listDirectoryPath, entry.filename);
4804
+ const stagingPath = path7.join(
4544
4805
  listDirectoryPath,
4545
4806
  `${desiredFilename}.staging-${process.pid}-${index}`
4546
4807
  );
4547
- const targetPath = path6.join(listDirectoryPath, desiredFilename);
4808
+ const targetPath = path7.join(listDirectoryPath, desiredFilename);
4548
4809
  try {
4549
4810
  await deps.fs.rename(fromPath, stagingPath);
4550
4811
  staged.push({ original: fromPath, staging: stagingPath, target: targetPath, finalized: false });
@@ -4693,7 +4954,7 @@ function createTasksView2(deps, layout, list) {
4693
4954
  assertCreateHasId(input);
4694
4955
  validateTaskId(input.id);
4695
4956
  await rejectSymbolicLinkComponents(deps.fs, listDirectoryPath);
4696
- return withFileLock(deps.fs, path6.join(listDirectoryPath, ".transition.lock"), async () => {
4957
+ return withFileLock(deps.fs, path7.join(listDirectoryPath, ".transition.lock"), async () => {
4697
4958
  const existing = await findTaskLocation(deps.fs, deps.path, layout, list, input.id);
4698
4959
  if (existing) {
4699
4960
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
@@ -4706,7 +4967,7 @@ function createTasksView2(deps, layout, list) {
4706
4967
  const nextOrder = maxOrder + 1;
4707
4968
  const width = padWidthForCount(activeEntries.length + 1);
4708
4969
  const filename = activeTaskFilename(input.id, nextOrder, width);
4709
- const targetPath = path6.join(listDirectoryPath, filename);
4970
+ const targetPath = path7.join(listDirectoryPath, filename);
4710
4971
  const frontmatter = createdFrontmatter(
4711
4972
  deps.defaults,
4712
4973
  input,
@@ -4814,7 +5075,7 @@ function createTasksView2(deps, layout, list) {
4814
5075
  validateTaskId(id);
4815
5076
  const { event, nextTask } = await withFileLock(
4816
5077
  deps.fs,
4817
- path6.join(listDirectoryPath, ".transition.lock"),
5078
+ path7.join(listDirectoryPath, ".transition.lock"),
4818
5079
  fireTask
4819
5080
  );
4820
5081
  await event.onEnter?.(nextTask);
@@ -4907,7 +5168,7 @@ async function markdownDirBackend(deps) {
4907
5168
  if (entryName === ARCHIVE_DIRECTORY_NAME || isHiddenEntry(entryName)) {
4908
5169
  continue;
4909
5170
  }
4910
- const entryPath = path6.join(deps.path, entryName);
5171
+ const entryPath = path7.join(deps.path, entryName);
4911
5172
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
4912
5173
  const entryStat = await statIfExists(deps.fs, entryPath);
4913
5174
  if (entryStat?.isDirectory()) {
@@ -4949,7 +5210,7 @@ async function markdownDirBackend(deps) {
4949
5210
  }
4950
5211
  const targetListDir = listPath(deps.path, layout, targetListName);
4951
5212
  await rejectSymbolicLinkComponents(deps.fs, targetListDir);
4952
- return withFileLock(deps.fs, path6.join(targetListDir, ".transition.lock"), async () => {
5213
+ return withFileLock(deps.fs, path7.join(targetListDir, ".transition.lock"), async () => {
4953
5214
  const targetExisting = await findTaskLocation(deps.fs, deps.path, layout, targetListName, id);
4954
5215
  if (targetExisting) {
4955
5216
  throw new TaskAlreadyExistsError(`Task "${targetListName}/${id}" already exists.`);
@@ -4999,7 +5260,7 @@ async function markdownDirBackend(deps) {
4999
5260
  );
5000
5261
  const width = padWidthForCount(targetEntries.length + 1);
5001
5262
  const targetFilename = activeTaskFilename(id, maxOrder + 1, width);
5002
- const targetPath = path6.join(targetListDir, targetFilename);
5263
+ const targetPath = path7.join(targetListDir, targetFilename);
5003
5264
  await deps.fs.rename(sourceLocation.path, targetPath);
5004
5265
  return createTask(
5005
5266
  targetListName,
@@ -5021,7 +5282,7 @@ async function markdownDirBackend(deps) {
5021
5282
  }
5022
5283
 
5023
5284
  // ../task-list/src/backends/yaml-file.ts
5024
- import path7 from "node:path";
5285
+ import path8 from "node:path";
5025
5286
  import { isMap, parseDocument as parseDocument2 } from "yaml";
5026
5287
 
5027
5288
  // ../task-list/src/schema/store.schema.json
@@ -5117,7 +5378,7 @@ function createTask2(list, id, taskRecord, sourcePath) {
5117
5378
  state: taskRecord.state,
5118
5379
  description: descriptionFromTaskRecord(taskRecord),
5119
5380
  metadata: metadataFromTaskRecord(taskRecord),
5120
- ...sourcePath !== void 0 && { sourcePath: path7.resolve(sourcePath) }
5381
+ ...sourcePath !== void 0 && { sourcePath: path8.resolve(sourcePath) }
5121
5382
  };
5122
5383
  }
5123
5384
  function matchesFilter(task, filter) {
@@ -5129,13 +5390,13 @@ function matchesFilter(task, filter) {
5129
5390
  }
5130
5391
  return true;
5131
5392
  }
5132
- function createTaskRecord(defaults, input, initialState) {
5393
+ function createTaskRecord(defaults2, input, initialState) {
5133
5394
  const taskRecord = Object.assign(/* @__PURE__ */ Object.create(null), {
5134
5395
  name: input.name,
5135
5396
  state: initialState,
5136
5397
  description: input.description ?? ""
5137
5398
  });
5138
- for (const [key2, value] of Object.entries(defaults.metadata)) {
5399
+ for (const [key2, value] of Object.entries(defaults2.metadata)) {
5139
5400
  if (!RESERVED_TASK_KEYS.has(key2)) {
5140
5401
  taskRecord[key2] = value;
5141
5402
  }
@@ -5682,7 +5943,7 @@ async function openGhIssuesBackend(options) {
5682
5943
 
5683
5944
  // ../task-list/src/move.ts
5684
5945
  import * as fsPromises2 from "node:fs/promises";
5685
- import path8 from "node:path";
5946
+ import path9 from "node:path";
5686
5947
 
5687
5948
  // ../toolcraft/src/human-in-loop/approval-tasks.ts
5688
5949
  import { randomBytes as randomBytes3 } from "node:crypto";
@@ -6178,13 +6439,13 @@ function formatAvailableApprovalCommandPaths(root) {
6178
6439
  }
6179
6440
  function enumerateApprovalCommandPaths(root) {
6180
6441
  const paths = [];
6181
- const visit = (node, path24) => {
6442
+ const visit = (node, path25) => {
6182
6443
  if (node.kind === "command") {
6183
- paths.push(path24.join("."));
6444
+ paths.push(path25.join("."));
6184
6445
  return;
6185
6446
  }
6186
6447
  for (const child of getVisibleCliChildren(node)) {
6187
- visit(child, [...path24, child.name]);
6448
+ visit(child, [...path25, child.name]);
6188
6449
  }
6189
6450
  };
6190
6451
  if (root.kind === "command") {
@@ -6219,21 +6480,21 @@ function createHandlerContext(command, params17) {
6219
6480
  }
6220
6481
  function createFs() {
6221
6482
  return {
6222
- readFile: async (path24, encoding = "utf8") => readFile2(path24, { encoding }),
6223
- writeFile: async (path24, contents) => {
6224
- await writeFile2(path24, contents);
6483
+ readFile: async (path25, encoding = "utf8") => readFile2(path25, { encoding }),
6484
+ writeFile: async (path25, contents) => {
6485
+ await writeFile2(path25, contents);
6225
6486
  },
6226
- exists: async (path24) => {
6487
+ exists: async (path25) => {
6227
6488
  try {
6228
- await access(path24);
6489
+ await access(path25);
6229
6490
  return true;
6230
6491
  } catch {
6231
6492
  return false;
6232
6493
  }
6233
6494
  },
6234
- lstat: async (path24) => lstat(path24),
6495
+ lstat: async (path25) => lstat(path25),
6235
6496
  rename: async (fromPath, toPath) => rename(fromPath, toPath),
6236
- unlink: async (path24) => unlink(path24)
6497
+ unlink: async (path25) => unlink(path25)
6237
6498
  };
6238
6499
  }
6239
6500
  function createEnv(values = process.env) {
@@ -6509,17 +6770,17 @@ function isMissingStateError(error3) {
6509
6770
  }
6510
6771
 
6511
6772
  // ../toolcraft/src/error-report.ts
6512
- import { mkdir as mkdir2, realpath, writeFile as writeFile4 } from "node:fs/promises";
6513
- import { randomUUID as randomUUID2 } from "node:crypto";
6773
+ import { mkdir as mkdir2, realpath as realpath2, writeFile as writeFile4 } from "node:fs/promises";
6774
+ import { randomUUID as randomUUID3 } from "node:crypto";
6514
6775
  import os from "node:os";
6515
- import path12 from "node:path";
6776
+ import path13 from "node:path";
6516
6777
  import { CommanderError } from "commander";
6517
6778
 
6518
6779
  // ../toolcraft/src/mcp-proxy.ts
6519
6780
  import { existsSync as existsSync2 } from "node:fs";
6520
6781
  import { lstat as lstat2, mkdir, readFile as readFile3, rename as rename2, writeFile as writeFile3 } from "node:fs/promises";
6521
- import path11 from "node:path";
6522
- import { createHash as createHash3, randomUUID } from "node:crypto";
6782
+ import path12 from "node:path";
6783
+ import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
6523
6784
 
6524
6785
  // ../tiny-mcp-client/src/internal.ts
6525
6786
  import { spawn as spawn5 } from "node:child_process";
@@ -6527,13 +6788,13 @@ import { PassThrough as PassThrough2 } from "node:stream";
6527
6788
 
6528
6789
  // ../mcp-oauth/src/client/auth-store-session-store.ts
6529
6790
  import crypto from "node:crypto";
6530
- import path10 from "node:path";
6791
+ import path11 from "node:path";
6531
6792
 
6532
6793
  // ../auth-store/src/encrypted-file-store.ts
6533
6794
  import { createCipheriv, createDecipheriv, randomBytes as randomBytes4, scrypt } from "node:crypto";
6534
6795
  import { promises as fs } from "node:fs";
6535
6796
  import { homedir, hostname, userInfo } from "node:os";
6536
- import path9 from "node:path";
6797
+ import path10 from "node:path";
6537
6798
  var derivedKeyCache = /* @__PURE__ */ new Map();
6538
6799
  var ENCRYPTION_ALGORITHM = "aes-256-gcm";
6539
6800
  var ENCRYPTION_VERSION = 1;
@@ -6545,6 +6806,7 @@ var temporaryFileSequence = 0;
6545
6806
  var EncryptedFileStore = class {
6546
6807
  fs;
6547
6808
  filePath;
6809
+ symbolicLinkCheckStartPath;
6548
6810
  salt;
6549
6811
  getMachineIdentity;
6550
6812
  getRandomBytes;
@@ -6552,11 +6814,22 @@ var EncryptedFileStore = class {
6552
6814
  constructor(input) {
6553
6815
  this.fs = input.fs ?? fs;
6554
6816
  this.salt = input.salt;
6555
- this.filePath = input.filePath ?? path9.join(
6556
- (input.getHomeDirectory ?? homedir)(),
6557
- input.defaultDirectory ?? ".auth-store",
6558
- input.defaultFileName ?? "credentials.enc"
6559
- );
6817
+ if (input.filePath === void 0) {
6818
+ const homeDirectory = (input.getHomeDirectory ?? homedir)();
6819
+ const defaultDirectory = input.defaultDirectory ?? ".auth-store";
6820
+ this.filePath = path10.join(
6821
+ homeDirectory,
6822
+ defaultDirectory,
6823
+ input.defaultFileName ?? "credentials.enc"
6824
+ );
6825
+ this.symbolicLinkCheckStartPath = resolveDefaultDirectoryCheckStart(
6826
+ homeDirectory,
6827
+ defaultDirectory
6828
+ );
6829
+ } else {
6830
+ this.filePath = input.filePath;
6831
+ this.symbolicLinkCheckStartPath = null;
6832
+ }
6560
6833
  this.getMachineIdentity = input.getMachineIdentity ?? defaultMachineIdentity;
6561
6834
  this.getRandomBytes = input.getRandomBytes ?? randomBytes4;
6562
6835
  }
@@ -6607,7 +6880,7 @@ var EncryptedFileStore = class {
6607
6880
  authTag: authTag.toString("base64"),
6608
6881
  ciphertext: ciphertext.toString("base64")
6609
6882
  };
6610
- await this.fs.mkdir(path9.dirname(this.filePath), { recursive: true });
6883
+ await this.fs.mkdir(path10.dirname(this.filePath), { recursive: true });
6611
6884
  await this.assertRegularCredentialPath();
6612
6885
  const temporaryPath = `${this.filePath}.${process.pid}.${temporaryFileSequence++}.tmp`;
6613
6886
  try {
@@ -6636,8 +6909,11 @@ var EncryptedFileStore = class {
6636
6909
  }
6637
6910
  }
6638
6911
  async assertRegularCredentialPath() {
6639
- const resolvedPath = path9.resolve(this.filePath);
6640
- const protectedPaths = [path9.dirname(resolvedPath), resolvedPath];
6912
+ const resolvedPath = path10.resolve(this.filePath);
6913
+ const protectedPaths = getProtectedCredentialPaths(
6914
+ resolvedPath,
6915
+ this.symbolicLinkCheckStartPath
6916
+ );
6641
6917
  for (const currentPath of protectedPaths) {
6642
6918
  try {
6643
6919
  const stats = await this.fs.lstat(currentPath);
@@ -6665,6 +6941,30 @@ var EncryptedFileStore = class {
6665
6941
  return this.keyPromise;
6666
6942
  }
6667
6943
  };
6944
+ function resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory) {
6945
+ const [firstSegment] = defaultDirectory.split(/[\\/]+/).filter(Boolean);
6946
+ return path10.resolve(homeDirectory, firstSegment ?? ".");
6947
+ }
6948
+ function getProtectedCredentialPaths(resolvedPath, symbolicLinkCheckStartPath) {
6949
+ if (symbolicLinkCheckStartPath === null) {
6950
+ return [path10.dirname(resolvedPath), resolvedPath];
6951
+ }
6952
+ const resolvedStartPath = path10.resolve(symbolicLinkCheckStartPath);
6953
+ if (!isPathInsideOrEqual(resolvedPath, resolvedStartPath)) {
6954
+ return [path10.dirname(resolvedPath), resolvedPath];
6955
+ }
6956
+ const protectedPaths = [resolvedStartPath];
6957
+ let currentPath = resolvedStartPath;
6958
+ for (const segment of path10.relative(resolvedStartPath, resolvedPath).split(path10.sep).filter(Boolean)) {
6959
+ currentPath = path10.join(currentPath, segment);
6960
+ protectedPaths.push(currentPath);
6961
+ }
6962
+ return protectedPaths;
6963
+ }
6964
+ function isPathInsideOrEqual(childPath, parentPath) {
6965
+ const relativePath = path10.relative(parentPath, childPath);
6966
+ return relativePath === "" || !relativePath.startsWith("..") && !path10.isAbsolute(relativePath);
6967
+ }
6668
6968
  async function removeIfPresent(fileSystem, filePath) {
6669
6969
  try {
6670
6970
  await fileSystem.unlink(filePath);
@@ -6815,6 +7115,17 @@ function runSecurityCommand(command, args, options) {
6815
7115
  });
6816
7116
  let stdout = "";
6817
7117
  let stderr = "";
7118
+ let stdinErrorMessage;
7119
+ const appendStderr = (message2) => {
7120
+ stderr = stderr.length === 0 ? message2 : `${stderr}${stderr.endsWith("\n") ? "" : "\n"}${message2}`;
7121
+ };
7122
+ const appendStdinError = () => {
7123
+ if (stdinErrorMessage === void 0) {
7124
+ return;
7125
+ }
7126
+ appendStderr(stdinErrorMessage);
7127
+ stdinErrorMessage = void 0;
7128
+ };
6818
7129
  child.stdout?.setEncoding("utf8");
6819
7130
  child.stdout?.on("data", (chunk) => {
6820
7131
  stdout += chunk.toString();
@@ -6824,17 +7135,23 @@ function runSecurityCommand(command, args, options) {
6824
7135
  stderr += chunk.toString();
6825
7136
  });
6826
7137
  if (options?.stdin !== void 0) {
7138
+ child.stdin?.once("error", (error3) => {
7139
+ stdinErrorMessage = error3 instanceof Error ? error3.message : String(error3);
7140
+ });
6827
7141
  child.stdin?.end(options.stdin);
6828
7142
  }
6829
7143
  child.on("error", (error3) => {
6830
7144
  const message2 = error3 instanceof Error ? error3.message : String(error3 ?? "Unknown error");
7145
+ appendStdinError();
7146
+ appendStderr(message2);
6831
7147
  resolve({
6832
7148
  stdout,
6833
- stderr: stderr ? `${stderr}${message2}` : message2,
7149
+ stderr,
6834
7150
  exitCode: 127
6835
7151
  });
6836
7152
  });
6837
7153
  child.on("close", (code) => {
7154
+ appendStdinError();
6838
7155
  resolve({
6839
7156
  stdout,
6840
7157
  stderr,
@@ -6972,19 +7289,24 @@ function createAuthStoreClientStore(options) {
6972
7289
  }
6973
7290
  };
6974
7291
  }
6975
- function createNamedSecretStore(key2, options, defaults) {
7292
+ function createNamedSecretStore(key2, options, defaults2) {
6976
7293
  const hash = crypto.createHash("sha256").update(key2).digest("hex");
6977
- const parsedFilePath = options.fileStore?.filePath === void 0 ? null : path10.parse(options.fileStore.filePath);
7294
+ const configuredFilePath = options.fileStore?.filePath;
7295
+ const parsedFilePath = configuredFilePath === void 0 ? null : path11.parse(configuredFilePath);
6978
7296
  const fileStore = {
6979
7297
  ...options.fileStore,
6980
- salt: options.fileStore?.salt ?? defaults.salt,
6981
- defaultDirectory: parsedFilePath?.dir || options.fileStore?.defaultDirectory || defaults.directory,
7298
+ filePath: parsedFilePath === null ? void 0 : path11.join(
7299
+ parsedFilePath.dir,
7300
+ `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
7301
+ ),
7302
+ salt: options.fileStore?.salt ?? defaults2.salt,
7303
+ defaultDirectory: options.fileStore?.defaultDirectory || defaults2.directory,
6982
7304
  defaultFileName: parsedFilePath === null ? `${hash}.enc` : `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
6983
7305
  };
6984
7306
  const keychainStore = {
6985
7307
  ...options.keychainStore,
6986
- service: options.keychainStore?.service ?? defaults.service,
6987
- account: `${options.keychainStore?.account ?? defaults.accountPrefix}:${hash}`
7308
+ service: options.keychainStore?.service ?? defaults2.service,
7309
+ account: `${options.keychainStore?.account ?? defaults2.accountPrefix}:${hash}`
6988
7310
  };
6989
7311
  return createSecretStore({ ...options, fileStore, keychainStore }).store;
6990
7312
  }
@@ -8557,10 +8879,19 @@ var McpClient = class {
8557
8879
  }
8558
8880
  try {
8559
8881
  let requestId;
8882
+ let cancellationSent = false;
8883
+ const sendCancellationNotification = () => {
8884
+ if (requestId === void 0 || cancellationSent) {
8885
+ return;
8886
+ }
8887
+ cancellationSent = true;
8888
+ messageLayer.sendNotification("notifications/cancelled", { requestId });
8889
+ };
8560
8890
  const requestPromise = messageLayer.sendRequest("tools/call", requestParams, {
8561
8891
  onRequestId: (nextRequestId) => {
8562
8892
  requestId = nextRequestId;
8563
- }
8893
+ },
8894
+ onTimeout: sendCancellationNotification
8564
8895
  }).then((result) => {
8565
8896
  if (!isCallToolResult(result)) {
8566
8897
  throw new McpError(ERROR_INVALID_REQUEST, "Invalid tool result");
@@ -8574,8 +8905,9 @@ var McpClient = class {
8574
8905
  let abortListener;
8575
8906
  const abortPromise = new Promise((_, reject) => {
8576
8907
  const rejectWithAbortReason = () => {
8908
+ sendCancellationNotification();
8577
8909
  if (requestId !== void 0) {
8578
- messageLayer.sendNotification("notifications/cancelled", { requestId });
8910
+ messageLayer.cancelRequest(requestId, signal.reason);
8579
8911
  }
8580
8912
  reject(signal.reason);
8581
8913
  };
@@ -8751,11 +9083,13 @@ var StdioTransport = class _StdioTransport {
8751
9083
  const child = this.child;
8752
9084
  this.readable = child.stdout;
8753
9085
  this.writable = child.stdin;
9086
+ const stderrDecoder = new TextDecoder();
8754
9087
  child.stderr.on("data", (chunk) => {
8755
- this.stderrOutput += chunkToString(chunk);
8756
- if (this.stderrOutput.length > _StdioTransport.STDERR_MAX_LENGTH) {
8757
- this.stderrOutput = this.stderrOutput.slice(-_StdioTransport.STDERR_MAX_LENGTH);
8758
- }
9088
+ const decoded = chunk instanceof Uint8Array ? stderrDecoder.decode(chunk, { stream: true }) : `${stderrDecoder.decode()}${String(chunk)}`;
9089
+ this.appendStderrOutput(decoded);
9090
+ });
9091
+ child.stderr.once("end", () => {
9092
+ this.appendStderrOutput(stderrDecoder.decode());
8759
9093
  });
8760
9094
  this.closed = new Promise((resolve) => {
8761
9095
  let settled = false;
@@ -8795,6 +9129,15 @@ var StdioTransport = class _StdioTransport {
8795
9129
  getStderrOutput() {
8796
9130
  return this.stderrOutput;
8797
9131
  }
9132
+ appendStderrOutput(chunk) {
9133
+ if (chunk.length === 0) {
9134
+ return;
9135
+ }
9136
+ this.stderrOutput += chunk;
9137
+ if (this.stderrOutput.length > _StdioTransport.STDERR_MAX_LENGTH) {
9138
+ this.stderrOutput = this.stderrOutput.slice(-_StdioTransport.STDERR_MAX_LENGTH);
9139
+ }
9140
+ }
8798
9141
  dispose(reason = new Error("Stdio transport disposed")) {
8799
9142
  void reason;
8800
9143
  if (this.disposed) {
@@ -9202,15 +9545,6 @@ function serializeJsonRpcMessage(message2) {
9202
9545
  return `${JSON.stringify(message2)}
9203
9546
  `;
9204
9547
  }
9205
- function chunkToString(chunk) {
9206
- if (typeof chunk === "string") {
9207
- return chunk;
9208
- }
9209
- if (chunk instanceof Uint8Array) {
9210
- return Buffer.from(chunk).toString("utf8");
9211
- }
9212
- return String(chunk);
9213
- }
9214
9548
  function normalizeLine(line) {
9215
9549
  return line.endsWith("\r") ? line.slice(0, -1) : line;
9216
9550
  }
@@ -9387,6 +9721,7 @@ var JsonRpcMessageLayer = class {
9387
9721
  return new Promise((resolve, reject) => {
9388
9722
  const timeout = setTimeout(() => {
9389
9723
  this.pendingRequests.delete(id);
9724
+ options.onTimeout?.(id);
9390
9725
  reject(new Error(`JSON-RPC request "${method}" timed out after ${timeoutMs}ms`));
9391
9726
  }, timeoutMs);
9392
9727
  this.pendingRequests.set(id, { resolve, reject, timeout });
@@ -9399,6 +9734,16 @@ var JsonRpcMessageLayer = class {
9399
9734
  }
9400
9735
  });
9401
9736
  }
9737
+ cancelRequest(requestId, reason) {
9738
+ const pending = this.pendingRequests.get(requestId);
9739
+ if (pending === void 0) {
9740
+ return false;
9741
+ }
9742
+ this.pendingRequests.delete(requestId);
9743
+ clearTimeout(pending.timeout);
9744
+ pending.reject(reason);
9745
+ return true;
9746
+ }
9402
9747
  dispose(reason = new Error("JSON-RPC message layer disposed")) {
9403
9748
  if (this.disposedError !== void 0) {
9404
9749
  return;
@@ -9799,13 +10144,13 @@ function convertJsonSchema(schema) {
9799
10144
  }
9800
10145
  return convertSchema(schema, schema, []);
9801
10146
  }
9802
- function convertSchema(schema, root, path24) {
9803
- const resolvedSchema = resolveReferencedSchema(schema, root, path24);
10147
+ function convertSchema(schema, root, path25) {
10148
+ const resolvedSchema = resolveReferencedSchema(schema, root, path25);
9804
10149
  const normalizedSchema = normalizeNullability(resolvedSchema);
9805
10150
  const composition = getComposition(normalizedSchema.schema);
9806
10151
  if (Array.isArray(normalizedSchema.schema.type)) {
9807
10152
  throw new Error(
9808
- `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
10153
+ `JSON Schema "${formatJsonSchemaPath(path25)}" has an unsupported type "${formatJsonSchemaType(
9809
10154
  normalizedSchema.schema.type
9810
10155
  )}". Supported: string, number, integer, boolean, array, object.`
9811
10156
  );
@@ -9817,13 +10162,13 @@ function convertSchema(schema, root, path24) {
9817
10162
  return convertEnumSchema(resolvedSchema, normalizedSchema.nullable);
9818
10163
  }
9819
10164
  if (composition !== void 0) {
9820
- return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path24);
10165
+ return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path25);
9821
10166
  }
9822
10167
  if (isRecordSchema(normalizedSchema.schema)) {
9823
10168
  return applyMetadata(
9824
10169
  S.Record(
9825
10170
  convertSchema(normalizedSchema.schema.additionalProperties, root, [
9826
- ...path24,
10171
+ ...path25,
9827
10172
  "additionalProperties"
9828
10173
  ])
9829
10174
  ),
@@ -9872,12 +10217,12 @@ function convertSchema(schema, root, path24) {
9872
10217
  if (normalizedSchema.schema.items === void 0) {
9873
10218
  throw new Error(
9874
10219
  `JSON Schema "${formatJsonSchemaPath(
9875
- path24
10220
+ path25
9876
10221
  )}" is an array but is missing the "items" field. Add "items": { ... } to declare the element type.`
9877
10222
  );
9878
10223
  }
9879
10224
  return S.Array(
9880
- convertSchema(normalizedSchema.schema.items, root, [...path24, "items"]),
10225
+ convertSchema(normalizedSchema.schema.items, root, [...path25, "items"]),
9881
10226
  createCommonOptions(
9882
10227
  normalizedSchema.schema,
9883
10228
  normalizedSchema.nullable,
@@ -9887,7 +10232,7 @@ function convertSchema(schema, root, path24) {
9887
10232
  case "object":
9888
10233
  return convertObjectSchema(normalizedSchema.schema, root, {
9889
10234
  nullable: normalizedSchema.nullable,
9890
- path: path24
10235
+ path: path25
9891
10236
  });
9892
10237
  case "null":
9893
10238
  return applyMetadata(S.Json(), normalizedSchema.schema, {
@@ -9902,12 +10247,12 @@ function convertSchema(schema, root, path24) {
9902
10247
  }
9903
10248
  throw new Error(
9904
10249
  `JSON Schema "${formatJsonSchemaPath(
9905
- path24
10250
+ path25
9906
10251
  )}" must declare one of: "type", "enum", "const", "oneOf", "anyOf", or "allOf".`
9907
10252
  );
9908
10253
  }
9909
10254
  throw new Error(
9910
- `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
10255
+ `JSON Schema "${formatJsonSchemaPath(path25)}" has an unsupported type "${formatJsonSchemaType(
9911
10256
  normalizedSchema.schema.type
9912
10257
  )}". Supported: string, number, integer, boolean, array, object.`
9913
10258
  );
@@ -9951,21 +10296,21 @@ function convertEnumSchema(schema, nullable) {
9951
10296
  )
9952
10297
  });
9953
10298
  }
9954
- function convertCompositionSchema(schema, root, nullable, path24) {
10299
+ function convertCompositionSchema(schema, root, nullable, path25) {
9955
10300
  const composition = getComposition(schema);
9956
10301
  const branchSchemas = composition?.branches ?? [];
9957
10302
  const keyword = composition?.keyword ?? "oneOf";
9958
10303
  const branches = branchSchemas.map(
9959
- (branch, index) => resolveReferencedSchema(branch, root, [...path24, keyword, String(index)])
10304
+ (branch, index) => resolveReferencedSchema(branch, root, [...path25, keyword, String(index)])
9960
10305
  );
9961
- const discriminator = findDiscriminator(branches, root, path24);
10306
+ const discriminator = findDiscriminator(branches, root, path25);
9962
10307
  if (discriminator !== void 0) {
9963
10308
  const convertedBranches = Object.fromEntries(
9964
10309
  branches.map((branch, index) => [
9965
10310
  getDiscriminatorLiteral(branch, discriminator, root),
9966
10311
  convertObjectSchema(branch, root, {
9967
10312
  omitProperty: discriminator,
9968
- path: [...path24, keyword, String(index)]
10313
+ path: [...path25, keyword, String(index)]
9969
10314
  })
9970
10315
  ])
9971
10316
  );
@@ -9984,7 +10329,7 @@ function convertCompositionSchema(schema, root, nullable, path24) {
9984
10329
  S.Union(
9985
10330
  branches.map(
9986
10331
  (branch, index) => convertObjectSchema(branch, root, {
9987
- path: [...path24, keyword, String(index)]
10332
+ path: [...path25, keyword, String(index)]
9988
10333
  })
9989
10334
  )
9990
10335
  ),
@@ -10086,11 +10431,11 @@ function getComposition(schema) {
10086
10431
  }
10087
10432
  return void 0;
10088
10433
  }
10089
- function formatJsonSchemaPath(path24) {
10090
- if (path24.length === 0) {
10434
+ function formatJsonSchemaPath(path25) {
10435
+ if (path25.length === 0) {
10091
10436
  return "#";
10092
10437
  }
10093
- return `#/${path24.map(escapeJsonPointerSegment).join("/")}`;
10438
+ return `#/${path25.map(escapeJsonPointerSegment).join("/")}`;
10094
10439
  }
10095
10440
  function formatJsonSchemaType(type2) {
10096
10441
  return Array.isArray(type2) ? JSON.stringify(type2) : String(type2);
@@ -10106,11 +10451,11 @@ function isRecordSchema(schema) {
10106
10451
  const propertyKeys = Object.keys(schema.properties ?? {});
10107
10452
  return schema.type === "object" && propertyKeys.length === 0 && typeof schema.additionalProperties === "object" && schema.additionalProperties !== null;
10108
10453
  }
10109
- function findDiscriminator(branches, root, path24) {
10454
+ function findDiscriminator(branches, root, path25) {
10110
10455
  const [firstBranch] = branches;
10111
10456
  if (firstBranch === void 0) {
10112
10457
  throw new Error(
10113
- `JSON Schema "${formatJsonSchemaPath(path24)}" uses oneOf/anyOf/allOf but has no branches.`
10458
+ `JSON Schema "${formatJsonSchemaPath(path25)}" uses oneOf/anyOf/allOf but has no branches.`
10114
10459
  );
10115
10460
  }
10116
10461
  const candidateKeys = Object.keys(firstBranch.properties ?? {});
@@ -10150,19 +10495,19 @@ function getDiscriminatorLiteral(branch, key2, root) {
10150
10495
  }
10151
10496
  return void 0;
10152
10497
  }
10153
- function resolveReferencedSchema(schema, root, path24) {
10498
+ function resolveReferencedSchema(schema, root, path25) {
10154
10499
  if (schema.$ref === void 0) {
10155
10500
  return schema;
10156
10501
  }
10157
10502
  const resolvedTarget = resolveLocalRef(root, schema.$ref);
10158
10503
  if (resolvedTarget === void 0) {
10159
10504
  throw new Error(
10160
- `JSON Schema "${formatJsonSchemaPath(path24)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
10505
+ `JSON Schema "${formatJsonSchemaPath(path25)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
10161
10506
  );
10162
10507
  }
10163
10508
  const { $ref: ignoredRef, ...siblingKeywords } = schema;
10164
10509
  void ignoredRef;
10165
- const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path24);
10510
+ const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path25);
10166
10511
  if (Object.keys(siblingKeywords).length === 0) {
10167
10512
  return resolvedSchema;
10168
10513
  }
@@ -10186,9 +10531,9 @@ function mergeJsonSchemas(base, overlay) {
10186
10531
  ...mergedRequired === void 0 ? {} : { required: mergedRequired }
10187
10532
  };
10188
10533
  }
10189
- function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__PURE__ */ new Set()) {
10534
+ function hasSelfReferencingRef(schema, root, path25 = "#", activePaths = /* @__PURE__ */ new Set()) {
10190
10535
  const nextActivePaths = new Set(activePaths);
10191
- nextActivePaths.add(path24);
10536
+ nextActivePaths.add(path25);
10192
10537
  const localRefPath = getLocalRefPath(schema.$ref);
10193
10538
  if (localRefPath !== void 0) {
10194
10539
  if (nextActivePaths.has(localRefPath)) {
@@ -10199,13 +10544,13 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
10199
10544
  return true;
10200
10545
  }
10201
10546
  }
10202
- if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path24}/items`, nextActivePaths)) {
10547
+ if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path25}/items`, nextActivePaths)) {
10203
10548
  return true;
10204
10549
  }
10205
10550
  if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null && hasSelfReferencingRef(
10206
10551
  schema.additionalProperties,
10207
10552
  root,
10208
- `${path24}/additionalProperties`,
10553
+ `${path25}/additionalProperties`,
10209
10554
  nextActivePaths
10210
10555
  )) {
10211
10556
  return true;
@@ -10214,7 +10559,7 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
10214
10559
  if (hasSelfReferencingRef(
10215
10560
  childSchema,
10216
10561
  root,
10217
- `${path24}/properties/${escapeJsonPointerSegment(key2)}`,
10562
+ `${path25}/properties/${escapeJsonPointerSegment(key2)}`,
10218
10563
  nextActivePaths
10219
10564
  )) {
10220
10565
  return true;
@@ -10224,24 +10569,24 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
10224
10569
  if (hasSelfReferencingRef(
10225
10570
  childSchema,
10226
10571
  root,
10227
- `${path24}/$defs/${escapeJsonPointerSegment(key2)}`,
10572
+ `${path25}/$defs/${escapeJsonPointerSegment(key2)}`,
10228
10573
  nextActivePaths
10229
10574
  )) {
10230
10575
  return true;
10231
10576
  }
10232
10577
  }
10233
10578
  for (const [index, childSchema] of (schema.oneOf ?? []).entries()) {
10234
- if (hasSelfReferencingRef(childSchema, root, `${path24}/oneOf/${index}`, nextActivePaths)) {
10579
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/oneOf/${index}`, nextActivePaths)) {
10235
10580
  return true;
10236
10581
  }
10237
10582
  }
10238
10583
  for (const [index, childSchema] of (schema.anyOf ?? []).entries()) {
10239
- if (hasSelfReferencingRef(childSchema, root, `${path24}/anyOf/${index}`, nextActivePaths)) {
10584
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/anyOf/${index}`, nextActivePaths)) {
10240
10585
  return true;
10241
10586
  }
10242
10587
  }
10243
10588
  for (const [index, childSchema] of (schema.allOf ?? []).entries()) {
10244
- if (hasSelfReferencingRef(childSchema, root, `${path24}/allOf/${index}`, nextActivePaths)) {
10589
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/allOf/${index}`, nextActivePaths)) {
10245
10590
  return true;
10246
10591
  }
10247
10592
  }
@@ -10257,14 +10602,14 @@ function getLocalRefPath(ref) {
10257
10602
  return ref.startsWith("#/") ? ref : void 0;
10258
10603
  }
10259
10604
  function resolveLocalRef(root, ref) {
10260
- const path24 = getLocalRefPath(ref);
10261
- if (path24 === void 0) {
10605
+ const path25 = getLocalRefPath(ref);
10606
+ if (path25 === void 0) {
10262
10607
  return void 0;
10263
10608
  }
10264
- if (path24 === "#") {
10609
+ if (path25 === "#") {
10265
10610
  return root;
10266
10611
  }
10267
- const segments = path24.slice(2).split("/").map(unescapeJsonPointerSegment);
10612
+ const segments = path25.slice(2).split("/").map(unescapeJsonPointerSegment);
10268
10613
  let current = root;
10269
10614
  for (const segment of segments) {
10270
10615
  if (Array.isArray(current)) {
@@ -10467,10 +10812,10 @@ function validateRenameMap2(name, tools, rename5) {
10467
10812
  }
10468
10813
  }
10469
10814
  }
10470
- function createConnection(name, config) {
10815
+ function createConnection(name, config2) {
10471
10816
  const connection = {
10472
10817
  name,
10473
- config,
10818
+ config: config2,
10474
10819
  async dispose() {
10475
10820
  shutdownDisposers.delete(connection.dispose);
10476
10821
  connection.connecting = void 0;
@@ -10525,8 +10870,8 @@ async function readCache(cachePath) {
10525
10870
  }
10526
10871
  }
10527
10872
  async function writeCache(cachePath, cache) {
10528
- const directory = path11.dirname(cachePath);
10529
- const tempPath = `${cachePath}.tmp-${randomUUID()}`;
10873
+ const directory = path12.dirname(cachePath);
10874
+ const tempPath = `${cachePath}.tmp-${randomUUID2()}`;
10530
10875
  await assertCachePathHasNoSymlinks(cachePath);
10531
10876
  await assertCachePathHasNoSymlinks(tempPath);
10532
10877
  await mkdir(directory, { recursive: true });
@@ -10537,13 +10882,13 @@ async function writeCache(cachePath, cache) {
10537
10882
  await assertCachePathHasNoSymlinks(cachePath);
10538
10883
  await rename2(tempPath, cachePath);
10539
10884
  }
10540
- async function fetchCache(name, config) {
10885
+ async function fetchCache(name, config2) {
10541
10886
  const logger2 = createLogger((message2) => {
10542
10887
  process.stderr.write(`${message2}
10543
10888
  `);
10544
10889
  });
10545
10890
  logger2.info(`MCP ${name}: connecting`);
10546
- const client = await dialUpstream(name, config);
10891
+ const client = await dialUpstream(name, config2);
10547
10892
  try {
10548
10893
  logger2.info(`MCP ${name}: listing tools`);
10549
10894
  const tools = [];
@@ -10562,7 +10907,7 @@ async function fetchCache(name, config) {
10562
10907
  $schema: MCP_PROXY_SCHEMA_URL,
10563
10908
  version: 1,
10564
10909
  upstream,
10565
- configFingerprint: fingerprintMcpServerConfig(config),
10910
+ configFingerprint: fingerprintMcpServerConfig(config2),
10566
10911
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
10567
10912
  tools
10568
10913
  };
@@ -10632,8 +10977,8 @@ function isRefreshRequested(name, refresh) {
10632
10977
  }
10633
10978
  async function resolveSingleProxy(group, options) {
10634
10979
  const internal = getInternalGroupConfig2(group);
10635
- const config = internal.mcp;
10636
- if (config === void 0) {
10980
+ const config2 = internal.mcp;
10981
+ if (config2 === void 0) {
10637
10982
  return;
10638
10983
  }
10639
10984
  const name = group.name;
@@ -10643,21 +10988,21 @@ async function resolveSingleProxy(group, options) {
10643
10988
  let cache;
10644
10989
  let shouldWriteCache = false;
10645
10990
  if (isRefreshRequested(name, refresh)) {
10646
- cache = await fetchCache(name, config);
10991
+ cache = await fetchCache(name, config2);
10647
10992
  shouldWriteCache = true;
10648
10993
  } else {
10649
10994
  const storedCache = await readCache(cachePath);
10650
- if (storedCache && cacheMatchesConfig(storedCache, config)) {
10995
+ if (storedCache && cacheMatchesConfig(storedCache, config2)) {
10651
10996
  cache = storedCache;
10652
10997
  } else {
10653
- cache = await fetchCache(name, config);
10998
+ cache = await fetchCache(name, config2);
10654
10999
  shouldWriteCache = true;
10655
11000
  }
10656
11001
  }
10657
11002
  const tools = filterAllowlistedTools(cache.tools, internal.tools);
10658
11003
  validateRenameMap2(name, tools, internal.rename);
10659
11004
  const previousConnection = getProxyConnection(group);
10660
- const nextConnection = createConnection(name, config);
11005
+ const nextConnection = createConnection(name, config2);
10661
11006
  try {
10662
11007
  replaceProxyChildrenSafely(group, tools, internal.rename, nextConnection);
10663
11008
  if (shouldWriteCache) {
@@ -10682,11 +11027,11 @@ async function resolveSingleProxy(group, options) {
10682
11027
  );
10683
11028
  }
10684
11029
  }
10685
- function cacheMatchesConfig(cache, config) {
10686
- return cache.configFingerprint === fingerprintMcpServerConfig(config);
11030
+ function cacheMatchesConfig(cache, config2) {
11031
+ return cache.configFingerprint === fingerprintMcpServerConfig(config2);
10687
11032
  }
10688
- function fingerprintMcpServerConfig(config) {
10689
- return createHash3("sha256").update(JSON.stringify(config)).digest("hex");
11033
+ function fingerprintMcpServerConfig(config2) {
11034
+ return createHash3("sha256").update(JSON.stringify(config2)).digest("hex");
10690
11035
  }
10691
11036
  function collectProxyGroups(root) {
10692
11037
  const groups = [];
@@ -10706,13 +11051,13 @@ function collectProxyGroups(root) {
10706
11051
  function findProjectRoot(from = process.cwd()) {
10707
11052
  let current = process.cwd();
10708
11053
  if (from !== current) {
10709
- current = path11.resolve(from);
11054
+ current = path12.resolve(from);
10710
11055
  }
10711
11056
  while (true) {
10712
- if (existsSync2(path11.join(current, "package.json"))) {
11057
+ if (existsSync2(path12.join(current, "package.json"))) {
10713
11058
  return current;
10714
11059
  }
10715
- const parent = path11.dirname(current);
11060
+ const parent = path12.dirname(current);
10716
11061
  if (parent === current) {
10717
11062
  return void 0;
10718
11063
  }
@@ -10729,7 +11074,7 @@ function resolveCachePath(name, projectRoot) {
10729
11074
  if (name.length === 0 || name === "." || name === ".." || name.includes("/") || name.includes("\\")) {
10730
11075
  throw new Error(`MCP proxy group name must be a file-safe name: "${name}".`);
10731
11076
  }
10732
- return path11.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
11077
+ return path12.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
10733
11078
  }
10734
11079
  async function assertCachePathHasNoSymlinks(filePath) {
10735
11080
  let currentPath = filePath;
@@ -10743,10 +11088,10 @@ async function assertCachePathHasNoSymlinks(filePath) {
10743
11088
  throw error3;
10744
11089
  }
10745
11090
  }
10746
- if (path11.basename(currentPath) === ".toolcraft") {
11091
+ if (path12.basename(currentPath) === ".toolcraft") {
10747
11092
  return;
10748
11093
  }
10749
- const parentPath = path11.dirname(currentPath);
11094
+ const parentPath = path12.dirname(currentPath);
10750
11095
  if (parentPath === currentPath) {
10751
11096
  return;
10752
11097
  }
@@ -10764,20 +11109,20 @@ function parseRefreshEnv(value) {
10764
11109
  const names = trimmed.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
10765
11110
  return names.length === 0 ? void 0 : new Set(names);
10766
11111
  }
10767
- async function dialUpstream(name, config) {
11112
+ async function dialUpstream(name, config2) {
10768
11113
  const client = new McpClient({
10769
11114
  clientInfo: {
10770
11115
  name: `${DEFAULT_CLIENT_INFO.name}-${name}`,
10771
11116
  version: DEFAULT_CLIENT_INFO.version
10772
11117
  }
10773
11118
  });
10774
- const transport = config.transport === "stdio" ? new StdioTransport({
10775
- command: config.command,
10776
- ...config.args === void 0 ? {} : { args: config.args },
10777
- ...config.env === void 0 ? {} : { env: config.env }
11119
+ const transport = config2.transport === "stdio" ? new StdioTransport({
11120
+ command: config2.command,
11121
+ ...config2.args === void 0 ? {} : { args: config2.args },
11122
+ ...config2.env === void 0 ? {} : { env: config2.env }
10778
11123
  }) : new HttpTransport({
10779
- url: config.url,
10780
- ...config.headers === void 0 ? {} : { headers: config.headers }
11124
+ url: config2.url,
11125
+ ...config2.headers === void 0 ? {} : { headers: config2.headers }
10781
11126
  });
10782
11127
  await client.connect(transport);
10783
11128
  return client;
@@ -10787,10 +11132,82 @@ async function resolveMcpProxies(root, options = {}) {
10787
11132
  await Promise.all(groups.map((group) => resolveSingleProxy(group, options)));
10788
11133
  }
10789
11134
 
11135
+ // ../toolcraft/src/redaction.ts
11136
+ var REDACTED_VALUE = "<redacted>";
11137
+ var SENSITIVE_NAME_PARTS = ["password", "token", "apikey", "secret"];
11138
+ var AUTHORIZATION_HEADER_NAMES = /* @__PURE__ */ new Set(["authorization", "proxyauthorization"]);
11139
+ var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set(["cookie", "setcookie"]);
11140
+ function isPlainObject2(value) {
11141
+ return typeof value === "object" && value !== null && !Array.isArray(value);
11142
+ }
11143
+ function normalizeName(name) {
11144
+ return name.toLowerCase().replace(/[^a-z0-9]/g, "");
11145
+ }
11146
+ function isSensitiveName(name) {
11147
+ const normalized = normalizeName(name);
11148
+ return SENSITIVE_NAME_PARTS.some((candidate) => normalized.includes(candidate));
11149
+ }
11150
+ function redactSecretLikeFieldsValue(value, name, seen) {
11151
+ if (name.length > 0 && isSensitiveName(name)) {
11152
+ return REDACTED_VALUE;
11153
+ }
11154
+ if (Array.isArray(value)) {
11155
+ if (seen.has(value)) {
11156
+ return "[Circular]";
11157
+ }
11158
+ seen.add(value);
11159
+ return value.map((entry) => redactSecretLikeFieldsValue(entry, name, seen));
11160
+ }
11161
+ if (isPlainObject2(value)) {
11162
+ if (seen.has(value)) {
11163
+ return "[Circular]";
11164
+ }
11165
+ seen.add(value);
11166
+ return Object.fromEntries(
11167
+ Object.entries(value).map(([key2, entry]) => [
11168
+ key2,
11169
+ redactSecretLikeFieldsValue(entry, key2, seen)
11170
+ ])
11171
+ );
11172
+ }
11173
+ return value;
11174
+ }
11175
+ function redactSecretLikeFields(value, name = "") {
11176
+ return redactSecretLikeFieldsValue(value, name, /* @__PURE__ */ new WeakSet());
11177
+ }
11178
+ function parseJsonObjectOrArray(value) {
11179
+ const trimmed = value.trim();
11180
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
11181
+ return void 0;
11182
+ }
11183
+ try {
11184
+ const parsed = JSON.parse(trimmed);
11185
+ return isPlainObject2(parsed) || Array.isArray(parsed) ? parsed : void 0;
11186
+ } catch {
11187
+ return void 0;
11188
+ }
11189
+ }
11190
+ function redactHttpBody(body) {
11191
+ if (typeof body === "string") {
11192
+ const parsed = parseJsonObjectOrArray(body);
11193
+ return parsed === void 0 ? body : redactSecretLikeFields(parsed);
11194
+ }
11195
+ return redactSecretLikeFields(body);
11196
+ }
11197
+ function redactHttpHeaderValue(name, value) {
11198
+ const normalized = normalizeName(name);
11199
+ if (AUTHORIZATION_HEADER_NAMES.has(normalized)) {
11200
+ return "Bearer ****";
11201
+ }
11202
+ if (SECRET_HEADER_NAMES.has(normalized) || isSensitiveName(name)) {
11203
+ return REDACTED_VALUE;
11204
+ }
11205
+ return value;
11206
+ }
11207
+
10790
11208
  // ../toolcraft/src/error-report.ts
10791
11209
  var ERROR_REPORTS_ENV = "TOOLCRAFT_ERROR_REPORTS";
10792
- var DEFAULT_SENSITIVE_NAMES = ["password", "token", "apikey", "secret"];
10793
- function isPlainObject2(value) {
11210
+ function isPlainObject3(value) {
10794
11211
  return typeof value === "object" && value !== null && !Array.isArray(value);
10795
11212
  }
10796
11213
  function unwrapOptional(schema) {
@@ -10800,7 +11217,7 @@ function unwrapOptional(schema) {
10800
11217
  return schema;
10801
11218
  }
10802
11219
  function hasHttpContext(error3) {
10803
- return error3 instanceof Error && error3.name === "HttpError" && isPlainObject2(error3.request) && isPlainObject2(error3.response);
11220
+ return error3 instanceof Error && error3.name === "HttpError" && isPlainObject3(error3.request) && isPlainObject3(error3.response);
10804
11221
  }
10805
11222
  function isSkippedError(error3) {
10806
11223
  if (error3 instanceof ApprovalDeclinedError) {
@@ -10820,25 +11237,25 @@ function reportsEnabled(option, env) {
10820
11237
  function resolveReportDir(option, projectRoot) {
10821
11238
  const configuredDir = typeof option === "object" ? option.dir : void 0;
10822
11239
  if (configuredDir === void 0 || configuredDir.length === 0) {
10823
- return path12.join(projectRoot, ".toolcraft", "errors");
11240
+ return path13.join(projectRoot, ".toolcraft", "errors");
10824
11241
  }
10825
- return path12.isAbsolute(configuredDir) ? configuredDir : path12.join(projectRoot, configuredDir);
11242
+ return path13.isAbsolute(configuredDir) ? configuredDir : path13.join(projectRoot, configuredDir);
10826
11243
  }
10827
11244
  function reportDirMustStayWithinProject(option) {
10828
11245
  const configuredDir = typeof option === "object" ? option.dir : void 0;
10829
- return configuredDir === void 0 || configuredDir.length === 0 || !path12.isAbsolute(configuredDir);
11246
+ return configuredDir === void 0 || configuredDir.length === 0 || !path13.isAbsolute(configuredDir);
10830
11247
  }
10831
11248
  function isWithinDirectory(parent, child) {
10832
- const relative = path12.relative(parent, child);
10833
- return relative === "" || !path12.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path12.sep}`);
11249
+ const relative = path13.relative(parent, child);
11250
+ return relative === "" || !path13.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path13.sep}`);
10834
11251
  }
10835
11252
  async function assertReportDirWithinProject(projectRoot, reportDir) {
10836
- if (!isWithinDirectory(path12.resolve(projectRoot), path12.resolve(reportDir))) {
11253
+ if (!isWithinDirectory(path13.resolve(projectRoot), path13.resolve(reportDir))) {
10837
11254
  throw new Error("Error report directory resolves outside project root.");
10838
11255
  }
10839
11256
  const [canonicalProjectRoot, canonicalReportDir] = await Promise.all([
10840
- realpath(projectRoot),
10841
- realpath(reportDir)
11257
+ realpath2(projectRoot),
11258
+ realpath2(reportDir)
10842
11259
  ]);
10843
11260
  if (!isWithinDirectory(canonicalProjectRoot, canonicalReportDir)) {
10844
11261
  throw new Error("Error report directory resolves outside project root.");
@@ -10884,7 +11301,7 @@ function slugifyCommandPath(commandPath) {
10884
11301
  return output.length === 0 ? "root" : output;
10885
11302
  }
10886
11303
  function relativeDisplayPath(projectRoot, absolutePath) {
10887
- const relative = path12.relative(projectRoot, absolutePath);
11304
+ const relative = path13.relative(projectRoot, absolutePath);
10888
11305
  return relative.length === 0 || relative.startsWith("..") ? absolutePath : relative;
10889
11306
  }
10890
11307
  function redactValue(value) {
@@ -10893,9 +11310,24 @@ function redactValue(value) {
10893
11310
  }
10894
11311
  return `<set, ${value.length} chars>`;
10895
11312
  }
10896
- function isSensitiveName(name) {
10897
- const normalized = name.toLowerCase();
10898
- return DEFAULT_SENSITIVE_NAMES.some((candidate) => normalized.includes(candidate));
11313
+ function collectStringLeaves(value, output) {
11314
+ if (typeof value === "string") {
11315
+ if (value.length > 0) {
11316
+ output.add(value);
11317
+ }
11318
+ return;
11319
+ }
11320
+ if (Array.isArray(value)) {
11321
+ for (const entry of value) {
11322
+ collectStringLeaves(entry, output);
11323
+ }
11324
+ return;
11325
+ }
11326
+ if (isPlainObject3(value)) {
11327
+ for (const entry of Object.values(value)) {
11328
+ collectStringLeaves(entry, output);
11329
+ }
11330
+ }
10899
11331
  }
10900
11332
  function schemaSecretValue(schema) {
10901
11333
  const unwrapped = unwrapOptional(schema);
@@ -10916,7 +11348,7 @@ function redactParamsValue(value, schema, name) {
10916
11348
  return "<redacted>";
10917
11349
  }
10918
11350
  const unwrapped = unwrapOptional(schema);
10919
- if (unwrapped.kind === "object" && isPlainObject2(value)) {
11351
+ if (unwrapped.kind === "object" && isPlainObject3(value)) {
10920
11352
  return Object.fromEntries(
10921
11353
  Object.entries(value).map(([key2, childValue]) => {
10922
11354
  const childSchema = unwrapped.shape[key2];
@@ -10938,6 +11370,52 @@ function redactParams(params17, command) {
10938
11370
  }
10939
11371
  return redactParamsValue(params17, command.params, "");
10940
11372
  }
11373
+ function collectSensitiveParamValues(value, schema, name, output) {
11374
+ if (shouldRedactParam(name, schema)) {
11375
+ collectStringLeaves(value, output);
11376
+ return;
11377
+ }
11378
+ const unwrapped = unwrapOptional(schema);
11379
+ if (unwrapped.kind === "object" && isPlainObject3(value)) {
11380
+ for (const [key2, childValue] of Object.entries(value)) {
11381
+ const childSchema = unwrapped.shape[key2];
11382
+ if (childSchema !== void 0) {
11383
+ collectSensitiveParamValues(childValue, childSchema, key2, output);
11384
+ }
11385
+ }
11386
+ return;
11387
+ }
11388
+ if (unwrapped.kind === "array" && Array.isArray(value)) {
11389
+ for (const entry of value) {
11390
+ collectSensitiveParamValues(entry, unwrapped.item, name, output);
11391
+ }
11392
+ }
11393
+ }
11394
+ function createReportStringRedactor(context, env) {
11395
+ const values = /* @__PURE__ */ new Set();
11396
+ for (const value of Object.values(context.secrets ?? {})) {
11397
+ if (value !== void 0 && value.length > 0) {
11398
+ values.add(value);
11399
+ }
11400
+ }
11401
+ for (const [name, secret] of Object.entries(context.command?.secrets ?? {})) {
11402
+ const value = context.secrets?.[name] ?? env[secret.env];
11403
+ if (value !== void 0 && value.length > 0) {
11404
+ values.add(value);
11405
+ }
11406
+ }
11407
+ if (context.command !== void 0) {
11408
+ collectSensitiveParamValues(context.params, context.command.params, "", values);
11409
+ }
11410
+ const orderedValues = [...values].sort((left, right) => right.length - left.length);
11411
+ return (value) => {
11412
+ let redacted = value;
11413
+ for (const secretValue of orderedValues) {
11414
+ redacted = redacted.split(secretValue).join("<redacted>");
11415
+ }
11416
+ return redacted;
11417
+ };
11418
+ }
10941
11419
  function commandSecretEnvNames(secrets) {
10942
11420
  if (secrets === void 0) {
10943
11421
  return [];
@@ -10991,28 +11469,42 @@ function redactArgv(argv, options) {
10991
11469
  function stableJson(value) {
10992
11470
  return JSON.stringify(value, null, 2) ?? "undefined";
10993
11471
  }
10994
- function redactStructuredErrorField(name, value) {
10995
- if (typeof value === "string" && name.toLowerCase() === "authorization") {
10996
- return "Bearer ****";
11472
+ function redactStructuredErrorField(name, value, redactString) {
11473
+ if (typeof value === "string") {
11474
+ const redactedHeaderValue = redactHttpHeaderValue(name, value);
11475
+ if (redactedHeaderValue !== value) {
11476
+ return redactedHeaderValue;
11477
+ }
11478
+ if (isSensitiveName(name)) {
11479
+ return "<redacted>";
11480
+ }
11481
+ return redactString(value);
10997
11482
  }
10998
11483
  if (Array.isArray(value)) {
10999
- return value.map((entry) => redactStructuredErrorField(name, entry));
11484
+ return value.map((entry) => redactStructuredErrorField(name, entry, redactString));
11000
11485
  }
11001
- if (isPlainObject2(value)) {
11486
+ if (isPlainObject3(value)) {
11002
11487
  return Object.fromEntries(
11003
- Object.entries(value).map(([key2, entry]) => [key2, redactStructuredErrorField(key2, entry)])
11488
+ Object.entries(value).map(([key2, entry]) => [
11489
+ key2,
11490
+ redactStructuredErrorField(key2, entry, redactString)
11491
+ ])
11004
11492
  );
11005
11493
  }
11006
11494
  return value;
11007
11495
  }
11008
- function ownStructuredFields(error3) {
11496
+ function ownStructuredFields(error3, redactString) {
11009
11497
  const fields = {};
11010
11498
  for (const key2 of Object.keys(error3)) {
11011
11499
  if (key2 === "name" || key2 === "message" || key2 === "stack" || key2 === "cause") {
11012
11500
  continue;
11013
11501
  }
11014
11502
  Object.defineProperty(fields, key2, {
11015
- value: redactStructuredErrorField(key2, error3[key2]),
11503
+ value: redactStructuredErrorField(
11504
+ key2,
11505
+ error3[key2],
11506
+ redactString
11507
+ ),
11016
11508
  enumerable: true,
11017
11509
  configurable: true,
11018
11510
  writable: true
@@ -11020,43 +11512,44 @@ function ownStructuredFields(error3) {
11020
11512
  }
11021
11513
  return fields;
11022
11514
  }
11023
- function formatStackChain(error3) {
11515
+ function formatStackChain(error3, redactString) {
11024
11516
  const lines = [];
11025
11517
  let current = error3;
11026
11518
  let index = 0;
11027
11519
  while (current !== void 0) {
11028
11520
  if (current instanceof Error) {
11029
- lines.push(
11030
- index === 0 ? current.stack ?? String(current) : `Caused by: ${current.stack ?? String(current)}`
11031
- );
11521
+ const stack = current.stack ?? String(current);
11522
+ lines.push(redactString(index === 0 ? stack : `Caused by: ${stack}`));
11032
11523
  current = current.cause;
11033
11524
  } else {
11034
- lines.push(index === 0 ? String(current) : `Caused by: ${String(current)}`);
11525
+ const message2 = String(current);
11526
+ lines.push(redactString(index === 0 ? message2 : `Caused by: ${message2}`));
11035
11527
  current = void 0;
11036
11528
  }
11037
11529
  index += 1;
11038
11530
  }
11039
11531
  return lines.join("\n");
11040
11532
  }
11041
- function formatHeaderValue(name, value) {
11042
- return name.toLowerCase() === "authorization" ? "Bearer ****" : value;
11533
+ function formatHeaderValue(name, value, redactString) {
11534
+ return redactString(redactHttpHeaderValue(name, value));
11043
11535
  }
11044
- function formatHeaders(headers) {
11045
- return Object.entries(headers).map(([name, value]) => `${name}: ${formatHeaderValue(name, value)}`).join("\n");
11536
+ function formatHeaders(headers, redactString) {
11537
+ return Object.entries(headers).map(([name, value]) => `${name}: ${formatHeaderValue(name, value, redactString)}`).join("\n");
11046
11538
  }
11047
- function formatBody(body) {
11048
- if (typeof body === "string") {
11049
- return body;
11539
+ function formatBody(body, redactString) {
11540
+ const redactedBody = redactHttpBody(body);
11541
+ if (typeof redactedBody === "string") {
11542
+ return redactString(redactedBody);
11050
11543
  }
11051
- return stableJson(body);
11544
+ return redactString(stableJson(redactedBody));
11052
11545
  }
11053
- function formatHttpTranscript(error3) {
11546
+ function formatHttpTranscript(error3, redactString) {
11054
11547
  const requestLines = [
11055
11548
  `${error3.request.method} ${error3.request.url}`,
11056
- formatHeaders(error3.request.headers)
11549
+ formatHeaders(error3.request.headers, redactString)
11057
11550
  ].filter((line) => line.length > 0);
11058
11551
  if (error3.request.body !== void 0) {
11059
- requestLines.push("", formatBody(error3.request.body));
11552
+ requestLines.push("", formatBody(error3.request.body, redactString));
11060
11553
  }
11061
11554
  return [
11062
11555
  "Request:",
@@ -11064,9 +11557,9 @@ function formatHttpTranscript(error3) {
11064
11557
  "",
11065
11558
  "Response:",
11066
11559
  `${error3.response.status} ${error3.response.statusText}`,
11067
- formatHeaders(error3.response.headers),
11560
+ formatHeaders(error3.response.headers, redactString),
11068
11561
  "",
11069
- formatBody(error3.response.body)
11562
+ formatBody(error3.response.body, redactString)
11070
11563
  ].join("\n");
11071
11564
  }
11072
11565
  function resolveToolcraftVersion(version) {
@@ -11075,9 +11568,10 @@ function resolveToolcraftVersion(version) {
11075
11568
  function buildReport(context) {
11076
11569
  const env = context.env ?? process.env;
11077
11570
  const error3 = context.error;
11571
+ const redactString = createReportStringRedactor(context, env);
11078
11572
  const errorName = error3 instanceof Error ? error3.name : typeof error3;
11079
- const errorMessage = error3 instanceof Error ? error3.message : String(error3);
11080
- const structuredFields = error3 instanceof Error ? ownStructuredFields(error3) : {};
11573
+ const errorMessage = redactString(error3 instanceof Error ? error3.message : String(error3));
11574
+ const structuredFields = error3 instanceof Error ? ownStructuredFields(error3, redactString) : {};
11081
11575
  const secretLines = Object.entries(context.command?.secrets ?? {}).map(([name, secret]) => {
11082
11576
  const value = context.secrets?.[name] ?? env[secret.env];
11083
11577
  return `${secret.env}=${redactValue(value)}`;
@@ -11091,7 +11585,9 @@ function buildReport(context) {
11091
11585
  `platform: ${process.platform} ${process.arch}`,
11092
11586
  "",
11093
11587
  "Argv",
11094
- stableJson(redactArgv(context.argv, { command: context.command, secrets: context.secrets })),
11588
+ redactString(
11589
+ stableJson(redactArgv(context.argv, { command: context.command, secrets: context.secrets }))
11590
+ ),
11095
11591
  "",
11096
11592
  "Resolved Secrets",
11097
11593
  ...secretLines.length === 0 ? ["<none>"] : secretLines,
@@ -11100,19 +11596,19 @@ function buildReport(context) {
11100
11596
  context.commandPath === void 0 || context.commandPath.length === 0 ? "root" : context.commandPath,
11101
11597
  "",
11102
11598
  "Parsed Params",
11103
- stableJson(redactParams(context.params, context.command)),
11599
+ redactString(stableJson(redactParams(context.params, context.command))),
11104
11600
  "",
11105
11601
  "Error",
11106
11602
  `name: ${errorName}`,
11107
11603
  `message: ${errorMessage}`,
11108
11604
  "structured fields:",
11109
- stableJson(structuredFields),
11605
+ redactString(stableJson(structuredFields)),
11110
11606
  "",
11111
11607
  "Stack",
11112
- formatStackChain(error3)
11608
+ formatStackChain(error3, redactString)
11113
11609
  ];
11114
11610
  if (hasHttpContext(error3)) {
11115
- lines.push("", "HTTP Transcript", formatHttpTranscript(error3));
11611
+ lines.push("", "HTTP Transcript", formatHttpTranscript(error3, redactString));
11116
11612
  }
11117
11613
  return `${lines.join("\n")}
11118
11614
  `;
@@ -11124,8 +11620,8 @@ async function writeErrorReport(context) {
11124
11620
  }
11125
11621
  const projectRoot = resolveProjectRoot(context.projectRoot);
11126
11622
  const reportDir = resolveReportDir(context.errorReports, projectRoot);
11127
- const fileName = `${formatTimestamp(/* @__PURE__ */ new Date())}-${slugifyCommandPath(context.commandPath)}-${randomUUID2()}.log`;
11128
- const absolutePath = path12.join(reportDir, fileName);
11623
+ const fileName = `${formatTimestamp(/* @__PURE__ */ new Date())}-${slugifyCommandPath(context.commandPath)}-${randomUUID3()}.log`;
11624
+ const absolutePath = path13.join(reportDir, fileName);
11129
11625
  await mkdir2(reportDir, { recursive: true });
11130
11626
  if (reportDirMustStayWithinProject(context.errorReports)) {
11131
11627
  await assertReportDirWithinProject(projectRoot, reportDir);
@@ -11572,6 +12068,7 @@ ${rendered.join("\n")}`);
11572
12068
  }
11573
12069
 
11574
12070
  // ../toolcraft/src/cli.ts
12071
+ configureTheme({ brand: "blue", label: "Toolcraft" });
11575
12072
  var RESERVED_SERVICE_NAMES = /* @__PURE__ */ new Set([
11576
12073
  "params",
11577
12074
  "secrets",
@@ -11589,7 +12086,7 @@ function inferProgramName(argv) {
11589
12086
  if (typeof entrypoint !== "string" || entrypoint.length === 0) {
11590
12087
  return "toolcraft";
11591
12088
  }
11592
- const parsed = path13.parse(entrypoint);
12089
+ const parsed = path14.parse(entrypoint);
11593
12090
  return parsed.name.length > 0 ? parsed.name : "toolcraft";
11594
12091
  }
11595
12092
  function normalizeRoots(roots, argv) {
@@ -11647,11 +12144,11 @@ function formatSegment(segment, casing) {
11647
12144
  const separator = casing === "snake" ? "_" : "-";
11648
12145
  return splitWords3(segment).join(separator);
11649
12146
  }
11650
- function toOptionFlag(path24, casing) {
11651
- return `--${path24.map((segment) => formatSegment(segment, casing)).join(".")}`;
12147
+ function toOptionFlag(path25, casing) {
12148
+ return `--${path25.map((segment) => formatSegment(segment, casing)).join(".")}`;
11652
12149
  }
11653
- function toOptionAttribute(path24, casing) {
11654
- return path24.map((segment) => {
12150
+ function toOptionAttribute(path25, casing) {
12151
+ return path25.map((segment) => {
11655
12152
  const formatted = formatSegment(segment, casing);
11656
12153
  if (casing === "snake") {
11657
12154
  return formatted;
@@ -11662,23 +12159,23 @@ function toOptionAttribute(path24, casing) {
11662
12159
  ).join("");
11663
12160
  }).join(".");
11664
12161
  }
11665
- function toDisplayPath(path24) {
11666
- return path24.join(".");
12162
+ function toDisplayPath(path25) {
12163
+ return path25.join(".");
11667
12164
  }
11668
- function toUnionKindControlPath(path24) {
11669
- if (path24.length === 0) {
12165
+ function toUnionKindControlPath(path25) {
12166
+ if (path25.length === 0) {
11670
12167
  return ["kind"];
11671
12168
  }
11672
- const head = path24.slice(0, -1);
11673
- const tail = path24[path24.length - 1] ?? "";
12169
+ const head = path25.slice(0, -1);
12170
+ const tail = path25[path25.length - 1] ?? "";
11674
12171
  return [...head, `${tail}Kind`];
11675
12172
  }
11676
- function toUnionKindDisplayPath(path24) {
11677
- if (path24.length === 0) {
12173
+ function toUnionKindDisplayPath(path25) {
12174
+ if (path25.length === 0) {
11678
12175
  return "kind";
11679
12176
  }
11680
- const head = path24.slice(0, -1);
11681
- const tail = path24[path24.length - 1] ?? "";
12177
+ const head = path25.slice(0, -1);
12178
+ const tail = path25[path25.length - 1] ?? "";
11682
12179
  return [...head, `${tail}-kind`].join(".");
11683
12180
  }
11684
12181
  function createSyntheticEnumSchema(values) {
@@ -11694,14 +12191,14 @@ function getRequiredBranchFingerprint(branch, casing) {
11694
12191
  const requiredKeys = Object.entries(branch.shape).filter(([, schema]) => schema.kind !== "optional").map(([key2]) => formatSegment(key2, casing)).sort();
11695
12192
  return requiredKeys.join("+");
11696
12193
  }
11697
- function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inheritedOptional = false, variantContext) {
12194
+ function collectFields(schema, casing, globalLongOptionFlags, path25 = [], inheritedOptional = false, variantContext) {
11698
12195
  const collected = {
11699
12196
  dynamicFields: [],
11700
12197
  fields: [],
11701
12198
  variants: []
11702
12199
  };
11703
12200
  for (const [key2, rawChildSchema] of Object.entries(schema.shape)) {
11704
- const nextPath = [...path24, key2];
12201
+ const nextPath = [...path25, key2];
11705
12202
  const runtimeOptional = inheritedOptional || rawChildSchema.kind === "optional";
11706
12203
  const childSchema = unwrapOptional2(rawChildSchema);
11707
12204
  const requiredWhenActive = rawChildSchema.kind !== "optional" && childSchema.default === void 0;
@@ -11882,9 +12379,9 @@ function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inher
11882
12379
  }
11883
12380
  return collected;
11884
12381
  }
11885
- function toCommanderOptionAttribute(path24, casing, globalLongOptionFlags) {
11886
- const optionAttribute = toOptionAttribute(path24, casing);
11887
- const optionFlag = toOptionFlag(path24, casing);
12382
+ function toCommanderOptionAttribute(path25, casing, globalLongOptionFlags) {
12383
+ const optionAttribute = toOptionAttribute(path25, casing);
12384
+ const optionFlag = toOptionFlag(path25, casing);
11888
12385
  if (!globalLongOptionFlags.has(optionFlag)) {
11889
12386
  return optionAttribute;
11890
12387
  }
@@ -12853,10 +13350,10 @@ function parseDebugStackMode(value) {
12853
13350
  formatInvalidEnumMessage("--debug", String(value), ["raw"], { candidates: ["raw"] })
12854
13351
  );
12855
13352
  }
12856
- function setNestedValue(target, path24, value) {
13353
+ function setNestedValue(target, path25, value) {
12857
13354
  let cursor = target;
12858
- for (let index = 0; index < path24.length - 1; index += 1) {
12859
- const segment = path24[index] ?? "";
13355
+ for (let index = 0; index < path25.length - 1; index += 1) {
13356
+ const segment = path25[index] ?? "";
12860
13357
  const existing = Object.prototype.hasOwnProperty.call(cursor, segment) ? cursor[segment] : void 0;
12861
13358
  if (typeof existing === "object" && existing !== null) {
12862
13359
  cursor = existing;
@@ -12871,7 +13368,7 @@ function setNestedValue(target, path24, value) {
12871
13368
  });
12872
13369
  cursor = next;
12873
13370
  }
12874
- const leaf = path24[path24.length - 1];
13371
+ const leaf = path25[path25.length - 1];
12875
13372
  if (leaf !== void 0) {
12876
13373
  Object.defineProperty(cursor, leaf, {
12877
13374
  value,
@@ -12981,21 +13478,21 @@ async function withOutputFormat2(output, fn) {
12981
13478
  }
12982
13479
  function createFs2() {
12983
13480
  return {
12984
- readFile: async (path24, encoding = "utf8") => readFile4(path24, { encoding }),
12985
- writeFile: async (path24, contents) => {
12986
- await writeFile5(path24, contents);
13481
+ readFile: async (path25, encoding = "utf8") => readFile4(path25, { encoding }),
13482
+ writeFile: async (path25, contents) => {
13483
+ await writeFile5(path25, contents);
12987
13484
  },
12988
- exists: async (path24) => {
13485
+ exists: async (path25) => {
12989
13486
  try {
12990
- await access2(path24);
13487
+ await access2(path25);
12991
13488
  return true;
12992
13489
  } catch {
12993
13490
  return false;
12994
13491
  }
12995
13492
  },
12996
- lstat: async (path24) => lstat3(path24),
13493
+ lstat: async (path25) => lstat3(path25),
12997
13494
  rename: async (fromPath, toPath) => rename3(fromPath, toPath),
12998
- unlink: async (path24) => unlink2(path24)
13495
+ unlink: async (path25) => unlink2(path25)
12999
13496
  };
13000
13497
  }
13001
13498
  function createEnv2(values = process.env) {
@@ -13005,15 +13502,15 @@ function createEnv2(values = process.env) {
13005
13502
  }
13006
13503
  };
13007
13504
  }
13008
- function isPlainObject3(value) {
13505
+ function isPlainObject4(value) {
13009
13506
  return typeof value === "object" && value !== null && !Array.isArray(value);
13010
13507
  }
13011
13508
  function hasFieldValue(value) {
13012
13509
  return value !== void 0;
13013
13510
  }
13014
- function hasNestedField(fields, path24) {
13511
+ function hasNestedField(fields, path25) {
13015
13512
  return fields.some(
13016
- (field) => path24.length < field.path.length && path24.every((segment, index) => field.path[index] === segment)
13513
+ (field) => path25.length < field.path.length && path25.every((segment, index) => field.path[index] === segment)
13017
13514
  );
13018
13515
  }
13019
13516
  function describeExpectedPresetValue(schema) {
@@ -13114,14 +13611,14 @@ async function loadPresetValues(fields, presetPath) {
13114
13611
  { cause: error3 }
13115
13612
  );
13116
13613
  }
13117
- if (!isPlainObject3(parsedPreset)) {
13614
+ if (!isPlainObject4(parsedPreset)) {
13118
13615
  throw new UserError(`Preset file "${presetPath}" must contain a JSON object.`);
13119
13616
  }
13120
13617
  const fieldByPath = new Map(fields.map((field) => [field.displayPath, field]));
13121
13618
  const presetValues = {};
13122
- function visitObject(current, path24) {
13619
+ function visitObject(current, path25) {
13123
13620
  for (const [key2, value] of Object.entries(current)) {
13124
- const nextPath = [...path24, key2];
13621
+ const nextPath = [...path25, key2];
13125
13622
  const displayPath = toDisplayPath(nextPath);
13126
13623
  const field = fieldByPath.get(displayPath);
13127
13624
  if (field !== void 0) {
@@ -13133,7 +13630,7 @@ async function loadPresetValues(fields, presetPath) {
13133
13630
  `Preset file "${presetPath}" contains unknown parameter "${displayPath}".`
13134
13631
  );
13135
13632
  }
13136
- if (!isPlainObject3(value)) {
13633
+ if (!isPlainObject4(value)) {
13137
13634
  throw new UserError(
13138
13635
  `Preset file "${presetPath}" has an invalid value for "${displayPath}". Expected an object, got ${describeReceived(value)}.`
13139
13636
  );
@@ -13176,8 +13673,8 @@ function matchesFixtureValue(expected, actual) {
13176
13673
  }
13177
13674
  return expected.every((item, index) => matchesFixtureValue(item, actual[index]));
13178
13675
  }
13179
- if (isPlainObject3(expected)) {
13180
- if (!isPlainObject3(actual)) {
13676
+ if (isPlainObject4(expected)) {
13677
+ if (!isPlainObject4(actual)) {
13181
13678
  return false;
13182
13679
  }
13183
13680
  return Object.entries(expected).every(
@@ -13240,9 +13737,9 @@ function createFixtureFetch(entries) {
13240
13737
  };
13241
13738
  }
13242
13739
  function createFixtureFs(definition) {
13243
- const fsDefinition = isPlainObject3(definition) ? definition : {};
13244
- const readFileEntries = isPlainObject3(fsDefinition.readFile) ? fsDefinition.readFile : {};
13245
- const existsEntries = isPlainObject3(fsDefinition.exists) ? fsDefinition.exists : {};
13740
+ const fsDefinition = isPlainObject4(definition) ? definition : {};
13741
+ const readFileEntries = isPlainObject4(fsDefinition.readFile) ? fsDefinition.readFile : {};
13742
+ const existsEntries = isPlainObject4(fsDefinition.exists) ? fsDefinition.exists : {};
13246
13743
  return {
13247
13744
  readFile: async (filePath) => {
13248
13745
  if (Object.prototype.hasOwnProperty.call(readFileEntries, filePath)) {
@@ -13265,10 +13762,10 @@ function createFixtureFs(definition) {
13265
13762
  function resolveFixtureMethodResult(methodName, definition, args) {
13266
13763
  if (Array.isArray(definition)) {
13267
13764
  for (const entry of definition) {
13268
- if (!isPlainObject3(entry)) {
13765
+ if (!isPlainObject4(entry)) {
13269
13766
  continue;
13270
13767
  }
13271
- const explicitMatcher = isPlainObject3(entry.request) ? entry.request : void 0;
13768
+ const explicitMatcher = isPlainObject4(entry.request) ? entry.request : void 0;
13272
13769
  const matcher = explicitMatcher ?? Object.fromEntries(
13273
13770
  Object.entries(entry).filter(
13274
13771
  ([key2]) => key2 !== "result" && key2 !== "response" && key2 !== "error"
@@ -13280,7 +13777,7 @@ function resolveFixtureMethodResult(methodName, definition, args) {
13280
13777
  matched = matchesFixtureValue(matcher.args, args);
13281
13778
  } else if (Object.keys(matcher).length === 0) {
13282
13779
  matched = true;
13283
- } else if (isPlainObject3(firstArg)) {
13780
+ } else if (isPlainObject4(firstArg)) {
13284
13781
  matched = matchesFixtureValue(matcher, firstArg);
13285
13782
  } else if (args.length === 1 && Object.keys(matcher).length === 1) {
13286
13783
  const [[, expectedValue]] = Object.entries(matcher);
@@ -13301,7 +13798,7 @@ function resolveFixtureMethodResult(methodName, definition, args) {
13301
13798
  return Promise.resolve(null);
13302
13799
  }
13303
13800
  }
13304
- if (isPlainObject3(definition)) {
13801
+ if (isPlainObject4(definition)) {
13305
13802
  const firstArg = args[0];
13306
13803
  if (typeof firstArg === "string" && Object.prototype.hasOwnProperty.call(definition, firstArg)) {
13307
13804
  return Promise.resolve(definition[firstArg]);
@@ -13313,7 +13810,7 @@ function resolveFixtureMethodResult(methodName, definition, args) {
13313
13810
  return Promise.resolve(null);
13314
13811
  }
13315
13812
  function createFixtureService(definition) {
13316
- const methods = isPlainObject3(definition) ? definition : {};
13813
+ const methods = isPlainObject4(definition) ? definition : {};
13317
13814
  return new Proxy(
13318
13815
  {},
13319
13816
  {
@@ -13328,8 +13825,8 @@ function createFixtureService(definition) {
13328
13825
  );
13329
13826
  }
13330
13827
  function resolveFixturePath(commandPath) {
13331
- const parsed = path13.parse(commandPath);
13332
- return path13.join(parsed.dir, `${parsed.name}.fixture.json`);
13828
+ const parsed = path14.parse(commandPath);
13829
+ return path14.join(parsed.dir, `${parsed.name}.fixture.json`);
13333
13830
  }
13334
13831
  function selectFixtureScenario(scenarios, selector, fixturePath) {
13335
13832
  if (isNumericFixtureSelector(selector)) {
@@ -13411,7 +13908,7 @@ async function resolveFixtureRuntime(command, services, requirementOptions) {
13411
13908
  };
13412
13909
  }
13413
13910
  const scenario = await loadFixtureScenario(command, selector);
13414
- const scenarioServices = isPlainObject3(scenario.services) ? scenario.services : {};
13911
+ const scenarioServices = isPlainObject4(scenario.services) ? scenario.services : {};
13415
13912
  const customServiceNames = /* @__PURE__ */ new Set([
13416
13913
  ...Object.keys(services),
13417
13914
  ...Object.keys(scenarioServices).filter((name) => !RESERVED_SERVICE_NAMES.has(name))
@@ -13463,8 +13960,8 @@ function validateServices(services) {
13463
13960
  }
13464
13961
  }
13465
13962
  }
13466
- function getNestedValue(target, path24) {
13467
- return path24.reduce(
13963
+ function getNestedValue(target, path25) {
13964
+ return path25.reduce(
13468
13965
  (current, segment) => current !== null && typeof current === "object" ? current[segment] : void 0,
13469
13966
  target
13470
13967
  );
@@ -13693,7 +14190,7 @@ function finalizeDynamicValue(schema, value, displayPath, errors2) {
13693
14190
  if (itemSchema.kind !== "object") {
13694
14191
  return value;
13695
14192
  }
13696
- if (!isPlainObject3(value)) {
14193
+ if (!isPlainObject4(value)) {
13697
14194
  errors2.push({
13698
14195
  path: displayPath,
13699
14196
  message: `Invalid value for "${displayPath}". Expected indexed object entries, got ${describeReceived(value)}.`
@@ -13728,7 +14225,7 @@ function finalizeDynamicValue(schema, value, displayPath, errors2) {
13728
14225
  );
13729
14226
  }
13730
14227
  case "object": {
13731
- if (!isPlainObject3(value)) {
14228
+ if (!isPlainObject4(value)) {
13732
14229
  errors2.push({
13733
14230
  path: displayPath,
13734
14231
  message: `Invalid value for "${displayPath}". Expected an object, got ${describeReceived(value)}.`
@@ -13759,7 +14256,7 @@ function finalizeDynamicValue(schema, value, displayPath, errors2) {
13759
14256
  return result;
13760
14257
  }
13761
14258
  case "record": {
13762
- if (!isPlainObject3(value)) {
14259
+ if (!isPlainObject4(value)) {
13763
14260
  errors2.push({
13764
14261
  path: displayPath,
13765
14262
  message: `Invalid value for "${displayPath}". Expected an object, got ${describeReceived(value)}.`
@@ -14185,10 +14682,10 @@ async function executeCommand(state, services, requirementOptions, runtimeOption
14185
14682
  }
14186
14683
  }
14187
14684
  function isStringRecord(value) {
14188
- return isPlainObject3(value) && Object.values(value).every((entry) => typeof entry === "string");
14685
+ return isPlainObject4(value) && Object.values(value).every((entry) => typeof entry === "string");
14189
14686
  }
14190
14687
  function isHttpErrorLike(error3) {
14191
- if (!isPlainObject3(error3)) {
14688
+ if (!isPlainObject4(error3)) {
14192
14689
  return false;
14193
14690
  }
14194
14691
  if (error3.name !== "HttpError" || typeof error3.message !== "string") {
@@ -14196,7 +14693,7 @@ function isHttpErrorLike(error3) {
14196
14693
  }
14197
14694
  const request = error3.request;
14198
14695
  const response = error3.response;
14199
- 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;
14696
+ 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;
14200
14697
  }
14201
14698
  function hasTypedOptionalField(value, field, type2) {
14202
14699
  return !(field in value) || typeof value[field] === type2;
@@ -14205,7 +14702,7 @@ function isNonEmptyString(value) {
14205
14702
  return typeof value === "string" && value.trim().length > 0;
14206
14703
  }
14207
14704
  function isProblemDetailsLike(body) {
14208
- if (!isPlainObject3(body)) {
14705
+ if (!isPlainObject4(body)) {
14209
14706
  return false;
14210
14707
  }
14211
14708
  if (!hasTypedOptionalField(body, "type", "string")) {
@@ -14226,11 +14723,11 @@ function isProblemDetailsLike(body) {
14226
14723
  return isNonEmptyString(body.title) || isNonEmptyString(body.detail);
14227
14724
  }
14228
14725
  function isGraphQLErrorEnvelopeLike(body) {
14229
- if (!isPlainObject3(body) || !Array.isArray(body.errors) || body.errors.length === 0) {
14726
+ if (!isPlainObject4(body) || !Array.isArray(body.errors) || body.errors.length === 0) {
14230
14727
  return false;
14231
14728
  }
14232
14729
  return body.errors.every((error3) => {
14233
- if (!isPlainObject3(error3) || typeof error3.message !== "string") {
14730
+ if (!isPlainObject4(error3) || typeof error3.message !== "string") {
14234
14731
  return false;
14235
14732
  }
14236
14733
  if ("path" in error3) {
@@ -14240,7 +14737,7 @@ function isGraphQLErrorEnvelopeLike(body) {
14240
14737
  }
14241
14738
  }
14242
14739
  if ("extensions" in error3) {
14243
- if (!isPlainObject3(error3.extensions)) {
14740
+ if (!isPlainObject4(error3.extensions)) {
14244
14741
  return false;
14245
14742
  }
14246
14743
  if ("code" in error3.extensions && typeof error3.extensions.code !== "string") {
@@ -14288,23 +14785,24 @@ function formatGraphQLErrorEnvelopeBody(body) {
14288
14785
  }).join("\n\n");
14289
14786
  }
14290
14787
  function formatHttpErrorBody(body) {
14291
- if (typeof body === "string") {
14292
- return body;
14788
+ const redactedBody = redactHttpBody(body);
14789
+ if (typeof redactedBody === "string") {
14790
+ return redactedBody;
14293
14791
  }
14294
- if (isProblemDetailsLike(body)) {
14295
- return formatProblemDetailsBody(body);
14792
+ if (isProblemDetailsLike(redactedBody)) {
14793
+ return formatProblemDetailsBody(redactedBody);
14296
14794
  }
14297
- if (isGraphQLErrorEnvelopeLike(body)) {
14298
- return formatGraphQLErrorEnvelopeBody(body);
14795
+ if (isGraphQLErrorEnvelopeLike(redactedBody)) {
14796
+ return formatGraphQLErrorEnvelopeBody(redactedBody);
14299
14797
  }
14300
- const serialized = JSON.stringify(body, null, 2);
14301
- return serialized === void 0 ? String(body) : serialized;
14798
+ const serialized = JSON.stringify(redactedBody, null, 2);
14799
+ return serialized === void 0 ? String(redactedBody) : serialized;
14302
14800
  }
14303
14801
  function indentHttpErrorBlock(value) {
14304
14802
  return value.split("\n").map((line) => ` ${line}`).join("\n");
14305
14803
  }
14306
14804
  function formatHttpHeaderValue(name, value) {
14307
- return name.toLowerCase() === "authorization" ? "Bearer ****" : value;
14805
+ return redactHttpHeaderValue(name, value);
14308
14806
  }
14309
14807
  function formatHttpErrorHeaders(headers) {
14310
14808
  return Object.entries(headers).map(
@@ -14322,7 +14820,11 @@ function renderHttpError(error3, options) {
14322
14820
  if (detailed) {
14323
14821
  lines.push("", "Request headers:", ...formatHttpErrorHeaders(error3.request.headers), "");
14324
14822
  if (error3.request.body !== void 0) {
14325
- lines.push("Request body:", indentHttpErrorBlock(formatHttpErrorBody(error3.request.body)), "");
14823
+ lines.push(
14824
+ "Request body:",
14825
+ indentHttpErrorBlock(formatHttpErrorBody(error3.request.body)),
14826
+ ""
14827
+ );
14326
14828
  }
14327
14829
  }
14328
14830
  lines.push(
@@ -14615,7 +15117,8 @@ function configureCommanderSuggestionOutput(command) {
14615
15117
  }
14616
15118
  async function runCLI(roots, options = {}) {
14617
15119
  enableSourceMaps();
14618
- const root = mergeApprovalsGroup(normalizeRoots(roots, process.argv));
15120
+ const normalizedRoot = normalizeRoots(roots, process.argv);
15121
+ const root = options.approvals === false ? normalizedRoot : mergeApprovalsGroup(normalizedRoot);
14619
15122
  await resolveMcpProxies(root, { projectRoot: options.projectRoot });
14620
15123
  const casing = options.casing ?? "kebab";
14621
15124
  const services = options.services ?? {};
@@ -14727,7 +15230,7 @@ async function runCLI(roots, options = {}) {
14727
15230
  }
14728
15231
 
14729
15232
  // src/terminal-pilot.ts
14730
- import { randomUUID as randomUUID3 } from "node:crypto";
15233
+ import { randomUUID as randomUUID4 } from "node:crypto";
14731
15234
 
14732
15235
  // src/terminal-session.ts
14733
15236
  import { EventEmitter } from "node:events";
@@ -15929,7 +16432,7 @@ var TerminalPilot = class _TerminalPilot {
15929
16432
  }
15930
16433
  async newSession(opts) {
15931
16434
  const session = new TerminalSession({
15932
- id: randomUUID3(),
16435
+ id: randomUUID4(),
15933
16436
  command: opts.command,
15934
16437
  args: opts.args,
15935
16438
  cwd: opts.cwd,
@@ -16204,7 +16707,7 @@ var getSession = defineCommand({
16204
16707
 
16205
16708
  // ../agent-skill-config/src/configs.ts
16206
16709
  import os2 from "node:os";
16207
- import path14 from "node:path";
16710
+ import path15 from "node:path";
16208
16711
 
16209
16712
  // ../agent-defs/src/agents/claude-code.ts
16210
16713
  var claudeCodeAgent = {
@@ -16410,11 +16913,11 @@ function resolveAgentSupport(input, registry = agentSkillConfigs) {
16410
16913
  if (!resolvedId) {
16411
16914
  return { status: "unknown", input };
16412
16915
  }
16413
- const config = registry[resolvedId];
16414
- if (!config) {
16916
+ const config2 = registry[resolvedId];
16917
+ if (!config2) {
16415
16918
  return { status: "unsupported", input, id: resolvedId };
16416
16919
  }
16417
- return { status: "supported", input, id: resolvedId, config: { ...config } };
16920
+ return { status: "supported", input, id: resolvedId, config: { ...config2 } };
16418
16921
  }
16419
16922
  function getAgentConfig(agentId) {
16420
16923
  const support = resolveAgentSupport(agentId);
@@ -16513,7 +17016,7 @@ var templateMutation = {
16513
17016
  };
16514
17017
 
16515
17018
  // ../config-mutations/src/execution/apply-mutation.ts
16516
- import path16 from "node:path";
17019
+ import path17 from "node:path";
16517
17020
 
16518
17021
  // ../config-mutations/src/formats/json.ts
16519
17022
  import * as jsonc from "jsonc-parser";
@@ -16551,6 +17054,13 @@ function cloneConfigValue(value) {
16551
17054
  function isConfigObject(value) {
16552
17055
  return typeof value === "object" && value !== null && !Array.isArray(value);
16553
17056
  }
17057
+ function detectIndent(content) {
17058
+ const match = content.match(/^[\t ]+/m);
17059
+ if (match) {
17060
+ return match[0];
17061
+ }
17062
+ return " ";
17063
+ }
16554
17064
  function parse3(content) {
16555
17065
  if (!content || content.trim() === "") {
16556
17066
  return {};
@@ -16590,6 +17100,9 @@ function merge(base, patch) {
16590
17100
  }
16591
17101
  return result;
16592
17102
  }
17103
+ function configValuesEqual(left, right) {
17104
+ return JSON.stringify(left) === JSON.stringify(right);
17105
+ }
16593
17106
  function prune(obj, shape) {
16594
17107
  let changed = false;
16595
17108
  const result = cloneConfigObject(obj);
@@ -16626,9 +17139,56 @@ function prune(obj, shape) {
16626
17139
  }
16627
17140
  return { changed, result };
16628
17141
  }
17142
+ function modifyAtPath(content, path25, value) {
17143
+ const indent = detectIndent(content);
17144
+ const formattingOptions = {
17145
+ tabSize: indent === " " ? 1 : indent.length,
17146
+ insertSpaces: indent !== " ",
17147
+ eol: "\n"
17148
+ };
17149
+ const edits = jsonc.modify(content, path25, value, { formattingOptions });
17150
+ let result = jsonc.applyEdits(content, edits);
17151
+ if (!result.endsWith("\n")) {
17152
+ result += "\n";
17153
+ }
17154
+ return result;
17155
+ }
17156
+ function removeAtPath(content, path25) {
17157
+ return modifyAtPath(content, path25, void 0);
17158
+ }
17159
+ function serializeUpdate(content, current, next) {
17160
+ let result = content || "{}";
17161
+ result = applyObjectUpdate(result, [], current, next);
17162
+ if (!result.endsWith("\n")) {
17163
+ result += "\n";
17164
+ }
17165
+ return result;
17166
+ }
17167
+ function applyObjectUpdate(content, path25, current, next) {
17168
+ let result = content;
17169
+ for (const key2 of Object.keys(current)) {
17170
+ if (!hasConfigEntry(next, key2)) {
17171
+ result = removeAtPath(result, [...path25, key2]);
17172
+ }
17173
+ }
17174
+ for (const [key2, nextValue] of Object.entries(next)) {
17175
+ const nextPath = [...path25, key2];
17176
+ const hasCurrent = hasConfigEntry(current, key2);
17177
+ const currentValue = hasCurrent ? current[key2] : void 0;
17178
+ if (hasCurrent && isConfigObject(currentValue) && isConfigObject(nextValue)) {
17179
+ result = applyObjectUpdate(result, nextPath, currentValue, nextValue);
17180
+ continue;
17181
+ }
17182
+ if (!hasCurrent || !configValuesEqual(currentValue, nextValue)) {
17183
+ result = modifyAtPath(result, nextPath, nextValue);
17184
+ }
17185
+ }
17186
+ return result;
17187
+ }
16629
17188
  var jsonFormat = {
16630
17189
  parse: parse3,
16631
17190
  serialize,
17191
+ serializeUpdate,
16632
17192
  merge,
16633
17193
  prune
16634
17194
  };
@@ -16812,20 +17372,20 @@ function getConfigFormat(pathOrFormat) {
16812
17372
  }
16813
17373
  return formatRegistry[formatName];
16814
17374
  }
16815
- function detectFormat(path24) {
16816
- const ext = getExtension(path24);
17375
+ function detectFormat(path25) {
17376
+ const ext = getExtension(path25);
16817
17377
  return extensionMap[ext];
16818
17378
  }
16819
- function getExtension(path24) {
16820
- const lastDot = path24.lastIndexOf(".");
17379
+ function getExtension(path25) {
17380
+ const lastDot = path25.lastIndexOf(".");
16821
17381
  if (lastDot === -1) {
16822
17382
  return "";
16823
17383
  }
16824
- return path24.slice(lastDot).toLowerCase();
17384
+ return path25.slice(lastDot).toLowerCase();
16825
17385
  }
16826
17386
 
16827
17387
  // ../config-mutations/src/execution/path-utils.ts
16828
- import path15 from "node:path";
17388
+ import path16 from "node:path";
16829
17389
  function expandHome(targetPath, homeDir) {
16830
17390
  if (!targetPath?.startsWith("~")) {
16831
17391
  return targetPath;
@@ -16842,7 +17402,7 @@ function expandHome(targetPath, homeDir) {
16842
17402
  remainder = remainder.slice(1);
16843
17403
  }
16844
17404
  }
16845
- return remainder.length === 0 ? homeDir : path15.join(homeDir, remainder);
17405
+ return remainder.length === 0 ? homeDir : path16.join(homeDir, remainder);
16846
17406
  }
16847
17407
  function validateHomePath(targetPath) {
16848
17408
  if (typeof targetPath !== "string" || targetPath.length === 0) {
@@ -16857,21 +17417,21 @@ function validateHomePath(targetPath) {
16857
17417
  function resolvePath(rawPath, homeDir, pathMapper) {
16858
17418
  validateHomePath(rawPath);
16859
17419
  const expanded = expandHome(rawPath, homeDir);
16860
- const canonicalHome = path15.resolve(homeDir);
16861
- const canonicalExpanded = path15.resolve(expanded);
16862
- const relative = path15.relative(canonicalHome, canonicalExpanded);
16863
- if (relative === ".." || relative.startsWith(`..${path15.sep}`) || path15.isAbsolute(relative)) {
17420
+ const canonicalHome = path16.resolve(homeDir);
17421
+ const canonicalExpanded = path16.resolve(expanded);
17422
+ const relative = path16.relative(canonicalHome, canonicalExpanded);
17423
+ if (relative === ".." || relative.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative)) {
16864
17424
  throw new Error(`Target path resolves outside home directory: "${rawPath}"`);
16865
17425
  }
16866
17426
  if (!pathMapper) {
16867
17427
  return canonicalExpanded;
16868
17428
  }
16869
- const rawDirectory = path15.dirname(expanded);
17429
+ const rawDirectory = path16.dirname(expanded);
16870
17430
  const mappedDirectory = pathMapper.mapTargetDirectory({
16871
17431
  targetDirectory: rawDirectory
16872
17432
  });
16873
- const filename = path15.basename(expanded);
16874
- return filename.length === 0 ? mappedDirectory : path15.join(mappedDirectory, filename);
17433
+ const filename = path16.basename(expanded);
17434
+ return filename.length === 0 ? mappedDirectory : path16.join(mappedDirectory, filename);
16875
17435
  }
16876
17436
 
16877
17437
  // ../config-mutations/src/fs-utils.ts
@@ -16935,8 +17495,8 @@ function isAlreadyExists(error3) {
16935
17495
  return Boolean(error3 && typeof error3 === "object" && "code" in error3 && error3.code === "EEXIST");
16936
17496
  }
16937
17497
  async function assertRegularWriteTarget(context, targetPath) {
16938
- const boundary = path16.dirname(path16.resolve(context.homeDir));
16939
- let currentPath = path16.resolve(targetPath);
17498
+ const boundary = path17.dirname(path17.resolve(context.homeDir));
17499
+ let currentPath = path17.resolve(targetPath);
16940
17500
  while (currentPath !== boundary) {
16941
17501
  try {
16942
17502
  if ((await context.fs.lstat(currentPath)).isSymbolicLink()) {
@@ -16947,7 +17507,7 @@ async function assertRegularWriteTarget(context, targetPath) {
16947
17507
  throw error3;
16948
17508
  }
16949
17509
  }
16950
- const parentPath = path16.dirname(currentPath);
17510
+ const parentPath = path17.dirname(currentPath);
16951
17511
  if (parentPath === currentPath) {
16952
17512
  return;
16953
17513
  }
@@ -17010,7 +17570,7 @@ function pruneKeysByPrefix(table, prefix) {
17010
17570
  const result = {};
17011
17571
  for (const [key2, value] of Object.entries(table)) {
17012
17572
  if (!key2.startsWith(prefix)) {
17013
- result[key2] = value;
17573
+ setConfigEntry(result, key2, value);
17014
17574
  }
17015
17575
  }
17016
17576
  return result;
@@ -17019,28 +17579,43 @@ function isConfigObject4(value) {
17019
17579
  return typeof value === "object" && value !== null && !Array.isArray(value);
17020
17580
  }
17021
17581
  function mergeWithPruneByPrefix(base, patch, pruneByPrefix) {
17022
- const result = { ...base };
17582
+ const result = cloneConfigObject(base);
17023
17583
  const prefixMap = pruneByPrefix ?? {};
17024
17584
  for (const [key2, value] of Object.entries(patch)) {
17585
+ if (value === void 0) {
17586
+ continue;
17587
+ }
17025
17588
  const current = result[key2];
17026
17589
  const prefix = prefixMap[key2];
17027
17590
  if (isConfigObject4(current) && isConfigObject4(value)) {
17028
17591
  if (prefix) {
17029
17592
  const pruned = pruneKeysByPrefix(current, prefix);
17030
- result[key2] = { ...pruned, ...value };
17593
+ setConfigEntry(result, key2, mergePrunedConfigObject(pruned, value));
17031
17594
  } else {
17032
- result[key2] = mergeWithPruneByPrefix(
17033
- current,
17034
- value,
17035
- prefixMap
17036
- );
17595
+ setConfigEntry(result, key2, mergeWithPruneByPrefix(current, value, prefixMap));
17037
17596
  }
17038
17597
  continue;
17039
17598
  }
17040
- result[key2] = value;
17599
+ setConfigEntry(result, key2, value);
17600
+ }
17601
+ return result;
17602
+ }
17603
+ function mergePrunedConfigObject(base, patch) {
17604
+ const result = cloneConfigObject(base);
17605
+ for (const [key2, value] of Object.entries(patch)) {
17606
+ if (value === void 0) {
17607
+ continue;
17608
+ }
17609
+ setConfigEntry(result, key2, value);
17041
17610
  }
17042
17611
  return result;
17043
17612
  }
17613
+ function serializeConfigUpdate(format, rawContent, current, next) {
17614
+ if (rawContent !== null && format.serializeUpdate) {
17615
+ return format.serializeUpdate(rawContent, current, next);
17616
+ }
17617
+ return format.serialize(next);
17618
+ }
17044
17619
  async function applyMutation(mutation, context, options) {
17045
17620
  switch (mutation.kind) {
17046
17621
  case "ensureDirectory":
@@ -17353,6 +17928,7 @@ async function applyConfigMerge(mutation, context, options) {
17353
17928
  }
17354
17929
  const format = getConfigFormat(formatName);
17355
17930
  const rawContent = await readFileIfExists(context.fs, targetPath);
17931
+ let preserveContent = rawContent;
17356
17932
  let current;
17357
17933
  try {
17358
17934
  current = rawContent === null ? {} : format.parse(rawContent);
@@ -17361,6 +17937,7 @@ async function applyConfigMerge(mutation, context, options) {
17361
17937
  await backupInvalidDocument(context, targetPath, rawContent);
17362
17938
  }
17363
17939
  current = {};
17940
+ preserveContent = null;
17364
17941
  }
17365
17942
  const value = resolveValue(mutation.value, options);
17366
17943
  let merged;
@@ -17369,7 +17946,7 @@ async function applyConfigMerge(mutation, context, options) {
17369
17946
  } else {
17370
17947
  merged = format.merge(current, value);
17371
17948
  }
17372
- const serialized = format.serialize(merged);
17949
+ const serialized = serializeConfigUpdate(format, preserveContent, current, merged);
17373
17950
  const changed = serialized !== rawContent;
17374
17951
  if (changed && !context.dryRun) {
17375
17952
  await writeAtomically2(context, targetPath, serialized);
@@ -17437,7 +18014,7 @@ async function applyConfigPrune(mutation, context, options) {
17437
18014
  details
17438
18015
  };
17439
18016
  }
17440
- const serialized = format.serialize(result);
18017
+ const serialized = serializeConfigUpdate(format, rawContent, current, result);
17441
18018
  if (!context.dryRun) {
17442
18019
  await writeAtomically2(context, targetPath, serialized);
17443
18020
  }
@@ -17462,6 +18039,7 @@ async function applyConfigTransform(mutation, context, options) {
17462
18039
  }
17463
18040
  const format = getConfigFormat(formatName);
17464
18041
  const rawContent = await readFileIfExists(context.fs, targetPath);
18042
+ let preserveContent = rawContent;
17465
18043
  let current;
17466
18044
  try {
17467
18045
  current = rawContent === null ? {} : format.parse(rawContent);
@@ -17470,6 +18048,7 @@ async function applyConfigTransform(mutation, context, options) {
17470
18048
  await backupInvalidDocument(context, targetPath, rawContent);
17471
18049
  }
17472
18050
  current = {};
18051
+ preserveContent = null;
17473
18052
  }
17474
18053
  const { content: transformed, changed } = mutation.transform(current, options);
17475
18054
  if (!changed) {
@@ -17493,7 +18072,7 @@ async function applyConfigTransform(mutation, context, options) {
17493
18072
  details
17494
18073
  };
17495
18074
  }
17496
- const serialized = format.serialize(transformed);
18075
+ const serialized = serializeConfigUpdate(format, preserveContent, current, transformed);
17497
18076
  if (!context.dryRun) {
17498
18077
  await writeAtomically2(context, targetPath, serialized);
17499
18078
  }
@@ -17635,7 +18214,7 @@ async function executeMutation(mutation, context, options) {
17635
18214
 
17636
18215
  // ../agent-skill-config/src/templates.ts
17637
18216
  import { readFile as readFile5, stat } from "node:fs/promises";
17638
- import path17 from "node:path";
18217
+ import path18 from "node:path";
17639
18218
  import { fileURLToPath as fileURLToPath3 } from "node:url";
17640
18219
 
17641
18220
  // ../agent-skill-config/src/apply.ts
@@ -17670,14 +18249,14 @@ async function installSkill(agentId, skill, options) {
17670
18249
  throw new UnsupportedAgentError(agentId);
17671
18250
  }
17672
18251
  const scope = options.scope ?? "local";
17673
- const config = support.config;
18252
+ const config2 = support.config;
17674
18253
  if (skill.name.length === 0 || skill.name === "." || skill.name === ".." || skill.name.includes("/") || skill.name.includes("\\") || skill.name.includes("\n") || skill.name.includes("\r")) {
17675
18254
  throw new Error(`Invalid skill name: ${skill.name}`);
17676
18255
  }
17677
- const skillDir = scope === "global" ? config.globalSkillDir : toHomeRelative(config.localSkillDir);
18256
+ const skillDir = scope === "global" ? config2.globalSkillDir : toHomeRelative(config2.localSkillDir);
17678
18257
  const skillFolderPath = `${skillDir}/${skill.name}`;
17679
18258
  const skillFilePath = `${skillFolderPath}/SKILL.md`;
17680
- const displayPath = `${scope === "global" ? config.globalSkillDir : config.localSkillDir}/${skill.name}/SKILL.md`;
18259
+ const displayPath = `${scope === "global" ? config2.globalSkillDir : config2.localSkillDir}/${skill.name}/SKILL.md`;
17681
18260
  const absoluteSkillPath = `${scope === "global" ? options.homeDir : options.cwd}/${skillFilePath.slice(2)}`;
17682
18261
  if (await pathExists2(options.fs, absoluteSkillPath)) {
17683
18262
  throw new Error(`Skill already exists: ${displayPath}`);
@@ -17712,21 +18291,21 @@ async function installSkill(agentId, skill, options) {
17712
18291
 
17713
18292
  // ../agent-skill-config/src/resolve-skill-reference.ts
17714
18293
  import { statSync as statSync2 } from "node:fs";
17715
- import path18 from "node:path";
18294
+ import path19 from "node:path";
17716
18295
 
17717
18296
  // ../agent-skill-config/src/git-exclude.ts
17718
18297
  import { execFileSync } from "node:child_process";
17719
18298
  import * as fs2 from "node:fs";
17720
- import path19 from "node:path";
18299
+ import path20 from "node:path";
17721
18300
 
17722
18301
  // ../agent-skill-config/src/bridge-active-skills.ts
17723
18302
  import * as fs3 from "node:fs";
17724
- import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
17725
- import path20 from "node:path";
18303
+ import { createHash as createHash4, randomUUID as randomUUID5 } from "node:crypto";
18304
+ import path21 from "node:path";
17726
18305
 
17727
18306
  // src/commands/installer.ts
17728
18307
  import os3 from "node:os";
17729
- import path21 from "node:path";
18308
+ import path22 from "node:path";
17730
18309
  import * as nodeFs2 from "node:fs/promises";
17731
18310
  import { readFile as readFile6 } from "node:fs/promises";
17732
18311
  var DEFAULT_INSTALL_AGENT = "claude-code";
@@ -17793,28 +18372,28 @@ function resolveHomeRelativePath(targetPath, homeDir) {
17793
18372
  return homeDir;
17794
18373
  }
17795
18374
  if (targetPath.startsWith("~/")) {
17796
- return path21.join(homeDir, targetPath.slice(2));
18375
+ return path22.join(homeDir, targetPath.slice(2));
17797
18376
  }
17798
18377
  return targetPath;
17799
18378
  }
17800
18379
  function getSkillFolderWithHome(agent, scope, cwd, homeDir) {
17801
- const config = getAgentConfig(agent);
17802
- if (!config) {
18380
+ const config2 = getAgentConfig(agent);
18381
+ if (!config2) {
17803
18382
  throwUnsupportedAgent(agent);
17804
18383
  }
17805
18384
  return {
17806
- displayPath: path21.join(
17807
- scope === "global" ? config.globalSkillDir : config.localSkillDir,
18385
+ displayPath: path22.join(
18386
+ scope === "global" ? config2.globalSkillDir : config2.localSkillDir,
17808
18387
  TERMINAL_PILOT_SKILL_NAME
17809
18388
  ),
17810
- fullPath: path21.join(
17811
- scope === "global" ? resolveHomeRelativePath(config.globalSkillDir, homeDir) : path21.resolve(cwd, config.localSkillDir),
18389
+ fullPath: path22.join(
18390
+ scope === "global" ? resolveHomeRelativePath(config2.globalSkillDir, homeDir) : path22.resolve(cwd, config2.localSkillDir),
17812
18391
  TERMINAL_PILOT_SKILL_NAME
17813
18392
  )
17814
18393
  };
17815
18394
  }
17816
18395
  async function assertNoSymbolicLinkPath(fs4, targetPath) {
17817
- const rootPath = path21.parse(targetPath).root;
18396
+ const rootPath = path22.parse(targetPath).root;
17818
18397
  let currentPath = targetPath;
17819
18398
  while (currentPath !== rootPath) {
17820
18399
  try {
@@ -17826,7 +18405,7 @@ async function assertNoSymbolicLinkPath(fs4, targetPath) {
17826
18405
  throw error3;
17827
18406
  }
17828
18407
  }
17829
- currentPath = path21.dirname(currentPath);
18408
+ currentPath = path22.dirname(currentPath);
17830
18409
  }
17831
18410
  }
17832
18411
 
@@ -17965,7 +18544,7 @@ var resize = defineCommand({
17965
18544
  });
17966
18545
 
17967
18546
  // ../terminal-png/src/index.ts
17968
- import { randomUUID as randomUUID5 } from "node:crypto";
18547
+ import { randomUUID as randomUUID6 } from "node:crypto";
17969
18548
  import { rename as rename4, rm, writeFile as writeFile6 } from "node:fs/promises";
17970
18549
 
17971
18550
  // ../terminal-png/src/ansi-parser.ts
@@ -18905,7 +19484,7 @@ async function renderTerminalPng(ansiText, options = {}) {
18905
19484
  });
18906
19485
  const png = renderPng(svg);
18907
19486
  if (options.output) {
18908
- const temporaryPath = `${options.output}.${randomUUID5()}.tmp`;
19487
+ const temporaryPath = `${options.output}.${randomUUID6()}.tmp`;
18909
19488
  try {
18910
19489
  await writeFile6(temporaryPath, png, { flag: "wx" });
18911
19490
  await rename4(temporaryPath, options.output);
@@ -18982,7 +19561,7 @@ var type = defineCommand({
18982
19561
  });
18983
19562
 
18984
19563
  // src/commands/uninstall.ts
18985
- import { randomUUID as randomUUID6 } from "node:crypto";
19564
+ import { randomUUID as randomUUID7 } from "node:crypto";
18986
19565
  var params14 = S.Object({
18987
19566
  agent: S.Enum(installableAgents, {
18988
19567
  description: "Agent to uninstall terminal-pilot from",
@@ -19018,7 +19597,7 @@ var uninstall = defineCommand({
19018
19597
  if (!await folderExists(services.fs, skill.fullPath)) {
19019
19598
  continue;
19020
19599
  }
19021
- const stagingPath = `${skill.fullPath}.removing-${randomUUID6()}`;
19600
+ const stagingPath = `${skill.fullPath}.removing-${randomUUID7()}`;
19022
19601
  await services.fs.rename(skill.fullPath, stagingPath);
19023
19602
  staged.push({ ...skill, stagingPath });
19024
19603
  }
@@ -19125,6 +19704,7 @@ function createTerminalPilotGroup() {
19125
19704
  var terminalPilotGroup = Object.freeze(createTerminalPilotGroup());
19126
19705
 
19127
19706
  // src/cli.ts
19707
+ configureTheme({ brand: "green", label: "Terminal Pilot" });
19128
19708
  function normalizeArgv(argv) {
19129
19709
  if (argv.includes("--json") && !argv.some((argument) => argument === "--output" || argument.startsWith("--output="))) {
19130
19710
  return argv.flatMap((argument) => argument === "--json" ? ["--output", "json"] : [argument]);
@@ -19148,8 +19728,8 @@ async function isDirectExecution(argv) {
19148
19728
  try {
19149
19729
  const modulePath = fileURLToPath5(import.meta.url);
19150
19730
  const [resolvedEntryPoint, resolvedModulePath] = await Promise.all([
19151
- realpath2(path22.resolve(entryPoint)),
19152
- realpath2(modulePath)
19731
+ realpath3(path23.resolve(entryPoint)),
19732
+ realpath3(modulePath)
19153
19733
  ]);
19154
19734
  return resolvedEntryPoint === resolvedModulePath;
19155
19735
  } catch {
@@ -19260,13 +19840,13 @@ function createTerminalPilotCliRepl() {
19260
19840
  }
19261
19841
 
19262
19842
  // src/testing/qa-cli.ts
19263
- var testingDirectory = path23.dirname(fileURLToPath6(import.meta.url));
19264
- var repoRoot = path23.resolve(testingDirectory, "../../../..");
19265
- var tsxPath = path23.join(repoRoot, "node_modules", ".bin", "tsx");
19266
- var testCliPath = path23.join(repoRoot, "packages/terminal-pilot/src/testing/test-cli.js");
19267
- var menuCliPath = path23.join(repoRoot, "packages/terminal-pilot/src/testing/menu-cli.js");
19268
- var vimSavedFile = path23.join(os4.tmpdir(), "terminal-pilot-qa-test.txt");
19269
- var vimDiscardFile = path23.join(os4.tmpdir(), "terminal-pilot-qa-discard.txt");
19843
+ var testingDirectory = path24.dirname(fileURLToPath6(import.meta.url));
19844
+ var repoRoot = path24.resolve(testingDirectory, "../../../..");
19845
+ var tsxPath = path24.join(repoRoot, "node_modules", ".bin", "tsx");
19846
+ var testCliPath = path24.join(repoRoot, "packages/terminal-pilot/src/testing/test-cli.js");
19847
+ var menuCliPath = path24.join(repoRoot, "packages/terminal-pilot/src/testing/menu-cli.js");
19848
+ var vimSavedFile = path24.join(os4.tmpdir(), "terminal-pilot-qa-test.txt");
19849
+ var vimDiscardFile = path24.join(os4.tmpdir(), "terminal-pilot-qa-discard.txt");
19270
19850
  var QaContext = class {
19271
19851
  repl = createTerminalPilotCliRepl();
19272
19852
  async close() {
@@ -20012,7 +20592,7 @@ var cases = [
20012
20592
  "VIM",
20013
20593
  "-t",
20014
20594
  "5000",
20015
- path23.basename(vimSavedFile)
20595
+ path24.basename(vimSavedFile)
20016
20596
  ]);
20017
20597
  await ctx.expectOk(["press-key", "-s", "VIM", "i"]);
20018
20598
  await ctx.expectOk(["type", "-s", "VIM", "hello from terminal-pilot"]);
@@ -20067,7 +20647,7 @@ var cases = [
20067
20647
  "VIM2",
20068
20648
  "-t",
20069
20649
  "5000",
20070
- path23.basename(vimDiscardFile)
20650
+ path24.basename(vimDiscardFile)
20071
20651
  ]);
20072
20652
  await ctx.expectOk(["press-key", "-s", "VIM2", "i"]);
20073
20653
  await ctx.expectOk(["type", "-s", "VIM2", "this should not be saved"]);