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.
- package/dist/cli.js +1076 -496
- package/dist/cli.js.map +4 -4
- package/dist/commands/close-session.js.map +1 -1
- package/dist/commands/create-session.js.map +1 -1
- package/dist/commands/fill.js.map +1 -1
- package/dist/commands/get-session.js.map +1 -1
- package/dist/commands/index.js +481 -163
- package/dist/commands/index.js.map +4 -4
- package/dist/commands/install.js +448 -130
- package/dist/commands/install.js.map +4 -4
- package/dist/commands/installer.js +154 -60
- package/dist/commands/installer.js.map +4 -4
- package/dist/commands/list-sessions.js.map +1 -1
- package/dist/commands/press-key.js.map +1 -1
- package/dist/commands/read-history.js.map +1 -1
- package/dist/commands/read-screen.js.map +1 -1
- package/dist/commands/resize.js.map +1 -1
- package/dist/commands/runtime.js.map +1 -1
- package/dist/commands/screenshot.js.map +1 -1
- package/dist/commands/send-signal.js.map +1 -1
- package/dist/commands/type.js.map +1 -1
- package/dist/commands/uninstall.js +187 -93
- package/dist/commands/uninstall.js.map +4 -4
- package/dist/commands/wait-for-exit.js.map +1 -1
- package/dist/commands/wait-for.js.map +1 -1
- package/dist/testing/cli-repl.js +1072 -492
- package/dist/testing/cli-repl.js.map +4 -4
- package/dist/testing/qa-cli.js +1082 -502
- package/dist/testing/qa-cli.js.map +4 -4
- package/node_modules/@poe-code/agent-skill-config/README.md +103 -0
- package/node_modules/@poe-code/agent-skill-config/dist/apply.d.ts +25 -0
- package/node_modules/@poe-code/agent-skill-config/dist/apply.js +159 -0
- package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.d.ts +23 -0
- package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.js +341 -0
- package/node_modules/@poe-code/agent-skill-config/dist/configs.d.ts +16 -0
- package/node_modules/@poe-code/agent-skill-config/dist/configs.js +70 -0
- package/node_modules/@poe-code/agent-skill-config/dist/exports.compile-check.d.ts +1 -0
- package/node_modules/@poe-code/agent-skill-config/dist/exports.compile-check.js +1 -0
- package/node_modules/@poe-code/agent-skill-config/dist/git-exclude.d.ts +8 -0
- package/node_modules/@poe-code/agent-skill-config/dist/git-exclude.js +159 -0
- package/node_modules/@poe-code/agent-skill-config/dist/index.d.ts +11 -0
- package/node_modules/@poe-code/agent-skill-config/dist/index.js +6 -0
- package/node_modules/@poe-code/agent-skill-config/dist/resolve-skill-reference.d.ts +22 -0
- package/node_modules/@poe-code/agent-skill-config/dist/resolve-skill-reference.js +87 -0
- package/node_modules/@poe-code/agent-skill-config/dist/templates/poe-generate.md +47 -0
- package/node_modules/@poe-code/agent-skill-config/dist/templates/terminal-pilot.md +45 -0
- package/node_modules/@poe-code/agent-skill-config/dist/templates.d.ts +3 -0
- package/node_modules/@poe-code/agent-skill-config/dist/templates.js +63 -0
- package/node_modules/@poe-code/agent-skill-config/dist/types.d.ts +16 -0
- package/node_modules/@poe-code/agent-skill-config/dist/types.js +1 -0
- package/node_modules/@poe-code/agent-skill-config/package.json +24 -0
- package/package.json +4 -2
package/dist/commands/install.js
CHANGED
|
@@ -206,11 +206,11 @@ function resolveAgentSupport(input, registry = agentSkillConfigs) {
|
|
|
206
206
|
if (!resolvedId) {
|
|
207
207
|
return { status: "unknown", input };
|
|
208
208
|
}
|
|
209
|
-
const
|
|
210
|
-
if (!
|
|
209
|
+
const config2 = registry[resolvedId];
|
|
210
|
+
if (!config2) {
|
|
211
211
|
return { status: "unsupported", input, id: resolvedId };
|
|
212
212
|
}
|
|
213
|
-
return { status: "supported", input, id: resolvedId, config: { ...
|
|
213
|
+
return { status: "supported", input, id: resolvedId, config: { ...config2 } };
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
// ../config-mutations/src/mutations/file-mutation.ts
|
|
@@ -307,7 +307,7 @@ var templateMutation = {
|
|
|
307
307
|
// ../config-mutations/src/execution/apply-mutation.ts
|
|
308
308
|
import path3 from "node:path";
|
|
309
309
|
|
|
310
|
-
// ../design
|
|
310
|
+
// ../toolcraft-design/src/internal/color-support.ts
|
|
311
311
|
function supportsColor(env = process.env, stream = process.stdout) {
|
|
312
312
|
if (env.FORCE_COLOR !== void 0 && env.FORCE_COLOR !== "0") {
|
|
313
313
|
return true;
|
|
@@ -321,7 +321,7 @@ function supportsColor(env = process.env, stream = process.stdout) {
|
|
|
321
321
|
return typeof env.TERM === "string" && env.TERM.length > 0 && env.TERM !== "dumb";
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
-
// ../design
|
|
324
|
+
// ../toolcraft-design/src/components/color.ts
|
|
325
325
|
var reset = "\x1B[0m";
|
|
326
326
|
var ansiStyles = {
|
|
327
327
|
reset: { open: reset },
|
|
@@ -423,41 +423,122 @@ function createColor(styles = []) {
|
|
|
423
423
|
}
|
|
424
424
|
var color = createColor();
|
|
425
425
|
|
|
426
|
-
// ../design
|
|
427
|
-
var
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
number: (text4) => color.cyanBright(text4),
|
|
432
|
-
intro: (text4) => color.bgMagenta.white(` Poe - ${text4} `),
|
|
433
|
-
resolvedSymbol: color.magenta("\u25C7"),
|
|
434
|
-
errorSymbol: color.red("\u25A0"),
|
|
435
|
-
accent: (text4) => color.cyan(text4),
|
|
436
|
-
muted: (text4) => color.dim(text4),
|
|
437
|
-
success: (text4) => color.green(text4),
|
|
438
|
-
warning: (text4) => color.yellow(text4),
|
|
439
|
-
error: (text4) => color.red(text4),
|
|
440
|
-
info: (text4) => color.magenta(text4),
|
|
441
|
-
badge: (text4) => color.bgYellow.black(` ${text4} `)
|
|
426
|
+
// ../toolcraft-design/src/tokens/brand.ts
|
|
427
|
+
var brands = {
|
|
428
|
+
purple: { name: "purple", primary: "#a200ff" },
|
|
429
|
+
blue: { name: "blue", primary: "#2f6fed" },
|
|
430
|
+
green: { name: "green", primary: "#1f9d57" }
|
|
442
431
|
};
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
intro: (text4) => color.bgHex("#a200ff").white(` Poe - ${text4} `),
|
|
449
|
-
resolvedSymbol: color.hex("#a200ff")("\u25C7"),
|
|
450
|
-
errorSymbol: color.hex("#cc0000")("\u25A0"),
|
|
451
|
-
accent: (text4) => color.hex("#006699").bold(text4),
|
|
452
|
-
muted: (text4) => color.hex("#666666")(text4),
|
|
453
|
-
success: (text4) => color.hex("#008800")(text4),
|
|
454
|
-
warning: (text4) => color.hex("#cc6600")(text4),
|
|
455
|
-
error: (text4) => color.hex("#cc0000")(text4),
|
|
456
|
-
info: (text4) => color.hex("#a200ff")(text4),
|
|
457
|
-
badge: (text4) => color.bgHex("#cc6600").white(` ${text4} `)
|
|
432
|
+
|
|
433
|
+
// ../toolcraft-design/src/internal/theme-state.ts
|
|
434
|
+
var defaults = {
|
|
435
|
+
brand: "purple",
|
|
436
|
+
label: "Poe"
|
|
458
437
|
};
|
|
438
|
+
var config = { ...defaults };
|
|
439
|
+
var revision = 0;
|
|
440
|
+
var brandConfigured = false;
|
|
441
|
+
function getThemeConfig() {
|
|
442
|
+
return { ...config };
|
|
443
|
+
}
|
|
444
|
+
function getThemeRevision() {
|
|
445
|
+
return revision;
|
|
446
|
+
}
|
|
447
|
+
function isThemeBrandConfigured() {
|
|
448
|
+
return brandConfigured;
|
|
449
|
+
}
|
|
459
450
|
|
|
460
|
-
// ../design
|
|
451
|
+
// ../toolcraft-design/src/tokens/colors.ts
|
|
452
|
+
var brand = brands.purple.primary;
|
|
453
|
+
function withStyles(palette, styles) {
|
|
454
|
+
return Object.defineProperty(palette, "styles", {
|
|
455
|
+
value: styles,
|
|
456
|
+
enumerable: false
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
function brandColor(activeBrand, purple) {
|
|
460
|
+
return activeBrand.name === "purple" ? purple : color.hex(activeBrand.primary);
|
|
461
|
+
}
|
|
462
|
+
function brandBackground(activeBrand, purple) {
|
|
463
|
+
return activeBrand.name === "purple" ? purple : color.bgHex(activeBrand.primary);
|
|
464
|
+
}
|
|
465
|
+
function createPalette(activeBrand, mode) {
|
|
466
|
+
const isPurple = activeBrand.name === "purple";
|
|
467
|
+
if (mode === "light") {
|
|
468
|
+
const active2 = color.hex(activeBrand.primary);
|
|
469
|
+
const prompt2 = isPurple ? color.hex("#006699") : active2;
|
|
470
|
+
const number2 = isPurple ? color.hex("#0077cc") : active2;
|
|
471
|
+
return withStyles(
|
|
472
|
+
{
|
|
473
|
+
header: (text4) => active2.bold(text4),
|
|
474
|
+
divider: (text4) => color.hex("#666666")(text4),
|
|
475
|
+
prompt: (text4) => prompt2.bold(text4),
|
|
476
|
+
number: (text4) => number2.bold(text4),
|
|
477
|
+
intro: (text4) => color.bgHex(activeBrand.primary).white(` ${getThemeConfig().label} - ${text4} `),
|
|
478
|
+
get resolvedSymbol() {
|
|
479
|
+
return active2("\u25C7");
|
|
480
|
+
},
|
|
481
|
+
get errorSymbol() {
|
|
482
|
+
return color.hex("#cc0000")("\u25A0");
|
|
483
|
+
},
|
|
484
|
+
accent: (text4) => prompt2.bold(text4),
|
|
485
|
+
muted: (text4) => color.hex("#666666")(text4),
|
|
486
|
+
success: (text4) => color.hex("#008800")(text4),
|
|
487
|
+
warning: (text4) => color.hex("#cc6600")(text4),
|
|
488
|
+
error: (text4) => color.hex("#cc0000")(text4),
|
|
489
|
+
info: (text4) => active2(text4),
|
|
490
|
+
badge: (text4) => color.bgHex("#cc6600").white(` ${text4} `)
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
accent: { fg: isPurple ? "#006699" : activeBrand.primary, bold: true },
|
|
494
|
+
muted: { fg: "#666666" },
|
|
495
|
+
success: { fg: "#008800" },
|
|
496
|
+
warning: { fg: "#cc6600" },
|
|
497
|
+
error: { fg: "#cc0000" },
|
|
498
|
+
info: { fg: activeBrand.primary }
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
const active = brandColor(activeBrand, color.magenta);
|
|
503
|
+
const activeBright = brandColor(activeBrand, color.magentaBright);
|
|
504
|
+
const activeBackground = brandBackground(activeBrand, color.bgMagenta);
|
|
505
|
+
const prompt = isPurple ? color.cyan : active;
|
|
506
|
+
const number = isPurple ? color.cyanBright : active;
|
|
507
|
+
return withStyles(
|
|
508
|
+
{
|
|
509
|
+
header: (text4) => activeBright.bold(text4),
|
|
510
|
+
divider: (text4) => color.dim(text4),
|
|
511
|
+
prompt: (text4) => prompt(text4),
|
|
512
|
+
number: (text4) => number(text4),
|
|
513
|
+
intro: (text4) => activeBackground.white(` ${getThemeConfig().label} - ${text4} `),
|
|
514
|
+
get resolvedSymbol() {
|
|
515
|
+
return active("\u25C7");
|
|
516
|
+
},
|
|
517
|
+
get errorSymbol() {
|
|
518
|
+
return color.red("\u25A0");
|
|
519
|
+
},
|
|
520
|
+
accent: (text4) => prompt(text4),
|
|
521
|
+
muted: (text4) => color.dim(text4),
|
|
522
|
+
success: (text4) => color.green(text4),
|
|
523
|
+
warning: (text4) => color.yellow(text4),
|
|
524
|
+
error: (text4) => color.red(text4),
|
|
525
|
+
info: (text4) => active(text4),
|
|
526
|
+
badge: (text4) => color.bgYellow.black(` ${text4} `)
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
accent: { fg: isPurple ? "cyan" : activeBrand.primary, bold: true },
|
|
530
|
+
muted: { dim: true },
|
|
531
|
+
success: { fg: "green" },
|
|
532
|
+
warning: { fg: "yellow" },
|
|
533
|
+
error: { fg: "red" },
|
|
534
|
+
info: { fg: isPurple ? "magenta" : activeBrand.primary }
|
|
535
|
+
}
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
var dark = createPalette(brands.purple, "dark");
|
|
539
|
+
var light = createPalette(brands.purple, "light");
|
|
540
|
+
|
|
541
|
+
// ../toolcraft-design/src/internal/output-format.ts
|
|
461
542
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
462
543
|
var VALID_FORMATS = /* @__PURE__ */ new Set(["terminal", "markdown", "json"]);
|
|
463
544
|
var formatStorage = new AsyncLocalStorage();
|
|
@@ -475,7 +556,7 @@ function resolveOutputFormat(env = process.env) {
|
|
|
475
556
|
return cached;
|
|
476
557
|
}
|
|
477
558
|
|
|
478
|
-
// ../design
|
|
559
|
+
// ../toolcraft-design/src/internal/theme-detect.ts
|
|
479
560
|
function detectThemeFromEnv(env) {
|
|
480
561
|
const apple = env.APPLE_INTERFACE_STYLE;
|
|
481
562
|
if (typeof apple === "string") {
|
|
@@ -512,17 +593,30 @@ function resolveThemeName(env = process.env) {
|
|
|
512
593
|
}
|
|
513
594
|
return "dark";
|
|
514
595
|
}
|
|
515
|
-
var
|
|
596
|
+
var themeCache = /* @__PURE__ */ new Map();
|
|
597
|
+
var cachedRevision = -1;
|
|
516
598
|
function getTheme(env) {
|
|
599
|
+
const themeName = resolveThemeName(env);
|
|
600
|
+
const config2 = getThemeConfig();
|
|
601
|
+
const requestedBrand = env?.POE_BRAND?.toLowerCase();
|
|
602
|
+
const activeBrandName = !isThemeBrandConfigured() && requestedBrand && Object.hasOwn(brands, requestedBrand) ? requestedBrand : config2.brand;
|
|
603
|
+
const revision2 = getThemeRevision();
|
|
604
|
+
if (revision2 !== cachedRevision) {
|
|
605
|
+
themeCache.clear();
|
|
606
|
+
cachedRevision = revision2;
|
|
607
|
+
}
|
|
608
|
+
const cacheKey = `${activeBrandName}:${themeName}`;
|
|
609
|
+
const cachedTheme = themeCache.get(cacheKey);
|
|
517
610
|
if (cachedTheme) {
|
|
518
611
|
return cachedTheme;
|
|
519
612
|
}
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
613
|
+
const activeBrand = brands[activeBrandName];
|
|
614
|
+
const theme = activeBrandName === "purple" ? themeName === "light" ? light : dark : createPalette(activeBrand, themeName);
|
|
615
|
+
themeCache.set(cacheKey, theme);
|
|
616
|
+
return theme;
|
|
523
617
|
}
|
|
524
618
|
|
|
525
|
-
// ../design
|
|
619
|
+
// ../toolcraft-design/src/components/symbols.ts
|
|
526
620
|
var symbols = {
|
|
527
621
|
get info() {
|
|
528
622
|
const format = resolveOutputFormat();
|
|
@@ -576,12 +670,12 @@ var symbols = {
|
|
|
576
670
|
}
|
|
577
671
|
};
|
|
578
672
|
|
|
579
|
-
// ../design
|
|
673
|
+
// ../toolcraft-design/src/internal/strip-ansi.ts
|
|
580
674
|
function stripAnsi(value) {
|
|
581
675
|
return value.replace(/\u001b\[[0-9;]*m/g, "");
|
|
582
676
|
}
|
|
583
677
|
|
|
584
|
-
// ../design
|
|
678
|
+
// ../toolcraft-design/src/prompts/primitives/log.ts
|
|
585
679
|
function renderMarkdownInline(value) {
|
|
586
680
|
return stripAnsi(value).replaceAll("\r\n", " ").replaceAll("\n", " ").replaceAll("\r", " ");
|
|
587
681
|
}
|
|
@@ -708,7 +802,7 @@ var log = {
|
|
|
708
802
|
error
|
|
709
803
|
};
|
|
710
804
|
|
|
711
|
-
// ../design
|
|
805
|
+
// ../toolcraft-design/src/components/logger.ts
|
|
712
806
|
function createLogger(emitter) {
|
|
713
807
|
const emit = (level, message2) => {
|
|
714
808
|
if (emitter) {
|
|
@@ -769,13 +863,14 @@ function createLogger(emitter) {
|
|
|
769
863
|
}
|
|
770
864
|
var logger = createLogger();
|
|
771
865
|
|
|
772
|
-
// ../design
|
|
866
|
+
// ../toolcraft-design/src/components/help-formatter.ts
|
|
773
867
|
var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
774
868
|
|
|
775
|
-
// ../design
|
|
869
|
+
// ../toolcraft-design/src/components/table.ts
|
|
776
870
|
var graphemeSegmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
777
871
|
|
|
778
|
-
// ../design
|
|
872
|
+
// ../toolcraft-design/src/components/template.ts
|
|
873
|
+
var MAX_PARTIAL_DEPTH = 100;
|
|
779
874
|
var HTML_ESCAPE = {
|
|
780
875
|
"&": "&",
|
|
781
876
|
"<": "<",
|
|
@@ -787,14 +882,27 @@ var HTML_ESCAPE = {
|
|
|
787
882
|
"=": "="
|
|
788
883
|
};
|
|
789
884
|
function renderTemplate(template, view, options = {}) {
|
|
790
|
-
const prepared = options.yield === void 0 ? template : template.split("{{yield}}").join(options.yield);
|
|
885
|
+
const prepared = options.yield === void 0 ? template : resolveTemplatePartials(template, options.partials ?? {}).split("{{yield}}").join(options.yield);
|
|
791
886
|
const tokens = parseTemplate(prepared);
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
887
|
+
validatePartialReferences(tokens, options.partials ?? {}, []);
|
|
888
|
+
if (options.validate === true) {
|
|
889
|
+
const expanded = resolveTemplatePartials(prepared, options.partials ?? {});
|
|
890
|
+
validateVariables(parseTemplate(expanded), { view });
|
|
891
|
+
}
|
|
892
|
+
const state = {
|
|
893
|
+
escape: options.escape === "none" ? String : escapeHtml,
|
|
894
|
+
partials: options.partials ?? {},
|
|
895
|
+
partialStack: [],
|
|
896
|
+
preserveMissing: options.yield !== void 0 && options.escape === "none",
|
|
897
|
+
validate: options.validate === true
|
|
898
|
+
};
|
|
899
|
+
return renderTokens(tokens, { view }, prepared, state);
|
|
900
|
+
}
|
|
901
|
+
function resolveTemplatePartials(template, partials) {
|
|
902
|
+
return expandTemplatePartials(template, partials, []);
|
|
795
903
|
}
|
|
796
|
-
function renderTemplateInContext(template, context,
|
|
797
|
-
return renderTokens(parseTemplate(template), context, template,
|
|
904
|
+
function renderTemplateInContext(template, context, state) {
|
|
905
|
+
return renderTokens(parseTemplate(template), context, template, state);
|
|
798
906
|
}
|
|
799
907
|
function parseTemplate(template) {
|
|
800
908
|
const root = [];
|
|
@@ -817,9 +925,6 @@ function parseTemplate(template) {
|
|
|
817
925
|
index = standalone?.nextIndex ?? parsed.end;
|
|
818
926
|
continue;
|
|
819
927
|
}
|
|
820
|
-
if (parsed.kind === "partial") {
|
|
821
|
-
throw new Error(`Partials are not supported: "${parsed.name}"`);
|
|
822
|
-
}
|
|
823
928
|
if (parsed.kind === "delimiter") {
|
|
824
929
|
throw new Error("Custom delimiters are not supported");
|
|
825
930
|
}
|
|
@@ -837,6 +942,15 @@ function parseTemplate(template) {
|
|
|
837
942
|
index = standalone?.nextIndex ?? parsed.end;
|
|
838
943
|
continue;
|
|
839
944
|
}
|
|
945
|
+
if (parsed.kind === "partial") {
|
|
946
|
+
tokens.push({
|
|
947
|
+
type: "partial",
|
|
948
|
+
name: parsed.name,
|
|
949
|
+
indent: standalone === void 0 ? "" : template.slice(standalone.lineStart, open)
|
|
950
|
+
});
|
|
951
|
+
index = standalone?.nextIndex ?? parsed.end;
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
840
954
|
if (parsed.kind === "close") {
|
|
841
955
|
const frame2 = stack.pop();
|
|
842
956
|
if (frame2 === void 0) {
|
|
@@ -907,7 +1021,7 @@ function getStandalone(template, tagStart, tagEnd, kind) {
|
|
|
907
1021
|
}
|
|
908
1022
|
return void 0;
|
|
909
1023
|
}
|
|
910
|
-
function renderTokens(tokens, context, template,
|
|
1024
|
+
function renderTokens(tokens, context, template, state) {
|
|
911
1025
|
let output = "";
|
|
912
1026
|
for (const token of tokens) {
|
|
913
1027
|
switch (token.type) {
|
|
@@ -916,32 +1030,62 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
|
|
|
916
1030
|
continue;
|
|
917
1031
|
case "name":
|
|
918
1032
|
case "unescaped": {
|
|
919
|
-
const
|
|
920
|
-
if (value == null) {
|
|
921
|
-
if (
|
|
1033
|
+
const result = lookup2(context, token.name);
|
|
1034
|
+
if (!result.hit || result.value == null) {
|
|
1035
|
+
if (state.validate) {
|
|
1036
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
1037
|
+
}
|
|
1038
|
+
if (state.preserveMissing) {
|
|
922
1039
|
output += token.raw;
|
|
923
1040
|
}
|
|
924
1041
|
continue;
|
|
925
1042
|
}
|
|
926
|
-
const rendered = String(value);
|
|
927
|
-
output += token.type === "name" ? escape(rendered) : rendered;
|
|
1043
|
+
const rendered = String(result.value);
|
|
1044
|
+
output += token.type === "name" ? state.escape(rendered) : rendered;
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
case "partial": {
|
|
1048
|
+
if (!Object.hasOwn(state.partials, token.name)) {
|
|
1049
|
+
throw new Error(`Partial "${token.name}" not found.`);
|
|
1050
|
+
}
|
|
1051
|
+
if (state.partialStack.includes(token.name)) {
|
|
1052
|
+
throw new Error(
|
|
1053
|
+
`Circular partial reference detected: ${[...state.partialStack, token.name].join(" -> ")}.`
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
if (state.partialStack.length >= MAX_PARTIAL_DEPTH) {
|
|
1057
|
+
throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
|
|
1058
|
+
}
|
|
1059
|
+
const partial = indentPartial(state.partials[token.name], token.indent);
|
|
1060
|
+
output += renderTokens(parseTemplate(partial), context, partial, {
|
|
1061
|
+
...state,
|
|
1062
|
+
partialStack: [...state.partialStack, token.name]
|
|
1063
|
+
});
|
|
928
1064
|
continue;
|
|
929
1065
|
}
|
|
930
1066
|
case "inverted": {
|
|
931
|
-
const
|
|
1067
|
+
const result = lookup2(context, token.name);
|
|
1068
|
+
if (!result.hit && state.validate) {
|
|
1069
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
1070
|
+
}
|
|
1071
|
+
const value = result.value;
|
|
932
1072
|
if (!value || Array.isArray(value) && value.length === 0) {
|
|
933
|
-
output += renderTokens(token.children, context, template,
|
|
1073
|
+
output += renderTokens(token.children, context, template, state);
|
|
934
1074
|
}
|
|
935
1075
|
continue;
|
|
936
1076
|
}
|
|
937
1077
|
case "section": {
|
|
938
|
-
const
|
|
1078
|
+
const result = lookup2(context, token.name);
|
|
1079
|
+
if (!result.hit && state.validate) {
|
|
1080
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
1081
|
+
}
|
|
1082
|
+
const value = result.value;
|
|
939
1083
|
if (!value) {
|
|
940
1084
|
continue;
|
|
941
1085
|
}
|
|
942
1086
|
if (Array.isArray(value)) {
|
|
943
1087
|
for (const item of value) {
|
|
944
|
-
output += renderTokens(token.children, pushContext(context, item), template,
|
|
1088
|
+
output += renderTokens(token.children, pushContext(context, item), template, state);
|
|
945
1089
|
}
|
|
946
1090
|
continue;
|
|
947
1091
|
}
|
|
@@ -950,7 +1094,7 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
|
|
|
950
1094
|
const rendered = value.call(
|
|
951
1095
|
context.view,
|
|
952
1096
|
raw,
|
|
953
|
-
(nextTemplate) => renderTemplateInContext(nextTemplate, context,
|
|
1097
|
+
(nextTemplate) => renderTemplateInContext(nextTemplate, context, state)
|
|
954
1098
|
);
|
|
955
1099
|
if (rendered != null) {
|
|
956
1100
|
output += String(rendered);
|
|
@@ -958,10 +1102,10 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
|
|
|
958
1102
|
continue;
|
|
959
1103
|
}
|
|
960
1104
|
if (typeof value === "object" || typeof value === "string" || typeof value === "number") {
|
|
961
|
-
output += renderTokens(token.children, pushContext(context, value), template,
|
|
1105
|
+
output += renderTokens(token.children, pushContext(context, value), template, state);
|
|
962
1106
|
continue;
|
|
963
1107
|
}
|
|
964
|
-
output += renderTokens(token.children, context, template,
|
|
1108
|
+
output += renderTokens(token.children, context, template, state);
|
|
965
1109
|
}
|
|
966
1110
|
}
|
|
967
1111
|
}
|
|
@@ -969,17 +1113,115 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
|
|
|
969
1113
|
}
|
|
970
1114
|
function lookup2(context, name) {
|
|
971
1115
|
if (name === ".") {
|
|
972
|
-
return callLambda(context.view, context.view);
|
|
1116
|
+
return { hit: true, value: callLambda(context.view, context.view) };
|
|
973
1117
|
}
|
|
974
1118
|
let cursor = context;
|
|
975
1119
|
while (cursor !== void 0) {
|
|
976
1120
|
const result = name.includes(".") ? lookupDotted(cursor.view, name) : lookupName(cursor.view, name);
|
|
977
1121
|
if (result.hit) {
|
|
978
|
-
return callLambda(result.value, cursor.view);
|
|
1122
|
+
return { hit: true, value: callLambda(result.value, cursor.view) };
|
|
979
1123
|
}
|
|
980
1124
|
cursor = cursor.parent;
|
|
981
1125
|
}
|
|
982
|
-
return void 0;
|
|
1126
|
+
return { hit: false, value: void 0 };
|
|
1127
|
+
}
|
|
1128
|
+
function validateVariables(tokens, context) {
|
|
1129
|
+
for (const token of tokens) {
|
|
1130
|
+
if (token.type === "text" || token.type === "partial") {
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
if (token.type === "name" || token.type === "unescaped") {
|
|
1134
|
+
if (!lookup2(context, token.name).hit) {
|
|
1135
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
1136
|
+
}
|
|
1137
|
+
continue;
|
|
1138
|
+
}
|
|
1139
|
+
if (token.type !== "section" && token.type !== "inverted") {
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1142
|
+
const result = lookup2(context, token.name);
|
|
1143
|
+
if (!result.hit) {
|
|
1144
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
1145
|
+
}
|
|
1146
|
+
if (Array.isArray(result.value) && result.value.length > 0) {
|
|
1147
|
+
for (const item of result.value) {
|
|
1148
|
+
validateVariables(token.children, pushContext(context, item));
|
|
1149
|
+
}
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
if (typeof result.value === "object" && result.value !== null || typeof result.value === "string" || typeof result.value === "number") {
|
|
1153
|
+
validateVariables(token.children, pushContext(context, result.value));
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
validateVariables(token.children, context);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
function validatePartialReferences(tokens, partials, partialStack) {
|
|
1160
|
+
for (const token of tokens) {
|
|
1161
|
+
if (token.type === "section" || token.type === "inverted") {
|
|
1162
|
+
validatePartialReferences(token.children, partials, partialStack);
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
if (token.type !== "partial") {
|
|
1166
|
+
continue;
|
|
1167
|
+
}
|
|
1168
|
+
if (!Object.hasOwn(partials, token.name)) {
|
|
1169
|
+
throw new Error(`Partial "${token.name}" not found.`);
|
|
1170
|
+
}
|
|
1171
|
+
if (partialStack.includes(token.name)) {
|
|
1172
|
+
throw new Error(
|
|
1173
|
+
`Circular partial reference detected: ${[...partialStack, token.name].join(" -> ")}.`
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
if (partialStack.length >= MAX_PARTIAL_DEPTH) {
|
|
1177
|
+
throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
|
|
1178
|
+
}
|
|
1179
|
+
validatePartialReferences(parseTemplate(partials[token.name]), partials, [
|
|
1180
|
+
...partialStack,
|
|
1181
|
+
token.name
|
|
1182
|
+
]);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
function indentPartial(partial, indent) {
|
|
1186
|
+
if (indent === "") {
|
|
1187
|
+
return partial;
|
|
1188
|
+
}
|
|
1189
|
+
return partial.split("\n").map((line) => line === "" ? "" : `${indent}${line}`).join("\n");
|
|
1190
|
+
}
|
|
1191
|
+
function expandTemplatePartials(template, partials, partialStack) {
|
|
1192
|
+
let output = "";
|
|
1193
|
+
let index = 0;
|
|
1194
|
+
while (index < template.length) {
|
|
1195
|
+
const open = template.indexOf("{{", index);
|
|
1196
|
+
if (open === -1) {
|
|
1197
|
+
output += template.slice(index);
|
|
1198
|
+
break;
|
|
1199
|
+
}
|
|
1200
|
+
const parsed = parseTag(template, open);
|
|
1201
|
+
if (parsed.kind !== "partial") {
|
|
1202
|
+
output += template.slice(index, parsed.end);
|
|
1203
|
+
index = parsed.end;
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
if (!Object.hasOwn(partials, parsed.name)) {
|
|
1207
|
+
throw new Error(`Partial "${parsed.name}" not found.`);
|
|
1208
|
+
}
|
|
1209
|
+
if (partialStack.includes(parsed.name)) {
|
|
1210
|
+
throw new Error(
|
|
1211
|
+
`Circular partial reference detected: ${[...partialStack, parsed.name].join(" -> ")}.`
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
if (partialStack.length >= MAX_PARTIAL_DEPTH) {
|
|
1215
|
+
throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
|
|
1216
|
+
}
|
|
1217
|
+
const standalone = getStandalone(template, open, parsed.end, parsed.kind);
|
|
1218
|
+
const beforePartial = standalone === void 0 ? template.slice(index, open) : template.slice(index, standalone.lineStart);
|
|
1219
|
+
const indent = standalone === void 0 ? "" : template.slice(standalone.lineStart, open);
|
|
1220
|
+
const partial = indentPartial(partials[parsed.name], indent);
|
|
1221
|
+
output += beforePartial + expandTemplatePartials(partial, partials, [...partialStack, parsed.name]);
|
|
1222
|
+
index = standalone?.nextIndex ?? parsed.end;
|
|
1223
|
+
}
|
|
1224
|
+
return output;
|
|
983
1225
|
}
|
|
984
1226
|
function lookupName(view, name) {
|
|
985
1227
|
if (!isPropertyContainer(view) || !hasProperty(view, name)) {
|
|
@@ -1039,22 +1281,22 @@ function hasProperty(value, key) {
|
|
|
1039
1281
|
return Object.prototype.hasOwnProperty.call(value, key);
|
|
1040
1282
|
}
|
|
1041
1283
|
|
|
1042
|
-
// ../design
|
|
1284
|
+
// ../toolcraft-design/src/components/browser.ts
|
|
1043
1285
|
import { spawn } from "node:child_process";
|
|
1044
1286
|
import process2 from "node:process";
|
|
1045
1287
|
|
|
1046
|
-
// ../design
|
|
1288
|
+
// ../toolcraft-design/src/acp/writer.ts
|
|
1047
1289
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
1048
1290
|
var storage = new AsyncLocalStorage2();
|
|
1049
1291
|
|
|
1050
|
-
// ../design
|
|
1292
|
+
// ../toolcraft-design/src/dashboard/terminal-width.ts
|
|
1051
1293
|
var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
1052
1294
|
|
|
1053
|
-
// ../design
|
|
1295
|
+
// ../toolcraft-design/src/dashboard/terminal.ts
|
|
1054
1296
|
import readline from "node:readline";
|
|
1055
1297
|
import { PassThrough } from "node:stream";
|
|
1056
1298
|
|
|
1057
|
-
// ../design
|
|
1299
|
+
// ../toolcraft-design/src/explorer/state.ts
|
|
1058
1300
|
var REGION_HEADER = 1 << 0;
|
|
1059
1301
|
var REGION_LIST = 1 << 1;
|
|
1060
1302
|
var REGION_DETAIL = 1 << 2;
|
|
@@ -1063,13 +1305,13 @@ var REGION_MODAL = 1 << 4;
|
|
|
1063
1305
|
var REGION_TOAST = 1 << 5;
|
|
1064
1306
|
var REGION_ALL = REGION_HEADER | REGION_LIST | REGION_DETAIL | REGION_FOOTER | REGION_MODAL | REGION_TOAST;
|
|
1065
1307
|
|
|
1066
|
-
// ../design
|
|
1308
|
+
// ../toolcraft-design/src/prompts/index.ts
|
|
1067
1309
|
import * as clack from "@clack/prompts";
|
|
1068
1310
|
|
|
1069
|
-
// ../design
|
|
1311
|
+
// ../toolcraft-design/src/prompts/primitives/cancel.ts
|
|
1070
1312
|
import { isCancel } from "@clack/prompts";
|
|
1071
1313
|
|
|
1072
|
-
// ../design
|
|
1314
|
+
// ../toolcraft-design/src/static/spinner.ts
|
|
1073
1315
|
var SPINNER_FRAMES = Object.freeze(["\u25D2", "\u25D0", "\u25D3", "\u25D1"]);
|
|
1074
1316
|
|
|
1075
1317
|
// ../config-mutations/src/formats/json.ts
|
|
@@ -1108,6 +1350,13 @@ function cloneConfigValue(value) {
|
|
|
1108
1350
|
function isConfigObject(value) {
|
|
1109
1351
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1110
1352
|
}
|
|
1353
|
+
function detectIndent(content) {
|
|
1354
|
+
const match = content.match(/^[\t ]+/m);
|
|
1355
|
+
if (match) {
|
|
1356
|
+
return match[0];
|
|
1357
|
+
}
|
|
1358
|
+
return " ";
|
|
1359
|
+
}
|
|
1111
1360
|
function parse3(content) {
|
|
1112
1361
|
if (!content || content.trim() === "") {
|
|
1113
1362
|
return {};
|
|
@@ -1147,6 +1396,9 @@ function merge(base, patch) {
|
|
|
1147
1396
|
}
|
|
1148
1397
|
return result;
|
|
1149
1398
|
}
|
|
1399
|
+
function configValuesEqual(left, right) {
|
|
1400
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
1401
|
+
}
|
|
1150
1402
|
function prune(obj, shape) {
|
|
1151
1403
|
let changed = false;
|
|
1152
1404
|
const result = cloneConfigObject(obj);
|
|
@@ -1183,9 +1435,56 @@ function prune(obj, shape) {
|
|
|
1183
1435
|
}
|
|
1184
1436
|
return { changed, result };
|
|
1185
1437
|
}
|
|
1438
|
+
function modifyAtPath(content, path10, value) {
|
|
1439
|
+
const indent = detectIndent(content);
|
|
1440
|
+
const formattingOptions = {
|
|
1441
|
+
tabSize: indent === " " ? 1 : indent.length,
|
|
1442
|
+
insertSpaces: indent !== " ",
|
|
1443
|
+
eol: "\n"
|
|
1444
|
+
};
|
|
1445
|
+
const edits = jsonc.modify(content, path10, value, { formattingOptions });
|
|
1446
|
+
let result = jsonc.applyEdits(content, edits);
|
|
1447
|
+
if (!result.endsWith("\n")) {
|
|
1448
|
+
result += "\n";
|
|
1449
|
+
}
|
|
1450
|
+
return result;
|
|
1451
|
+
}
|
|
1452
|
+
function removeAtPath(content, path10) {
|
|
1453
|
+
return modifyAtPath(content, path10, void 0);
|
|
1454
|
+
}
|
|
1455
|
+
function serializeUpdate(content, current, next) {
|
|
1456
|
+
let result = content || "{}";
|
|
1457
|
+
result = applyObjectUpdate(result, [], current, next);
|
|
1458
|
+
if (!result.endsWith("\n")) {
|
|
1459
|
+
result += "\n";
|
|
1460
|
+
}
|
|
1461
|
+
return result;
|
|
1462
|
+
}
|
|
1463
|
+
function applyObjectUpdate(content, path10, current, next) {
|
|
1464
|
+
let result = content;
|
|
1465
|
+
for (const key of Object.keys(current)) {
|
|
1466
|
+
if (!hasConfigEntry(next, key)) {
|
|
1467
|
+
result = removeAtPath(result, [...path10, key]);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
for (const [key, nextValue] of Object.entries(next)) {
|
|
1471
|
+
const nextPath = [...path10, key];
|
|
1472
|
+
const hasCurrent = hasConfigEntry(current, key);
|
|
1473
|
+
const currentValue = hasCurrent ? current[key] : void 0;
|
|
1474
|
+
if (hasCurrent && isConfigObject(currentValue) && isConfigObject(nextValue)) {
|
|
1475
|
+
result = applyObjectUpdate(result, nextPath, currentValue, nextValue);
|
|
1476
|
+
continue;
|
|
1477
|
+
}
|
|
1478
|
+
if (!hasCurrent || !configValuesEqual(currentValue, nextValue)) {
|
|
1479
|
+
result = modifyAtPath(result, nextPath, nextValue);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
return result;
|
|
1483
|
+
}
|
|
1186
1484
|
var jsonFormat = {
|
|
1187
1485
|
parse: parse3,
|
|
1188
1486
|
serialize,
|
|
1487
|
+
serializeUpdate,
|
|
1189
1488
|
merge,
|
|
1190
1489
|
prune
|
|
1191
1490
|
};
|
|
@@ -1567,7 +1866,7 @@ function pruneKeysByPrefix(table, prefix) {
|
|
|
1567
1866
|
const result = {};
|
|
1568
1867
|
for (const [key, value] of Object.entries(table)) {
|
|
1569
1868
|
if (!key.startsWith(prefix)) {
|
|
1570
|
-
result
|
|
1869
|
+
setConfigEntry(result, key, value);
|
|
1571
1870
|
}
|
|
1572
1871
|
}
|
|
1573
1872
|
return result;
|
|
@@ -1576,28 +1875,43 @@ function isConfigObject4(value) {
|
|
|
1576
1875
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1577
1876
|
}
|
|
1578
1877
|
function mergeWithPruneByPrefix(base, patch, pruneByPrefix) {
|
|
1579
|
-
const result =
|
|
1878
|
+
const result = cloneConfigObject(base);
|
|
1580
1879
|
const prefixMap = pruneByPrefix ?? {};
|
|
1581
1880
|
for (const [key, value] of Object.entries(patch)) {
|
|
1881
|
+
if (value === void 0) {
|
|
1882
|
+
continue;
|
|
1883
|
+
}
|
|
1582
1884
|
const current = result[key];
|
|
1583
1885
|
const prefix = prefixMap[key];
|
|
1584
1886
|
if (isConfigObject4(current) && isConfigObject4(value)) {
|
|
1585
1887
|
if (prefix) {
|
|
1586
1888
|
const pruned = pruneKeysByPrefix(current, prefix);
|
|
1587
|
-
result
|
|
1889
|
+
setConfigEntry(result, key, mergePrunedConfigObject(pruned, value));
|
|
1588
1890
|
} else {
|
|
1589
|
-
result
|
|
1590
|
-
current,
|
|
1591
|
-
value,
|
|
1592
|
-
prefixMap
|
|
1593
|
-
);
|
|
1891
|
+
setConfigEntry(result, key, mergeWithPruneByPrefix(current, value, prefixMap));
|
|
1594
1892
|
}
|
|
1595
1893
|
continue;
|
|
1596
1894
|
}
|
|
1597
|
-
result
|
|
1895
|
+
setConfigEntry(result, key, value);
|
|
1896
|
+
}
|
|
1897
|
+
return result;
|
|
1898
|
+
}
|
|
1899
|
+
function mergePrunedConfigObject(base, patch) {
|
|
1900
|
+
const result = cloneConfigObject(base);
|
|
1901
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
1902
|
+
if (value === void 0) {
|
|
1903
|
+
continue;
|
|
1904
|
+
}
|
|
1905
|
+
setConfigEntry(result, key, value);
|
|
1598
1906
|
}
|
|
1599
1907
|
return result;
|
|
1600
1908
|
}
|
|
1909
|
+
function serializeConfigUpdate(format, rawContent, current, next) {
|
|
1910
|
+
if (rawContent !== null && format.serializeUpdate) {
|
|
1911
|
+
return format.serializeUpdate(rawContent, current, next);
|
|
1912
|
+
}
|
|
1913
|
+
return format.serialize(next);
|
|
1914
|
+
}
|
|
1601
1915
|
async function applyMutation(mutation, context, options) {
|
|
1602
1916
|
switch (mutation.kind) {
|
|
1603
1917
|
case "ensureDirectory":
|
|
@@ -1910,6 +2224,7 @@ async function applyConfigMerge(mutation, context, options) {
|
|
|
1910
2224
|
}
|
|
1911
2225
|
const format = getConfigFormat(formatName);
|
|
1912
2226
|
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
2227
|
+
let preserveContent = rawContent;
|
|
1913
2228
|
let current;
|
|
1914
2229
|
try {
|
|
1915
2230
|
current = rawContent === null ? {} : format.parse(rawContent);
|
|
@@ -1918,6 +2233,7 @@ async function applyConfigMerge(mutation, context, options) {
|
|
|
1918
2233
|
await backupInvalidDocument(context, targetPath, rawContent);
|
|
1919
2234
|
}
|
|
1920
2235
|
current = {};
|
|
2236
|
+
preserveContent = null;
|
|
1921
2237
|
}
|
|
1922
2238
|
const value = resolveValue(mutation.value, options);
|
|
1923
2239
|
let merged;
|
|
@@ -1926,7 +2242,7 @@ async function applyConfigMerge(mutation, context, options) {
|
|
|
1926
2242
|
} else {
|
|
1927
2243
|
merged = format.merge(current, value);
|
|
1928
2244
|
}
|
|
1929
|
-
const serialized = format
|
|
2245
|
+
const serialized = serializeConfigUpdate(format, preserveContent, current, merged);
|
|
1930
2246
|
const changed = serialized !== rawContent;
|
|
1931
2247
|
if (changed && !context.dryRun) {
|
|
1932
2248
|
await writeAtomically(context, targetPath, serialized);
|
|
@@ -1994,7 +2310,7 @@ async function applyConfigPrune(mutation, context, options) {
|
|
|
1994
2310
|
details
|
|
1995
2311
|
};
|
|
1996
2312
|
}
|
|
1997
|
-
const serialized = format
|
|
2313
|
+
const serialized = serializeConfigUpdate(format, rawContent, current, result);
|
|
1998
2314
|
if (!context.dryRun) {
|
|
1999
2315
|
await writeAtomically(context, targetPath, serialized);
|
|
2000
2316
|
}
|
|
@@ -2019,6 +2335,7 @@ async function applyConfigTransform(mutation, context, options) {
|
|
|
2019
2335
|
}
|
|
2020
2336
|
const format = getConfigFormat(formatName);
|
|
2021
2337
|
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
2338
|
+
let preserveContent = rawContent;
|
|
2022
2339
|
let current;
|
|
2023
2340
|
try {
|
|
2024
2341
|
current = rawContent === null ? {} : format.parse(rawContent);
|
|
@@ -2027,6 +2344,7 @@ async function applyConfigTransform(mutation, context, options) {
|
|
|
2027
2344
|
await backupInvalidDocument(context, targetPath, rawContent);
|
|
2028
2345
|
}
|
|
2029
2346
|
current = {};
|
|
2347
|
+
preserveContent = null;
|
|
2030
2348
|
}
|
|
2031
2349
|
const { content: transformed, changed } = mutation.transform(current, options);
|
|
2032
2350
|
if (!changed) {
|
|
@@ -2050,7 +2368,7 @@ async function applyConfigTransform(mutation, context, options) {
|
|
|
2050
2368
|
details
|
|
2051
2369
|
};
|
|
2052
2370
|
}
|
|
2053
|
-
const serialized = format
|
|
2371
|
+
const serialized = serializeConfigUpdate(format, preserveContent, current, transformed);
|
|
2054
2372
|
if (!context.dryRun) {
|
|
2055
2373
|
await writeAtomically(context, targetPath, serialized);
|
|
2056
2374
|
}
|
|
@@ -2227,14 +2545,14 @@ async function installSkill(agentId, skill, options) {
|
|
|
2227
2545
|
throw new UnsupportedAgentError(agentId);
|
|
2228
2546
|
}
|
|
2229
2547
|
const scope = options.scope ?? "local";
|
|
2230
|
-
const
|
|
2548
|
+
const config2 = support.config;
|
|
2231
2549
|
if (skill.name.length === 0 || skill.name === "." || skill.name === ".." || skill.name.includes("/") || skill.name.includes("\\") || skill.name.includes("\n") || skill.name.includes("\r")) {
|
|
2232
2550
|
throw new Error(`Invalid skill name: ${skill.name}`);
|
|
2233
2551
|
}
|
|
2234
|
-
const skillDir = scope === "global" ?
|
|
2552
|
+
const skillDir = scope === "global" ? config2.globalSkillDir : toHomeRelative(config2.localSkillDir);
|
|
2235
2553
|
const skillFolderPath = `${skillDir}/${skill.name}`;
|
|
2236
2554
|
const skillFilePath = `${skillFolderPath}/SKILL.md`;
|
|
2237
|
-
const displayPath = `${scope === "global" ?
|
|
2555
|
+
const displayPath = `${scope === "global" ? config2.globalSkillDir : config2.localSkillDir}/${skill.name}/SKILL.md`;
|
|
2238
2556
|
const absoluteSkillPath = `${scope === "global" ? options.homeDir : options.cwd}/${skillFilePath.slice(2)}`;
|
|
2239
2557
|
if (await pathExists2(options.fs, absoluteSkillPath)) {
|
|
2240
2558
|
throw new Error(`Skill already exists: ${displayPath}`);
|
|
@@ -2293,19 +2611,19 @@ var UserError = class extends Error {
|
|
|
2293
2611
|
};
|
|
2294
2612
|
|
|
2295
2613
|
// ../toolcraft/src/human-in-loop/config.ts
|
|
2296
|
-
function validateHumanInLoopOnDefine(
|
|
2297
|
-
const label = Array.isArray(
|
|
2298
|
-
if (
|
|
2299
|
-
throw new Error(`${label} '${
|
|
2614
|
+
function validateHumanInLoopOnDefine(config2) {
|
|
2615
|
+
const label = Array.isArray(config2.children) ? "group" : "command";
|
|
2616
|
+
if (config2.confirm === true && config2.humanInLoop !== void 0 && config2.humanInLoop !== null) {
|
|
2617
|
+
throw new Error(`${label} '${config2.name}': use either confirm or humanInLoop, not both`);
|
|
2300
2618
|
}
|
|
2301
|
-
if (
|
|
2619
|
+
if (config2.humanInLoop === void 0 || config2.humanInLoop === null) {
|
|
2302
2620
|
return;
|
|
2303
2621
|
}
|
|
2304
|
-
if (
|
|
2305
|
-
throw new Error(`${label} '${
|
|
2622
|
+
if (config2.humanInLoop.mode !== "sync" && config2.humanInLoop.mode !== "async") {
|
|
2623
|
+
throw new Error(`${label} '${config2.name}': humanInLoop.mode must be "sync" or "async"`);
|
|
2306
2624
|
}
|
|
2307
|
-
if (typeof
|
|
2308
|
-
throw new Error(`${label} '${
|
|
2625
|
+
if (typeof config2.humanInLoop.message !== "function") {
|
|
2626
|
+
throw new Error(`${label} '${config2.name}': humanInLoop.message must be a function`);
|
|
2309
2627
|
}
|
|
2310
2628
|
}
|
|
2311
2629
|
function mergeHumanInLoopFromGroup(groupHumanInLoop, childHumanInLoop) {
|
|
@@ -2335,12 +2653,12 @@ function assertValidBranches(branches, discriminator) {
|
|
|
2335
2653
|
}
|
|
2336
2654
|
}
|
|
2337
2655
|
}
|
|
2338
|
-
function OneOf(
|
|
2339
|
-
assertValidBranches(
|
|
2656
|
+
function OneOf(config2) {
|
|
2657
|
+
assertValidBranches(config2.branches, config2.discriminator);
|
|
2340
2658
|
return {
|
|
2341
2659
|
kind: "oneOf",
|
|
2342
|
-
discriminator:
|
|
2343
|
-
branches:
|
|
2660
|
+
discriminator: config2.discriminator,
|
|
2661
|
+
branches: config2.branches
|
|
2344
2662
|
};
|
|
2345
2663
|
}
|
|
2346
2664
|
|
|
@@ -2620,28 +2938,28 @@ function mergeSecrets(parent, child) {
|
|
|
2620
2938
|
function resolveCommandScope(ownScope, inheritedScope) {
|
|
2621
2939
|
return cloneScope(ownScope ?? inheritedScope) ?? ["cli", "sdk"];
|
|
2622
2940
|
}
|
|
2623
|
-
function createBaseCommand(
|
|
2941
|
+
function createBaseCommand(config2) {
|
|
2624
2942
|
const command = {
|
|
2625
2943
|
kind: "command",
|
|
2626
|
-
name:
|
|
2627
|
-
description:
|
|
2628
|
-
aliases: [...
|
|
2629
|
-
positional: [...
|
|
2630
|
-
params:
|
|
2631
|
-
secrets: cloneSecrets(
|
|
2632
|
-
scope: resolveCommandScope(
|
|
2633
|
-
confirm:
|
|
2634
|
-
humanInLoop:
|
|
2635
|
-
requires: cloneRequires(
|
|
2636
|
-
handler:
|
|
2637
|
-
render:
|
|
2944
|
+
name: config2.name,
|
|
2945
|
+
description: config2.description,
|
|
2946
|
+
aliases: [...config2.aliases ?? []],
|
|
2947
|
+
positional: [...config2.positional ?? []],
|
|
2948
|
+
params: config2.params,
|
|
2949
|
+
secrets: cloneSecrets(config2.secrets),
|
|
2950
|
+
scope: resolveCommandScope(config2.scope, void 0),
|
|
2951
|
+
confirm: config2.confirm ?? false,
|
|
2952
|
+
humanInLoop: config2.humanInLoop,
|
|
2953
|
+
requires: cloneRequires(config2.requires),
|
|
2954
|
+
handler: config2.handler,
|
|
2955
|
+
render: config2.render
|
|
2638
2956
|
};
|
|
2639
2957
|
Object.defineProperty(command, commandConfigSymbol, {
|
|
2640
2958
|
value: {
|
|
2641
|
-
scope: cloneScope(
|
|
2642
|
-
humanInLoop:
|
|
2643
|
-
secrets: cloneSecrets(
|
|
2644
|
-
requires: cloneRequires(
|
|
2959
|
+
scope: cloneScope(config2.scope),
|
|
2960
|
+
humanInLoop: config2.humanInLoop,
|
|
2961
|
+
secrets: cloneSecrets(config2.secrets),
|
|
2962
|
+
requires: cloneRequires(config2.requires),
|
|
2645
2963
|
sourcePath: inferCommandSourcePath()
|
|
2646
2964
|
}
|
|
2647
2965
|
});
|
|
@@ -2681,10 +2999,10 @@ function materializeCommand(command, inherited) {
|
|
|
2681
2999
|
});
|
|
2682
3000
|
return materialized;
|
|
2683
3001
|
}
|
|
2684
|
-
function defineCommand(
|
|
2685
|
-
validateHumanInLoopOnDefine(
|
|
3002
|
+
function defineCommand(config2) {
|
|
3003
|
+
validateHumanInLoopOnDefine(config2);
|
|
2686
3004
|
return materializeCommand(
|
|
2687
|
-
createBaseCommand(
|
|
3005
|
+
createBaseCommand(config2),
|
|
2688
3006
|
{
|
|
2689
3007
|
scope: void 0,
|
|
2690
3008
|
humanInLoop: void 0,
|