pakhale 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/cli.js +1031 -69
- package/package.json +2 -1
- package/skills/think-from-first-principles/SKILL.md +114 -0
- package/skills/sitedrop/SKILL.md +0 -40
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { homedir } from "node:os";
|
|
|
6
6
|
import { parseArgs, styleText } from "node:util";
|
|
7
7
|
import process$1, { stdin, stdout } from "node:process";
|
|
8
8
|
import l__default from "node:readline";
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
9
10
|
import { spawn } from "node:child_process";
|
|
10
11
|
|
|
11
12
|
//#region rolldown:runtime
|
|
@@ -104,7 +105,7 @@ var require_picocolors = /* @__PURE__ */ __commonJS({ "node_modules/picocolors/p
|
|
|
104
105
|
|
|
105
106
|
//#endregion
|
|
106
107
|
//#region config.ts
|
|
107
|
-
var import_picocolors$
|
|
108
|
+
var import_picocolors$4 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
108
109
|
const config = {
|
|
109
110
|
agents: ["claude-code", "opencode"],
|
|
110
111
|
marketplaces: {
|
|
@@ -195,6 +196,14 @@ const config = {
|
|
|
195
196
|
repo: "github/gh-stack",
|
|
196
197
|
skills: ["gh-stack"]
|
|
197
198
|
} }
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
name: "sitedrop",
|
|
202
|
+
deliver: { all: {
|
|
203
|
+
via: "skills",
|
|
204
|
+
repo: "pratikpakhale/sitedrop",
|
|
205
|
+
skills: ["sitedrop"]
|
|
206
|
+
} }
|
|
198
207
|
}
|
|
199
208
|
],
|
|
200
209
|
authoredSkillsDir: "skills",
|
|
@@ -218,14 +227,14 @@ const config = {
|
|
|
218
227
|
//#endregion
|
|
219
228
|
//#region src/util/log.ts
|
|
220
229
|
const log = {
|
|
221
|
-
agent: (s) => console.log(`\n${import_picocolors$
|
|
222
|
-
section: (s) => console.log(`\n${import_picocolors$
|
|
223
|
-
ok: (s) => console.log(` ${import_picocolors$
|
|
224
|
-
skip: (s) => console.log(` ${import_picocolors$
|
|
225
|
-
warn: (s) => console.log(` ${import_picocolors$
|
|
226
|
-
fail: (s) => console.log(` ${import_picocolors$
|
|
227
|
-
plan: (s) => console.log(` ${import_picocolors$
|
|
228
|
-
info: (s) => console.log(` ${import_picocolors$
|
|
230
|
+
agent: (s) => console.log(`\n${import_picocolors$4.default.bold(import_picocolors$4.default.magenta(`■ ${s}`))}`),
|
|
231
|
+
section: (s) => console.log(`\n${import_picocolors$4.default.bold(import_picocolors$4.default.cyan(`▸ ${s}`))}`),
|
|
232
|
+
ok: (s) => console.log(` ${import_picocolors$4.default.green("✓")} ${s}`),
|
|
233
|
+
skip: (s) => console.log(` ${import_picocolors$4.default.dim("·")} ${import_picocolors$4.default.dim(s)}`),
|
|
234
|
+
warn: (s) => console.log(` ${import_picocolors$4.default.yellow("!")} ${s}`),
|
|
235
|
+
fail: (s) => console.log(` ${import_picocolors$4.default.red("✗")} ${s}`),
|
|
236
|
+
plan: (s) => console.log(` ${import_picocolors$4.default.yellow("would")} ${s}`),
|
|
237
|
+
info: (s) => console.log(` ${import_picocolors$4.default.dim(s)}`)
|
|
229
238
|
};
|
|
230
239
|
|
|
231
240
|
//#endregion
|
|
@@ -633,7 +642,7 @@ function isActionKey(n$2, e) {
|
|
|
633
642
|
for (const s of n$2) if (s !== void 0 && isActionKey(s, e)) return true;
|
|
634
643
|
return false;
|
|
635
644
|
}
|
|
636
|
-
function diffLines(i$1, s) {
|
|
645
|
+
function diffLines$1(i$1, s) {
|
|
637
646
|
if (i$1 === s) return;
|
|
638
647
|
const e = i$1.split(`
|
|
639
648
|
`), t = s.split(`
|
|
@@ -661,8 +670,8 @@ function wrapTextWithPrefix(e, r$1, o, t = o, s = o, n$2) {
|
|
|
661
670
|
hard: true,
|
|
662
671
|
trim: false
|
|
663
672
|
}).split(`
|
|
664
|
-
`).map((c, i$1, m$1) => {
|
|
665
|
-
const d = n$2 ? n$2(c, i$1) : c;
|
|
673
|
+
`).map((c$1, i$1, m$1) => {
|
|
674
|
+
const d = n$2 ? n$2(c$1, i$1) : c$1;
|
|
666
675
|
return i$1 === 0 ? `${t}${d}` : i$1 === m$1.length - 1 ? `${s}${d}` : `${o}${d}`;
|
|
667
676
|
}).join(`
|
|
668
677
|
`);
|
|
@@ -813,7 +822,7 @@ var V = class {
|
|
|
813
822
|
if (t !== this._prevFrame) {
|
|
814
823
|
if (this.state === "initial") this.output.write(import_src$1.cursor.hide);
|
|
815
824
|
else {
|
|
816
|
-
const e = diffLines(this._prevFrame, t), i$1 = getRows(this.output);
|
|
825
|
+
const e = diffLines$1(this._prevFrame, t), i$1 = getRows(this.output);
|
|
817
826
|
if (this.restoreCursor(), e) {
|
|
818
827
|
const n$2 = Math.max(0, e.numLinesAfter - i$1), s = Math.max(0, e.numLinesBefore - i$1);
|
|
819
828
|
let r$1 = e.lines.find((o) => o >= n$2);
|
|
@@ -891,6 +900,34 @@ var a = class extends V {
|
|
|
891
900
|
});
|
|
892
901
|
}
|
|
893
902
|
};
|
|
903
|
+
let n$1 = class n$2 extends V {
|
|
904
|
+
options;
|
|
905
|
+
cursor = 0;
|
|
906
|
+
get _selectedValue() {
|
|
907
|
+
return this.options[this.cursor];
|
|
908
|
+
}
|
|
909
|
+
changeValue() {
|
|
910
|
+
const e = this._selectedValue;
|
|
911
|
+
this.value = e === void 0 ? void 0 : e.value;
|
|
912
|
+
}
|
|
913
|
+
constructor(e) {
|
|
914
|
+
super(e, false), this.options = e.options;
|
|
915
|
+
const o = this.options.findIndex(({ value: s }) => s === e.initialValue), t = o === -1 ? 0 : o;
|
|
916
|
+
this.cursor = this.options[t]?.disabled ? findCursor(t, 1, this.options) : t, this.changeValue(), this.on("cursor", (s) => {
|
|
917
|
+
switch (s) {
|
|
918
|
+
case "left":
|
|
919
|
+
case "up":
|
|
920
|
+
this.cursor = findCursor(this.cursor, -1, this.options);
|
|
921
|
+
break;
|
|
922
|
+
case "down":
|
|
923
|
+
case "right":
|
|
924
|
+
this.cursor = findCursor(this.cursor, 1, this.options);
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
this.changeValue();
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
};
|
|
894
931
|
|
|
895
932
|
//#endregion
|
|
896
933
|
//#region node_modules/@clack/prompts/dist/index.mjs
|
|
@@ -939,11 +976,11 @@ const limitOptions = ({ cursor: l, options: e, style: w, output: p$1 = process.s
|
|
|
939
976
|
const i$1 = getColumns(p$1) - C, m$1 = getRows(p$1), M = styleText("dim", "..."), v = Math.max(m$1 - r$1, 0), a$1 = Math.max(Math.min(b, v), 5);
|
|
940
977
|
let f = 0;
|
|
941
978
|
l >= a$1 - 3 && (f = Math.max(Math.min(l - a$1 + 3, e.length - a$1), 0));
|
|
942
|
-
let d = a$1 < e.length && f > 0, c = a$1 < e.length && f + a$1 < e.length;
|
|
979
|
+
let d = a$1 < e.length && f > 0, c$1 = a$1 < e.length && f + a$1 < e.length;
|
|
943
980
|
const W = Math.min(f + a$1, e.length), s = [];
|
|
944
981
|
let g = 0;
|
|
945
|
-
d && g++, c && g++;
|
|
946
|
-
const T = f + (d ? 1 : 0), y = W - (c ? 1 : 0);
|
|
982
|
+
d && g++, c$1 && g++;
|
|
983
|
+
const T = f + (d ? 1 : 0), y = W - (c$1 ? 1 : 0);
|
|
947
984
|
for (let t = T; t < y; t++) {
|
|
948
985
|
const n$2 = e[t], h$1 = wrapAnsi(n$2 ? w(n$2, t === l) : "", i$1, {
|
|
949
986
|
hard: true,
|
|
@@ -957,12 +994,12 @@ const limitOptions = ({ cursor: l, options: e, style: w, output: p$1 = process.s
|
|
|
957
994
|
const h$1 = l - T;
|
|
958
995
|
let u$4 = v;
|
|
959
996
|
const L = () => I(s, o, 0, h$1, u$4), E = () => I(s, o, h$1 + 1, s.length, u$4, true);
|
|
960
|
-
d ? ({lineCount: o, removals: t} = L(), o > u$4 && (c || (u$4 -= 1), {lineCount: o, removals: n$2} = E())) : (c || (u$4 -= 1), {lineCount: o, removals: n$2} = E(), o > u$4 && (u$4 -= 1, {lineCount: o, removals: t} = L())), t > 0 && (d = true, s.splice(0, t)), n$2 > 0 && (c = true, s.splice(s.length - n$2, n$2));
|
|
997
|
+
d ? ({lineCount: o, removals: t} = L(), o > u$4 && (c$1 || (u$4 -= 1), {lineCount: o, removals: n$2} = E())) : (c$1 || (u$4 -= 1), {lineCount: o, removals: n$2} = E(), o > u$4 && (u$4 -= 1, {lineCount: o, removals: t} = L())), t > 0 && (d = true, s.splice(0, t)), n$2 > 0 && (c$1 = true, s.splice(s.length - n$2, n$2));
|
|
961
998
|
}
|
|
962
999
|
const x = [];
|
|
963
1000
|
d && x.push(M);
|
|
964
1001
|
for (const t of s) for (const n$2 of t) x.push(n$2);
|
|
965
|
-
return c && x.push(M), x;
|
|
1002
|
+
return c$1 && x.push(M), x;
|
|
966
1003
|
};
|
|
967
1004
|
const MULTISELECT_INSTRUCTIONS = [
|
|
968
1005
|
`${styleText("dim", "↑/↓")} to navigate`,
|
|
@@ -1074,6 +1111,63 @@ const u$3 = {
|
|
|
1074
1111
|
block: unicodeOr("█", "#")
|
|
1075
1112
|
};
|
|
1076
1113
|
const SELECT_INSTRUCTIONS = [`${styleText("dim", "↑/↓")} to navigate`, `${styleText("dim", "Enter:")} confirm`];
|
|
1114
|
+
const c = (t, o) => t.includes(`
|
|
1115
|
+
`) ? t.split(`
|
|
1116
|
+
`).map((d) => o(d)).join(`
|
|
1117
|
+
`) : o(t);
|
|
1118
|
+
const select$1 = (t) => {
|
|
1119
|
+
const o = (n$2, m$1) => {
|
|
1120
|
+
if (n$2 === void 0) return "";
|
|
1121
|
+
const s = n$2.label ?? String(n$2.value);
|
|
1122
|
+
switch (m$1) {
|
|
1123
|
+
case "disabled": return `${styleText("gray", S_RADIO_INACTIVE)} ${c(s, (i$1) => styleText("gray", i$1))}${n$2.hint ? ` ${styleText("dim", `(${n$2.hint ?? "disabled"})`)}` : ""}`;
|
|
1124
|
+
case "selected": return `${c(s, (i$1) => styleText("dim", i$1))}`;
|
|
1125
|
+
case "active": return `${styleText("green", S_RADIO_ACTIVE)} ${s}${n$2.hint ? ` ${styleText("dim", `(${n$2.hint})`)}` : ""}`;
|
|
1126
|
+
case "cancelled": return `${c(s, (i$1) => styleText(["strikethrough", "dim"], i$1))}`;
|
|
1127
|
+
default: return `${styleText("dim", S_RADIO_INACTIVE)} ${c(s, (i$1) => styleText("dim", i$1))}`;
|
|
1128
|
+
}
|
|
1129
|
+
}, d = t.showInstructions ?? true;
|
|
1130
|
+
return new n$1({
|
|
1131
|
+
options: t.options,
|
|
1132
|
+
signal: t.signal,
|
|
1133
|
+
input: t.input,
|
|
1134
|
+
output: t.output,
|
|
1135
|
+
initialValue: t.initialValue,
|
|
1136
|
+
render() {
|
|
1137
|
+
const n$2 = t.withGuide ?? settings.withGuide, m$1 = `${symbol(this.state)} `, s = `${symbolBar(this.state)} `, i$1 = wrapTextWithPrefix(t.output, t.message, s, m$1), u$4 = `${n$2 ? `${styleText("gray", S_BAR)}
|
|
1138
|
+
` : ""}${i$1}
|
|
1139
|
+
`;
|
|
1140
|
+
switch (this.state) {
|
|
1141
|
+
case "submit": {
|
|
1142
|
+
const r$1 = n$2 ? `${styleText("gray", S_BAR)} ` : "";
|
|
1143
|
+
return `${u$4}${wrapTextWithPrefix(t.output, o(this.options[this.cursor], "selected"), r$1)}`;
|
|
1144
|
+
}
|
|
1145
|
+
case "cancel": {
|
|
1146
|
+
const r$1 = n$2 ? `${styleText("gray", S_BAR)} ` : "";
|
|
1147
|
+
return `${u$4}${wrapTextWithPrefix(t.output, o(this.options[this.cursor], "cancelled"), r$1)}${n$2 ? `
|
|
1148
|
+
${styleText("gray", S_BAR)}` : ""}`;
|
|
1149
|
+
}
|
|
1150
|
+
default: {
|
|
1151
|
+
const r$1 = n$2 ? `${styleText("cyan", S_BAR)} ` : "", a$1 = u$4.split(`
|
|
1152
|
+
`).length, p$1 = d ? formatInstructionFooter(SELECT_INSTRUCTIONS, n$2) : n$2 ? [styleText("cyan", S_BAR_END)] : [], b = p$1.join(`
|
|
1153
|
+
`), f = p$1.length + 1;
|
|
1154
|
+
return `${u$4}${r$1}${limitOptions({
|
|
1155
|
+
output: t.output,
|
|
1156
|
+
cursor: this.cursor,
|
|
1157
|
+
options: this.options,
|
|
1158
|
+
maxItems: t.maxItems,
|
|
1159
|
+
columnPadding: r$1.length,
|
|
1160
|
+
rowPadding: a$1 + f,
|
|
1161
|
+
style: (g, x) => o(g, g.disabled ? "disabled" : x ? "active" : "inactive")
|
|
1162
|
+
}).join(`
|
|
1163
|
+
${r$1}`)}
|
|
1164
|
+
${b}
|
|
1165
|
+
`;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}).prompt();
|
|
1170
|
+
};
|
|
1077
1171
|
const i = `${styleText("gray", S_BAR)} `;
|
|
1078
1172
|
|
|
1079
1173
|
//#endregion
|
|
@@ -1083,12 +1177,12 @@ async function multiSelect(message, choices) {
|
|
|
1083
1177
|
if (!choices.length) return [];
|
|
1084
1178
|
const picked = await multiselect({
|
|
1085
1179
|
message,
|
|
1086
|
-
options: choices.map((c) => ({
|
|
1087
|
-
value: c.value,
|
|
1088
|
-
label: c.label,
|
|
1089
|
-
hint: c.hint
|
|
1180
|
+
options: choices.map((c$1) => ({
|
|
1181
|
+
value: c$1.value,
|
|
1182
|
+
label: c$1.label,
|
|
1183
|
+
hint: c$1.hint
|
|
1090
1184
|
})),
|
|
1091
|
-
initialValues: choices.map((c) => c.value),
|
|
1185
|
+
initialValues: choices.map((c$1) => c$1.value),
|
|
1092
1186
|
required: false
|
|
1093
1187
|
});
|
|
1094
1188
|
if (isCancel(picked)) {
|
|
@@ -1097,6 +1191,22 @@ async function multiSelect(message, choices) {
|
|
|
1097
1191
|
}
|
|
1098
1192
|
return picked;
|
|
1099
1193
|
}
|
|
1194
|
+
/** One answer from a list. Cancelling returns null — the caller decides what safe means. */
|
|
1195
|
+
async function select(message, choices) {
|
|
1196
|
+
const picked = await select$1({
|
|
1197
|
+
message,
|
|
1198
|
+
options: choices.map((c$1) => ({
|
|
1199
|
+
value: c$1.value,
|
|
1200
|
+
label: c$1.label,
|
|
1201
|
+
hint: c$1.hint
|
|
1202
|
+
}))
|
|
1203
|
+
});
|
|
1204
|
+
if (isCancel(picked)) {
|
|
1205
|
+
cancel("cancelled");
|
|
1206
|
+
return null;
|
|
1207
|
+
}
|
|
1208
|
+
return picked;
|
|
1209
|
+
}
|
|
1100
1210
|
function isInteractive() {
|
|
1101
1211
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
1102
1212
|
}
|
|
@@ -1210,7 +1320,7 @@ function logCoverage(config$1) {
|
|
|
1210
1320
|
const nameWidth = Math.max(...rows.map((r$1) => r$1.name.length));
|
|
1211
1321
|
const cellWidths = config$1.agents.map((_, i$1) => Math.max(...rows.map((r$1) => r$1.cells[i$1].length)));
|
|
1212
1322
|
for (const { name: name$1, cells } of rows) {
|
|
1213
|
-
const line = cells.map((c, i$1) => c.padEnd(cellWidths[i$1])).join(" ");
|
|
1323
|
+
const line = cells.map((c$1, i$1) => c$1.padEnd(cellWidths[i$1])).join(" ");
|
|
1214
1324
|
log.info(`${name$1.padEnd(nameWidth)} ${line.trimEnd()}`);
|
|
1215
1325
|
}
|
|
1216
1326
|
}
|
|
@@ -1268,8 +1378,10 @@ function claudePluginInstalls(config$1, home) {
|
|
|
1268
1378
|
return out;
|
|
1269
1379
|
}
|
|
1270
1380
|
/**
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1381
|
+
* `linkDir` is where *this* agent expects to find each skill afterwards — the shared store
|
|
1382
|
+
* itself for agents that read it directly. Always pass it: `.skill-lock.json` is one
|
|
1383
|
+
* agent-agnostic file, so a name-only probe is satisfied by whichever agent installed first
|
|
1384
|
+
* and every later agent's install is skipped forever, silently reporting `unchanged`.
|
|
1273
1385
|
*/
|
|
1274
1386
|
function skillInstalls(config$1, agent, home, linkDir) {
|
|
1275
1387
|
return skillDeliveries(config$1, agent).map((delivery) => {
|
|
@@ -1300,6 +1412,36 @@ function skillInstalls(config$1, agent, home, linkDir) {
|
|
|
1300
1412
|
});
|
|
1301
1413
|
}
|
|
1302
1414
|
|
|
1415
|
+
//#endregion
|
|
1416
|
+
//#region src/commands/setup/agents/state.ts
|
|
1417
|
+
/** Machine-local bookkeeping, never a source of truth — do not sync or vendor it. */
|
|
1418
|
+
function stateFileFor(home) {
|
|
1419
|
+
return join(home, ".agents", ".setup-state.json");
|
|
1420
|
+
}
|
|
1421
|
+
function hashContent(content) {
|
|
1422
|
+
return createHash("sha256").update(content).digest("hex");
|
|
1423
|
+
}
|
|
1424
|
+
function hashValue(value) {
|
|
1425
|
+
return hashContent(stable(value));
|
|
1426
|
+
}
|
|
1427
|
+
async function loadState(file) {
|
|
1428
|
+
try {
|
|
1429
|
+
const parsed = JSON.parse(await readFile(file, "utf8"));
|
|
1430
|
+
return {
|
|
1431
|
+
files: parsed.files ?? {},
|
|
1432
|
+
keys: parsed.keys ?? {}
|
|
1433
|
+
};
|
|
1434
|
+
} catch {
|
|
1435
|
+
return {
|
|
1436
|
+
files: {},
|
|
1437
|
+
keys: {}
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
async function saveState(file, state) {
|
|
1442
|
+
await writeJson(file, state);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1303
1445
|
//#endregion
|
|
1304
1446
|
//#region src/commands/setup/agents/store.ts
|
|
1305
1447
|
const AGENTS_STORE = ".agents/skills";
|
|
@@ -1312,6 +1454,7 @@ async function buildStorePlan(ctx) {
|
|
|
1312
1454
|
const archiveDir = join(ctx.home, ".agents/.setup-backups", stamp);
|
|
1313
1455
|
return {
|
|
1314
1456
|
archiveDir,
|
|
1457
|
+
stateFile: stateFileFor(ctx.home),
|
|
1315
1458
|
groups: [{
|
|
1316
1459
|
section: "Skills store (~/.agents/skills)",
|
|
1317
1460
|
artifacts: (await authoredSkillNames(ctx)).map((name$1) => ({
|
|
@@ -1398,6 +1541,7 @@ async function buildPlan$1(ctx) {
|
|
|
1398
1541
|
});
|
|
1399
1542
|
return {
|
|
1400
1543
|
archiveDir,
|
|
1544
|
+
stateFile: stateFileFor(ctx.home),
|
|
1401
1545
|
groups
|
|
1402
1546
|
};
|
|
1403
1547
|
}
|
|
@@ -1423,8 +1567,8 @@ function claudeMcp(server) {
|
|
|
1423
1567
|
...server.headers && { headers: server.headers }
|
|
1424
1568
|
};
|
|
1425
1569
|
}
|
|
1426
|
-
function mapValues(record, fn) {
|
|
1427
|
-
return Object.fromEntries(Object.entries(record).map(([k, v]) => [k, fn(v)]));
|
|
1570
|
+
function mapValues(record$1, fn) {
|
|
1571
|
+
return Object.fromEntries(Object.entries(record$1).map(([k, v]) => [k, fn(v)]));
|
|
1428
1572
|
}
|
|
1429
1573
|
async function authoredSkillLinks(ctx, root, archiveDir) {
|
|
1430
1574
|
return (await authoredSkillNames(ctx)).map((name$1) => ({
|
|
@@ -1473,7 +1617,7 @@ async function buildPlan(ctx) {
|
|
|
1473
1617
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1474
1618
|
const groups = [{
|
|
1475
1619
|
section: "Skills (remote)",
|
|
1476
|
-
artifacts: skillInstalls(ctx.config, "opencode", ctx.home)
|
|
1620
|
+
artifacts: skillInstalls(ctx.config, "opencode", ctx.home, join(ctx.home, AGENTS_STORE))
|
|
1477
1621
|
}, {
|
|
1478
1622
|
section: "Instructions",
|
|
1479
1623
|
artifacts: [{
|
|
@@ -1494,6 +1638,7 @@ async function buildPlan(ctx) {
|
|
|
1494
1638
|
});
|
|
1495
1639
|
return {
|
|
1496
1640
|
archiveDir: join(root, ".setup-backups", stamp),
|
|
1641
|
+
stateFile: stateFileFor(ctx.home),
|
|
1497
1642
|
groups
|
|
1498
1643
|
};
|
|
1499
1644
|
}
|
|
@@ -1561,14 +1706,631 @@ async function which(bin) {
|
|
|
1561
1706
|
])).ok;
|
|
1562
1707
|
}
|
|
1563
1708
|
|
|
1709
|
+
//#endregion
|
|
1710
|
+
//#region node_modules/diff/libesm/diff/base.js
|
|
1711
|
+
var Diff = class {
|
|
1712
|
+
diff(oldStr, newStr, options = {}) {
|
|
1713
|
+
let callback;
|
|
1714
|
+
if (typeof options === "function") {
|
|
1715
|
+
callback = options;
|
|
1716
|
+
options = {};
|
|
1717
|
+
} else if ("callback" in options) callback = options.callback;
|
|
1718
|
+
const oldString = this.castInput(oldStr, options);
|
|
1719
|
+
const newString = this.castInput(newStr, options);
|
|
1720
|
+
const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
|
|
1721
|
+
const newTokens = this.removeEmpty(this.tokenize(newString, options));
|
|
1722
|
+
return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
|
|
1723
|
+
}
|
|
1724
|
+
diffWithOptionsObj(oldTokens, newTokens, options, callback) {
|
|
1725
|
+
var _a;
|
|
1726
|
+
const done = (value) => {
|
|
1727
|
+
value = this.postProcess(value, options);
|
|
1728
|
+
if (callback) {
|
|
1729
|
+
setTimeout(function() {
|
|
1730
|
+
callback(value);
|
|
1731
|
+
}, 0);
|
|
1732
|
+
return;
|
|
1733
|
+
} else return value;
|
|
1734
|
+
};
|
|
1735
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
1736
|
+
let editLength = 1;
|
|
1737
|
+
let maxEditLength = newLen + oldLen;
|
|
1738
|
+
if (options.maxEditLength != null) maxEditLength = Math.min(maxEditLength, options.maxEditLength);
|
|
1739
|
+
const maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : Infinity;
|
|
1740
|
+
const abortAfterTimestamp = Date.now() + maxExecutionTime;
|
|
1741
|
+
const bestPath = [{
|
|
1742
|
+
oldPos: -1,
|
|
1743
|
+
lastComponent: void 0
|
|
1744
|
+
}];
|
|
1745
|
+
let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
|
|
1746
|
+
if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
|
|
1747
|
+
let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
|
|
1748
|
+
const execEditLength = () => {
|
|
1749
|
+
for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
|
|
1750
|
+
let basePath;
|
|
1751
|
+
const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
|
|
1752
|
+
if (removePath) bestPath[diagonalPath - 1] = void 0;
|
|
1753
|
+
let canAdd = false;
|
|
1754
|
+
if (addPath) {
|
|
1755
|
+
const addPathNewPos = addPath.oldPos - diagonalPath;
|
|
1756
|
+
canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
|
|
1757
|
+
}
|
|
1758
|
+
const canRemove = removePath && removePath.oldPos + 1 < oldLen;
|
|
1759
|
+
if (!canAdd && !canRemove) {
|
|
1760
|
+
bestPath[diagonalPath] = void 0;
|
|
1761
|
+
continue;
|
|
1762
|
+
}
|
|
1763
|
+
if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) basePath = this.addToPath(addPath, true, false, 0, options);
|
|
1764
|
+
else basePath = this.addToPath(removePath, false, true, 1, options);
|
|
1765
|
+
newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
|
|
1766
|
+
if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
|
|
1767
|
+
else {
|
|
1768
|
+
bestPath[diagonalPath] = basePath;
|
|
1769
|
+
if (basePath.oldPos + 1 >= oldLen) maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
|
|
1770
|
+
if (newPos + 1 >= newLen) minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
editLength++;
|
|
1774
|
+
};
|
|
1775
|
+
if (callback) (function exec$1() {
|
|
1776
|
+
setTimeout(function() {
|
|
1777
|
+
if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) return callback(void 0);
|
|
1778
|
+
if (!execEditLength()) exec$1();
|
|
1779
|
+
}, 0);
|
|
1780
|
+
})();
|
|
1781
|
+
else while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
|
|
1782
|
+
const ret = execEditLength();
|
|
1783
|
+
if (ret) return ret;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
addToPath(path, added, removed, oldPosInc, options) {
|
|
1787
|
+
const last = path.lastComponent;
|
|
1788
|
+
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) return {
|
|
1789
|
+
oldPos: path.oldPos + oldPosInc,
|
|
1790
|
+
lastComponent: {
|
|
1791
|
+
count: last.count + 1,
|
|
1792
|
+
added,
|
|
1793
|
+
removed,
|
|
1794
|
+
previousComponent: last.previousComponent
|
|
1795
|
+
}
|
|
1796
|
+
};
|
|
1797
|
+
else return {
|
|
1798
|
+
oldPos: path.oldPos + oldPosInc,
|
|
1799
|
+
lastComponent: {
|
|
1800
|
+
count: 1,
|
|
1801
|
+
added,
|
|
1802
|
+
removed,
|
|
1803
|
+
previousComponent: last
|
|
1804
|
+
}
|
|
1805
|
+
};
|
|
1806
|
+
}
|
|
1807
|
+
extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
|
|
1808
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
1809
|
+
let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
|
|
1810
|
+
while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
|
|
1811
|
+
newPos++;
|
|
1812
|
+
oldPos++;
|
|
1813
|
+
commonCount++;
|
|
1814
|
+
if (options.oneChangePerToken) basePath.lastComponent = {
|
|
1815
|
+
count: 1,
|
|
1816
|
+
previousComponent: basePath.lastComponent,
|
|
1817
|
+
added: false,
|
|
1818
|
+
removed: false
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
if (commonCount && !options.oneChangePerToken) basePath.lastComponent = {
|
|
1822
|
+
count: commonCount,
|
|
1823
|
+
previousComponent: basePath.lastComponent,
|
|
1824
|
+
added: false,
|
|
1825
|
+
removed: false
|
|
1826
|
+
};
|
|
1827
|
+
basePath.oldPos = oldPos;
|
|
1828
|
+
return newPos;
|
|
1829
|
+
}
|
|
1830
|
+
equals(left, right, options) {
|
|
1831
|
+
if (options.comparator) return options.comparator(left, right);
|
|
1832
|
+
else return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
|
|
1833
|
+
}
|
|
1834
|
+
removeEmpty(array) {
|
|
1835
|
+
const ret = [];
|
|
1836
|
+
for (let i$1 = 0; i$1 < array.length; i$1++) if (array[i$1]) ret.push(array[i$1]);
|
|
1837
|
+
return ret;
|
|
1838
|
+
}
|
|
1839
|
+
castInput(value, options) {
|
|
1840
|
+
return value;
|
|
1841
|
+
}
|
|
1842
|
+
tokenize(value, options) {
|
|
1843
|
+
return Array.from(value);
|
|
1844
|
+
}
|
|
1845
|
+
join(chars) {
|
|
1846
|
+
return chars.join("");
|
|
1847
|
+
}
|
|
1848
|
+
postProcess(changeObjects, options) {
|
|
1849
|
+
return changeObjects;
|
|
1850
|
+
}
|
|
1851
|
+
get useLongestToken() {
|
|
1852
|
+
return false;
|
|
1853
|
+
}
|
|
1854
|
+
buildValues(lastComponent, newTokens, oldTokens) {
|
|
1855
|
+
const components = [];
|
|
1856
|
+
let nextComponent;
|
|
1857
|
+
while (lastComponent) {
|
|
1858
|
+
components.push(lastComponent);
|
|
1859
|
+
nextComponent = lastComponent.previousComponent;
|
|
1860
|
+
delete lastComponent.previousComponent;
|
|
1861
|
+
lastComponent = nextComponent;
|
|
1862
|
+
}
|
|
1863
|
+
components.reverse();
|
|
1864
|
+
const componentLen = components.length;
|
|
1865
|
+
let componentPos = 0, newPos = 0, oldPos = 0;
|
|
1866
|
+
for (; componentPos < componentLen; componentPos++) {
|
|
1867
|
+
const component = components[componentPos];
|
|
1868
|
+
if (!component.removed) {
|
|
1869
|
+
if (!component.added && this.useLongestToken) {
|
|
1870
|
+
let value = newTokens.slice(newPos, newPos + component.count);
|
|
1871
|
+
value = value.map(function(value$1, i$1) {
|
|
1872
|
+
const oldValue = oldTokens[oldPos + i$1];
|
|
1873
|
+
return oldValue.length > value$1.length ? oldValue : value$1;
|
|
1874
|
+
});
|
|
1875
|
+
component.value = this.join(value);
|
|
1876
|
+
} else component.value = this.join(newTokens.slice(newPos, newPos + component.count));
|
|
1877
|
+
newPos += component.count;
|
|
1878
|
+
if (!component.added) oldPos += component.count;
|
|
1879
|
+
} else {
|
|
1880
|
+
component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
|
|
1881
|
+
oldPos += component.count;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
return components;
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
|
|
1888
|
+
//#endregion
|
|
1889
|
+
//#region node_modules/diff/libesm/diff/character.js
|
|
1890
|
+
var CharacterDiff = class extends Diff {};
|
|
1891
|
+
const characterDiff = new CharacterDiff();
|
|
1892
|
+
|
|
1893
|
+
//#endregion
|
|
1894
|
+
//#region node_modules/diff/libesm/util/string.js
|
|
1895
|
+
function longestCommonPrefix(str1, str2) {
|
|
1896
|
+
let i$1;
|
|
1897
|
+
for (i$1 = 0; i$1 < str1.length && i$1 < str2.length; i$1++) if (str1[i$1] != str2[i$1]) return str1.slice(0, i$1);
|
|
1898
|
+
return str1.slice(0, i$1);
|
|
1899
|
+
}
|
|
1900
|
+
function longestCommonSuffix(str1, str2) {
|
|
1901
|
+
let i$1;
|
|
1902
|
+
if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) return "";
|
|
1903
|
+
for (i$1 = 0; i$1 < str1.length && i$1 < str2.length; i$1++) if (str1[str1.length - (i$1 + 1)] != str2[str2.length - (i$1 + 1)]) return str1.slice(-i$1);
|
|
1904
|
+
return str1.slice(-i$1);
|
|
1905
|
+
}
|
|
1906
|
+
function replacePrefix(string, oldPrefix, newPrefix) {
|
|
1907
|
+
if (string.slice(0, oldPrefix.length) != oldPrefix) throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);
|
|
1908
|
+
return newPrefix + string.slice(oldPrefix.length);
|
|
1909
|
+
}
|
|
1910
|
+
function replaceSuffix(string, oldSuffix, newSuffix) {
|
|
1911
|
+
if (!oldSuffix) return string + newSuffix;
|
|
1912
|
+
if (string.slice(-oldSuffix.length) != oldSuffix) throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);
|
|
1913
|
+
return string.slice(0, -oldSuffix.length) + newSuffix;
|
|
1914
|
+
}
|
|
1915
|
+
function removePrefix(string, oldPrefix) {
|
|
1916
|
+
return replacePrefix(string, oldPrefix, "");
|
|
1917
|
+
}
|
|
1918
|
+
function removeSuffix(string, oldSuffix) {
|
|
1919
|
+
return replaceSuffix(string, oldSuffix, "");
|
|
1920
|
+
}
|
|
1921
|
+
function maximumOverlap(string1, string2) {
|
|
1922
|
+
return string2.slice(0, overlapCount(string1, string2));
|
|
1923
|
+
}
|
|
1924
|
+
function overlapCount(a$1, b) {
|
|
1925
|
+
let startA = 0;
|
|
1926
|
+
if (a$1.length > b.length) startA = a$1.length - b.length;
|
|
1927
|
+
let endB = b.length;
|
|
1928
|
+
if (a$1.length < b.length) endB = a$1.length;
|
|
1929
|
+
const map = Array(endB);
|
|
1930
|
+
let k = 0;
|
|
1931
|
+
map[0] = 0;
|
|
1932
|
+
for (let j = 1; j < endB; j++) {
|
|
1933
|
+
if (b[j] == b[k]) map[j] = map[k];
|
|
1934
|
+
else map[j] = k;
|
|
1935
|
+
while (k > 0 && b[j] != b[k]) k = map[k];
|
|
1936
|
+
if (b[j] == b[k]) k++;
|
|
1937
|
+
}
|
|
1938
|
+
k = 0;
|
|
1939
|
+
for (let i$1 = startA; i$1 < a$1.length; i$1++) {
|
|
1940
|
+
while (k > 0 && a$1[i$1] != b[k]) k = map[k];
|
|
1941
|
+
if (a$1[i$1] == b[k]) k++;
|
|
1942
|
+
}
|
|
1943
|
+
return k;
|
|
1944
|
+
}
|
|
1945
|
+
/**
|
|
1946
|
+
* Split a string into segments using a word segmenter, merging consecutive
|
|
1947
|
+
* segments if they are both whitespace segments. Whitespace segments can
|
|
1948
|
+
* appear adjacent to one another for two reasons:
|
|
1949
|
+
* - newlines always get their own segment
|
|
1950
|
+
* - where a diacritic is attached to a whitespace character in the text, the
|
|
1951
|
+
* segment ends after the diacritic, so e.g. " \u0300 " becomes two segments.
|
|
1952
|
+
* This function therefore runs the segmenter's .segment() method and then
|
|
1953
|
+
* merges consecutive segments of whitespace into a single part.
|
|
1954
|
+
*/
|
|
1955
|
+
function segment(string, segmenter) {
|
|
1956
|
+
const parts = [];
|
|
1957
|
+
for (const segmentObj of Array.from(segmenter.segment(string))) {
|
|
1958
|
+
const segment$1 = segmentObj.segment;
|
|
1959
|
+
if (parts.length && /\s/.test(parts[parts.length - 1]) && /\s/.test(segment$1)) parts[parts.length - 1] += segment$1;
|
|
1960
|
+
else parts.push(segment$1);
|
|
1961
|
+
}
|
|
1962
|
+
return parts;
|
|
1963
|
+
}
|
|
1964
|
+
function trailingWs(string, segmenter) {
|
|
1965
|
+
if (segmenter) return leadingAndTrailingWs(string, segmenter)[1];
|
|
1966
|
+
let i$1;
|
|
1967
|
+
for (i$1 = string.length - 1; i$1 >= 0; i$1--) if (!string[i$1].match(/\s/)) break;
|
|
1968
|
+
return string.substring(i$1 + 1);
|
|
1969
|
+
}
|
|
1970
|
+
function leadingWs(string, segmenter) {
|
|
1971
|
+
if (segmenter) return leadingAndTrailingWs(string, segmenter)[0];
|
|
1972
|
+
const match = string.match(/^\s*/);
|
|
1973
|
+
return match ? match[0] : "";
|
|
1974
|
+
}
|
|
1975
|
+
function leadingAndTrailingWs(string, segmenter) {
|
|
1976
|
+
if (!segmenter) return [leadingWs(string), trailingWs(string)];
|
|
1977
|
+
if (segmenter.resolvedOptions().granularity != "word") throw new Error("The segmenter passed must have a granularity of \"word\"");
|
|
1978
|
+
const segments = segment(string, segmenter);
|
|
1979
|
+
const firstSeg = segments[0];
|
|
1980
|
+
const lastSeg = segments[segments.length - 1];
|
|
1981
|
+
return [/\s/.test(firstSeg) ? firstSeg : "", /\s/.test(lastSeg) ? lastSeg : ""];
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
//#endregion
|
|
1985
|
+
//#region node_modules/diff/libesm/diff/word.js
|
|
1986
|
+
const extendedWordChars = "a-zA-Z0-9_\\u{AD}\\u{C0}-\\u{D6}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}";
|
|
1987
|
+
const tokenizeIncludingWhitespace = new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`, "ug");
|
|
1988
|
+
var WordDiff = class extends Diff {
|
|
1989
|
+
equals(left, right, options) {
|
|
1990
|
+
if (options.ignoreCase) {
|
|
1991
|
+
left = left.toLowerCase();
|
|
1992
|
+
right = right.toLowerCase();
|
|
1993
|
+
}
|
|
1994
|
+
return left.trim() === right.trim();
|
|
1995
|
+
}
|
|
1996
|
+
tokenize(value, options = {}) {
|
|
1997
|
+
let parts;
|
|
1998
|
+
if (options.intlSegmenter) {
|
|
1999
|
+
const segmenter = options.intlSegmenter;
|
|
2000
|
+
if (segmenter.resolvedOptions().granularity != "word") throw new Error("The segmenter passed must have a granularity of \"word\"");
|
|
2001
|
+
parts = segment(value, segmenter);
|
|
2002
|
+
} else parts = value.match(tokenizeIncludingWhitespace) || [];
|
|
2003
|
+
const tokens = [];
|
|
2004
|
+
let prevPart = null;
|
|
2005
|
+
parts.forEach((part) => {
|
|
2006
|
+
if (/\s/.test(part)) if (prevPart == null) tokens.push(part);
|
|
2007
|
+
else tokens.push(tokens.pop() + part);
|
|
2008
|
+
else if (prevPart != null && /\s/.test(prevPart)) if (tokens[tokens.length - 1] == prevPart) tokens.push(tokens.pop() + part);
|
|
2009
|
+
else tokens.push(prevPart + part);
|
|
2010
|
+
else tokens.push(part);
|
|
2011
|
+
prevPart = part;
|
|
2012
|
+
});
|
|
2013
|
+
return tokens;
|
|
2014
|
+
}
|
|
2015
|
+
join(tokens) {
|
|
2016
|
+
return tokens.map((token, i$1) => {
|
|
2017
|
+
if (i$1 == 0) return token;
|
|
2018
|
+
else return token.replace(/^\s+/, "");
|
|
2019
|
+
}).join("");
|
|
2020
|
+
}
|
|
2021
|
+
postProcess(changes, options) {
|
|
2022
|
+
if (!changes || options.oneChangePerToken) return changes;
|
|
2023
|
+
let lastKeep = null;
|
|
2024
|
+
let insertion = null;
|
|
2025
|
+
let deletion = null;
|
|
2026
|
+
changes.forEach((change) => {
|
|
2027
|
+
if (change.added) insertion = change;
|
|
2028
|
+
else if (change.removed) deletion = change;
|
|
2029
|
+
else {
|
|
2030
|
+
if (insertion || deletion) dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change, options.intlSegmenter);
|
|
2031
|
+
lastKeep = change;
|
|
2032
|
+
insertion = null;
|
|
2033
|
+
deletion = null;
|
|
2034
|
+
}
|
|
2035
|
+
});
|
|
2036
|
+
if (insertion || deletion) dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null, options.intlSegmenter);
|
|
2037
|
+
return changes;
|
|
2038
|
+
}
|
|
2039
|
+
};
|
|
2040
|
+
const wordDiff = new WordDiff();
|
|
2041
|
+
function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep, segmenter) {
|
|
2042
|
+
if (deletion && insertion) {
|
|
2043
|
+
const [oldWsPrefix, oldWsSuffix] = leadingAndTrailingWs(deletion.value, segmenter);
|
|
2044
|
+
const [newWsPrefix, newWsSuffix] = leadingAndTrailingWs(insertion.value, segmenter);
|
|
2045
|
+
if (startKeep) {
|
|
2046
|
+
const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
|
|
2047
|
+
startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
|
|
2048
|
+
deletion.value = removePrefix(deletion.value, commonWsPrefix);
|
|
2049
|
+
insertion.value = removePrefix(insertion.value, commonWsPrefix);
|
|
2050
|
+
}
|
|
2051
|
+
if (endKeep) {
|
|
2052
|
+
const commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);
|
|
2053
|
+
endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix);
|
|
2054
|
+
deletion.value = removeSuffix(deletion.value, commonWsSuffix);
|
|
2055
|
+
insertion.value = removeSuffix(insertion.value, commonWsSuffix);
|
|
2056
|
+
}
|
|
2057
|
+
} else if (insertion) {
|
|
2058
|
+
if (startKeep) {
|
|
2059
|
+
const ws = leadingWs(insertion.value, segmenter);
|
|
2060
|
+
insertion.value = insertion.value.substring(ws.length);
|
|
2061
|
+
}
|
|
2062
|
+
if (endKeep) {
|
|
2063
|
+
const ws = leadingWs(endKeep.value, segmenter);
|
|
2064
|
+
endKeep.value = endKeep.value.substring(ws.length);
|
|
2065
|
+
}
|
|
2066
|
+
} else if (startKeep && endKeep) {
|
|
2067
|
+
const newWsFull = leadingWs(endKeep.value, segmenter), [delWsStart, delWsEnd] = leadingAndTrailingWs(deletion.value, segmenter);
|
|
2068
|
+
const newWsStart = longestCommonPrefix(newWsFull, delWsStart);
|
|
2069
|
+
deletion.value = removePrefix(deletion.value, newWsStart);
|
|
2070
|
+
const newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);
|
|
2071
|
+
deletion.value = removeSuffix(deletion.value, newWsEnd);
|
|
2072
|
+
endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd);
|
|
2073
|
+
startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));
|
|
2074
|
+
} else if (endKeep) {
|
|
2075
|
+
const endKeepWsPrefix = leadingWs(endKeep.value, segmenter);
|
|
2076
|
+
const overlap = maximumOverlap(trailingWs(deletion.value, segmenter), endKeepWsPrefix);
|
|
2077
|
+
deletion.value = removeSuffix(deletion.value, overlap);
|
|
2078
|
+
} else if (startKeep) {
|
|
2079
|
+
const overlap = maximumOverlap(trailingWs(startKeep.value, segmenter), leadingWs(deletion.value, segmenter));
|
|
2080
|
+
deletion.value = removePrefix(deletion.value, overlap);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
var WordsWithSpaceDiff = class extends Diff {
|
|
2084
|
+
tokenize(value) {
|
|
2085
|
+
const regex = new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`, "ug");
|
|
2086
|
+
return value.match(regex) || [];
|
|
2087
|
+
}
|
|
2088
|
+
};
|
|
2089
|
+
const wordsWithSpaceDiff = new WordsWithSpaceDiff();
|
|
2090
|
+
|
|
2091
|
+
//#endregion
|
|
2092
|
+
//#region node_modules/diff/libesm/diff/line.js
|
|
2093
|
+
var LineDiff = class extends Diff {
|
|
2094
|
+
constructor() {
|
|
2095
|
+
super(...arguments);
|
|
2096
|
+
this.tokenize = tokenize;
|
|
2097
|
+
}
|
|
2098
|
+
equals(left, right, options) {
|
|
2099
|
+
if (options.ignoreWhitespace) {
|
|
2100
|
+
if (!options.newlineIsToken || !left.includes("\n")) left = left.trim();
|
|
2101
|
+
if (!options.newlineIsToken || !right.includes("\n")) right = right.trim();
|
|
2102
|
+
} else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
|
|
2103
|
+
if (left.endsWith("\n")) left = left.slice(0, -1);
|
|
2104
|
+
if (right.endsWith("\n")) right = right.slice(0, -1);
|
|
2105
|
+
}
|
|
2106
|
+
return super.equals(left, right, options);
|
|
2107
|
+
}
|
|
2108
|
+
};
|
|
2109
|
+
const lineDiff = new LineDiff();
|
|
2110
|
+
function diffLines(oldStr, newStr, options) {
|
|
2111
|
+
return lineDiff.diff(oldStr, newStr, options);
|
|
2112
|
+
}
|
|
2113
|
+
function tokenize(value, options) {
|
|
2114
|
+
if (options.stripTrailingCr) value = value.replace(/\r\n/g, "\n");
|
|
2115
|
+
const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
|
|
2116
|
+
if (!linesAndNewlines[linesAndNewlines.length - 1]) linesAndNewlines.pop();
|
|
2117
|
+
for (let i$1 = 0; i$1 < linesAndNewlines.length; i$1++) {
|
|
2118
|
+
const line = linesAndNewlines[i$1];
|
|
2119
|
+
if (i$1 % 2 && !options.newlineIsToken) retLines[retLines.length - 1] += line;
|
|
2120
|
+
else retLines.push(line);
|
|
2121
|
+
}
|
|
2122
|
+
return retLines;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
//#endregion
|
|
2126
|
+
//#region node_modules/diff/libesm/diff/sentence.js
|
|
2127
|
+
function isSentenceEndPunct(char) {
|
|
2128
|
+
return char == "." || char == "!" || char == "?";
|
|
2129
|
+
}
|
|
2130
|
+
var SentenceDiff = class extends Diff {
|
|
2131
|
+
tokenize(value) {
|
|
2132
|
+
var _a;
|
|
2133
|
+
const result = [];
|
|
2134
|
+
let tokenStartI = 0;
|
|
2135
|
+
for (let i$1 = 0; i$1 < value.length; i$1++) {
|
|
2136
|
+
if (i$1 == value.length - 1) {
|
|
2137
|
+
result.push(value.slice(tokenStartI));
|
|
2138
|
+
break;
|
|
2139
|
+
}
|
|
2140
|
+
if (isSentenceEndPunct(value[i$1]) && value[i$1 + 1].match(/\s/)) {
|
|
2141
|
+
result.push(value.slice(tokenStartI, i$1 + 1));
|
|
2142
|
+
i$1 = tokenStartI = i$1 + 1;
|
|
2143
|
+
while ((_a = value[i$1 + 1]) === null || _a === void 0 ? void 0 : _a.match(/\s/)) i$1++;
|
|
2144
|
+
result.push(value.slice(tokenStartI, i$1 + 1));
|
|
2145
|
+
tokenStartI = i$1 + 1;
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
return result;
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
const sentenceDiff = new SentenceDiff();
|
|
2152
|
+
|
|
2153
|
+
//#endregion
|
|
2154
|
+
//#region node_modules/diff/libesm/diff/css.js
|
|
2155
|
+
var CssDiff = class extends Diff {
|
|
2156
|
+
tokenize(value) {
|
|
2157
|
+
return value.split(/([{}:;,]|\s+)/);
|
|
2158
|
+
}
|
|
2159
|
+
};
|
|
2160
|
+
const cssDiff = new CssDiff();
|
|
2161
|
+
|
|
2162
|
+
//#endregion
|
|
2163
|
+
//#region node_modules/diff/libesm/diff/json.js
|
|
2164
|
+
var JsonDiff = class extends Diff {
|
|
2165
|
+
constructor() {
|
|
2166
|
+
super(...arguments);
|
|
2167
|
+
this.tokenize = tokenize;
|
|
2168
|
+
}
|
|
2169
|
+
get useLongestToken() {
|
|
2170
|
+
return true;
|
|
2171
|
+
}
|
|
2172
|
+
castInput(value, options) {
|
|
2173
|
+
const { undefinedReplacement, stringifyReplacer = (k, v) => typeof v === "undefined" ? undefinedReplacement : v } = options;
|
|
2174
|
+
return typeof value === "string" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), null, " ");
|
|
2175
|
+
}
|
|
2176
|
+
equals(left, right, options) {
|
|
2177
|
+
return super.equals(left.replace(/,([\r\n])/g, "$1"), right.replace(/,([\r\n])/g, "$1"), options);
|
|
2178
|
+
}
|
|
2179
|
+
};
|
|
2180
|
+
const jsonDiff = new JsonDiff();
|
|
2181
|
+
function canonicalize(obj, stack, replacementStack, replacer, key) {
|
|
2182
|
+
stack = stack || [];
|
|
2183
|
+
replacementStack = replacementStack || [];
|
|
2184
|
+
if (replacer) obj = replacer(key === void 0 ? "" : key, obj);
|
|
2185
|
+
let i$1;
|
|
2186
|
+
for (i$1 = 0; i$1 < stack.length; i$1 += 1) if (stack[i$1] === obj) return replacementStack[i$1];
|
|
2187
|
+
let canonicalizedObj;
|
|
2188
|
+
if ("[object Array]" === Object.prototype.toString.call(obj)) {
|
|
2189
|
+
stack.push(obj);
|
|
2190
|
+
canonicalizedObj = new Array(obj.length);
|
|
2191
|
+
replacementStack.push(canonicalizedObj);
|
|
2192
|
+
for (i$1 = 0; i$1 < obj.length; i$1 += 1) canonicalizedObj[i$1] = canonicalize(obj[i$1], stack, replacementStack, replacer, String(i$1));
|
|
2193
|
+
stack.pop();
|
|
2194
|
+
replacementStack.pop();
|
|
2195
|
+
return canonicalizedObj;
|
|
2196
|
+
}
|
|
2197
|
+
if (obj && obj.toJSON) obj = obj.toJSON();
|
|
2198
|
+
if (typeof obj === "object" && obj !== null) {
|
|
2199
|
+
stack.push(obj);
|
|
2200
|
+
canonicalizedObj = {};
|
|
2201
|
+
replacementStack.push(canonicalizedObj);
|
|
2202
|
+
const sortedKeys = [];
|
|
2203
|
+
let key$1;
|
|
2204
|
+
for (key$1 in obj)
|
|
2205
|
+
/* istanbul ignore else */
|
|
2206
|
+
if (Object.prototype.hasOwnProperty.call(obj, key$1)) sortedKeys.push(key$1);
|
|
2207
|
+
sortedKeys.sort();
|
|
2208
|
+
for (i$1 = 0; i$1 < sortedKeys.length; i$1 += 1) {
|
|
2209
|
+
key$1 = sortedKeys[i$1];
|
|
2210
|
+
canonicalizedObj[key$1] = canonicalize(obj[key$1], stack, replacementStack, replacer, key$1);
|
|
2211
|
+
}
|
|
2212
|
+
stack.pop();
|
|
2213
|
+
replacementStack.pop();
|
|
2214
|
+
} else canonicalizedObj = obj;
|
|
2215
|
+
return canonicalizedObj;
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
//#endregion
|
|
2219
|
+
//#region node_modules/diff/libesm/diff/array.js
|
|
2220
|
+
var ArrayDiff = class extends Diff {
|
|
2221
|
+
tokenize(value) {
|
|
2222
|
+
return value.slice();
|
|
2223
|
+
}
|
|
2224
|
+
join(value) {
|
|
2225
|
+
return value;
|
|
2226
|
+
}
|
|
2227
|
+
removeEmpty(value) {
|
|
2228
|
+
return value;
|
|
2229
|
+
}
|
|
2230
|
+
};
|
|
2231
|
+
const arrayDiff = new ArrayDiff();
|
|
2232
|
+
|
|
2233
|
+
//#endregion
|
|
2234
|
+
//#region node_modules/diff/libesm/patch/create.js
|
|
2235
|
+
function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
|
|
2236
|
+
let optionsObj;
|
|
2237
|
+
if (!options) optionsObj = {};
|
|
2238
|
+
else if (typeof options === "function") optionsObj = { callback: options };
|
|
2239
|
+
else optionsObj = options;
|
|
2240
|
+
if (typeof optionsObj.context === "undefined") optionsObj.context = 4;
|
|
2241
|
+
const context = optionsObj.context;
|
|
2242
|
+
if (optionsObj.newlineIsToken) throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
|
|
2243
|
+
if (!optionsObj.callback) return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
|
|
2244
|
+
else {
|
|
2245
|
+
const { callback } = optionsObj;
|
|
2246
|
+
diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff$1) => {
|
|
2247
|
+
callback(diffLinesResultToPatch(diff$1));
|
|
2248
|
+
} }));
|
|
2249
|
+
}
|
|
2250
|
+
function diffLinesResultToPatch(diff$1) {
|
|
2251
|
+
if (!diff$1) return;
|
|
2252
|
+
diff$1.push({
|
|
2253
|
+
value: "",
|
|
2254
|
+
lines: []
|
|
2255
|
+
});
|
|
2256
|
+
function contextLines(lines) {
|
|
2257
|
+
return lines.map(function(entry) {
|
|
2258
|
+
return " " + entry;
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
const hunks = [];
|
|
2262
|
+
let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
|
|
2263
|
+
for (let i$1 = 0; i$1 < diff$1.length; i$1++) {
|
|
2264
|
+
const current = diff$1[i$1], lines = current.lines || splitLines(current.value);
|
|
2265
|
+
current.lines = lines;
|
|
2266
|
+
if (current.added || current.removed) {
|
|
2267
|
+
if (!oldRangeStart) {
|
|
2268
|
+
const prev = diff$1[i$1 - 1];
|
|
2269
|
+
oldRangeStart = oldLine;
|
|
2270
|
+
newRangeStart = newLine;
|
|
2271
|
+
if (prev) {
|
|
2272
|
+
curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
|
|
2273
|
+
oldRangeStart -= curRange.length;
|
|
2274
|
+
newRangeStart -= curRange.length;
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
for (const line of lines) curRange.push((current.added ? "+" : "-") + line);
|
|
2278
|
+
if (current.added) newLine += lines.length;
|
|
2279
|
+
else oldLine += lines.length;
|
|
2280
|
+
} else {
|
|
2281
|
+
if (oldRangeStart) if (lines.length <= context * 2 && i$1 < diff$1.length - 2) for (const line of contextLines(lines)) curRange.push(line);
|
|
2282
|
+
else {
|
|
2283
|
+
const contextSize = Math.min(lines.length, context);
|
|
2284
|
+
for (const line of contextLines(lines.slice(0, contextSize))) curRange.push(line);
|
|
2285
|
+
const hunk = {
|
|
2286
|
+
oldStart: oldRangeStart,
|
|
2287
|
+
oldLines: oldLine - oldRangeStart + contextSize,
|
|
2288
|
+
newStart: newRangeStart,
|
|
2289
|
+
newLines: newLine - newRangeStart + contextSize,
|
|
2290
|
+
lines: curRange
|
|
2291
|
+
};
|
|
2292
|
+
hunks.push(hunk);
|
|
2293
|
+
oldRangeStart = 0;
|
|
2294
|
+
newRangeStart = 0;
|
|
2295
|
+
curRange = [];
|
|
2296
|
+
}
|
|
2297
|
+
oldLine += lines.length;
|
|
2298
|
+
newLine += lines.length;
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
for (const hunk of hunks) for (let i$1 = 0; i$1 < hunk.lines.length; i$1++) if (hunk.lines[i$1].endsWith("\n")) hunk.lines[i$1] = hunk.lines[i$1].slice(0, -1);
|
|
2302
|
+
else {
|
|
2303
|
+
hunk.lines.splice(i$1 + 1, 0, "\");
|
|
2304
|
+
i$1++;
|
|
2305
|
+
}
|
|
2306
|
+
return {
|
|
2307
|
+
oldFileName,
|
|
2308
|
+
newFileName,
|
|
2309
|
+
oldHeader,
|
|
2310
|
+
newHeader,
|
|
2311
|
+
hunks
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
/**
|
|
2316
|
+
* Split `text` into an array of lines, including the trailing newline character (where present)
|
|
2317
|
+
*/
|
|
2318
|
+
function splitLines(text) {
|
|
2319
|
+
const hasTrailingNl = text.endsWith("\n");
|
|
2320
|
+
const result = text.split("\n").map((line) => line + "\n");
|
|
2321
|
+
if (hasTrailingNl) result.pop();
|
|
2322
|
+
else result.push(result.pop().slice(0, -1));
|
|
2323
|
+
return result;
|
|
2324
|
+
}
|
|
2325
|
+
|
|
1564
2326
|
//#endregion
|
|
1565
2327
|
//#region src/commands/setup/agents/diff.ts
|
|
1566
|
-
async function diff(plan) {
|
|
2328
|
+
async function diff(plan, state) {
|
|
1567
2329
|
const probes = new Probes();
|
|
1568
2330
|
const sections = [];
|
|
1569
2331
|
for (const group of plan.groups) {
|
|
1570
2332
|
const changes = [];
|
|
1571
|
-
for (const artifact of group.artifacts) changes.push(await changeFor(artifact, plan.archiveDir, probes));
|
|
2333
|
+
for (const artifact of group.artifacts) changes.push(await changeFor(artifact, plan.archiveDir, state, probes));
|
|
1572
2334
|
sections.push({
|
|
1573
2335
|
title: group.section,
|
|
1574
2336
|
changes
|
|
@@ -1576,29 +2338,62 @@ async function diff(plan) {
|
|
|
1576
2338
|
}
|
|
1577
2339
|
return sections;
|
|
1578
2340
|
}
|
|
1579
|
-
function changeFor(a$1, archiveDir, probes) {
|
|
2341
|
+
function changeFor(a$1, archiveDir, state, probes) {
|
|
1580
2342
|
switch (a$1.kind) {
|
|
1581
|
-
case "file": return fileChange(a$1);
|
|
2343
|
+
case "file": return fileChange(a$1, archiveDir, state);
|
|
1582
2344
|
case "symlink": return symlinkChange(a$1);
|
|
1583
|
-
case "jsonMerge": return jsonMergeChange(a$1, archiveDir);
|
|
2345
|
+
case "jsonMerge": return jsonMergeChange(a$1, archiveDir, state);
|
|
1584
2346
|
case "install": return installChange(a$1, probes);
|
|
1585
2347
|
}
|
|
1586
2348
|
}
|
|
1587
|
-
async function fileChange(a$1) {
|
|
2349
|
+
async function fileChange(a$1, archiveDir, state) {
|
|
1588
2350
|
const next = await readFile(a$1.src);
|
|
1589
|
-
|
|
2351
|
+
const current = await readFile(a$1.dest).catch(() => null);
|
|
2352
|
+
const record$1 = {
|
|
2353
|
+
file: a$1.dest,
|
|
2354
|
+
hash: hashContent(next)
|
|
2355
|
+
};
|
|
2356
|
+
if (current?.equals(next)) return {
|
|
1590
2357
|
status: "unchanged",
|
|
1591
|
-
label: a$1.dest
|
|
2358
|
+
label: a$1.dest,
|
|
2359
|
+
record: record$1
|
|
2360
|
+
};
|
|
2361
|
+
const action = {
|
|
2362
|
+
do: "write-file",
|
|
2363
|
+
src: a$1.src,
|
|
2364
|
+
dest: a$1.dest,
|
|
2365
|
+
...a$1.mode && { mode: a$1.mode }
|
|
2366
|
+
};
|
|
2367
|
+
if (current === null && a$1.dest in state.files) return {
|
|
2368
|
+
status: "conflict",
|
|
2369
|
+
label: a$1.dest,
|
|
2370
|
+
summary: "was deleted on this machine",
|
|
2371
|
+
diffText: unified(basename(a$1.dest), "", next.toString()),
|
|
2372
|
+
apply: {
|
|
2373
|
+
action,
|
|
2374
|
+
record: record$1
|
|
2375
|
+
},
|
|
2376
|
+
keep: null
|
|
2377
|
+
};
|
|
2378
|
+
if (current !== null && state.files[a$1.dest] !== hashContent(current)) return {
|
|
2379
|
+
status: "conflict",
|
|
2380
|
+
label: a$1.dest,
|
|
2381
|
+
summary: "has content setup did not write",
|
|
2382
|
+
diffText: unified(basename(a$1.dest), current.toString(), next.toString()),
|
|
2383
|
+
apply: {
|
|
2384
|
+
action: {
|
|
2385
|
+
...action,
|
|
2386
|
+
backupTo: archiveDir
|
|
2387
|
+
},
|
|
2388
|
+
record: record$1
|
|
2389
|
+
},
|
|
2390
|
+
keep: null
|
|
1592
2391
|
};
|
|
1593
2392
|
return {
|
|
1594
2393
|
status: "pending",
|
|
1595
2394
|
label: a$1.dest,
|
|
1596
|
-
action
|
|
1597
|
-
|
|
1598
|
-
src: a$1.src,
|
|
1599
|
-
dest: a$1.dest,
|
|
1600
|
-
...a$1.mode && { mode: a$1.mode }
|
|
1601
|
-
}
|
|
2395
|
+
action,
|
|
2396
|
+
record: record$1
|
|
1602
2397
|
};
|
|
1603
2398
|
}
|
|
1604
2399
|
async function symlinkChange(a$1) {
|
|
@@ -1613,7 +2408,8 @@ async function symlinkChange(a$1) {
|
|
|
1613
2408
|
label,
|
|
1614
2409
|
action: link
|
|
1615
2410
|
};
|
|
1616
|
-
|
|
2411
|
+
const st = await lstat(a$1.linkPath);
|
|
2412
|
+
if (st.isSymbolicLink()) {
|
|
1617
2413
|
if (await readlink(a$1.linkPath) === a$1.target) return {
|
|
1618
2414
|
status: "unchanged",
|
|
1619
2415
|
label
|
|
@@ -1634,49 +2430,106 @@ async function symlinkChange(a$1) {
|
|
|
1634
2430
|
};
|
|
1635
2431
|
const archiveTo = join(a$1.archiveDisplaced, basename(a$1.linkPath));
|
|
1636
2432
|
return {
|
|
1637
|
-
status: "
|
|
2433
|
+
status: "conflict",
|
|
1638
2434
|
label,
|
|
1639
|
-
|
|
2435
|
+
summary: `a real ${st.isDirectory() ? "directory" : "file"} sits where the link goes`,
|
|
2436
|
+
diffText: "",
|
|
2437
|
+
apply: { action: {
|
|
1640
2438
|
...link,
|
|
1641
2439
|
archiveTo
|
|
1642
|
-
}
|
|
2440
|
+
} },
|
|
2441
|
+
keep: null
|
|
1643
2442
|
};
|
|
1644
2443
|
}
|
|
1645
|
-
async function jsonMergeChange(a$1, archiveDir) {
|
|
2444
|
+
async function jsonMergeChange(a$1, archiveDir, state) {
|
|
1646
2445
|
const label = basename(a$1.dest);
|
|
1647
2446
|
const raw = await readFile(a$1.dest, "utf8").catch(() => null);
|
|
1648
2447
|
let current = {};
|
|
1649
|
-
if (raw !== null)
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
2448
|
+
if (raw !== null) {
|
|
2449
|
+
let parsed;
|
|
2450
|
+
try {
|
|
2451
|
+
parsed = JSON.parse(raw);
|
|
2452
|
+
} catch {
|
|
2453
|
+
return {
|
|
2454
|
+
status: "blocked",
|
|
2455
|
+
label,
|
|
2456
|
+
reason: "not parseable JSON (comments?)"
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {
|
|
1653
2460
|
status: "blocked",
|
|
1654
2461
|
label,
|
|
1655
|
-
reason: "not
|
|
2462
|
+
reason: "not a JSON object"
|
|
1656
2463
|
};
|
|
2464
|
+
current = parsed;
|
|
1657
2465
|
}
|
|
1658
|
-
const
|
|
1659
|
-
...current,
|
|
2466
|
+
const desired = {
|
|
1660
2467
|
...a$1.managed,
|
|
1661
2468
|
...a$1.derived
|
|
1662
2469
|
};
|
|
2470
|
+
const value = {
|
|
2471
|
+
...current,
|
|
2472
|
+
...desired
|
|
2473
|
+
};
|
|
2474
|
+
const record$1 = {
|
|
2475
|
+
file: a$1.dest,
|
|
2476
|
+
keys: Object.fromEntries(Object.keys(desired).map((k) => [k, hashValue(desired[k])]))
|
|
2477
|
+
};
|
|
1663
2478
|
if (stable(current) === stable(value)) return {
|
|
1664
2479
|
status: "unchanged",
|
|
1665
|
-
label
|
|
2480
|
+
label,
|
|
2481
|
+
record: record$1
|
|
1666
2482
|
};
|
|
1667
2483
|
const notes = Object.keys(value).filter((k) => stable(current[k]) !== stable(value[k])).map((k) => `set ${k}${k in a$1.derived ? " (derived)" : ""}`);
|
|
1668
2484
|
const unmanaged = Object.keys(current).filter((k) => !(k in a$1.managed) && !(k in a$1.derived));
|
|
1669
2485
|
if (unmanaged.length) notes.push(`preserved unmanaged keys: ${unmanaged.join(", ")}`);
|
|
1670
|
-
|
|
2486
|
+
const action = {
|
|
2487
|
+
do: "write-json",
|
|
2488
|
+
dest: a$1.dest,
|
|
2489
|
+
value,
|
|
2490
|
+
backupTo: archiveDir
|
|
2491
|
+
};
|
|
2492
|
+
const ours = state.keys[a$1.dest] ?? {};
|
|
2493
|
+
const contested = Object.keys(desired).filter((k) => {
|
|
2494
|
+
if (stable(current[k]) === stable(desired[k])) return false;
|
|
2495
|
+
if (k in current) return ours[k] !== hashValue(current[k]);
|
|
2496
|
+
return k in ours;
|
|
2497
|
+
});
|
|
2498
|
+
if (!contested.length) return {
|
|
1671
2499
|
status: "pending",
|
|
1672
2500
|
label,
|
|
2501
|
+
action,
|
|
2502
|
+
notes,
|
|
2503
|
+
record: record$1
|
|
2504
|
+
};
|
|
2505
|
+
const keepValue = { ...value };
|
|
2506
|
+
for (const k of contested) if (k in current) keepValue[k] = current[k];
|
|
2507
|
+
else delete keepValue[k];
|
|
2508
|
+
const keepRecord = {
|
|
2509
|
+
file: a$1.dest,
|
|
2510
|
+
keys: Object.fromEntries(Object.entries(record$1.keys).filter(([k]) => !contested.includes(k)))
|
|
2511
|
+
};
|
|
2512
|
+
const keep = stable(keepValue) === stable(current) ? null : {
|
|
1673
2513
|
action: {
|
|
1674
2514
|
do: "write-json",
|
|
1675
2515
|
dest: a$1.dest,
|
|
1676
|
-
value,
|
|
2516
|
+
value: keepValue,
|
|
1677
2517
|
backupTo: archiveDir
|
|
1678
2518
|
},
|
|
1679
|
-
|
|
2519
|
+
record: keepRecord,
|
|
2520
|
+
notes: [`kept your values: ${contested.join(", ")}`]
|
|
2521
|
+
};
|
|
2522
|
+
return {
|
|
2523
|
+
status: "conflict",
|
|
2524
|
+
label,
|
|
2525
|
+
summary: `set outside setup: ${contested.join(", ")}`,
|
|
2526
|
+
diffText: contested.map((k) => unified(k, k in current ? pretty(current[k]) : "", pretty(desired[k]))).join("\n"),
|
|
2527
|
+
apply: {
|
|
2528
|
+
action,
|
|
2529
|
+
record: record$1,
|
|
2530
|
+
notes
|
|
2531
|
+
},
|
|
2532
|
+
keep
|
|
1680
2533
|
};
|
|
1681
2534
|
}
|
|
1682
2535
|
async function installChange(a$1, probes) {
|
|
@@ -1698,6 +2551,18 @@ async function installChange(a$1, probes) {
|
|
|
1698
2551
|
}
|
|
1699
2552
|
};
|
|
1700
2553
|
}
|
|
2554
|
+
function pretty(value) {
|
|
2555
|
+
return `${JSON.stringify(value, null, 2) ?? "null"}\n`;
|
|
2556
|
+
}
|
|
2557
|
+
function unified(name$1, before, after) {
|
|
2558
|
+
const patch = structuredPatch(name$1, name$1, before, after);
|
|
2559
|
+
const lines = [`── ${name$1}`];
|
|
2560
|
+
for (const hunk of patch.hunks) {
|
|
2561
|
+
lines.push(`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`);
|
|
2562
|
+
lines.push(...hunk.lines);
|
|
2563
|
+
}
|
|
2564
|
+
return lines.join("\n");
|
|
2565
|
+
}
|
|
1701
2566
|
/** Memoised machine lookups — `claude plugin list` costs a process spawn, so it runs once. */
|
|
1702
2567
|
var Probes = class {
|
|
1703
2568
|
onPathCache = /* @__PURE__ */ new Map();
|
|
@@ -1753,8 +2618,11 @@ var Probes = class {
|
|
|
1753
2618
|
//#endregion
|
|
1754
2619
|
//#region src/commands/setup/agents/executor.ts
|
|
1755
2620
|
/** The one place `dryRun` is consulted: the same diff is either printed or committed. */
|
|
1756
|
-
async function runPlan(plan, dryRun) {
|
|
1757
|
-
|
|
2621
|
+
async function runPlan(plan, dryRun, resolve$1) {
|
|
2622
|
+
const state = await loadState(plan.stateFile);
|
|
2623
|
+
const before = stable(state);
|
|
2624
|
+
await walk(await diff(plan, state), dryRun ? render : (change) => commit(change, state, resolve$1));
|
|
2625
|
+
if (!dryRun && stable(state) !== before) await saveState(plan.stateFile, state);
|
|
1758
2626
|
}
|
|
1759
2627
|
async function walk(sections, handle) {
|
|
1760
2628
|
for (const { title, changes } of sections) {
|
|
@@ -1769,29 +2637,59 @@ function render(change) {
|
|
|
1769
2637
|
case "pending":
|
|
1770
2638
|
log.plan(phrase(change.action));
|
|
1771
2639
|
for (const note of change.notes ?? []) log.info(note);
|
|
2640
|
+
return;
|
|
2641
|
+
case "conflict":
|
|
2642
|
+
log.warn(`conflict: ${change.label} — ${change.summary}`);
|
|
2643
|
+
log.info("will ask keep / use config / show diff (piped runs keep; --force uses config)");
|
|
1772
2644
|
}
|
|
1773
2645
|
}
|
|
1774
|
-
async function commit(change) {
|
|
2646
|
+
async function commit(change, state, resolve$1) {
|
|
1775
2647
|
switch (change.status) {
|
|
1776
|
-
case "unchanged":
|
|
2648
|
+
case "unchanged":
|
|
2649
|
+
record(state, change.record);
|
|
2650
|
+
return log.skip(`${change.label} (unchanged)`);
|
|
1777
2651
|
case "blocked": return log.fail(`${change.label} — ${change.reason}, leaving it alone`);
|
|
1778
2652
|
case "pending": {
|
|
1779
2653
|
const { ok, notes } = await perform(change.action);
|
|
1780
2654
|
if (!ok) return log.fail(`${change.label}: ${notes.join(" ")}`);
|
|
2655
|
+
record(state, change.record);
|
|
1781
2656
|
log.ok(change.label);
|
|
1782
2657
|
for (const note of [...notes, ...change.notes ?? []]) log.info(note);
|
|
2658
|
+
return;
|
|
2659
|
+
}
|
|
2660
|
+
case "conflict": {
|
|
2661
|
+
const outcome = await resolve$1(change) === "apply" ? change.apply : change.keep;
|
|
2662
|
+
if (!outcome) return log.warn(`${change.label} — ${change.summary}; kept as-is (resolve interactively or with --force)`);
|
|
2663
|
+
const { ok, notes } = await perform(outcome.action);
|
|
2664
|
+
if (!ok) return log.fail(`${change.label}: ${notes.join(" ")}`);
|
|
2665
|
+
record(state, outcome.record);
|
|
2666
|
+
log.ok(change.label);
|
|
2667
|
+
for (const note of [...notes, ...outcome.notes ?? []]) log.info(note);
|
|
1783
2668
|
}
|
|
1784
2669
|
}
|
|
1785
2670
|
}
|
|
2671
|
+
function record(state, entry) {
|
|
2672
|
+
if (!entry) return;
|
|
2673
|
+
if ("hash" in entry) state.files[entry.file] = entry.hash;
|
|
2674
|
+
else state.keys[entry.file] = {
|
|
2675
|
+
...state.keys[entry.file],
|
|
2676
|
+
...entry.keys
|
|
2677
|
+
};
|
|
2678
|
+
}
|
|
1786
2679
|
async function perform(action) {
|
|
1787
2680
|
switch (action.do) {
|
|
1788
2681
|
case "write-file": {
|
|
2682
|
+
const notes = [];
|
|
2683
|
+
if (action.backupTo) {
|
|
2684
|
+
const bak = await backup(action.dest, action.backupTo);
|
|
2685
|
+
if (bak) notes.push(`backed up → ${bak}`);
|
|
2686
|
+
}
|
|
1789
2687
|
const bytes = await readFile(action.src);
|
|
1790
2688
|
await ensureDir(dirname(action.dest));
|
|
1791
2689
|
await writeFile(action.dest, bytes, action.mode ? { mode: action.mode } : void 0);
|
|
1792
2690
|
return {
|
|
1793
2691
|
ok: true,
|
|
1794
|
-
notes
|
|
2692
|
+
notes
|
|
1795
2693
|
};
|
|
1796
2694
|
}
|
|
1797
2695
|
case "link": {
|
|
@@ -1848,16 +2746,72 @@ function phrase(action) {
|
|
|
1848
2746
|
}
|
|
1849
2747
|
}
|
|
1850
2748
|
|
|
2749
|
+
//#endregion
|
|
2750
|
+
//#region src/commands/setup/agents/resolve.ts
|
|
2751
|
+
var import_picocolors$3 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
2752
|
+
/** `--force`: the config wins every conflict, exactly as if each prompt answered "use config". */
|
|
2753
|
+
const forceResolver = async () => "apply";
|
|
2754
|
+
/** No one to ask — keep what the machine has, dpkg's default for the same reason. */
|
|
2755
|
+
const keepResolver = async () => "keep";
|
|
2756
|
+
function defaultResolver() {
|
|
2757
|
+
return isInteractive() ? interactiveResolver() : keepResolver;
|
|
2758
|
+
}
|
|
2759
|
+
function interactiveResolver(ask = select) {
|
|
2760
|
+
let rest$1 = null;
|
|
2761
|
+
return async (conflict) => {
|
|
2762
|
+
if (rest$1) return rest$1;
|
|
2763
|
+
for (;;) switch (await ask(`${conflict.label} — ${conflict.summary}`, [
|
|
2764
|
+
{
|
|
2765
|
+
value: "keep",
|
|
2766
|
+
label: "Keep what this machine has",
|
|
2767
|
+
hint: "asks again next run"
|
|
2768
|
+
},
|
|
2769
|
+
{
|
|
2770
|
+
value: "apply",
|
|
2771
|
+
label: "Use the config's version",
|
|
2772
|
+
hint: "existing is backed up"
|
|
2773
|
+
},
|
|
2774
|
+
...conflict.diffText ? [{
|
|
2775
|
+
value: "diff",
|
|
2776
|
+
label: "Show the diff first"
|
|
2777
|
+
}] : [],
|
|
2778
|
+
{
|
|
2779
|
+
value: "keep-all",
|
|
2780
|
+
label: "Keep — here and for every remaining conflict"
|
|
2781
|
+
},
|
|
2782
|
+
{
|
|
2783
|
+
value: "apply-all",
|
|
2784
|
+
label: "Use config — here and for every remaining conflict"
|
|
2785
|
+
}
|
|
2786
|
+
])) {
|
|
2787
|
+
case "diff":
|
|
2788
|
+
printDiff(conflict.diffText);
|
|
2789
|
+
continue;
|
|
2790
|
+
case "apply": return "apply";
|
|
2791
|
+
case "apply-all": return rest$1 = "apply";
|
|
2792
|
+
case "keep-all":
|
|
2793
|
+
case null: return rest$1 = "keep";
|
|
2794
|
+
default: return "keep";
|
|
2795
|
+
}
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
function printDiff(text) {
|
|
2799
|
+
for (const line of text.split("\n")) if (line.startsWith("+")) console.log(` ${import_picocolors$3.default.green(line)}`);
|
|
2800
|
+
else if (line.startsWith("-")) console.log(` ${import_picocolors$3.default.red(line)}`);
|
|
2801
|
+
else if (line.startsWith("@@")) console.log(` ${import_picocolors$3.default.cyan(line)}`);
|
|
2802
|
+
else console.log(` ${import_picocolors$3.default.dim(line)}`);
|
|
2803
|
+
}
|
|
2804
|
+
|
|
1851
2805
|
//#endregion
|
|
1852
2806
|
//#region src/commands/setup/agents/apply.ts
|
|
1853
2807
|
/** An agent with no config directory is not on this machine — skip it, never create it. */
|
|
1854
2808
|
function isInstalled(home, emitter) {
|
|
1855
2809
|
return exists(join(home, emitter.configDir));
|
|
1856
2810
|
}
|
|
1857
|
-
async function applyAgents(ctx, ids, dryRun) {
|
|
2811
|
+
async function applyAgents(ctx, ids, dryRun, resolve$1 = defaultResolver()) {
|
|
1858
2812
|
validateExtensions(ctx.config);
|
|
1859
2813
|
logCoverage(ctx.config);
|
|
1860
|
-
await runPlan(await buildStorePlan(ctx), dryRun);
|
|
2814
|
+
await runPlan(await buildStorePlan(ctx), dryRun, resolve$1);
|
|
1861
2815
|
for (const id of ids) {
|
|
1862
2816
|
const emitter = emitters[id];
|
|
1863
2817
|
if (!emitter) continue;
|
|
@@ -1866,7 +2820,7 @@ async function applyAgents(ctx, ids, dryRun) {
|
|
|
1866
2820
|
log.warn(`${id} not installed on this machine — skipping`);
|
|
1867
2821
|
continue;
|
|
1868
2822
|
}
|
|
1869
|
-
await runPlan(await emitter.buildPlan(ctx), dryRun);
|
|
2823
|
+
await runPlan(await emitter.buildPlan(ctx), dryRun, resolve$1);
|
|
1870
2824
|
}
|
|
1871
2825
|
}
|
|
1872
2826
|
|
|
@@ -1881,10 +2835,14 @@ scripted runs apply to every configured agent.
|
|
|
1881
2835
|
|
|
1882
2836
|
plan dry run — show every change, write nothing
|
|
1883
2837
|
|
|
2838
|
+
Anything on the machine that setup did not write is a conflict: interactively you choose
|
|
2839
|
+
keep / use config / see the diff; piped runs keep the machine's version.
|
|
2840
|
+
|
|
1884
2841
|
Options:
|
|
1885
2842
|
-n, --dry-run same as plan
|
|
1886
2843
|
-a, --agent <id> target one agent (repeatable) — skips the prompt
|
|
1887
2844
|
--all every configured agent — skips the prompt
|
|
2845
|
+
--force resolve every conflict in the config's favour, no prompts
|
|
1888
2846
|
--home <dir> apply against a different home directory
|
|
1889
2847
|
-h, --help show this help`;
|
|
1890
2848
|
const agents = {
|
|
@@ -1908,6 +2866,10 @@ const agents = {
|
|
|
1908
2866
|
type: "boolean",
|
|
1909
2867
|
default: false
|
|
1910
2868
|
},
|
|
2869
|
+
force: {
|
|
2870
|
+
type: "boolean",
|
|
2871
|
+
default: false
|
|
2872
|
+
},
|
|
1911
2873
|
home: { type: "string" },
|
|
1912
2874
|
help: {
|
|
1913
2875
|
type: "boolean",
|
|
@@ -1945,7 +2907,7 @@ const agents = {
|
|
|
1945
2907
|
home,
|
|
1946
2908
|
repoRoot: packageRoot$1,
|
|
1947
2909
|
config
|
|
1948
|
-
}, selected, dryRun);
|
|
2910
|
+
}, selected, dryRun, values.force ? forceResolver : defaultResolver());
|
|
1949
2911
|
console.log(dryRun ? `\n${import_picocolors$2.default.yellow("dry run complete — nothing written")}\n` : `\n${import_picocolors$2.default.green("done")}\n`);
|
|
1950
2912
|
return 0;
|
|
1951
2913
|
}
|
|
@@ -2009,7 +2971,7 @@ async function version() {
|
|
|
2009
2971
|
}
|
|
2010
2972
|
function usage() {
|
|
2011
2973
|
console.log(`Usage: pakhale <command> [options]\n\nCommands:`);
|
|
2012
|
-
for (const c of Object.values(commands)) console.log(` ${c.name.padEnd(10)} ${c.describe}`);
|
|
2974
|
+
for (const c$1 of Object.values(commands)) console.log(` ${c$1.name.padEnd(10)} ${c$1.describe}`);
|
|
2013
2975
|
console.log(`\nOptions:\n -h, --help show this help\n -v, --version show version`);
|
|
2014
2976
|
}
|
|
2015
2977
|
if (!name || name === "--help" || name === "-h") {
|