terminal-pilot 0.0.19 → 0.0.20
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 +537 -242
- package/dist/cli.js.map +4 -4
- package/dist/commands/index.js +261 -37
- package/dist/commands/index.js.map +3 -3
- package/dist/commands/install.js +261 -37
- package/dist/commands/install.js.map +3 -3
- package/dist/commands/installer.js.map +1 -1
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/testing/cli-repl.js +533 -238
- package/dist/testing/cli-repl.js.map +4 -4
- package/dist/testing/qa-cli.js +543 -248
- 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 +3 -2
package/dist/commands/install.js
CHANGED
|
@@ -776,6 +776,7 @@ var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
|
776
776
|
var graphemeSegmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
777
777
|
|
|
778
778
|
// ../design-system/src/components/template.ts
|
|
779
|
+
var MAX_PARTIAL_DEPTH = 100;
|
|
779
780
|
var HTML_ESCAPE = {
|
|
780
781
|
"&": "&",
|
|
781
782
|
"<": "<",
|
|
@@ -787,14 +788,27 @@ var HTML_ESCAPE = {
|
|
|
787
788
|
"=": "="
|
|
788
789
|
};
|
|
789
790
|
function renderTemplate(template, view, options = {}) {
|
|
790
|
-
const prepared = options.yield === void 0 ? template : template.split("{{yield}}").join(options.yield);
|
|
791
|
+
const prepared = options.yield === void 0 ? template : resolveTemplatePartials(template, options.partials ?? {}).split("{{yield}}").join(options.yield);
|
|
791
792
|
const tokens = parseTemplate(prepared);
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
793
|
+
validatePartialReferences(tokens, options.partials ?? {}, []);
|
|
794
|
+
if (options.validate === true) {
|
|
795
|
+
const expanded = resolveTemplatePartials(prepared, options.partials ?? {});
|
|
796
|
+
validateVariables(parseTemplate(expanded), { view });
|
|
797
|
+
}
|
|
798
|
+
const state = {
|
|
799
|
+
escape: options.escape === "none" ? String : escapeHtml,
|
|
800
|
+
partials: options.partials ?? {},
|
|
801
|
+
partialStack: [],
|
|
802
|
+
preserveMissing: options.yield !== void 0 && options.escape === "none",
|
|
803
|
+
validate: options.validate === true
|
|
804
|
+
};
|
|
805
|
+
return renderTokens(tokens, { view }, prepared, state);
|
|
806
|
+
}
|
|
807
|
+
function resolveTemplatePartials(template, partials) {
|
|
808
|
+
return expandTemplatePartials(template, partials, []);
|
|
795
809
|
}
|
|
796
|
-
function renderTemplateInContext(template, context,
|
|
797
|
-
return renderTokens(parseTemplate(template), context, template,
|
|
810
|
+
function renderTemplateInContext(template, context, state) {
|
|
811
|
+
return renderTokens(parseTemplate(template), context, template, state);
|
|
798
812
|
}
|
|
799
813
|
function parseTemplate(template) {
|
|
800
814
|
const root = [];
|
|
@@ -817,9 +831,6 @@ function parseTemplate(template) {
|
|
|
817
831
|
index = standalone?.nextIndex ?? parsed.end;
|
|
818
832
|
continue;
|
|
819
833
|
}
|
|
820
|
-
if (parsed.kind === "partial") {
|
|
821
|
-
throw new Error(`Partials are not supported: "${parsed.name}"`);
|
|
822
|
-
}
|
|
823
834
|
if (parsed.kind === "delimiter") {
|
|
824
835
|
throw new Error("Custom delimiters are not supported");
|
|
825
836
|
}
|
|
@@ -837,6 +848,15 @@ function parseTemplate(template) {
|
|
|
837
848
|
index = standalone?.nextIndex ?? parsed.end;
|
|
838
849
|
continue;
|
|
839
850
|
}
|
|
851
|
+
if (parsed.kind === "partial") {
|
|
852
|
+
tokens.push({
|
|
853
|
+
type: "partial",
|
|
854
|
+
name: parsed.name,
|
|
855
|
+
indent: standalone === void 0 ? "" : template.slice(standalone.lineStart, open)
|
|
856
|
+
});
|
|
857
|
+
index = standalone?.nextIndex ?? parsed.end;
|
|
858
|
+
continue;
|
|
859
|
+
}
|
|
840
860
|
if (parsed.kind === "close") {
|
|
841
861
|
const frame2 = stack.pop();
|
|
842
862
|
if (frame2 === void 0) {
|
|
@@ -907,7 +927,7 @@ function getStandalone(template, tagStart, tagEnd, kind) {
|
|
|
907
927
|
}
|
|
908
928
|
return void 0;
|
|
909
929
|
}
|
|
910
|
-
function renderTokens(tokens, context, template,
|
|
930
|
+
function renderTokens(tokens, context, template, state) {
|
|
911
931
|
let output = "";
|
|
912
932
|
for (const token of tokens) {
|
|
913
933
|
switch (token.type) {
|
|
@@ -916,32 +936,62 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
|
|
|
916
936
|
continue;
|
|
917
937
|
case "name":
|
|
918
938
|
case "unescaped": {
|
|
919
|
-
const
|
|
920
|
-
if (value == null) {
|
|
921
|
-
if (
|
|
939
|
+
const result = lookup2(context, token.name);
|
|
940
|
+
if (!result.hit || result.value == null) {
|
|
941
|
+
if (state.validate) {
|
|
942
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
943
|
+
}
|
|
944
|
+
if (state.preserveMissing) {
|
|
922
945
|
output += token.raw;
|
|
923
946
|
}
|
|
924
947
|
continue;
|
|
925
948
|
}
|
|
926
|
-
const rendered = String(value);
|
|
927
|
-
output += token.type === "name" ? escape(rendered) : rendered;
|
|
949
|
+
const rendered = String(result.value);
|
|
950
|
+
output += token.type === "name" ? state.escape(rendered) : rendered;
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
case "partial": {
|
|
954
|
+
if (!Object.hasOwn(state.partials, token.name)) {
|
|
955
|
+
throw new Error(`Partial "${token.name}" not found.`);
|
|
956
|
+
}
|
|
957
|
+
if (state.partialStack.includes(token.name)) {
|
|
958
|
+
throw new Error(
|
|
959
|
+
`Circular partial reference detected: ${[...state.partialStack, token.name].join(" -> ")}.`
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
if (state.partialStack.length >= MAX_PARTIAL_DEPTH) {
|
|
963
|
+
throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
|
|
964
|
+
}
|
|
965
|
+
const partial = indentPartial(state.partials[token.name], token.indent);
|
|
966
|
+
output += renderTokens(parseTemplate(partial), context, partial, {
|
|
967
|
+
...state,
|
|
968
|
+
partialStack: [...state.partialStack, token.name]
|
|
969
|
+
});
|
|
928
970
|
continue;
|
|
929
971
|
}
|
|
930
972
|
case "inverted": {
|
|
931
|
-
const
|
|
973
|
+
const result = lookup2(context, token.name);
|
|
974
|
+
if (!result.hit && state.validate) {
|
|
975
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
976
|
+
}
|
|
977
|
+
const value = result.value;
|
|
932
978
|
if (!value || Array.isArray(value) && value.length === 0) {
|
|
933
|
-
output += renderTokens(token.children, context, template,
|
|
979
|
+
output += renderTokens(token.children, context, template, state);
|
|
934
980
|
}
|
|
935
981
|
continue;
|
|
936
982
|
}
|
|
937
983
|
case "section": {
|
|
938
|
-
const
|
|
984
|
+
const result = lookup2(context, token.name);
|
|
985
|
+
if (!result.hit && state.validate) {
|
|
986
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
987
|
+
}
|
|
988
|
+
const value = result.value;
|
|
939
989
|
if (!value) {
|
|
940
990
|
continue;
|
|
941
991
|
}
|
|
942
992
|
if (Array.isArray(value)) {
|
|
943
993
|
for (const item of value) {
|
|
944
|
-
output += renderTokens(token.children, pushContext(context, item), template,
|
|
994
|
+
output += renderTokens(token.children, pushContext(context, item), template, state);
|
|
945
995
|
}
|
|
946
996
|
continue;
|
|
947
997
|
}
|
|
@@ -950,7 +1000,7 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
|
|
|
950
1000
|
const rendered = value.call(
|
|
951
1001
|
context.view,
|
|
952
1002
|
raw,
|
|
953
|
-
(nextTemplate) => renderTemplateInContext(nextTemplate, context,
|
|
1003
|
+
(nextTemplate) => renderTemplateInContext(nextTemplate, context, state)
|
|
954
1004
|
);
|
|
955
1005
|
if (rendered != null) {
|
|
956
1006
|
output += String(rendered);
|
|
@@ -958,10 +1008,10 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
|
|
|
958
1008
|
continue;
|
|
959
1009
|
}
|
|
960
1010
|
if (typeof value === "object" || typeof value === "string" || typeof value === "number") {
|
|
961
|
-
output += renderTokens(token.children, pushContext(context, value), template,
|
|
1011
|
+
output += renderTokens(token.children, pushContext(context, value), template, state);
|
|
962
1012
|
continue;
|
|
963
1013
|
}
|
|
964
|
-
output += renderTokens(token.children, context, template,
|
|
1014
|
+
output += renderTokens(token.children, context, template, state);
|
|
965
1015
|
}
|
|
966
1016
|
}
|
|
967
1017
|
}
|
|
@@ -969,17 +1019,115 @@ function renderTokens(tokens, context, template, escape, preserveMissing) {
|
|
|
969
1019
|
}
|
|
970
1020
|
function lookup2(context, name) {
|
|
971
1021
|
if (name === ".") {
|
|
972
|
-
return callLambda(context.view, context.view);
|
|
1022
|
+
return { hit: true, value: callLambda(context.view, context.view) };
|
|
973
1023
|
}
|
|
974
1024
|
let cursor = context;
|
|
975
1025
|
while (cursor !== void 0) {
|
|
976
1026
|
const result = name.includes(".") ? lookupDotted(cursor.view, name) : lookupName(cursor.view, name);
|
|
977
1027
|
if (result.hit) {
|
|
978
|
-
return callLambda(result.value, cursor.view);
|
|
1028
|
+
return { hit: true, value: callLambda(result.value, cursor.view) };
|
|
979
1029
|
}
|
|
980
1030
|
cursor = cursor.parent;
|
|
981
1031
|
}
|
|
982
|
-
return void 0;
|
|
1032
|
+
return { hit: false, value: void 0 };
|
|
1033
|
+
}
|
|
1034
|
+
function validateVariables(tokens, context) {
|
|
1035
|
+
for (const token of tokens) {
|
|
1036
|
+
if (token.type === "text" || token.type === "partial") {
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
if (token.type === "name" || token.type === "unescaped") {
|
|
1040
|
+
if (!lookup2(context, token.name).hit) {
|
|
1041
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
1042
|
+
}
|
|
1043
|
+
continue;
|
|
1044
|
+
}
|
|
1045
|
+
if (token.type !== "section" && token.type !== "inverted") {
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
const result = lookup2(context, token.name);
|
|
1049
|
+
if (!result.hit) {
|
|
1050
|
+
throw new Error(`Template variable "${token.name}" not found.`);
|
|
1051
|
+
}
|
|
1052
|
+
if (Array.isArray(result.value) && result.value.length > 0) {
|
|
1053
|
+
for (const item of result.value) {
|
|
1054
|
+
validateVariables(token.children, pushContext(context, item));
|
|
1055
|
+
}
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
if (typeof result.value === "object" && result.value !== null || typeof result.value === "string" || typeof result.value === "number") {
|
|
1059
|
+
validateVariables(token.children, pushContext(context, result.value));
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
validateVariables(token.children, context);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
function validatePartialReferences(tokens, partials, partialStack) {
|
|
1066
|
+
for (const token of tokens) {
|
|
1067
|
+
if (token.type === "section" || token.type === "inverted") {
|
|
1068
|
+
validatePartialReferences(token.children, partials, partialStack);
|
|
1069
|
+
continue;
|
|
1070
|
+
}
|
|
1071
|
+
if (token.type !== "partial") {
|
|
1072
|
+
continue;
|
|
1073
|
+
}
|
|
1074
|
+
if (!Object.hasOwn(partials, token.name)) {
|
|
1075
|
+
throw new Error(`Partial "${token.name}" not found.`);
|
|
1076
|
+
}
|
|
1077
|
+
if (partialStack.includes(token.name)) {
|
|
1078
|
+
throw new Error(
|
|
1079
|
+
`Circular partial reference detected: ${[...partialStack, token.name].join(" -> ")}.`
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
if (partialStack.length >= MAX_PARTIAL_DEPTH) {
|
|
1083
|
+
throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
|
|
1084
|
+
}
|
|
1085
|
+
validatePartialReferences(parseTemplate(partials[token.name]), partials, [
|
|
1086
|
+
...partialStack,
|
|
1087
|
+
token.name
|
|
1088
|
+
]);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
function indentPartial(partial, indent) {
|
|
1092
|
+
if (indent === "") {
|
|
1093
|
+
return partial;
|
|
1094
|
+
}
|
|
1095
|
+
return partial.split("\n").map((line) => line === "" ? "" : `${indent}${line}`).join("\n");
|
|
1096
|
+
}
|
|
1097
|
+
function expandTemplatePartials(template, partials, partialStack) {
|
|
1098
|
+
let output = "";
|
|
1099
|
+
let index = 0;
|
|
1100
|
+
while (index < template.length) {
|
|
1101
|
+
const open = template.indexOf("{{", index);
|
|
1102
|
+
if (open === -1) {
|
|
1103
|
+
output += template.slice(index);
|
|
1104
|
+
break;
|
|
1105
|
+
}
|
|
1106
|
+
const parsed = parseTag(template, open);
|
|
1107
|
+
if (parsed.kind !== "partial") {
|
|
1108
|
+
output += template.slice(index, parsed.end);
|
|
1109
|
+
index = parsed.end;
|
|
1110
|
+
continue;
|
|
1111
|
+
}
|
|
1112
|
+
if (!Object.hasOwn(partials, parsed.name)) {
|
|
1113
|
+
throw new Error(`Partial "${parsed.name}" not found.`);
|
|
1114
|
+
}
|
|
1115
|
+
if (partialStack.includes(parsed.name)) {
|
|
1116
|
+
throw new Error(
|
|
1117
|
+
`Circular partial reference detected: ${[...partialStack, parsed.name].join(" -> ")}.`
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
if (partialStack.length >= MAX_PARTIAL_DEPTH) {
|
|
1121
|
+
throw new Error(`Maximum partial depth exceeded (${MAX_PARTIAL_DEPTH}).`);
|
|
1122
|
+
}
|
|
1123
|
+
const standalone = getStandalone(template, open, parsed.end, parsed.kind);
|
|
1124
|
+
const beforePartial = standalone === void 0 ? template.slice(index, open) : template.slice(index, standalone.lineStart);
|
|
1125
|
+
const indent = standalone === void 0 ? "" : template.slice(standalone.lineStart, open);
|
|
1126
|
+
const partial = indentPartial(partials[parsed.name], indent);
|
|
1127
|
+
output += beforePartial + expandTemplatePartials(partial, partials, [...partialStack, parsed.name]);
|
|
1128
|
+
index = standalone?.nextIndex ?? parsed.end;
|
|
1129
|
+
}
|
|
1130
|
+
return output;
|
|
983
1131
|
}
|
|
984
1132
|
function lookupName(view, name) {
|
|
985
1133
|
if (!isPropertyContainer(view) || !hasProperty(view, name)) {
|
|
@@ -1108,6 +1256,13 @@ function cloneConfigValue(value) {
|
|
|
1108
1256
|
function isConfigObject(value) {
|
|
1109
1257
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1110
1258
|
}
|
|
1259
|
+
function detectIndent(content) {
|
|
1260
|
+
const match = content.match(/^[\t ]+/m);
|
|
1261
|
+
if (match) {
|
|
1262
|
+
return match[0];
|
|
1263
|
+
}
|
|
1264
|
+
return " ";
|
|
1265
|
+
}
|
|
1111
1266
|
function parse3(content) {
|
|
1112
1267
|
if (!content || content.trim() === "") {
|
|
1113
1268
|
return {};
|
|
@@ -1147,6 +1302,9 @@ function merge(base, patch) {
|
|
|
1147
1302
|
}
|
|
1148
1303
|
return result;
|
|
1149
1304
|
}
|
|
1305
|
+
function configValuesEqual(left, right) {
|
|
1306
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
1307
|
+
}
|
|
1150
1308
|
function prune(obj, shape) {
|
|
1151
1309
|
let changed = false;
|
|
1152
1310
|
const result = cloneConfigObject(obj);
|
|
@@ -1183,9 +1341,56 @@ function prune(obj, shape) {
|
|
|
1183
1341
|
}
|
|
1184
1342
|
return { changed, result };
|
|
1185
1343
|
}
|
|
1344
|
+
function modifyAtPath(content, path10, value) {
|
|
1345
|
+
const indent = detectIndent(content);
|
|
1346
|
+
const formattingOptions = {
|
|
1347
|
+
tabSize: indent === " " ? 1 : indent.length,
|
|
1348
|
+
insertSpaces: indent !== " ",
|
|
1349
|
+
eol: "\n"
|
|
1350
|
+
};
|
|
1351
|
+
const edits = jsonc.modify(content, path10, value, { formattingOptions });
|
|
1352
|
+
let result = jsonc.applyEdits(content, edits);
|
|
1353
|
+
if (!result.endsWith("\n")) {
|
|
1354
|
+
result += "\n";
|
|
1355
|
+
}
|
|
1356
|
+
return result;
|
|
1357
|
+
}
|
|
1358
|
+
function removeAtPath(content, path10) {
|
|
1359
|
+
return modifyAtPath(content, path10, void 0);
|
|
1360
|
+
}
|
|
1361
|
+
function serializeUpdate(content, current, next) {
|
|
1362
|
+
let result = content || "{}";
|
|
1363
|
+
result = applyObjectUpdate(result, [], current, next);
|
|
1364
|
+
if (!result.endsWith("\n")) {
|
|
1365
|
+
result += "\n";
|
|
1366
|
+
}
|
|
1367
|
+
return result;
|
|
1368
|
+
}
|
|
1369
|
+
function applyObjectUpdate(content, path10, current, next) {
|
|
1370
|
+
let result = content;
|
|
1371
|
+
for (const key of Object.keys(current)) {
|
|
1372
|
+
if (!hasConfigEntry(next, key)) {
|
|
1373
|
+
result = removeAtPath(result, [...path10, key]);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
for (const [key, nextValue] of Object.entries(next)) {
|
|
1377
|
+
const nextPath = [...path10, key];
|
|
1378
|
+
const hasCurrent = hasConfigEntry(current, key);
|
|
1379
|
+
const currentValue = hasCurrent ? current[key] : void 0;
|
|
1380
|
+
if (hasCurrent && isConfigObject(currentValue) && isConfigObject(nextValue)) {
|
|
1381
|
+
result = applyObjectUpdate(result, nextPath, currentValue, nextValue);
|
|
1382
|
+
continue;
|
|
1383
|
+
}
|
|
1384
|
+
if (!hasCurrent || !configValuesEqual(currentValue, nextValue)) {
|
|
1385
|
+
result = modifyAtPath(result, nextPath, nextValue);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
return result;
|
|
1389
|
+
}
|
|
1186
1390
|
var jsonFormat = {
|
|
1187
1391
|
parse: parse3,
|
|
1188
1392
|
serialize,
|
|
1393
|
+
serializeUpdate,
|
|
1189
1394
|
merge,
|
|
1190
1395
|
prune
|
|
1191
1396
|
};
|
|
@@ -1567,7 +1772,7 @@ function pruneKeysByPrefix(table, prefix) {
|
|
|
1567
1772
|
const result = {};
|
|
1568
1773
|
for (const [key, value] of Object.entries(table)) {
|
|
1569
1774
|
if (!key.startsWith(prefix)) {
|
|
1570
|
-
result
|
|
1775
|
+
setConfigEntry(result, key, value);
|
|
1571
1776
|
}
|
|
1572
1777
|
}
|
|
1573
1778
|
return result;
|
|
@@ -1576,28 +1781,43 @@ function isConfigObject4(value) {
|
|
|
1576
1781
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1577
1782
|
}
|
|
1578
1783
|
function mergeWithPruneByPrefix(base, patch, pruneByPrefix) {
|
|
1579
|
-
const result =
|
|
1784
|
+
const result = cloneConfigObject(base);
|
|
1580
1785
|
const prefixMap = pruneByPrefix ?? {};
|
|
1581
1786
|
for (const [key, value] of Object.entries(patch)) {
|
|
1787
|
+
if (value === void 0) {
|
|
1788
|
+
continue;
|
|
1789
|
+
}
|
|
1582
1790
|
const current = result[key];
|
|
1583
1791
|
const prefix = prefixMap[key];
|
|
1584
1792
|
if (isConfigObject4(current) && isConfigObject4(value)) {
|
|
1585
1793
|
if (prefix) {
|
|
1586
1794
|
const pruned = pruneKeysByPrefix(current, prefix);
|
|
1587
|
-
result
|
|
1795
|
+
setConfigEntry(result, key, mergePrunedConfigObject(pruned, value));
|
|
1588
1796
|
} else {
|
|
1589
|
-
result
|
|
1590
|
-
current,
|
|
1591
|
-
value,
|
|
1592
|
-
prefixMap
|
|
1593
|
-
);
|
|
1797
|
+
setConfigEntry(result, key, mergeWithPruneByPrefix(current, value, prefixMap));
|
|
1594
1798
|
}
|
|
1595
1799
|
continue;
|
|
1596
1800
|
}
|
|
1597
|
-
result
|
|
1801
|
+
setConfigEntry(result, key, value);
|
|
1598
1802
|
}
|
|
1599
1803
|
return result;
|
|
1600
1804
|
}
|
|
1805
|
+
function mergePrunedConfigObject(base, patch) {
|
|
1806
|
+
const result = cloneConfigObject(base);
|
|
1807
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
1808
|
+
if (value === void 0) {
|
|
1809
|
+
continue;
|
|
1810
|
+
}
|
|
1811
|
+
setConfigEntry(result, key, value);
|
|
1812
|
+
}
|
|
1813
|
+
return result;
|
|
1814
|
+
}
|
|
1815
|
+
function serializeConfigUpdate(format, rawContent, current, next) {
|
|
1816
|
+
if (rawContent !== null && format.serializeUpdate) {
|
|
1817
|
+
return format.serializeUpdate(rawContent, current, next);
|
|
1818
|
+
}
|
|
1819
|
+
return format.serialize(next);
|
|
1820
|
+
}
|
|
1601
1821
|
async function applyMutation(mutation, context, options) {
|
|
1602
1822
|
switch (mutation.kind) {
|
|
1603
1823
|
case "ensureDirectory":
|
|
@@ -1910,6 +2130,7 @@ async function applyConfigMerge(mutation, context, options) {
|
|
|
1910
2130
|
}
|
|
1911
2131
|
const format = getConfigFormat(formatName);
|
|
1912
2132
|
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
2133
|
+
let preserveContent = rawContent;
|
|
1913
2134
|
let current;
|
|
1914
2135
|
try {
|
|
1915
2136
|
current = rawContent === null ? {} : format.parse(rawContent);
|
|
@@ -1918,6 +2139,7 @@ async function applyConfigMerge(mutation, context, options) {
|
|
|
1918
2139
|
await backupInvalidDocument(context, targetPath, rawContent);
|
|
1919
2140
|
}
|
|
1920
2141
|
current = {};
|
|
2142
|
+
preserveContent = null;
|
|
1921
2143
|
}
|
|
1922
2144
|
const value = resolveValue(mutation.value, options);
|
|
1923
2145
|
let merged;
|
|
@@ -1926,7 +2148,7 @@ async function applyConfigMerge(mutation, context, options) {
|
|
|
1926
2148
|
} else {
|
|
1927
2149
|
merged = format.merge(current, value);
|
|
1928
2150
|
}
|
|
1929
|
-
const serialized = format
|
|
2151
|
+
const serialized = serializeConfigUpdate(format, preserveContent, current, merged);
|
|
1930
2152
|
const changed = serialized !== rawContent;
|
|
1931
2153
|
if (changed && !context.dryRun) {
|
|
1932
2154
|
await writeAtomically(context, targetPath, serialized);
|
|
@@ -1994,7 +2216,7 @@ async function applyConfigPrune(mutation, context, options) {
|
|
|
1994
2216
|
details
|
|
1995
2217
|
};
|
|
1996
2218
|
}
|
|
1997
|
-
const serialized = format
|
|
2219
|
+
const serialized = serializeConfigUpdate(format, rawContent, current, result);
|
|
1998
2220
|
if (!context.dryRun) {
|
|
1999
2221
|
await writeAtomically(context, targetPath, serialized);
|
|
2000
2222
|
}
|
|
@@ -2019,6 +2241,7 @@ async function applyConfigTransform(mutation, context, options) {
|
|
|
2019
2241
|
}
|
|
2020
2242
|
const format = getConfigFormat(formatName);
|
|
2021
2243
|
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
2244
|
+
let preserveContent = rawContent;
|
|
2022
2245
|
let current;
|
|
2023
2246
|
try {
|
|
2024
2247
|
current = rawContent === null ? {} : format.parse(rawContent);
|
|
@@ -2027,6 +2250,7 @@ async function applyConfigTransform(mutation, context, options) {
|
|
|
2027
2250
|
await backupInvalidDocument(context, targetPath, rawContent);
|
|
2028
2251
|
}
|
|
2029
2252
|
current = {};
|
|
2253
|
+
preserveContent = null;
|
|
2030
2254
|
}
|
|
2031
2255
|
const { content: transformed, changed } = mutation.transform(current, options);
|
|
2032
2256
|
if (!changed) {
|
|
@@ -2050,7 +2274,7 @@ async function applyConfigTransform(mutation, context, options) {
|
|
|
2050
2274
|
details
|
|
2051
2275
|
};
|
|
2052
2276
|
}
|
|
2053
|
-
const serialized = format
|
|
2277
|
+
const serialized = serializeConfigUpdate(format, preserveContent, current, transformed);
|
|
2054
2278
|
if (!context.dryRun) {
|
|
2055
2279
|
await writeAtomically(context, targetPath, serialized);
|
|
2056
2280
|
}
|