lopebase 0.6.4 → 0.6.5
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/lopebase.js +287 -276
- package/package.json +1 -1
package/dist/lopebase.js
CHANGED
|
@@ -14,7 +14,7 @@ var __toESMCache_node, __toESMCache_esm, __toESM = (mod, isNodeMode, target) =>
|
|
|
14
14
|
return cached;
|
|
15
15
|
}
|
|
16
16
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
17
|
-
let to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target;
|
|
17
|
+
let to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target;
|
|
18
18
|
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
19
19
|
for (let key of __getOwnPropNames(mod))
|
|
20
20
|
if (!__hasOwnProp.call(to, key))
|
|
@@ -157,8 +157,8 @@ var require_windows = __commonJS(function(exports, module) {
|
|
|
157
157
|
if (pathext = pathext.split(";"), pathext.indexOf("") !== -1)
|
|
158
158
|
return !0;
|
|
159
159
|
for (var i = 0;i < pathext.length; i++) {
|
|
160
|
-
var
|
|
161
|
-
if (
|
|
160
|
+
var p = pathext[i].toLowerCase();
|
|
161
|
+
if (p && path.substr(-p.length).toLowerCase() === p)
|
|
162
162
|
return !0;
|
|
163
163
|
}
|
|
164
164
|
return !1;
|
|
@@ -195,7 +195,7 @@ var require_mode = __commonJS(function(exports, module) {
|
|
|
195
195
|
return stat.isFile() && checkMode(stat, options);
|
|
196
196
|
}
|
|
197
197
|
function checkMode(stat, options) {
|
|
198
|
-
var { mode: mod, uid, gid } = stat, myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid(), myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid(),
|
|
198
|
+
var { mode: mod, uid, gid } = stat, myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid(), myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid(), u = parseInt("100", 8), g = parseInt("010", 8), o = parseInt("001", 8), ug = u | g, ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0;
|
|
199
199
|
return ret;
|
|
200
200
|
}
|
|
201
201
|
});
|
|
@@ -268,19 +268,19 @@ var require_which = __commonJS(function(exports, module) {
|
|
|
268
268
|
let { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt), found = [], step = (i) => new Promise((resolve, reject) => {
|
|
269
269
|
if (i === pathEnv.length)
|
|
270
270
|
return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
|
|
271
|
-
let ppRaw = pathEnv[i], pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw, pCmd = path.join(pathPart, cmd),
|
|
272
|
-
resolve(subStep(
|
|
273
|
-
}), subStep = (
|
|
271
|
+
let ppRaw = pathEnv[i], pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw, pCmd = path.join(pathPart, cmd), p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
272
|
+
resolve(subStep(p, i, 0));
|
|
273
|
+
}), subStep = (p, i, ii) => new Promise((resolve, reject) => {
|
|
274
274
|
if (ii === pathExt.length)
|
|
275
275
|
return resolve(step(i + 1));
|
|
276
276
|
let ext = pathExt[ii];
|
|
277
|
-
isexe(
|
|
277
|
+
isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
|
|
278
278
|
if (!er && is)
|
|
279
279
|
if (opt.all)
|
|
280
|
-
found.push(
|
|
280
|
+
found.push(p + ext);
|
|
281
281
|
else
|
|
282
|
-
return resolve(
|
|
283
|
-
return resolve(subStep(
|
|
282
|
+
return resolve(p + ext);
|
|
283
|
+
return resolve(subStep(p, i, ii + 1));
|
|
284
284
|
});
|
|
285
285
|
});
|
|
286
286
|
return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
|
|
@@ -288,9 +288,9 @@ var require_which = __commonJS(function(exports, module) {
|
|
|
288
288
|
opt = opt || {};
|
|
289
289
|
let { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt), found = [];
|
|
290
290
|
for (let i = 0;i < pathEnv.length; i++) {
|
|
291
|
-
let ppRaw = pathEnv[i], pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw, pCmd = path.join(pathPart, cmd),
|
|
292
|
-
for (let
|
|
293
|
-
let cur =
|
|
291
|
+
let ppRaw = pathEnv[i], pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw, pCmd = path.join(pathPart, cmd), p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
292
|
+
for (let j = 0;j < pathExt.length; j++) {
|
|
293
|
+
let cur = p + pathExt[j];
|
|
294
294
|
try {
|
|
295
295
|
if (isexe.sync(cur, { pathExt: pathExtExe }))
|
|
296
296
|
if (opt.all)
|
|
@@ -337,7 +337,7 @@ var require_resolveCommand = __commonJS(function(exports, module) {
|
|
|
337
337
|
path: env[getPathKey({ env })],
|
|
338
338
|
pathExt: withoutPathExt ? path.delimiter : void 0
|
|
339
339
|
});
|
|
340
|
-
} catch (
|
|
340
|
+
} catch (e) {} finally {
|
|
341
341
|
if (shouldSwitchCwd)
|
|
342
342
|
process.chdir(cwd);
|
|
343
343
|
}
|
|
@@ -392,7 +392,7 @@ var require_readShebang = __commonJS(function(exports, module) {
|
|
|
392
392
|
let buffer = Buffer.alloc(150), fd;
|
|
393
393
|
try {
|
|
394
394
|
fd = fs.openSync(command, "r"), fs.readSync(fd, buffer, 0, 150, 0), fs.closeSync(fd);
|
|
395
|
-
} catch (
|
|
395
|
+
} catch (e) {}
|
|
396
396
|
return shebangCommand(buffer.toString());
|
|
397
397
|
}
|
|
398
398
|
module.exports = readShebang;
|
|
@@ -968,17 +968,17 @@ var V2 = ce(), u = (t, n) => V2 ? t : n, le = u("◆", "*"), L2 = u("■", "x"),
|
|
|
968
968
|
return import_picocolors2.default.green(C);
|
|
969
969
|
}
|
|
970
970
|
}, G2 = (t) => {
|
|
971
|
-
let { cursor: n, options:
|
|
972
|
-
n >=
|
|
973
|
-
let $
|
|
974
|
-
return
|
|
975
|
-
let
|
|
976
|
-
return
|
|
971
|
+
let { cursor: n, options: r, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5)), l = 0;
|
|
972
|
+
n >= l + a - 3 ? l = Math.max(Math.min(n - a + 3, r.length - a), 0) : n < l + 2 && (l = Math.max(n - 2, 0));
|
|
973
|
+
let $ = a < r.length && l > 0, g = a < r.length && l + a < r.length;
|
|
974
|
+
return r.slice(l, l + a).map((p, v, f) => {
|
|
975
|
+
let j = v === 0 && $, E = v === f.length - 1 && g;
|
|
976
|
+
return j || E ? import_picocolors2.default.dim("...") : i(p, v + l === n);
|
|
977
977
|
});
|
|
978
978
|
}, he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
|
|
979
979
|
let n = `${import_picocolors2.default.gray(o)}
|
|
980
980
|
${b2(this.state)} ${t.message}
|
|
981
|
-
`,
|
|
981
|
+
`, r = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r;
|
|
982
982
|
switch (this.state) {
|
|
983
983
|
case "error":
|
|
984
984
|
return `${n.trim()}
|
|
@@ -998,7 +998,7 @@ ${import_picocolors2.default.cyan(d2)}
|
|
|
998
998
|
} }).prompt(), ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
|
|
999
999
|
let n = `${import_picocolors2.default.gray(o)}
|
|
1000
1000
|
${b2(this.state)} ${t.message}
|
|
1001
|
-
`,
|
|
1001
|
+
`, r = this.valueWithCursor, i = this.masked;
|
|
1002
1002
|
switch (this.state) {
|
|
1003
1003
|
case "error":
|
|
1004
1004
|
return `${n.trim()}
|
|
@@ -1011,16 +1011,16 @@ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(th
|
|
|
1011
1011
|
return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(i ?? ""))}${i ? `
|
|
1012
1012
|
${import_picocolors2.default.gray(o)}` : ""}`;
|
|
1013
1013
|
default:
|
|
1014
|
-
return `${n}${import_picocolors2.default.cyan(o)} ${
|
|
1014
|
+
return `${n}${import_picocolors2.default.cyan(o)} ${r}
|
|
1015
1015
|
${import_picocolors2.default.cyan(d2)}
|
|
1016
1016
|
`;
|
|
1017
1017
|
}
|
|
1018
1018
|
} }).prompt(), ye = (t) => {
|
|
1019
|
-
let n = t.active ?? "Yes",
|
|
1020
|
-
return new dD({ active: n, inactive:
|
|
1019
|
+
let n = t.active ?? "Yes", r = t.inactive ?? "No";
|
|
1020
|
+
return new dD({ active: n, inactive: r, initialValue: t.initialValue ?? !0, render() {
|
|
1021
1021
|
let i = `${import_picocolors2.default.gray(o)}
|
|
1022
1022
|
${b2(this.state)} ${t.message}
|
|
1023
|
-
`, s = this.value ? n :
|
|
1023
|
+
`, s = this.value ? n : r;
|
|
1024
1024
|
switch (this.state) {
|
|
1025
1025
|
case "submit":
|
|
1026
1026
|
return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
|
|
@@ -1028,19 +1028,19 @@ ${b2(this.state)} ${t.message}
|
|
|
1028
1028
|
return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
|
|
1029
1029
|
${import_picocolors2.default.gray(o)}`;
|
|
1030
1030
|
default:
|
|
1031
|
-
return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(
|
|
1031
|
+
return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r)}` : `${import_picocolors2.default.green(k2)} ${r}`}
|
|
1032
1032
|
${import_picocolors2.default.cyan(d2)}
|
|
1033
1033
|
`;
|
|
1034
1034
|
}
|
|
1035
1035
|
} }).prompt();
|
|
1036
1036
|
}, ve = (t) => {
|
|
1037
|
-
let n = (
|
|
1038
|
-
let s =
|
|
1037
|
+
let n = (r, i) => {
|
|
1038
|
+
let s = r.label ?? String(r.value);
|
|
1039
1039
|
switch (i) {
|
|
1040
1040
|
case "selected":
|
|
1041
1041
|
return `${import_picocolors2.default.dim(s)}`;
|
|
1042
1042
|
case "active":
|
|
1043
|
-
return `${import_picocolors2.default.green(k2)} ${s} ${
|
|
1043
|
+
return `${import_picocolors2.default.green(k2)} ${s} ${r.hint ? import_picocolors2.default.dim(`(${r.hint})`) : ""}`;
|
|
1044
1044
|
case "cancelled":
|
|
1045
1045
|
return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}`;
|
|
1046
1046
|
default:
|
|
@@ -1048,17 +1048,17 @@ ${import_picocolors2.default.cyan(d2)}
|
|
|
1048
1048
|
}
|
|
1049
1049
|
};
|
|
1050
1050
|
return new LD({ options: t.options, initialValue: t.initialValue, render() {
|
|
1051
|
-
let
|
|
1051
|
+
let r = `${import_picocolors2.default.gray(o)}
|
|
1052
1052
|
${b2(this.state)} ${t.message}
|
|
1053
1053
|
`;
|
|
1054
1054
|
switch (this.state) {
|
|
1055
1055
|
case "submit":
|
|
1056
|
-
return `${
|
|
1056
|
+
return `${r}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
|
|
1057
1057
|
case "cancel":
|
|
1058
|
-
return `${
|
|
1058
|
+
return `${r}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
|
|
1059
1059
|
${import_picocolors2.default.gray(o)}`;
|
|
1060
1060
|
default:
|
|
1061
|
-
return `${
|
|
1061
|
+
return `${r}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
|
|
1062
1062
|
${import_picocolors2.default.cyan(o)} `)}
|
|
1063
1063
|
${import_picocolors2.default.cyan(d2)}
|
|
1064
1064
|
`;
|
|
@@ -1066,16 +1066,16 @@ ${import_picocolors2.default.cyan(d2)}
|
|
|
1066
1066
|
} }).prompt();
|
|
1067
1067
|
};
|
|
1068
1068
|
var fe = (t) => {
|
|
1069
|
-
let n = (
|
|
1070
|
-
let s =
|
|
1071
|
-
return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${
|
|
1069
|
+
let n = (r, i) => {
|
|
1070
|
+
let s = r.label ?? String(r.value);
|
|
1071
|
+
return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r.hint ? import_picocolors2.default.dim(`(${r.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r.hint ? import_picocolors2.default.dim(`(${r.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r.hint ? import_picocolors2.default.dim(`(${r.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
|
|
1072
1072
|
};
|
|
1073
|
-
return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? !0, cursorAt: t.cursorAt, validate(
|
|
1074
|
-
if (this.required &&
|
|
1073
|
+
return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? !0, cursorAt: t.cursorAt, validate(r) {
|
|
1074
|
+
if (this.required && r.length === 0)
|
|
1075
1075
|
return `Please select at least one option.
|
|
1076
1076
|
${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
|
|
1077
1077
|
}, render() {
|
|
1078
|
-
let
|
|
1078
|
+
let r = `${import_picocolors2.default.gray(o)}
|
|
1079
1079
|
${b2(this.state)} ${t.message}
|
|
1080
1080
|
`, i = (s, c) => {
|
|
1081
1081
|
let a = this.value.includes(s.value);
|
|
@@ -1083,23 +1083,23 @@ ${b2(this.state)} ${t.message}
|
|
|
1083
1083
|
};
|
|
1084
1084
|
switch (this.state) {
|
|
1085
1085
|
case "submit":
|
|
1086
|
-
return `${
|
|
1086
|
+
return `${r}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
|
|
1087
1087
|
case "cancel": {
|
|
1088
1088
|
let s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
|
|
1089
|
-
return `${
|
|
1089
|
+
return `${r}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
|
|
1090
1090
|
${import_picocolors2.default.gray(o)}` : ""}`;
|
|
1091
1091
|
}
|
|
1092
1092
|
case "error": {
|
|
1093
1093
|
let s = this.error.split(`
|
|
1094
1094
|
`).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
|
|
1095
1095
|
`);
|
|
1096
|
-
return `${
|
|
1096
|
+
return `${r + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
|
|
1097
1097
|
${import_picocolors2.default.yellow(o)} `)}
|
|
1098
1098
|
${s}
|
|
1099
1099
|
`;
|
|
1100
1100
|
}
|
|
1101
1101
|
default:
|
|
1102
|
-
return `${
|
|
1102
|
+
return `${r}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
|
|
1103
1103
|
${import_picocolors2.default.cyan(o)} `)}
|
|
1104
1104
|
${import_picocolors2.default.cyan(d2)}
|
|
1105
1105
|
`;
|
|
@@ -1107,13 +1107,13 @@ ${import_picocolors2.default.cyan(d2)}
|
|
|
1107
1107
|
} }).prompt();
|
|
1108
1108
|
};
|
|
1109
1109
|
var Me = (t = "", n = "") => {
|
|
1110
|
-
let
|
|
1110
|
+
let r = `
|
|
1111
1111
|
${t}
|
|
1112
1112
|
`.split(`
|
|
1113
|
-
`), i = S2(n).length, s = Math.max(
|
|
1114
|
-
let $
|
|
1115
|
-
return
|
|
1116
|
-
}, 0), i) + 2, c =
|
|
1113
|
+
`), i = S2(n).length, s = Math.max(r.reduce((a, l) => {
|
|
1114
|
+
let $ = S2(l);
|
|
1115
|
+
return $.length > a ? $.length : a;
|
|
1116
|
+
}, 0), i) + 2, c = r.map((a) => `${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(a)}${" ".repeat(s - S2(a).length)}${import_picocolors2.default.gray(o)}`).join(`
|
|
1117
1117
|
`);
|
|
1118
1118
|
process.stdout.write(`${import_picocolors2.default.gray(o)}
|
|
1119
1119
|
${import_picocolors2.default.green(C)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
|
|
@@ -1133,13 +1133,13 @@ ${import_picocolors2.default.gray(d2)} ${t}
|
|
|
1133
1133
|
|
|
1134
1134
|
`);
|
|
1135
1135
|
}, M2 = { message: (t = "", { symbol: n = import_picocolors2.default.gray(o) } = {}) => {
|
|
1136
|
-
let
|
|
1136
|
+
let r = [`${import_picocolors2.default.gray(o)}`];
|
|
1137
1137
|
if (t) {
|
|
1138
1138
|
let [i, ...s] = t.split(`
|
|
1139
1139
|
`);
|
|
1140
|
-
|
|
1140
|
+
r.push(`${n} ${i}`, ...s.map((c) => `${import_picocolors2.default.gray(o)} ${c}`));
|
|
1141
1141
|
}
|
|
1142
|
-
process.stdout.write(`${
|
|
1142
|
+
process.stdout.write(`${r.join(`
|
|
1143
1143
|
`)}
|
|
1144
1144
|
`);
|
|
1145
1145
|
}, info: (t) => {
|
|
@@ -1156,57 +1156,68 @@ ${import_picocolors2.default.gray(d2)} ${t}
|
|
|
1156
1156
|
M2.message(t, { symbol: import_picocolors2.default.red(K2) });
|
|
1157
1157
|
} }, J2 = `${import_picocolors2.default.gray(o)} `;
|
|
1158
1158
|
var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
1159
|
-
let n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"],
|
|
1160
|
-
let
|
|
1161
|
-
a &&
|
|
1162
|
-
},
|
|
1163
|
-
process.on("uncaughtExceptionMonitor",
|
|
1159
|
+
let n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r = V2 ? 80 : 120, i = process.env.CI === "true", s, c, a = !1, l = "", $, g = performance.now(), p = (m) => {
|
|
1160
|
+
let h = m > 1 ? "Something went wrong" : "Canceled";
|
|
1161
|
+
a && N(h, m);
|
|
1162
|
+
}, v = () => p(2), f = () => p(1), j = () => {
|
|
1163
|
+
process.on("uncaughtExceptionMonitor", v), process.on("unhandledRejection", v), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p);
|
|
1164
1164
|
}, E = () => {
|
|
1165
|
-
process.removeListener("uncaughtExceptionMonitor",
|
|
1166
|
-
},
|
|
1167
|
-
if ($
|
|
1165
|
+
process.removeListener("uncaughtExceptionMonitor", v), process.removeListener("unhandledRejection", v), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p);
|
|
1166
|
+
}, B = () => {
|
|
1167
|
+
if ($ === void 0)
|
|
1168
1168
|
return;
|
|
1169
1169
|
i && process.stdout.write(`
|
|
1170
1170
|
`);
|
|
1171
|
-
let
|
|
1171
|
+
let m = $.split(`
|
|
1172
1172
|
`);
|
|
1173
|
-
process.stdout.write(import_sisteransi2.cursor.move(-999,
|
|
1174
|
-
},
|
|
1175
|
-
let
|
|
1176
|
-
return
|
|
1177
|
-
},
|
|
1178
|
-
a = !0, s = fD(),
|
|
1173
|
+
process.stdout.write(import_sisteransi2.cursor.move(-999, m.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m.length));
|
|
1174
|
+
}, R = (m) => m.replace(/\.+$/, ""), O = (m) => {
|
|
1175
|
+
let h = (performance.now() - m) / 1000, w = Math.floor(h / 60), I = Math.floor(h % 60);
|
|
1176
|
+
return w > 0 ? `[${w}m ${I}s]` : `[${I}s]`;
|
|
1177
|
+
}, H = (m = "") => {
|
|
1178
|
+
a = !0, s = fD(), l = R(m), g = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
|
|
1179
1179
|
`);
|
|
1180
|
-
let
|
|
1181
|
-
|
|
1182
|
-
if (i &&
|
|
1180
|
+
let h = 0, w = 0;
|
|
1181
|
+
j(), c = setInterval(() => {
|
|
1182
|
+
if (i && l === $)
|
|
1183
1183
|
return;
|
|
1184
|
-
|
|
1185
|
-
let
|
|
1184
|
+
B(), $ = l;
|
|
1185
|
+
let I = import_picocolors2.default.magenta(n[h]);
|
|
1186
1186
|
if (i)
|
|
1187
|
-
process.stdout.write(`${
|
|
1187
|
+
process.stdout.write(`${I} ${l}...`);
|
|
1188
1188
|
else if (t === "timer")
|
|
1189
|
-
process.stdout.write(`${
|
|
1189
|
+
process.stdout.write(`${I} ${l} ${O(g)}`);
|
|
1190
1190
|
else {
|
|
1191
|
-
let
|
|
1192
|
-
process.stdout.write(`${
|
|
1191
|
+
let z = ".".repeat(Math.floor(w)).slice(0, 3);
|
|
1192
|
+
process.stdout.write(`${I} ${l}${z}`);
|
|
1193
1193
|
}
|
|
1194
|
-
|
|
1195
|
-
},
|
|
1196
|
-
},
|
|
1197
|
-
a = !1, clearInterval(c),
|
|
1198
|
-
let
|
|
1199
|
-
|
|
1200
|
-
`) : process.stdout.write(`${
|
|
1194
|
+
h = h + 1 < n.length ? h + 1 : 0, w = w < n.length ? w + 0.125 : 0;
|
|
1195
|
+
}, r);
|
|
1196
|
+
}, N = (m = "", h = 0) => {
|
|
1197
|
+
a = !1, clearInterval(c), B();
|
|
1198
|
+
let w = h === 0 ? import_picocolors2.default.green(C) : h === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
|
|
1199
|
+
l = R(m ?? l), t === "timer" ? process.stdout.write(`${w} ${l} ${O(g)}
|
|
1200
|
+
`) : process.stdout.write(`${w} ${l}
|
|
1201
1201
|
`), E(), s();
|
|
1202
1202
|
};
|
|
1203
|
-
return { start:
|
|
1204
|
-
|
|
1203
|
+
return { start: H, stop: N, message: (m = "") => {
|
|
1204
|
+
l = R(m ?? l);
|
|
1205
1205
|
} };
|
|
1206
1206
|
};
|
|
1207
1207
|
|
|
1208
1208
|
// ../admin-adapter/src/releases.ts
|
|
1209
|
-
var ADAPTER_VERSION = "0.4.
|
|
1209
|
+
var ADAPTER_VERSION = "0.4.2", ADAPTER_RELEASES = [
|
|
1210
|
+
{
|
|
1211
|
+
version: "0.4.2",
|
|
1212
|
+
date: "2026-11-03",
|
|
1213
|
+
features: [
|
|
1214
|
+
"A service check that fails is tried once more within its time limit before the health address reports it down, so one dropped database query no longer marks the product down. cachedCheck retries the same way before it keeps a failure.",
|
|
1215
|
+
"When health() reports ok: false and no services are declared, the health address now answers 503, so LopeBase sees the product down instead of up.",
|
|
1216
|
+
"A health() hook that throws is reported as unhealthy instead of crashing the request.",
|
|
1217
|
+
"Every answer is sent with Cache-Control: no-store, so a CDN in front of the app never serves an old health result or caches rows."
|
|
1218
|
+
],
|
|
1219
|
+
steps: []
|
|
1220
|
+
},
|
|
1210
1221
|
{
|
|
1211
1222
|
version: "0.4.1",
|
|
1212
1223
|
date: "2026-10-08",
|
|
@@ -1273,29 +1284,29 @@ var ADAPTER_VERSION = "0.4.1", ADAPTER_RELEASES = [
|
|
|
1273
1284
|
steps: []
|
|
1274
1285
|
}
|
|
1275
1286
|
];
|
|
1276
|
-
function compareVersions(a,
|
|
1277
|
-
let parts = (
|
|
1278
|
-
if (
|
|
1279
|
-
return
|
|
1280
|
-
if (
|
|
1287
|
+
function compareVersions(a, b) {
|
|
1288
|
+
let parts = (v) => (v.match(/^\D*(\d+)\.(\d+)\.(\d+)/) ?? []).slice(1).map(Number), [x, y] = [parts(a), parts(b)];
|
|
1289
|
+
if (x.length !== 3)
|
|
1290
|
+
return y.length === 3 ? -1 : 0;
|
|
1291
|
+
if (y.length !== 3)
|
|
1281
1292
|
return 1;
|
|
1282
1293
|
for (let i = 0;i < 3; i++)
|
|
1283
|
-
if (
|
|
1284
|
-
return
|
|
1294
|
+
if (x[i] !== y[i])
|
|
1295
|
+
return x[i] < y[i] ? -1 : 1;
|
|
1285
1296
|
return 0;
|
|
1286
1297
|
}
|
|
1287
1298
|
function releasesSince(version) {
|
|
1288
|
-
return ADAPTER_RELEASES.filter((
|
|
1299
|
+
return ADAPTER_RELEASES.filter((r) => !version || compareVersions(r.version, version) > 0).reverse();
|
|
1289
1300
|
}
|
|
1290
1301
|
function upgradePrompt(fromVersion) {
|
|
1291
|
-
let todo = releasesSince(fromVersion), breaking = todo.flatMap((
|
|
1302
|
+
let todo = releasesSince(fromVersion), breaking = todo.flatMap((r) => r.breaking ?? []), steps = todo.flatMap((r) => r.steps);
|
|
1292
1303
|
return [
|
|
1293
|
-
`Update this app's LopeBase adapter (@lopebase/adapter) from ${fromVersion ?? "its current version"} to 0.4.
|
|
1304
|
+
`Update this app's LopeBase adapter (@lopebase/adapter) from ${fromVersion ?? "its current version"} to 0.4.2.`,
|
|
1294
1305
|
"",
|
|
1295
1306
|
"1. Install it with this repo's package manager, for example `npm install @lopebase/adapter@latest`. A 0.x range like ^0.1.2 does not pick up 0.2 or later on its own.",
|
|
1296
1307
|
...breaking.length ? [
|
|
1297
1308
|
"2. These changes would stop the adapter from starting; handle each one:",
|
|
1298
|
-
...breaking.map((
|
|
1309
|
+
...breaking.map((b) => ` - ${b}`)
|
|
1299
1310
|
] : ["2. Nothing in this update stops an existing adapter from starting."],
|
|
1300
1311
|
...steps.length ? [
|
|
1301
1312
|
"3. Adopt what is new, asking the human before each change:",
|
|
@@ -1311,7 +1322,7 @@ function upgradePrompt(fromVersion) {
|
|
|
1311
1322
|
var SIGNATURE_HEADER = "lopebase-signature";
|
|
1312
1323
|
var enc = /* @__PURE__ */ new TextEncoder;
|
|
1313
1324
|
function hex(bytes) {
|
|
1314
|
-
return [...new Uint8Array(bytes)].map((
|
|
1325
|
+
return [...new Uint8Array(bytes)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1315
1326
|
}
|
|
1316
1327
|
async function sha256Hex(data) {
|
|
1317
1328
|
return hex(await crypto.subtle.digest("SHA-256", data));
|
|
@@ -1322,8 +1333,8 @@ async function hmacHex(secret, message) {
|
|
|
1322
1333
|
}
|
|
1323
1334
|
function newSigningSecret() {
|
|
1324
1335
|
let bytes = crypto.getRandomValues(new Uint8Array(32)), bin = "";
|
|
1325
|
-
for (let
|
|
1326
|
-
bin += String.fromCharCode(
|
|
1336
|
+
for (let b of bytes)
|
|
1337
|
+
bin += String.fromCharCode(b);
|
|
1327
1338
|
return "lbs_" + btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1328
1339
|
}
|
|
1329
1340
|
function payload(t, method, pathAndQuery, bodyHash) {
|
|
@@ -1360,7 +1371,7 @@ var SENSITIVE_PARTS = /* @__PURE__ */ new Set([
|
|
|
1360
1371
|
]), SENSITIVE_JOINED = /apikey|privatekey|secretkey|accesskey|accountnumber|routingnumber|stripecustomer|paymentmethod|recoverycode/;
|
|
1361
1372
|
function isSensitiveFieldName(name) {
|
|
1362
1373
|
let parts = name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
|
|
1363
|
-
if (parts.some((
|
|
1374
|
+
if (parts.some((p) => SENSITIVE_PARTS.has(p)))
|
|
1364
1375
|
return !0;
|
|
1365
1376
|
return SENSITIVE_JOINED.test(parts.join(""));
|
|
1366
1377
|
}
|
|
@@ -1379,12 +1390,12 @@ function conformanceChecks(opts) {
|
|
|
1379
1390
|
let remote = !opts.adapter, base = opts.baseUrl ? opts.baseUrl.replace(/\/$/, "") : `${opts.origin ?? "https://property.test"}${(opts.basePath ?? opts.adapter?.config.basePath ?? DEFAULT_BASE_PATH).replace(/\/$/, "")}`, send = (req) => opts.adapter ? opts.adapter.handle(req) : fetch(req);
|
|
1380
1391
|
async function signedHeaders(url, method, bodyText, timestamp) {
|
|
1381
1392
|
if (opts.secret) {
|
|
1382
|
-
let
|
|
1393
|
+
let u = new URL(url);
|
|
1383
1394
|
return {
|
|
1384
1395
|
[SIGNATURE_HEADER]: await signRequest({
|
|
1385
1396
|
secret: opts.secret,
|
|
1386
1397
|
method,
|
|
1387
|
-
pathAndQuery:
|
|
1398
|
+
pathAndQuery: u.pathname + u.search,
|
|
1388
1399
|
body: bodyText,
|
|
1389
1400
|
timestamp
|
|
1390
1401
|
})
|
|
@@ -1402,14 +1413,14 @@ function conformanceChecks(opts) {
|
|
|
1402
1413
|
...init?.headers
|
|
1403
1414
|
}
|
|
1404
1415
|
}));
|
|
1405
|
-
}, resources = () => authed("/resources").then((
|
|
1416
|
+
}, resources = () => authed("/resources").then((r) => body(r)), checks = [
|
|
1406
1417
|
{
|
|
1407
1418
|
name: "GET /health returns { ok } without auth",
|
|
1408
1419
|
async run() {
|
|
1409
1420
|
let res = await send(new Request(`${base}/health`));
|
|
1410
1421
|
assert.equal(res.status, 200);
|
|
1411
|
-
let
|
|
1412
|
-
assert.equal(typeof
|
|
1422
|
+
let b = await body(res);
|
|
1423
|
+
assert.equal(typeof b.ok, "boolean");
|
|
1413
1424
|
}
|
|
1414
1425
|
},
|
|
1415
1426
|
{
|
|
@@ -1424,10 +1435,10 @@ function conformanceChecks(opts) {
|
|
|
1424
1435
|
async run() {
|
|
1425
1436
|
let res = await authed("/resources");
|
|
1426
1437
|
assert.equal(res.status, 200);
|
|
1427
|
-
let
|
|
1428
|
-
assert.ok(Array.isArray(
|
|
1429
|
-
for (let
|
|
1430
|
-
assert.ok(
|
|
1438
|
+
let b = await body(res);
|
|
1439
|
+
assert.ok(Array.isArray(b.resources));
|
|
1440
|
+
for (let r of b.resources)
|
|
1441
|
+
assert.ok(r.name && r.label && r.readCapability), assert.ok(Array.isArray(r.fields));
|
|
1431
1442
|
}
|
|
1432
1443
|
},
|
|
1433
1444
|
{
|
|
@@ -1435,9 +1446,9 @@ function conformanceChecks(opts) {
|
|
|
1435
1446
|
async run() {
|
|
1436
1447
|
let res = await authed("/actions");
|
|
1437
1448
|
assert.equal(res.status, 200);
|
|
1438
|
-
let
|
|
1439
|
-
assert.ok(Array.isArray(
|
|
1440
|
-
for (let a of
|
|
1449
|
+
let b = await body(res);
|
|
1450
|
+
assert.ok(Array.isArray(b.actions));
|
|
1451
|
+
for (let a of b.actions)
|
|
1441
1452
|
assert.ok(a.name && a.label && a.capability), assert.ok(Array.isArray(a.params));
|
|
1442
1453
|
}
|
|
1443
1454
|
},
|
|
@@ -1456,7 +1467,7 @@ function conformanceChecks(opts) {
|
|
|
1456
1467
|
{
|
|
1457
1468
|
name: "GET /resources/:name/:id returns a row or 404-null",
|
|
1458
1469
|
async run() {
|
|
1459
|
-
let cat = await resources(), meta = opts.sampleResource ? cat.resources.find((
|
|
1470
|
+
let cat = await resources(), meta = opts.sampleResource ? cat.resources.find((r) => r.name === opts.sampleResource) : cat.resources[0];
|
|
1460
1471
|
if (!meta)
|
|
1461
1472
|
return;
|
|
1462
1473
|
let first = (await body(await authed(`/resources/${meta.name}?limit=1`))).rows[0];
|
|
@@ -1471,8 +1482,8 @@ function conformanceChecks(opts) {
|
|
|
1471
1482
|
async run() {
|
|
1472
1483
|
let res = await authed("/audit");
|
|
1473
1484
|
assert.equal(res.status, 200);
|
|
1474
|
-
let
|
|
1475
|
-
assert.ok(Array.isArray(
|
|
1485
|
+
let b = await body(res);
|
|
1486
|
+
assert.ok(Array.isArray(b.rows));
|
|
1476
1487
|
}
|
|
1477
1488
|
},
|
|
1478
1489
|
{
|
|
@@ -1486,24 +1497,24 @@ function conformanceChecks(opts) {
|
|
|
1486
1497
|
name: "no field in the catalog looks like a secret unless marked safe",
|
|
1487
1498
|
async run() {
|
|
1488
1499
|
let cat = await resources();
|
|
1489
|
-
for (let
|
|
1490
|
-
for (let f of
|
|
1491
|
-
assert.ok(!isSensitiveFieldName(f.name) || f.sensitive === "allow", `${
|
|
1500
|
+
for (let r of cat.resources)
|
|
1501
|
+
for (let f of r.fields)
|
|
1502
|
+
assert.ok(!isSensitiveFieldName(f.name) || f.sensitive === "allow", `${r.name}.${f.name} looks sensitive`);
|
|
1492
1503
|
}
|
|
1493
1504
|
},
|
|
1494
1505
|
{
|
|
1495
1506
|
name: "rows contain only declared fields, and a page is at most 100",
|
|
1496
1507
|
async run() {
|
|
1497
1508
|
let cat = await resources();
|
|
1498
|
-
for (let
|
|
1499
|
-
let res = await authed(`/resources/${
|
|
1509
|
+
for (let r of cat.resources) {
|
|
1510
|
+
let res = await authed(`/resources/${r.name}?limit=1000`);
|
|
1500
1511
|
assert.equal(res.status, 200);
|
|
1501
1512
|
let page = await body(res);
|
|
1502
|
-
assert.ok(page.rows.length <= 100, `${
|
|
1503
|
-
let declared = /* @__PURE__ */ new Set(["id", ...
|
|
1513
|
+
assert.ok(page.rows.length <= 100, `${r.name} returned ${page.rows.length} rows`);
|
|
1514
|
+
let declared = /* @__PURE__ */ new Set(["id", ...r.fields.map((f) => f.name)]);
|
|
1504
1515
|
for (let row of page.rows)
|
|
1505
|
-
for (let
|
|
1506
|
-
assert.ok(declared.has(
|
|
1516
|
+
for (let k of Object.keys(row))
|
|
1517
|
+
assert.ok(declared.has(k), `${r.name} returned undeclared field ${k}`);
|
|
1507
1518
|
}
|
|
1508
1519
|
}
|
|
1509
1520
|
},
|
|
@@ -1521,7 +1532,7 @@ function conformanceChecks(opts) {
|
|
|
1521
1532
|
{
|
|
1522
1533
|
name: "a mutation writes an audit row (PATCH round-trips into /audit)",
|
|
1523
1534
|
async run() {
|
|
1524
|
-
let writable = (await resources()).resources.find((
|
|
1535
|
+
let writable = (await resources()).resources.find((r) => r.writeCapability && r.fields.some((f) => f.editable));
|
|
1525
1536
|
if (!writable || remote)
|
|
1526
1537
|
return;
|
|
1527
1538
|
let row = (await body(await authed(`/resources/${writable.name}?limit=1`))).rows[0];
|
|
@@ -1557,8 +1568,8 @@ async function checkAdapter(input) {
|
|
|
1557
1568
|
})
|
|
1558
1569
|
} : { authorization: `Bearer ${input.token ?? ""}` };
|
|
1559
1570
|
status = (await fetch(url, { headers })).status;
|
|
1560
|
-
} catch (
|
|
1561
|
-
let error = `Could not reach ${base} (${
|
|
1571
|
+
} catch (e) {
|
|
1572
|
+
let error = `Could not reach ${base} (${e instanceof Error ? e.message : String(e)}).`;
|
|
1562
1573
|
return log(`FAIL ${error}`), { passed, failed: [{ name: "reachable", error }] };
|
|
1563
1574
|
}
|
|
1564
1575
|
if (status === 401) {
|
|
@@ -1576,9 +1587,9 @@ async function checkAdapter(input) {
|
|
|
1576
1587
|
}))
|
|
1577
1588
|
try {
|
|
1578
1589
|
await c.run(), passed++, log(`pass ${c.name}`);
|
|
1579
|
-
} catch (
|
|
1580
|
-
let error =
|
|
1581
|
-
`)[0] : String(
|
|
1590
|
+
} catch (e) {
|
|
1591
|
+
let error = e instanceof Error ? e.message.split(`
|
|
1592
|
+
`)[0] : String(e);
|
|
1582
1593
|
failed.push({ name: c.name, error }), log(`FAIL ${c.name}: ${error}`);
|
|
1583
1594
|
}
|
|
1584
1595
|
return { passed, failed };
|
|
@@ -1592,7 +1603,7 @@ var AGENTS = [
|
|
|
1592
1603
|
id: "claude",
|
|
1593
1604
|
label: "Claude Code",
|
|
1594
1605
|
bin: "claude",
|
|
1595
|
-
args: (
|
|
1606
|
+
args: (p) => [p],
|
|
1596
1607
|
mcpAdd: (argv) => [
|
|
1597
1608
|
"mcp",
|
|
1598
1609
|
"add",
|
|
@@ -1607,27 +1618,27 @@ var AGENTS = [
|
|
|
1607
1618
|
id: "codex",
|
|
1608
1619
|
label: "Codex",
|
|
1609
1620
|
bin: "codex",
|
|
1610
|
-
args: (
|
|
1621
|
+
args: (p) => [p],
|
|
1611
1622
|
mcpAdd: (argv) => ["mcp", "add", "lopebase", "--", ...argv]
|
|
1612
1623
|
},
|
|
1613
1624
|
{
|
|
1614
1625
|
id: "gemini",
|
|
1615
1626
|
label: "Gemini CLI",
|
|
1616
1627
|
bin: "gemini",
|
|
1617
|
-
args: (
|
|
1628
|
+
args: (p) => ["-i", p],
|
|
1618
1629
|
mcpAdd: (argv) => ["mcp", "add", "lopebase", ...argv]
|
|
1619
1630
|
},
|
|
1620
1631
|
{
|
|
1621
1632
|
id: "opencode",
|
|
1622
1633
|
label: "opencode",
|
|
1623
1634
|
bin: "opencode",
|
|
1624
|
-
args: (
|
|
1635
|
+
args: (p) => ["--prompt", p]
|
|
1625
1636
|
},
|
|
1626
1637
|
{
|
|
1627
1638
|
id: "cursor-agent",
|
|
1628
1639
|
label: "Cursor Agent",
|
|
1629
1640
|
bin: "cursor-agent",
|
|
1630
|
-
args: (
|
|
1641
|
+
args: (p) => [p]
|
|
1631
1642
|
}
|
|
1632
1643
|
];
|
|
1633
1644
|
function isInstalled(bin) {
|
|
@@ -1666,17 +1677,17 @@ import os from "node:os";
|
|
|
1666
1677
|
import path from "node:path";
|
|
1667
1678
|
var DEFAULT_URL = "https://app.lopebase.com";
|
|
1668
1679
|
function workspaceUrl(input) {
|
|
1669
|
-
let
|
|
1670
|
-
if (!
|
|
1680
|
+
let v = input.trim().replace(/\/+$/, "");
|
|
1681
|
+
if (!v)
|
|
1671
1682
|
return null;
|
|
1672
|
-
if (/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(
|
|
1673
|
-
return `https://${
|
|
1674
|
-
let withScheme = /^https?:\/\//i.test(
|
|
1683
|
+
if (/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(v))
|
|
1684
|
+
return `https://${v.toLowerCase()}.lopebase.com`;
|
|
1685
|
+
let withScheme = /^https?:\/\//i.test(v) ? v : `https://${v}`;
|
|
1675
1686
|
try {
|
|
1676
|
-
let
|
|
1677
|
-
if (!
|
|
1687
|
+
let u = new URL(withScheme);
|
|
1688
|
+
if (!u.hostname.includes(".") && u.hostname !== "localhost")
|
|
1678
1689
|
return null;
|
|
1679
|
-
return `${
|
|
1690
|
+
return `${u.origin}${u.pathname.replace(/\/+$/, "")}`;
|
|
1680
1691
|
} catch {
|
|
1681
1692
|
return null;
|
|
1682
1693
|
}
|
|
@@ -1726,7 +1737,7 @@ var APP_SIDE_ENV = /^(NEXT_PUBLIC_|PUBLIC_|VITE_|NUXT_PUBLIC_|EXPO_PUBLIC_|REACT
|
|
|
1726
1737
|
function evidenceFor(facts, rule) {
|
|
1727
1738
|
let out = [], weak = [];
|
|
1728
1739
|
for (let re of rule.deps ?? []) {
|
|
1729
|
-
let hit = facts.dependencies.find((
|
|
1740
|
+
let hit = facts.dependencies.find((d) => re.test(d));
|
|
1730
1741
|
if (hit)
|
|
1731
1742
|
out.push(`uses ${hit.replace(/^(py|gem|composer|go|cargo):/, "")}`);
|
|
1732
1743
|
}
|
|
@@ -1736,7 +1747,7 @@ function evidenceFor(facts, rule) {
|
|
|
1736
1747
|
out.push(`has ${hit.replace(/#.*$/, "")}`);
|
|
1737
1748
|
}
|
|
1738
1749
|
for (let re of rule.env ?? []) {
|
|
1739
|
-
let hit = facts.envKeys.find((
|
|
1750
|
+
let hit = facts.envKeys.find((k) => re.test(k));
|
|
1740
1751
|
if (hit)
|
|
1741
1752
|
(APP_SIDE_ENV.test(hit) ? out : weak).push(`env ${hit}`);
|
|
1742
1753
|
}
|
|
@@ -2318,11 +2329,11 @@ var QUEUES = [
|
|
|
2318
2329
|
[/^py:celery$/, "Job queue (Celery)"],
|
|
2319
2330
|
[/^gem:sidekiq$/, "Job queue (Sidekiq)"]
|
|
2320
2331
|
], NOT_A_SERVICE = /* @__PURE__ */ new Set(["Prisma", "Drizzle"]);
|
|
2321
|
-
function watchList(
|
|
2332
|
+
function watchList(d, facts) {
|
|
2322
2333
|
let slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""), out = [];
|
|
2323
|
-
if (
|
|
2334
|
+
if (d.sources.some((s) => s.source === "uptime") || facts.siteUrl)
|
|
2324
2335
|
out.push({ id: "site", label: facts.siteUrl ?? "Website", how: "address" });
|
|
2325
|
-
for (let s of
|
|
2336
|
+
for (let s of d.stack)
|
|
2326
2337
|
if (s.kind === "database" && !NOT_A_SERVICE.has(s.name))
|
|
2327
2338
|
out.push({ id: slug(s.name), label: s.name, how: "service" });
|
|
2328
2339
|
for (let [re, label] of QUEUES)
|
|
@@ -2332,7 +2343,7 @@ function watchList(d3, facts) {
|
|
|
2332
2343
|
label,
|
|
2333
2344
|
how: "service"
|
|
2334
2345
|
});
|
|
2335
|
-
let email =
|
|
2346
|
+
let email = d.stack.find((s) => s.kind === "email" && s.name !== "Nodemailer");
|
|
2336
2347
|
if (email)
|
|
2337
2348
|
out.push({
|
|
2338
2349
|
id: "email",
|
|
@@ -2340,7 +2351,7 @@ function watchList(d3, facts) {
|
|
|
2340
2351
|
how: "service"
|
|
2341
2352
|
});
|
|
2342
2353
|
let seen = /* @__PURE__ */ new Set;
|
|
2343
|
-
return out.filter((
|
|
2354
|
+
return out.filter((w) => !seen.has(w.id) && seen.add(w.id));
|
|
2344
2355
|
}
|
|
2345
2356
|
|
|
2346
2357
|
// src/device-login.ts
|
|
@@ -2357,27 +2368,27 @@ async function startDeviceLogin(url, opts = {}) {
|
|
|
2357
2368
|
});
|
|
2358
2369
|
if (!res.ok)
|
|
2359
2370
|
return null;
|
|
2360
|
-
let
|
|
2361
|
-
if (typeof
|
|
2371
|
+
let b = await res.json();
|
|
2372
|
+
if (typeof b.device_code !== "string" || typeof b.user_code !== "string")
|
|
2362
2373
|
return null;
|
|
2363
2374
|
return {
|
|
2364
|
-
deviceCode:
|
|
2365
|
-
userCode:
|
|
2366
|
-
verifyUrl: String(
|
|
2367
|
-
interval: Number(
|
|
2368
|
-
expiresIn: Number(
|
|
2375
|
+
deviceCode: b.device_code,
|
|
2376
|
+
userCode: b.user_code,
|
|
2377
|
+
verifyUrl: String(b.verification_uri_complete ?? b.verification_uri),
|
|
2378
|
+
interval: Number(b.interval) || 5,
|
|
2379
|
+
expiresIn: Number(b.expires_in) || 600
|
|
2369
2380
|
};
|
|
2370
2381
|
} catch {
|
|
2371
2382
|
return null;
|
|
2372
2383
|
}
|
|
2373
2384
|
}
|
|
2374
2385
|
async function pollDeviceLogin(url, start, opts = {}) {
|
|
2375
|
-
let f = opts.fetchImpl ?? fetch, sleep = opts.sleep ?? ((ms) => new Promise((
|
|
2386
|
+
let f = opts.fetchImpl ?? fetch, sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms))), interval = start.interval, deadline = Date.now() + start.expiresIn * 1000;
|
|
2376
2387
|
while (Date.now() < deadline) {
|
|
2377
2388
|
await sleep(interval * 1000);
|
|
2378
|
-
let
|
|
2389
|
+
let body;
|
|
2379
2390
|
try {
|
|
2380
|
-
|
|
2391
|
+
body = await (await f(`${url}/api/oauth/token`, {
|
|
2381
2392
|
method: "POST",
|
|
2382
2393
|
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
2383
2394
|
body: new URLSearchParams({
|
|
@@ -2388,14 +2399,14 @@ async function pollDeviceLogin(url, start, opts = {}) {
|
|
|
2388
2399
|
} catch {
|
|
2389
2400
|
continue;
|
|
2390
2401
|
}
|
|
2391
|
-
if (typeof
|
|
2402
|
+
if (typeof body.access_token === "string")
|
|
2392
2403
|
return {
|
|
2393
2404
|
ok: !0,
|
|
2394
|
-
token:
|
|
2395
|
-
url: typeof
|
|
2396
|
-
scope: String(
|
|
2405
|
+
token: body.access_token,
|
|
2406
|
+
url: typeof body.workspace_url === "string" ? body.workspace_url : url,
|
|
2407
|
+
scope: String(body.scope ?? "")
|
|
2397
2408
|
};
|
|
2398
|
-
switch (
|
|
2409
|
+
switch (body.error) {
|
|
2399
2410
|
case "authorization_pending":
|
|
2400
2411
|
continue;
|
|
2401
2412
|
case "slow_down":
|
|
@@ -2417,7 +2428,7 @@ async function pollDeviceLogin(url, start, opts = {}) {
|
|
|
2417
2428
|
return {
|
|
2418
2429
|
ok: !1,
|
|
2419
2430
|
reason: "error",
|
|
2420
|
-
message: String(
|
|
2431
|
+
message: String(body.error_description ?? body.error ?? "Sign-in failed.")
|
|
2421
2432
|
};
|
|
2422
2433
|
}
|
|
2423
2434
|
}
|
|
@@ -2486,7 +2497,7 @@ async function runMcpProxy(auth, fetchImpl = fetch) {
|
|
|
2486
2497
|
}
|
|
2487
2498
|
process.stdout.write(`${text}
|
|
2488
2499
|
`);
|
|
2489
|
-
} catch (
|
|
2500
|
+
} catch (e) {
|
|
2490
2501
|
if (id === null)
|
|
2491
2502
|
return;
|
|
2492
2503
|
write({
|
|
@@ -2494,7 +2505,7 @@ async function runMcpProxy(auth, fetchImpl = fetch) {
|
|
|
2494
2505
|
id,
|
|
2495
2506
|
error: {
|
|
2496
2507
|
code: -32000,
|
|
2497
|
-
message: `Could not reach LopeBase at ${endpoint}: ${String(
|
|
2508
|
+
message: `Could not reach LopeBase at ${endpoint}: ${String(e)}`
|
|
2498
2509
|
}
|
|
2499
2510
|
});
|
|
2500
2511
|
}
|
|
@@ -2512,7 +2523,7 @@ function onboardingPrompt(input) {
|
|
|
2512
2523
|
`- Stack: ${stack}`,
|
|
2513
2524
|
`- Already in use: ${found.map((s) => s.label).join(", ") || "none of the sources LopeBase reads"}`,
|
|
2514
2525
|
`- The human wants connected: ${chosen.join(", ") || "whatever get_onboarding_status recommends"}`,
|
|
2515
|
-
`- Worth watching for uptime: ${(input.watch ?? []).map((
|
|
2526
|
+
`- Worth watching for uptime: ${(input.watch ?? []).map((w) => `${w.label} (${w.how === "address" ? "uptime check on its address" : "adapter health service"})`).join(", ") || "the site, if it has one"}`,
|
|
2516
2527
|
`- LopeBase pageviews: ${input.pageviews ? "yes, the human wants them" : "not chosen; offer once, do not push"}`,
|
|
2517
2528
|
"",
|
|
2518
2529
|
"How to work:",
|
|
@@ -2586,15 +2597,15 @@ var MONOREPO_DIRS = ["apps", "packages", "services", "sites", "web", "site"], SK
|
|
|
2586
2597
|
".github/workflows",
|
|
2587
2598
|
"content/config.ts"
|
|
2588
2599
|
], EXAMPLE_ENV = /^(\.env\.(example|sample|template|dist|local\.example|development\.example|production\.example)|example\.env|\.dev\.vars\.example)$/;
|
|
2589
|
-
function readText(
|
|
2600
|
+
function readText(file) {
|
|
2590
2601
|
try {
|
|
2591
|
-
return readFileSync2(
|
|
2602
|
+
return readFileSync2(file, "utf8");
|
|
2592
2603
|
} catch {
|
|
2593
2604
|
return null;
|
|
2594
2605
|
}
|
|
2595
2606
|
}
|
|
2596
|
-
function readJson(
|
|
2597
|
-
let text = readText(
|
|
2607
|
+
function readJson(file) {
|
|
2608
|
+
let text = readText(file);
|
|
2598
2609
|
if (text === null)
|
|
2599
2610
|
return null;
|
|
2600
2611
|
try {
|
|
@@ -2603,9 +2614,9 @@ function readJson(file2) {
|
|
|
2603
2614
|
return null;
|
|
2604
2615
|
}
|
|
2605
2616
|
}
|
|
2606
|
-
function isDir(
|
|
2617
|
+
function isDir(p) {
|
|
2607
2618
|
try {
|
|
2608
|
-
return statSync(
|
|
2619
|
+
return statSync(p).isDirectory();
|
|
2609
2620
|
} catch {
|
|
2610
2621
|
return !1;
|
|
2611
2622
|
}
|
|
@@ -2630,14 +2641,14 @@ function isPackage(dir) {
|
|
|
2630
2641
|
}
|
|
2631
2642
|
function workspaceGlobs(root) {
|
|
2632
2643
|
let globs = [], ws = readJson(path2.join(root, "package.json"))?.workspaces, list = Array.isArray(ws) ? ws : ws && typeof ws === "object" && Array.isArray(ws.packages) ? ws.packages : [];
|
|
2633
|
-
for (let
|
|
2634
|
-
if (typeof
|
|
2635
|
-
globs.push(
|
|
2644
|
+
for (let g of list)
|
|
2645
|
+
if (typeof g === "string")
|
|
2646
|
+
globs.push(g);
|
|
2636
2647
|
let pnpm = readText(path2.join(root, "pnpm-workspace.yaml"));
|
|
2637
2648
|
if (pnpm)
|
|
2638
|
-
for (let
|
|
2639
|
-
globs.push(
|
|
2640
|
-
return globs.filter((
|
|
2649
|
+
for (let m of pnpm.matchAll(/^\s*-\s*["']?([^"'\s#]+)["']?/gm))
|
|
2650
|
+
globs.push(m[1]);
|
|
2651
|
+
return globs.filter((g) => !g.startsWith("!"));
|
|
2641
2652
|
}
|
|
2642
2653
|
function expandGlob(root, glob) {
|
|
2643
2654
|
let clean = glob.replace(/\/\*\*$/, "/*").replace(/\/$/, "");
|
|
@@ -2646,24 +2657,24 @@ function expandGlob(root, glob) {
|
|
|
2646
2657
|
return isDir(dir) ? [dir] : [];
|
|
2647
2658
|
}
|
|
2648
2659
|
let [base] = clean.split("*"), parent = path2.join(root, base);
|
|
2649
|
-
return listDir(parent).filter((
|
|
2660
|
+
return listDir(parent).filter((e) => !SKIP_DIRS.has(e) && !e.startsWith(".")).map((e) => path2.join(parent, e)).filter(isDir);
|
|
2650
2661
|
}
|
|
2651
2662
|
function packageDirs(root) {
|
|
2652
2663
|
let dirs = /* @__PURE__ */ new Set([root]);
|
|
2653
|
-
for (let
|
|
2654
|
-
for (let
|
|
2655
|
-
if (isPackage(
|
|
2656
|
-
dirs.add(
|
|
2664
|
+
for (let g of workspaceGlobs(root))
|
|
2665
|
+
for (let d of expandGlob(root, g))
|
|
2666
|
+
if (isPackage(d))
|
|
2667
|
+
dirs.add(d);
|
|
2657
2668
|
for (let group of MONOREPO_DIRS) {
|
|
2658
|
-
let
|
|
2659
|
-
if (!isDir(
|
|
2669
|
+
let g = path2.join(root, group);
|
|
2670
|
+
if (!isDir(g))
|
|
2660
2671
|
continue;
|
|
2661
|
-
if (isPackage(
|
|
2662
|
-
dirs.add(
|
|
2663
|
-
for (let entry of listDir(
|
|
2664
|
-
let
|
|
2665
|
-
if (!SKIP_DIRS.has(entry) && isDir(
|
|
2666
|
-
dirs.add(
|
|
2672
|
+
if (isPackage(g))
|
|
2673
|
+
dirs.add(g);
|
|
2674
|
+
for (let entry of listDir(g)) {
|
|
2675
|
+
let d = path2.join(g, entry);
|
|
2676
|
+
if (!SKIP_DIRS.has(entry) && isDir(d) && isPackage(d))
|
|
2677
|
+
dirs.add(d);
|
|
2667
2678
|
}
|
|
2668
2679
|
}
|
|
2669
2680
|
return [...dirs].slice(0, MAX_PACKAGES);
|
|
@@ -2671,36 +2682,36 @@ function packageDirs(root) {
|
|
|
2671
2682
|
function pythonRequirements(text) {
|
|
2672
2683
|
let out = [];
|
|
2673
2684
|
for (let line of text.split(/\r?\n/)) {
|
|
2674
|
-
let
|
|
2675
|
-
if (
|
|
2676
|
-
out.push(
|
|
2685
|
+
let m = /^\s*([A-Za-z0-9][A-Za-z0-9._-]*)/.exec(line.replace(/#.*/, ""));
|
|
2686
|
+
if (m && !line.trim().startsWith("-"))
|
|
2687
|
+
out.push(m[1].toLowerCase());
|
|
2677
2688
|
}
|
|
2678
2689
|
return out;
|
|
2679
2690
|
}
|
|
2680
2691
|
function pythonProjectDeps(text) {
|
|
2681
2692
|
let out = /* @__PURE__ */ new Set;
|
|
2682
2693
|
for (let block of text.matchAll(/(?:^|\n)\s*dependencies\s*=\s*\[([\s\S]*?)\]/g))
|
|
2683
|
-
for (let
|
|
2684
|
-
out.add(
|
|
2694
|
+
for (let m of block[1].matchAll(/["']([A-Za-z0-9][A-Za-z0-9._-]*)/g))
|
|
2695
|
+
out.add(m[1].toLowerCase());
|
|
2685
2696
|
for (let table of text.matchAll(/\[(?:tool\.poetry\.(?:group\.[a-z]+\.)?dependencies|(?:dev-)?packages)\]([\s\S]*?)(?=\n\[|$)/g))
|
|
2686
|
-
for (let
|
|
2687
|
-
out.add(
|
|
2697
|
+
for (let m of table[1].matchAll(/^\s*([A-Za-z0-9][A-Za-z0-9._-]*)\s*=/gm))
|
|
2698
|
+
out.add(m[1].toLowerCase());
|
|
2688
2699
|
return out.delete("python"), [...out];
|
|
2689
2700
|
}
|
|
2690
2701
|
function gemfileDeps(text) {
|
|
2691
|
-
return [...text.matchAll(/^\s*gem\s+["']([^"']+)["']/gm)].map((
|
|
2702
|
+
return [...text.matchAll(/^\s*gem\s+["']([^"']+)["']/gm)].map((m) => m[1]);
|
|
2692
2703
|
}
|
|
2693
2704
|
function goModDeps(text) {
|
|
2694
2705
|
let out = [];
|
|
2695
|
-
for (let
|
|
2696
|
-
out.push(
|
|
2706
|
+
for (let m of text.matchAll(/^\s*(?:require\s+)?([a-z0-9.-]+\.[a-z]+\/[^\s]+)\s+v[0-9]/gm))
|
|
2707
|
+
out.push(m[1]);
|
|
2697
2708
|
return out;
|
|
2698
2709
|
}
|
|
2699
2710
|
function cargoDeps(text) {
|
|
2700
2711
|
let out = [];
|
|
2701
2712
|
for (let table of text.matchAll(/\[(?:dev-|build-)?dependencies\]([\s\S]*?)(?=\n\[|$)/g))
|
|
2702
|
-
for (let
|
|
2703
|
-
out.push(
|
|
2713
|
+
for (let m of table[1].matchAll(/^\s*([A-Za-z0-9_-]+)\s*=/gm))
|
|
2714
|
+
out.push(m[1]);
|
|
2704
2715
|
return out;
|
|
2705
2716
|
}
|
|
2706
2717
|
function manifestDeps(dir) {
|
|
@@ -2719,10 +2730,10 @@ function manifestDeps(dir) {
|
|
|
2719
2730
|
if (gem)
|
|
2720
2731
|
add("gem", gemfileDeps(gem));
|
|
2721
2732
|
let composer = readJson(path2.join(dir, "composer.json"));
|
|
2722
|
-
for (let
|
|
2723
|
-
let
|
|
2724
|
-
if (
|
|
2725
|
-
add("composer", Object.keys(
|
|
2733
|
+
for (let k of ["require", "require-dev"]) {
|
|
2734
|
+
let d = composer?.[k];
|
|
2735
|
+
if (d && typeof d === "object")
|
|
2736
|
+
add("composer", Object.keys(d));
|
|
2726
2737
|
}
|
|
2727
2738
|
let gomod = readText(path2.join(dir, "go.mod"));
|
|
2728
2739
|
if (gomod)
|
|
@@ -2736,7 +2747,7 @@ function siteFromWrangler(text) {
|
|
|
2736
2747
|
let first = [
|
|
2737
2748
|
...text.matchAll(/(?:pattern|route)["']?\s*[:=]\s*["']([^"'*/\s]+)/g),
|
|
2738
2749
|
...text.matchAll(/custom_domain["']?\s*[:=]\s*["']([^"'*/\s]+)/g)
|
|
2739
|
-
].map((
|
|
2750
|
+
].map((m) => m[1].toLowerCase()).filter((h) => h.includes(".") && !h.endsWith("workers.dev"))[0];
|
|
2740
2751
|
if (!first)
|
|
2741
2752
|
return;
|
|
2742
2753
|
return `https://${first.replace(/^(app|www|api|console)\./, "")}`;
|
|
@@ -2744,26 +2755,26 @@ function siteFromWrangler(text) {
|
|
|
2744
2755
|
var NOT_A_SITE = /(^|\.)(localhost|example\.(com|org)|your-?(site|domain)\.[a-z]+|vercel\.app|netlify\.app|pages\.dev|workers\.dev|github\.com|gitlab\.com|npmjs\.com)$/;
|
|
2745
2756
|
function publicSite(url) {
|
|
2746
2757
|
try {
|
|
2747
|
-
let
|
|
2748
|
-
if (!
|
|
2758
|
+
let u = new URL(url.startsWith("http") ? url : `https://${url}`);
|
|
2759
|
+
if (!u.hostname.includes(".") || NOT_A_SITE.test(u.hostname))
|
|
2749
2760
|
return;
|
|
2750
|
-
return `https://${
|
|
2761
|
+
return `https://${u.hostname.replace(/^www\./, "")}`;
|
|
2751
2762
|
} catch {
|
|
2752
2763
|
return;
|
|
2753
2764
|
}
|
|
2754
2765
|
}
|
|
2755
2766
|
function siteFromConfig(text) {
|
|
2756
|
-
let
|
|
2757
|
-
return
|
|
2767
|
+
let m = /\b(?:site|siteUrl|baseURL|baseUrl|url)\s*[:=]\s*["'`](https?:\/\/[^"'`\s]+)["'`]/.exec(text);
|
|
2768
|
+
return m ? publicSite(m[1]) : void 0;
|
|
2758
2769
|
}
|
|
2759
2770
|
function githubRepo(gitConfig) {
|
|
2760
2771
|
let remotes = [
|
|
2761
2772
|
...gitConfig.matchAll(/\[remote "([^"]+)"\][^[]*?url\s*=\s*(\S+)/g)
|
|
2762
|
-
].sort((a,
|
|
2773
|
+
].sort((a, b) => Number(b[1] === "origin") - Number(a[1] === "origin"));
|
|
2763
2774
|
for (let [, , url] of remotes) {
|
|
2764
|
-
let
|
|
2765
|
-
if (
|
|
2766
|
-
return `${
|
|
2775
|
+
let m = /github\.com[:/]([\w.-]+)\/([\w.-]+?)(?:\.git)?\/?$/.exec(url);
|
|
2776
|
+
if (m)
|
|
2777
|
+
return `${m[1]}/${m[2]}`;
|
|
2767
2778
|
}
|
|
2768
2779
|
return;
|
|
2769
2780
|
}
|
|
@@ -2778,21 +2789,21 @@ function readGitConfig(root) {
|
|
|
2778
2789
|
return readText(path2.join(gitDir, "config")) ?? readText(path2.join(gitDir, "..", "..", "config"));
|
|
2779
2790
|
}
|
|
2780
2791
|
function siteFromHtml(html) {
|
|
2781
|
-
let
|
|
2782
|
-
return
|
|
2792
|
+
let m = /<link[^>]+rel=["']canonical["'][^>]+href=["'](https?:\/\/[^"']+)/i.exec(html) ?? /<link[^>]+href=["'](https?:\/\/[^"']+)["'][^>]+rel=["']canonical["']/i.exec(html) ?? /<meta[^>]+property=["']og:url["'][^>]+content=["'](https?:\/\/[^"']+)/i.exec(html);
|
|
2793
|
+
return m ? publicSite(m[1]) : void 0;
|
|
2783
2794
|
}
|
|
2784
2795
|
function envKeyNames(text) {
|
|
2785
2796
|
let out = [];
|
|
2786
2797
|
for (let line of text.split(/\r?\n/)) {
|
|
2787
|
-
let
|
|
2788
|
-
if (
|
|
2789
|
-
out.push(
|
|
2798
|
+
let m = /^\s*(?:#\s*)?(?:export\s+)?([A-Z][A-Z0-9_]*)\s*=/.exec(line);
|
|
2799
|
+
if (m)
|
|
2800
|
+
out.push(m[1]);
|
|
2790
2801
|
}
|
|
2791
2802
|
return out;
|
|
2792
2803
|
}
|
|
2793
2804
|
var SITE_CONFIGS = /^(astro\.config\.\w+|next-sitemap\.config\.\w+|gatsby-config\.\w+|docusaurus\.config\.\w+|hugo\.toml|config\.toml|_config\.ya?ml|nuxt\.config\.\w+)$/;
|
|
2794
2805
|
function scanProject(root, onProgress) {
|
|
2795
|
-
let deps = /* @__PURE__ */ new Set, files = /* @__PURE__ */ new Set, envKeys = /* @__PURE__ */ new Set, name, siteUrl, dirs = packageDirs(root), relDir = (
|
|
2806
|
+
let deps = /* @__PURE__ */ new Set, files = /* @__PURE__ */ new Set, envKeys = /* @__PURE__ */ new Set, name, siteUrl, dirs = packageDirs(root), relDir = (d) => path2.relative(root, d).split(path2.sep).join("/") || ".";
|
|
2796
2807
|
onProgress?.({
|
|
2797
2808
|
label: `Found ${dirs.length} ${dirs.length === 1 ? "package" : "packages"}`,
|
|
2798
2809
|
detail: dirs.length > 1 ? dirs.map(relDir).join(", ") : void 0
|
|
@@ -2805,22 +2816,22 @@ function scanProject(root, onProgress) {
|
|
|
2805
2816
|
name = pkg.name;
|
|
2806
2817
|
if (!siteUrl && typeof pkg.homepage === "string")
|
|
2807
2818
|
siteUrl = publicSite(pkg.homepage);
|
|
2808
|
-
for (let
|
|
2809
|
-
let
|
|
2810
|
-
if (
|
|
2811
|
-
for (let n of Object.keys(
|
|
2819
|
+
for (let k of ["dependencies", "devDependencies"]) {
|
|
2820
|
+
let d = pkg[k];
|
|
2821
|
+
if (d && typeof d === "object")
|
|
2822
|
+
for (let n of Object.keys(d))
|
|
2812
2823
|
deps.add(n);
|
|
2813
2824
|
}
|
|
2814
2825
|
}
|
|
2815
|
-
for (let
|
|
2816
|
-
deps.add(
|
|
2826
|
+
for (let d of manifestDeps(dir))
|
|
2827
|
+
deps.add(d);
|
|
2817
2828
|
for (let entry of listDir(dir)) {
|
|
2818
2829
|
if (EXAMPLE_ENV.test(entry)) {
|
|
2819
2830
|
let text = readText(path2.join(dir, entry));
|
|
2820
2831
|
if (text) {
|
|
2821
2832
|
envFiles++;
|
|
2822
|
-
for (let
|
|
2823
|
-
envKeys.add(
|
|
2833
|
+
for (let k of envKeyNames(text))
|
|
2834
|
+
envKeys.add(k);
|
|
2824
2835
|
}
|
|
2825
2836
|
}
|
|
2826
2837
|
if (!MARKERS.some((re) => re.test(entry)))
|
|
@@ -2891,8 +2902,8 @@ function paint(rgb, text, bg = !1) {
|
|
|
2891
2902
|
return text;
|
|
2892
2903
|
if (!trueColor())
|
|
2893
2904
|
return bg ? import_picocolors3.default.bgMagenta(import_picocolors3.default.black(text)) : import_picocolors3.default.magenta(text);
|
|
2894
|
-
let [
|
|
2895
|
-
return `\x1B[${bg ? 48 : 38};2;${
|
|
2905
|
+
let [r, g, b] = rgb;
|
|
2906
|
+
return `\x1B[${bg ? 48 : 38};2;${r};${g};${b}m${text}\x1B[${bg ? 49 : 39}m`;
|
|
2896
2907
|
}
|
|
2897
2908
|
var brand = (text) => paint(BRAND, text), badge = (text) => paint(BRAND, import_picocolors3.default.black(import_picocolors3.default.bold(` ${text} `)), !0), ramp = (i, text) => paint(RAMP[Math.min(i, RAMP.length - 1)], text), MARK = [
|
|
2898
2909
|
" ▗▖ ▗▖ ",
|
|
@@ -2907,7 +2918,7 @@ var brand = (text) => paint(BRAND, text), badge = (text) => paint(BRAND, import_
|
|
|
2907
2918
|
function motionAllowed(argv = process.argv, env = process.env, isTTY = Boolean(process.stdout.isTTY)) {
|
|
2908
2919
|
return isTTY && !env.CI && !env.LOPEBASE_NO_MOTION && env.TERM !== "dumb" && !argv.includes("--no-motion");
|
|
2909
2920
|
}
|
|
2910
|
-
var sleep = (ms) => new Promise((
|
|
2921
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
2911
2922
|
function logoLines(opts) {
|
|
2912
2923
|
let right = {
|
|
2913
2924
|
3: `${import_picocolors3.default.bold("Lope")}${brand("Base")}${opts.version ? import_picocolors3.default.dim(` v${opts.version}`) : ""}`,
|
|
@@ -2928,7 +2939,7 @@ ${lines.join(`
|
|
|
2928
2939
|
`);
|
|
2929
2940
|
return;
|
|
2930
2941
|
}
|
|
2931
|
-
let blank = MARK.map((
|
|
2942
|
+
let blank = MARK.map((r) => " ".repeat(r.length)), frame = (shown) => MARK.map((row, i) => shown.has(i) ? HORIZON.has(i) ? import_picocolors3.default.dim(ramp(i, row)) : ramp(i, row) : blank[i]), up = `\x1B[${MARK.length}A`, onInterrupt = () => {
|
|
2932
2943
|
write(`\x1B[?25h
|
|
2933
2944
|
`), process.exit(130);
|
|
2934
2945
|
};
|
|
@@ -2982,8 +2993,8 @@ function stackRows(detection, facts) {
|
|
|
2982
2993
|
rows.push(["Repo", facts.repo]);
|
|
2983
2994
|
if (!rows.length)
|
|
2984
2995
|
return [import_picocolors3.default.dim("Nothing recognized yet. Your agent will look closer.")];
|
|
2985
|
-
let width = Math.max(...rows.map(([
|
|
2986
|
-
return rows.map(([
|
|
2996
|
+
let width = Math.max(...rows.map(([k]) => k.length));
|
|
2997
|
+
return rows.map(([k, v]) => `${import_picocolors3.default.dim(k.padEnd(width))} ${v}`);
|
|
2987
2998
|
}
|
|
2988
2999
|
var PLAN = [
|
|
2989
3000
|
{
|
|
@@ -3008,13 +3019,13 @@ function planLines() {
|
|
|
3008
3019
|
${import_picocolors3.default.dim(s.detail)}`);
|
|
3009
3020
|
}
|
|
3010
3021
|
function stepRail(n, total = PLAN.length) {
|
|
3011
|
-
return Array.from({ length: total }, (
|
|
3022
|
+
return Array.from({ length: total }, (_, i) => i < n ? brand("◆") : import_picocolors3.default.dim("◇")).join(import_picocolors3.default.dim(" ── "));
|
|
3012
3023
|
}
|
|
3013
3024
|
function stepTitle(n) {
|
|
3014
3025
|
return `${stepRail(n)} ${import_picocolors3.default.dim(`Step ${n} of ${PLAN.length}`)} ${import_picocolors3.default.bold(PLAN[n - 1].title)}`;
|
|
3015
3026
|
}
|
|
3016
3027
|
async function horizon(opts) {
|
|
3017
|
-
let write = opts.write ?? ((s) => process.stdout.write(s)), width = opts.width ?? 28, line = (n) => Array.from({ length: n }, (
|
|
3028
|
+
let write = opts.write ?? ((s) => process.stdout.write(s)), width = opts.width ?? 28, line = (n) => Array.from({ length: n }, (_, i) => ramp(Math.floor(i / width * RAMP.length), "━")).join("");
|
|
3018
3029
|
if (!opts.motion) {
|
|
3019
3030
|
write(` ${line(width)}
|
|
3020
3031
|
`);
|
|
@@ -3026,15 +3037,15 @@ async function horizon(opts) {
|
|
|
3026
3037
|
`);
|
|
3027
3038
|
}
|
|
3028
3039
|
function watchRows(items) {
|
|
3029
|
-
return items.map((
|
|
3040
|
+
return items.map((w) => w.how === "address" ? `${brand("◉")} ${import_picocolors3.default.bold(w.label)} ${import_picocolors3.default.dim("uptime check, every 15 minutes")}` : `${brand("○")} ${import_picocolors3.default.bold(w.label)} ${import_picocolors3.default.dim("a service in the adapter's health list")}`);
|
|
3030
3041
|
}
|
|
3031
3042
|
|
|
3032
3043
|
// src/update.ts
|
|
3033
3044
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
3034
3045
|
import path3 from "node:path";
|
|
3035
|
-
var readJson2 = (
|
|
3046
|
+
var readJson2 = (file) => {
|
|
3036
3047
|
try {
|
|
3037
|
-
return JSON.parse(readFileSync3(
|
|
3048
|
+
return JSON.parse(readFileSync3(file, "utf8"));
|
|
3038
3049
|
} catch {
|
|
3039
3050
|
return null;
|
|
3040
3051
|
}
|
|
@@ -3051,7 +3062,7 @@ function findAdapterInstalls(root) {
|
|
|
3051
3062
|
}["@lopebase/adapter"];
|
|
3052
3063
|
if (!range || range.startsWith("workspace:"))
|
|
3053
3064
|
continue;
|
|
3054
|
-
let installed = [dir, root].map((
|
|
3065
|
+
let installed = [dir, root].map((d) => readJson2(path3.join(d, "node_modules/@lopebase/adapter/package.json"))).find((p) => typeof p?.version === "string")?.version;
|
|
3055
3066
|
out.push({ dir: path3.relative(root, dir) || ".", range, installed });
|
|
3056
3067
|
}
|
|
3057
3068
|
return out;
|
|
@@ -3068,8 +3079,8 @@ async function latestOnNpm(name, timeoutMs = 1500, fetchImpl = fetch) {
|
|
|
3068
3079
|
});
|
|
3069
3080
|
if (!res.ok)
|
|
3070
3081
|
return;
|
|
3071
|
-
let
|
|
3072
|
-
return typeof
|
|
3082
|
+
let body = await res.json();
|
|
3083
|
+
return typeof body.version === "string" ? body.version : void 0;
|
|
3073
3084
|
} catch {
|
|
3074
3085
|
return;
|
|
3075
3086
|
}
|
|
@@ -3140,12 +3151,12 @@ async function checkToken(auth) {
|
|
|
3140
3151
|
});
|
|
3141
3152
|
if (res.status === 401)
|
|
3142
3153
|
return { ok: !1, message: "That token is not valid or has expired." };
|
|
3143
|
-
let
|
|
3144
|
-
return { ok: !0, products: JSON.parse(
|
|
3145
|
-
} catch (
|
|
3154
|
+
let body = await res.json();
|
|
3155
|
+
return { ok: !0, products: JSON.parse(body.result?.content?.[0]?.text ?? "[]").length };
|
|
3156
|
+
} catch (e) {
|
|
3146
3157
|
return {
|
|
3147
3158
|
ok: !1,
|
|
3148
|
-
message: `Could not reach ${auth.url} (${String(
|
|
3159
|
+
message: `Could not reach ${auth.url} (${String(e)}).`
|
|
3149
3160
|
};
|
|
3150
3161
|
}
|
|
3151
3162
|
}
|
|
@@ -3173,8 +3184,8 @@ async function login() {
|
|
|
3173
3184
|
s.start("Waiting for you to approve in the browser");
|
|
3174
3185
|
let res = await pollDeviceLogin(url, device);
|
|
3175
3186
|
if (res.ok) {
|
|
3176
|
-
let
|
|
3177
|
-
return s.stop(`Connected to ${import_picocolors4.default.bold(res.url)}. Saved to ${import_picocolors4.default.dim(
|
|
3187
|
+
let file = saveAuth({ url: res.url, token: res.token });
|
|
3188
|
+
return s.stop(`Connected to ${import_picocolors4.default.bold(res.url)}. Saved to ${import_picocolors4.default.dim(file)}`), { url: res.url, token: res.token };
|
|
3178
3189
|
}
|
|
3179
3190
|
if (s.stop(import_picocolors4.default.red(res.message)), res.reason === "denied")
|
|
3180
3191
|
bail("Nothing was connected.");
|
|
@@ -3187,7 +3198,7 @@ async function askWorkspace() {
|
|
|
3187
3198
|
return workspaceUrl(guard(await he({
|
|
3188
3199
|
message: "Your LopeBase workspace (name or address)",
|
|
3189
3200
|
placeholder: "yourteam or https://yourteam.lopebase.com",
|
|
3190
|
-
validate: (
|
|
3201
|
+
validate: (v) => workspaceUrl(v ?? "") ? void 0 : "Type your workspace name, like yourteam, or its full address"
|
|
3191
3202
|
})));
|
|
3192
3203
|
}
|
|
3193
3204
|
async function pasteLogin(url) {
|
|
@@ -3201,33 +3212,33 @@ async function pasteLogin(url) {
|
|
|
3201
3212
|
for (;; ) {
|
|
3202
3213
|
let token = guard(await ge({
|
|
3203
3214
|
message: "Paste the agent token",
|
|
3204
|
-
validate: (
|
|
3215
|
+
validate: (v) => v?.startsWith("lb_agent_") ? void 0 : "Tokens start with lb_agent_"
|
|
3205
3216
|
})).trim(), s = Y2();
|
|
3206
3217
|
s.start("Checking the token");
|
|
3207
3218
|
let check = await checkToken({ url, token });
|
|
3208
3219
|
if (check.ok) {
|
|
3209
|
-
let
|
|
3210
|
-
return s.stop(`Signed in. ${check.products} ${check.products === 1 ? "property" : "properties"} in this workspace. Saved to ${import_picocolors4.default.dim(
|
|
3220
|
+
let file = saveAuth({ url, token });
|
|
3221
|
+
return s.stop(`Signed in. ${check.products} ${check.products === 1 ? "property" : "properties"} in this workspace. Saved to ${import_picocolors4.default.dim(file)}`), { url, token };
|
|
3211
3222
|
}
|
|
3212
3223
|
s.stop(import_picocolors4.default.red(check.message ?? "That did not work."));
|
|
3213
3224
|
}
|
|
3214
3225
|
}
|
|
3215
|
-
async function printDetection(
|
|
3216
|
-
Me(stackRows(
|
|
3226
|
+
async function printDetection(d, facts) {
|
|
3227
|
+
Me(stackRows(d, facts).join(`
|
|
3217
3228
|
`), "Your stack"), await pace(motion, 150);
|
|
3218
|
-
let found =
|
|
3229
|
+
let found = d.sources.filter((s) => s.status === "found");
|
|
3219
3230
|
if (found.length)
|
|
3220
3231
|
Me(found.map((s) => `${import_picocolors4.default.green("●")} ${import_picocolors4.default.bold(s.label)} ${import_picocolors4.default.dim(s.evidence.join(", "))}`).join(`
|
|
3221
3232
|
`), "Already in your code, ready to connect"), await pace(motion, 150);
|
|
3222
|
-
let possible =
|
|
3233
|
+
let possible = d.sources.filter((s) => s.status === "possible");
|
|
3223
3234
|
if (possible.length)
|
|
3224
3235
|
Me(possible.map((s) => `${import_picocolors4.default.yellow("?")} ${import_picocolors4.default.bold(s.label)} ${import_picocolors4.default.dim(`only ${s.evidence.join(", ")}`)}`).join(`
|
|
3225
3236
|
`), "Maybe in use, your agent will check"), await pace(motion, 150);
|
|
3226
|
-
let watch = watchList(
|
|
3237
|
+
let watch = watchList(d, facts);
|
|
3227
3238
|
if (watch.length)
|
|
3228
3239
|
Me(watchRows(watch).join(`
|
|
3229
3240
|
`), "Worth watching for uptime"), await pace(motion, 150);
|
|
3230
|
-
for (let gap of
|
|
3241
|
+
for (let gap of d.gaps)
|
|
3231
3242
|
M2.info(import_picocolors4.default.dim(gap));
|
|
3232
3243
|
}
|
|
3233
3244
|
async function scanWithProgress() {
|
|
@@ -3289,7 +3300,7 @@ async function init() {
|
|
|
3289
3300
|
label: src.status === "found" ? src.label : src.status === "possible" ? `${src.label} ${import_picocolors4.default.dim("(maybe in use, we'll check)")}` : `${src.label} ${import_picocolors4.default.dim("(not set up yet, we'll help)")}`,
|
|
3290
3301
|
hint: src.why
|
|
3291
3302
|
})),
|
|
3292
|
-
...watchList(detection, facts).some((
|
|
3303
|
+
...watchList(detection, facts).some((w) => w.how === "address") ? [
|
|
3293
3304
|
{
|
|
3294
3305
|
value: PAGEVIEWS,
|
|
3295
3306
|
label: `${PAGEVIEWS} ${import_picocolors4.default.dim("(one tag, no cookies)")}`,
|
|
@@ -3313,7 +3324,7 @@ async function init() {
|
|
|
3313
3324
|
`${import_picocolors4.default.bold(agent)} will now:`,
|
|
3314
3325
|
` ${brand("1.")} add ${import_picocolors4.default.bold(productName || "this product")} to your workspace`,
|
|
3315
3326
|
` ${brand("2.")} connect ${chosen.length ? chosen.join(", ") : "what it recommends"}`,
|
|
3316
|
-
` ${brand("3.")} pick what to watch for uptime: ${watchList(detection, facts).map((
|
|
3327
|
+
` ${brand("3.")} pick what to watch for uptime: ${watchList(detection, facts).map((w) => w.label).join(", ") || "the site"}`,
|
|
3317
3328
|
` ${brand("4.")} stop and ask you for any sign-in, key, or yes`,
|
|
3318
3329
|
"",
|
|
3319
3330
|
import_picocolors4.default.dim("You can follow along in your workspace as each one turns green.")
|
|
@@ -3351,7 +3362,7 @@ async function handOff(prompt, plan) {
|
|
|
3351
3362
|
stdio: "inherit",
|
|
3352
3363
|
cwd
|
|
3353
3364
|
});
|
|
3354
|
-
child.on("error", (
|
|
3365
|
+
child.on("error", (e) => bail(`Could not start ${agent.label}: ${e.message}`)), child.on("exit", (code) => process.exit(code ?? 0));
|
|
3355
3366
|
}
|
|
3356
3367
|
async function noticeNewerCli() {
|
|
3357
3368
|
let mine = version(), latest = await latestOnNpm("lopebase");
|
|
@@ -3377,11 +3388,11 @@ async function update() {
|
|
|
3377
3388
|
let latest = npmLatest && isBehind(ADAPTER_VERSION, npmLatest) ? npmLatest : ADAPTER_VERSION, behind = installs.filter((i) => isBehind(runningVersion(i), latest));
|
|
3378
3389
|
if (s.stop(installs.map((i) => `${i.dir === "." ? "This folder" : i.dir} runs ${import_picocolors4.default.bold(runningVersion(i))}`).join(", ")), !behind.length)
|
|
3379
3390
|
return Se(`Up to date with ${import_picocolors4.default.bold(latest)}.`);
|
|
3380
|
-
let from = behind.map(runningVersion).sort((a,
|
|
3381
|
-
if (Me(
|
|
3382
|
-
`${brand("◆")} ${import_picocolors4.default.bold(
|
|
3383
|
-
...
|
|
3384
|
-
...(
|
|
3391
|
+
let from = behind.map(runningVersion).sort((a, b) => isBehind(a, b) ? -1 : 1)[0], releases = releasesSince(from);
|
|
3392
|
+
if (Me(releases.flatMap((r) => [
|
|
3393
|
+
`${brand("◆")} ${import_picocolors4.default.bold(r.version)} ${import_picocolors4.default.dim(r.date)}`,
|
|
3394
|
+
...r.features.map((f) => ` ${f}`),
|
|
3395
|
+
...(r.breaking ?? []).map((b) => ` ${import_picocolors4.default.yellow("!")} ${b}`)
|
|
3385
3396
|
]).join(`
|
|
3386
3397
|
`), `New since ${from}`), npmLatest && isBehind(ADAPTER_VERSION, npmLatest))
|
|
3387
3398
|
M2.warn(`npm has ${npmLatest}, newer than these notes. Run ${brand("npx lopebase@latest update")} for its steps.`);
|
|
@@ -3433,7 +3444,7 @@ async function main() {
|
|
|
3433
3444
|
baseUrl: rest[1],
|
|
3434
3445
|
secret,
|
|
3435
3446
|
token: secret ? void 0 : token,
|
|
3436
|
-
log: (
|
|
3447
|
+
log: (l) => console.log(l.startsWith("FAIL") ? import_picocolors4.default.red(l) : import_picocolors4.default.green(l))
|
|
3437
3448
|
});
|
|
3438
3449
|
console.log(res.failed.length ? import_picocolors4.default.red(`${res.failed.length} failed, ${res.passed} passed`) : import_picocolors4.default.green(`All ${res.passed} checks passed. Ready to connect.`)), process.exit(res.failed.length ? 1 : 0);
|
|
3439
3450
|
}
|
package/package.json
CHANGED