@freecodecamp/universe-cli 0.7.2 → 0.8.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 +13 -0
- package/dist/index.cjs +1086 -76
- package/dist/index.js +882 -28
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2434,8 +2434,8 @@ var require_stringifyNumber = __commonJS({
|
|
|
2434
2434
|
i = n.length;
|
|
2435
2435
|
n += ".";
|
|
2436
2436
|
}
|
|
2437
|
-
let
|
|
2438
|
-
while (
|
|
2437
|
+
let d3 = minFractionDigits - (n.length - i - 1);
|
|
2438
|
+
while (d3-- > 0)
|
|
2439
2439
|
n += "0";
|
|
2440
2440
|
}
|
|
2441
2441
|
return n;
|
|
@@ -3174,10 +3174,10 @@ var require_timestamp = __commonJS({
|
|
|
3174
3174
|
let date5 = Date.UTC(year, month - 1, day, hour || 0, minute || 0, second || 0, millisec);
|
|
3175
3175
|
const tz = match[8];
|
|
3176
3176
|
if (tz && tz !== "Z") {
|
|
3177
|
-
let
|
|
3178
|
-
if (Math.abs(
|
|
3179
|
-
|
|
3180
|
-
date5 -= 6e4 *
|
|
3177
|
+
let d3 = parseSexagesimal(tz, false);
|
|
3178
|
+
if (Math.abs(d3) < 30)
|
|
3179
|
+
d3 *= 60;
|
|
3180
|
+
date5 -= 6e4 * d3;
|
|
3181
3181
|
}
|
|
3182
3182
|
return new Date(date5);
|
|
3183
3183
|
},
|
|
@@ -4702,12 +4702,12 @@ var require_resolve_flow_scalar = __commonJS({
|
|
|
4702
4702
|
};
|
|
4703
4703
|
}
|
|
4704
4704
|
const valueEnd = offset + source.length;
|
|
4705
|
-
const
|
|
4705
|
+
const re2 = resolveEnd.resolveEnd(end, valueEnd, strict, onError);
|
|
4706
4706
|
return {
|
|
4707
4707
|
value,
|
|
4708
4708
|
type: _type,
|
|
4709
|
-
comment:
|
|
4710
|
-
range: [offset, valueEnd,
|
|
4709
|
+
comment: re2.comment,
|
|
4710
|
+
range: [offset, valueEnd, re2.offset]
|
|
4711
4711
|
};
|
|
4712
4712
|
}
|
|
4713
4713
|
function plainValue(source, onError) {
|
|
@@ -5092,10 +5092,10 @@ var require_compose_node = __commonJS({
|
|
|
5092
5092
|
if (alias.source.endsWith(":"))
|
|
5093
5093
|
onError(offset + source.length - 1, "BAD_ALIAS", "Alias ending in : is ambiguous", true);
|
|
5094
5094
|
const valueEnd = offset + source.length;
|
|
5095
|
-
const
|
|
5096
|
-
alias.range = [offset, valueEnd,
|
|
5097
|
-
if (
|
|
5098
|
-
alias.comment =
|
|
5095
|
+
const re2 = resolveEnd.resolveEnd(end, valueEnd, options.strict, onError);
|
|
5096
|
+
alias.range = [offset, valueEnd, re2.offset];
|
|
5097
|
+
if (re2.comment)
|
|
5098
|
+
alias.comment = re2.comment;
|
|
5099
5099
|
return alias;
|
|
5100
5100
|
}
|
|
5101
5101
|
exports2.composeEmptyNode = composeEmptyNode;
|
|
@@ -5136,10 +5136,10 @@ var require_compose_doc = __commonJS({
|
|
|
5136
5136
|
}
|
|
5137
5137
|
doc.contents = value ? composeNode.composeNode(ctx, value, props, onError) : composeNode.composeEmptyNode(ctx, props.end, start, null, props, onError);
|
|
5138
5138
|
const contentEnd = doc.contents.range[2];
|
|
5139
|
-
const
|
|
5140
|
-
if (
|
|
5141
|
-
doc.comment =
|
|
5142
|
-
doc.range = [offset, contentEnd,
|
|
5139
|
+
const re2 = resolveEnd.resolveEnd(end, contentEnd, false, onError);
|
|
5140
|
+
if (re2.comment)
|
|
5141
|
+
doc.comment = re2.comment;
|
|
5142
|
+
doc.range = [offset, contentEnd, re2.offset];
|
|
5143
5143
|
return doc;
|
|
5144
5144
|
}
|
|
5145
5145
|
exports2.composeDoc = composeDoc;
|
|
@@ -8396,6 +8396,11 @@ function wrapAnsi(string4, columns, options) {
|
|
|
8396
8396
|
// node_modules/.pnpm/@clack+core@1.2.0/node_modules/@clack/core/dist/index.mjs
|
|
8397
8397
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
8398
8398
|
var import_node_tty = require("tty");
|
|
8399
|
+
function d(r, t2, e) {
|
|
8400
|
+
if (!e.some((o) => !o.disabled)) return r;
|
|
8401
|
+
const s = r + t2, i = Math.max(e.length - 1, 0), n = s < 0 ? i : s > i ? 0 : s;
|
|
8402
|
+
return e[n].disabled ? d(n, t2 < 0 ? -1 : 1, e) : n;
|
|
8403
|
+
}
|
|
8399
8404
|
var E = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
8400
8405
|
var G = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
8401
8406
|
var u = { actions: new Set(E), aliases: /* @__PURE__ */ new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["", "cancel"], ["escape", "cancel"]]), messages: { cancel: "Canceled", error: "Something went wrong" }, withGuide: true, date: { monthNames: [...G], messages: { required: "Please enter a valid date", invalidMonth: "There are only 12 months in a year", invalidDay: (r, t2) => `There are only ${r} days in ${t2}`, afterMin: (r) => `Date must be on or after ${r.toISOString().slice(0, 10)}`, beforeMax: (r) => `Date must be on or before ${r.toISOString().slice(0, 10)}` } } };
|
|
@@ -8589,6 +8594,52 @@ var Q = class extends p {
|
|
|
8589
8594
|
});
|
|
8590
8595
|
}
|
|
8591
8596
|
};
|
|
8597
|
+
var nt = class extends p {
|
|
8598
|
+
options;
|
|
8599
|
+
cursor = 0;
|
|
8600
|
+
get _selectedValue() {
|
|
8601
|
+
return this.options[this.cursor];
|
|
8602
|
+
}
|
|
8603
|
+
changeValue() {
|
|
8604
|
+
this.value = this._selectedValue.value;
|
|
8605
|
+
}
|
|
8606
|
+
constructor(t2) {
|
|
8607
|
+
super(t2, false), this.options = t2.options;
|
|
8608
|
+
const e = this.options.findIndex(({ value: i }) => i === t2.initialValue), s = e === -1 ? 0 : e;
|
|
8609
|
+
this.cursor = this.options[s].disabled ? d(s, 1, this.options) : s, this.changeValue(), this.on("cursor", (i) => {
|
|
8610
|
+
switch (i) {
|
|
8611
|
+
case "left":
|
|
8612
|
+
case "up":
|
|
8613
|
+
this.cursor = d(this.cursor, -1, this.options);
|
|
8614
|
+
break;
|
|
8615
|
+
case "down":
|
|
8616
|
+
case "right":
|
|
8617
|
+
this.cursor = d(this.cursor, 1, this.options);
|
|
8618
|
+
break;
|
|
8619
|
+
}
|
|
8620
|
+
this.changeValue();
|
|
8621
|
+
});
|
|
8622
|
+
}
|
|
8623
|
+
};
|
|
8624
|
+
var at = class extends p {
|
|
8625
|
+
get userInputWithCursor() {
|
|
8626
|
+
if (this.state === "submit") return this.userInput;
|
|
8627
|
+
const t2 = this.userInput;
|
|
8628
|
+
if (this.cursor >= t2.length) return `${this.userInput}\u2588`;
|
|
8629
|
+
const e = t2.slice(0, this.cursor), [s, ...i] = t2.slice(this.cursor);
|
|
8630
|
+
return `${e}${(0, import_node_util.styleText)("inverse", s)}${i.join("")}`;
|
|
8631
|
+
}
|
|
8632
|
+
get cursor() {
|
|
8633
|
+
return this._cursor;
|
|
8634
|
+
}
|
|
8635
|
+
constructor(t2) {
|
|
8636
|
+
super({ ...t2, initialUserInput: t2.initialUserInput ?? t2.initialValue }), this.on("userInput", (e) => {
|
|
8637
|
+
this._setValue(e);
|
|
8638
|
+
}), this.on("finalize", () => {
|
|
8639
|
+
this.value || (this.value = t2.defaultValue), this.value === void 0 && (this.value = "");
|
|
8640
|
+
});
|
|
8641
|
+
}
|
|
8642
|
+
};
|
|
8592
8643
|
|
|
8593
8644
|
// node_modules/.pnpm/@clack+prompts@1.2.0/node_modules/@clack/prompts/dist/index.mjs
|
|
8594
8645
|
var import_node_util2 = require("util");
|
|
@@ -8607,7 +8658,7 @@ var oe = w2("\u25A0", "x");
|
|
|
8607
8658
|
var ue = w2("\u25B2", "x");
|
|
8608
8659
|
var F = w2("\u25C7", "o");
|
|
8609
8660
|
var le = w2("\u250C", "T");
|
|
8610
|
-
var
|
|
8661
|
+
var d2 = w2("\u2502", "|");
|
|
8611
8662
|
var E2 = w2("\u2514", "\u2014");
|
|
8612
8663
|
var Ie = w2("\u2510", "T");
|
|
8613
8664
|
var Ee = w2("\u2518", "\u2014");
|
|
@@ -8640,26 +8691,71 @@ var V2 = (e) => {
|
|
|
8640
8691
|
return (0, import_node_util2.styleText)("green", F);
|
|
8641
8692
|
}
|
|
8642
8693
|
};
|
|
8694
|
+
var ye = (e) => {
|
|
8695
|
+
switch (e) {
|
|
8696
|
+
case "initial":
|
|
8697
|
+
case "active":
|
|
8698
|
+
return (0, import_node_util2.styleText)("cyan", d2);
|
|
8699
|
+
case "cancel":
|
|
8700
|
+
return (0, import_node_util2.styleText)("red", d2);
|
|
8701
|
+
case "error":
|
|
8702
|
+
return (0, import_node_util2.styleText)("yellow", d2);
|
|
8703
|
+
case "submit":
|
|
8704
|
+
return (0, import_node_util2.styleText)("green", d2);
|
|
8705
|
+
}
|
|
8706
|
+
};
|
|
8707
|
+
var et2 = (e, i, s, r, u2) => {
|
|
8708
|
+
let n = i, o = 0;
|
|
8709
|
+
for (let c2 = s; c2 < r; c2++) {
|
|
8710
|
+
const a = e[c2];
|
|
8711
|
+
if (n = n - a.length, o++, n <= u2) break;
|
|
8712
|
+
}
|
|
8713
|
+
return { lineCount: n, removals: o };
|
|
8714
|
+
};
|
|
8715
|
+
var Y2 = ({ cursor: e, options: i, style: s, output: r = process.stdout, maxItems: u2 = Number.POSITIVE_INFINITY, columnPadding: n = 0, rowPadding: o = 4 }) => {
|
|
8716
|
+
const c2 = O(r) - n, a = A(r), l = (0, import_node_util2.styleText)("dim", "..."), $2 = Math.max(a - o, 0), y2 = Math.max(Math.min(u2, $2), 5);
|
|
8717
|
+
let p2 = 0;
|
|
8718
|
+
e >= y2 - 3 && (p2 = Math.max(Math.min(e - y2 + 3, i.length - y2), 0));
|
|
8719
|
+
let m = y2 < i.length && p2 > 0, g = y2 < i.length && p2 + y2 < i.length;
|
|
8720
|
+
const S2 = Math.min(p2 + y2, i.length), h = [];
|
|
8721
|
+
let f = 0;
|
|
8722
|
+
m && f++, g && f++;
|
|
8723
|
+
const v = p2 + (m ? 1 : 0), T = S2 - (g ? 1 : 0);
|
|
8724
|
+
for (let b = v; b < T; b++) {
|
|
8725
|
+
const x = wrapAnsi(s(i[b], b === e), c2, { hard: true, trim: false }).split(`
|
|
8726
|
+
`);
|
|
8727
|
+
h.push(x), f += x.length;
|
|
8728
|
+
}
|
|
8729
|
+
if (f > $2) {
|
|
8730
|
+
let b = 0, x = 0, G2 = f;
|
|
8731
|
+
const M2 = e - v, R2 = (j2, D2) => et2(h, G2, j2, D2, $2);
|
|
8732
|
+
m ? ({ lineCount: G2, removals: b } = R2(0, M2), G2 > $2 && ({ lineCount: G2, removals: x } = R2(M2 + 1, h.length))) : ({ lineCount: G2, removals: x } = R2(M2 + 1, h.length), G2 > $2 && ({ lineCount: G2, removals: b } = R2(0, M2))), b > 0 && (m = true, h.splice(0, b)), x > 0 && (g = true, h.splice(h.length - x, x));
|
|
8733
|
+
}
|
|
8734
|
+
const C2 = [];
|
|
8735
|
+
m && C2.push(l);
|
|
8736
|
+
for (const b of h) for (const x of b) C2.push(x);
|
|
8737
|
+
return g && C2.push(l), C2;
|
|
8738
|
+
};
|
|
8643
8739
|
var ot2 = (e) => {
|
|
8644
8740
|
const i = e.active ?? "Yes", s = e.inactive ?? "No";
|
|
8645
8741
|
return new Q({ active: i, inactive: s, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue ?? true, render() {
|
|
8646
|
-
const r = e.withGuide ?? u.withGuide, u2 = `${V2(this.state)} `, n = r ? `${(0, import_node_util2.styleText)("gray",
|
|
8742
|
+
const r = e.withGuide ?? u.withGuide, u2 = `${V2(this.state)} `, n = r ? `${(0, import_node_util2.styleText)("gray", d2)} ` : "", o = R(e.output, e.message, n, u2), c2 = `${r ? `${(0, import_node_util2.styleText)("gray", d2)}
|
|
8647
8743
|
` : ""}${o}
|
|
8648
8744
|
`, a = this.value ? i : s;
|
|
8649
8745
|
switch (this.state) {
|
|
8650
8746
|
case "submit": {
|
|
8651
|
-
const l = r ? `${(0, import_node_util2.styleText)("gray",
|
|
8747
|
+
const l = r ? `${(0, import_node_util2.styleText)("gray", d2)} ` : "";
|
|
8652
8748
|
return `${c2}${l}${(0, import_node_util2.styleText)("dim", a)}`;
|
|
8653
8749
|
}
|
|
8654
8750
|
case "cancel": {
|
|
8655
|
-
const l = r ? `${(0, import_node_util2.styleText)("gray",
|
|
8751
|
+
const l = r ? `${(0, import_node_util2.styleText)("gray", d2)} ` : "";
|
|
8656
8752
|
return `${c2}${l}${(0, import_node_util2.styleText)(["strikethrough", "dim"], a)}${r ? `
|
|
8657
|
-
${(0, import_node_util2.styleText)("gray",
|
|
8753
|
+
${(0, import_node_util2.styleText)("gray", d2)}` : ""}`;
|
|
8658
8754
|
}
|
|
8659
8755
|
default: {
|
|
8660
|
-
const l = r ? `${(0, import_node_util2.styleText)("cyan",
|
|
8756
|
+
const l = r ? `${(0, import_node_util2.styleText)("cyan", d2)} ` : "", $2 = r ? (0, import_node_util2.styleText)("cyan", E2) : "";
|
|
8661
8757
|
return `${c2}${l}${this.value ? `${(0, import_node_util2.styleText)("green", z2)} ${i}` : `${(0, import_node_util2.styleText)("dim", H2)} ${(0, import_node_util2.styleText)("dim", i)}`}${e.vertical ? r ? `
|
|
8662
|
-
${(0, import_node_util2.styleText)("cyan",
|
|
8758
|
+
${(0, import_node_util2.styleText)("cyan", d2)} ` : `
|
|
8663
8759
|
` : ` ${(0, import_node_util2.styleText)("dim", "/")} `}${this.value ? `${(0, import_node_util2.styleText)("dim", H2)} ${(0, import_node_util2.styleText)("dim", s)}` : `${(0, import_node_util2.styleText)("green", z2)} ${s}`}
|
|
8664
8760
|
${$2}
|
|
8665
8761
|
`;
|
|
@@ -8667,7 +8763,7 @@ ${$2}
|
|
|
8667
8763
|
}
|
|
8668
8764
|
} }).prompt();
|
|
8669
8765
|
};
|
|
8670
|
-
var O2 = { message: (e = [], { symbol: i = (0, import_node_util2.styleText)("gray",
|
|
8766
|
+
var O2 = { message: (e = [], { symbol: i = (0, import_node_util2.styleText)("gray", d2), secondarySymbol: s = (0, import_node_util2.styleText)("gray", d2), output: r = process.stdout, spacing: u2 = 1, withGuide: n } = {}) => {
|
|
8671
8767
|
const o = [], c2 = n ?? u.withGuide, a = c2 ? s : "", l = c2 ? `${i} ` : "", $2 = c2 ? `${s} ` : "";
|
|
8672
8768
|
for (let p2 = 0; p2 < u2; p2++) o.push(a);
|
|
8673
8769
|
const y2 = Array.isArray(e) ? e : e.split(`
|
|
@@ -8715,7 +8811,7 @@ var fe = ({ indicator: e = "dots", onCancel: i, output: s = process.stdout, canc
|
|
|
8715
8811
|
const A2 = (performance.now() - _2) / 1e3, k = Math.floor(A2 / 60), L = Math.floor(A2 % 60);
|
|
8716
8812
|
return k > 0 ? `[${k}m ${L}s]` : `[${L}s]`;
|
|
8717
8813
|
}, D2 = a.withGuide ?? u.withGuide, ie = (_2 = "") => {
|
|
8718
|
-
p2 = true, $2 = z({ output: s }), g = R2(_2), h = performance.now(), D2 && s.write(`${(0, import_node_util2.styleText)("gray",
|
|
8814
|
+
p2 = true, $2 = z({ output: s }), g = R2(_2), h = performance.now(), D2 && s.write(`${(0, import_node_util2.styleText)("gray", d2)}
|
|
8719
8815
|
`);
|
|
8720
8816
|
let A2 = 0, k = 0;
|
|
8721
8817
|
x(), y2 = setInterval(() => {
|
|
@@ -8747,7 +8843,81 @@ var fe = ({ indicator: e = "dots", onCancel: i, output: s = process.stdout, canc
|
|
|
8747
8843
|
} };
|
|
8748
8844
|
};
|
|
8749
8845
|
var Ve = { light: w2("\u2500", "-"), heavy: w2("\u2501", "="), block: w2("\u2588", "#") };
|
|
8750
|
-
var
|
|
8846
|
+
var re = (e, i) => e.includes(`
|
|
8847
|
+
`) ? e.split(`
|
|
8848
|
+
`).map((s) => i(s)).join(`
|
|
8849
|
+
`) : i(e);
|
|
8850
|
+
var _t = (e) => {
|
|
8851
|
+
const i = (s, r) => {
|
|
8852
|
+
const u2 = s.label ?? String(s.value);
|
|
8853
|
+
switch (r) {
|
|
8854
|
+
case "disabled":
|
|
8855
|
+
return `${(0, import_node_util2.styleText)("gray", H2)} ${re(u2, (n) => (0, import_node_util2.styleText)("gray", n))}${s.hint ? ` ${(0, import_node_util2.styleText)("dim", `(${s.hint ?? "disabled"})`)}` : ""}`;
|
|
8856
|
+
case "selected":
|
|
8857
|
+
return `${re(u2, (n) => (0, import_node_util2.styleText)("dim", n))}`;
|
|
8858
|
+
case "active":
|
|
8859
|
+
return `${(0, import_node_util2.styleText)("green", z2)} ${u2}${s.hint ? ` ${(0, import_node_util2.styleText)("dim", `(${s.hint})`)}` : ""}`;
|
|
8860
|
+
case "cancelled":
|
|
8861
|
+
return `${re(u2, (n) => (0, import_node_util2.styleText)(["strikethrough", "dim"], n))}`;
|
|
8862
|
+
default:
|
|
8863
|
+
return `${(0, import_node_util2.styleText)("dim", H2)} ${re(u2, (n) => (0, import_node_util2.styleText)("dim", n))}`;
|
|
8864
|
+
}
|
|
8865
|
+
};
|
|
8866
|
+
return new nt({ options: e.options, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue, render() {
|
|
8867
|
+
const s = e.withGuide ?? u.withGuide, r = `${V2(this.state)} `, u2 = `${ye(this.state)} `, n = R(e.output, e.message, u2, r), o = `${s ? `${(0, import_node_util2.styleText)("gray", d2)}
|
|
8868
|
+
` : ""}${n}
|
|
8869
|
+
`;
|
|
8870
|
+
switch (this.state) {
|
|
8871
|
+
case "submit": {
|
|
8872
|
+
const c2 = s ? `${(0, import_node_util2.styleText)("gray", d2)} ` : "", a = R(e.output, i(this.options[this.cursor], "selected"), c2);
|
|
8873
|
+
return `${o}${a}`;
|
|
8874
|
+
}
|
|
8875
|
+
case "cancel": {
|
|
8876
|
+
const c2 = s ? `${(0, import_node_util2.styleText)("gray", d2)} ` : "", a = R(e.output, i(this.options[this.cursor], "cancelled"), c2);
|
|
8877
|
+
return `${o}${a}${s ? `
|
|
8878
|
+
${(0, import_node_util2.styleText)("gray", d2)}` : ""}`;
|
|
8879
|
+
}
|
|
8880
|
+
default: {
|
|
8881
|
+
const c2 = s ? `${(0, import_node_util2.styleText)("cyan", d2)} ` : "", a = s ? (0, import_node_util2.styleText)("cyan", E2) : "", l = o.split(`
|
|
8882
|
+
`).length, $2 = s ? 2 : 1;
|
|
8883
|
+
return `${o}${c2}${Y2({ output: e.output, cursor: this.cursor, options: this.options, maxItems: e.maxItems, columnPadding: c2.length, rowPadding: l + $2, style: (y2, p2) => i(y2, y2.disabled ? "disabled" : p2 ? "active" : "inactive") }).join(`
|
|
8884
|
+
${c2}`)}
|
|
8885
|
+
${a}
|
|
8886
|
+
`;
|
|
8887
|
+
}
|
|
8888
|
+
}
|
|
8889
|
+
} }).prompt();
|
|
8890
|
+
};
|
|
8891
|
+
var je = `${(0, import_node_util2.styleText)("gray", d2)} `;
|
|
8892
|
+
var Ot = (e) => new at({ validate: e.validate, placeholder: e.placeholder, defaultValue: e.defaultValue, initialValue: e.initialValue, output: e.output, signal: e.signal, input: e.input, render() {
|
|
8893
|
+
const i = e?.withGuide ?? u.withGuide, s = `${`${i ? `${(0, import_node_util2.styleText)("gray", d2)}
|
|
8894
|
+
` : ""}${V2(this.state)} `}${e.message}
|
|
8895
|
+
`, r = e.placeholder ? (0, import_node_util2.styleText)("inverse", e.placeholder[0]) + (0, import_node_util2.styleText)("dim", e.placeholder.slice(1)) : (0, import_node_util2.styleText)(["inverse", "hidden"], "_"), u2 = this.userInput ? this.userInputWithCursor : r, n = this.value ?? "";
|
|
8896
|
+
switch (this.state) {
|
|
8897
|
+
case "error": {
|
|
8898
|
+
const o = this.error ? ` ${(0, import_node_util2.styleText)("yellow", this.error)}` : "", c2 = i ? `${(0, import_node_util2.styleText)("yellow", d2)} ` : "", a = i ? (0, import_node_util2.styleText)("yellow", E2) : "";
|
|
8899
|
+
return `${s.trim()}
|
|
8900
|
+
${c2}${u2}
|
|
8901
|
+
${a}${o}
|
|
8902
|
+
`;
|
|
8903
|
+
}
|
|
8904
|
+
case "submit": {
|
|
8905
|
+
const o = n ? ` ${(0, import_node_util2.styleText)("dim", n)}` : "", c2 = i ? (0, import_node_util2.styleText)("gray", d2) : "";
|
|
8906
|
+
return `${s}${c2}${o}`;
|
|
8907
|
+
}
|
|
8908
|
+
case "cancel": {
|
|
8909
|
+
const o = n ? ` ${(0, import_node_util2.styleText)(["strikethrough", "dim"], n)}` : "", c2 = i ? (0, import_node_util2.styleText)("gray", d2) : "";
|
|
8910
|
+
return `${s}${c2}${o}${n.trim() ? `
|
|
8911
|
+
${c2}` : ""}`;
|
|
8912
|
+
}
|
|
8913
|
+
default: {
|
|
8914
|
+
const o = i ? `${(0, import_node_util2.styleText)("cyan", d2)} ` : "", c2 = i ? (0, import_node_util2.styleText)("cyan", E2) : "";
|
|
8915
|
+
return `${s}${o}${u2}
|
|
8916
|
+
${c2}
|
|
8917
|
+
`;
|
|
8918
|
+
}
|
|
8919
|
+
}
|
|
8920
|
+
} }).prompt();
|
|
8751
8921
|
|
|
8752
8922
|
// src/output/exit-codes.ts
|
|
8753
8923
|
var EXIT_USAGE = 10;
|
|
@@ -8780,6 +8950,9 @@ var StorageError = class extends CliError {
|
|
|
8780
8950
|
var GitError = class extends CliError {
|
|
8781
8951
|
exitCode = EXIT_GIT;
|
|
8782
8952
|
};
|
|
8953
|
+
var ConfirmError = class extends CliError {
|
|
8954
|
+
exitCode = EXIT_CONFIRM;
|
|
8955
|
+
};
|
|
8783
8956
|
var PartialUploadError = class extends CliError {
|
|
8784
8957
|
exitCode = EXIT_PARTIAL;
|
|
8785
8958
|
};
|
|
@@ -8792,8 +8965,8 @@ var import_node_child_process = require("child_process");
|
|
|
8792
8965
|
function getGitState() {
|
|
8793
8966
|
try {
|
|
8794
8967
|
const hash2 = (0, import_node_child_process.execSync)("git rev-parse HEAD", { encoding: "utf-8" }).trim();
|
|
8795
|
-
const
|
|
8796
|
-
return { hash: hash2, dirty:
|
|
8968
|
+
const status2 = (0, import_node_child_process.execSync)("git status --porcelain", { encoding: "utf-8" });
|
|
8969
|
+
return { hash: hash2, dirty: status2.length > 0 };
|
|
8797
8970
|
} catch {
|
|
8798
8971
|
return { hash: null, dirty: false, error: "not a git repository" };
|
|
8799
8972
|
}
|
|
@@ -8842,13 +9015,13 @@ var import_node_child_process2 = require("child_process");
|
|
|
8842
9015
|
var import_promises = require("fs/promises");
|
|
8843
9016
|
var import_node_path3 = require("path");
|
|
8844
9017
|
var defaultExec = async (req) => {
|
|
8845
|
-
return new Promise((resolveExit,
|
|
9018
|
+
return new Promise((resolveExit, reject2) => {
|
|
8846
9019
|
const child = (0, import_node_child_process2.spawn)(req.command, {
|
|
8847
9020
|
cwd: req.cwd,
|
|
8848
9021
|
shell: true,
|
|
8849
9022
|
stdio: "inherit"
|
|
8850
9023
|
});
|
|
8851
|
-
child.on("error", (err) =>
|
|
9024
|
+
child.on("error", (err) => reject2(err));
|
|
8852
9025
|
child.on("exit", (code) => resolveExit(code ?? 1));
|
|
8853
9026
|
});
|
|
8854
9027
|
};
|
|
@@ -9005,15 +9178,15 @@ function compilePattern(pattern) {
|
|
|
9005
9178
|
const anchored = pattern.includes("/");
|
|
9006
9179
|
const body = globToRegexBody(pattern);
|
|
9007
9180
|
if (anchored) {
|
|
9008
|
-
const
|
|
9009
|
-
return { test: (rel) =>
|
|
9181
|
+
const re3 = new RegExp(`^${body}$`);
|
|
9182
|
+
return { test: (rel) => re3.test(rel) };
|
|
9010
9183
|
}
|
|
9011
|
-
const
|
|
9184
|
+
const re2 = new RegExp(`^${body}$`);
|
|
9012
9185
|
return {
|
|
9013
9186
|
test: (rel) => {
|
|
9014
9187
|
const idx = rel.lastIndexOf("/");
|
|
9015
9188
|
const base = idx === -1 ? rel : rel.slice(idx + 1);
|
|
9016
|
-
return
|
|
9189
|
+
return re2.test(base);
|
|
9017
9190
|
}
|
|
9018
9191
|
};
|
|
9019
9192
|
}
|
|
@@ -22895,26 +23068,26 @@ function editDistance(a, b) {
|
|
|
22895
23068
|
const n = b.length;
|
|
22896
23069
|
if (m === 0) return n;
|
|
22897
23070
|
if (n === 0) return m;
|
|
22898
|
-
const
|
|
23071
|
+
const d3 = Array.from(
|
|
22899
23072
|
{ length: m + 1 },
|
|
22900
23073
|
() => new Array(n + 1).fill(0)
|
|
22901
23074
|
);
|
|
22902
|
-
for (let i = 0; i <= m; i++)
|
|
22903
|
-
for (let j2 = 0; j2 <= n; j2++)
|
|
23075
|
+
for (let i = 0; i <= m; i++) d3[i][0] = i;
|
|
23076
|
+
for (let j2 = 0; j2 <= n; j2++) d3[0][j2] = j2;
|
|
22904
23077
|
for (let i = 1; i <= m; i++) {
|
|
22905
23078
|
for (let j2 = 1; j2 <= n; j2++) {
|
|
22906
23079
|
const cost = a[i - 1] === b[j2 - 1] ? 0 : 1;
|
|
22907
|
-
|
|
22908
|
-
|
|
22909
|
-
|
|
22910
|
-
|
|
23080
|
+
d3[i][j2] = Math.min(
|
|
23081
|
+
d3[i - 1][j2] + 1,
|
|
23082
|
+
d3[i][j2 - 1] + 1,
|
|
23083
|
+
d3[i - 1][j2 - 1] + cost
|
|
22911
23084
|
);
|
|
22912
23085
|
if (i > 1 && j2 > 1 && a[i - 1] === b[j2 - 2] && a[i - 2] === b[j2 - 1]) {
|
|
22913
|
-
|
|
23086
|
+
d3[i][j2] = Math.min(d3[i][j2], d3[i - 2][j2 - 2] + 1);
|
|
22914
23087
|
}
|
|
22915
23088
|
}
|
|
22916
23089
|
}
|
|
22917
|
-
return
|
|
23090
|
+
return d3[m][n];
|
|
22918
23091
|
}
|
|
22919
23092
|
function suggest(target, candidates, threshold = 2) {
|
|
22920
23093
|
if (candidates.length === 0) return null;
|
|
@@ -22927,15 +23100,60 @@ function suggest(target, candidates, threshold = 2) {
|
|
|
22927
23100
|
let best = null;
|
|
22928
23101
|
let bestD = threshold + 1;
|
|
22929
23102
|
for (const c2 of candidates) {
|
|
22930
|
-
const
|
|
22931
|
-
if (
|
|
22932
|
-
bestD =
|
|
23103
|
+
const d3 = editDistance(lc, c2.toLowerCase());
|
|
23104
|
+
if (d3 < bestD) {
|
|
23105
|
+
bestD = d3;
|
|
22933
23106
|
best = c2;
|
|
22934
23107
|
}
|
|
22935
23108
|
}
|
|
22936
23109
|
return bestD <= threshold ? best : null;
|
|
22937
23110
|
}
|
|
22938
23111
|
|
|
23112
|
+
// src/commands/repo/schema.ts
|
|
23113
|
+
var REPO_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,99}$/;
|
|
23114
|
+
var repoName = external_exports.string().regex(
|
|
23115
|
+
REPO_NAME_RE,
|
|
23116
|
+
"must start with a letter or digit, then letters, digits, '.', '_' or '-' (max 100 chars)"
|
|
23117
|
+
);
|
|
23118
|
+
var visibilitySchema = external_exports.enum(["public", "private"]);
|
|
23119
|
+
var repoStatusSchema = external_exports.enum([
|
|
23120
|
+
"pending",
|
|
23121
|
+
"approved",
|
|
23122
|
+
"active",
|
|
23123
|
+
"rejected",
|
|
23124
|
+
"failed"
|
|
23125
|
+
]);
|
|
23126
|
+
var createRepoRequestSchema = external_exports.object({
|
|
23127
|
+
name: repoName,
|
|
23128
|
+
visibility: visibilitySchema.default("private"),
|
|
23129
|
+
description: external_exports.string().max(350).optional(),
|
|
23130
|
+
template: repoName.optional()
|
|
23131
|
+
}).strict();
|
|
23132
|
+
var repoRowSchema = external_exports.object({
|
|
23133
|
+
id: external_exports.string(),
|
|
23134
|
+
name: external_exports.string(),
|
|
23135
|
+
owner: external_exports.string(),
|
|
23136
|
+
visibility: visibilitySchema,
|
|
23137
|
+
description: external_exports.string().optional(),
|
|
23138
|
+
template: external_exports.string().optional(),
|
|
23139
|
+
status: repoStatusSchema,
|
|
23140
|
+
url: external_exports.string().optional(),
|
|
23141
|
+
error: external_exports.string().optional(),
|
|
23142
|
+
requestedBy: external_exports.string(),
|
|
23143
|
+
approver: external_exports.string().optional(),
|
|
23144
|
+
rejectReason: external_exports.string().optional(),
|
|
23145
|
+
createdAt: external_exports.string(),
|
|
23146
|
+
updatedAt: external_exports.string()
|
|
23147
|
+
});
|
|
23148
|
+
var repoRowArraySchema = external_exports.array(repoRowSchema);
|
|
23149
|
+
var repoApproveResultSchema = external_exports.object({
|
|
23150
|
+
outcome: external_exports.enum(["ok", "approved_failed"]),
|
|
23151
|
+
request: repoRowSchema
|
|
23152
|
+
});
|
|
23153
|
+
var repoTemplatesResponseSchema = external_exports.object({
|
|
23154
|
+
templates: external_exports.array(external_exports.string())
|
|
23155
|
+
});
|
|
23156
|
+
|
|
22939
23157
|
// src/lib/proxy-client.ts
|
|
22940
23158
|
var DEFAULT_FETCH_TIMEOUT_MS = 3e4;
|
|
22941
23159
|
function parseFetchTimeoutMs(env) {
|
|
@@ -22949,11 +23167,13 @@ var ProxyError = class extends CliError {
|
|
|
22949
23167
|
exitCode;
|
|
22950
23168
|
status;
|
|
22951
23169
|
code;
|
|
22952
|
-
|
|
23170
|
+
requestId;
|
|
23171
|
+
constructor(status2, code, message, requestId) {
|
|
22953
23172
|
super(message);
|
|
22954
|
-
this.status =
|
|
23173
|
+
this.status = status2;
|
|
22955
23174
|
this.code = code;
|
|
22956
|
-
this.exitCode = mapExitCode(
|
|
23175
|
+
this.exitCode = mapExitCode(status2);
|
|
23176
|
+
this.requestId = requestId;
|
|
22957
23177
|
}
|
|
22958
23178
|
};
|
|
22959
23179
|
var AliasDriftError = class extends ProxyError {
|
|
@@ -22963,16 +23183,22 @@ var AliasDriftError = class extends ProxyError {
|
|
|
22963
23183
|
this.current = current;
|
|
22964
23184
|
}
|
|
22965
23185
|
};
|
|
22966
|
-
function mapExitCode(
|
|
22967
|
-
if (
|
|
22968
|
-
if (
|
|
23186
|
+
function mapExitCode(status2) {
|
|
23187
|
+
if (status2 === 401 || status2 === 403) return EXIT_CREDENTIALS;
|
|
23188
|
+
if (status2 === 422 || status2 === 0 || status2 >= 500) return EXIT_STORAGE;
|
|
22969
23189
|
return EXIT_USAGE;
|
|
22970
23190
|
}
|
|
22971
23191
|
function wrapProxyError(command, err) {
|
|
22972
23192
|
if (err instanceof ProxyError) {
|
|
23193
|
+
let message = `${command} failed (${err.code}): ${err.message}`;
|
|
23194
|
+
if (err.code === "user_unauthorized") {
|
|
23195
|
+
message += "\n hint: the active GitHub token may lack the read:org scope or SSO authorization for the org. $GITHUB_TOKEN / $GH_TOKEN override `gh auth token` \u2014 run `universe whoami` to check the active identity source, then unset them or re-authorize the token (Configure SSO).";
|
|
23196
|
+
}
|
|
22973
23197
|
return {
|
|
22974
23198
|
code: err.exitCode,
|
|
22975
|
-
message
|
|
23199
|
+
message,
|
|
23200
|
+
kind: err.code,
|
|
23201
|
+
requestId: err.requestId
|
|
22976
23202
|
};
|
|
22977
23203
|
}
|
|
22978
23204
|
if (err instanceof CliError) {
|
|
@@ -22987,34 +23213,34 @@ function isProxyErrorEnvelope(value) {
|
|
|
22987
23213
|
return typeof value === "object" && value !== null && !Array.isArray(value) && "error" in value;
|
|
22988
23214
|
}
|
|
22989
23215
|
async function readErrorEnvelope(response) {
|
|
22990
|
-
const
|
|
23216
|
+
const status2 = response.status;
|
|
22991
23217
|
let raw;
|
|
22992
23218
|
try {
|
|
22993
23219
|
raw = await response.json();
|
|
22994
23220
|
} catch {
|
|
22995
23221
|
return {
|
|
22996
|
-
code: `http_${
|
|
23222
|
+
code: `http_${status2}`,
|
|
22997
23223
|
message: response.statusText || "request failed"
|
|
22998
23224
|
};
|
|
22999
23225
|
}
|
|
23000
23226
|
if (isProxyErrorEnvelope(raw) && raw.error) {
|
|
23001
23227
|
const current = typeof raw.current === "string" ? raw.current : void 0;
|
|
23002
23228
|
return {
|
|
23003
|
-
code: raw.error.code ?? `http_${
|
|
23229
|
+
code: raw.error.code ?? `http_${status2}`,
|
|
23004
23230
|
message: raw.error.message ?? response.statusText ?? "request failed",
|
|
23005
23231
|
...current === void 0 ? {} : { current }
|
|
23006
23232
|
};
|
|
23007
23233
|
}
|
|
23008
23234
|
return {
|
|
23009
|
-
code: `http_${
|
|
23235
|
+
code: `http_${status2}`,
|
|
23010
23236
|
message: response.statusText || "request failed"
|
|
23011
23237
|
};
|
|
23012
23238
|
}
|
|
23013
|
-
function throwProxyError(
|
|
23014
|
-
if (
|
|
23239
|
+
function throwProxyError(status2, env, requestId) {
|
|
23240
|
+
if (status2 === 409 && env.code === "alias_drift") {
|
|
23015
23241
|
throw new AliasDriftError(env.message, env.current ?? "");
|
|
23016
23242
|
}
|
|
23017
|
-
throw new ProxyError(
|
|
23243
|
+
throw new ProxyError(status2, env.code, env.message, requestId);
|
|
23018
23244
|
}
|
|
23019
23245
|
function stripTrailingSlash(url2) {
|
|
23020
23246
|
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
@@ -23023,6 +23249,7 @@ function createProxyClient(cfg) {
|
|
|
23023
23249
|
const base = stripTrailingSlash(cfg.baseUrl);
|
|
23024
23250
|
const fetchImpl = cfg.fetch ?? globalThis.fetch.bind(globalThis);
|
|
23025
23251
|
const timeoutMs = cfg.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
|
|
23252
|
+
const debug = cfg.debug ?? false;
|
|
23026
23253
|
function withTimeoutSignal(init) {
|
|
23027
23254
|
if (timeoutMs <= 0) return init;
|
|
23028
23255
|
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
@@ -23034,31 +23261,65 @@ function createProxyClient(cfg) {
|
|
|
23034
23261
|
throw new ProxyError(
|
|
23035
23262
|
0,
|
|
23036
23263
|
"timeout",
|
|
23037
|
-
`proxy timed out after ${timeoutMs}ms`
|
|
23264
|
+
`proxy timed out after ${timeoutMs}ms (${base})`
|
|
23038
23265
|
);
|
|
23039
23266
|
}
|
|
23040
23267
|
const message = err instanceof Error ? err.message : String(err);
|
|
23041
|
-
throw new ProxyError(
|
|
23268
|
+
throw new ProxyError(
|
|
23269
|
+
0,
|
|
23270
|
+
"network_error",
|
|
23271
|
+
`proxy unreachable at ${base}: ${message}`
|
|
23272
|
+
);
|
|
23042
23273
|
}
|
|
23043
23274
|
async function userBearer() {
|
|
23044
23275
|
const tok = await cfg.getAuthToken();
|
|
23045
23276
|
return `Bearer ${tok}`;
|
|
23046
23277
|
}
|
|
23047
|
-
async function call(url2, init) {
|
|
23278
|
+
async function call(url2, init, validate) {
|
|
23279
|
+
const startedAt = debug ? Date.now() : 0;
|
|
23048
23280
|
let response;
|
|
23049
23281
|
try {
|
|
23050
23282
|
response = await fetchImpl(url2, withTimeoutSignal(init));
|
|
23051
23283
|
} catch (err) {
|
|
23052
23284
|
translateFetchError(err);
|
|
23053
23285
|
}
|
|
23286
|
+
if (debug) {
|
|
23287
|
+
process.stderr.write(
|
|
23288
|
+
`[universe] ${init.method ?? "GET"} ${url2} -> ${response.status} (${Date.now() - startedAt}ms)
|
|
23289
|
+
`
|
|
23290
|
+
);
|
|
23291
|
+
}
|
|
23054
23292
|
if (!response.ok) {
|
|
23293
|
+
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
23055
23294
|
const env = await readErrorEnvelope(response);
|
|
23056
|
-
throwProxyError(response.status, env);
|
|
23295
|
+
throwProxyError(response.status, env, requestId);
|
|
23057
23296
|
}
|
|
23058
23297
|
if (response.status === 204) {
|
|
23059
23298
|
return void 0;
|
|
23060
23299
|
}
|
|
23061
|
-
|
|
23300
|
+
let raw;
|
|
23301
|
+
try {
|
|
23302
|
+
raw = await response.json();
|
|
23303
|
+
} catch {
|
|
23304
|
+
throw new ProxyError(
|
|
23305
|
+
0,
|
|
23306
|
+
"malformed_response",
|
|
23307
|
+
"proxy returned a non-JSON response body"
|
|
23308
|
+
);
|
|
23309
|
+
}
|
|
23310
|
+
if (validate) {
|
|
23311
|
+
try {
|
|
23312
|
+
validate(raw);
|
|
23313
|
+
} catch (err) {
|
|
23314
|
+
const detail = err instanceof Error ? err.message : "invalid shape";
|
|
23315
|
+
throw new ProxyError(
|
|
23316
|
+
0,
|
|
23317
|
+
"malformed_response",
|
|
23318
|
+
`proxy returned an unexpected response shape: ${detail}`
|
|
23319
|
+
);
|
|
23320
|
+
}
|
|
23321
|
+
}
|
|
23322
|
+
return raw;
|
|
23062
23323
|
}
|
|
23063
23324
|
return {
|
|
23064
23325
|
async whoami() {
|
|
@@ -23219,6 +23480,105 @@ function createProxyClient(cfg) {
|
|
|
23219
23480
|
Accept: "application/json"
|
|
23220
23481
|
}
|
|
23221
23482
|
});
|
|
23483
|
+
},
|
|
23484
|
+
async createRepoRequest(req) {
|
|
23485
|
+
const body = { name: req.name };
|
|
23486
|
+
if (req.visibility !== void 0) body.visibility = req.visibility;
|
|
23487
|
+
if (req.description !== void 0) body.description = req.description;
|
|
23488
|
+
if (req.template !== void 0 && req.template !== "") {
|
|
23489
|
+
body.template = req.template;
|
|
23490
|
+
}
|
|
23491
|
+
return call(
|
|
23492
|
+
`${base}/api/repo`,
|
|
23493
|
+
{
|
|
23494
|
+
method: "POST",
|
|
23495
|
+
headers: {
|
|
23496
|
+
Authorization: await userBearer(),
|
|
23497
|
+
Accept: "application/json",
|
|
23498
|
+
"Content-Type": "application/json"
|
|
23499
|
+
},
|
|
23500
|
+
body: JSON.stringify(body)
|
|
23501
|
+
},
|
|
23502
|
+
(raw) => repoRowSchema.parse(raw)
|
|
23503
|
+
);
|
|
23504
|
+
},
|
|
23505
|
+
async listRepoRequests(req) {
|
|
23506
|
+
const params = new URLSearchParams();
|
|
23507
|
+
if (req?.status) params.set("status", req.status);
|
|
23508
|
+
if (req?.mine) params.set("mine", "1");
|
|
23509
|
+
const qs = params.toString();
|
|
23510
|
+
const url2 = `${base}/api/repos${qs ? `?${qs}` : ""}`;
|
|
23511
|
+
return call(
|
|
23512
|
+
url2,
|
|
23513
|
+
{
|
|
23514
|
+
method: "GET",
|
|
23515
|
+
headers: {
|
|
23516
|
+
Authorization: await userBearer(),
|
|
23517
|
+
Accept: "application/json"
|
|
23518
|
+
}
|
|
23519
|
+
},
|
|
23520
|
+
(raw) => repoRowArraySchema.parse(raw)
|
|
23521
|
+
);
|
|
23522
|
+
},
|
|
23523
|
+
async getRepoRequest(id) {
|
|
23524
|
+
const url2 = `${base}/api/repo/${encodeURIComponent(id)}`;
|
|
23525
|
+
return call(
|
|
23526
|
+
url2,
|
|
23527
|
+
{
|
|
23528
|
+
method: "GET",
|
|
23529
|
+
headers: {
|
|
23530
|
+
Authorization: await userBearer(),
|
|
23531
|
+
Accept: "application/json"
|
|
23532
|
+
}
|
|
23533
|
+
},
|
|
23534
|
+
(raw) => repoRowSchema.parse(raw)
|
|
23535
|
+
);
|
|
23536
|
+
},
|
|
23537
|
+
async approveRepoRequest(req) {
|
|
23538
|
+
const url2 = `${base}/api/repo/${encodeURIComponent(req.id)}/approve`;
|
|
23539
|
+
return call(
|
|
23540
|
+
url2,
|
|
23541
|
+
{
|
|
23542
|
+
method: "POST",
|
|
23543
|
+
headers: {
|
|
23544
|
+
Authorization: await userBearer(),
|
|
23545
|
+
Accept: "application/json"
|
|
23546
|
+
}
|
|
23547
|
+
},
|
|
23548
|
+
(raw) => repoApproveResultSchema.parse(raw)
|
|
23549
|
+
);
|
|
23550
|
+
},
|
|
23551
|
+
async rejectRepoRequest(req) {
|
|
23552
|
+
const url2 = `${base}/api/repo/${encodeURIComponent(req.id)}/reject`;
|
|
23553
|
+
const body = {};
|
|
23554
|
+
if (req.reason !== void 0) body.reason = req.reason;
|
|
23555
|
+
return call(
|
|
23556
|
+
url2,
|
|
23557
|
+
{
|
|
23558
|
+
method: "POST",
|
|
23559
|
+
headers: {
|
|
23560
|
+
Authorization: await userBearer(),
|
|
23561
|
+
Accept: "application/json",
|
|
23562
|
+
"Content-Type": "application/json"
|
|
23563
|
+
},
|
|
23564
|
+
body: JSON.stringify(body)
|
|
23565
|
+
},
|
|
23566
|
+
(raw) => repoRowSchema.parse(raw)
|
|
23567
|
+
);
|
|
23568
|
+
},
|
|
23569
|
+
async listRepoTemplates() {
|
|
23570
|
+
const res = await call(
|
|
23571
|
+
`${base}/api/repo/templates`,
|
|
23572
|
+
{
|
|
23573
|
+
method: "GET",
|
|
23574
|
+
headers: {
|
|
23575
|
+
Authorization: await userBearer(),
|
|
23576
|
+
Accept: "application/json"
|
|
23577
|
+
}
|
|
23578
|
+
},
|
|
23579
|
+
(raw) => repoTemplatesResponseSchema.parse(raw)
|
|
23580
|
+
);
|
|
23581
|
+
return res.templates ?? [];
|
|
23222
23582
|
}
|
|
23223
23583
|
};
|
|
23224
23584
|
}
|
|
@@ -23359,11 +23719,17 @@ function buildEnvelope(command, success2, data) {
|
|
|
23359
23719
|
...data
|
|
23360
23720
|
};
|
|
23361
23721
|
}
|
|
23362
|
-
function buildErrorEnvelope(command, code, message, issues) {
|
|
23722
|
+
function buildErrorEnvelope(command, code, message, issues, kind, requestId) {
|
|
23363
23723
|
const error48 = {
|
|
23364
23724
|
code,
|
|
23365
23725
|
message
|
|
23366
23726
|
};
|
|
23727
|
+
if (kind !== void 0) {
|
|
23728
|
+
error48.kind = kind;
|
|
23729
|
+
}
|
|
23730
|
+
if (requestId !== void 0) {
|
|
23731
|
+
error48.requestId = requestId;
|
|
23732
|
+
}
|
|
23367
23733
|
if (issues !== void 0) {
|
|
23368
23734
|
error48.issues = issues;
|
|
23369
23735
|
}
|
|
@@ -23464,12 +23830,14 @@ function outputError(ctx, code, message, optsOrIssues) {
|
|
|
23464
23830
|
ctx.command,
|
|
23465
23831
|
code,
|
|
23466
23832
|
redactedMessage,
|
|
23467
|
-
redactedIssues
|
|
23833
|
+
redactedIssues,
|
|
23834
|
+
opts.kind,
|
|
23835
|
+
opts.requestId
|
|
23468
23836
|
);
|
|
23469
23837
|
const payload = opts.extras ? { ...envelope, ...redactObject(opts.extras) } : envelope;
|
|
23470
23838
|
process.stdout.write(JSON.stringify(payload) + "\n");
|
|
23471
23839
|
} else {
|
|
23472
|
-
(opts.logError ?? ((m) => O2.error(m)))(redactedMessage);
|
|
23840
|
+
(opts.logError ?? ((m) => O2.error(m, { output: process.stderr })))(redactedMessage);
|
|
23473
23841
|
}
|
|
23474
23842
|
}
|
|
23475
23843
|
|
|
@@ -23994,10 +24362,10 @@ async function readSiteFromYaml(cwd, read) {
|
|
|
23994
24362
|
}
|
|
23995
24363
|
function formatTable(deploys) {
|
|
23996
24364
|
const header = ["DEPLOY ID", "TIMESTAMP", "SHA"];
|
|
23997
|
-
const rows = deploys.map((
|
|
23998
|
-
|
|
23999
|
-
|
|
24000
|
-
|
|
24365
|
+
const rows = deploys.map((d3) => [
|
|
24366
|
+
d3.deployId,
|
|
24367
|
+
d3.timestamp ? d3.timestamp.replace("T", " ").replace("Z", "") : "\u2014",
|
|
24368
|
+
d3.sha ?? "\u2014"
|
|
24001
24369
|
]);
|
|
24002
24370
|
const widths = header.map(
|
|
24003
24371
|
(h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length))
|
|
@@ -24041,7 +24409,7 @@ async function ls(options, deps = {}) {
|
|
|
24041
24409
|
const sorted = [...raw].sort(
|
|
24042
24410
|
(a, b) => b.deployId.localeCompare(a.deployId)
|
|
24043
24411
|
);
|
|
24044
|
-
const deploys = sorted.map((
|
|
24412
|
+
const deploys = sorted.map((d3) => parseDeployId(d3.deployId));
|
|
24045
24413
|
if (options.json) {
|
|
24046
24414
|
emitJson4(
|
|
24047
24415
|
buildEnvelope("ls", true, {
|
|
@@ -24382,6 +24750,7 @@ async function whoami(options, deps = {}) {
|
|
|
24382
24750
|
buildEnvelope("whoami", true, {
|
|
24383
24751
|
login: result.login,
|
|
24384
24752
|
identitySource: identity.source,
|
|
24753
|
+
proxyUrl: baseUrl,
|
|
24385
24754
|
authorizedSitesCount: count
|
|
24386
24755
|
})
|
|
24387
24756
|
);
|
|
@@ -24391,6 +24760,7 @@ async function whoami(options, deps = {}) {
|
|
|
24391
24760
|
[
|
|
24392
24761
|
`Logged in as: ${result.login}`,
|
|
24393
24762
|
`Identity source: ${identity.source}`,
|
|
24763
|
+
`Proxy: ${baseUrl}`,
|
|
24394
24764
|
sitesLine
|
|
24395
24765
|
].join("\n")
|
|
24396
24766
|
);
|
|
@@ -24621,6 +24991,495 @@ async function update(options, deps = {}) {
|
|
|
24621
24991
|
}
|
|
24622
24992
|
}
|
|
24623
24993
|
|
|
24994
|
+
// src/commands/repo/_shared.ts
|
|
24995
|
+
var defaultRepoPrompts = {
|
|
24996
|
+
text: Ot,
|
|
24997
|
+
select: _t,
|
|
24998
|
+
confirm: ot2,
|
|
24999
|
+
isCancel: q
|
|
25000
|
+
};
|
|
25001
|
+
function emitJson9(envelope) {
|
|
25002
|
+
process.stdout.write(JSON.stringify(envelope) + "\n");
|
|
25003
|
+
}
|
|
25004
|
+
async function setupClient2(deps) {
|
|
25005
|
+
const env = deps.env ?? process.env;
|
|
25006
|
+
const resolveId = deps.resolveIdentity ?? resolveIdentity;
|
|
25007
|
+
const mkClient = deps.createProxyClient ?? createProxyClient;
|
|
25008
|
+
const identity = await resolveId({ env });
|
|
25009
|
+
if (!identity) {
|
|
25010
|
+
throw new CredentialError(
|
|
25011
|
+
"No GitHub identity available. Run `universe login`, set $GITHUB_TOKEN, or install the gh CLI."
|
|
25012
|
+
);
|
|
25013
|
+
}
|
|
25014
|
+
const baseUrl = env["UNIVERSE_PROXY_URL"] ?? DEFAULT_PROXY_URL;
|
|
25015
|
+
const client = mkClient({
|
|
25016
|
+
baseUrl,
|
|
25017
|
+
getAuthToken: () => identity.token,
|
|
25018
|
+
timeoutMs: parseFetchTimeoutMs(env),
|
|
25019
|
+
debug: Boolean(env["UNIVERSE_DEBUG"])
|
|
25020
|
+
});
|
|
25021
|
+
return { client, identitySource: identity.source };
|
|
25022
|
+
}
|
|
25023
|
+
function formatRepoTable(rows, emptyMsg = "No repo requests.") {
|
|
25024
|
+
if (rows.length === 0) return emptyMsg;
|
|
25025
|
+
const headers = [
|
|
25026
|
+
"ID",
|
|
25027
|
+
"REPO",
|
|
25028
|
+
"VIS",
|
|
25029
|
+
"STATUS",
|
|
25030
|
+
"REQUESTED BY",
|
|
25031
|
+
"REQUESTED AT"
|
|
25032
|
+
];
|
|
25033
|
+
const cells = rows.map((r) => [
|
|
25034
|
+
r.id,
|
|
25035
|
+
r.name,
|
|
25036
|
+
r.visibility,
|
|
25037
|
+
r.status,
|
|
25038
|
+
r.requestedBy,
|
|
25039
|
+
r.createdAt
|
|
25040
|
+
]);
|
|
25041
|
+
const widths = headers.map(
|
|
25042
|
+
(h, i) => Math.max(h.length, ...cells.map((row) => row[i]?.length ?? 0))
|
|
25043
|
+
);
|
|
25044
|
+
const fmt = (row) => row.map((c2, i) => c2.padEnd(widths[i] ?? 0)).join(" ");
|
|
25045
|
+
return [fmt(headers), ...cells.map(fmt)].join("\n");
|
|
25046
|
+
}
|
|
25047
|
+
|
|
25048
|
+
// src/commands/repo/approve.ts
|
|
25049
|
+
async function approve(options, deps = {}) {
|
|
25050
|
+
const command = "repo approve";
|
|
25051
|
+
const success2 = deps.logSuccess ?? ((s) => O2.success(s));
|
|
25052
|
+
const error48 = deps.logError ?? ((s) => O2.error(s));
|
|
25053
|
+
const exit = deps.exit ?? exitWithCode;
|
|
25054
|
+
const prompts = deps.prompts ?? defaultRepoPrompts;
|
|
25055
|
+
const isTTY = deps.isTTY ?? Boolean(process.stdout.isTTY);
|
|
25056
|
+
let creationFailure;
|
|
25057
|
+
let identitySource;
|
|
25058
|
+
try {
|
|
25059
|
+
if (!options.id || options.id.trim().length === 0) {
|
|
25060
|
+
throw new UsageError("request id is required (positional argument)");
|
|
25061
|
+
}
|
|
25062
|
+
const setup = await setupClient2(deps);
|
|
25063
|
+
const client = setup.client;
|
|
25064
|
+
identitySource = setup.identitySource;
|
|
25065
|
+
if (!options.json && !options.yes) {
|
|
25066
|
+
if (!isTTY) {
|
|
25067
|
+
throw new UsageError(
|
|
25068
|
+
"non-interactive session: pass --yes to approve without confirmation"
|
|
25069
|
+
);
|
|
25070
|
+
}
|
|
25071
|
+
const cur = await client.getRepoRequest(options.id);
|
|
25072
|
+
const ok = await prompts.confirm({
|
|
25073
|
+
message: `Approve ${cur.visibility} repo "${cur.name}" requested by ${cur.requestedBy}? This creates the repository.`
|
|
25074
|
+
});
|
|
25075
|
+
if (prompts.isCancel(ok) || ok === false) {
|
|
25076
|
+
throw new ConfirmError("repo approve cancelled");
|
|
25077
|
+
}
|
|
25078
|
+
}
|
|
25079
|
+
const res = await client.approveRepoRequest({ id: options.id });
|
|
25080
|
+
const row = res.request;
|
|
25081
|
+
if (res.outcome === "approved_failed") {
|
|
25082
|
+
if (!options.json) {
|
|
25083
|
+
throw new StorageError(
|
|
25084
|
+
`approved, but repository creation failed: ${row.error ?? "unknown"} (${row.owner}/${row.name}, requested by ${row.requestedBy})`
|
|
25085
|
+
);
|
|
25086
|
+
}
|
|
25087
|
+
creationFailure = {
|
|
25088
|
+
outcome: res.outcome,
|
|
25089
|
+
id: row.id,
|
|
25090
|
+
repo: `${row.owner}/${row.name}`,
|
|
25091
|
+
status: row.status,
|
|
25092
|
+
creationError: row.error ?? "unknown",
|
|
25093
|
+
requestedBy: row.requestedBy,
|
|
25094
|
+
identitySource
|
|
25095
|
+
};
|
|
25096
|
+
} else if (options.json) {
|
|
25097
|
+
emitJson9(
|
|
25098
|
+
buildEnvelope(command, true, {
|
|
25099
|
+
id: row.id,
|
|
25100
|
+
outcome: res.outcome,
|
|
25101
|
+
repo: `${row.owner}/${row.name}`,
|
|
25102
|
+
url: row.url,
|
|
25103
|
+
visibility: row.visibility,
|
|
25104
|
+
approver: row.approver,
|
|
25105
|
+
identitySource
|
|
25106
|
+
})
|
|
25107
|
+
);
|
|
25108
|
+
} else {
|
|
25109
|
+
success2(
|
|
25110
|
+
[
|
|
25111
|
+
`Approved ${row.name}`,
|
|
25112
|
+
``,
|
|
25113
|
+
` Repository: ${row.url ?? `${row.owner}/${row.name}`}`,
|
|
25114
|
+
` Visibility: ${row.visibility}`,
|
|
25115
|
+
` Approved by: ${row.approver ?? "you"}`
|
|
25116
|
+
].join("\n")
|
|
25117
|
+
);
|
|
25118
|
+
}
|
|
25119
|
+
} catch (err) {
|
|
25120
|
+
const { code, message, kind, requestId } = wrapProxyError(command, err);
|
|
25121
|
+
outputError({ json: options.json, command }, code, message, {
|
|
25122
|
+
logError: error48,
|
|
25123
|
+
kind,
|
|
25124
|
+
requestId,
|
|
25125
|
+
extras: identitySource ? { identitySource } : void 0
|
|
25126
|
+
});
|
|
25127
|
+
exit(code);
|
|
25128
|
+
return;
|
|
25129
|
+
}
|
|
25130
|
+
if (creationFailure) {
|
|
25131
|
+
outputError(
|
|
25132
|
+
{ json: true, command },
|
|
25133
|
+
EXIT_STORAGE,
|
|
25134
|
+
"approved, but repository creation failed",
|
|
25135
|
+
{ logError: error48, extras: creationFailure }
|
|
25136
|
+
);
|
|
25137
|
+
exit(EXIT_STORAGE);
|
|
25138
|
+
}
|
|
25139
|
+
}
|
|
25140
|
+
|
|
25141
|
+
// src/commands/repo/create.ts
|
|
25142
|
+
function blankToUndefined(s) {
|
|
25143
|
+
if (s === void 0 || s === null) return void 0;
|
|
25144
|
+
const t2 = String(s).trim();
|
|
25145
|
+
return t2 === "" ? void 0 : t2;
|
|
25146
|
+
}
|
|
25147
|
+
async function promptTemplate(client, prompts) {
|
|
25148
|
+
let templates = [];
|
|
25149
|
+
try {
|
|
25150
|
+
templates = await client.listRepoTemplates();
|
|
25151
|
+
} catch {
|
|
25152
|
+
templates = [];
|
|
25153
|
+
}
|
|
25154
|
+
if (templates.length === 0) {
|
|
25155
|
+
const v2 = await prompts.text({
|
|
25156
|
+
message: "Template (optional)",
|
|
25157
|
+
placeholder: "name of an org template repo; blank for an empty repo"
|
|
25158
|
+
});
|
|
25159
|
+
if (prompts.isCancel(v2)) throw new ConfirmError("repo create cancelled");
|
|
25160
|
+
return blankToUndefined(String(v2));
|
|
25161
|
+
}
|
|
25162
|
+
const v = await prompts.select({
|
|
25163
|
+
message: "Template",
|
|
25164
|
+
options: [
|
|
25165
|
+
{ value: "", label: "None (blank repo)" },
|
|
25166
|
+
...templates.map((t2) => ({ value: t2, label: t2 }))
|
|
25167
|
+
],
|
|
25168
|
+
initialValue: ""
|
|
25169
|
+
});
|
|
25170
|
+
if (prompts.isCancel(v)) throw new ConfirmError("repo create cancelled");
|
|
25171
|
+
return blankToUndefined(String(v));
|
|
25172
|
+
}
|
|
25173
|
+
async function create(options, deps = {}) {
|
|
25174
|
+
const command = "repo create";
|
|
25175
|
+
const success2 = deps.logSuccess ?? ((s) => O2.success(s));
|
|
25176
|
+
const error48 = deps.logError ?? ((s) => O2.error(s));
|
|
25177
|
+
const exit = deps.exit ?? exitWithCode;
|
|
25178
|
+
const prompts = deps.prompts ?? defaultRepoPrompts;
|
|
25179
|
+
const isTTY = deps.isTTY ?? Boolean(process.stdout.isTTY);
|
|
25180
|
+
const canPrompt = !options.json && !options.yes && isTTY;
|
|
25181
|
+
let identitySource = "";
|
|
25182
|
+
try {
|
|
25183
|
+
let client;
|
|
25184
|
+
const ensureClient = async () => {
|
|
25185
|
+
if (!client) {
|
|
25186
|
+
const setup = await setupClient2(deps);
|
|
25187
|
+
client = setup.client;
|
|
25188
|
+
identitySource = setup.identitySource;
|
|
25189
|
+
}
|
|
25190
|
+
return client;
|
|
25191
|
+
};
|
|
25192
|
+
let name = blankToUndefined(options.name) ?? "";
|
|
25193
|
+
let visibility = options.visibility;
|
|
25194
|
+
let description = options.description;
|
|
25195
|
+
let template = options.template;
|
|
25196
|
+
if (canPrompt) {
|
|
25197
|
+
if (!name) {
|
|
25198
|
+
const v = await prompts.text({
|
|
25199
|
+
message: "Repository name",
|
|
25200
|
+
placeholder: "learn-python-rpg"
|
|
25201
|
+
});
|
|
25202
|
+
if (prompts.isCancel(v))
|
|
25203
|
+
throw new ConfirmError("repo create cancelled");
|
|
25204
|
+
name = String(v).trim();
|
|
25205
|
+
}
|
|
25206
|
+
if (visibility === void 0) {
|
|
25207
|
+
const v = await prompts.select({
|
|
25208
|
+
message: "Visibility",
|
|
25209
|
+
options: [
|
|
25210
|
+
{ value: "private", label: "Private" },
|
|
25211
|
+
{ value: "public", label: "Public" }
|
|
25212
|
+
],
|
|
25213
|
+
initialValue: "private"
|
|
25214
|
+
});
|
|
25215
|
+
if (prompts.isCancel(v))
|
|
25216
|
+
throw new ConfirmError("repo create cancelled");
|
|
25217
|
+
visibility = String(v);
|
|
25218
|
+
}
|
|
25219
|
+
if (description === void 0) {
|
|
25220
|
+
const v = await prompts.text({
|
|
25221
|
+
message: "Description (optional)",
|
|
25222
|
+
placeholder: "What is this project about?"
|
|
25223
|
+
});
|
|
25224
|
+
if (prompts.isCancel(v))
|
|
25225
|
+
throw new ConfirmError("repo create cancelled");
|
|
25226
|
+
description = String(v);
|
|
25227
|
+
}
|
|
25228
|
+
if (template === void 0) {
|
|
25229
|
+
template = await promptTemplate(await ensureClient(), prompts);
|
|
25230
|
+
}
|
|
25231
|
+
}
|
|
25232
|
+
if (!name) {
|
|
25233
|
+
throw new UsageError("repo name is required");
|
|
25234
|
+
}
|
|
25235
|
+
const candidate = { name };
|
|
25236
|
+
if (visibility !== void 0 && visibility !== "") {
|
|
25237
|
+
candidate.visibility = visibility;
|
|
25238
|
+
}
|
|
25239
|
+
const desc = blankToUndefined(description);
|
|
25240
|
+
if (desc !== void 0) candidate.description = desc;
|
|
25241
|
+
const tmpl = blankToUndefined(template);
|
|
25242
|
+
if (tmpl !== void 0) candidate.template = tmpl;
|
|
25243
|
+
const parsed = createRepoRequestSchema.safeParse(candidate);
|
|
25244
|
+
if (!parsed.success) {
|
|
25245
|
+
const issues = parsed.error.issues.map(
|
|
25246
|
+
(i) => `${i.path.join(".") || "input"}: ${i.message}`
|
|
25247
|
+
);
|
|
25248
|
+
throw new UsageError(issues.join("; "));
|
|
25249
|
+
}
|
|
25250
|
+
const body = parsed.data;
|
|
25251
|
+
if (!options.json && !options.yes) {
|
|
25252
|
+
if (!isTTY) {
|
|
25253
|
+
throw new UsageError(
|
|
25254
|
+
"non-interactive session: pass --yes to submit without confirmation (or --json)"
|
|
25255
|
+
);
|
|
25256
|
+
}
|
|
25257
|
+
const ok = await prompts.confirm({
|
|
25258
|
+
message: `Submit request to create ${body.visibility} repo "${body.name}"${body.template ? ` from template ${body.template}` : ""}?`
|
|
25259
|
+
});
|
|
25260
|
+
if (prompts.isCancel(ok) || ok === false) {
|
|
25261
|
+
throw new ConfirmError("repo create cancelled");
|
|
25262
|
+
}
|
|
25263
|
+
}
|
|
25264
|
+
const activeClient = await ensureClient();
|
|
25265
|
+
const row = await activeClient.createRepoRequest({
|
|
25266
|
+
name: body.name,
|
|
25267
|
+
visibility: body.visibility,
|
|
25268
|
+
description: body.description,
|
|
25269
|
+
template: body.template
|
|
25270
|
+
});
|
|
25271
|
+
if (options.json) {
|
|
25272
|
+
emitJson9(
|
|
25273
|
+
buildEnvelope(command, true, {
|
|
25274
|
+
id: row.id,
|
|
25275
|
+
name: row.name,
|
|
25276
|
+
owner: row.owner,
|
|
25277
|
+
visibility: row.visibility,
|
|
25278
|
+
template: row.template,
|
|
25279
|
+
status: row.status,
|
|
25280
|
+
identitySource
|
|
25281
|
+
})
|
|
25282
|
+
);
|
|
25283
|
+
} else {
|
|
25284
|
+
success2(
|
|
25285
|
+
[
|
|
25286
|
+
`Request submitted`,
|
|
25287
|
+
``,
|
|
25288
|
+
` Request id: ${row.id}`,
|
|
25289
|
+
` Repository: ${row.owner}/${row.name}`,
|
|
25290
|
+
` Visibility: ${row.visibility}`,
|
|
25291
|
+
...row.template ? [` Template: ${row.template}`] : [],
|
|
25292
|
+
` Status: ${row.status} \u2014 run \`universe repo ls\` to review`
|
|
25293
|
+
].join("\n")
|
|
25294
|
+
);
|
|
25295
|
+
}
|
|
25296
|
+
} catch (err) {
|
|
25297
|
+
const { code, message, kind, requestId } = wrapProxyError(command, err);
|
|
25298
|
+
outputError({ json: options.json, command }, code, message, {
|
|
25299
|
+
logError: error48,
|
|
25300
|
+
kind,
|
|
25301
|
+
requestId,
|
|
25302
|
+
extras: identitySource ? { identitySource } : void 0
|
|
25303
|
+
});
|
|
25304
|
+
exit(code);
|
|
25305
|
+
}
|
|
25306
|
+
}
|
|
25307
|
+
|
|
25308
|
+
// src/commands/repo/ls.ts
|
|
25309
|
+
var LS_STATUSES = [...repoStatusSchema.options, "all"];
|
|
25310
|
+
async function ls3(options, deps = {}) {
|
|
25311
|
+
const command = "repo ls";
|
|
25312
|
+
const message = deps.logMessage ?? ((s) => O2.message(s));
|
|
25313
|
+
const error48 = deps.logError ?? ((s) => O2.error(s));
|
|
25314
|
+
const exit = deps.exit ?? exitWithCode;
|
|
25315
|
+
let identitySource;
|
|
25316
|
+
try {
|
|
25317
|
+
if (options.status !== void 0 && !LS_STATUSES.includes(options.status)) {
|
|
25318
|
+
throw new UsageError(
|
|
25319
|
+
`invalid --status "${options.status}": must be one of ${LS_STATUSES.join(", ")}`
|
|
25320
|
+
);
|
|
25321
|
+
}
|
|
25322
|
+
const setup = await setupClient2(deps);
|
|
25323
|
+
const client = setup.client;
|
|
25324
|
+
identitySource = setup.identitySource;
|
|
25325
|
+
const rows = await client.listRepoRequests({
|
|
25326
|
+
status: options.status,
|
|
25327
|
+
mine: options.mine ?? false
|
|
25328
|
+
});
|
|
25329
|
+
const status2 = options.status ?? "pending";
|
|
25330
|
+
if (options.json) {
|
|
25331
|
+
emitJson9(
|
|
25332
|
+
buildEnvelope(command, true, {
|
|
25333
|
+
count: rows.length,
|
|
25334
|
+
status: status2,
|
|
25335
|
+
mine: options.mine ?? false,
|
|
25336
|
+
requests: rows,
|
|
25337
|
+
identitySource
|
|
25338
|
+
})
|
|
25339
|
+
);
|
|
25340
|
+
} else {
|
|
25341
|
+
const empty = status2 === "all" ? "No repo requests." : `No ${status2} repo requests.`;
|
|
25342
|
+
message(formatRepoTable(rows, empty));
|
|
25343
|
+
}
|
|
25344
|
+
} catch (err) {
|
|
25345
|
+
const {
|
|
25346
|
+
code,
|
|
25347
|
+
message: msg,
|
|
25348
|
+
kind,
|
|
25349
|
+
requestId
|
|
25350
|
+
} = wrapProxyError(command, err);
|
|
25351
|
+
outputError({ json: options.json, command }, code, msg, {
|
|
25352
|
+
logError: error48,
|
|
25353
|
+
kind,
|
|
25354
|
+
requestId,
|
|
25355
|
+
extras: identitySource ? { identitySource } : void 0
|
|
25356
|
+
});
|
|
25357
|
+
exit(code);
|
|
25358
|
+
}
|
|
25359
|
+
}
|
|
25360
|
+
|
|
25361
|
+
// src/commands/repo/reject.ts
|
|
25362
|
+
async function reject(options, deps = {}) {
|
|
25363
|
+
const command = "repo reject";
|
|
25364
|
+
const success2 = deps.logSuccess ?? ((s) => O2.success(s));
|
|
25365
|
+
const error48 = deps.logError ?? ((s) => O2.error(s));
|
|
25366
|
+
const exit = deps.exit ?? exitWithCode;
|
|
25367
|
+
const prompts = deps.prompts ?? defaultRepoPrompts;
|
|
25368
|
+
const isTTY = deps.isTTY ?? Boolean(process.stdout.isTTY);
|
|
25369
|
+
let identitySource;
|
|
25370
|
+
try {
|
|
25371
|
+
if (!options.id || options.id.trim().length === 0) {
|
|
25372
|
+
throw new UsageError("request id is required (positional argument)");
|
|
25373
|
+
}
|
|
25374
|
+
const setup = await setupClient2(deps);
|
|
25375
|
+
const client = setup.client;
|
|
25376
|
+
identitySource = setup.identitySource;
|
|
25377
|
+
if (!options.json && !options.yes) {
|
|
25378
|
+
if (!isTTY) {
|
|
25379
|
+
throw new UsageError(
|
|
25380
|
+
"non-interactive session: pass --yes to reject without confirmation"
|
|
25381
|
+
);
|
|
25382
|
+
}
|
|
25383
|
+
const cur = await client.getRepoRequest(options.id);
|
|
25384
|
+
const ok = await prompts.confirm({
|
|
25385
|
+
message: `Reject the request for "${cur.name}" by ${cur.requestedBy}?`
|
|
25386
|
+
});
|
|
25387
|
+
if (prompts.isCancel(ok) || ok === false) {
|
|
25388
|
+
throw new ConfirmError("repo reject cancelled");
|
|
25389
|
+
}
|
|
25390
|
+
}
|
|
25391
|
+
const reason = options.reason === void 0 ? void 0 : String(options.reason).trim() || void 0;
|
|
25392
|
+
const row = await client.rejectRepoRequest({
|
|
25393
|
+
id: options.id,
|
|
25394
|
+
reason
|
|
25395
|
+
});
|
|
25396
|
+
if (options.json) {
|
|
25397
|
+
emitJson9(
|
|
25398
|
+
buildEnvelope(command, true, {
|
|
25399
|
+
id: row.id,
|
|
25400
|
+
status: row.status,
|
|
25401
|
+
repo: `${row.owner}/${row.name}`,
|
|
25402
|
+
rejectReason: row.rejectReason,
|
|
25403
|
+
identitySource
|
|
25404
|
+
})
|
|
25405
|
+
);
|
|
25406
|
+
} else {
|
|
25407
|
+
success2(
|
|
25408
|
+
[
|
|
25409
|
+
`Rejected ${row.name}`,
|
|
25410
|
+
``,
|
|
25411
|
+
` Repository: ${row.owner}/${row.name}`,
|
|
25412
|
+
...row.rejectReason ? [` Reason: ${row.rejectReason}`] : []
|
|
25413
|
+
].join("\n")
|
|
25414
|
+
);
|
|
25415
|
+
}
|
|
25416
|
+
} catch (err) {
|
|
25417
|
+
const { code, message, kind, requestId } = wrapProxyError(command, err);
|
|
25418
|
+
outputError({ json: options.json, command }, code, message, {
|
|
25419
|
+
logError: error48,
|
|
25420
|
+
kind,
|
|
25421
|
+
requestId,
|
|
25422
|
+
extras: identitySource ? { identitySource } : void 0
|
|
25423
|
+
});
|
|
25424
|
+
exit(code);
|
|
25425
|
+
}
|
|
25426
|
+
}
|
|
25427
|
+
|
|
25428
|
+
// src/commands/repo/status.ts
|
|
25429
|
+
function humanRow(row) {
|
|
25430
|
+
const lines = [
|
|
25431
|
+
`Request ${row.id}`,
|
|
25432
|
+
``,
|
|
25433
|
+
` Repository: ${row.owner}/${row.name}`,
|
|
25434
|
+
` Visibility: ${row.visibility}`,
|
|
25435
|
+
` Status: ${row.status}`,
|
|
25436
|
+
` Requested by: ${row.requestedBy}`
|
|
25437
|
+
];
|
|
25438
|
+
if (row.template) lines.push(` Template: ${row.template}`);
|
|
25439
|
+
if (row.url) lines.push(` URL: ${row.url}`);
|
|
25440
|
+
if (row.approver) lines.push(` Approver: ${row.approver}`);
|
|
25441
|
+
if (row.rejectReason) lines.push(` Reason: ${row.rejectReason}`);
|
|
25442
|
+
if (row.error) lines.push(` Error: ${row.error}`);
|
|
25443
|
+
lines.push(` Created: ${row.createdAt}`);
|
|
25444
|
+
lines.push(` Updated: ${row.updatedAt}`);
|
|
25445
|
+
return lines.join("\n");
|
|
25446
|
+
}
|
|
25447
|
+
async function status(options, deps = {}) {
|
|
25448
|
+
const command = "repo status";
|
|
25449
|
+
const message = deps.logMessage ?? ((s) => O2.message(s));
|
|
25450
|
+
const error48 = deps.logError ?? ((s) => O2.error(s));
|
|
25451
|
+
const exit = deps.exit ?? exitWithCode;
|
|
25452
|
+
let identitySource;
|
|
25453
|
+
try {
|
|
25454
|
+
if (!options.id || options.id.trim().length === 0) {
|
|
25455
|
+
throw new UsageError("request id is required (positional argument)");
|
|
25456
|
+
}
|
|
25457
|
+
const setup = await setupClient2(deps);
|
|
25458
|
+
const client = setup.client;
|
|
25459
|
+
identitySource = setup.identitySource;
|
|
25460
|
+
const row = await client.getRepoRequest(options.id);
|
|
25461
|
+
if (options.json) {
|
|
25462
|
+
emitJson9(buildEnvelope(command, true, { request: row, identitySource }));
|
|
25463
|
+
} else {
|
|
25464
|
+
message(humanRow(row));
|
|
25465
|
+
}
|
|
25466
|
+
} catch (err) {
|
|
25467
|
+
const {
|
|
25468
|
+
code,
|
|
25469
|
+
message: msg,
|
|
25470
|
+
kind,
|
|
25471
|
+
requestId
|
|
25472
|
+
} = wrapProxyError(command, err);
|
|
25473
|
+
outputError({ json: options.json, command }, code, msg, {
|
|
25474
|
+
logError: error48,
|
|
25475
|
+
kind,
|
|
25476
|
+
requestId,
|
|
25477
|
+
extras: identitySource ? { identitySource } : void 0
|
|
25478
|
+
});
|
|
25479
|
+
exit(code);
|
|
25480
|
+
}
|
|
25481
|
+
}
|
|
25482
|
+
|
|
24624
25483
|
// src/lib/update-notifier.ts
|
|
24625
25484
|
var import_node_fs3 = require("fs");
|
|
24626
25485
|
var import_promises8 = require("fs/promises");
|
|
@@ -24776,7 +25635,7 @@ function installExitNotice(current) {
|
|
|
24776
25635
|
}
|
|
24777
25636
|
|
|
24778
25637
|
// src/cli.ts
|
|
24779
|
-
var version2 = true ? "0.
|
|
25638
|
+
var version2 = true ? "0.8.0" : "0.0.0";
|
|
24780
25639
|
function handleActionError(command, json2, err) {
|
|
24781
25640
|
const ctx = { json: json2, command };
|
|
24782
25641
|
const message = err instanceof Error ? err.message : "unknown error";
|
|
@@ -24793,12 +25652,14 @@ function findFirstPositional(args) {
|
|
|
24793
25652
|
}
|
|
24794
25653
|
function run(argv = process.argv) {
|
|
24795
25654
|
installExitNotice(version2);
|
|
24796
|
-
void refreshIfStale()
|
|
25655
|
+
void refreshIfStale().catch(() => {
|
|
25656
|
+
});
|
|
24797
25657
|
const args = argv.slice(2);
|
|
24798
25658
|
const firstPosIdx = findFirstPositional(args);
|
|
24799
25659
|
const namespace = firstPosIdx >= 0 ? args[firstPosIdx] : void 0;
|
|
24800
25660
|
const isStatic = namespace === "static";
|
|
24801
25661
|
const isSites = namespace === "sites";
|
|
25662
|
+
const isRepo = namespace === "repo";
|
|
24802
25663
|
if (isSites) {
|
|
24803
25664
|
const sitesArgs = [
|
|
24804
25665
|
...args.slice(0, firstPosIdx),
|
|
@@ -24865,6 +25726,136 @@ function run(argv = process.argv) {
|
|
|
24865
25726
|
sitesCli.parse(["node", "universe-sites", ...sitesArgs]);
|
|
24866
25727
|
return;
|
|
24867
25728
|
}
|
|
25729
|
+
if (isRepo) {
|
|
25730
|
+
const repoArgs = [
|
|
25731
|
+
...args.slice(0, firstPosIdx),
|
|
25732
|
+
...args.slice(firstPosIdx + 1)
|
|
25733
|
+
];
|
|
25734
|
+
const repoCli = cac("universe repo");
|
|
25735
|
+
repoCli.command(
|
|
25736
|
+
"create [name]",
|
|
25737
|
+
"Request a new repository under freeCodeCamp-Universe (staff only)"
|
|
25738
|
+
).option("--json", "Output as JSON").option("--visibility <vis>", "public or private (default: private)").option("--description <text>", "Repository description").option(
|
|
25739
|
+
"--template <name>",
|
|
25740
|
+
"Org template repo to generate from; omit for a blank repo"
|
|
25741
|
+
).option("--yes", "Skip confirmation prompts (required for non-TTY/CI)").example("universe repo create my-app --visibility private --yes").action(
|
|
25742
|
+
async (name, flags) => {
|
|
25743
|
+
try {
|
|
25744
|
+
await create({
|
|
25745
|
+
json: flags.json ?? false,
|
|
25746
|
+
name,
|
|
25747
|
+
visibility: flags.visibility,
|
|
25748
|
+
description: flags.description,
|
|
25749
|
+
template: flags.template,
|
|
25750
|
+
yes: flags.yes ?? false
|
|
25751
|
+
});
|
|
25752
|
+
} catch (err) {
|
|
25753
|
+
handleActionError("repo create", flags.json ?? false, err);
|
|
25754
|
+
}
|
|
25755
|
+
}
|
|
25756
|
+
);
|
|
25757
|
+
repoCli.command("ls", "List repo requests (default: pending)").option("--json", "Output as JSON").option(
|
|
25758
|
+
"--status <status>",
|
|
25759
|
+
"pending | approved | active | rejected | failed | all"
|
|
25760
|
+
).option("--mine", "Only requests you submitted").action(
|
|
25761
|
+
async (flags) => {
|
|
25762
|
+
try {
|
|
25763
|
+
await ls3({
|
|
25764
|
+
json: flags.json ?? false,
|
|
25765
|
+
status: flags.status,
|
|
25766
|
+
mine: flags.mine ?? false
|
|
25767
|
+
});
|
|
25768
|
+
} catch (err) {
|
|
25769
|
+
handleActionError("repo ls", flags.json ?? false, err);
|
|
25770
|
+
}
|
|
25771
|
+
}
|
|
25772
|
+
);
|
|
25773
|
+
repoCli.command(
|
|
25774
|
+
"approve <id>",
|
|
25775
|
+
"Approve a pending request \u2014 creates the repo (admin only)"
|
|
25776
|
+
).option("--json", "Output as JSON").option("--yes", "Skip confirmation prompts (required for non-TTY/CI)").example("universe repo approve req_abc123 --yes --json").action(async (id, flags) => {
|
|
25777
|
+
try {
|
|
25778
|
+
await approve({
|
|
25779
|
+
json: flags.json ?? false,
|
|
25780
|
+
id,
|
|
25781
|
+
yes: flags.yes ?? false
|
|
25782
|
+
});
|
|
25783
|
+
} catch (err) {
|
|
25784
|
+
handleActionError("repo approve", flags.json ?? false, err);
|
|
25785
|
+
}
|
|
25786
|
+
});
|
|
25787
|
+
repoCli.command("reject <id>", "Reject a pending request (admin only)").option("--json", "Output as JSON").option("--reason <text>", "Reason shown to the requester").option("--yes", "Skip confirmation prompts (required for non-TTY/CI)").example('universe repo reject req_abc123 --reason "out of scope" --yes').action(
|
|
25788
|
+
async (id, flags) => {
|
|
25789
|
+
try {
|
|
25790
|
+
await reject({
|
|
25791
|
+
json: flags.json ?? false,
|
|
25792
|
+
id,
|
|
25793
|
+
reason: flags.reason,
|
|
25794
|
+
yes: flags.yes ?? false
|
|
25795
|
+
});
|
|
25796
|
+
} catch (err) {
|
|
25797
|
+
handleActionError("repo reject", flags.json ?? false, err);
|
|
25798
|
+
}
|
|
25799
|
+
}
|
|
25800
|
+
);
|
|
25801
|
+
repoCli.command("status <id>", "Show a request's current state").option("--json", "Output as JSON").action(async (id, flags) => {
|
|
25802
|
+
try {
|
|
25803
|
+
await status({ json: flags.json ?? false, id });
|
|
25804
|
+
} catch (err) {
|
|
25805
|
+
handleActionError("repo status", flags.json ?? false, err);
|
|
25806
|
+
}
|
|
25807
|
+
});
|
|
25808
|
+
repoCli.help();
|
|
25809
|
+
repoCli.version(version2);
|
|
25810
|
+
const knownRepoSubs = /* @__PURE__ */ new Set([
|
|
25811
|
+
"create",
|
|
25812
|
+
"ls",
|
|
25813
|
+
"approve",
|
|
25814
|
+
"reject",
|
|
25815
|
+
"status"
|
|
25816
|
+
]);
|
|
25817
|
+
const repoValueFlags = /* @__PURE__ */ new Set([
|
|
25818
|
+
"--visibility",
|
|
25819
|
+
"--description",
|
|
25820
|
+
"--template",
|
|
25821
|
+
"--status",
|
|
25822
|
+
"--reason"
|
|
25823
|
+
]);
|
|
25824
|
+
let repoSub;
|
|
25825
|
+
for (let i = 0; i < repoArgs.length; i += 1) {
|
|
25826
|
+
const a = repoArgs[i];
|
|
25827
|
+
if (a === void 0) continue;
|
|
25828
|
+
if (repoValueFlags.has(a)) {
|
|
25829
|
+
i += 1;
|
|
25830
|
+
continue;
|
|
25831
|
+
}
|
|
25832
|
+
if (!a.startsWith("-")) {
|
|
25833
|
+
repoSub = a;
|
|
25834
|
+
break;
|
|
25835
|
+
}
|
|
25836
|
+
}
|
|
25837
|
+
const repoJson = repoArgs.includes("--json");
|
|
25838
|
+
const repoWantsHelp = repoArgs.includes("--help") || repoArgs.includes("-h") || repoArgs.includes("--version");
|
|
25839
|
+
if (repoSub === void 0 ? !repoWantsHelp : !knownRepoSubs.has(repoSub)) {
|
|
25840
|
+
if (repoSub === void 0 && !repoJson) {
|
|
25841
|
+
repoCli.outputHelp();
|
|
25842
|
+
} else {
|
|
25843
|
+
outputError(
|
|
25844
|
+
{ json: repoJson, command: "repo" },
|
|
25845
|
+
EXIT_USAGE,
|
|
25846
|
+
repoSub === void 0 ? "missing repo subcommand \u2014 run `universe repo --help`" : `unknown repo subcommand "${repoSub}" \u2014 run \`universe repo --help\``
|
|
25847
|
+
);
|
|
25848
|
+
}
|
|
25849
|
+
exitWithCode(EXIT_USAGE);
|
|
25850
|
+
return;
|
|
25851
|
+
}
|
|
25852
|
+
try {
|
|
25853
|
+
repoCli.parse(["node", "universe-repo", ...repoArgs]);
|
|
25854
|
+
} catch (err) {
|
|
25855
|
+
handleActionError("repo", repoJson, err);
|
|
25856
|
+
}
|
|
25857
|
+
return;
|
|
25858
|
+
}
|
|
24868
25859
|
if (isStatic) {
|
|
24869
25860
|
const staticArgs = [
|
|
24870
25861
|
...args.slice(0, firstPosIdx),
|
|
@@ -24948,11 +25939,30 @@ function run(argv = process.argv) {
|
|
|
24948
25939
|
});
|
|
24949
25940
|
cli.command("static <subcommand>", "Static site deployment commands");
|
|
24950
25941
|
cli.command("sites <subcommand>", "Static site registry commands");
|
|
25942
|
+
cli.command(
|
|
25943
|
+
"repo <subcommand>",
|
|
25944
|
+
"Repository creation + approval queue commands"
|
|
25945
|
+
);
|
|
24951
25946
|
cli.help();
|
|
24952
25947
|
cli.version(version2);
|
|
24953
25948
|
cli.parse(argv);
|
|
24954
25949
|
}
|
|
24955
25950
|
}
|
|
24956
25951
|
|
|
25952
|
+
// src/lib/fatal.ts
|
|
25953
|
+
function formatFatal(err) {
|
|
25954
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
25955
|
+
return `universe: ${redact(message)}`;
|
|
25956
|
+
}
|
|
25957
|
+
function defaultOnFatal(err) {
|
|
25958
|
+
process.stderr.write(formatFatal(err) + "\n");
|
|
25959
|
+
process.exit(EXIT_USAGE);
|
|
25960
|
+
}
|
|
25961
|
+
function installFatalHandlers(onFatal = defaultOnFatal) {
|
|
25962
|
+
process.on("unhandledRejection", onFatal);
|
|
25963
|
+
process.on("uncaughtException", onFatal);
|
|
25964
|
+
}
|
|
25965
|
+
|
|
24957
25966
|
// src/index.ts
|
|
25967
|
+
installFatalHandlers();
|
|
24958
25968
|
run();
|