@codevector/cli 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -24
- package/dist/index.js +2403 -1326
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
- package/scripts/postinstall.mjs +140 -0
package/dist/index.js
CHANGED
|
@@ -37,14 +37,14 @@ var require_src = __commonJS({
|
|
|
37
37
|
var CSI2 = `${ESC2}[`;
|
|
38
38
|
var beep = "\x07";
|
|
39
39
|
var cursor = {
|
|
40
|
-
to(
|
|
41
|
-
if (!y) return `${CSI2}${
|
|
42
|
-
return `${CSI2}${y + 1};${
|
|
40
|
+
to(x3, y) {
|
|
41
|
+
if (!y) return `${CSI2}${x3 + 1}G`;
|
|
42
|
+
return `${CSI2}${y + 1};${x3 + 1}H`;
|
|
43
43
|
},
|
|
44
|
-
move(
|
|
44
|
+
move(x3, y) {
|
|
45
45
|
let ret = "";
|
|
46
|
-
if (
|
|
47
|
-
else if (
|
|
46
|
+
if (x3 < 0) ret += `${CSI2}${-x3}D`;
|
|
47
|
+
else if (x3 > 0) ret += `${CSI2}${x3}C`;
|
|
48
48
|
if (y < 0) ret += `${CSI2}${-y}A`;
|
|
49
49
|
else if (y > 0) ret += `${CSI2}${y}B`;
|
|
50
50
|
return ret;
|
|
@@ -163,7 +163,7 @@ function toArray(val) {
|
|
|
163
163
|
function formatLineColumns(lines, linePrefix = "") {
|
|
164
164
|
const maxLength = [];
|
|
165
165
|
for (const line of lines) for (const [i, element] of line.entries()) maxLength[i] = Math.max(maxLength[i] || 0, element.length);
|
|
166
|
-
return lines.map((l) => l.map((
|
|
166
|
+
return lines.map((l) => l.map((c, i) => linePrefix + c[i === 0 ? "padStart" : "padEnd"](maxLength[i])).join(" ")).join("\n");
|
|
167
167
|
}
|
|
168
168
|
function resolveValue(input) {
|
|
169
169
|
return typeof input === "function" ? input() : input;
|
|
@@ -274,7 +274,7 @@ var noColor = /* @__PURE__ */ (() => {
|
|
|
274
274
|
const env = globalThis.process?.env ?? {};
|
|
275
275
|
return env.NO_COLOR === "1" || env.TERM === "dumb" || env.TEST || env.CI;
|
|
276
276
|
})();
|
|
277
|
-
var _c = (
|
|
277
|
+
var _c = (c, r = 39) => (t) => noColor ? t : `\x1B[${c}m${t}\x1B[${r}m`;
|
|
278
278
|
var bold = /* @__PURE__ */ _c(1, 22);
|
|
279
279
|
var cyan = /* @__PURE__ */ _c(36);
|
|
280
280
|
var gray = /* @__PURE__ */ _c(90);
|
|
@@ -552,9 +552,9 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
552
552
|
return [`--${long}`, `-${short}`];
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
-
// ../../node_modules/.pnpm/@clack+core@1.3.
|
|
555
|
+
// ../../node_modules/.pnpm/@clack+core@1.3.1/node_modules/@clack/core/dist/index.mjs
|
|
556
556
|
import { styleText as v } from "util";
|
|
557
|
-
import { stdout as
|
|
557
|
+
import { stdout as x, stdin as D } from "process";
|
|
558
558
|
import * as b from "readline";
|
|
559
559
|
import E from "readline";
|
|
560
560
|
|
|
@@ -570,11 +570,11 @@ var getCodePointsLength = /* @__PURE__ */ (() => {
|
|
|
570
570
|
return input.length - surrogatePairsNr;
|
|
571
571
|
};
|
|
572
572
|
})();
|
|
573
|
-
var isFullWidth = (
|
|
574
|
-
return
|
|
573
|
+
var isFullWidth = (x3) => {
|
|
574
|
+
return x3 === 12288 || x3 >= 65281 && x3 <= 65376 || x3 >= 65504 && x3 <= 65510;
|
|
575
575
|
};
|
|
576
|
-
var isWideNotCJKTNotEmoji = (
|
|
577
|
-
return
|
|
576
|
+
var isWideNotCJKTNotEmoji = (x3) => {
|
|
577
|
+
return x3 === 8987 || x3 === 9001 || x3 >= 12272 && x3 <= 12287 || x3 >= 12289 && x3 <= 12350 || x3 >= 12441 && x3 <= 12543 || x3 >= 12549 && x3 <= 12591 || x3 >= 12593 && x3 <= 12686 || x3 >= 12688 && x3 <= 12771 || x3 >= 12783 && x3 <= 12830 || x3 >= 12832 && x3 <= 12871 || x3 >= 12880 && x3 <= 19903 || x3 >= 65040 && x3 <= 65049 || x3 >= 65072 && x3 <= 65106 || x3 >= 65108 && x3 <= 65126 || x3 >= 65128 && x3 <= 65131 || x3 >= 127488 && x3 <= 127490 || x3 >= 127504 && x3 <= 127547 || x3 >= 127552 && x3 <= 127560 || x3 >= 131072 && x3 <= 196605 || x3 >= 196608 && x3 <= 262141;
|
|
578
578
|
};
|
|
579
579
|
|
|
580
580
|
// ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
|
|
@@ -894,13 +894,13 @@ function wrapAnsi(string4, columns, options) {
|
|
|
894
894
|
return String(string4).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
|
|
895
895
|
}
|
|
896
896
|
|
|
897
|
-
// ../../node_modules/.pnpm/@clack+core@1.3.
|
|
897
|
+
// ../../node_modules/.pnpm/@clack+core@1.3.1/node_modules/@clack/core/dist/index.mjs
|
|
898
898
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
899
899
|
import { ReadStream as O } from "tty";
|
|
900
|
-
function
|
|
900
|
+
function f(r, t, s) {
|
|
901
901
|
if (!s.some((o) => !o.disabled)) return r;
|
|
902
902
|
const e2 = r + t, i = Math.max(s.length - 1, 0), n = e2 < 0 ? i : e2 > i ? 0 : e2;
|
|
903
|
-
return s[n].disabled ?
|
|
903
|
+
return s[n].disabled ? f(n, t < 0 ? -1 : 1, s) : n;
|
|
904
904
|
}
|
|
905
905
|
var G = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
906
906
|
var K = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
@@ -927,7 +927,7 @@ function w(r, t) {
|
|
|
927
927
|
const s = r;
|
|
928
928
|
s.isTTY && s.setRawMode(t);
|
|
929
929
|
}
|
|
930
|
-
function R({ input: r = D, output: t =
|
|
930
|
+
function R({ input: r = D, output: t = x, overwrite: s = true, hideCursor: e2 = true } = {}) {
|
|
931
931
|
const i = b.createInterface({ input: r, output: t, prompt: "", tabSize: 1 });
|
|
932
932
|
b.emitKeypressEvents(r, i), r instanceof O && r.isTTY && r.setRawMode(true);
|
|
933
933
|
const n = (o, { name: u, sequence: a }) => {
|
|
@@ -937,8 +937,8 @@ function R({ input: r = D, output: t = S, overwrite: s = true, hideCursor: e2 =
|
|
|
937
937
|
return;
|
|
938
938
|
}
|
|
939
939
|
if (!s) return;
|
|
940
|
-
const
|
|
941
|
-
b.moveCursor(t,
|
|
940
|
+
const c = u === "return" ? 0 : -1, y = u === "return" ? -1 : 0;
|
|
941
|
+
b.moveCursor(t, c, y, () => {
|
|
942
942
|
b.clearLine(t, 1, () => {
|
|
943
943
|
r.once("keypress", n);
|
|
944
944
|
});
|
|
@@ -950,16 +950,16 @@ function R({ input: r = D, output: t = S, overwrite: s = true, hideCursor: e2 =
|
|
|
950
950
|
}
|
|
951
951
|
var A = (r) => "columns" in r && typeof r.columns == "number" ? r.columns : 80;
|
|
952
952
|
var L = (r) => "rows" in r && typeof r.rows == "number" ? r.rows : 20;
|
|
953
|
-
function W(r, t, s, e2 = s, i) {
|
|
954
|
-
const
|
|
955
|
-
return wrapAnsi(t,
|
|
956
|
-
`).map((
|
|
957
|
-
const
|
|
958
|
-
return
|
|
953
|
+
function W(r, t, s, e2 = s, i = s, n) {
|
|
954
|
+
const o = A(r ?? x);
|
|
955
|
+
return wrapAnsi(t, o - s.length, { hard: true, trim: false }).split(`
|
|
956
|
+
`).map((u, a, l) => {
|
|
957
|
+
const c = n ? n(u, a) : u;
|
|
958
|
+
return a === 0 ? `${e2}${c}` : a === l.length - 1 ? `${i}${c}` : `${s}${c}`;
|
|
959
959
|
}).join(`
|
|
960
960
|
`);
|
|
961
961
|
}
|
|
962
|
-
var
|
|
962
|
+
var m = class {
|
|
963
963
|
input;
|
|
964
964
|
output;
|
|
965
965
|
_abortSignal;
|
|
@@ -975,7 +975,7 @@ var p = class {
|
|
|
975
975
|
value;
|
|
976
976
|
userInput = "";
|
|
977
977
|
constructor(t, s = true) {
|
|
978
|
-
const { input: e2 = D, output: i =
|
|
978
|
+
const { input: e2 = D, output: i = x, render: n, signal: o, ...u } = t;
|
|
979
979
|
this.opts = u, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = n.bind(this), this._track = s, this._abortSignal = o, this.input = e2, this.output = i;
|
|
980
980
|
}
|
|
981
981
|
unsubscribe() {
|
|
@@ -1084,7 +1084,24 @@ var p = class {
|
|
|
1084
1084
|
}
|
|
1085
1085
|
}
|
|
1086
1086
|
};
|
|
1087
|
-
var
|
|
1087
|
+
var X = class extends m {
|
|
1088
|
+
get cursor() {
|
|
1089
|
+
return this.value ? 0 : 1;
|
|
1090
|
+
}
|
|
1091
|
+
get _value() {
|
|
1092
|
+
return this.cursor === 0;
|
|
1093
|
+
}
|
|
1094
|
+
constructor(t) {
|
|
1095
|
+
super(t, false), this.value = !!t.initialValue, this.on("userInput", () => {
|
|
1096
|
+
this.value = this._value;
|
|
1097
|
+
}), this.on("confirm", (s) => {
|
|
1098
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
|
|
1099
|
+
}), this.on("cursor", () => {
|
|
1100
|
+
this.value = !this.value;
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
var nt = class extends m {
|
|
1088
1105
|
options;
|
|
1089
1106
|
cursor = 0;
|
|
1090
1107
|
get _value() {
|
|
@@ -1111,17 +1128,17 @@ var nt = class extends p {
|
|
|
1111
1128
|
constructor(t) {
|
|
1112
1129
|
super(t, false), this.options = t.options, this.value = [...t.initialValues ?? []];
|
|
1113
1130
|
const s = Math.max(this.options.findIndex(({ value: e2 }) => e2 === t.cursorAt), 0);
|
|
1114
|
-
this.cursor = this.options[s].disabled ?
|
|
1131
|
+
this.cursor = this.options[s].disabled ? f(s, 1, this.options) : s, this.on("key", (e2) => {
|
|
1115
1132
|
e2 === "a" && this.toggleAll(), e2 === "i" && this.toggleInvert();
|
|
1116
1133
|
}), this.on("cursor", (e2) => {
|
|
1117
1134
|
switch (e2) {
|
|
1118
1135
|
case "left":
|
|
1119
1136
|
case "up":
|
|
1120
|
-
this.cursor =
|
|
1137
|
+
this.cursor = f(this.cursor, -1, this.options);
|
|
1121
1138
|
break;
|
|
1122
1139
|
case "down":
|
|
1123
1140
|
case "right":
|
|
1124
|
-
this.cursor =
|
|
1141
|
+
this.cursor = f(this.cursor, 1, this.options);
|
|
1125
1142
|
break;
|
|
1126
1143
|
case "space":
|
|
1127
1144
|
this.toggleValue();
|
|
@@ -1130,7 +1147,7 @@ var nt = class extends p {
|
|
|
1130
1147
|
});
|
|
1131
1148
|
}
|
|
1132
1149
|
};
|
|
1133
|
-
var ot = class extends
|
|
1150
|
+
var ot = class extends m {
|
|
1134
1151
|
_mask = "\u2022";
|
|
1135
1152
|
get cursor() {
|
|
1136
1153
|
return this._cursor;
|
|
@@ -1154,7 +1171,7 @@ var ot = class extends p {
|
|
|
1154
1171
|
});
|
|
1155
1172
|
}
|
|
1156
1173
|
};
|
|
1157
|
-
var ut = class extends
|
|
1174
|
+
var ut = class extends m {
|
|
1158
1175
|
options;
|
|
1159
1176
|
cursor = 0;
|
|
1160
1177
|
get _selectedValue() {
|
|
@@ -1166,22 +1183,22 @@ var ut = class extends p {
|
|
|
1166
1183
|
constructor(t) {
|
|
1167
1184
|
super(t, false), this.options = t.options;
|
|
1168
1185
|
const s = this.options.findIndex(({ value: i }) => i === t.initialValue), e2 = s === -1 ? 0 : s;
|
|
1169
|
-
this.cursor = this.options[e2].disabled ?
|
|
1186
|
+
this.cursor = this.options[e2].disabled ? f(e2, 1, this.options) : e2, this.changeValue(), this.on("cursor", (i) => {
|
|
1170
1187
|
switch (i) {
|
|
1171
1188
|
case "left":
|
|
1172
1189
|
case "up":
|
|
1173
|
-
this.cursor =
|
|
1190
|
+
this.cursor = f(this.cursor, -1, this.options);
|
|
1174
1191
|
break;
|
|
1175
1192
|
case "down":
|
|
1176
1193
|
case "right":
|
|
1177
|
-
this.cursor =
|
|
1194
|
+
this.cursor = f(this.cursor, 1, this.options);
|
|
1178
1195
|
break;
|
|
1179
1196
|
}
|
|
1180
1197
|
this.changeValue();
|
|
1181
1198
|
});
|
|
1182
1199
|
}
|
|
1183
1200
|
};
|
|
1184
|
-
var ht = class extends
|
|
1201
|
+
var ht = class extends m {
|
|
1185
1202
|
get userInputWithCursor() {
|
|
1186
1203
|
if (this.state === "submit") return this.userInput;
|
|
1187
1204
|
const t = this.userInput;
|
|
@@ -1201,54 +1218,54 @@ var ht = class extends p {
|
|
|
1201
1218
|
}
|
|
1202
1219
|
};
|
|
1203
1220
|
|
|
1204
|
-
// ../../node_modules/.pnpm/@clack+prompts@1.
|
|
1221
|
+
// ../../node_modules/.pnpm/@clack+prompts@1.4.0/node_modules/@clack/prompts/dist/index.mjs
|
|
1205
1222
|
import { styleText as e, stripVTControlCharacters as nt2 } from "util";
|
|
1206
|
-
import
|
|
1223
|
+
import V2 from "process";
|
|
1207
1224
|
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
1208
|
-
import { existsSync as
|
|
1209
|
-
import { dirname as bt, join as
|
|
1210
|
-
function
|
|
1211
|
-
return
|
|
1212
|
-
}
|
|
1213
|
-
var tt =
|
|
1214
|
-
var
|
|
1215
|
-
var w2 = (t,
|
|
1216
|
-
var
|
|
1217
|
-
var
|
|
1225
|
+
import { existsSync as Qt, lstatSync as wt, readdirSync as Zt } from "fs";
|
|
1226
|
+
import { dirname as bt, join as te } from "path";
|
|
1227
|
+
function ee() {
|
|
1228
|
+
return V2.platform !== "win32" ? V2.env.TERM !== "linux" : !!V2.env.CI || !!V2.env.WT_SESSION || !!V2.env.TERMINUS_SUBLIME || V2.env.ConEmuTask === "{cmd::Cmder}" || V2.env.TERM_PROGRAM === "Terminus-Sublime" || V2.env.TERM_PROGRAM === "vscode" || V2.env.TERM === "xterm-256color" || V2.env.TERM === "alacritty" || V2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
1229
|
+
}
|
|
1230
|
+
var tt = ee();
|
|
1231
|
+
var ot2 = () => process.env.CI === "true";
|
|
1232
|
+
var w2 = (t, i) => tt ? t : i;
|
|
1233
|
+
var Tt = w2("\u25C6", "*");
|
|
1234
|
+
var at2 = w2("\u25A0", "x");
|
|
1218
1235
|
var ut2 = w2("\u25B2", "x");
|
|
1219
|
-
var
|
|
1236
|
+
var H = w2("\u25C7", "o");
|
|
1220
1237
|
var lt = w2("\u250C", "T");
|
|
1221
1238
|
var $ = w2("\u2502", "|");
|
|
1222
|
-
var
|
|
1223
|
-
var
|
|
1224
|
-
var
|
|
1239
|
+
var x2 = w2("\u2514", "\u2014");
|
|
1240
|
+
var _t = w2("\u2510", "T");
|
|
1241
|
+
var xt = w2("\u2518", "\u2014");
|
|
1225
1242
|
var z2 = w2("\u25CF", ">");
|
|
1226
|
-
var
|
|
1243
|
+
var U = w2("\u25CB", " ");
|
|
1227
1244
|
var et2 = w2("\u25FB", "[\u2022]");
|
|
1228
|
-
var
|
|
1229
|
-
var
|
|
1230
|
-
var
|
|
1245
|
+
var K2 = w2("\u25FC", "[+]");
|
|
1246
|
+
var Y2 = w2("\u25FB", "[ ]");
|
|
1247
|
+
var Et = w2("\u25AA", "\u2022");
|
|
1231
1248
|
var st = w2("\u2500", "-");
|
|
1232
1249
|
var ct = w2("\u256E", "+");
|
|
1233
|
-
var
|
|
1250
|
+
var Gt = w2("\u251C", "+");
|
|
1234
1251
|
var $t = w2("\u256F", "+");
|
|
1235
1252
|
var dt = w2("\u2570", "+");
|
|
1236
|
-
var
|
|
1253
|
+
var Mt = w2("\u256D", "+");
|
|
1237
1254
|
var ht2 = w2("\u25CF", "\u2022");
|
|
1238
1255
|
var pt = w2("\u25C6", "*");
|
|
1239
1256
|
var mt = w2("\u25B2", "!");
|
|
1240
1257
|
var gt = w2("\u25A0", "x");
|
|
1241
|
-
var
|
|
1258
|
+
var P = (t) => {
|
|
1242
1259
|
switch (t) {
|
|
1243
1260
|
case "initial":
|
|
1244
1261
|
case "active":
|
|
1245
|
-
return e("cyan",
|
|
1262
|
+
return e("cyan", Tt);
|
|
1246
1263
|
case "cancel":
|
|
1247
|
-
return e("red",
|
|
1264
|
+
return e("red", at2);
|
|
1248
1265
|
case "error":
|
|
1249
1266
|
return e("yellow", ut2);
|
|
1250
1267
|
case "submit":
|
|
1251
|
-
return e("green",
|
|
1268
|
+
return e("green", H);
|
|
1252
1269
|
}
|
|
1253
1270
|
};
|
|
1254
1271
|
var yt = (t) => {
|
|
@@ -1264,247 +1281,274 @@ var yt = (t) => {
|
|
|
1264
1281
|
return e("green", $);
|
|
1265
1282
|
}
|
|
1266
1283
|
};
|
|
1267
|
-
var
|
|
1268
|
-
let
|
|
1269
|
-
for (let
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
}
|
|
1273
|
-
return { lineCount: n, removals: o };
|
|
1284
|
+
var Ot = (t, i, s, r, u, n = false) => {
|
|
1285
|
+
let a = i, c = 0;
|
|
1286
|
+
if (n) for (let o = r - 1; o >= s && (a -= t[o].length, c++, !(a <= u)); o--) ;
|
|
1287
|
+
else for (let o = s; o < r && (a -= t[o].length, c++, !(a <= u)); o++) ;
|
|
1288
|
+
return { lineCount: a, removals: c };
|
|
1274
1289
|
};
|
|
1275
|
-
var
|
|
1276
|
-
const
|
|
1290
|
+
var F = ({ cursor: t, options: i, style: s, output: r = process.stdout, maxItems: u = Number.POSITIVE_INFINITY, columnPadding: n = 0, rowPadding: a = 4 }) => {
|
|
1291
|
+
const c = A(r) - n, o = L(r), l = e("dim", "..."), d = Math.max(o - a, 0), g = Math.max(Math.min(u, d), 5);
|
|
1277
1292
|
let p2 = 0;
|
|
1278
|
-
t >=
|
|
1279
|
-
let
|
|
1280
|
-
const
|
|
1281
|
-
let
|
|
1282
|
-
|
|
1283
|
-
const v2 = p2 + (
|
|
1284
|
-
for (let b2 = v2; b2 <
|
|
1285
|
-
const G2 = wrapAnsi(s(
|
|
1293
|
+
t >= g - 3 && (p2 = Math.max(Math.min(t - g + 3, i.length - g), 0));
|
|
1294
|
+
let f2 = g < i.length && p2 > 0, h2 = g < i.length && p2 + g < i.length;
|
|
1295
|
+
const I = Math.min(p2 + g, i.length), m2 = [];
|
|
1296
|
+
let y = 0;
|
|
1297
|
+
f2 && y++, h2 && y++;
|
|
1298
|
+
const v2 = p2 + (f2 ? 1 : 0), C2 = I - (h2 ? 1 : 0);
|
|
1299
|
+
for (let b2 = v2; b2 < C2; b2++) {
|
|
1300
|
+
const G2 = wrapAnsi(s(i[b2], b2 === t), c, { hard: true, trim: false }).split(`
|
|
1286
1301
|
`);
|
|
1287
|
-
|
|
1288
|
-
}
|
|
1289
|
-
if (
|
|
1290
|
-
let b2 = 0, G2 = 0,
|
|
1291
|
-
const
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1302
|
+
m2.push(G2), y += G2.length;
|
|
1303
|
+
}
|
|
1304
|
+
if (y > d) {
|
|
1305
|
+
let b2 = 0, G2 = 0, M = y;
|
|
1306
|
+
const N = t - v2;
|
|
1307
|
+
let O2 = d;
|
|
1308
|
+
const j2 = () => Ot(m2, M, 0, N, O2), k2 = () => Ot(m2, M, N + 1, m2.length, O2, true);
|
|
1309
|
+
f2 ? ({ lineCount: M, removals: b2 } = j2(), M > O2 && (h2 || (O2 -= 1), { lineCount: M, removals: G2 } = k2())) : (h2 || (O2 -= 1), { lineCount: M, removals: G2 } = k2(), M > O2 && (O2 -= 1, { lineCount: M, removals: b2 } = j2())), b2 > 0 && (f2 = true, m2.splice(0, b2)), G2 > 0 && (h2 = true, m2.splice(m2.length - G2, G2));
|
|
1310
|
+
}
|
|
1311
|
+
const S = [];
|
|
1312
|
+
f2 && S.push(l);
|
|
1313
|
+
for (const b2 of m2) for (const G2 of b2) S.push(G2);
|
|
1314
|
+
return h2 && S.push(l), S;
|
|
1315
|
+
};
|
|
1316
|
+
var ue = (t) => {
|
|
1317
|
+
const i = t.active ?? "Yes", s = t.inactive ?? "No";
|
|
1318
|
+
return new X({ active: i, inactive: s, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue ?? true, render() {
|
|
1319
|
+
const r = t.withGuide ?? h.withGuide, u = `${P(this.state)} `, n = r ? `${e("gray", $)} ` : "", a = W(t.output, t.message, n, u), c = `${r ? `${e("gray", $)}
|
|
1320
|
+
` : ""}${a}
|
|
1321
|
+
`, o = this.value ? i : s;
|
|
1322
|
+
switch (this.state) {
|
|
1323
|
+
case "submit": {
|
|
1324
|
+
const l = r ? `${e("gray", $)} ` : "";
|
|
1325
|
+
return `${c}${l}${e("dim", o)}`;
|
|
1326
|
+
}
|
|
1327
|
+
case "cancel": {
|
|
1328
|
+
const l = r ? `${e("gray", $)} ` : "";
|
|
1329
|
+
return `${c}${l}${e(["strikethrough", "dim"], o)}${r ? `
|
|
1330
|
+
${e("gray", $)}` : ""}`;
|
|
1331
|
+
}
|
|
1332
|
+
default: {
|
|
1333
|
+
const l = r ? `${e("cyan", $)} ` : "", d = r ? e("cyan", x2) : "";
|
|
1334
|
+
return `${c}${l}${this.value ? `${e("green", z2)} ${i}` : `${e("dim", U)} ${e("dim", i)}`}${t.vertical ? r ? `
|
|
1335
|
+
${e("cyan", $)} ` : `
|
|
1336
|
+
` : ` ${e("dim", "/")} `}${this.value ? `${e("dim", U)} ${e("dim", s)}` : `${e("green", z2)} ${s}`}
|
|
1337
|
+
${d}
|
|
1338
|
+
`;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
} }).prompt();
|
|
1298
1342
|
};
|
|
1299
|
-
var R2 = { message: (t = [], { symbol:
|
|
1300
|
-
const
|
|
1301
|
-
for (let p2 = 0; p2 < u; p2++)
|
|
1302
|
-
const
|
|
1343
|
+
var R2 = { message: (t = [], { symbol: i = e("gray", $), secondarySymbol: s = e("gray", $), output: r = process.stdout, spacing: u = 1, withGuide: n } = {}) => {
|
|
1344
|
+
const a = [], c = n ?? h.withGuide, o = c ? s : "", l = c ? `${i} ` : "", d = c ? `${s} ` : "";
|
|
1345
|
+
for (let p2 = 0; p2 < u; p2++) a.push(o);
|
|
1346
|
+
const g = Array.isArray(t) ? t : t.split(`
|
|
1303
1347
|
`);
|
|
1304
|
-
if (
|
|
1305
|
-
const [p2, ...
|
|
1306
|
-
p2.length > 0 ?
|
|
1307
|
-
for (const
|
|
1348
|
+
if (g.length > 0) {
|
|
1349
|
+
const [p2, ...f2] = g;
|
|
1350
|
+
p2.length > 0 ? a.push(`${l}${p2}`) : a.push(c ? i : "");
|
|
1351
|
+
for (const h2 of f2) h2.length > 0 ? a.push(`${d}${h2}`) : a.push(c ? s : "");
|
|
1308
1352
|
}
|
|
1309
|
-
|
|
1353
|
+
r.write(`${a.join(`
|
|
1310
1354
|
`)}
|
|
1311
1355
|
`);
|
|
1312
|
-
}, info: (t,
|
|
1313
|
-
R2.message(t, { ...
|
|
1314
|
-
}, success: (t,
|
|
1315
|
-
R2.message(t, { ...
|
|
1316
|
-
}, step: (t,
|
|
1317
|
-
R2.message(t, { ...
|
|
1318
|
-
}, warn: (t,
|
|
1319
|
-
R2.message(t, { ...
|
|
1320
|
-
}, warning: (t,
|
|
1321
|
-
R2.warn(t,
|
|
1322
|
-
}, error: (t,
|
|
1323
|
-
R2.message(t, { ...
|
|
1356
|
+
}, info: (t, i) => {
|
|
1357
|
+
R2.message(t, { ...i, symbol: e("blue", ht2) });
|
|
1358
|
+
}, success: (t, i) => {
|
|
1359
|
+
R2.message(t, { ...i, symbol: e("green", pt) });
|
|
1360
|
+
}, step: (t, i) => {
|
|
1361
|
+
R2.message(t, { ...i, symbol: e("green", H) });
|
|
1362
|
+
}, warn: (t, i) => {
|
|
1363
|
+
R2.message(t, { ...i, symbol: e("yellow", mt) });
|
|
1364
|
+
}, warning: (t, i) => {
|
|
1365
|
+
R2.warn(t, i);
|
|
1366
|
+
}, error: (t, i) => {
|
|
1367
|
+
R2.message(t, { ...i, symbol: e("red", gt) });
|
|
1324
1368
|
} };
|
|
1325
|
-
var me = (t = "",
|
|
1326
|
-
const s =
|
|
1327
|
-
s.write(`${
|
|
1369
|
+
var me = (t = "", i) => {
|
|
1370
|
+
const s = i?.output ?? process.stdout, r = i?.withGuide ?? h.withGuide ? `${e("gray", x2)} ` : "";
|
|
1371
|
+
s.write(`${r}${e("red", t)}
|
|
1328
1372
|
|
|
1329
1373
|
`);
|
|
1330
1374
|
};
|
|
1331
|
-
var ge = (t = "",
|
|
1332
|
-
const s =
|
|
1333
|
-
s.write(`${
|
|
1375
|
+
var ge = (t = "", i) => {
|
|
1376
|
+
const s = i?.output ?? process.stdout, r = i?.withGuide ?? h.withGuide ? `${e("gray", lt)} ` : "";
|
|
1377
|
+
s.write(`${r}${t}
|
|
1334
1378
|
`);
|
|
1335
1379
|
};
|
|
1336
|
-
var ye = (t = "",
|
|
1337
|
-
const s =
|
|
1338
|
-
${e("gray",
|
|
1339
|
-
s.write(`${
|
|
1380
|
+
var ye = (t = "", i) => {
|
|
1381
|
+
const s = i?.output ?? process.stdout, r = i?.withGuide ?? h.withGuide ? `${e("gray", $)}
|
|
1382
|
+
${e("gray", x2)} ` : "";
|
|
1383
|
+
s.write(`${r}${t}
|
|
1340
1384
|
|
|
1341
1385
|
`);
|
|
1342
1386
|
};
|
|
1343
|
-
var Q2 = (t,
|
|
1344
|
-
`).map((s) =>
|
|
1387
|
+
var Q2 = (t, i) => t.split(`
|
|
1388
|
+
`).map((s) => i(s)).join(`
|
|
1345
1389
|
`);
|
|
1346
1390
|
var ve = (t) => {
|
|
1347
|
-
const
|
|
1348
|
-
const n =
|
|
1349
|
-
return u === "disabled" ? `${e("gray",
|
|
1391
|
+
const i = (r, u) => {
|
|
1392
|
+
const n = r.label ?? String(r.value);
|
|
1393
|
+
return u === "disabled" ? `${e("gray", Y2)} ${Q2(n, (a) => e(["strikethrough", "gray"], a))}${r.hint ? ` ${e("dim", `(${r.hint ?? "disabled"})`)}` : ""}` : u === "active" ? `${e("cyan", et2)} ${n}${r.hint ? ` ${e("dim", `(${r.hint})`)}` : ""}` : u === "selected" ? `${e("green", K2)} ${Q2(n, (a) => e("dim", a))}${r.hint ? ` ${e("dim", `(${r.hint})`)}` : ""}` : u === "cancelled" ? `${Q2(n, (a) => e(["strikethrough", "dim"], a))}` : u === "active-selected" ? `${e("green", K2)} ${n}${r.hint ? ` ${e("dim", `(${r.hint})`)}` : ""}` : u === "submitted" ? `${Q2(n, (a) => e("dim", a))}` : `${e("dim", Y2)} ${Q2(n, (a) => e("dim", a))}`;
|
|
1350
1394
|
}, s = t.required ?? true;
|
|
1351
|
-
return new nt({ options: t.options, signal: t.signal, input: t.input, output: t.output, initialValues: t.initialValues, required: s, cursorAt: t.cursorAt, validate(
|
|
1352
|
-
if (s && (
|
|
1395
|
+
return new nt({ options: t.options, signal: t.signal, input: t.input, output: t.output, initialValues: t.initialValues, required: s, cursorAt: t.cursorAt, validate(r) {
|
|
1396
|
+
if (s && (r === void 0 || r.length === 0)) return `Please select at least one option.
|
|
1353
1397
|
${e("reset", e("dim", `Press ${e(["gray", "bgWhite", "inverse"], " space ")} to select, ${e("gray", e("bgWhite", e("inverse", " enter ")))} to submit`))}`;
|
|
1354
1398
|
}, render() {
|
|
1355
|
-
const
|
|
1399
|
+
const r = t.withGuide ?? h.withGuide, u = W(t.output, t.message, r ? `${yt(this.state)} ` : "", `${P(this.state)} `), n = `${r ? `${e("gray", $)}
|
|
1356
1400
|
` : ""}${u}
|
|
1357
|
-
`,
|
|
1358
|
-
if (
|
|
1359
|
-
const
|
|
1360
|
-
return l &&
|
|
1401
|
+
`, a = this.value ?? [], c = (o, l) => {
|
|
1402
|
+
if (o.disabled) return i(o, "disabled");
|
|
1403
|
+
const d = a.includes(o.value);
|
|
1404
|
+
return l && d ? i(o, "active-selected") : d ? i(o, "selected") : i(o, l ? "active" : "inactive");
|
|
1361
1405
|
};
|
|
1362
1406
|
switch (this.state) {
|
|
1363
1407
|
case "submit": {
|
|
1364
|
-
const
|
|
1408
|
+
const o = this.options.filter(({ value: d }) => a.includes(d)).map((d) => i(d, "submitted")).join(e("dim", ", ")) || e("dim", "none"), l = W(t.output, o, r ? `${e("gray", $)} ` : "");
|
|
1365
1409
|
return `${n}${l}`;
|
|
1366
1410
|
}
|
|
1367
1411
|
case "cancel": {
|
|
1368
|
-
const
|
|
1369
|
-
if (
|
|
1370
|
-
const l = W(t.output,
|
|
1371
|
-
return `${n}${l}${
|
|
1412
|
+
const o = this.options.filter(({ value: d }) => a.includes(d)).map((d) => i(d, "cancelled")).join(e("dim", ", "));
|
|
1413
|
+
if (o.trim() === "") return `${n}${e("gray", $)}`;
|
|
1414
|
+
const l = W(t.output, o, r ? `${e("gray", $)} ` : "");
|
|
1415
|
+
return `${n}${l}${r ? `
|
|
1372
1416
|
${e("gray", $)}` : ""}`;
|
|
1373
1417
|
}
|
|
1374
1418
|
case "error": {
|
|
1375
|
-
const
|
|
1376
|
-
`).map((p2,
|
|
1377
|
-
`),
|
|
1378
|
-
`).length,
|
|
1419
|
+
const o = r ? `${e("yellow", $)} ` : "", l = this.error.split(`
|
|
1420
|
+
`).map((p2, f2) => f2 === 0 ? `${r ? `${e("yellow", x2)} ` : ""}${e("yellow", p2)}` : ` ${p2}`).join(`
|
|
1421
|
+
`), d = n.split(`
|
|
1422
|
+
`).length, g = l.split(`
|
|
1379
1423
|
`).length + 1;
|
|
1380
|
-
return `${n}${
|
|
1381
|
-
${
|
|
1424
|
+
return `${n}${o}${F({ output: t.output, options: this.options, cursor: this.cursor, maxItems: t.maxItems, columnPadding: o.length, rowPadding: d + g, style: c }).join(`
|
|
1425
|
+
${o}`)}
|
|
1382
1426
|
${l}
|
|
1383
1427
|
`;
|
|
1384
1428
|
}
|
|
1385
1429
|
default: {
|
|
1386
|
-
const
|
|
1387
|
-
`).length,
|
|
1388
|
-
return `${n}${
|
|
1389
|
-
${
|
|
1390
|
-
${
|
|
1430
|
+
const o = r ? `${e("cyan", $)} ` : "", l = n.split(`
|
|
1431
|
+
`).length, d = r ? 2 : 1;
|
|
1432
|
+
return `${n}${o}${F({ output: t.output, options: this.options, cursor: this.cursor, maxItems: t.maxItems, columnPadding: o.length, rowPadding: l + d, style: c }).join(`
|
|
1433
|
+
${o}`)}
|
|
1434
|
+
${r ? e("cyan", x2) : ""}
|
|
1391
1435
|
`;
|
|
1392
1436
|
}
|
|
1393
1437
|
}
|
|
1394
1438
|
} }).prompt();
|
|
1395
1439
|
};
|
|
1396
1440
|
var we = (t) => e("dim", t);
|
|
1397
|
-
var be = (t,
|
|
1398
|
-
const
|
|
1399
|
-
`), n = u.reduce((
|
|
1400
|
-
return wrapAnsi(t,
|
|
1441
|
+
var be = (t, i, s) => {
|
|
1442
|
+
const r = { hard: true, trim: false }, u = wrapAnsi(t, i, r).split(`
|
|
1443
|
+
`), n = u.reduce((o, l) => Math.max(dist_default2(l), o), 0), a = u.map(s).reduce((o, l) => Math.max(dist_default2(l), o), 0), c = i - (a - n);
|
|
1444
|
+
return wrapAnsi(t, c, r);
|
|
1401
1445
|
};
|
|
1402
|
-
var Se = (t = "",
|
|
1403
|
-
const
|
|
1404
|
-
`).map(n), ""],
|
|
1405
|
-
const
|
|
1406
|
-
return
|
|
1407
|
-
}, 0),
|
|
1408
|
-
`),
|
|
1409
|
-
` : "",
|
|
1410
|
-
|
|
1446
|
+
var Se = (t = "", i = "", s) => {
|
|
1447
|
+
const r = s?.output ?? V2.stdout, u = s?.withGuide ?? h.withGuide, n = s?.format ?? we, a = ["", ...be(t, A(r) - 6, n).split(`
|
|
1448
|
+
`).map(n), ""], c = dist_default2(i), o = Math.max(a.reduce((p2, f2) => {
|
|
1449
|
+
const h2 = dist_default2(f2);
|
|
1450
|
+
return h2 > p2 ? h2 : p2;
|
|
1451
|
+
}, 0), c) + 2, l = a.map((p2) => `${e("gray", $)} ${p2}${" ".repeat(o - dist_default2(p2))}${e("gray", $)}`).join(`
|
|
1452
|
+
`), d = u ? `${e("gray", $)}
|
|
1453
|
+
` : "", g = u ? Gt : dt;
|
|
1454
|
+
r.write(`${d}${e("green", H)} ${e("reset", i)} ${e("gray", st.repeat(Math.max(o - c - 1, 1)) + ct)}
|
|
1411
1455
|
${l}
|
|
1412
|
-
${e("gray",
|
|
1456
|
+
${e("gray", g + st.repeat(o + 2) + $t)}
|
|
1413
1457
|
`);
|
|
1414
1458
|
};
|
|
1415
|
-
var Ce = (t) => new ot({ validate: t.validate, mask: t.mask ??
|
|
1416
|
-
const
|
|
1417
|
-
` : ""}${
|
|
1418
|
-
`,
|
|
1459
|
+
var Ce = (t) => new ot({ validate: t.validate, mask: t.mask ?? Et, signal: t.signal, input: t.input, output: t.output, render() {
|
|
1460
|
+
const i = t.withGuide ?? h.withGuide, s = `${i ? `${e("gray", $)}
|
|
1461
|
+
` : ""}${P(this.state)} ${t.message}
|
|
1462
|
+
`, r = this.userInputWithCursor, u = this.masked;
|
|
1419
1463
|
switch (this.state) {
|
|
1420
1464
|
case "error": {
|
|
1421
|
-
const n =
|
|
1465
|
+
const n = i ? `${e("yellow", $)} ` : "", a = i ? `${e("yellow", x2)} ` : "", c = u ?? "";
|
|
1422
1466
|
return t.clearOnError && this.clear(), `${s.trim()}
|
|
1423
|
-
${n}${
|
|
1424
|
-
${
|
|
1467
|
+
${n}${c}
|
|
1468
|
+
${a}${e("yellow", this.error)}
|
|
1425
1469
|
`;
|
|
1426
1470
|
}
|
|
1427
1471
|
case "submit": {
|
|
1428
|
-
const n =
|
|
1429
|
-
return `${s}${n}${
|
|
1472
|
+
const n = i ? `${e("gray", $)} ` : "", a = u ? e("dim", u) : "";
|
|
1473
|
+
return `${s}${n}${a}`;
|
|
1430
1474
|
}
|
|
1431
1475
|
case "cancel": {
|
|
1432
|
-
const n =
|
|
1433
|
-
return `${s}${n}${
|
|
1476
|
+
const n = i ? `${e("gray", $)} ` : "", a = u ? e(["strikethrough", "dim"], u) : "";
|
|
1477
|
+
return `${s}${n}${a}${u && i ? `
|
|
1434
1478
|
${e("gray", $)}` : ""}`;
|
|
1435
1479
|
}
|
|
1436
1480
|
default: {
|
|
1437
|
-
const n =
|
|
1438
|
-
return `${s}${n}${
|
|
1439
|
-
${
|
|
1481
|
+
const n = i ? `${e("cyan", $)} ` : "", a = i ? e("cyan", x2) : "";
|
|
1482
|
+
return `${s}${n}${r}
|
|
1483
|
+
${a}
|
|
1440
1484
|
`;
|
|
1441
1485
|
}
|
|
1442
1486
|
}
|
|
1443
1487
|
} }).prompt();
|
|
1444
|
-
var
|
|
1445
|
-
var ft = ({ indicator: t = "dots", onCancel:
|
|
1446
|
-
const l =
|
|
1447
|
-
let
|
|
1448
|
-
const
|
|
1449
|
-
const
|
|
1450
|
-
|
|
1451
|
-
},
|
|
1452
|
-
process.on("uncaughtExceptionMonitor",
|
|
1453
|
-
},
|
|
1454
|
-
process.removeListener("uncaughtExceptionMonitor",
|
|
1455
|
-
},
|
|
1456
|
-
if (
|
|
1488
|
+
var Te = (t) => e("magenta", t);
|
|
1489
|
+
var ft = ({ indicator: t = "dots", onCancel: i, output: s = process.stdout, cancelMessage: r, errorMessage: u, frames: n = tt ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], delay: a = tt ? 80 : 120, signal: c, ...o } = {}) => {
|
|
1490
|
+
const l = ot2();
|
|
1491
|
+
let d, g, p2 = false, f2 = false, h2 = "", I, m2 = performance.now();
|
|
1492
|
+
const y = A(s), v2 = o?.styleFrame ?? Te, C2 = (_) => {
|
|
1493
|
+
const A2 = _ > 1 ? u ?? h.messages.error : r ?? h.messages.cancel;
|
|
1494
|
+
f2 = _ === 1, p2 && (W2(A2, _), f2 && typeof i == "function" && i());
|
|
1495
|
+
}, S = () => C2(2), b2 = () => C2(1), G2 = () => {
|
|
1496
|
+
process.on("uncaughtExceptionMonitor", S), process.on("unhandledRejection", S), process.on("SIGINT", b2), process.on("SIGTERM", b2), process.on("exit", C2), c && c.addEventListener("abort", b2);
|
|
1497
|
+
}, M = () => {
|
|
1498
|
+
process.removeListener("uncaughtExceptionMonitor", S), process.removeListener("unhandledRejection", S), process.removeListener("SIGINT", b2), process.removeListener("SIGTERM", b2), process.removeListener("exit", C2), c && c.removeEventListener("abort", b2);
|
|
1499
|
+
}, N = () => {
|
|
1500
|
+
if (I === void 0) return;
|
|
1457
1501
|
l && s.write(`
|
|
1458
1502
|
`);
|
|
1459
|
-
const
|
|
1503
|
+
const _ = wrapAnsi(I, y, { hard: true, trim: false }).split(`
|
|
1460
1504
|
`);
|
|
1461
|
-
|
|
1462
|
-
},
|
|
1463
|
-
const
|
|
1464
|
-
return
|
|
1465
|
-
},
|
|
1466
|
-
p2 = true,
|
|
1505
|
+
_.length > 1 && s.write(import_sisteransi2.cursor.up(_.length - 1)), s.write(import_sisteransi2.cursor.to(0)), s.write(import_sisteransi2.erase.down());
|
|
1506
|
+
}, O2 = (_) => _.replace(/\.+$/, ""), j2 = (_) => {
|
|
1507
|
+
const A2 = (performance.now() - _) / 1e3, L2 = Math.floor(A2 / 60), D2 = Math.floor(A2 % 60);
|
|
1508
|
+
return L2 > 0 ? `[${L2}m ${D2}s]` : `[${D2}s]`;
|
|
1509
|
+
}, k2 = o.withGuide ?? h.withGuide, rt2 = (_ = "") => {
|
|
1510
|
+
p2 = true, d = R({ output: s }), h2 = O2(_), m2 = performance.now(), k2 && s.write(`${e("gray", $)}
|
|
1467
1511
|
`);
|
|
1468
|
-
let
|
|
1469
|
-
G2(),
|
|
1470
|
-
if (l &&
|
|
1471
|
-
|
|
1472
|
-
const
|
|
1512
|
+
let A2 = 0, L2 = 0;
|
|
1513
|
+
G2(), g = setInterval(() => {
|
|
1514
|
+
if (l && h2 === I) return;
|
|
1515
|
+
N(), I = h2;
|
|
1516
|
+
const D2 = v2(n[A2]);
|
|
1473
1517
|
let Z;
|
|
1474
|
-
if (l) Z = `${
|
|
1475
|
-
else if (t === "timer") Z = `${
|
|
1518
|
+
if (l) Z = `${D2} ${h2}...`;
|
|
1519
|
+
else if (t === "timer") Z = `${D2} ${h2} ${j2(m2)}`;
|
|
1476
1520
|
else {
|
|
1477
|
-
const kt = ".".repeat(Math.floor(
|
|
1478
|
-
Z = `${
|
|
1521
|
+
const kt = ".".repeat(Math.floor(L2)).slice(0, 3);
|
|
1522
|
+
Z = `${D2} ${h2}${kt}`;
|
|
1479
1523
|
}
|
|
1480
|
-
const
|
|
1481
|
-
s.write(
|
|
1482
|
-
},
|
|
1483
|
-
}, W2 = (
|
|
1524
|
+
const Bt = wrapAnsi(Z, y, { hard: true, trim: false });
|
|
1525
|
+
s.write(Bt), A2 = A2 + 1 < n.length ? A2 + 1 : 0, L2 = L2 < 4 ? L2 + 0.125 : 0;
|
|
1526
|
+
}, a);
|
|
1527
|
+
}, W2 = (_ = "", A2 = 0, L2 = false) => {
|
|
1484
1528
|
if (!p2) return;
|
|
1485
|
-
p2 = false, clearInterval(
|
|
1486
|
-
const
|
|
1487
|
-
|
|
1488
|
-
`) : s.write(`${
|
|
1489
|
-
`)),
|
|
1490
|
-
};
|
|
1491
|
-
return { start: rt2, stop: (
|
|
1492
|
-
|
|
1493
|
-
}, cancel: (
|
|
1494
|
-
return
|
|
1529
|
+
p2 = false, clearInterval(g), N();
|
|
1530
|
+
const D2 = A2 === 0 ? e("green", H) : A2 === 1 ? e("red", at2) : e("red", ut2);
|
|
1531
|
+
h2 = _ ?? h2, L2 || (t === "timer" ? s.write(`${D2} ${h2} ${j2(m2)}
|
|
1532
|
+
`) : s.write(`${D2} ${h2}
|
|
1533
|
+
`)), M(), d();
|
|
1534
|
+
};
|
|
1535
|
+
return { start: rt2, stop: (_ = "") => W2(_, 0), message: (_ = "") => {
|
|
1536
|
+
h2 = O2(_ ?? h2);
|
|
1537
|
+
}, cancel: (_ = "") => W2(_, 1), error: (_ = "") => W2(_, 2), clear: () => W2("", 0, true), get isCancelled() {
|
|
1538
|
+
return f2;
|
|
1495
1539
|
} };
|
|
1496
1540
|
};
|
|
1497
|
-
var
|
|
1498
|
-
var it2 = (t,
|
|
1541
|
+
var jt = { light: w2("\u2500", "-"), heavy: w2("\u2501", "="), block: w2("\u2588", "#") };
|
|
1542
|
+
var it2 = (t, i) => t.includes(`
|
|
1499
1543
|
`) ? t.split(`
|
|
1500
|
-
`).map((s) =>
|
|
1501
|
-
`) :
|
|
1502
|
-
var
|
|
1503
|
-
const
|
|
1544
|
+
`).map((s) => i(s)).join(`
|
|
1545
|
+
`) : i(t);
|
|
1546
|
+
var xe = (t) => {
|
|
1547
|
+
const i = (s, r) => {
|
|
1504
1548
|
const u = s.label ?? String(s.value);
|
|
1505
|
-
switch (
|
|
1549
|
+
switch (r) {
|
|
1506
1550
|
case "disabled":
|
|
1507
|
-
return `${e("gray",
|
|
1551
|
+
return `${e("gray", U)} ${it2(u, (n) => e("gray", n))}${s.hint ? ` ${e("dim", `(${s.hint ?? "disabled"})`)}` : ""}`;
|
|
1508
1552
|
case "selected":
|
|
1509
1553
|
return `${it2(u, (n) => e("dim", n))}`;
|
|
1510
1554
|
case "active":
|
|
@@ -1512,60 +1556,60 @@ var Ee = (t) => {
|
|
|
1512
1556
|
case "cancelled":
|
|
1513
1557
|
return `${it2(u, (n) => e(["strikethrough", "dim"], n))}`;
|
|
1514
1558
|
default:
|
|
1515
|
-
return `${e("dim",
|
|
1559
|
+
return `${e("dim", U)} ${it2(u, (n) => e("dim", n))}`;
|
|
1516
1560
|
}
|
|
1517
1561
|
};
|
|
1518
1562
|
return new ut({ options: t.options, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue, render() {
|
|
1519
|
-
const s = t.withGuide ?? h.withGuide,
|
|
1563
|
+
const s = t.withGuide ?? h.withGuide, r = `${P(this.state)} `, u = `${yt(this.state)} `, n = W(t.output, t.message, u, r), a = `${s ? `${e("gray", $)}
|
|
1520
1564
|
` : ""}${n}
|
|
1521
1565
|
`;
|
|
1522
1566
|
switch (this.state) {
|
|
1523
1567
|
case "submit": {
|
|
1524
|
-
const
|
|
1525
|
-
return `${
|
|
1568
|
+
const c = s ? `${e("gray", $)} ` : "", o = W(t.output, i(this.options[this.cursor], "selected"), c);
|
|
1569
|
+
return `${a}${o}`;
|
|
1526
1570
|
}
|
|
1527
1571
|
case "cancel": {
|
|
1528
|
-
const
|
|
1529
|
-
return `${
|
|
1572
|
+
const c = s ? `${e("gray", $)} ` : "", o = W(t.output, i(this.options[this.cursor], "cancelled"), c);
|
|
1573
|
+
return `${a}${o}${s ? `
|
|
1530
1574
|
${e("gray", $)}` : ""}`;
|
|
1531
1575
|
}
|
|
1532
1576
|
default: {
|
|
1533
|
-
const
|
|
1534
|
-
`).length,
|
|
1535
|
-
return `${
|
|
1536
|
-
${
|
|
1537
|
-
${
|
|
1577
|
+
const c = s ? `${e("cyan", $)} ` : "", o = s ? e("cyan", x2) : "", l = a.split(`
|
|
1578
|
+
`).length, d = s ? 2 : 1;
|
|
1579
|
+
return `${a}${c}${F({ output: t.output, cursor: this.cursor, options: this.options, maxItems: t.maxItems, columnPadding: c.length, rowPadding: l + d, style: (g, p2) => i(g, g.disabled ? "disabled" : p2 ? "active" : "inactive") }).join(`
|
|
1580
|
+
${c}`)}
|
|
1581
|
+
${o}
|
|
1538
1582
|
`;
|
|
1539
1583
|
}
|
|
1540
1584
|
}
|
|
1541
1585
|
} }).prompt();
|
|
1542
1586
|
};
|
|
1543
|
-
var
|
|
1544
|
-
var
|
|
1545
|
-
const
|
|
1546
|
-
` : ""}${
|
|
1547
|
-
`,
|
|
1587
|
+
var Nt = `${e("gray", $)} `;
|
|
1588
|
+
var Pe = (t) => new ht({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, output: t.output, signal: t.signal, input: t.input, render() {
|
|
1589
|
+
const i = t?.withGuide ?? h.withGuide, s = `${`${i ? `${e("gray", $)}
|
|
1590
|
+
` : ""}${P(this.state)} `}${t.message}
|
|
1591
|
+
`, r = t.placeholder ? e("inverse", t.placeholder[0]) + e("dim", t.placeholder.slice(1)) : e(["inverse", "hidden"], "_"), u = this.userInput ? this.userInputWithCursor : r, n = this.value ?? "";
|
|
1548
1592
|
switch (this.state) {
|
|
1549
1593
|
case "error": {
|
|
1550
|
-
const
|
|
1594
|
+
const a = this.error ? ` ${e("yellow", this.error)}` : "", c = i ? `${e("yellow", $)} ` : "", o = i ? e("yellow", x2) : "";
|
|
1551
1595
|
return `${s.trim()}
|
|
1552
|
-
${
|
|
1553
|
-
${
|
|
1596
|
+
${c}${u}
|
|
1597
|
+
${o}${a}
|
|
1554
1598
|
`;
|
|
1555
1599
|
}
|
|
1556
1600
|
case "submit": {
|
|
1557
|
-
const
|
|
1558
|
-
return `${s}${
|
|
1601
|
+
const a = n ? ` ${e("dim", n)}` : "", c = i ? e("gray", $) : "";
|
|
1602
|
+
return `${s}${c}${a}`;
|
|
1559
1603
|
}
|
|
1560
1604
|
case "cancel": {
|
|
1561
|
-
const
|
|
1562
|
-
return `${s}${
|
|
1563
|
-
${
|
|
1605
|
+
const a = n ? ` ${e(["strikethrough", "dim"], n)}` : "", c = i ? e("gray", $) : "";
|
|
1606
|
+
return `${s}${c}${a}${n.trim() ? `
|
|
1607
|
+
${c}` : ""}`;
|
|
1564
1608
|
}
|
|
1565
1609
|
default: {
|
|
1566
|
-
const
|
|
1567
|
-
return `${s}${
|
|
1568
|
-
${
|
|
1610
|
+
const a = i ? `${e("cyan", $)} ` : "", c = i ? e("cyan", x2) : "";
|
|
1611
|
+
return `${s}${a}${u}
|
|
1612
|
+
${c}
|
|
1569
1613
|
`;
|
|
1570
1614
|
}
|
|
1571
1615
|
}
|
|
@@ -1994,9 +2038,16 @@ function trimRightSlash(s) {
|
|
|
1994
2038
|
}
|
|
1995
2039
|
|
|
1996
2040
|
// src/lib/credentials.ts
|
|
1997
|
-
import {
|
|
1998
|
-
|
|
1999
|
-
|
|
2041
|
+
import {
|
|
2042
|
+
chmodSync as chmodSync2,
|
|
2043
|
+
mkdirSync as mkdirSync3,
|
|
2044
|
+
readFileSync as readFileSync5,
|
|
2045
|
+
renameSync as renameSync2,
|
|
2046
|
+
rmSync,
|
|
2047
|
+
statSync as statSync3,
|
|
2048
|
+
writeFileSync as writeFileSync4
|
|
2049
|
+
} from "fs";
|
|
2050
|
+
import { dirname as dirname3 } from "path";
|
|
2000
2051
|
|
|
2001
2052
|
// ../../node_modules/.pnpm/zod@4.4.2/node_modules/zod/v4/classic/external.js
|
|
2002
2053
|
var external_exports = {};
|
|
@@ -3156,21 +3207,21 @@ function required(Class2, schema, mask) {
|
|
|
3156
3207
|
});
|
|
3157
3208
|
return clone(schema, def);
|
|
3158
3209
|
}
|
|
3159
|
-
function aborted(
|
|
3160
|
-
if (
|
|
3210
|
+
function aborted(x3, startIndex = 0) {
|
|
3211
|
+
if (x3.aborted === true)
|
|
3161
3212
|
return true;
|
|
3162
|
-
for (let i = startIndex; i <
|
|
3163
|
-
if (
|
|
3213
|
+
for (let i = startIndex; i < x3.issues.length; i++) {
|
|
3214
|
+
if (x3.issues[i]?.continue !== true) {
|
|
3164
3215
|
return true;
|
|
3165
3216
|
}
|
|
3166
3217
|
}
|
|
3167
3218
|
return false;
|
|
3168
3219
|
}
|
|
3169
|
-
function explicitlyAborted(
|
|
3170
|
-
if (
|
|
3220
|
+
function explicitlyAborted(x3, startIndex = 0) {
|
|
3221
|
+
if (x3.aborted === true)
|
|
3171
3222
|
return true;
|
|
3172
|
-
for (let i = startIndex; i <
|
|
3173
|
-
if (
|
|
3223
|
+
for (let i = startIndex; i < x3.issues.length; i++) {
|
|
3224
|
+
if (x3.issues[i]?.continue === false) {
|
|
3174
3225
|
return true;
|
|
3175
3226
|
}
|
|
3176
3227
|
}
|
|
@@ -4247,9 +4298,9 @@ var Doc = class {
|
|
|
4247
4298
|
return;
|
|
4248
4299
|
}
|
|
4249
4300
|
const content = arg;
|
|
4250
|
-
const lines = content.split("\n").filter((
|
|
4251
|
-
const minIndent = Math.min(...lines.map((
|
|
4252
|
-
const dedented = lines.map((
|
|
4301
|
+
const lines = content.split("\n").filter((x3) => x3);
|
|
4302
|
+
const minIndent = Math.min(...lines.map((x3) => x3.length - x3.trimStart().length));
|
|
4303
|
+
const dedented = lines.map((x3) => x3.slice(minIndent)).map((x3) => " ".repeat(this.indent * 2) + x3);
|
|
4253
4304
|
for (const line of dedented) {
|
|
4254
4305
|
this.content.push(line);
|
|
4255
4306
|
}
|
|
@@ -4258,7 +4309,7 @@ var Doc = class {
|
|
|
4258
4309
|
const F2 = Function;
|
|
4259
4310
|
const args = this?.args;
|
|
4260
4311
|
const content = this?.content ?? [``];
|
|
4261
|
-
const lines = [...content.map((
|
|
4312
|
+
const lines = [...content.map((x3) => ` ${x3}`)];
|
|
4262
4313
|
return new F2(...args, lines.join("\n"));
|
|
4263
4314
|
}
|
|
4264
4315
|
};
|
|
@@ -4635,7 +4686,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
|
4635
4686
|
function isValidBase64URL(data) {
|
|
4636
4687
|
if (!base64url.test(data))
|
|
4637
4688
|
return false;
|
|
4638
|
-
const base643 = data.replace(/[-_]/g, (
|
|
4689
|
+
const base643 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/");
|
|
4639
4690
|
const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
|
|
4640
4691
|
return isValidBase64(padded);
|
|
4641
4692
|
}
|
|
@@ -5036,13 +5087,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
5036
5087
|
}
|
|
5037
5088
|
return propValues;
|
|
5038
5089
|
});
|
|
5039
|
-
const
|
|
5090
|
+
const isObject6 = isObject2;
|
|
5040
5091
|
const catchall = def.catchall;
|
|
5041
5092
|
let value;
|
|
5042
5093
|
inst._zod.parse = (payload, ctx) => {
|
|
5043
5094
|
value ?? (value = _normalized.value);
|
|
5044
5095
|
const input = payload.value;
|
|
5045
|
-
if (!
|
|
5096
|
+
if (!isObject6(input)) {
|
|
5046
5097
|
payload.issues.push({
|
|
5047
5098
|
expected: "object",
|
|
5048
5099
|
code: "invalid_type",
|
|
@@ -5169,7 +5220,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
5169
5220
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
5170
5221
|
};
|
|
5171
5222
|
let fastpass;
|
|
5172
|
-
const
|
|
5223
|
+
const isObject6 = isObject2;
|
|
5173
5224
|
const jit = !globalConfig.jitless;
|
|
5174
5225
|
const allowsEval2 = allowsEval;
|
|
5175
5226
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -5178,7 +5229,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
5178
5229
|
inst._zod.parse = (payload, ctx) => {
|
|
5179
5230
|
value ?? (value = _normalized.value);
|
|
5180
5231
|
const input = payload.value;
|
|
5181
|
-
if (!
|
|
5232
|
+
if (!isObject6(input)) {
|
|
5182
5233
|
payload.issues.push({
|
|
5183
5234
|
expected: "object",
|
|
5184
5235
|
code: "invalid_type",
|
|
@@ -5468,7 +5519,7 @@ function handleIntersectionResults(result, left, right) {
|
|
|
5468
5519
|
result.issues.push(iss);
|
|
5469
5520
|
}
|
|
5470
5521
|
}
|
|
5471
|
-
const bothKeys = [...unrecKeys].filter(([,
|
|
5522
|
+
const bothKeys = [...unrecKeys].filter(([, f2]) => f2.l && f2.r).map(([k2]) => k2);
|
|
5472
5523
|
if (bothKeys.length && unrecIssue) {
|
|
5473
5524
|
result.issues.push({ ...unrecIssue, keys: bothKeys });
|
|
5474
5525
|
}
|
|
@@ -5983,7 +6034,7 @@ var $ZodNonOptional = /* @__PURE__ */ $constructor("$ZodNonOptional", (inst, def
|
|
|
5983
6034
|
$ZodType.init(inst, def);
|
|
5984
6035
|
defineLazy(inst._zod, "values", () => {
|
|
5985
6036
|
const v2 = def.innerType._zod.values;
|
|
5986
|
-
return v2 ? new Set([...v2].filter((
|
|
6037
|
+
return v2 ? new Set([...v2].filter((x3) => x3 !== void 0)) : void 0;
|
|
5987
6038
|
});
|
|
5988
6039
|
inst._zod.parse = (payload, ctx) => {
|
|
5989
6040
|
const result = def.innerType._zod.run(payload, ctx);
|
|
@@ -6311,10 +6362,10 @@ var $ZodPromise = /* @__PURE__ */ $constructor("$ZodPromise", (inst, def) => {
|
|
|
6311
6362
|
var $ZodLazy = /* @__PURE__ */ $constructor("$ZodLazy", (inst, def) => {
|
|
6312
6363
|
$ZodType.init(inst, def);
|
|
6313
6364
|
defineLazy(inst._zod, "innerType", () => {
|
|
6314
|
-
const
|
|
6315
|
-
if (!
|
|
6316
|
-
|
|
6317
|
-
return
|
|
6365
|
+
const d = def;
|
|
6366
|
+
if (!d._cachedInner)
|
|
6367
|
+
d._cachedInner = def.getter();
|
|
6368
|
+
return d._cachedInner;
|
|
6318
6369
|
});
|
|
6319
6370
|
defineLazy(inst._zod, "pattern", () => inst._zod.innerType?._zod?.pattern);
|
|
6320
6371
|
defineLazy(inst._zod, "propValues", () => inst._zod.innerType?._zod?.propValues);
|
|
@@ -12349,8 +12400,8 @@ var $ZodRegistry = class {
|
|
|
12349
12400
|
if (p2) {
|
|
12350
12401
|
const pm = { ...this.get(p2) ?? {} };
|
|
12351
12402
|
delete pm.id;
|
|
12352
|
-
const
|
|
12353
|
-
return Object.keys(
|
|
12403
|
+
const f2 = { ...pm, ...this._map.get(schema) };
|
|
12404
|
+
return Object.keys(f2).length ? f2 : void 0;
|
|
12354
12405
|
}
|
|
12355
12406
|
return this._map.get(schema);
|
|
12356
12407
|
}
|
|
@@ -13960,7 +14011,7 @@ var fileProcessor = (schema, _ctx, json2, _params) => {
|
|
|
13960
14011
|
Object.assign(_json, file2);
|
|
13961
14012
|
} else {
|
|
13962
14013
|
Object.assign(_json, file2);
|
|
13963
|
-
_json.anyOf = mime.map((
|
|
14014
|
+
_json.anyOf = mime.map((m2) => ({ contentMediaType: m2 }));
|
|
13964
14015
|
}
|
|
13965
14016
|
} else {
|
|
13966
14017
|
Object.assign(_json, file2);
|
|
@@ -14047,7 +14098,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
|
|
|
14047
14098
|
var unionProcessor = (schema, ctx, json2, params) => {
|
|
14048
14099
|
const def = schema._zod.def;
|
|
14049
14100
|
const isExclusive = def.inclusive === false;
|
|
14050
|
-
const options = def.options.map((
|
|
14101
|
+
const options = def.options.map((x3, i) => process2(x3, ctx, {
|
|
14051
14102
|
...params,
|
|
14052
14103
|
path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
|
|
14053
14104
|
}));
|
|
@@ -14080,7 +14131,7 @@ var tupleProcessor = (schema, ctx, _json, params) => {
|
|
|
14080
14131
|
json2.type = "array";
|
|
14081
14132
|
const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
|
|
14082
14133
|
const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
|
|
14083
|
-
const prefixItems = def.items.map((
|
|
14134
|
+
const prefixItems = def.items.map((x3, i) => process2(x3, ctx, {
|
|
14084
14135
|
...params,
|
|
14085
14136
|
path: [...params.path, prefixPath, i]
|
|
14086
14137
|
}));
|
|
@@ -14806,11 +14857,11 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
14806
14857
|
transform(tx) {
|
|
14807
14858
|
return pipe(this, transform(tx));
|
|
14808
14859
|
},
|
|
14809
|
-
default(
|
|
14810
|
-
return _default2(this,
|
|
14860
|
+
default(d) {
|
|
14861
|
+
return _default2(this, d);
|
|
14811
14862
|
},
|
|
14812
|
-
prefault(
|
|
14813
|
-
return prefault(this,
|
|
14863
|
+
prefault(d) {
|
|
14864
|
+
return prefault(this, d);
|
|
14814
14865
|
},
|
|
14815
14866
|
catch(params) {
|
|
14816
14867
|
return _catch2(this, params);
|
|
@@ -15307,9 +15358,9 @@ var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
|
|
|
15307
15358
|
inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params);
|
|
15308
15359
|
inst.min = (value, params) => inst.check(_gte(value, params));
|
|
15309
15360
|
inst.max = (value, params) => inst.check(_lte(value, params));
|
|
15310
|
-
const
|
|
15311
|
-
inst.minDate =
|
|
15312
|
-
inst.maxDate =
|
|
15361
|
+
const c = inst._zod.bag;
|
|
15362
|
+
inst.minDate = c.minimum ? new Date(c.minimum) : null;
|
|
15363
|
+
inst.maxDate = c.maximum ? new Date(c.maximum) : null;
|
|
15313
15364
|
});
|
|
15314
15365
|
function date3(params) {
|
|
15315
15366
|
return _date(ZodDate, params);
|
|
@@ -16506,6 +16557,92 @@ function date4(params) {
|
|
|
16506
16557
|
// ../../node_modules/.pnpm/zod@4.4.2/node_modules/zod/v4/classic/external.js
|
|
16507
16558
|
config(en_default());
|
|
16508
16559
|
|
|
16560
|
+
// src/config-writers/claude-code.ts
|
|
16561
|
+
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
16562
|
+
import { homedir as homedir2 } from "os";
|
|
16563
|
+
import { join as join2 } from "path";
|
|
16564
|
+
|
|
16565
|
+
// src/lib/merge-json.ts
|
|
16566
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
|
|
16567
|
+
import { dirname } from "path";
|
|
16568
|
+
function isPlainObject2(v2) {
|
|
16569
|
+
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
16570
|
+
}
|
|
16571
|
+
function deepMerge2(base, patch, opts = {}, currentPath = []) {
|
|
16572
|
+
const hookPaths = new Set(opts.hookArrayPaths ?? []);
|
|
16573
|
+
const dedupeKey = opts.hookDedupeKey ?? "command";
|
|
16574
|
+
const out = { ...base };
|
|
16575
|
+
for (const [k2, v2] of Object.entries(patch)) {
|
|
16576
|
+
const nextPath = [...currentPath, k2];
|
|
16577
|
+
const pathStr = nextPath.join(".");
|
|
16578
|
+
const existing = out[k2];
|
|
16579
|
+
if (isPlainObject2(v2) && isPlainObject2(existing)) {
|
|
16580
|
+
out[k2] = deepMerge2(existing, v2, opts, nextPath);
|
|
16581
|
+
continue;
|
|
16582
|
+
}
|
|
16583
|
+
if (Array.isArray(v2) && Array.isArray(existing) && hookPaths.has(pathStr)) {
|
|
16584
|
+
out[k2] = mergeHookArray(existing, v2, dedupeKey);
|
|
16585
|
+
continue;
|
|
16586
|
+
}
|
|
16587
|
+
out[k2] = v2;
|
|
16588
|
+
}
|
|
16589
|
+
return out;
|
|
16590
|
+
}
|
|
16591
|
+
function extractHookCommands(entry, dedupeKey) {
|
|
16592
|
+
if (!isPlainObject2(entry)) return [];
|
|
16593
|
+
if (typeof entry[dedupeKey] === "string") return [entry[dedupeKey]];
|
|
16594
|
+
const inner = entry.hooks;
|
|
16595
|
+
if (!Array.isArray(inner)) return [];
|
|
16596
|
+
return inner.filter(isPlainObject2).map((h2) => h2[dedupeKey]).filter((x3) => typeof x3 === "string");
|
|
16597
|
+
}
|
|
16598
|
+
function mergeHookArray(existing, patch, dedupeKey) {
|
|
16599
|
+
const patchCommands = new Set(patch.flatMap((e2) => extractHookCommands(e2, dedupeKey)));
|
|
16600
|
+
const kept = existing.filter((entry) => {
|
|
16601
|
+
if (!isPlainObject2(entry) || typeof entry[dedupeKey] !== "string") return true;
|
|
16602
|
+
return !patchCommands.has(entry[dedupeKey]);
|
|
16603
|
+
});
|
|
16604
|
+
const keptCommands = new Set(kept.flatMap((e2) => extractHookCommands(e2, dedupeKey)));
|
|
16605
|
+
const additions = patch.filter((entry) => {
|
|
16606
|
+
const cmds = extractHookCommands(entry, dedupeKey);
|
|
16607
|
+
if (cmds.length === 0) return true;
|
|
16608
|
+
return !cmds.some((c) => keptCommands.has(c));
|
|
16609
|
+
});
|
|
16610
|
+
return [...kept, ...additions];
|
|
16611
|
+
}
|
|
16612
|
+
function mergeJsonFile(filePath, patch, opts = {}) {
|
|
16613
|
+
const dir = dirname(filePath);
|
|
16614
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
16615
|
+
let existing = {};
|
|
16616
|
+
let mode;
|
|
16617
|
+
try {
|
|
16618
|
+
const raw = readFileSync(filePath, "utf8");
|
|
16619
|
+
if (raw.trim().length > 0) {
|
|
16620
|
+
const parsed = JSON.parse(raw);
|
|
16621
|
+
if (isPlainObject2(parsed)) existing = parsed;
|
|
16622
|
+
else {
|
|
16623
|
+
throw new Error(
|
|
16624
|
+
`${filePath} contains non-object JSON (${Array.isArray(parsed) ? "array" : typeof parsed}). Refusing to overwrite.`
|
|
16625
|
+
);
|
|
16626
|
+
}
|
|
16627
|
+
}
|
|
16628
|
+
mode = statSync(filePath).mode & 511;
|
|
16629
|
+
} catch (err) {
|
|
16630
|
+
if (err.code !== "ENOENT") throw err;
|
|
16631
|
+
}
|
|
16632
|
+
const merged = deepMerge2(existing, patch, opts);
|
|
16633
|
+
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
16634
|
+
writeFileSync(tmp, `${JSON.stringify(merged, null, 2)}
|
|
16635
|
+
`);
|
|
16636
|
+
if (mode !== void 0) {
|
|
16637
|
+
try {
|
|
16638
|
+
chmodSync(tmp, mode);
|
|
16639
|
+
} catch {
|
|
16640
|
+
}
|
|
16641
|
+
}
|
|
16642
|
+
renameSync(tmp, filePath);
|
|
16643
|
+
return merged;
|
|
16644
|
+
}
|
|
16645
|
+
|
|
16509
16646
|
// src/lib/paths.ts
|
|
16510
16647
|
import { homedir } from "os";
|
|
16511
16648
|
import { join } from "path";
|
|
@@ -16517,87 +16654,649 @@ function userCwd() {
|
|
|
16517
16654
|
return process.env.INIT_CWD ?? process.cwd();
|
|
16518
16655
|
}
|
|
16519
16656
|
|
|
16520
|
-
// src/
|
|
16521
|
-
var
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16657
|
+
// src/config-writers/claude-code.ts
|
|
16658
|
+
var writeClaudeCodeConfig = ({
|
|
16659
|
+
gatewayUrl,
|
|
16660
|
+
apiKey,
|
|
16661
|
+
hookScriptPath,
|
|
16662
|
+
scope,
|
|
16663
|
+
project,
|
|
16664
|
+
model,
|
|
16665
|
+
availableModels = []
|
|
16666
|
+
}) => {
|
|
16667
|
+
const path = claudeSettingsPath(scope);
|
|
16668
|
+
const baseUrl = `${trimRightSlash2(gatewayUrl)}/gateway/anthropic`;
|
|
16669
|
+
const env = {
|
|
16670
|
+
ANTHROPIC_BASE_URL: baseUrl,
|
|
16671
|
+
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
16672
|
+
ANTHROPIC_CUSTOM_HEADERS: buildCustomHeaders(scope, project)
|
|
16532
16673
|
};
|
|
16533
|
-
const
|
|
16534
|
-
|
|
16535
|
-
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
16536
|
-
try {
|
|
16537
|
-
chmodSync(dir, 448);
|
|
16538
|
-
} catch {
|
|
16674
|
+
for (const [key, value] of Object.entries(resolveTierDefaults(availableModels))) {
|
|
16675
|
+
env[key] = value;
|
|
16539
16676
|
}
|
|
16540
|
-
const
|
|
16541
|
-
|
|
16542
|
-
|
|
16543
|
-
|
|
16544
|
-
|
|
16677
|
+
const patch = {
|
|
16678
|
+
env,
|
|
16679
|
+
hooks: {
|
|
16680
|
+
Stop: [{ matcher: "*", hooks: [{ type: "command", command: hookScriptPath }] }],
|
|
16681
|
+
SessionEnd: [{ matcher: "*", hooks: [{ type: "command", command: hookScriptPath }] }]
|
|
16682
|
+
}
|
|
16683
|
+
};
|
|
16684
|
+
patch.model = model?.slug;
|
|
16685
|
+
if (availableModels.length > 0) {
|
|
16686
|
+
patch.availableModels = availableModels.map((m2) => m2.slug).sort();
|
|
16687
|
+
}
|
|
16688
|
+
mergeJsonFile(path, patch, {
|
|
16689
|
+
hookArrayPaths: ["hooks.Stop", "hooks.SessionEnd"],
|
|
16690
|
+
hookDedupeKey: "command"
|
|
16691
|
+
});
|
|
16692
|
+
const notes = [];
|
|
16693
|
+
if (scope === "local") notes.push("Claude Code auto-ignores settings.local.json in git.");
|
|
16694
|
+
if (scope !== "user" && !project) {
|
|
16695
|
+
notes.push(
|
|
16696
|
+
"Project slug could not be derived (no git remote and no .codevector.json). Per-project usage attribution will be blank until you set one."
|
|
16697
|
+
);
|
|
16698
|
+
}
|
|
16699
|
+
return {
|
|
16700
|
+
tool: "claude-code",
|
|
16701
|
+
status: "configured",
|
|
16702
|
+
path,
|
|
16703
|
+
scope,
|
|
16704
|
+
notes: notes.length > 0 ? notes.join(" ") : void 0
|
|
16705
|
+
};
|
|
16706
|
+
};
|
|
16707
|
+
function claudeSettingsPath(scope) {
|
|
16708
|
+
switch (scope) {
|
|
16709
|
+
case "user":
|
|
16710
|
+
return join2(homedir2(), ".claude", "settings.json");
|
|
16711
|
+
case "project":
|
|
16712
|
+
return join2(userCwd(), ".claude", "settings.json");
|
|
16713
|
+
case "local":
|
|
16714
|
+
return join2(userCwd(), ".claude", "settings.local.json");
|
|
16545
16715
|
}
|
|
16546
|
-
renameSync(tmp, CREDENTIALS_FILE);
|
|
16547
|
-
return parsed;
|
|
16548
16716
|
}
|
|
16549
|
-
|
|
16550
|
-
|
|
16551
|
-
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16717
|
+
function detectClaudeCodeConfig() {
|
|
16718
|
+
const scopes = ["local", "project", "user"];
|
|
16719
|
+
for (const scope of scopes) {
|
|
16720
|
+
const path = claudeSettingsPath(scope);
|
|
16721
|
+
if (!existsSync(path)) continue;
|
|
16722
|
+
try {
|
|
16723
|
+
const raw = JSON.parse(readFileSync2(path, "utf8"));
|
|
16724
|
+
if (raw.env?.ANTHROPIC_BASE_URL?.includes("/gateway/anthropic")) {
|
|
16725
|
+
return { scope, modelSlug: raw.model };
|
|
16726
|
+
}
|
|
16727
|
+
} catch {
|
|
16728
|
+
}
|
|
16556
16729
|
}
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16561
|
-
|
|
16562
|
-
|
|
16730
|
+
return void 0;
|
|
16731
|
+
}
|
|
16732
|
+
function resolveTierDefaults(available) {
|
|
16733
|
+
const out = {};
|
|
16734
|
+
const tierToEnv = {
|
|
16735
|
+
haiku: "ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
16736
|
+
sonnet: "ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
16737
|
+
opus: "ANTHROPIC_DEFAULT_OPUS_MODEL"
|
|
16738
|
+
};
|
|
16739
|
+
for (const [tier, envKey] of Object.entries(tierToEnv)) {
|
|
16740
|
+
const matches = available.filter(
|
|
16741
|
+
(m2) => typeof m2.family === "string" && m2.family.toLowerCase().includes(tier)
|
|
16563
16742
|
);
|
|
16743
|
+
if (matches.length === 1) {
|
|
16744
|
+
out[envKey] = matches[0].slug;
|
|
16745
|
+
}
|
|
16564
16746
|
}
|
|
16565
|
-
return
|
|
16747
|
+
return out;
|
|
16566
16748
|
}
|
|
16567
|
-
function
|
|
16568
|
-
|
|
16569
|
-
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
if (
|
|
16573
|
-
throw err;
|
|
16749
|
+
function buildCustomHeaders(scope, project) {
|
|
16750
|
+
const safe = (v2) => v2.replace(/[\r\n]/g, "").trim();
|
|
16751
|
+
const headers = [`x-client-app: claude-code`];
|
|
16752
|
+
if (scope !== "user" && project) {
|
|
16753
|
+
const slug = safe(project);
|
|
16754
|
+
if (slug) headers.push(`x-project: ${slug}`);
|
|
16574
16755
|
}
|
|
16756
|
+
return headers.join("\n");
|
|
16575
16757
|
}
|
|
16576
|
-
function
|
|
16758
|
+
function trimRightSlash2(url2) {
|
|
16759
|
+
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
16760
|
+
}
|
|
16761
|
+
|
|
16762
|
+
// src/config-writers/opencode.ts
|
|
16763
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
16764
|
+
import { homedir as homedir3 } from "os";
|
|
16765
|
+
import { join as join4 } from "path";
|
|
16766
|
+
|
|
16767
|
+
// src/lib/gitignore.ts
|
|
16768
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
16769
|
+
import { join as join3 } from "path";
|
|
16770
|
+
function ensureGitignored(pattern, cwd = userCwd()) {
|
|
16771
|
+
const path = join3(cwd, ".gitignore");
|
|
16772
|
+
const trimmed = pattern.trim();
|
|
16773
|
+
if (!trimmed) return false;
|
|
16774
|
+
let existing = "";
|
|
16775
|
+
if (existsSync2(path)) {
|
|
16776
|
+
existing = readFileSync3(path, "utf8");
|
|
16777
|
+
if (hasMatchingEntry(existing, trimmed)) return false;
|
|
16778
|
+
}
|
|
16779
|
+
const needsLeadingNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
16780
|
+
const prefix = needsLeadingNewline ? "\n" : "";
|
|
16577
16781
|
try {
|
|
16578
|
-
|
|
16579
|
-
|
|
16580
|
-
return
|
|
16782
|
+
writeFileSync2(path, `${existing}${prefix}${trimmed}
|
|
16783
|
+
`);
|
|
16784
|
+
return true;
|
|
16581
16785
|
} catch {
|
|
16582
16786
|
return false;
|
|
16583
16787
|
}
|
|
16584
16788
|
}
|
|
16585
|
-
function
|
|
16586
|
-
|
|
16587
|
-
|
|
16588
|
-
|
|
16589
|
-
|
|
16590
|
-
|
|
16591
|
-
function unwrap(value) {
|
|
16592
|
-
if (q(value)) {
|
|
16593
|
-
me("Cancelled.");
|
|
16594
|
-
process.exit(130);
|
|
16789
|
+
function hasMatchingEntry(contents, pattern) {
|
|
16790
|
+
const lines = contents.split("\n").map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean);
|
|
16791
|
+
if (lines.includes(pattern)) return true;
|
|
16792
|
+
if (pattern.includes("/")) {
|
|
16793
|
+
const topDir = `${pattern.split("/")[0]}/`;
|
|
16794
|
+
if (lines.includes(topDir)) return true;
|
|
16595
16795
|
}
|
|
16596
|
-
return
|
|
16796
|
+
return false;
|
|
16597
16797
|
}
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16798
|
+
|
|
16799
|
+
// src/config-writers/opencode.ts
|
|
16800
|
+
var ENV_VAR_NAME = "CODEVECTOR_GATEWAY_KEY";
|
|
16801
|
+
var PROVIDER_PREFIX = "codevector";
|
|
16802
|
+
var writeOpencodeConfig = ({
|
|
16803
|
+
gatewayUrl,
|
|
16804
|
+
apiKey,
|
|
16805
|
+
scope,
|
|
16806
|
+
project,
|
|
16807
|
+
model,
|
|
16808
|
+
availableModels = []
|
|
16809
|
+
}) => {
|
|
16810
|
+
const path = opencodeSettingsPath(scope);
|
|
16811
|
+
const gateway = trimRightSlash3(gatewayUrl);
|
|
16812
|
+
const keyLiteral = scope === "project" ? `{env:${ENV_VAR_NAME}}` : apiKey;
|
|
16813
|
+
removeStaleGatewayProviders(path, gateway);
|
|
16814
|
+
const models = buildModelEntries(availableModels);
|
|
16815
|
+
const options = {
|
|
16816
|
+
apiKey: keyLiteral,
|
|
16817
|
+
baseURL: `${gateway}/gateway/openai/v1`,
|
|
16818
|
+
headers: buildCustomHeaders2(scope, project)
|
|
16819
|
+
};
|
|
16820
|
+
const patch = {
|
|
16821
|
+
$schema: "https://opencode.ai/config.json",
|
|
16822
|
+
provider: {
|
|
16823
|
+
[PROVIDER_PREFIX]: {
|
|
16824
|
+
options,
|
|
16825
|
+
models
|
|
16826
|
+
}
|
|
16827
|
+
}
|
|
16828
|
+
};
|
|
16829
|
+
patch.model = model ? `${PROVIDER_PREFIX}/${model.slug}` : void 0;
|
|
16830
|
+
mergeJsonFile(path, patch);
|
|
16831
|
+
forceReplaceCgwModels(path, models);
|
|
16832
|
+
const notes = [];
|
|
16833
|
+
if (scope === "local") {
|
|
16834
|
+
if (ensureGitignored("opencode.json")) {
|
|
16835
|
+
notes.push("Added `opencode.json` to .gitignore.");
|
|
16836
|
+
}
|
|
16837
|
+
}
|
|
16838
|
+
if (scope === "project") {
|
|
16839
|
+
notes.push(
|
|
16840
|
+
`Project scope avoids embedding secrets. Export ${ENV_VAR_NAME}=<your key> before running opencode, or switch to local scope to embed the key.`
|
|
16841
|
+
);
|
|
16842
|
+
}
|
|
16843
|
+
if (scope !== "user" && !project) {
|
|
16844
|
+
notes.push(
|
|
16845
|
+
"Project slug could not be derived (no git remote and no .codevector.json). Per-project usage attribution will be blank until you set one."
|
|
16846
|
+
);
|
|
16847
|
+
}
|
|
16848
|
+
return {
|
|
16849
|
+
tool: "opencode",
|
|
16850
|
+
status: "configured",
|
|
16851
|
+
path,
|
|
16852
|
+
scope,
|
|
16853
|
+
notes: notes.length > 0 ? notes.join(" ") : void 0
|
|
16854
|
+
};
|
|
16855
|
+
};
|
|
16856
|
+
function syncOpencodeModels(path, availableModels) {
|
|
16857
|
+
if (!existsSync3(path)) {
|
|
16858
|
+
throw new Error(
|
|
16859
|
+
`No opencode config found at ${path}. Run \`codevector configure opencode\` first.`
|
|
16860
|
+
);
|
|
16861
|
+
}
|
|
16862
|
+
const raw = readFileSync4(path, "utf8");
|
|
16863
|
+
let parsed;
|
|
16864
|
+
try {
|
|
16865
|
+
parsed = raw.trim().length === 0 ? {} : JSON.parse(raw);
|
|
16866
|
+
} catch (err) {
|
|
16867
|
+
throw new Error(`${path} is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
16868
|
+
}
|
|
16869
|
+
if (!isObject3(parsed)) {
|
|
16870
|
+
throw new Error(`${path} is not a JSON object; refusing to overwrite.`);
|
|
16871
|
+
}
|
|
16872
|
+
const provider = isObject3(parsed.provider) ? parsed.provider : void 0;
|
|
16873
|
+
const codevector = provider && isObject3(provider[PROVIDER_PREFIX]) ? provider[PROVIDER_PREFIX] : void 0;
|
|
16874
|
+
if (!provider || !codevector) {
|
|
16875
|
+
throw new Error(
|
|
16876
|
+
`${path} has no \`provider.${PROVIDER_PREFIX}\` entry. Run \`codevector configure opencode\` first.`
|
|
16877
|
+
);
|
|
16878
|
+
}
|
|
16879
|
+
const models = buildModelEntries(availableModels);
|
|
16880
|
+
codevector.models = models;
|
|
16881
|
+
writeFileSync3(path, `${JSON.stringify(parsed, null, 2)}
|
|
16882
|
+
`);
|
|
16883
|
+
return Object.keys(models).length;
|
|
16884
|
+
}
|
|
16885
|
+
function buildModelEntries(availableModels) {
|
|
16886
|
+
const out = {};
|
|
16887
|
+
for (const m2 of availableModels) {
|
|
16888
|
+
const entry = {};
|
|
16889
|
+
if (m2.displayName) entry.name = m2.displayName;
|
|
16890
|
+
if (m2.family) entry.family = m2.family;
|
|
16891
|
+
if (m2.releaseDate) entry.release_date = m2.releaseDate;
|
|
16892
|
+
const inP = parsePrice(m2.inputPricePerMtok);
|
|
16893
|
+
const outP = parsePrice(m2.outputPricePerMtok);
|
|
16894
|
+
if (inP !== void 0 && outP !== void 0) {
|
|
16895
|
+
const cost = { input: inP, output: outP };
|
|
16896
|
+
const cacheReadP = parsePrice(m2.cachedInputPricePerMtok);
|
|
16897
|
+
const cacheWriteP = parsePrice(m2.cacheWritePricePerMtok);
|
|
16898
|
+
if (cacheReadP !== void 0) cost.cache_read = cacheReadP;
|
|
16899
|
+
if (cacheWriteP !== void 0) cost.cache_write = cacheWriteP;
|
|
16900
|
+
entry.cost = cost;
|
|
16901
|
+
}
|
|
16902
|
+
const ctx = m2.contextWindow;
|
|
16903
|
+
const outTok = m2.maxOutputTokens;
|
|
16904
|
+
if (typeof ctx === "number" && ctx > 0 && typeof outTok === "number" && outTok > 0) {
|
|
16905
|
+
const limit = { context: ctx, output: outTok };
|
|
16906
|
+
if (typeof m2.maxInputTokens === "number" && m2.maxInputTokens > 0) {
|
|
16907
|
+
limit.input = m2.maxInputTokens;
|
|
16908
|
+
}
|
|
16909
|
+
entry.limit = limit;
|
|
16910
|
+
}
|
|
16911
|
+
if (typeof m2.supportsReasoning === "boolean") entry.reasoning = m2.supportsReasoning;
|
|
16912
|
+
if (typeof m2.supportsAttachment === "boolean") entry.attachment = m2.supportsAttachment;
|
|
16913
|
+
if (typeof m2.supportsToolCall === "boolean") entry.tool_call = m2.supportsToolCall;
|
|
16914
|
+
if (typeof m2.supportsTemperature === "boolean") entry.temperature = m2.supportsTemperature;
|
|
16915
|
+
const inMods = m2.inputModalities;
|
|
16916
|
+
const outMods = m2.outputModalities;
|
|
16917
|
+
if (inMods && inMods.length > 0 && outMods && outMods.length > 0) {
|
|
16918
|
+
entry.modalities = { input: [...inMods], output: [...outMods] };
|
|
16919
|
+
}
|
|
16920
|
+
out[m2.slug] = entry;
|
|
16921
|
+
}
|
|
16922
|
+
return out;
|
|
16923
|
+
}
|
|
16924
|
+
function parsePrice(raw) {
|
|
16925
|
+
if (raw == null) return void 0;
|
|
16926
|
+
const n = Number(raw);
|
|
16927
|
+
return Number.isFinite(n) ? n : void 0;
|
|
16928
|
+
}
|
|
16929
|
+
function forceReplaceCgwModels(path, models) {
|
|
16930
|
+
if (!existsSync3(path)) return;
|
|
16931
|
+
let parsed;
|
|
16932
|
+
try {
|
|
16933
|
+
parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
16934
|
+
} catch {
|
|
16935
|
+
return;
|
|
16936
|
+
}
|
|
16937
|
+
if (!isObject3(parsed)) return;
|
|
16938
|
+
const provider = parsed.provider;
|
|
16939
|
+
if (!isObject3(provider)) return;
|
|
16940
|
+
const codevector = provider[PROVIDER_PREFIX];
|
|
16941
|
+
if (!isObject3(codevector)) return;
|
|
16942
|
+
codevector.models = models;
|
|
16943
|
+
writeFileSync3(path, `${JSON.stringify(parsed, null, 2)}
|
|
16944
|
+
`);
|
|
16945
|
+
}
|
|
16946
|
+
function opencodeSettingsPath(scope) {
|
|
16947
|
+
switch (scope) {
|
|
16948
|
+
case "user":
|
|
16949
|
+
return join4(homedir3(), ".config", "opencode", "opencode.json");
|
|
16950
|
+
case "project":
|
|
16951
|
+
case "local":
|
|
16952
|
+
return join4(userCwd(), "opencode.json");
|
|
16953
|
+
}
|
|
16954
|
+
}
|
|
16955
|
+
function detectOpencodeConfig() {
|
|
16956
|
+
const scopes = ["local", "project", "user"];
|
|
16957
|
+
for (const scope of scopes) {
|
|
16958
|
+
const path = opencodeSettingsPath(scope);
|
|
16959
|
+
if (!existsSync3(path)) continue;
|
|
16960
|
+
try {
|
|
16961
|
+
const raw = JSON.parse(readFileSync4(path, "utf8"));
|
|
16962
|
+
if (raw.provider?.codevector?.options?.baseURL) {
|
|
16963
|
+
const modelSlug = raw.model?.startsWith("codevector/") ? raw.model.slice("codevector/".length) : raw.model;
|
|
16964
|
+
return { scope, modelSlug };
|
|
16965
|
+
}
|
|
16966
|
+
} catch {
|
|
16967
|
+
}
|
|
16968
|
+
}
|
|
16969
|
+
return void 0;
|
|
16970
|
+
}
|
|
16971
|
+
function removeStaleGatewayProviders(path, gateway) {
|
|
16972
|
+
if (!existsSync3(path)) return;
|
|
16973
|
+
let parsed;
|
|
16974
|
+
try {
|
|
16975
|
+
const raw = readFileSync4(path, "utf8");
|
|
16976
|
+
if (raw.trim().length === 0) return;
|
|
16977
|
+
parsed = JSON.parse(raw);
|
|
16978
|
+
} catch {
|
|
16979
|
+
return;
|
|
16980
|
+
}
|
|
16981
|
+
if (!isObject3(parsed)) return;
|
|
16982
|
+
const provider = parsed.provider;
|
|
16983
|
+
if (!isObject3(provider)) return;
|
|
16984
|
+
const ourBaseUrls = /* @__PURE__ */ new Set([`${gateway}/gateway/anthropic`, `${gateway}/gateway/openai/v1`]);
|
|
16985
|
+
let mutated = false;
|
|
16986
|
+
for (const key of ["openai", "anthropic"]) {
|
|
16987
|
+
const entry = provider[key];
|
|
16988
|
+
if (!isObject3(entry)) continue;
|
|
16989
|
+
const options = entry.options;
|
|
16990
|
+
if (!isObject3(options)) continue;
|
|
16991
|
+
const baseURL = options.baseURL;
|
|
16992
|
+
if (typeof baseURL === "string" && ourBaseUrls.has(baseURL)) {
|
|
16993
|
+
delete provider[key];
|
|
16994
|
+
mutated = true;
|
|
16995
|
+
}
|
|
16996
|
+
}
|
|
16997
|
+
if (mutated) {
|
|
16998
|
+
writeFileSync3(path, `${JSON.stringify(parsed, null, 2)}
|
|
16999
|
+
`);
|
|
17000
|
+
}
|
|
17001
|
+
}
|
|
17002
|
+
function isObject3(v2) {
|
|
17003
|
+
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
17004
|
+
}
|
|
17005
|
+
function buildCustomHeaders2(scope, project) {
|
|
17006
|
+
const safe = (v2) => v2.replace(/[\r\n]/g, "").trim();
|
|
17007
|
+
const headers = {
|
|
17008
|
+
"x-client-app": "opencode"
|
|
17009
|
+
};
|
|
17010
|
+
if (scope !== "user" && project) {
|
|
17011
|
+
const slug = safe(project);
|
|
17012
|
+
if (slug) {
|
|
17013
|
+
headers["x-project"] = slug;
|
|
17014
|
+
}
|
|
17015
|
+
}
|
|
17016
|
+
return headers;
|
|
17017
|
+
}
|
|
17018
|
+
function trimRightSlash3(url2) {
|
|
17019
|
+
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
17020
|
+
}
|
|
17021
|
+
|
|
17022
|
+
// src/lib/credentials-lock.ts
|
|
17023
|
+
import { closeSync, constants, mkdirSync as mkdirSync2, openSync, statSync as statSync2, unlinkSync } from "fs";
|
|
17024
|
+
import { dirname as dirname2 } from "path";
|
|
17025
|
+
var LOCK_FILE = `${CREDENTIALS_FILE}.lock`;
|
|
17026
|
+
var MAX_RETRIES = 50;
|
|
17027
|
+
var RETRY_INTERVAL_MS = 100;
|
|
17028
|
+
var STALE_LOCK_MS = 3e4;
|
|
17029
|
+
var sleepView = new Int32Array(new SharedArrayBuffer(4));
|
|
17030
|
+
function syncSleep(ms) {
|
|
17031
|
+
Atomics.wait(sleepView, 0, 0, ms);
|
|
17032
|
+
}
|
|
17033
|
+
var lockDepth = 0;
|
|
17034
|
+
function withCredentialsLockSync(fn) {
|
|
17035
|
+
if (lockDepth > 0) {
|
|
17036
|
+
lockDepth++;
|
|
17037
|
+
try {
|
|
17038
|
+
return fn();
|
|
17039
|
+
} finally {
|
|
17040
|
+
lockDepth--;
|
|
17041
|
+
}
|
|
17042
|
+
}
|
|
17043
|
+
acquireLock();
|
|
17044
|
+
lockDepth++;
|
|
17045
|
+
try {
|
|
17046
|
+
return fn();
|
|
17047
|
+
} finally {
|
|
17048
|
+
lockDepth--;
|
|
17049
|
+
releaseLock();
|
|
17050
|
+
}
|
|
17051
|
+
}
|
|
17052
|
+
function acquireLock() {
|
|
17053
|
+
mkdirSync2(dirname2(LOCK_FILE), { recursive: true, mode: 448 });
|
|
17054
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
17055
|
+
try {
|
|
17056
|
+
const fd = openSync(
|
|
17057
|
+
LOCK_FILE,
|
|
17058
|
+
constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL,
|
|
17059
|
+
384
|
|
17060
|
+
);
|
|
17061
|
+
closeSync(fd);
|
|
17062
|
+
return;
|
|
17063
|
+
} catch (err) {
|
|
17064
|
+
if (err.code !== "EEXIST") throw err;
|
|
17065
|
+
try {
|
|
17066
|
+
const stats = statSync2(LOCK_FILE);
|
|
17067
|
+
if (Date.now() - stats.mtimeMs > STALE_LOCK_MS) {
|
|
17068
|
+
try {
|
|
17069
|
+
unlinkSync(LOCK_FILE);
|
|
17070
|
+
} catch {
|
|
17071
|
+
}
|
|
17072
|
+
continue;
|
|
17073
|
+
}
|
|
17074
|
+
} catch {
|
|
17075
|
+
continue;
|
|
17076
|
+
}
|
|
17077
|
+
syncSleep(RETRY_INTERVAL_MS);
|
|
17078
|
+
}
|
|
17079
|
+
}
|
|
17080
|
+
throw new Error(
|
|
17081
|
+
`Could not acquire credentials lock at ${LOCK_FILE} after ${MAX_RETRIES * RETRY_INTERVAL_MS / 1e3}s. Is another codevector command running? If you're sure none are, delete the lockfile manually.`
|
|
17082
|
+
);
|
|
17083
|
+
}
|
|
17084
|
+
function releaseLock() {
|
|
17085
|
+
try {
|
|
17086
|
+
unlinkSync(LOCK_FILE);
|
|
17087
|
+
} catch {
|
|
17088
|
+
}
|
|
17089
|
+
}
|
|
17090
|
+
|
|
17091
|
+
// src/lib/credentials.ts
|
|
17092
|
+
var ToolConfigSchema = external_exports.object({
|
|
17093
|
+
tool: external_exports.string().min(1),
|
|
17094
|
+
scope: external_exports.enum(["user", "project", "local"]),
|
|
17095
|
+
modelSlug: external_exports.string().optional()
|
|
17096
|
+
});
|
|
17097
|
+
var ProfileSchema = external_exports.object({
|
|
17098
|
+
apiKey: external_exports.string().min(1),
|
|
17099
|
+
gatewayUrl: external_exports.url(),
|
|
17100
|
+
userId: external_exports.uuid(),
|
|
17101
|
+
email: external_exports.email(),
|
|
17102
|
+
savedAt: external_exports.iso.datetime(),
|
|
17103
|
+
toolConfigs: external_exports.array(ToolConfigSchema).optional()
|
|
17104
|
+
});
|
|
17105
|
+
var ProfilesFileSchema = external_exports.object({
|
|
17106
|
+
activeProfile: external_exports.string().min(1),
|
|
17107
|
+
profiles: external_exports.record(external_exports.string().min(1), ProfileSchema)
|
|
17108
|
+
});
|
|
17109
|
+
function writeProfilesFile(payload) {
|
|
17110
|
+
const parsed = ProfilesFileSchema.parse(payload);
|
|
17111
|
+
const dir = dirname3(CREDENTIALS_FILE);
|
|
17112
|
+
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
17113
|
+
try {
|
|
17114
|
+
chmodSync2(dir, 448);
|
|
17115
|
+
} catch {
|
|
17116
|
+
}
|
|
17117
|
+
const tmp = `${CREDENTIALS_FILE}.${process.pid}.tmp`;
|
|
17118
|
+
writeFileSync4(tmp, JSON.stringify(parsed, null, 2), { mode: 384 });
|
|
17119
|
+
try {
|
|
17120
|
+
chmodSync2(tmp, 384);
|
|
17121
|
+
} catch {
|
|
17122
|
+
}
|
|
17123
|
+
renameSync2(tmp, CREDENTIALS_FILE);
|
|
17124
|
+
}
|
|
17125
|
+
function readProfilesSync() {
|
|
17126
|
+
let raw;
|
|
17127
|
+
try {
|
|
17128
|
+
raw = readFileSync5(CREDENTIALS_FILE, "utf8");
|
|
17129
|
+
} catch (err) {
|
|
17130
|
+
if (err.code === "ENOENT") return null;
|
|
17131
|
+
throw err;
|
|
17132
|
+
}
|
|
17133
|
+
let parsed;
|
|
17134
|
+
try {
|
|
17135
|
+
parsed = JSON.parse(raw);
|
|
17136
|
+
} catch {
|
|
17137
|
+
throw new Error(
|
|
17138
|
+
`${CREDENTIALS_FILE} is not valid JSON. Run \`codevector auth logout\` and re-login.`
|
|
17139
|
+
);
|
|
17140
|
+
}
|
|
17141
|
+
if (parsed && typeof parsed === "object" && "profiles" in parsed) {
|
|
17142
|
+
return ProfilesFileSchema.parse(parsed);
|
|
17143
|
+
}
|
|
17144
|
+
return withCredentialsLockSync(() => {
|
|
17145
|
+
let lockedRaw;
|
|
17146
|
+
try {
|
|
17147
|
+
lockedRaw = readFileSync5(CREDENTIALS_FILE, "utf8");
|
|
17148
|
+
} catch (err) {
|
|
17149
|
+
if (err.code === "ENOENT") {
|
|
17150
|
+
return null;
|
|
17151
|
+
}
|
|
17152
|
+
throw err;
|
|
17153
|
+
}
|
|
17154
|
+
const lockedParsed = JSON.parse(lockedRaw);
|
|
17155
|
+
if (lockedParsed && typeof lockedParsed === "object" && "profiles" in lockedParsed) {
|
|
17156
|
+
return ProfilesFileSchema.parse(lockedParsed);
|
|
17157
|
+
}
|
|
17158
|
+
const oldProfile = ProfileSchema.parse(lockedParsed);
|
|
17159
|
+
const seeded = seedToolConfigsFromDisk();
|
|
17160
|
+
const defaultProfile = {
|
|
17161
|
+
...oldProfile,
|
|
17162
|
+
...seeded.length > 0 ? { toolConfigs: seeded } : {}
|
|
17163
|
+
};
|
|
17164
|
+
const migrated = {
|
|
17165
|
+
activeProfile: "default",
|
|
17166
|
+
profiles: { default: defaultProfile }
|
|
17167
|
+
};
|
|
17168
|
+
try {
|
|
17169
|
+
writeProfilesFile(migrated);
|
|
17170
|
+
} catch {
|
|
17171
|
+
}
|
|
17172
|
+
return migrated;
|
|
17173
|
+
});
|
|
17174
|
+
}
|
|
17175
|
+
function seedToolConfigsFromDisk() {
|
|
17176
|
+
const out = [];
|
|
17177
|
+
const claude = detectClaudeCodeConfig();
|
|
17178
|
+
if (claude) {
|
|
17179
|
+
out.push({
|
|
17180
|
+
tool: "claude-code",
|
|
17181
|
+
scope: claude.scope,
|
|
17182
|
+
...claude.modelSlug ? { modelSlug: claude.modelSlug } : {}
|
|
17183
|
+
});
|
|
17184
|
+
}
|
|
17185
|
+
const opencode = detectOpencodeConfig();
|
|
17186
|
+
if (opencode) {
|
|
17187
|
+
out.push({
|
|
17188
|
+
tool: "opencode",
|
|
17189
|
+
scope: opencode.scope,
|
|
17190
|
+
...opencode.modelSlug ? { modelSlug: opencode.modelSlug } : {}
|
|
17191
|
+
});
|
|
17192
|
+
}
|
|
17193
|
+
return out;
|
|
17194
|
+
}
|
|
17195
|
+
async function readProfiles() {
|
|
17196
|
+
return readProfilesSync();
|
|
17197
|
+
}
|
|
17198
|
+
async function getActiveProfile() {
|
|
17199
|
+
const profiles = readProfilesSync();
|
|
17200
|
+
if (!profiles) return null;
|
|
17201
|
+
return profiles.profiles[profiles.activeProfile] ?? null;
|
|
17202
|
+
}
|
|
17203
|
+
async function setActiveProfile(name) {
|
|
17204
|
+
withCredentialsLockSync(() => {
|
|
17205
|
+
const profiles = readProfilesSync();
|
|
17206
|
+
if (!profiles) {
|
|
17207
|
+
throw new Error("No profiles configured. Run `codevector auth login` first.");
|
|
17208
|
+
}
|
|
17209
|
+
if (!profiles.profiles[name]) {
|
|
17210
|
+
throw new Error(`Profile "${name}" does not exist.`);
|
|
17211
|
+
}
|
|
17212
|
+
profiles.activeProfile = name;
|
|
17213
|
+
writeProfilesFile(profiles);
|
|
17214
|
+
});
|
|
17215
|
+
}
|
|
17216
|
+
function writeProfile(name, creds, toolConfigs) {
|
|
17217
|
+
return withCredentialsLockSync(() => {
|
|
17218
|
+
const existing = readProfilesSync();
|
|
17219
|
+
const resolvedToolConfigs = toolConfigs ?? existing?.profiles[name]?.toolConfigs;
|
|
17220
|
+
const payload = {
|
|
17221
|
+
...creds,
|
|
17222
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17223
|
+
...resolvedToolConfigs ? { toolConfigs: resolvedToolConfigs } : {}
|
|
17224
|
+
};
|
|
17225
|
+
const parsed = ProfileSchema.parse(payload);
|
|
17226
|
+
const profiles = existing ?? { activeProfile: name, profiles: {} };
|
|
17227
|
+
profiles.profiles[name] = parsed;
|
|
17228
|
+
profiles.activeProfile = name;
|
|
17229
|
+
writeProfilesFile(profiles);
|
|
17230
|
+
return parsed;
|
|
17231
|
+
});
|
|
17232
|
+
}
|
|
17233
|
+
async function readCredentials() {
|
|
17234
|
+
return getActiveProfile();
|
|
17235
|
+
}
|
|
17236
|
+
function deleteProfile(name) {
|
|
17237
|
+
return withCredentialsLockSync(() => {
|
|
17238
|
+
const profiles = readProfilesSync();
|
|
17239
|
+
if (!profiles) return false;
|
|
17240
|
+
if (!profiles.profiles[name]) return false;
|
|
17241
|
+
delete profiles.profiles[name];
|
|
17242
|
+
const remaining = Object.keys(profiles.profiles);
|
|
17243
|
+
if (remaining.length === 0) {
|
|
17244
|
+
rmSync(CREDENTIALS_FILE, { force: true });
|
|
17245
|
+
return true;
|
|
17246
|
+
}
|
|
17247
|
+
if (profiles.activeProfile === name) {
|
|
17248
|
+
const next = remaining.sort((a, b2) => {
|
|
17249
|
+
if (a === "default") return -1;
|
|
17250
|
+
if (b2 === "default") return 1;
|
|
17251
|
+
return a.localeCompare(b2);
|
|
17252
|
+
})[0];
|
|
17253
|
+
profiles.activeProfile = next;
|
|
17254
|
+
}
|
|
17255
|
+
writeProfilesFile(profiles);
|
|
17256
|
+
return true;
|
|
17257
|
+
});
|
|
17258
|
+
}
|
|
17259
|
+
function updateProfileToolConfigs(name, configs) {
|
|
17260
|
+
withCredentialsLockSync(() => {
|
|
17261
|
+
const profiles = readProfilesSync();
|
|
17262
|
+
if (!profiles || !profiles.profiles[name]) {
|
|
17263
|
+
throw new Error(`Profile "${name}" does not exist.`);
|
|
17264
|
+
}
|
|
17265
|
+
const profile = profiles.profiles[name];
|
|
17266
|
+
const existing = profile.toolConfigs ?? [];
|
|
17267
|
+
const byTool = new Map(existing.map((c) => [c.tool, c]));
|
|
17268
|
+
for (const cfg of configs) {
|
|
17269
|
+
byTool.set(cfg.tool, cfg);
|
|
17270
|
+
}
|
|
17271
|
+
profile.toolConfigs = Array.from(byTool.values());
|
|
17272
|
+
writeProfilesFile(profiles);
|
|
17273
|
+
});
|
|
17274
|
+
}
|
|
17275
|
+
function credentialsFileModeOk() {
|
|
17276
|
+
try {
|
|
17277
|
+
const stats = statSync3(CREDENTIALS_FILE);
|
|
17278
|
+
const mode = stats.mode & 511;
|
|
17279
|
+
return mode === 384;
|
|
17280
|
+
} catch {
|
|
17281
|
+
return false;
|
|
17282
|
+
}
|
|
17283
|
+
}
|
|
17284
|
+
function maskApiKey(key) {
|
|
17285
|
+
if (key.length <= 12) return "********";
|
|
17286
|
+
return `${key.slice(0, 5)}\u2026${key.slice(-4)}`;
|
|
17287
|
+
}
|
|
17288
|
+
|
|
17289
|
+
// src/lib/prompt.ts
|
|
17290
|
+
function unwrap(value) {
|
|
17291
|
+
if (q(value)) {
|
|
17292
|
+
me("Cancelled.");
|
|
17293
|
+
process.exit(130);
|
|
17294
|
+
}
|
|
17295
|
+
return value;
|
|
17296
|
+
}
|
|
17297
|
+
async function promptText(message, placeholder) {
|
|
17298
|
+
return unwrap(
|
|
17299
|
+
await Pe({
|
|
16601
17300
|
message,
|
|
16602
17301
|
placeholder,
|
|
16603
17302
|
validate: (v2) => !v2 || v2.trim().length === 0 ? "Required." : void 0
|
|
@@ -16627,10 +17326,63 @@ var authLoginCommand = defineCommand({
|
|
|
16627
17326
|
"api-key": {
|
|
16628
17327
|
type: "string",
|
|
16629
17328
|
description: "API key. Prompted (masked) if omitted."
|
|
17329
|
+
},
|
|
17330
|
+
profile: {
|
|
17331
|
+
type: "string",
|
|
17332
|
+
description: "Profile name to create or update. Prompted if omitted."
|
|
16630
17333
|
}
|
|
16631
17334
|
},
|
|
16632
17335
|
async run({ args }) {
|
|
16633
17336
|
ge("codevector auth login");
|
|
17337
|
+
const profiles = await readProfiles();
|
|
17338
|
+
const existingNames = profiles ? Object.keys(profiles.profiles) : [];
|
|
17339
|
+
const hasDefault = existingNames.includes("default");
|
|
17340
|
+
let profileName;
|
|
17341
|
+
if (args.profile) {
|
|
17342
|
+
const trimmed = args.profile.trim();
|
|
17343
|
+
if (!trimmed || trimmed === "__create__") {
|
|
17344
|
+
R2.error(
|
|
17345
|
+
trimmed ? `"__create__" is a reserved name. Choose a different profile name.` : "Profile name cannot be empty."
|
|
17346
|
+
);
|
|
17347
|
+
process.exitCode = 1;
|
|
17348
|
+
return;
|
|
17349
|
+
}
|
|
17350
|
+
profileName = trimmed;
|
|
17351
|
+
} else {
|
|
17352
|
+
const options = [
|
|
17353
|
+
{ value: "default", label: "default", hint: hasDefault ? "existing" : "new" },
|
|
17354
|
+
{ value: "__create__", label: "Create new profile" },
|
|
17355
|
+
...existingNames.filter((n) => n !== "default").sort().map((name) => ({ value: name, label: name, hint: "existing" }))
|
|
17356
|
+
];
|
|
17357
|
+
const selected = unwrap(
|
|
17358
|
+
await xe({
|
|
17359
|
+
message: "Select Profile",
|
|
17360
|
+
options,
|
|
17361
|
+
initialValue: profiles?.activeProfile ?? "default"
|
|
17362
|
+
})
|
|
17363
|
+
);
|
|
17364
|
+
if (selected === "__create__") {
|
|
17365
|
+
const name = unwrap(
|
|
17366
|
+
await Pe({
|
|
17367
|
+
message: "Profile Name",
|
|
17368
|
+
validate: (v2) => {
|
|
17369
|
+
const trimmed = v2?.trim();
|
|
17370
|
+
if (!trimmed) return "Required.";
|
|
17371
|
+
if (trimmed === "default")
|
|
17372
|
+
return `"default" is reserved. Select "default" from the list instead.`;
|
|
17373
|
+
if (trimmed === "__create__")
|
|
17374
|
+
return `"__create__" is a reserved name. Choose a different name.`;
|
|
17375
|
+
if (existingNames.includes(trimmed))
|
|
17376
|
+
return `Profile "${trimmed}" already exists. Choose a different name or select it from the list to update it.`;
|
|
17377
|
+
return void 0;
|
|
17378
|
+
}
|
|
17379
|
+
})
|
|
17380
|
+
);
|
|
17381
|
+
profileName = name.trim();
|
|
17382
|
+
} else {
|
|
17383
|
+
profileName = selected;
|
|
17384
|
+
}
|
|
17385
|
+
}
|
|
16634
17386
|
const gatewayUrl = (args["gateway-url"] ?? await promptText("Gateway URL", "https://...")).trim();
|
|
16635
17387
|
if (!gatewayUrl) throw new Error("Gateway URL is required.");
|
|
16636
17388
|
assertHttpsUrl(gatewayUrl);
|
|
@@ -16642,15 +17394,16 @@ var authLoginCommand = defineCommand({
|
|
|
16642
17394
|
try {
|
|
16643
17395
|
const me2 = await translateErrors(() => call(parseResponse(client.me.$get())));
|
|
16644
17396
|
const config2 = await translateErrors(() => call(parseResponse(client.config.$get())));
|
|
16645
|
-
const stored =
|
|
17397
|
+
const stored = writeProfile(profileName, {
|
|
16646
17398
|
apiKey,
|
|
16647
17399
|
gatewayUrl: config2.gatewayPublicUrl,
|
|
16648
17400
|
userId: me2.user.id,
|
|
16649
17401
|
email: me2.user.email
|
|
16650
17402
|
});
|
|
16651
|
-
s.stop(`Signed in as ${stored.email}`);
|
|
17403
|
+
s.stop(`Signed in as ${stored.email} (${profileName})`);
|
|
16652
17404
|
Se(
|
|
16653
17405
|
`Gateway: ${stored.gatewayUrl}
|
|
17406
|
+
Profile: ${profileName}
|
|
16654
17407
|
Next: run \`codevector configure claude-code\`.`,
|
|
16655
17408
|
"Credentials saved"
|
|
16656
17409
|
);
|
|
@@ -16665,16 +17418,50 @@ Next: run \`codevector configure claude-code\`.`,
|
|
|
16665
17418
|
var authLogoutCommand = defineCommand({
|
|
16666
17419
|
meta: {
|
|
16667
17420
|
name: "logout",
|
|
16668
|
-
description: "Delete local credentials."
|
|
17421
|
+
description: "Delete local credentials for a profile."
|
|
16669
17422
|
},
|
|
16670
|
-
|
|
16671
|
-
|
|
17423
|
+
args: {
|
|
17424
|
+
profile: {
|
|
17425
|
+
type: "string",
|
|
17426
|
+
description: "Profile to log out of. Defaults to the active profile."
|
|
17427
|
+
}
|
|
17428
|
+
},
|
|
17429
|
+
async run({ args }) {
|
|
17430
|
+
const profiles = await readProfiles();
|
|
17431
|
+
if (!profiles || Object.keys(profiles.profiles).length === 0) {
|
|
17432
|
+
R2.info("No credentials were found. Nothing to do.");
|
|
17433
|
+
return;
|
|
17434
|
+
}
|
|
17435
|
+
let target = args.profile;
|
|
17436
|
+
if (!target) {
|
|
17437
|
+
const names = Object.keys(profiles.profiles);
|
|
17438
|
+
if (names.length === 1) {
|
|
17439
|
+
target = names[0];
|
|
17440
|
+
} else {
|
|
17441
|
+
const sortedNames = [...names].sort((a, b2) => {
|
|
17442
|
+
if (a === "default") return -1;
|
|
17443
|
+
if (b2 === "default") return 1;
|
|
17444
|
+
return a.localeCompare(b2);
|
|
17445
|
+
});
|
|
17446
|
+
const options = sortedNames.map((n) => ({
|
|
17447
|
+
value: n,
|
|
17448
|
+
label: n,
|
|
17449
|
+
hint: profiles.activeProfile === n ? "active" : void 0
|
|
17450
|
+
}));
|
|
17451
|
+
target = unwrap(
|
|
17452
|
+
await xe({
|
|
17453
|
+
message: "Select profile to log out of",
|
|
17454
|
+
options,
|
|
17455
|
+
initialValue: profiles.activeProfile
|
|
17456
|
+
})
|
|
17457
|
+
);
|
|
17458
|
+
}
|
|
17459
|
+
}
|
|
17460
|
+
const removed = deleteProfile(target);
|
|
16672
17461
|
if (removed) {
|
|
16673
|
-
R2.success(
|
|
16674
|
-
"Logged out. Hooks are left in place \u2014 run `codevector auth login` to sign back in."
|
|
16675
|
-
);
|
|
17462
|
+
R2.success(`Logged out of profile "${target}".`);
|
|
16676
17463
|
} else {
|
|
16677
|
-
R2.info("
|
|
17464
|
+
R2.info(`Profile "${target}" not found. Nothing to do.`);
|
|
16678
17465
|
}
|
|
16679
17466
|
}
|
|
16680
17467
|
});
|
|
@@ -16753,32 +17540,32 @@ function assertHttpsUrl(urlString) {
|
|
|
16753
17540
|
}
|
|
16754
17541
|
|
|
16755
17542
|
// src/commands/configure.ts
|
|
16756
|
-
import { homedir as
|
|
17543
|
+
import { homedir as homedir5 } from "os";
|
|
16757
17544
|
|
|
16758
17545
|
// src/lib/hooks.ts
|
|
16759
|
-
import { chmodSync as
|
|
16760
|
-
import { dirname as
|
|
17546
|
+
import { chmodSync as chmodSync3, copyFileSync, existsSync as existsSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
17547
|
+
import { dirname as dirname4, join as join5 } from "path";
|
|
16761
17548
|
import { fileURLToPath } from "url";
|
|
16762
17549
|
function bundledHookSource() {
|
|
16763
|
-
const here =
|
|
17550
|
+
const here = dirname4(fileURLToPath(import.meta.url));
|
|
16764
17551
|
const candidates = [
|
|
16765
|
-
|
|
17552
|
+
join5(here, "hooks", "acceptance.sh"),
|
|
16766
17553
|
// production — dist/hooks/…
|
|
16767
|
-
|
|
17554
|
+
join5(here, "..", "hooks", "acceptance.sh")
|
|
16768
17555
|
// dev — src/hooks/…
|
|
16769
17556
|
];
|
|
16770
17557
|
for (const candidate of candidates) {
|
|
16771
|
-
if (
|
|
17558
|
+
if (existsSync4(candidate)) return candidate;
|
|
16772
17559
|
}
|
|
16773
17560
|
throw new Error(
|
|
16774
17561
|
"Could not locate the bundled acceptance hook script (acceptance.sh). Reinstall @codevector/cli to repair the installation."
|
|
16775
17562
|
);
|
|
16776
17563
|
}
|
|
16777
17564
|
function installAcceptanceHook() {
|
|
16778
|
-
|
|
17565
|
+
mkdirSync4(HOOKS_DIR, { recursive: true, mode: 448 });
|
|
16779
17566
|
copyFileSync(bundledHookSource(), ACCEPTANCE_HOOK_FILE);
|
|
16780
17567
|
try {
|
|
16781
|
-
|
|
17568
|
+
chmodSync3(ACCEPTANCE_HOOK_FILE, 493);
|
|
16782
17569
|
} catch {
|
|
16783
17570
|
}
|
|
16784
17571
|
return ACCEPTANCE_HOOK_FILE;
|
|
@@ -16786,8 +17573,8 @@ function installAcceptanceHook() {
|
|
|
16786
17573
|
|
|
16787
17574
|
// src/lib/project-context.ts
|
|
16788
17575
|
import { execFileSync } from "child_process";
|
|
16789
|
-
import { existsSync as
|
|
16790
|
-
import { join as
|
|
17576
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
|
|
17577
|
+
import { join as join6 } from "path";
|
|
16791
17578
|
var DEFAULT_TICKET_PATTERN = /[A-Z]+-\d+/;
|
|
16792
17579
|
function safeGit(args, cwd) {
|
|
16793
17580
|
try {
|
|
@@ -16826,10 +17613,10 @@ function resolveProjectContext(cwd = process.cwd(), ticketPattern = DEFAULT_TICK
|
|
|
16826
17613
|
return { project, ticket };
|
|
16827
17614
|
}
|
|
16828
17615
|
function readLocalConfig(cwd) {
|
|
16829
|
-
const path =
|
|
16830
|
-
if (!
|
|
17616
|
+
const path = join6(cwd, ".codevector.json");
|
|
17617
|
+
if (!existsSync5(path)) return null;
|
|
16831
17618
|
try {
|
|
16832
|
-
const parsed = JSON.parse(
|
|
17619
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
16833
17620
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
16834
17621
|
const p2 = parsed;
|
|
16835
17622
|
const result = {};
|
|
@@ -16852,193 +17639,18 @@ function safeCompileTicketPattern(pattern) {
|
|
|
16852
17639
|
}
|
|
16853
17640
|
}
|
|
16854
17641
|
|
|
16855
|
-
// src/config-writers/claude-code.ts
|
|
16856
|
-
import { homedir as homedir2 } from "os";
|
|
16857
|
-
import { join as join4 } from "path";
|
|
16858
|
-
|
|
16859
|
-
// src/lib/merge-json.ts
|
|
16860
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
16861
|
-
import { dirname as dirname3 } from "path";
|
|
16862
|
-
function isPlainObject2(v2) {
|
|
16863
|
-
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
16864
|
-
}
|
|
16865
|
-
function deepMerge2(base, patch, opts = {}, currentPath = []) {
|
|
16866
|
-
const hookPaths = new Set(opts.hookArrayPaths ?? []);
|
|
16867
|
-
const dedupeKey = opts.hookDedupeKey ?? "command";
|
|
16868
|
-
const out = { ...base };
|
|
16869
|
-
for (const [k2, v2] of Object.entries(patch)) {
|
|
16870
|
-
const nextPath = [...currentPath, k2];
|
|
16871
|
-
const pathStr = nextPath.join(".");
|
|
16872
|
-
const existing = out[k2];
|
|
16873
|
-
if (isPlainObject2(v2) && isPlainObject2(existing)) {
|
|
16874
|
-
out[k2] = deepMerge2(existing, v2, opts, nextPath);
|
|
16875
|
-
continue;
|
|
16876
|
-
}
|
|
16877
|
-
if (Array.isArray(v2) && Array.isArray(existing) && hookPaths.has(pathStr)) {
|
|
16878
|
-
out[k2] = mergeHookArray(existing, v2, dedupeKey);
|
|
16879
|
-
continue;
|
|
16880
|
-
}
|
|
16881
|
-
out[k2] = v2;
|
|
16882
|
-
}
|
|
16883
|
-
return out;
|
|
16884
|
-
}
|
|
16885
|
-
function extractHookCommands(entry, dedupeKey) {
|
|
16886
|
-
if (!isPlainObject2(entry)) return [];
|
|
16887
|
-
if (typeof entry[dedupeKey] === "string") return [entry[dedupeKey]];
|
|
16888
|
-
const inner = entry.hooks;
|
|
16889
|
-
if (!Array.isArray(inner)) return [];
|
|
16890
|
-
return inner.filter(isPlainObject2).map((h2) => h2[dedupeKey]).filter((x) => typeof x === "string");
|
|
16891
|
-
}
|
|
16892
|
-
function mergeHookArray(existing, patch, dedupeKey) {
|
|
16893
|
-
const patchCommands = new Set(patch.flatMap((e2) => extractHookCommands(e2, dedupeKey)));
|
|
16894
|
-
const kept = existing.filter((entry) => {
|
|
16895
|
-
if (!isPlainObject2(entry) || typeof entry[dedupeKey] !== "string") return true;
|
|
16896
|
-
return !patchCommands.has(entry[dedupeKey]);
|
|
16897
|
-
});
|
|
16898
|
-
const keptCommands = new Set(kept.flatMap((e2) => extractHookCommands(e2, dedupeKey)));
|
|
16899
|
-
const additions = patch.filter((entry) => {
|
|
16900
|
-
const cmds = extractHookCommands(entry, dedupeKey);
|
|
16901
|
-
if (cmds.length === 0) return true;
|
|
16902
|
-
return !cmds.some((c2) => keptCommands.has(c2));
|
|
16903
|
-
});
|
|
16904
|
-
return [...kept, ...additions];
|
|
16905
|
-
}
|
|
16906
|
-
function mergeJsonFile(filePath, patch, opts = {}) {
|
|
16907
|
-
const dir = dirname3(filePath);
|
|
16908
|
-
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
16909
|
-
let existing = {};
|
|
16910
|
-
let mode;
|
|
16911
|
-
try {
|
|
16912
|
-
const raw = readFileSync2(filePath, "utf8");
|
|
16913
|
-
if (raw.trim().length > 0) {
|
|
16914
|
-
const parsed = JSON.parse(raw);
|
|
16915
|
-
if (isPlainObject2(parsed)) existing = parsed;
|
|
16916
|
-
else {
|
|
16917
|
-
throw new Error(
|
|
16918
|
-
`${filePath} contains non-object JSON (${Array.isArray(parsed) ? "array" : typeof parsed}). Refusing to overwrite.`
|
|
16919
|
-
);
|
|
16920
|
-
}
|
|
16921
|
-
}
|
|
16922
|
-
mode = statSync2(filePath).mode & 511;
|
|
16923
|
-
} catch (err) {
|
|
16924
|
-
if (err.code !== "ENOENT") throw err;
|
|
16925
|
-
}
|
|
16926
|
-
const merged = deepMerge2(existing, patch, opts);
|
|
16927
|
-
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
16928
|
-
writeFileSync2(tmp, `${JSON.stringify(merged, null, 2)}
|
|
16929
|
-
`);
|
|
16930
|
-
if (mode !== void 0) {
|
|
16931
|
-
try {
|
|
16932
|
-
chmodSync3(tmp, mode);
|
|
16933
|
-
} catch {
|
|
16934
|
-
}
|
|
16935
|
-
}
|
|
16936
|
-
renameSync2(tmp, filePath);
|
|
16937
|
-
return merged;
|
|
16938
|
-
}
|
|
16939
|
-
|
|
16940
|
-
// src/config-writers/claude-code.ts
|
|
16941
|
-
var writeClaudeCodeConfig = ({
|
|
16942
|
-
gatewayUrl,
|
|
16943
|
-
apiKey,
|
|
16944
|
-
hookScriptPath,
|
|
16945
|
-
scope,
|
|
16946
|
-
project,
|
|
16947
|
-
model,
|
|
16948
|
-
availableModels = []
|
|
16949
|
-
}) => {
|
|
16950
|
-
const path = claudeSettingsPath(scope);
|
|
16951
|
-
const baseUrl = `${trimRightSlash2(gatewayUrl)}/gateway/anthropic`;
|
|
16952
|
-
const env = {
|
|
16953
|
-
ANTHROPIC_BASE_URL: baseUrl,
|
|
16954
|
-
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
16955
|
-
ANTHROPIC_CUSTOM_HEADERS: buildCustomHeaders(scope, project)
|
|
16956
|
-
};
|
|
16957
|
-
for (const [key, value] of Object.entries(resolveTierDefaults(availableModels))) {
|
|
16958
|
-
env[key] = value;
|
|
16959
|
-
}
|
|
16960
|
-
const patch = {
|
|
16961
|
-
env,
|
|
16962
|
-
hooks: {
|
|
16963
|
-
Stop: [{ matcher: "*", hooks: [{ type: "command", command: hookScriptPath }] }],
|
|
16964
|
-
SessionEnd: [{ matcher: "*", hooks: [{ type: "command", command: hookScriptPath }] }]
|
|
16965
|
-
}
|
|
16966
|
-
};
|
|
16967
|
-
if (model) patch.model = model.slug;
|
|
16968
|
-
if (availableModels.length > 0) {
|
|
16969
|
-
patch.availableModels = availableModels.map((m) => m.slug).sort();
|
|
16970
|
-
}
|
|
16971
|
-
mergeJsonFile(path, patch, {
|
|
16972
|
-
hookArrayPaths: ["hooks.Stop", "hooks.SessionEnd"],
|
|
16973
|
-
hookDedupeKey: "command"
|
|
16974
|
-
});
|
|
16975
|
-
const notes = [];
|
|
16976
|
-
if (scope === "local") notes.push("Claude Code auto-ignores settings.local.json in git.");
|
|
16977
|
-
if (scope !== "user" && !project) {
|
|
16978
|
-
notes.push(
|
|
16979
|
-
"Project slug could not be derived (no git remote and no .codevector.json). Per-project usage attribution will be blank until you set one."
|
|
16980
|
-
);
|
|
16981
|
-
}
|
|
16982
|
-
return {
|
|
16983
|
-
tool: "claude-code",
|
|
16984
|
-
status: "configured",
|
|
16985
|
-
path,
|
|
16986
|
-
scope,
|
|
16987
|
-
notes: notes.length > 0 ? notes.join(" ") : void 0
|
|
16988
|
-
};
|
|
16989
|
-
};
|
|
16990
|
-
function claudeSettingsPath(scope) {
|
|
16991
|
-
switch (scope) {
|
|
16992
|
-
case "user":
|
|
16993
|
-
return join4(homedir2(), ".claude", "settings.json");
|
|
16994
|
-
case "project":
|
|
16995
|
-
return join4(userCwd(), ".claude", "settings.json");
|
|
16996
|
-
case "local":
|
|
16997
|
-
return join4(userCwd(), ".claude", "settings.local.json");
|
|
16998
|
-
}
|
|
16999
|
-
}
|
|
17000
|
-
function resolveTierDefaults(available) {
|
|
17001
|
-
const out = {};
|
|
17002
|
-
const tierToEnv = {
|
|
17003
|
-
haiku: "ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
17004
|
-
sonnet: "ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
17005
|
-
opus: "ANTHROPIC_DEFAULT_OPUS_MODEL"
|
|
17006
|
-
};
|
|
17007
|
-
for (const [tier, envKey] of Object.entries(tierToEnv)) {
|
|
17008
|
-
const matches = available.filter(
|
|
17009
|
-
(m) => typeof m.family === "string" && m.family.toLowerCase().includes(tier)
|
|
17010
|
-
);
|
|
17011
|
-
if (matches.length === 1) {
|
|
17012
|
-
out[envKey] = matches[0].slug;
|
|
17013
|
-
}
|
|
17014
|
-
}
|
|
17015
|
-
return out;
|
|
17016
|
-
}
|
|
17017
|
-
function buildCustomHeaders(scope, project) {
|
|
17018
|
-
const safe = (v2) => v2.replace(/[\r\n]/g, "").trim();
|
|
17019
|
-
const headers = [`x-client-app: claude-code`];
|
|
17020
|
-
if (scope !== "user" && project) {
|
|
17021
|
-
const slug = safe(project);
|
|
17022
|
-
if (slug) headers.push(`x-project: ${slug}`);
|
|
17023
|
-
}
|
|
17024
|
-
return headers.join("\n");
|
|
17025
|
-
}
|
|
17026
|
-
function trimRightSlash2(url2) {
|
|
17027
|
-
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
17028
|
-
}
|
|
17029
|
-
|
|
17030
17642
|
// src/config-writers/codex.ts
|
|
17031
17643
|
import {
|
|
17032
17644
|
chmodSync as chmodSync4,
|
|
17033
|
-
existsSync as
|
|
17034
|
-
mkdirSync as
|
|
17035
|
-
readFileSync as
|
|
17645
|
+
existsSync as existsSync6,
|
|
17646
|
+
mkdirSync as mkdirSync5,
|
|
17647
|
+
readFileSync as readFileSync7,
|
|
17036
17648
|
renameSync as renameSync3,
|
|
17037
|
-
statSync as
|
|
17038
|
-
writeFileSync as
|
|
17649
|
+
statSync as statSync4,
|
|
17650
|
+
writeFileSync as writeFileSync5
|
|
17039
17651
|
} from "fs";
|
|
17040
|
-
import { dirname as
|
|
17041
|
-
import { homedir as
|
|
17652
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
17653
|
+
import { homedir as homedir4 } from "os";
|
|
17042
17654
|
|
|
17043
17655
|
// ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/error.js
|
|
17044
17656
|
function getLineColFromPtr(string4, ptr) {
|
|
@@ -17095,12 +17707,12 @@ function indexOfNewline(str, start = 0, end = str.length) {
|
|
|
17095
17707
|
}
|
|
17096
17708
|
function skipComment(str, ptr) {
|
|
17097
17709
|
for (let i = ptr; i < str.length; i++) {
|
|
17098
|
-
let
|
|
17099
|
-
if (
|
|
17710
|
+
let c = str[i];
|
|
17711
|
+
if (c === "\n")
|
|
17100
17712
|
return i;
|
|
17101
|
-
if (
|
|
17713
|
+
if (c === "\r" && str[i + 1] === "\n")
|
|
17102
17714
|
return i + 1;
|
|
17103
|
-
if (
|
|
17715
|
+
if (c < " " && c !== " " || c === "\x7F") {
|
|
17104
17716
|
throw new TomlError("control characters are not allowed in comments", {
|
|
17105
17717
|
toml: str,
|
|
17106
17718
|
ptr
|
|
@@ -17110,11 +17722,11 @@ function skipComment(str, ptr) {
|
|
|
17110
17722
|
return str.length;
|
|
17111
17723
|
}
|
|
17112
17724
|
function skipVoid(str, ptr, banNewLines, banComments) {
|
|
17113
|
-
let
|
|
17725
|
+
let c;
|
|
17114
17726
|
while (1) {
|
|
17115
|
-
while ((
|
|
17727
|
+
while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
|
|
17116
17728
|
ptr++;
|
|
17117
|
-
if (banComments ||
|
|
17729
|
+
if (banComments || c !== "#")
|
|
17118
17730
|
break;
|
|
17119
17731
|
ptr = skipComment(str, ptr);
|
|
17120
17732
|
}
|
|
@@ -17126,12 +17738,12 @@ function skipUntil(str, ptr, sep, end, banNewLines = false) {
|
|
|
17126
17738
|
return ptr < 0 ? str.length : ptr;
|
|
17127
17739
|
}
|
|
17128
17740
|
for (let i = ptr; i < str.length; i++) {
|
|
17129
|
-
let
|
|
17130
|
-
if (
|
|
17741
|
+
let c = str[i];
|
|
17742
|
+
if (c === "#") {
|
|
17131
17743
|
i = indexOfNewline(str, i);
|
|
17132
|
-
} else if (
|
|
17744
|
+
} else if (c === sep) {
|
|
17133
17745
|
return i + 1;
|
|
17134
|
-
} else if (
|
|
17746
|
+
} else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
|
|
17135
17747
|
return i;
|
|
17136
17748
|
}
|
|
17137
17749
|
}
|
|
@@ -17281,15 +17893,15 @@ function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
17281
17893
|
let parsed = "";
|
|
17282
17894
|
let sliceStart = ptr;
|
|
17283
17895
|
while (ptr < endPtr - 1) {
|
|
17284
|
-
let
|
|
17285
|
-
if (
|
|
17896
|
+
let c = str[ptr++];
|
|
17897
|
+
if (c === "\n" || c === "\r" && str[ptr] === "\n") {
|
|
17286
17898
|
if (!isMultiline) {
|
|
17287
17899
|
throw new TomlError("newlines are not allowed in strings", {
|
|
17288
17900
|
toml: str,
|
|
17289
17901
|
ptr: ptr - 1
|
|
17290
17902
|
});
|
|
17291
17903
|
}
|
|
17292
|
-
} else if (
|
|
17904
|
+
} else if (c < " " && c !== " " || c === "\x7F") {
|
|
17293
17905
|
throw new TomlError("control characters are not allowed in strings", {
|
|
17294
17906
|
toml: str,
|
|
17295
17907
|
ptr: ptr - 1
|
|
@@ -17297,8 +17909,8 @@ function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
17297
17909
|
}
|
|
17298
17910
|
if (isEscape) {
|
|
17299
17911
|
isEscape = false;
|
|
17300
|
-
if (
|
|
17301
|
-
let code = str.slice(ptr, ptr +=
|
|
17912
|
+
if (c === "x" || c === "u" || c === "U") {
|
|
17913
|
+
let code = str.slice(ptr, ptr += c === "x" ? 2 : c === "u" ? 4 : 8);
|
|
17302
17914
|
if (!ESCAPE_REGEX.test(code)) {
|
|
17303
17915
|
throw new TomlError("invalid unicode escape", {
|
|
17304
17916
|
toml: str,
|
|
@@ -17313,7 +17925,7 @@ function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
17313
17925
|
ptr: tmp
|
|
17314
17926
|
});
|
|
17315
17927
|
}
|
|
17316
|
-
} else if (isMultiline && (
|
|
17928
|
+
} else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) {
|
|
17317
17929
|
ptr = skipVoid(str, ptr - 1, true);
|
|
17318
17930
|
if (str[ptr] !== "\n" && str[ptr] !== "\r") {
|
|
17319
17931
|
throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
|
|
@@ -17322,8 +17934,8 @@ function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
17322
17934
|
});
|
|
17323
17935
|
}
|
|
17324
17936
|
ptr = skipVoid(str, ptr);
|
|
17325
|
-
} else if (
|
|
17326
|
-
parsed += ESC_MAP[
|
|
17937
|
+
} else if (c in ESC_MAP) {
|
|
17938
|
+
parsed += ESC_MAP[c];
|
|
17327
17939
|
} else {
|
|
17328
17940
|
throw new TomlError("unrecognized escape sequence", {
|
|
17329
17941
|
toml: str,
|
|
@@ -17331,7 +17943,7 @@ function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
17331
17943
|
});
|
|
17332
17944
|
}
|
|
17333
17945
|
sliceStart = ptr;
|
|
17334
|
-
} else if (!isLiteral &&
|
|
17946
|
+
} else if (!isLiteral && c === "\\") {
|
|
17335
17947
|
tmp = ptr - 1;
|
|
17336
17948
|
isEscape = true;
|
|
17337
17949
|
parsed += str.slice(sliceStart, tmp);
|
|
@@ -17407,9 +18019,9 @@ function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
|
17407
18019
|
ptr
|
|
17408
18020
|
});
|
|
17409
18021
|
}
|
|
17410
|
-
let
|
|
17411
|
-
if (
|
|
17412
|
-
let [value, endPtr2] =
|
|
18022
|
+
let c = str[ptr];
|
|
18023
|
+
if (c === "[" || c === "{") {
|
|
18024
|
+
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
|
17413
18025
|
if (end) {
|
|
17414
18026
|
endPtr2 = skipVoid(str, endPtr2);
|
|
17415
18027
|
if (str[endPtr2] === ",")
|
|
@@ -17424,7 +18036,7 @@ function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
|
17424
18036
|
return [value, endPtr2];
|
|
17425
18037
|
}
|
|
17426
18038
|
let endPtr;
|
|
17427
|
-
if (
|
|
18039
|
+
if (c === '"' || c === "'") {
|
|
17428
18040
|
endPtr = getStringEnd(str, ptr);
|
|
17429
18041
|
let parsed = parseString(str, ptr, endPtr);
|
|
17430
18042
|
if (end) {
|
|
@@ -17470,10 +18082,10 @@ function parseKey(str, ptr, end = "=") {
|
|
|
17470
18082
|
});
|
|
17471
18083
|
}
|
|
17472
18084
|
do {
|
|
17473
|
-
let
|
|
17474
|
-
if (
|
|
17475
|
-
if (
|
|
17476
|
-
if (
|
|
18085
|
+
let c = str[ptr = ++dot];
|
|
18086
|
+
if (c !== " " && c !== " ") {
|
|
18087
|
+
if (c === '"' || c === "'") {
|
|
18088
|
+
if (c === str[ptr + 1] && c === str[ptr + 2]) {
|
|
17477
18089
|
throw new TomlError("multiline strings are not allowed in keys", {
|
|
17478
18090
|
toml: str,
|
|
17479
18091
|
ptr
|
|
@@ -17529,17 +18141,17 @@ function parseKey(str, ptr, end = "=") {
|
|
|
17529
18141
|
function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
17530
18142
|
let res = {};
|
|
17531
18143
|
let seen = /* @__PURE__ */ new Set();
|
|
17532
|
-
let
|
|
18144
|
+
let c;
|
|
17533
18145
|
ptr++;
|
|
17534
|
-
while ((
|
|
17535
|
-
if (
|
|
18146
|
+
while ((c = str[ptr++]) !== "}" && c) {
|
|
18147
|
+
if (c === ",") {
|
|
17536
18148
|
throw new TomlError("expected value, found comma", {
|
|
17537
18149
|
toml: str,
|
|
17538
18150
|
ptr: ptr - 1
|
|
17539
18151
|
});
|
|
17540
|
-
} else if (
|
|
18152
|
+
} else if (c === "#")
|
|
17541
18153
|
ptr = skipComment(str, ptr);
|
|
17542
|
-
else if (
|
|
18154
|
+
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
17543
18155
|
let k2;
|
|
17544
18156
|
let t = res;
|
|
17545
18157
|
let hasOwn = false;
|
|
@@ -17570,7 +18182,7 @@ function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
|
17570
18182
|
ptr = valueEndPtr;
|
|
17571
18183
|
}
|
|
17572
18184
|
}
|
|
17573
|
-
if (!
|
|
18185
|
+
if (!c) {
|
|
17574
18186
|
throw new TomlError("unfinished table encountered", {
|
|
17575
18187
|
toml: str,
|
|
17576
18188
|
ptr
|
|
@@ -17580,23 +18192,23 @@ function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
|
17580
18192
|
}
|
|
17581
18193
|
function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
17582
18194
|
let res = [];
|
|
17583
|
-
let
|
|
18195
|
+
let c;
|
|
17584
18196
|
ptr++;
|
|
17585
|
-
while ((
|
|
17586
|
-
if (
|
|
18197
|
+
while ((c = str[ptr++]) !== "]" && c) {
|
|
18198
|
+
if (c === ",") {
|
|
17587
18199
|
throw new TomlError("expected value, found comma", {
|
|
17588
18200
|
toml: str,
|
|
17589
18201
|
ptr: ptr - 1
|
|
17590
18202
|
});
|
|
17591
|
-
} else if (
|
|
18203
|
+
} else if (c === "#")
|
|
17592
18204
|
ptr = skipComment(str, ptr);
|
|
17593
|
-
else if (
|
|
18205
|
+
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
17594
18206
|
let e2 = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
|
|
17595
18207
|
res.push(e2[0]);
|
|
17596
18208
|
ptr = e2[1];
|
|
17597
18209
|
}
|
|
17598
18210
|
}
|
|
17599
|
-
if (!
|
|
18211
|
+
if (!c) {
|
|
17600
18212
|
throw new TomlError("unfinished array encountered", {
|
|
17601
18213
|
toml: str,
|
|
17602
18214
|
ptr
|
|
@@ -17608,33 +18220,33 @@ function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
|
17608
18220
|
// ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/parse.js
|
|
17609
18221
|
function peekTable(key, table, meta3, type) {
|
|
17610
18222
|
let t = table;
|
|
17611
|
-
let
|
|
18223
|
+
let m2 = meta3;
|
|
17612
18224
|
let k2;
|
|
17613
18225
|
let hasOwn = false;
|
|
17614
18226
|
let state;
|
|
17615
18227
|
for (let i = 0; i < key.length; i++) {
|
|
17616
18228
|
if (i) {
|
|
17617
18229
|
t = hasOwn ? t[k2] : t[k2] = {};
|
|
17618
|
-
|
|
18230
|
+
m2 = (state = m2[k2]).c;
|
|
17619
18231
|
if (type === 0 && (state.t === 1 || state.t === 2)) {
|
|
17620
18232
|
return null;
|
|
17621
18233
|
}
|
|
17622
18234
|
if (state.t === 2) {
|
|
17623
18235
|
let l = t.length - 1;
|
|
17624
18236
|
t = t[l];
|
|
17625
|
-
|
|
18237
|
+
m2 = m2[l].c;
|
|
17626
18238
|
}
|
|
17627
18239
|
}
|
|
17628
18240
|
k2 = key[i];
|
|
17629
|
-
if ((hasOwn = Object.hasOwn(t, k2)) &&
|
|
18241
|
+
if ((hasOwn = Object.hasOwn(t, k2)) && m2[k2]?.t === 0 && m2[k2]?.d) {
|
|
17630
18242
|
return null;
|
|
17631
18243
|
}
|
|
17632
18244
|
if (!hasOwn) {
|
|
17633
18245
|
if (k2 === "__proto__") {
|
|
17634
18246
|
Object.defineProperty(t, k2, { enumerable: true, configurable: true, writable: true });
|
|
17635
|
-
Object.defineProperty(
|
|
18247
|
+
Object.defineProperty(m2, k2, { enumerable: true, configurable: true, writable: true });
|
|
17636
18248
|
}
|
|
17637
|
-
|
|
18249
|
+
m2[k2] = {
|
|
17638
18250
|
t: i < key.length - 1 && type === 2 ? 3 : type,
|
|
17639
18251
|
d: false,
|
|
17640
18252
|
i: 0,
|
|
@@ -17642,7 +18254,7 @@ function peekTable(key, table, meta3, type) {
|
|
|
17642
18254
|
};
|
|
17643
18255
|
}
|
|
17644
18256
|
}
|
|
17645
|
-
state =
|
|
18257
|
+
state = m2[k2];
|
|
17646
18258
|
if (state.t !== type && !(type === 1 && state.t === 3)) {
|
|
17647
18259
|
return null;
|
|
17648
18260
|
}
|
|
@@ -17669,7 +18281,7 @@ function parse3(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
17669
18281
|
let res = {};
|
|
17670
18282
|
let meta3 = {};
|
|
17671
18283
|
let tbl = res;
|
|
17672
|
-
let
|
|
18284
|
+
let m2 = meta3;
|
|
17673
18285
|
for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
|
|
17674
18286
|
if (toml[ptr] === "[") {
|
|
17675
18287
|
let isTableArray = toml[++ptr] === "[";
|
|
@@ -17696,7 +18308,7 @@ function parse3(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
17696
18308
|
ptr
|
|
17697
18309
|
});
|
|
17698
18310
|
}
|
|
17699
|
-
|
|
18311
|
+
m2 = p2[2];
|
|
17700
18312
|
tbl = p2[1];
|
|
17701
18313
|
ptr = k2[1];
|
|
17702
18314
|
} else {
|
|
@@ -17704,7 +18316,7 @@ function parse3(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
17704
18316
|
let p2 = peekTable(
|
|
17705
18317
|
k2[0],
|
|
17706
18318
|
tbl,
|
|
17707
|
-
|
|
18319
|
+
m2,
|
|
17708
18320
|
0
|
|
17709
18321
|
/* Type.DOTTED */
|
|
17710
18322
|
);
|
|
@@ -17872,7 +18484,7 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
17872
18484
|
}
|
|
17873
18485
|
|
|
17874
18486
|
// src/config-writers/codex.ts
|
|
17875
|
-
var
|
|
18487
|
+
var ENV_VAR_NAME2 = "CODEVECTOR_GATEWAY_KEY";
|
|
17876
18488
|
var PROVIDER_ID = "codevector";
|
|
17877
18489
|
var writeCodexConfig = ({
|
|
17878
18490
|
gatewayUrl,
|
|
@@ -17880,424 +18492,92 @@ var writeCodexConfig = ({
|
|
|
17880
18492
|
model,
|
|
17881
18493
|
availableModels = []
|
|
17882
18494
|
}) => {
|
|
17883
|
-
|
|
17884
|
-
|
|
17885
|
-
tool: "codex",
|
|
17886
|
-
status: "skipped",
|
|
17887
|
-
path: "",
|
|
17888
|
-
scope,
|
|
17889
|
-
notes: `codex only supports user-scope config. Re-run with \`--scope user\` or pick user in the prompt.`
|
|
17890
|
-
};
|
|
17891
|
-
}
|
|
17892
|
-
const path = codexConfigPath();
|
|
17893
|
-
const gateway = trimRightSlash3(gatewayUrl);
|
|
18495
|
+
const path = codexConfigPath(scope);
|
|
18496
|
+
const gateway = trimRightSlash4(gatewayUrl);
|
|
17894
18497
|
const existing = readTomlOrEmpty(path);
|
|
17895
18498
|
const merged = { ...existing };
|
|
17896
18499
|
merged.model_provider = PROVIDER_ID;
|
|
17897
|
-
const providers =
|
|
18500
|
+
const providers = isObject4(merged.model_providers) ? { ...merged.model_providers } : {};
|
|
17898
18501
|
providers[PROVIDER_ID] = {
|
|
17899
18502
|
name: "CodeVector Gateway",
|
|
17900
18503
|
base_url: `${gateway}/gateway/openai/v1`,
|
|
17901
|
-
env_key:
|
|
18504
|
+
env_key: ENV_VAR_NAME2,
|
|
17902
18505
|
wire_api: "responses"
|
|
17903
18506
|
};
|
|
17904
18507
|
merged.model_providers = providers;
|
|
17905
18508
|
if (model) {
|
|
17906
18509
|
merged.model = model.slug;
|
|
17907
|
-
const meta3 = availableModels.find((
|
|
18510
|
+
const meta3 = availableModels.find((m2) => m2.slug === model.slug);
|
|
17908
18511
|
if (meta3?.supportsReasoning === true) {
|
|
17909
18512
|
merged.model_reasoning_summary = "auto";
|
|
17910
18513
|
merged.model_supports_reasoning_summaries = true;
|
|
18514
|
+
} else {
|
|
18515
|
+
delete merged.model_reasoning_summary;
|
|
18516
|
+
delete merged.model_supports_reasoning_summaries;
|
|
17911
18517
|
}
|
|
17912
|
-
}
|
|
17913
|
-
writeTomlAtomic(path, merged);
|
|
17914
|
-
return {
|
|
17915
|
-
tool: "codex",
|
|
17916
|
-
status: "configured",
|
|
17917
|
-
path,
|
|
17918
|
-
scope,
|
|
17919
|
-
notes: `codex does not auto-load .env files. Add to your shell rc: export ${ENV_VAR_NAME}=<your key>`
|
|
17920
|
-
};
|
|
17921
|
-
};
|
|
17922
|
-
function codexConfigPath() {
|
|
17923
|
-
return join5(homedir3(), ".codex", "config.toml");
|
|
17924
|
-
}
|
|
17925
|
-
function readTomlOrEmpty(path) {
|
|
17926
|
-
if (!existsSync3(path)) return {};
|
|
17927
|
-
const raw = readFileSync3(path, "utf8");
|
|
17928
|
-
if (raw.trim().length === 0) return {};
|
|
17929
|
-
const parsed = parse3(raw);
|
|
17930
|
-
if (!isObject3(parsed)) {
|
|
17931
|
-
throw new Error(`${path} is not a TOML table. Refusing to overwrite.`);
|
|
17932
|
-
}
|
|
17933
|
-
return parsed;
|
|
17934
|
-
}
|
|
17935
|
-
function writeTomlAtomic(path, value) {
|
|
17936
|
-
const dir = dirname4(path);
|
|
17937
|
-
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
17938
|
-
let mode;
|
|
17939
|
-
if (existsSync3(path)) {
|
|
17940
|
-
mode = statSync3(path).mode & 511;
|
|
17941
|
-
}
|
|
17942
|
-
const tmp = `${path}.${process.pid}.tmp`;
|
|
17943
|
-
writeFileSync3(tmp, `${stringify(value)}
|
|
17944
|
-
`);
|
|
17945
|
-
if (mode !== void 0) {
|
|
17946
|
-
try {
|
|
17947
|
-
chmodSync4(tmp, mode);
|
|
17948
|
-
} catch {
|
|
17949
|
-
}
|
|
17950
|
-
}
|
|
17951
|
-
renameSync3(tmp, path);
|
|
17952
|
-
}
|
|
17953
|
-
function isObject3(v2) {
|
|
17954
|
-
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
17955
|
-
}
|
|
17956
|
-
function trimRightSlash3(url2) {
|
|
17957
|
-
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
17958
|
-
}
|
|
17959
|
-
|
|
17960
|
-
// src/config-writers/opencode.ts
|
|
17961
|
-
import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
17962
|
-
import { homedir as homedir4 } from "os";
|
|
17963
|
-
import { join as join7 } from "path";
|
|
17964
|
-
|
|
17965
|
-
// src/lib/gitignore.ts
|
|
17966
|
-
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
17967
|
-
import { join as join6 } from "path";
|
|
17968
|
-
function ensureGitignored(pattern, cwd = userCwd()) {
|
|
17969
|
-
const path = join6(cwd, ".gitignore");
|
|
17970
|
-
const trimmed = pattern.trim();
|
|
17971
|
-
if (!trimmed) return false;
|
|
17972
|
-
let existing = "";
|
|
17973
|
-
if (existsSync4(path)) {
|
|
17974
|
-
existing = readFileSync4(path, "utf8");
|
|
17975
|
-
if (hasMatchingEntry(existing, trimmed)) return false;
|
|
17976
|
-
}
|
|
17977
|
-
const needsLeadingNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
17978
|
-
const prefix = needsLeadingNewline ? "\n" : "";
|
|
17979
|
-
try {
|
|
17980
|
-
writeFileSync4(path, `${existing}${prefix}${trimmed}
|
|
17981
|
-
`);
|
|
17982
|
-
return true;
|
|
17983
|
-
} catch {
|
|
17984
|
-
return false;
|
|
17985
|
-
}
|
|
17986
|
-
}
|
|
17987
|
-
function hasMatchingEntry(contents, pattern) {
|
|
17988
|
-
const lines = contents.split("\n").map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean);
|
|
17989
|
-
if (lines.includes(pattern)) return true;
|
|
17990
|
-
if (pattern.includes("/")) {
|
|
17991
|
-
const topDir = `${pattern.split("/")[0]}/`;
|
|
17992
|
-
if (lines.includes(topDir)) return true;
|
|
17993
|
-
}
|
|
17994
|
-
return false;
|
|
17995
|
-
}
|
|
17996
|
-
|
|
17997
|
-
// src/config-writers/opencode.ts
|
|
17998
|
-
var ENV_VAR_NAME2 = "CODEVECTOR_GATEWAY_KEY";
|
|
17999
|
-
var PROVIDER_PREFIX = "codevector";
|
|
18000
|
-
var writeOpencodeConfig = ({
|
|
18001
|
-
gatewayUrl,
|
|
18002
|
-
apiKey,
|
|
18003
|
-
scope,
|
|
18004
|
-
model,
|
|
18005
|
-
availableModels = []
|
|
18006
|
-
}) => {
|
|
18007
|
-
const path = opencodeSettingsPath(scope);
|
|
18008
|
-
const gateway = trimRightSlash4(gatewayUrl);
|
|
18009
|
-
const keyLiteral = scope === "project" ? `{env:${ENV_VAR_NAME2}}` : apiKey;
|
|
18010
|
-
removeStaleGatewayProviders(path, gateway);
|
|
18011
|
-
const models = buildModelEntries(availableModels);
|
|
18012
|
-
const patch = {
|
|
18013
|
-
$schema: "https://opencode.ai/config.json",
|
|
18014
|
-
provider: {
|
|
18015
|
-
[PROVIDER_PREFIX]: {
|
|
18016
|
-
options: {
|
|
18017
|
-
apiKey: keyLiteral,
|
|
18018
|
-
baseURL: `${gateway}/gateway/openai/v1`
|
|
18019
|
-
},
|
|
18020
|
-
models
|
|
18021
|
-
}
|
|
18022
|
-
}
|
|
18023
|
-
};
|
|
18024
|
-
if (model) {
|
|
18025
|
-
patch.model = `${PROVIDER_PREFIX}/${model.slug}`;
|
|
18026
|
-
}
|
|
18027
|
-
mergeJsonFile(path, patch);
|
|
18028
|
-
forceReplaceCgwModels(path, models);
|
|
18029
|
-
const notes = [];
|
|
18030
|
-
if (scope === "local") {
|
|
18031
|
-
if (ensureGitignored("opencode.json")) {
|
|
18032
|
-
notes.push("Added `opencode.json` to .gitignore.");
|
|
18033
|
-
}
|
|
18034
|
-
}
|
|
18035
|
-
if (scope === "project") {
|
|
18036
|
-
notes.push(
|
|
18037
|
-
`Project scope avoids embedding secrets. Export ${ENV_VAR_NAME2}=<your key> before running opencode, or switch to local scope to embed the key.`
|
|
18038
|
-
);
|
|
18039
|
-
}
|
|
18040
|
-
return {
|
|
18041
|
-
tool: "opencode",
|
|
18042
|
-
status: "configured",
|
|
18043
|
-
path,
|
|
18044
|
-
scope,
|
|
18045
|
-
notes: notes.length > 0 ? notes.join(" ") : void 0
|
|
18046
|
-
};
|
|
18047
|
-
};
|
|
18048
|
-
function syncOpencodeModels(path, availableModels) {
|
|
18049
|
-
if (!existsSync5(path)) {
|
|
18050
|
-
throw new Error(
|
|
18051
|
-
`No opencode config found at ${path}. Run \`codevector configure opencode\` first.`
|
|
18052
|
-
);
|
|
18053
|
-
}
|
|
18054
|
-
const raw = readFileSync5(path, "utf8");
|
|
18055
|
-
let parsed;
|
|
18056
|
-
try {
|
|
18057
|
-
parsed = raw.trim().length === 0 ? {} : JSON.parse(raw);
|
|
18058
|
-
} catch (err) {
|
|
18059
|
-
throw new Error(`${path} is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
18060
|
-
}
|
|
18061
|
-
if (!isObject4(parsed)) {
|
|
18062
|
-
throw new Error(`${path} is not a JSON object; refusing to overwrite.`);
|
|
18063
|
-
}
|
|
18064
|
-
const provider = isObject4(parsed.provider) ? parsed.provider : void 0;
|
|
18065
|
-
const codevector = provider && isObject4(provider[PROVIDER_PREFIX]) ? provider[PROVIDER_PREFIX] : void 0;
|
|
18066
|
-
if (!provider || !codevector) {
|
|
18067
|
-
throw new Error(
|
|
18068
|
-
`${path} has no \`provider.${PROVIDER_PREFIX}\` entry. Run \`codevector configure opencode\` first.`
|
|
18069
|
-
);
|
|
18070
|
-
}
|
|
18071
|
-
const models = buildModelEntries(availableModels);
|
|
18072
|
-
codevector.models = models;
|
|
18073
|
-
writeFileSync5(path, `${JSON.stringify(parsed, null, 2)}
|
|
18074
|
-
`);
|
|
18075
|
-
return Object.keys(models).length;
|
|
18076
|
-
}
|
|
18077
|
-
function buildModelEntries(availableModels) {
|
|
18078
|
-
const out = {};
|
|
18079
|
-
for (const m of availableModels) {
|
|
18080
|
-
const entry = {};
|
|
18081
|
-
if (m.displayName) entry.name = m.displayName;
|
|
18082
|
-
if (m.family) entry.family = m.family;
|
|
18083
|
-
if (m.releaseDate) entry.release_date = m.releaseDate;
|
|
18084
|
-
const inP = parsePrice(m.inputPricePerMtok);
|
|
18085
|
-
const outP = parsePrice(m.outputPricePerMtok);
|
|
18086
|
-
if (inP !== void 0 && outP !== void 0) {
|
|
18087
|
-
const cost = { input: inP, output: outP };
|
|
18088
|
-
const cacheReadP = parsePrice(m.cachedInputPricePerMtok);
|
|
18089
|
-
const cacheWriteP = parsePrice(m.cacheWritePricePerMtok);
|
|
18090
|
-
if (cacheReadP !== void 0) cost.cache_read = cacheReadP;
|
|
18091
|
-
if (cacheWriteP !== void 0) cost.cache_write = cacheWriteP;
|
|
18092
|
-
entry.cost = cost;
|
|
18093
|
-
}
|
|
18094
|
-
const ctx = m.contextWindow;
|
|
18095
|
-
const outTok = m.maxOutputTokens;
|
|
18096
|
-
if (typeof ctx === "number" && ctx > 0 && typeof outTok === "number" && outTok > 0) {
|
|
18097
|
-
const limit = { context: ctx, output: outTok };
|
|
18098
|
-
if (typeof m.maxInputTokens === "number" && m.maxInputTokens > 0) {
|
|
18099
|
-
limit.input = m.maxInputTokens;
|
|
18100
|
-
}
|
|
18101
|
-
entry.limit = limit;
|
|
18102
|
-
}
|
|
18103
|
-
if (m.supportsReasoning === true) entry.reasoning = true;
|
|
18104
|
-
if (m.supportsAttachment === true) entry.attachment = true;
|
|
18105
|
-
if (m.supportsToolCall === true) entry.tool_call = true;
|
|
18106
|
-
if (m.supportsTemperature === true) entry.temperature = true;
|
|
18107
|
-
const inMods = m.inputModalities;
|
|
18108
|
-
const outMods = m.outputModalities;
|
|
18109
|
-
if (inMods && inMods.length > 0 && outMods && outMods.length > 0) {
|
|
18110
|
-
entry.modalities = { input: [...inMods], output: [...outMods] };
|
|
18111
|
-
}
|
|
18112
|
-
out[m.slug] = entry;
|
|
18113
|
-
}
|
|
18114
|
-
return out;
|
|
18115
|
-
}
|
|
18116
|
-
function parsePrice(raw) {
|
|
18117
|
-
if (raw == null) return void 0;
|
|
18118
|
-
const n = Number(raw);
|
|
18119
|
-
return Number.isFinite(n) ? n : void 0;
|
|
18120
|
-
}
|
|
18121
|
-
function forceReplaceCgwModels(path, models) {
|
|
18122
|
-
if (!existsSync5(path)) return;
|
|
18123
|
-
let parsed;
|
|
18124
|
-
try {
|
|
18125
|
-
parsed = JSON.parse(readFileSync5(path, "utf8"));
|
|
18126
|
-
} catch {
|
|
18127
|
-
return;
|
|
18128
|
-
}
|
|
18129
|
-
if (!isObject4(parsed)) return;
|
|
18130
|
-
const provider = parsed.provider;
|
|
18131
|
-
if (!isObject4(provider)) return;
|
|
18132
|
-
const codevector = provider[PROVIDER_PREFIX];
|
|
18133
|
-
if (!isObject4(codevector)) return;
|
|
18134
|
-
codevector.models = models;
|
|
18135
|
-
writeFileSync5(path, `${JSON.stringify(parsed, null, 2)}
|
|
18136
|
-
`);
|
|
18137
|
-
}
|
|
18138
|
-
function opencodeSettingsPath(scope) {
|
|
18139
|
-
switch (scope) {
|
|
18140
|
-
case "user":
|
|
18141
|
-
return join7(homedir4(), ".config", "opencode", "opencode.json");
|
|
18142
|
-
case "project":
|
|
18143
|
-
case "local":
|
|
18144
|
-
return join7(userCwd(), "opencode.json");
|
|
18145
|
-
}
|
|
18146
|
-
}
|
|
18147
|
-
function removeStaleGatewayProviders(path, gateway) {
|
|
18148
|
-
if (!existsSync5(path)) return;
|
|
18149
|
-
let parsed;
|
|
18150
|
-
try {
|
|
18151
|
-
const raw = readFileSync5(path, "utf8");
|
|
18152
|
-
if (raw.trim().length === 0) return;
|
|
18153
|
-
parsed = JSON.parse(raw);
|
|
18154
|
-
} catch {
|
|
18155
|
-
return;
|
|
18156
|
-
}
|
|
18157
|
-
if (!isObject4(parsed)) return;
|
|
18158
|
-
const provider = parsed.provider;
|
|
18159
|
-
if (!isObject4(provider)) return;
|
|
18160
|
-
const ourBaseUrls = /* @__PURE__ */ new Set([`${gateway}/gateway/anthropic`, `${gateway}/gateway/openai/v1`]);
|
|
18161
|
-
let mutated = false;
|
|
18162
|
-
for (const key of ["openai", "anthropic"]) {
|
|
18163
|
-
const entry = provider[key];
|
|
18164
|
-
if (!isObject4(entry)) continue;
|
|
18165
|
-
const options = entry.options;
|
|
18166
|
-
if (!isObject4(options)) continue;
|
|
18167
|
-
const baseURL = options.baseURL;
|
|
18168
|
-
if (typeof baseURL === "string" && ourBaseUrls.has(baseURL)) {
|
|
18169
|
-
delete provider[key];
|
|
18170
|
-
mutated = true;
|
|
18171
|
-
}
|
|
18172
|
-
}
|
|
18173
|
-
if (mutated) {
|
|
18174
|
-
writeFileSync5(path, `${JSON.stringify(parsed, null, 2)}
|
|
18175
|
-
`);
|
|
18176
|
-
}
|
|
18177
|
-
}
|
|
18178
|
-
function isObject4(v2) {
|
|
18179
|
-
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
18180
|
-
}
|
|
18181
|
-
function trimRightSlash4(url2) {
|
|
18182
|
-
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
18183
|
-
}
|
|
18184
|
-
|
|
18185
|
-
// src/config-writers/qwen-code.ts
|
|
18186
|
-
import { homedir as homedir5 } from "os";
|
|
18187
|
-
import { join as join8 } from "path";
|
|
18188
|
-
|
|
18189
|
-
// src/lib/env-file.ts
|
|
18190
|
-
import { chmodSync as chmodSync5, existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
18191
|
-
import { dirname as dirname5 } from "path";
|
|
18192
|
-
function mergeEnvFile(path, entries) {
|
|
18193
|
-
mkdirSync5(dirname5(path), { recursive: true, mode: 448 });
|
|
18194
|
-
const existing = existsSync6(path) ? readFileSync6(path, "utf8") : "";
|
|
18195
|
-
const lines = existing.split("\n");
|
|
18196
|
-
const seen = /* @__PURE__ */ new Set();
|
|
18197
|
-
const updated = lines.map((line) => {
|
|
18198
|
-
const match = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=/);
|
|
18199
|
-
if (!match) return line;
|
|
18200
|
-
const key = match[1];
|
|
18201
|
-
if (key === void 0 || !(key in entries)) return line;
|
|
18202
|
-
seen.add(key);
|
|
18203
|
-
return `${key}=${quote(entries[key] ?? "")}`;
|
|
18204
|
-
});
|
|
18205
|
-
for (const [key, value] of Object.entries(entries)) {
|
|
18206
|
-
if (!seen.has(key)) updated.push(`${key}=${quote(value)}`);
|
|
18207
|
-
}
|
|
18208
|
-
while (updated.length > 0 && updated[updated.length - 1] === "") updated.pop();
|
|
18209
|
-
writeFileSync6(path, `${updated.join("\n")}
|
|
18210
|
-
`);
|
|
18211
|
-
try {
|
|
18212
|
-
chmodSync5(path, 384);
|
|
18213
|
-
} catch {
|
|
18214
|
-
}
|
|
18215
|
-
}
|
|
18216
|
-
function quote(v2) {
|
|
18217
|
-
const escaped = v2.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
|
|
18218
|
-
return `"${escaped}"`;
|
|
18219
|
-
}
|
|
18220
|
-
|
|
18221
|
-
// src/config-writers/qwen-code.ts
|
|
18222
|
-
var ENV_VAR_NAME3 = "CODEVECTOR_GATEWAY_KEY";
|
|
18223
|
-
var writeQwenCodeConfig = ({
|
|
18224
|
-
gatewayUrl,
|
|
18225
|
-
apiKey,
|
|
18226
|
-
hookScriptPath,
|
|
18227
|
-
scope,
|
|
18228
|
-
model
|
|
18229
|
-
}) => {
|
|
18230
|
-
const path = qwenSettingsPath(scope);
|
|
18231
|
-
const gateway = trimRightSlash5(gatewayUrl);
|
|
18232
|
-
const patch = {
|
|
18233
|
-
modelProviders: {
|
|
18234
|
-
anthropic: [
|
|
18235
|
-
{
|
|
18236
|
-
id: "codevector-anthropic",
|
|
18237
|
-
name: "CodeVector Gateway (Anthropic)",
|
|
18238
|
-
envKey: ENV_VAR_NAME3,
|
|
18239
|
-
baseUrl: `${gateway}/gateway/anthropic`
|
|
18240
|
-
}
|
|
18241
|
-
],
|
|
18242
|
-
openai: [
|
|
18243
|
-
{
|
|
18244
|
-
id: "codevector-openai",
|
|
18245
|
-
name: "CodeVector Gateway (OpenAI-compat)",
|
|
18246
|
-
envKey: ENV_VAR_NAME3,
|
|
18247
|
-
baseUrl: `${gateway}/gateway/openai/v1`
|
|
18248
|
-
}
|
|
18249
|
-
]
|
|
18250
|
-
},
|
|
18251
|
-
hooks: {
|
|
18252
|
-
Stop: [{ matcher: "*", hooks: [{ type: "command", command: hookScriptPath, async: true }] }],
|
|
18253
|
-
SessionEnd: [
|
|
18254
|
-
{ matcher: "*", hooks: [{ type: "command", command: hookScriptPath, async: true }] }
|
|
18255
|
-
]
|
|
18256
|
-
}
|
|
18257
|
-
};
|
|
18258
|
-
if (model) patch.model = { name: model.slug };
|
|
18259
|
-
mergeJsonFile(path, patch, {
|
|
18260
|
-
hookArrayPaths: ["hooks.Stop", "hooks.SessionEnd"]
|
|
18261
|
-
});
|
|
18262
|
-
const notes = [];
|
|
18263
|
-
if (scope === "project") {
|
|
18264
|
-
notes.push(
|
|
18265
|
-
`Project scope avoids writing the API key. Export ${ENV_VAR_NAME3}=<your key> in your shell, or switch to local scope to drop it into .qwen/.env.`
|
|
18266
|
-
);
|
|
18267
18518
|
} else {
|
|
18268
|
-
|
|
18269
|
-
|
|
18270
|
-
|
|
18519
|
+
delete merged.model;
|
|
18520
|
+
delete merged.model_reasoning_summary;
|
|
18521
|
+
delete merged.model_supports_reasoning_summaries;
|
|
18271
18522
|
}
|
|
18523
|
+
writeTomlAtomic(path, merged);
|
|
18524
|
+
const notes = [
|
|
18525
|
+
`codex does not auto-load .env files. Add to your shell rc: export ${ENV_VAR_NAME2}=<your key>`
|
|
18526
|
+
];
|
|
18272
18527
|
if (scope === "local") {
|
|
18273
|
-
if (ensureGitignored(".
|
|
18274
|
-
notes.push("Added `.
|
|
18528
|
+
if (ensureGitignored(".codex/config.toml")) {
|
|
18529
|
+
notes.push("Added `.codex/config.toml` to .gitignore.");
|
|
18275
18530
|
}
|
|
18276
18531
|
}
|
|
18277
18532
|
return {
|
|
18278
|
-
tool: "
|
|
18533
|
+
tool: "codex",
|
|
18279
18534
|
status: "configured",
|
|
18280
18535
|
path,
|
|
18281
18536
|
scope,
|
|
18282
|
-
notes: notes.
|
|
18537
|
+
notes: notes.join(" ")
|
|
18283
18538
|
};
|
|
18284
18539
|
};
|
|
18285
|
-
function
|
|
18286
|
-
return join8(qwenRootForScope(scope), "settings.json");
|
|
18287
|
-
}
|
|
18288
|
-
function qwenEnvPath(scope) {
|
|
18289
|
-
return join8(qwenRootForScope(scope), ".env");
|
|
18290
|
-
}
|
|
18291
|
-
function qwenRootForScope(scope) {
|
|
18540
|
+
function codexConfigPath(scope = "user") {
|
|
18292
18541
|
switch (scope) {
|
|
18293
18542
|
case "user":
|
|
18294
|
-
return
|
|
18543
|
+
return join7(homedir4(), ".codex", "config.toml");
|
|
18295
18544
|
case "project":
|
|
18296
18545
|
case "local":
|
|
18297
|
-
return
|
|
18546
|
+
return join7(userCwd(), ".codex", "config.toml");
|
|
18547
|
+
}
|
|
18548
|
+
}
|
|
18549
|
+
function readTomlOrEmpty(path) {
|
|
18550
|
+
if (!existsSync6(path)) return {};
|
|
18551
|
+
const raw = readFileSync7(path, "utf8");
|
|
18552
|
+
if (raw.trim().length === 0) return {};
|
|
18553
|
+
const parsed = parse3(raw);
|
|
18554
|
+
if (!isObject4(parsed)) {
|
|
18555
|
+
throw new Error(`${path} is not a TOML table. Refusing to overwrite.`);
|
|
18556
|
+
}
|
|
18557
|
+
return parsed;
|
|
18558
|
+
}
|
|
18559
|
+
function writeTomlAtomic(path, value) {
|
|
18560
|
+
const dir = dirname5(path);
|
|
18561
|
+
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
18562
|
+
let mode;
|
|
18563
|
+
if (existsSync6(path)) {
|
|
18564
|
+
mode = statSync4(path).mode & 511;
|
|
18565
|
+
}
|
|
18566
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
18567
|
+
writeFileSync5(tmp, `${stringify(value)}
|
|
18568
|
+
`);
|
|
18569
|
+
if (mode !== void 0) {
|
|
18570
|
+
try {
|
|
18571
|
+
chmodSync4(tmp, mode);
|
|
18572
|
+
} catch {
|
|
18573
|
+
}
|
|
18298
18574
|
}
|
|
18575
|
+
renameSync3(tmp, path);
|
|
18576
|
+
}
|
|
18577
|
+
function isObject4(v2) {
|
|
18578
|
+
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
18299
18579
|
}
|
|
18300
|
-
function
|
|
18580
|
+
function trimRightSlash4(url2) {
|
|
18301
18581
|
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
18302
18582
|
}
|
|
18303
18583
|
|
|
@@ -18305,11 +18585,10 @@ function trimRightSlash5(url2) {
|
|
|
18305
18585
|
var WRITERS = {
|
|
18306
18586
|
"claude-code": writeClaudeCodeConfig,
|
|
18307
18587
|
opencode: writeOpencodeConfig,
|
|
18308
|
-
"qwen-code": writeQwenCodeConfig,
|
|
18309
18588
|
codex: writeCodexConfig
|
|
18310
18589
|
};
|
|
18311
|
-
var ALL_TOOLS = ["claude-code", "opencode", "
|
|
18312
|
-
var SCOPES = ["local", "project"
|
|
18590
|
+
var ALL_TOOLS = ["claude-code", "opencode", "codex"];
|
|
18591
|
+
var SCOPES = ["local", "project"];
|
|
18313
18592
|
var configureCommand = defineCommand({
|
|
18314
18593
|
meta: {
|
|
18315
18594
|
name: "configure",
|
|
@@ -18319,12 +18598,12 @@ var configureCommand = defineCommand({
|
|
|
18319
18598
|
tool: {
|
|
18320
18599
|
type: "positional",
|
|
18321
18600
|
required: false,
|
|
18322
|
-
description: "Tool to configure. Prompted if omitted. One of: claude-code, opencode,
|
|
18601
|
+
description: "Tool to configure. Prompted if omitted. One of: claude-code, opencode, codex, all."
|
|
18323
18602
|
},
|
|
18324
18603
|
scope: {
|
|
18325
18604
|
type: "string",
|
|
18326
|
-
description: "Settings scope: local (default, per-repo, gitignored)
|
|
18327
|
-
valueHint: "local|project
|
|
18605
|
+
description: "Settings scope: local (default, per-repo, gitignored) or project (committed). For user-scope (global) setup, use `codevector system configure`.",
|
|
18606
|
+
valueHint: "local|project"
|
|
18328
18607
|
},
|
|
18329
18608
|
all: {
|
|
18330
18609
|
type: "boolean",
|
|
@@ -18332,10 +18611,17 @@ var configureCommand = defineCommand({
|
|
|
18332
18611
|
}
|
|
18333
18612
|
},
|
|
18334
18613
|
async run({ args }) {
|
|
18335
|
-
const
|
|
18336
|
-
if (!
|
|
18614
|
+
const initialProfiles = await readProfiles();
|
|
18615
|
+
if (!initialProfiles) {
|
|
18337
18616
|
throw new Error("Not signed in. Run `codevector auth login` first.");
|
|
18338
18617
|
}
|
|
18618
|
+
const activeProfileName = initialProfiles.activeProfile;
|
|
18619
|
+
const creds = initialProfiles.profiles[activeProfileName];
|
|
18620
|
+
if (!creds) {
|
|
18621
|
+
throw new Error(
|
|
18622
|
+
`Active profile "${activeProfileName}" is missing from credentials. Run \`codevector auth login\` to recover.`
|
|
18623
|
+
);
|
|
18624
|
+
}
|
|
18339
18625
|
ge("codevector configure");
|
|
18340
18626
|
const tools = await resolveTools(args);
|
|
18341
18627
|
const scope = await resolveScope(args.scope, tools);
|
|
@@ -18370,25 +18656,25 @@ var configureCommand = defineCommand({
|
|
|
18370
18656
|
scope,
|
|
18371
18657
|
...project ? { project } : {},
|
|
18372
18658
|
...model ? { model } : {},
|
|
18373
|
-
availableModels: reachable.map((
|
|
18374
|
-
slug:
|
|
18375
|
-
displayName:
|
|
18376
|
-
contextWindow:
|
|
18377
|
-
maxOutputTokens:
|
|
18378
|
-
maxInputTokens:
|
|
18379
|
-
inputPricePerMtok:
|
|
18380
|
-
cachedInputPricePerMtok:
|
|
18381
|
-
cacheWritePricePerMtok:
|
|
18382
|
-
reasoningPricePerMtok:
|
|
18383
|
-
outputPricePerMtok:
|
|
18384
|
-
supportsReasoning:
|
|
18385
|
-
supportsAttachment:
|
|
18386
|
-
supportsToolCall:
|
|
18387
|
-
supportsTemperature:
|
|
18388
|
-
inputModalities:
|
|
18389
|
-
outputModalities:
|
|
18390
|
-
releaseDate:
|
|
18391
|
-
family:
|
|
18659
|
+
availableModels: reachable.map((m2) => ({
|
|
18660
|
+
slug: m2.slug,
|
|
18661
|
+
displayName: m2.displayName,
|
|
18662
|
+
contextWindow: m2.contextWindow,
|
|
18663
|
+
maxOutputTokens: m2.maxOutputTokens,
|
|
18664
|
+
maxInputTokens: m2.maxInputTokens,
|
|
18665
|
+
inputPricePerMtok: m2.inputPricePerMtok,
|
|
18666
|
+
cachedInputPricePerMtok: m2.cachedInputPricePerMtok,
|
|
18667
|
+
cacheWritePricePerMtok: m2.cacheWritePricePerMtok,
|
|
18668
|
+
reasoningPricePerMtok: m2.reasoningPricePerMtok,
|
|
18669
|
+
outputPricePerMtok: m2.outputPricePerMtok,
|
|
18670
|
+
supportsReasoning: m2.supportsReasoning,
|
|
18671
|
+
supportsAttachment: m2.supportsAttachment,
|
|
18672
|
+
supportsToolCall: m2.supportsToolCall,
|
|
18673
|
+
supportsTemperature: m2.supportsTemperature,
|
|
18674
|
+
inputModalities: m2.inputModalities,
|
|
18675
|
+
outputModalities: m2.outputModalities,
|
|
18676
|
+
releaseDate: m2.releaseDate,
|
|
18677
|
+
family: m2.family
|
|
18392
18678
|
}))
|
|
18393
18679
|
})
|
|
18394
18680
|
);
|
|
@@ -18402,6 +18688,19 @@ var configureCommand = defineCommand({
|
|
|
18402
18688
|
});
|
|
18403
18689
|
}
|
|
18404
18690
|
}
|
|
18691
|
+
const persisted = [];
|
|
18692
|
+
for (const r of results) {
|
|
18693
|
+
if (r.status === "configured") {
|
|
18694
|
+
persisted.push({
|
|
18695
|
+
tool: r.tool,
|
|
18696
|
+
scope: r.scope,
|
|
18697
|
+
...model ? { modelSlug: model.slug } : {}
|
|
18698
|
+
});
|
|
18699
|
+
}
|
|
18700
|
+
}
|
|
18701
|
+
if (persisted.length > 0) {
|
|
18702
|
+
updateProfileToolConfigs(activeProfileName, persisted);
|
|
18703
|
+
}
|
|
18405
18704
|
for (const r of results) {
|
|
18406
18705
|
if (r.status === "configured") {
|
|
18407
18706
|
R2.success(`${r.tool} \u2192 ${r.path} [${r.scope}]`);
|
|
@@ -18428,9 +18727,13 @@ async function resolveTools(args) {
|
|
|
18428
18727
|
`Unsupported tool "${args.tool}". Known: ${ALL_TOOLS.join(", ")}, or pass --all.`
|
|
18429
18728
|
);
|
|
18430
18729
|
}
|
|
18730
|
+
Se(
|
|
18731
|
+
"Use arrow keys to move, space to toggle, a to toggle all, enter to confirm.",
|
|
18732
|
+
"Controls"
|
|
18733
|
+
);
|
|
18431
18734
|
const picked = unwrap(
|
|
18432
18735
|
await ve({
|
|
18433
|
-
message: "Which tools do you want to configure?",
|
|
18736
|
+
message: "Which tools do you want to configure? (space to select/deselect, enter to confirm)",
|
|
18434
18737
|
options: ALL_TOOLS.map((t) => ({ value: t, label: t })),
|
|
18435
18738
|
initialValues: ["claude-code"],
|
|
18436
18739
|
required: true
|
|
@@ -18439,6 +18742,11 @@ async function resolveTools(args) {
|
|
|
18439
18742
|
return picked;
|
|
18440
18743
|
}
|
|
18441
18744
|
async function resolveScope(raw, tools) {
|
|
18745
|
+
if (raw === "user") {
|
|
18746
|
+
throw new Error(
|
|
18747
|
+
"`--scope user` is no longer supported by `configure`. Run `codevector system configure` to set the global (user-scope) config for all editors at once, with backups."
|
|
18748
|
+
);
|
|
18749
|
+
}
|
|
18442
18750
|
if (raw) {
|
|
18443
18751
|
if (!isScope(raw)) {
|
|
18444
18752
|
throw new Error(`Invalid --scope "${raw}". Use one of: ${SCOPES.join(", ")}.`);
|
|
@@ -18446,8 +18754,8 @@ async function resolveScope(raw, tools) {
|
|
|
18446
18754
|
return raw;
|
|
18447
18755
|
}
|
|
18448
18756
|
return unwrap(
|
|
18449
|
-
await
|
|
18450
|
-
message: "Where should these settings be written?",
|
|
18757
|
+
await xe({
|
|
18758
|
+
message: "Where should these settings be written? (arrow keys to move, enter to select)",
|
|
18451
18759
|
options: [
|
|
18452
18760
|
{
|
|
18453
18761
|
value: "local",
|
|
@@ -18458,11 +18766,6 @@ async function resolveScope(raw, tools) {
|
|
|
18458
18766
|
value: "project",
|
|
18459
18767
|
label: "project",
|
|
18460
18768
|
hint: `${pathHint(tools, "project")} \u2014 committed, shared with team`
|
|
18461
|
-
},
|
|
18462
|
-
{
|
|
18463
|
-
value: "user",
|
|
18464
|
-
label: "user",
|
|
18465
|
-
hint: `${pathHint(tools, "user")} \u2014 global default for all projects`
|
|
18466
18769
|
}
|
|
18467
18770
|
],
|
|
18468
18771
|
initialValue: "local"
|
|
@@ -18477,14 +18780,12 @@ function pathHint(tools, scope) {
|
|
|
18477
18780
|
return relativizeHomeAndCwd(claudeSettingsPath(scope));
|
|
18478
18781
|
case "opencode":
|
|
18479
18782
|
return relativizeHomeAndCwd(opencodeSettingsPath(scope));
|
|
18480
|
-
case "qwen-code":
|
|
18481
|
-
return relativizeHomeAndCwd(qwenSettingsPath(scope));
|
|
18482
18783
|
case "codex":
|
|
18483
|
-
return
|
|
18784
|
+
return relativizeHomeAndCwd(codexConfigPath(scope));
|
|
18484
18785
|
}
|
|
18485
18786
|
}
|
|
18486
18787
|
function relativizeHomeAndCwd(absolutePath) {
|
|
18487
|
-
const home =
|
|
18788
|
+
const home = homedir5();
|
|
18488
18789
|
const cwd = userCwd();
|
|
18489
18790
|
if (home && absolutePath.startsWith(`${home}/`)) {
|
|
18490
18791
|
return `~${absolutePath.slice(home.length)}`;
|
|
@@ -18506,26 +18807,26 @@ async function fetchReachableChatModels(creds) {
|
|
|
18506
18807
|
s.start("Loading reachable models\u2026");
|
|
18507
18808
|
try {
|
|
18508
18809
|
const res = await call(parseResponse(client.models.$get()));
|
|
18509
|
-
const models = res.data.filter((
|
|
18510
|
-
slug:
|
|
18511
|
-
providerKind:
|
|
18512
|
-
displayName:
|
|
18513
|
-
contextWindow:
|
|
18514
|
-
maxOutputTokens:
|
|
18515
|
-
maxInputTokens:
|
|
18516
|
-
inputPricePerMtok:
|
|
18517
|
-
cachedInputPricePerMtok:
|
|
18518
|
-
cacheWritePricePerMtok:
|
|
18519
|
-
reasoningPricePerMtok:
|
|
18520
|
-
outputPricePerMtok:
|
|
18521
|
-
supportsReasoning:
|
|
18522
|
-
supportsAttachment:
|
|
18523
|
-
supportsToolCall:
|
|
18524
|
-
supportsTemperature:
|
|
18525
|
-
inputModalities:
|
|
18526
|
-
outputModalities:
|
|
18527
|
-
releaseDate:
|
|
18528
|
-
family:
|
|
18810
|
+
const models = res.data.filter((m2) => m2.kind === "chat").map((m2) => ({
|
|
18811
|
+
slug: m2.slug,
|
|
18812
|
+
providerKind: m2.providerKind,
|
|
18813
|
+
displayName: m2.displayName,
|
|
18814
|
+
contextWindow: m2.contextWindow,
|
|
18815
|
+
maxOutputTokens: m2.maxOutputTokens,
|
|
18816
|
+
maxInputTokens: m2.maxInputTokens,
|
|
18817
|
+
inputPricePerMtok: m2.inputPricePerMtok,
|
|
18818
|
+
cachedInputPricePerMtok: m2.cachedInputPricePerMtok,
|
|
18819
|
+
cacheWritePricePerMtok: m2.cacheWritePricePerMtok,
|
|
18820
|
+
reasoningPricePerMtok: m2.reasoningPricePerMtok,
|
|
18821
|
+
outputPricePerMtok: m2.outputPricePerMtok,
|
|
18822
|
+
supportsReasoning: m2.supportsReasoning,
|
|
18823
|
+
supportsAttachment: m2.supportsAttachment,
|
|
18824
|
+
supportsToolCall: m2.supportsToolCall,
|
|
18825
|
+
supportsTemperature: m2.supportsTemperature,
|
|
18826
|
+
inputModalities: m2.inputModalities,
|
|
18827
|
+
outputModalities: m2.outputModalities,
|
|
18828
|
+
releaseDate: m2.releaseDate,
|
|
18829
|
+
family: m2.family
|
|
18529
18830
|
}));
|
|
18530
18831
|
s.stop(`${models.length} model${models.length === 1 ? "" : "s"} reachable`);
|
|
18531
18832
|
return models;
|
|
@@ -18544,31 +18845,31 @@ async function pickPinnedModel(models) {
|
|
|
18544
18845
|
}
|
|
18545
18846
|
const SKIP = "__skip__";
|
|
18546
18847
|
const picked = unwrap(
|
|
18547
|
-
await
|
|
18548
|
-
message: "Pin a default model for these tools?",
|
|
18848
|
+
await xe({
|
|
18849
|
+
message: "Pin a default model for these tools? (arrow keys to move, enter to select)",
|
|
18549
18850
|
options: [
|
|
18550
18851
|
{
|
|
18551
18852
|
value: SKIP,
|
|
18552
18853
|
label: "Skip (recommended)",
|
|
18553
18854
|
hint: "let each tool pick per request \u2014 keeps model-switching UIs working"
|
|
18554
18855
|
},
|
|
18555
|
-
...models.map((
|
|
18556
|
-
value:
|
|
18557
|
-
label:
|
|
18558
|
-
hint: `${
|
|
18856
|
+
...models.map((m2) => ({
|
|
18857
|
+
value: m2.slug,
|
|
18858
|
+
label: m2.slug,
|
|
18859
|
+
hint: `${m2.displayName}${m2.providerKind ? ` \xB7 ${m2.providerKind}` : ""}`
|
|
18559
18860
|
}))
|
|
18560
18861
|
],
|
|
18561
18862
|
initialValue: SKIP
|
|
18562
18863
|
})
|
|
18563
18864
|
);
|
|
18564
18865
|
if (picked === SKIP) return void 0;
|
|
18565
|
-
const chosen = models.find((
|
|
18866
|
+
const chosen = models.find((m2) => m2.slug === picked);
|
|
18566
18867
|
if (!chosen) return void 0;
|
|
18567
18868
|
return { slug: chosen.slug, providerKind: chosen.providerKind };
|
|
18568
18869
|
}
|
|
18569
18870
|
|
|
18570
18871
|
// src/commands/doctor.ts
|
|
18571
|
-
import { existsSync as existsSync7, readFileSync as
|
|
18872
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
|
|
18572
18873
|
var CLAUDE_SCOPE_ORDER = ["local", "project", "user"];
|
|
18573
18874
|
var doctorCommand = defineCommand({
|
|
18574
18875
|
meta: {
|
|
@@ -18624,7 +18925,7 @@ var doctorCommand = defineCommand({
|
|
|
18624
18925
|
detail: `${ACCEPTANCE_HOOK_FILE} missing \u2014 run \`codevector configure claude-code\``
|
|
18625
18926
|
});
|
|
18626
18927
|
} else {
|
|
18627
|
-
const mode =
|
|
18928
|
+
const mode = statSync5(ACCEPTANCE_HOOK_FILE).mode & 511;
|
|
18628
18929
|
checks.push(
|
|
18629
18930
|
mode & 64 ? { level: "ok", label: "acceptance hook", detail: "installed + executable" } : {
|
|
18630
18931
|
level: "warn",
|
|
@@ -18634,7 +18935,7 @@ var doctorCommand = defineCommand({
|
|
|
18634
18935
|
);
|
|
18635
18936
|
}
|
|
18636
18937
|
emit(checks);
|
|
18637
|
-
if (checks.some((
|
|
18938
|
+
if (checks.some((c) => c.level === "fail")) {
|
|
18638
18939
|
process.exitCode = 1;
|
|
18639
18940
|
}
|
|
18640
18941
|
}
|
|
@@ -18644,7 +18945,7 @@ function inspectClaudeSettings() {
|
|
|
18644
18945
|
const path = claudeSettingsPath(scope);
|
|
18645
18946
|
if (!existsSync7(path)) continue;
|
|
18646
18947
|
try {
|
|
18647
|
-
const raw = JSON.parse(
|
|
18948
|
+
const raw = JSON.parse(readFileSync8(path, "utf8"));
|
|
18648
18949
|
if (typeof raw.env?.ANTHROPIC_BASE_URL === "string") {
|
|
18649
18950
|
return {
|
|
18650
18951
|
level: "ok",
|
|
@@ -18668,23 +18969,23 @@ function inspectClaudeSettings() {
|
|
|
18668
18969
|
}
|
|
18669
18970
|
function emit(checks) {
|
|
18670
18971
|
Se(
|
|
18671
|
-
checks.map((
|
|
18672
|
-
const icon =
|
|
18673
|
-
const detail =
|
|
18674
|
-
return `${icon} ${
|
|
18972
|
+
checks.map((c) => {
|
|
18973
|
+
const icon = c.level === "ok" ? "\u2713" : c.level === "warn" ? "!" : "\u2717";
|
|
18974
|
+
const detail = c.detail ? ` \u2014 ${c.detail}` : "";
|
|
18975
|
+
return `${icon} ${c.label}${detail}`;
|
|
18675
18976
|
}).join("\n"),
|
|
18676
18977
|
"Doctor"
|
|
18677
18978
|
);
|
|
18678
|
-
for (const
|
|
18679
|
-
if (
|
|
18680
|
-
else if (
|
|
18979
|
+
for (const c of checks) {
|
|
18980
|
+
if (c.level === "fail") R2.error(c.label);
|
|
18981
|
+
else if (c.level === "warn") R2.warn(c.label);
|
|
18681
18982
|
}
|
|
18682
18983
|
}
|
|
18683
18984
|
|
|
18684
18985
|
// src/commands/init.ts
|
|
18685
|
-
import { existsSync as existsSync8, writeFileSync as
|
|
18986
|
+
import { existsSync as existsSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
18686
18987
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
18687
|
-
import { join as
|
|
18988
|
+
import { join as join8 } from "path";
|
|
18688
18989
|
var DEFAULT_TICKET_PATTERN2 = "[A-Z]+-\\d+";
|
|
18689
18990
|
var initCommand = defineCommand({
|
|
18690
18991
|
meta: {
|
|
@@ -18705,269 +19006,1003 @@ var initCommand = defineCommand({
|
|
|
18705
19006
|
description: "Overwrite an existing .codevector.json."
|
|
18706
19007
|
}
|
|
18707
19008
|
},
|
|
18708
|
-
run({ args }) {
|
|
18709
|
-
const cwd = userCwd();
|
|
18710
|
-
const target =
|
|
18711
|
-
if (existsSync8(target) && !args.force) {
|
|
18712
|
-
throw new Error(`.codevector.json already exists in ${cwd}. Pass --force to overwrite.`);
|
|
19009
|
+
run({ args }) {
|
|
19010
|
+
const cwd = userCwd();
|
|
19011
|
+
const target = join8(cwd, ".codevector.json");
|
|
19012
|
+
if (existsSync8(target) && !args.force) {
|
|
19013
|
+
throw new Error(`.codevector.json already exists in ${cwd}. Pass --force to overwrite.`);
|
|
19014
|
+
}
|
|
19015
|
+
const projectName = args.project ?? deriveProjectName(cwd);
|
|
19016
|
+
if (!projectName) {
|
|
19017
|
+
throw new Error(
|
|
19018
|
+
"Could not derive projectName from git remote. Pass --project <name> explicitly."
|
|
19019
|
+
);
|
|
19020
|
+
}
|
|
19021
|
+
const ticketPattern = args["ticket-pattern"] ?? DEFAULT_TICKET_PATTERN2;
|
|
19022
|
+
writeFileSync6(target, `${JSON.stringify({ projectName, ticketPattern }, null, 2)}
|
|
19023
|
+
`, {
|
|
19024
|
+
mode: 420
|
|
19025
|
+
});
|
|
19026
|
+
R2.success(`Wrote ${target}`);
|
|
19027
|
+
R2.info(`projectName: ${projectName}`);
|
|
19028
|
+
R2.info(`ticketPattern: ${ticketPattern}`);
|
|
19029
|
+
}
|
|
19030
|
+
});
|
|
19031
|
+
function deriveProjectName(cwd) {
|
|
19032
|
+
try {
|
|
19033
|
+
const out = execFileSync2("git", ["remote", "get-url", "origin"], {
|
|
19034
|
+
encoding: "utf8",
|
|
19035
|
+
cwd,
|
|
19036
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
19037
|
+
timeout: 2e3
|
|
19038
|
+
}).trim();
|
|
19039
|
+
return out ? repoSlugFromRemote(out) : null;
|
|
19040
|
+
} catch {
|
|
19041
|
+
return null;
|
|
19042
|
+
}
|
|
19043
|
+
}
|
|
19044
|
+
|
|
19045
|
+
// src/lib/table.ts
|
|
19046
|
+
function renderTable(headers, rows) {
|
|
19047
|
+
const widths = headers.map(
|
|
19048
|
+
(h2, i) => Math.max(h2.length, ...rows.map((row) => (row[i] ?? "").length))
|
|
19049
|
+
);
|
|
19050
|
+
const pad = (s, i) => s.padEnd(widths[i] ?? 0);
|
|
19051
|
+
const divider = widths.map((w3) => "\u2500".repeat(w3)).join(" ");
|
|
19052
|
+
return [headers.map(pad).join(" "), divider, ...rows.map((row) => row.map(pad).join(" "))].join(
|
|
19053
|
+
"\n"
|
|
19054
|
+
);
|
|
19055
|
+
}
|
|
19056
|
+
|
|
19057
|
+
// src/commands/sync-models.ts
|
|
19058
|
+
var SCOPES2 = ["local", "project", "user"];
|
|
19059
|
+
var modelsSyncCommand = defineCommand({
|
|
19060
|
+
meta: {
|
|
19061
|
+
name: "sync",
|
|
19062
|
+
description: "Refresh the model list (with names, costs, context limits) in an existing opencode.json."
|
|
19063
|
+
},
|
|
19064
|
+
args: {
|
|
19065
|
+
scope: {
|
|
19066
|
+
type: "string",
|
|
19067
|
+
description: "Settings scope: local (default, per-repo), project, user.",
|
|
19068
|
+
valueHint: "local|project|user"
|
|
19069
|
+
},
|
|
19070
|
+
path: {
|
|
19071
|
+
type: "string",
|
|
19072
|
+
description: "Explicit opencode.json path. Overrides --scope.",
|
|
19073
|
+
valueHint: "/path/to/opencode.json"
|
|
19074
|
+
}
|
|
19075
|
+
},
|
|
19076
|
+
async run({ args }) {
|
|
19077
|
+
const creds = await readCredentials();
|
|
19078
|
+
if (!creds) {
|
|
19079
|
+
throw new Error("Not signed in. Run `codevector auth login` first.");
|
|
19080
|
+
}
|
|
19081
|
+
ge("Sync models");
|
|
19082
|
+
const target = await resolveTarget(args);
|
|
19083
|
+
const client = gatewayClient(creds.gatewayUrl, creds.apiKey, 1e4);
|
|
19084
|
+
const s = ft();
|
|
19085
|
+
s.start("Loading reachable models\u2026");
|
|
19086
|
+
let reachable;
|
|
19087
|
+
try {
|
|
19088
|
+
const res = await call(parseResponse(client.models.$get()));
|
|
19089
|
+
reachable = res.data.filter((m2) => m2.kind === "chat").map((m2) => ({
|
|
19090
|
+
slug: m2.slug,
|
|
19091
|
+
displayName: m2.displayName,
|
|
19092
|
+
contextWindow: m2.contextWindow,
|
|
19093
|
+
maxOutputTokens: m2.maxOutputTokens,
|
|
19094
|
+
maxInputTokens: m2.maxInputTokens,
|
|
19095
|
+
inputPricePerMtok: m2.inputPricePerMtok,
|
|
19096
|
+
cachedInputPricePerMtok: m2.cachedInputPricePerMtok,
|
|
19097
|
+
cacheWritePricePerMtok: m2.cacheWritePricePerMtok,
|
|
19098
|
+
reasoningPricePerMtok: m2.reasoningPricePerMtok,
|
|
19099
|
+
outputPricePerMtok: m2.outputPricePerMtok,
|
|
19100
|
+
supportsReasoning: m2.supportsReasoning,
|
|
19101
|
+
supportsAttachment: m2.supportsAttachment,
|
|
19102
|
+
supportsToolCall: m2.supportsToolCall,
|
|
19103
|
+
supportsTemperature: m2.supportsTemperature,
|
|
19104
|
+
inputModalities: m2.inputModalities,
|
|
19105
|
+
outputModalities: m2.outputModalities,
|
|
19106
|
+
releaseDate: m2.releaseDate,
|
|
19107
|
+
family: m2.family
|
|
19108
|
+
}));
|
|
19109
|
+
s.stop(`${reachable.length} model${reachable.length === 1 ? "" : "s"} reachable`);
|
|
19110
|
+
} catch (err) {
|
|
19111
|
+
s.stop("Could not load models");
|
|
19112
|
+
R2.error(err instanceof ApiClientError ? err.message : String(err));
|
|
19113
|
+
process.exitCode = 1;
|
|
19114
|
+
return;
|
|
19115
|
+
}
|
|
19116
|
+
try {
|
|
19117
|
+
const written = syncOpencodeModels(target, reachable);
|
|
19118
|
+
R2.success(`Wrote ${written} model${written === 1 ? "" : "s"} to ${target}`);
|
|
19119
|
+
} catch (err) {
|
|
19120
|
+
R2.error(err instanceof Error ? err.message : String(err));
|
|
19121
|
+
process.exitCode = 1;
|
|
19122
|
+
return;
|
|
19123
|
+
}
|
|
19124
|
+
ye("Done.");
|
|
19125
|
+
}
|
|
19126
|
+
});
|
|
19127
|
+
async function resolveTarget(args) {
|
|
19128
|
+
if (args.path) return args.path;
|
|
19129
|
+
if (args.scope) {
|
|
19130
|
+
if (!isScope2(args.scope)) {
|
|
19131
|
+
throw new Error(`Invalid --scope "${args.scope}". Use one of: ${SCOPES2.join(", ")}.`);
|
|
19132
|
+
}
|
|
19133
|
+
return opencodeSettingsPath(args.scope);
|
|
19134
|
+
}
|
|
19135
|
+
const picked = unwrap(
|
|
19136
|
+
await xe({
|
|
19137
|
+
message: "Which opencode.json should be refreshed? (arrow keys to move, enter to select)",
|
|
19138
|
+
options: [
|
|
19139
|
+
{ value: "local", label: "local", hint: "./opencode.json (this repo)" },
|
|
19140
|
+
{ value: "project", label: "project", hint: "./opencode.json (this repo, committed)" },
|
|
19141
|
+
{ value: "user", label: "user", hint: "~/.config/opencode/opencode.json (global)" }
|
|
19142
|
+
],
|
|
19143
|
+
initialValue: "local"
|
|
19144
|
+
})
|
|
19145
|
+
);
|
|
19146
|
+
return opencodeSettingsPath(picked);
|
|
19147
|
+
}
|
|
19148
|
+
function isScope2(value) {
|
|
19149
|
+
return SCOPES2.includes(value);
|
|
19150
|
+
}
|
|
19151
|
+
|
|
19152
|
+
// src/commands/models.ts
|
|
19153
|
+
var modelsListCommand = defineCommand({
|
|
19154
|
+
meta: {
|
|
19155
|
+
name: "list",
|
|
19156
|
+
description: "List models you can reach through the gateway."
|
|
19157
|
+
},
|
|
19158
|
+
args: {
|
|
19159
|
+
kind: {
|
|
19160
|
+
type: "string",
|
|
19161
|
+
description: "Filter by kind: chat or embedding.",
|
|
19162
|
+
valueHint: "chat|embedding"
|
|
19163
|
+
},
|
|
19164
|
+
json: {
|
|
19165
|
+
type: "boolean",
|
|
19166
|
+
description: "Emit raw JSON (for scripting)."
|
|
19167
|
+
}
|
|
19168
|
+
},
|
|
19169
|
+
async run({ args }) {
|
|
19170
|
+
const creds = await readCredentials();
|
|
19171
|
+
if (!creds) {
|
|
19172
|
+
R2.warn("Not signed in. Run `codevector auth login` to get started.");
|
|
19173
|
+
process.exitCode = 1;
|
|
19174
|
+
return;
|
|
19175
|
+
}
|
|
19176
|
+
const kindFilter = args.kind;
|
|
19177
|
+
if (kindFilter && kindFilter !== "chat" && kindFilter !== "embedding") {
|
|
19178
|
+
throw new Error(`Invalid --kind "${kindFilter}". Use "chat" or "embedding".`);
|
|
19179
|
+
}
|
|
19180
|
+
const client = gatewayClient(creds.gatewayUrl, creds.apiKey, 1e4);
|
|
19181
|
+
const s = args.json ? null : ft();
|
|
19182
|
+
s?.start("Loading models\u2026");
|
|
19183
|
+
try {
|
|
19184
|
+
const res = await call(parseResponse(client.models.$get()));
|
|
19185
|
+
const filtered = kindFilter ? res.data.filter((m2) => m2.kind === kindFilter) : res.data;
|
|
19186
|
+
s?.stop(`${filtered.length} model${filtered.length === 1 ? "" : "s"} reachable`);
|
|
19187
|
+
if (args.json) {
|
|
19188
|
+
process.stdout.write(`${JSON.stringify(filtered, null, 2)}
|
|
19189
|
+
`);
|
|
19190
|
+
return;
|
|
19191
|
+
}
|
|
19192
|
+
if (filtered.length === 0) {
|
|
19193
|
+
R2.info(
|
|
19194
|
+
kindFilter ? `No ${kindFilter} models available. Ask your gateway admin to grant access.` : "No models available. Ask your gateway admin to grant access."
|
|
19195
|
+
);
|
|
19196
|
+
return;
|
|
19197
|
+
}
|
|
19198
|
+
const headers = [
|
|
19199
|
+
"SLUG",
|
|
19200
|
+
"KIND",
|
|
19201
|
+
"STATUS",
|
|
19202
|
+
"PROVIDER",
|
|
19203
|
+
"CONTEXT",
|
|
19204
|
+
"IN $/MTOK",
|
|
19205
|
+
"OUT $/MTOK",
|
|
19206
|
+
"NAME"
|
|
19207
|
+
];
|
|
19208
|
+
const cells = filtered.map((m2) => [
|
|
19209
|
+
m2.slug,
|
|
19210
|
+
m2.kind,
|
|
19211
|
+
m2.status,
|
|
19212
|
+
m2.providerKind ?? "\u2014",
|
|
19213
|
+
m2.contextWindow ? m2.contextWindow.toLocaleString() : "\u2014",
|
|
19214
|
+
m2.inputPricePerMtok ?? "\u2014",
|
|
19215
|
+
m2.outputPricePerMtok ?? "\u2014",
|
|
19216
|
+
m2.displayName
|
|
19217
|
+
]);
|
|
19218
|
+
Se(renderTable(headers, cells), "Reachable models");
|
|
19219
|
+
} catch (err) {
|
|
19220
|
+
s?.stop("Could not load models");
|
|
19221
|
+
R2.error(err instanceof ApiClientError ? err.message : String(err));
|
|
19222
|
+
process.exitCode = 1;
|
|
19223
|
+
}
|
|
19224
|
+
}
|
|
19225
|
+
});
|
|
19226
|
+
var modelsCommand = defineCommand({
|
|
19227
|
+
meta: {
|
|
19228
|
+
name: "models",
|
|
19229
|
+
description: "List and manage models."
|
|
19230
|
+
},
|
|
19231
|
+
subCommands: {
|
|
19232
|
+
list: modelsListCommand,
|
|
19233
|
+
sync: modelsSyncCommand
|
|
19234
|
+
}
|
|
19235
|
+
});
|
|
19236
|
+
|
|
19237
|
+
// src/commands/profile.ts
|
|
19238
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
|
|
19239
|
+
var WRITERS2 = {
|
|
19240
|
+
"claude-code": writeClaudeCodeConfig,
|
|
19241
|
+
opencode: writeOpencodeConfig,
|
|
19242
|
+
codex: writeCodexConfig
|
|
19243
|
+
};
|
|
19244
|
+
var profileListCommand = defineCommand({
|
|
19245
|
+
meta: {
|
|
19246
|
+
name: "list",
|
|
19247
|
+
description: "List all currently configured profiles."
|
|
19248
|
+
},
|
|
19249
|
+
async run() {
|
|
19250
|
+
const profiles = await readProfiles();
|
|
19251
|
+
if (!profiles || Object.keys(profiles.profiles).length === 0) {
|
|
19252
|
+
R2.info("No profiles configured. Run `codevector auth login` to get started.");
|
|
19253
|
+
return;
|
|
19254
|
+
}
|
|
19255
|
+
const names = Object.keys(profiles.profiles).sort((a, b2) => {
|
|
19256
|
+
if (a === "default") return -1;
|
|
19257
|
+
if (b2 === "default") return 1;
|
|
19258
|
+
return a.localeCompare(b2);
|
|
19259
|
+
});
|
|
19260
|
+
const lines = names.map((name) => {
|
|
19261
|
+
const p2 = profiles.profiles[name];
|
|
19262
|
+
const marker = name === profiles.activeProfile ? " *" : " ";
|
|
19263
|
+
return `${marker} ${name.padEnd(12)} ${p2.email.padEnd(24)} ${p2.gatewayUrl} (${maskApiKey(p2.apiKey)})`;
|
|
19264
|
+
});
|
|
19265
|
+
Se(lines.join("\n"), "Profiles");
|
|
19266
|
+
}
|
|
19267
|
+
});
|
|
19268
|
+
var profileSwitchCommand = defineCommand({
|
|
19269
|
+
meta: {
|
|
19270
|
+
name: "switch",
|
|
19271
|
+
description: "Switch the active profile used by subsequent commands."
|
|
19272
|
+
},
|
|
19273
|
+
async run() {
|
|
19274
|
+
const profiles = await readProfiles();
|
|
19275
|
+
if (!profiles || Object.keys(profiles.profiles).length === 0) {
|
|
19276
|
+
R2.warn("No profiles configured. Run `codevector auth login` first.");
|
|
19277
|
+
process.exitCode = 1;
|
|
19278
|
+
return;
|
|
18713
19279
|
}
|
|
18714
|
-
const
|
|
18715
|
-
|
|
18716
|
-
|
|
18717
|
-
|
|
19280
|
+
const names = Object.keys(profiles.profiles).sort((a, b2) => {
|
|
19281
|
+
if (a === "default") return -1;
|
|
19282
|
+
if (b2 === "default") return 1;
|
|
19283
|
+
return a.localeCompare(b2);
|
|
19284
|
+
});
|
|
19285
|
+
const selected = unwrap(
|
|
19286
|
+
await xe({
|
|
19287
|
+
message: "Select active profile",
|
|
19288
|
+
options: names.map((n) => ({
|
|
19289
|
+
value: n,
|
|
19290
|
+
label: n,
|
|
19291
|
+
hint: n === profiles.activeProfile ? "active" : void 0
|
|
19292
|
+
})),
|
|
19293
|
+
initialValue: profiles.activeProfile
|
|
19294
|
+
})
|
|
19295
|
+
);
|
|
19296
|
+
await setActiveProfile(selected);
|
|
19297
|
+
const active = await getActiveProfile();
|
|
19298
|
+
if (!active) {
|
|
19299
|
+
R2.error(`Profile "${selected}" disappeared mid-switch. Re-run \`codevector profile switch\`.`);
|
|
19300
|
+
process.exitCode = 1;
|
|
19301
|
+
return;
|
|
19302
|
+
}
|
|
19303
|
+
R2.success(`Active profile set to "${selected}".`);
|
|
19304
|
+
Se(
|
|
19305
|
+
`User: ${active.email}
|
|
19306
|
+
Gateway: ${active.gatewayUrl}
|
|
19307
|
+
Key: ${maskApiKey(active.apiKey)}`,
|
|
19308
|
+
`Profile: ${selected}`
|
|
19309
|
+
);
|
|
19310
|
+
const storedToolConfigs = active.toolConfigs ?? [];
|
|
19311
|
+
const defaultCodexConfig = { tool: "codex", scope: "user" };
|
|
19312
|
+
const hasCodexUserConfig = storedToolConfigs.some((tc) => tc.tool === "codex");
|
|
19313
|
+
const toolConfigs = hasCodexUserConfig ? storedToolConfigs : [...storedToolConfigs, defaultCodexConfig];
|
|
19314
|
+
if (!hasCodexUserConfig) {
|
|
19315
|
+
R2.info(
|
|
19316
|
+
storedToolConfigs.length === 0 ? "No stored tool configurations for this profile; applying codex user-scope config." : "No stored codex configuration for this profile; applying codex user-scope config."
|
|
18718
19317
|
);
|
|
18719
19318
|
}
|
|
18720
|
-
const
|
|
18721
|
-
|
|
18722
|
-
|
|
18723
|
-
|
|
19319
|
+
const fetched = await fetchReachableModels(active.gatewayUrl, active.apiKey);
|
|
19320
|
+
if (!fetched.ok) {
|
|
19321
|
+
R2.warn(
|
|
19322
|
+
`Could not reach the gateway to verify reachable models: ${fetched.reason}.`
|
|
19323
|
+
);
|
|
19324
|
+
R2.info(
|
|
19325
|
+
"Stored tool configurations were left unchanged. Re-run `codevector profile switch` once the gateway is reachable to reapply them."
|
|
19326
|
+
);
|
|
19327
|
+
return;
|
|
19328
|
+
}
|
|
19329
|
+
const reachable = fetched.models;
|
|
19330
|
+
const hookPath = installAcceptanceHook();
|
|
19331
|
+
const project = resolveProjectContext(userCwd()).project ?? void 0;
|
|
19332
|
+
const results = [];
|
|
19333
|
+
const persisted = [];
|
|
19334
|
+
for (const tc of toolConfigs) {
|
|
19335
|
+
const tool = tc.tool;
|
|
19336
|
+
const writer = WRITERS2[tool];
|
|
19337
|
+
if (!writer) {
|
|
19338
|
+
results.push({
|
|
19339
|
+
tool: tc.tool,
|
|
19340
|
+
status: "skipped",
|
|
19341
|
+
path: "",
|
|
19342
|
+
scope: tc.scope,
|
|
19343
|
+
notes: `Unsupported tool "${tc.tool}".`
|
|
19344
|
+
});
|
|
19345
|
+
continue;
|
|
19346
|
+
}
|
|
19347
|
+
const storedModelSlug = tool === "codex" && tc.modelSlug === "codex" ? void 0 : tc.modelSlug;
|
|
19348
|
+
const reachableModel = storedModelSlug ? reachable.find((m2) => m2.slug === storedModelSlug) : void 0;
|
|
19349
|
+
const pinAllowed = !reachableModel ? false : tool !== "codex" || isResponsesCompatibleProviderKind(reachableModel.providerKind);
|
|
19350
|
+
let modelArg = storedModelSlug && pinAllowed ? { slug: reachableModel.slug, providerKind: reachableModel.providerKind } : void 0;
|
|
19351
|
+
let extraNote;
|
|
19352
|
+
if (tc.modelSlug === "codex" && tool === "codex") {
|
|
19353
|
+
extraNote = `Pinned model "codex" is an alias; selecting a concrete reachable model for this profile.`;
|
|
19354
|
+
} else if (storedModelSlug && !reachableModel) {
|
|
19355
|
+
extraNote = `Pinned model "${tc.modelSlug}" is not reachable with this profile; model pin removed.`;
|
|
19356
|
+
} else if (storedModelSlug && reachableModel && !pinAllowed) {
|
|
19357
|
+
extraNote = `Pinned model "${tc.modelSlug}" is incompatible with Codex Responses; model pin removed.`;
|
|
19358
|
+
}
|
|
19359
|
+
if (tool === "codex" && !modelArg) {
|
|
19360
|
+
const fallback = pickCodexFallbackModel(reachable);
|
|
19361
|
+
if (fallback) {
|
|
19362
|
+
modelArg = { slug: fallback.slug, providerKind: fallback.providerKind };
|
|
19363
|
+
if (tc.modelSlug) {
|
|
19364
|
+
extraNote = `Pinned model "${tc.modelSlug}" unavailable for this profile; defaulting Codex to "${fallback.slug}".`;
|
|
19365
|
+
} else {
|
|
19366
|
+
extraNote = `No stored Codex model pin for this profile; defaulting to "${fallback.slug}".`;
|
|
19367
|
+
}
|
|
19368
|
+
}
|
|
19369
|
+
}
|
|
19370
|
+
try {
|
|
19371
|
+
const result = writer({
|
|
19372
|
+
gatewayUrl: active.gatewayUrl,
|
|
19373
|
+
apiKey: active.apiKey,
|
|
19374
|
+
hookScriptPath: hookPath,
|
|
19375
|
+
scope: tc.scope,
|
|
19376
|
+
...project ? { project } : {},
|
|
19377
|
+
...modelArg ? { model: modelArg } : {},
|
|
19378
|
+
availableModels: reachable
|
|
19379
|
+
});
|
|
19380
|
+
if (extraNote) {
|
|
19381
|
+
result.notes = result.notes ? `${result.notes} ${extraNote}` : extraNote;
|
|
19382
|
+
}
|
|
19383
|
+
results.push(result);
|
|
19384
|
+
if (result.status === "configured") {
|
|
19385
|
+
persisted.push({
|
|
19386
|
+
tool: result.tool,
|
|
19387
|
+
scope: result.scope,
|
|
19388
|
+
...modelArg ? { modelSlug: modelArg.slug } : {}
|
|
19389
|
+
});
|
|
19390
|
+
}
|
|
19391
|
+
} catch (err) {
|
|
19392
|
+
results.push({
|
|
19393
|
+
tool: tc.tool,
|
|
19394
|
+
status: "skipped",
|
|
19395
|
+
path: "",
|
|
19396
|
+
scope: tc.scope,
|
|
19397
|
+
notes: err instanceof Error ? err.message : String(err)
|
|
19398
|
+
});
|
|
19399
|
+
}
|
|
19400
|
+
}
|
|
19401
|
+
if (persisted.length > 0) {
|
|
19402
|
+
updateProfileToolConfigs(selected, persisted);
|
|
19403
|
+
}
|
|
19404
|
+
const lines = results.map((r) => {
|
|
19405
|
+
if (r.status === "configured") {
|
|
19406
|
+
const noteStr = r.notes ? `
|
|
19407
|
+
${r.notes}` : "";
|
|
19408
|
+
return ` \u2713 ${r.tool} \u2192 ${r.path} [${r.scope}]${noteStr}`;
|
|
19409
|
+
}
|
|
19410
|
+
return ` ! ${r.tool}: skipped \u2014 ${r.notes ?? "unknown reason"}`;
|
|
18724
19411
|
});
|
|
18725
|
-
|
|
18726
|
-
|
|
18727
|
-
|
|
19412
|
+
Se(lines.join("\n"), "Tool configurations updated");
|
|
19413
|
+
const codexConfigured = results.some(
|
|
19414
|
+
(r) => r.tool === "codex" && r.status === "configured"
|
|
19415
|
+
);
|
|
19416
|
+
if (codexConfigured) {
|
|
19417
|
+
Se(
|
|
19418
|
+
`codex reads its API key from $CODEVECTOR_GATEWAY_KEY in your shell, not from codevector's credentials file.
|
|
19419
|
+
Update your shell to use this profile's key:
|
|
19420
|
+
export CODEVECTOR_GATEWAY_KEY=${active.apiKey}
|
|
19421
|
+
Or add it to your shell rc to persist across sessions.`,
|
|
19422
|
+
"codex requires env var update"
|
|
19423
|
+
);
|
|
19424
|
+
}
|
|
18728
19425
|
}
|
|
18729
19426
|
});
|
|
18730
|
-
|
|
19427
|
+
var profileCommand = defineCommand({
|
|
19428
|
+
meta: {
|
|
19429
|
+
name: "profile",
|
|
19430
|
+
description: "Manage CLI profiles."
|
|
19431
|
+
},
|
|
19432
|
+
subCommands: {
|
|
19433
|
+
list: profileListCommand,
|
|
19434
|
+
switch: profileSwitchCommand
|
|
19435
|
+
}
|
|
19436
|
+
});
|
|
19437
|
+
async function fetchReachableModels(gatewayUrl, apiKey) {
|
|
19438
|
+
const client = gatewayClient(gatewayUrl, apiKey, 1e4);
|
|
18731
19439
|
try {
|
|
18732
|
-
const
|
|
18733
|
-
|
|
18734
|
-
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
|
|
18738
|
-
|
|
19440
|
+
const res = await call(parseResponse(client.models.$get()));
|
|
19441
|
+
const models = res.data.filter((m2) => m2.kind === "chat").map((m2) => ({
|
|
19442
|
+
slug: m2.slug,
|
|
19443
|
+
providerKind: m2.providerKind,
|
|
19444
|
+
displayName: m2.displayName,
|
|
19445
|
+
contextWindow: m2.contextWindow,
|
|
19446
|
+
maxOutputTokens: m2.maxOutputTokens,
|
|
19447
|
+
maxInputTokens: m2.maxInputTokens,
|
|
19448
|
+
inputPricePerMtok: m2.inputPricePerMtok,
|
|
19449
|
+
cachedInputPricePerMtok: m2.cachedInputPricePerMtok,
|
|
19450
|
+
cacheWritePricePerMtok: m2.cacheWritePricePerMtok,
|
|
19451
|
+
reasoningPricePerMtok: m2.reasoningPricePerMtok,
|
|
19452
|
+
outputPricePerMtok: m2.outputPricePerMtok,
|
|
19453
|
+
supportsReasoning: m2.supportsReasoning,
|
|
19454
|
+
supportsAttachment: m2.supportsAttachment,
|
|
19455
|
+
supportsToolCall: m2.supportsToolCall,
|
|
19456
|
+
supportsTemperature: m2.supportsTemperature,
|
|
19457
|
+
inputModalities: m2.inputModalities,
|
|
19458
|
+
outputModalities: m2.outputModalities,
|
|
19459
|
+
releaseDate: m2.releaseDate,
|
|
19460
|
+
family: m2.family
|
|
19461
|
+
}));
|
|
19462
|
+
return { ok: true, models };
|
|
19463
|
+
} catch (err) {
|
|
19464
|
+
return { ok: false, reason: err instanceof ApiClientError ? err.message : String(err) };
|
|
19465
|
+
}
|
|
19466
|
+
}
|
|
19467
|
+
function isResponsesCompatibleProviderKind(providerKind) {
|
|
19468
|
+
return providerKind === "openai" || providerKind === "openai_compatible";
|
|
19469
|
+
}
|
|
19470
|
+
function pickCodexFallbackModel(reachable) {
|
|
19471
|
+
const candidates = reachable.filter((m2) => isResponsesCompatibleProviderKind(m2.providerKind));
|
|
19472
|
+
if (candidates.length === 0) {
|
|
19473
|
+
return void 0;
|
|
19474
|
+
}
|
|
19475
|
+
const ranked = readCodexNuxRankedModels();
|
|
19476
|
+
for (const slug of ranked) {
|
|
19477
|
+
const match = candidates.find((m2) => m2.slug === slug);
|
|
19478
|
+
if (match) return match;
|
|
19479
|
+
}
|
|
19480
|
+
return candidates[0];
|
|
19481
|
+
}
|
|
19482
|
+
function readCodexNuxRankedModels() {
|
|
19483
|
+
const path = codexConfigPath();
|
|
19484
|
+
if (!existsSync9(path)) return [];
|
|
19485
|
+
let parsed;
|
|
19486
|
+
try {
|
|
19487
|
+
parsed = parse3(readFileSync9(path, "utf8"));
|
|
18739
19488
|
} catch {
|
|
18740
|
-
return
|
|
19489
|
+
return [];
|
|
18741
19490
|
}
|
|
19491
|
+
if (!isObject5(parsed)) return [];
|
|
19492
|
+
const tui = asObject(parsed.tui);
|
|
19493
|
+
const availability = asObject(tui?.model_availability_nux);
|
|
19494
|
+
if (!availability) return [];
|
|
19495
|
+
return Object.entries(availability).filter((entry) => typeof entry[1] === "number" && Number.isFinite(entry[1])).sort((a, b2) => b2[1] - a[1] || a[0].localeCompare(b2[0])).map(([slug]) => slug);
|
|
18742
19496
|
}
|
|
18743
|
-
|
|
18744
|
-
|
|
18745
|
-
|
|
18746
|
-
|
|
18747
|
-
|
|
18748
|
-
);
|
|
18749
|
-
const pad = (s, i) => s.padEnd(widths[i] ?? 0);
|
|
18750
|
-
const divider = widths.map((w3) => "\u2500".repeat(w3)).join(" ");
|
|
18751
|
-
return [headers.map(pad).join(" "), divider, ...rows.map((row) => row.map(pad).join(" "))].join(
|
|
18752
|
-
"\n"
|
|
18753
|
-
);
|
|
19497
|
+
function isObject5(value) {
|
|
19498
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19499
|
+
}
|
|
19500
|
+
function asObject(value) {
|
|
19501
|
+
return isObject5(value) ? value : void 0;
|
|
18754
19502
|
}
|
|
18755
19503
|
|
|
18756
|
-
// src/commands/
|
|
18757
|
-
var
|
|
18758
|
-
var modelsSyncCommand = defineCommand({
|
|
19504
|
+
// src/commands/status.ts
|
|
19505
|
+
var statusCommand = defineCommand({
|
|
18759
19506
|
meta: {
|
|
18760
|
-
name: "
|
|
18761
|
-
description: "
|
|
18762
|
-
},
|
|
18763
|
-
args: {
|
|
18764
|
-
scope: {
|
|
18765
|
-
type: "string",
|
|
18766
|
-
description: "Settings scope: local (default, per-repo), project, user.",
|
|
18767
|
-
valueHint: "local|project|user"
|
|
18768
|
-
},
|
|
18769
|
-
path: {
|
|
18770
|
-
type: "string",
|
|
18771
|
-
description: "Explicit opencode.json path. Overrides --scope.",
|
|
18772
|
-
valueHint: "/path/to/opencode.json"
|
|
18773
|
-
}
|
|
19507
|
+
name: "status",
|
|
19508
|
+
description: "Show current login + gateway reachability."
|
|
18774
19509
|
},
|
|
18775
|
-
async run(
|
|
19510
|
+
async run() {
|
|
18776
19511
|
const creds = await readCredentials();
|
|
18777
19512
|
if (!creds) {
|
|
18778
|
-
|
|
19513
|
+
R2.warn("Not signed in. Run `codevector auth login` to get started.");
|
|
19514
|
+
process.exitCode = 1;
|
|
19515
|
+
return;
|
|
18779
19516
|
}
|
|
18780
|
-
|
|
18781
|
-
|
|
19517
|
+
Se(
|
|
19518
|
+
`Signed in as ${creds.email}
|
|
19519
|
+
Gateway: ${creds.gatewayUrl}
|
|
19520
|
+
API key: ${maskApiKey(creds.apiKey)}
|
|
19521
|
+
Last saved: ${creds.savedAt}`,
|
|
19522
|
+
"Credentials"
|
|
19523
|
+
);
|
|
18782
19524
|
const client = gatewayClient(creds.gatewayUrl, creds.apiKey, 1e4);
|
|
18783
19525
|
const s = ft();
|
|
18784
|
-
s.start("
|
|
18785
|
-
let reachable;
|
|
19526
|
+
s.start("Reaching gateway\u2026");
|
|
18786
19527
|
try {
|
|
18787
19528
|
const res = await call(parseResponse(client.models.$get()));
|
|
18788
|
-
|
|
18789
|
-
|
|
18790
|
-
|
|
18791
|
-
contextWindow: m.contextWindow,
|
|
18792
|
-
maxOutputTokens: m.maxOutputTokens,
|
|
18793
|
-
maxInputTokens: m.maxInputTokens,
|
|
18794
|
-
inputPricePerMtok: m.inputPricePerMtok,
|
|
18795
|
-
cachedInputPricePerMtok: m.cachedInputPricePerMtok,
|
|
18796
|
-
cacheWritePricePerMtok: m.cacheWritePricePerMtok,
|
|
18797
|
-
reasoningPricePerMtok: m.reasoningPricePerMtok,
|
|
18798
|
-
outputPricePerMtok: m.outputPricePerMtok,
|
|
18799
|
-
supportsReasoning: m.supportsReasoning,
|
|
18800
|
-
supportsAttachment: m.supportsAttachment,
|
|
18801
|
-
supportsToolCall: m.supportsToolCall,
|
|
18802
|
-
supportsTemperature: m.supportsTemperature,
|
|
18803
|
-
inputModalities: m.inputModalities,
|
|
18804
|
-
outputModalities: m.outputModalities,
|
|
18805
|
-
releaseDate: m.releaseDate,
|
|
18806
|
-
family: m.family
|
|
18807
|
-
}));
|
|
18808
|
-
s.stop(`${reachable.length} model${reachable.length === 1 ? "" : "s"} reachable`);
|
|
19529
|
+
s.stop(
|
|
19530
|
+
res.data.length === 0 ? "Gateway reachable \u2014 no models granted. Ask your admin for access." : `Gateway reachable \u2014 ${res.data.length} model${res.data.length === 1 ? "" : "s"} available. Run \`codevector models\` to list them.`
|
|
19531
|
+
);
|
|
18809
19532
|
} catch (err) {
|
|
18810
|
-
s.stop("
|
|
19533
|
+
s.stop("Gateway unreachable");
|
|
18811
19534
|
R2.error(err instanceof ApiClientError ? err.message : String(err));
|
|
18812
19535
|
process.exitCode = 1;
|
|
18813
|
-
return;
|
|
18814
|
-
}
|
|
18815
|
-
try {
|
|
18816
|
-
const written = syncOpencodeModels(target, reachable);
|
|
18817
|
-
R2.success(`Wrote ${written} model${written === 1 ? "" : "s"} to ${target}`);
|
|
18818
|
-
} catch (err) {
|
|
18819
|
-
R2.error(err instanceof Error ? err.message : String(err));
|
|
18820
|
-
process.exitCode = 1;
|
|
18821
|
-
return;
|
|
18822
19536
|
}
|
|
18823
|
-
ye("Done.");
|
|
18824
19537
|
}
|
|
18825
19538
|
});
|
|
18826
|
-
|
|
18827
|
-
|
|
18828
|
-
|
|
18829
|
-
|
|
18830
|
-
|
|
19539
|
+
|
|
19540
|
+
// src/commands/system.ts
|
|
19541
|
+
import { existsSync as existsSync11 } from "fs";
|
|
19542
|
+
|
|
19543
|
+
// src/lib/backup.ts
|
|
19544
|
+
import {
|
|
19545
|
+
copyFileSync as copyFileSync2,
|
|
19546
|
+
existsSync as existsSync10,
|
|
19547
|
+
mkdirSync as mkdirSync6,
|
|
19548
|
+
readdirSync,
|
|
19549
|
+
statSync as statSync6
|
|
19550
|
+
} from "fs";
|
|
19551
|
+
import { basename, dirname as dirname6, join as join9 } from "path";
|
|
19552
|
+
import { homedir as homedir6 } from "os";
|
|
19553
|
+
var BACKUP_ROOT = process.env.CODEVECTOR_BACKUP_ROOT ?? join9(homedir6(), ".codevector", "backups");
|
|
19554
|
+
function backupTimestamp(d = /* @__PURE__ */ new Date()) {
|
|
19555
|
+
return d.toISOString().replace(/:/g, "-");
|
|
19556
|
+
}
|
|
19557
|
+
function backupFile(sourcePath, tool, timestamp) {
|
|
19558
|
+
if (!existsSync10(sourcePath)) return void 0;
|
|
19559
|
+
const destDir = join9(BACKUP_ROOT, timestamp, tool);
|
|
19560
|
+
mkdirSync6(destDir, { recursive: true, mode: 448 });
|
|
19561
|
+
const dest = join9(destDir, basename(sourcePath));
|
|
19562
|
+
copyFileSync2(sourcePath, dest);
|
|
19563
|
+
return dest;
|
|
19564
|
+
}
|
|
19565
|
+
function listBackupRuns() {
|
|
19566
|
+
if (!existsSync10(BACKUP_ROOT)) return [];
|
|
19567
|
+
const entries = readdirSync(BACKUP_ROOT, { withFileTypes: true }).filter((e2) => e2.isDirectory()).map((e2) => e2.name).sort().reverse();
|
|
19568
|
+
const runs = [];
|
|
19569
|
+
for (const ts of entries) {
|
|
19570
|
+
const dir = join9(BACKUP_ROOT, ts);
|
|
19571
|
+
const tools = readdirSync(dir, { withFileTypes: true }).filter((e2) => e2.isDirectory());
|
|
19572
|
+
const collected = [];
|
|
19573
|
+
for (const toolDir of tools) {
|
|
19574
|
+
const toolPath = join9(dir, toolDir.name);
|
|
19575
|
+
for (const file2 of readdirSync(toolPath, { withFileTypes: true })) {
|
|
19576
|
+
if (!file2.isFile()) continue;
|
|
19577
|
+
collected.push({
|
|
19578
|
+
tool: toolDir.name,
|
|
19579
|
+
original: "",
|
|
19580
|
+
// resolved by caller per tool — see restoreBackup()
|
|
19581
|
+
backup: join9(toolPath, file2.name)
|
|
19582
|
+
});
|
|
19583
|
+
}
|
|
18831
19584
|
}
|
|
18832
|
-
|
|
19585
|
+
if (collected.length === 0) continue;
|
|
19586
|
+
runs.push({ timestamp: ts, dir, entries: collected });
|
|
18833
19587
|
}
|
|
18834
|
-
|
|
18835
|
-
await Ee({
|
|
18836
|
-
message: "Which opencode.json should be refreshed?",
|
|
18837
|
-
options: [
|
|
18838
|
-
{ value: "local", label: "local", hint: "./opencode.json (this repo)" },
|
|
18839
|
-
{ value: "project", label: "project", hint: "./opencode.json (this repo, committed)" },
|
|
18840
|
-
{ value: "user", label: "user", hint: "~/.config/opencode/opencode.json (global)" }
|
|
18841
|
-
],
|
|
18842
|
-
initialValue: "local"
|
|
18843
|
-
})
|
|
18844
|
-
);
|
|
18845
|
-
return opencodeSettingsPath(picked);
|
|
19588
|
+
return runs;
|
|
18846
19589
|
}
|
|
18847
|
-
function
|
|
18848
|
-
|
|
19590
|
+
function restoreBackup(backupPath, originalPath) {
|
|
19591
|
+
if (!existsSync10(backupPath)) {
|
|
19592
|
+
throw new Error(`Backup file missing: ${backupPath}`);
|
|
19593
|
+
}
|
|
19594
|
+
mkdirSync6(dirname6(originalPath), { recursive: true });
|
|
19595
|
+
copyFileSync2(backupPath, originalPath);
|
|
19596
|
+
}
|
|
19597
|
+
function backupRunMtime(dir) {
|
|
19598
|
+
return statSync6(dir).mtime;
|
|
18849
19599
|
}
|
|
18850
19600
|
|
|
18851
|
-
// src/commands/
|
|
18852
|
-
var
|
|
19601
|
+
// src/commands/system.ts
|
|
19602
|
+
var TOOLS = ["claude-code", "opencode", "codex"];
|
|
19603
|
+
var WRITERS3 = {
|
|
19604
|
+
"claude-code": writeClaudeCodeConfig,
|
|
19605
|
+
opencode: writeOpencodeConfig,
|
|
19606
|
+
codex: writeCodexConfig
|
|
19607
|
+
};
|
|
19608
|
+
function userPathFor(tool) {
|
|
19609
|
+
switch (tool) {
|
|
19610
|
+
case "claude-code":
|
|
19611
|
+
return claudeSettingsPath("user");
|
|
19612
|
+
case "opencode":
|
|
19613
|
+
return opencodeSettingsPath("user");
|
|
19614
|
+
case "codex":
|
|
19615
|
+
return codexConfigPath("user");
|
|
19616
|
+
}
|
|
19617
|
+
}
|
|
19618
|
+
var systemConfigureCommand = defineCommand({
|
|
18853
19619
|
meta: {
|
|
18854
|
-
name: "
|
|
18855
|
-
description: "
|
|
19620
|
+
name: "configure",
|
|
19621
|
+
description: "Write user-scope (global, machine-wide) config for all supported editors at once. Existing files are backed up so `system restore` can roll back."
|
|
19622
|
+
},
|
|
19623
|
+
args: {},
|
|
19624
|
+
async run() {
|
|
19625
|
+
const profiles = await readProfiles();
|
|
19626
|
+
if (!profiles) {
|
|
19627
|
+
throw new Error("Not signed in. Run `codevector auth login` first.");
|
|
19628
|
+
}
|
|
19629
|
+
const creds = profiles.profiles[profiles.activeProfile];
|
|
19630
|
+
if (!creds) {
|
|
19631
|
+
throw new Error(
|
|
19632
|
+
`Active profile "${profiles.activeProfile}" is missing from credentials. Run \`codevector auth login\` to recover.`
|
|
19633
|
+
);
|
|
19634
|
+
}
|
|
19635
|
+
ge("codevector system configure");
|
|
19636
|
+
const timestamp = backupTimestamp();
|
|
19637
|
+
const backups = [];
|
|
19638
|
+
for (const tool of TOOLS) {
|
|
19639
|
+
const target = userPathFor(tool);
|
|
19640
|
+
const backup = backupFile(target, tool, timestamp);
|
|
19641
|
+
if (backup) backups.push({ tool, backup });
|
|
19642
|
+
}
|
|
19643
|
+
if (backups.length > 0) {
|
|
19644
|
+
R2.info(
|
|
19645
|
+
`Backed up ${backups.length} existing config file${backups.length === 1 ? "" : "s"} to ${BACKUP_ROOT}/${timestamp}/`
|
|
19646
|
+
);
|
|
19647
|
+
} else {
|
|
19648
|
+
R2.info("No pre-existing user-scope config files to back up.");
|
|
19649
|
+
}
|
|
19650
|
+
const reachable = await fetchReachableChatModels2(creds);
|
|
19651
|
+
const hookPath = installAcceptanceHook();
|
|
19652
|
+
const results = [];
|
|
19653
|
+
for (const tool of TOOLS) {
|
|
19654
|
+
const writer = WRITERS3[tool];
|
|
19655
|
+
try {
|
|
19656
|
+
results.push(
|
|
19657
|
+
writer({
|
|
19658
|
+
gatewayUrl: creds.gatewayUrl,
|
|
19659
|
+
apiKey: creds.apiKey,
|
|
19660
|
+
hookScriptPath: hookPath,
|
|
19661
|
+
scope: "user",
|
|
19662
|
+
availableModels: reachable
|
|
19663
|
+
})
|
|
19664
|
+
);
|
|
19665
|
+
} catch (err) {
|
|
19666
|
+
results.push({
|
|
19667
|
+
tool,
|
|
19668
|
+
status: "skipped",
|
|
19669
|
+
path: "",
|
|
19670
|
+
scope: "user",
|
|
19671
|
+
notes: err instanceof Error ? err.message : String(err)
|
|
19672
|
+
});
|
|
19673
|
+
}
|
|
19674
|
+
}
|
|
19675
|
+
for (const r of results) {
|
|
19676
|
+
if (r.status === "configured") {
|
|
19677
|
+
R2.success(`${r.tool} \u2192 ${r.path} [user]`);
|
|
19678
|
+
if (r.notes) R2.info(r.notes);
|
|
19679
|
+
} else {
|
|
19680
|
+
R2.warn(`${r.tool}: skipped \u2014 ${r.notes ?? "unknown reason"}`);
|
|
19681
|
+
}
|
|
19682
|
+
}
|
|
19683
|
+
if (backups.length > 0) {
|
|
19684
|
+
Se(
|
|
19685
|
+
`To roll back: codevector system restore --timestamp ${timestamp}`,
|
|
19686
|
+
"Rollback available"
|
|
19687
|
+
);
|
|
19688
|
+
}
|
|
19689
|
+
ye("Done.");
|
|
19690
|
+
}
|
|
19691
|
+
});
|
|
19692
|
+
var systemRestoreCommand = defineCommand({
|
|
19693
|
+
meta: {
|
|
19694
|
+
name: "restore",
|
|
19695
|
+
description: "Restore previously backed-up user-scope config files for all editors. Pick a backup run (--timestamp) or use --latest."
|
|
18856
19696
|
},
|
|
18857
19697
|
args: {
|
|
18858
|
-
|
|
19698
|
+
timestamp: {
|
|
18859
19699
|
type: "string",
|
|
18860
|
-
description: "
|
|
18861
|
-
valueHint: "chat|embedding"
|
|
19700
|
+
description: "Specific backup timestamp (directory name under ~/.codevector/backups/)."
|
|
18862
19701
|
},
|
|
18863
|
-
|
|
19702
|
+
latest: {
|
|
18864
19703
|
type: "boolean",
|
|
18865
|
-
description: "
|
|
19704
|
+
description: "Restore the most recent backup without prompting."
|
|
19705
|
+
},
|
|
19706
|
+
yes: {
|
|
19707
|
+
type: "boolean",
|
|
19708
|
+
description: "Skip the confirmation prompt before overwriting current files."
|
|
18866
19709
|
}
|
|
18867
19710
|
},
|
|
18868
19711
|
async run({ args }) {
|
|
18869
|
-
|
|
18870
|
-
|
|
18871
|
-
|
|
18872
|
-
|
|
19712
|
+
ge("codevector system restore");
|
|
19713
|
+
const runs = listBackupRuns();
|
|
19714
|
+
if (runs.length === 0) {
|
|
19715
|
+
R2.warn(`No backups found under ${BACKUP_ROOT}.`);
|
|
19716
|
+
ye("Nothing to restore.");
|
|
18873
19717
|
return;
|
|
18874
19718
|
}
|
|
18875
|
-
|
|
18876
|
-
if (
|
|
18877
|
-
|
|
19719
|
+
let chosen = runs[0];
|
|
19720
|
+
if (args.timestamp) {
|
|
19721
|
+
const match = runs.find((r) => r.timestamp === args.timestamp);
|
|
19722
|
+
if (!match) {
|
|
19723
|
+
throw new Error(
|
|
19724
|
+
`No backup found with timestamp "${args.timestamp}". Available: ${runs.map((r) => r.timestamp).join(", ")}.`
|
|
19725
|
+
);
|
|
19726
|
+
}
|
|
19727
|
+
chosen = match;
|
|
19728
|
+
} else if (!args.latest) {
|
|
19729
|
+
const picked = unwrap(
|
|
19730
|
+
await xe({
|
|
19731
|
+
message: "Which backup do you want to restore? (arrow keys to move, enter to select)",
|
|
19732
|
+
options: runs.map((r) => ({
|
|
19733
|
+
value: r.timestamp,
|
|
19734
|
+
label: r.timestamp,
|
|
19735
|
+
hint: `${backupRunMtime(r.dir).toLocaleString()} \xB7 ${r.entries.length} file${r.entries.length === 1 ? "" : "s"}`
|
|
19736
|
+
})),
|
|
19737
|
+
initialValue: runs[0].timestamp
|
|
19738
|
+
})
|
|
19739
|
+
);
|
|
19740
|
+
const match = runs.find((r) => r.timestamp === picked);
|
|
19741
|
+
if (!match) throw new Error(`Internal error: picked timestamp not found (${picked}).`);
|
|
19742
|
+
chosen = match;
|
|
19743
|
+
}
|
|
19744
|
+
R2.info(`Backup ${chosen.timestamp} \u2014 ${chosen.entries.length} file(s):`);
|
|
19745
|
+
const plan = [];
|
|
19746
|
+
for (const e2 of chosen.entries) {
|
|
19747
|
+
if (!isTool2(e2.tool)) {
|
|
19748
|
+
R2.warn(` skip ${e2.tool} (unknown tool in backup)`);
|
|
19749
|
+
continue;
|
|
19750
|
+
}
|
|
19751
|
+
const target = userPathFor(e2.tool);
|
|
19752
|
+
plan.push({ tool: e2.tool, backup: e2.backup, target });
|
|
19753
|
+
R2.info(` ${e2.tool} \u2192 ${target}${existsSync11(target) ? " (will overwrite)" : " (new)"}`);
|
|
18878
19754
|
}
|
|
18879
|
-
|
|
18880
|
-
|
|
18881
|
-
|
|
18882
|
-
|
|
18883
|
-
|
|
18884
|
-
const
|
|
18885
|
-
|
|
18886
|
-
|
|
18887
|
-
process.stdout.write(`${JSON.stringify(filtered, null, 2)}
|
|
18888
|
-
`);
|
|
19755
|
+
if (plan.length === 0) {
|
|
19756
|
+
ye("Nothing to restore.");
|
|
19757
|
+
return;
|
|
19758
|
+
}
|
|
19759
|
+
if (!args.yes) {
|
|
19760
|
+
const ok = await confirmRestore();
|
|
19761
|
+
if (!ok) {
|
|
19762
|
+
ye("Aborted.");
|
|
18889
19763
|
return;
|
|
18890
19764
|
}
|
|
18891
|
-
|
|
18892
|
-
|
|
18893
|
-
|
|
18894
|
-
);
|
|
18895
|
-
|
|
19765
|
+
}
|
|
19766
|
+
for (const step of plan) {
|
|
19767
|
+
try {
|
|
19768
|
+
restoreBackup(step.backup, step.target);
|
|
19769
|
+
R2.success(`Restored ${step.tool} \u2192 ${step.target}`);
|
|
19770
|
+
} catch (err) {
|
|
19771
|
+
R2.error(`${step.tool}: ${err instanceof Error ? err.message : String(err)}`);
|
|
19772
|
+
process.exitCode = 1;
|
|
18896
19773
|
}
|
|
18897
|
-
const headers = [
|
|
18898
|
-
"SLUG",
|
|
18899
|
-
"KIND",
|
|
18900
|
-
"STATUS",
|
|
18901
|
-
"PROVIDER",
|
|
18902
|
-
"CONTEXT",
|
|
18903
|
-
"IN $/MTOK",
|
|
18904
|
-
"OUT $/MTOK",
|
|
18905
|
-
"NAME"
|
|
18906
|
-
];
|
|
18907
|
-
const cells = filtered.map((m) => [
|
|
18908
|
-
m.slug,
|
|
18909
|
-
m.kind,
|
|
18910
|
-
m.status,
|
|
18911
|
-
m.providerKind ?? "\u2014",
|
|
18912
|
-
m.contextWindow ? m.contextWindow.toLocaleString() : "\u2014",
|
|
18913
|
-
m.inputPricePerMtok ?? "\u2014",
|
|
18914
|
-
m.outputPricePerMtok ?? "\u2014",
|
|
18915
|
-
m.displayName
|
|
18916
|
-
]);
|
|
18917
|
-
Se(renderTable(headers, cells), "Reachable models");
|
|
18918
|
-
} catch (err) {
|
|
18919
|
-
s?.stop("Could not load models");
|
|
18920
|
-
R2.error(err instanceof ApiClientError ? err.message : String(err));
|
|
18921
|
-
process.exitCode = 1;
|
|
18922
19774
|
}
|
|
19775
|
+
ye("Done.");
|
|
18923
19776
|
}
|
|
18924
19777
|
});
|
|
18925
|
-
|
|
19778
|
+
async function confirmRestore() {
|
|
19779
|
+
const v2 = await ue({
|
|
19780
|
+
message: "Overwrite current user-scope config files with this backup?",
|
|
19781
|
+
initialValue: false
|
|
19782
|
+
});
|
|
19783
|
+
if (q(v2)) return false;
|
|
19784
|
+
return v2 === true;
|
|
19785
|
+
}
|
|
19786
|
+
function isTool2(value) {
|
|
19787
|
+
return TOOLS.includes(value);
|
|
19788
|
+
}
|
|
19789
|
+
async function fetchReachableChatModels2(creds) {
|
|
19790
|
+
const client = gatewayClient(creds.gatewayUrl, creds.apiKey, 1e4);
|
|
19791
|
+
const s = ft();
|
|
19792
|
+
s.start("Loading reachable models\u2026");
|
|
19793
|
+
try {
|
|
19794
|
+
const res = await call(parseResponse(client.models.$get()));
|
|
19795
|
+
const models = res.data.filter((m2) => m2.kind === "chat").map((m2) => ({
|
|
19796
|
+
slug: m2.slug,
|
|
19797
|
+
displayName: m2.displayName,
|
|
19798
|
+
contextWindow: m2.contextWindow,
|
|
19799
|
+
maxOutputTokens: m2.maxOutputTokens,
|
|
19800
|
+
maxInputTokens: m2.maxInputTokens,
|
|
19801
|
+
inputPricePerMtok: m2.inputPricePerMtok,
|
|
19802
|
+
cachedInputPricePerMtok: m2.cachedInputPricePerMtok,
|
|
19803
|
+
cacheWritePricePerMtok: m2.cacheWritePricePerMtok,
|
|
19804
|
+
reasoningPricePerMtok: m2.reasoningPricePerMtok,
|
|
19805
|
+
outputPricePerMtok: m2.outputPricePerMtok,
|
|
19806
|
+
supportsReasoning: m2.supportsReasoning,
|
|
19807
|
+
supportsAttachment: m2.supportsAttachment,
|
|
19808
|
+
supportsToolCall: m2.supportsToolCall,
|
|
19809
|
+
supportsTemperature: m2.supportsTemperature,
|
|
19810
|
+
inputModalities: m2.inputModalities,
|
|
19811
|
+
outputModalities: m2.outputModalities,
|
|
19812
|
+
releaseDate: m2.releaseDate,
|
|
19813
|
+
family: m2.family
|
|
19814
|
+
}));
|
|
19815
|
+
s.stop(`${models.length} model${models.length === 1 ? "" : "s"} reachable`);
|
|
19816
|
+
return models;
|
|
19817
|
+
} catch (err) {
|
|
19818
|
+
s.stop("Could not load models");
|
|
19819
|
+
R2.warn(
|
|
19820
|
+
`Continuing without model list \u2014 ${err instanceof ApiClientError ? err.message : String(err)}.`
|
|
19821
|
+
);
|
|
19822
|
+
return [];
|
|
19823
|
+
}
|
|
19824
|
+
}
|
|
19825
|
+
var systemCommand = defineCommand({
|
|
18926
19826
|
meta: {
|
|
18927
|
-
name: "
|
|
18928
|
-
description: "
|
|
19827
|
+
name: "system",
|
|
19828
|
+
description: "Machine-wide (user-scope) operations. Use `system configure` for global setup of all editors and `system restore` to roll back."
|
|
18929
19829
|
},
|
|
18930
19830
|
subCommands: {
|
|
18931
|
-
|
|
18932
|
-
|
|
19831
|
+
configure: systemConfigureCommand,
|
|
19832
|
+
restore: systemRestoreCommand
|
|
18933
19833
|
}
|
|
18934
19834
|
});
|
|
18935
19835
|
|
|
18936
|
-
// src/commands/
|
|
18937
|
-
|
|
19836
|
+
// src/commands/update.ts
|
|
19837
|
+
import { spawnSync } from "child_process";
|
|
19838
|
+
|
|
19839
|
+
// package.json
|
|
19840
|
+
var package_default = {
|
|
19841
|
+
name: "@codevector/cli",
|
|
19842
|
+
version: "0.4.0",
|
|
19843
|
+
description: "CodeVector CLI \u2014 installs and configures first-party coding-tool integrations.",
|
|
19844
|
+
license: "UNLICENSED",
|
|
19845
|
+
bin: {
|
|
19846
|
+
codevector: "./bin/codevector.mjs"
|
|
19847
|
+
},
|
|
19848
|
+
files: [
|
|
19849
|
+
"bin",
|
|
19850
|
+
"dist",
|
|
19851
|
+
"scripts",
|
|
19852
|
+
"src/hooks"
|
|
19853
|
+
],
|
|
19854
|
+
type: "module",
|
|
19855
|
+
publishConfig: {
|
|
19856
|
+
access: "public"
|
|
19857
|
+
},
|
|
19858
|
+
scripts: {
|
|
19859
|
+
dev: "tsx src/index.ts",
|
|
19860
|
+
build: "tsup",
|
|
19861
|
+
"type-check": "tsc --noEmit",
|
|
19862
|
+
test: "vitest run",
|
|
19863
|
+
"test:watch": "vitest",
|
|
19864
|
+
postinstall: "node scripts/postinstall.mjs"
|
|
19865
|
+
},
|
|
19866
|
+
dependencies: {
|
|
19867
|
+
"@clack/prompts": "1.4.0",
|
|
19868
|
+
citty: "^0.2.2",
|
|
19869
|
+
hono: "4.12.16",
|
|
19870
|
+
"smol-toml": "^1.6.1"
|
|
19871
|
+
},
|
|
19872
|
+
devDependencies: {
|
|
19873
|
+
"@codevector/api": "workspace:*",
|
|
19874
|
+
"@codevector/common": "workspace:*",
|
|
19875
|
+
"@types/node": "25.6.0",
|
|
19876
|
+
tsup: "^8.5.1",
|
|
19877
|
+
tsx: "4.21.0",
|
|
19878
|
+
typescript: "6.0.3",
|
|
19879
|
+
vitest: "4.1.5",
|
|
19880
|
+
zod: "4.4.2"
|
|
19881
|
+
},
|
|
19882
|
+
engines: {
|
|
19883
|
+
node: ">=20"
|
|
19884
|
+
}
|
|
19885
|
+
};
|
|
19886
|
+
|
|
19887
|
+
// src/lib/install-pref.ts
|
|
19888
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync10, renameSync as renameSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
19889
|
+
import { join as join10 } from "path";
|
|
19890
|
+
var INSTALL_PREF_FILE = join10(CODEVECTOR_CONFIG_DIR, "install.json");
|
|
19891
|
+
var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn"];
|
|
19892
|
+
function isPackageManager(v2) {
|
|
19893
|
+
return typeof v2 === "string" && PACKAGE_MANAGERS.includes(v2);
|
|
19894
|
+
}
|
|
19895
|
+
function readInstallPref() {
|
|
19896
|
+
if (!existsSync12(INSTALL_PREF_FILE)) return void 0;
|
|
19897
|
+
try {
|
|
19898
|
+
const raw = readFileSync10(INSTALL_PREF_FILE, "utf8");
|
|
19899
|
+
const parsed = JSON.parse(raw);
|
|
19900
|
+
if (!isPackageManager(parsed.packageManager)) return void 0;
|
|
19901
|
+
const source = parsed.source === "user" ? "user" : "auto";
|
|
19902
|
+
return {
|
|
19903
|
+
packageManager: parsed.packageManager,
|
|
19904
|
+
source,
|
|
19905
|
+
detectedAt: typeof parsed.detectedAt === "string" ? parsed.detectedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
19906
|
+
};
|
|
19907
|
+
} catch {
|
|
19908
|
+
return void 0;
|
|
19909
|
+
}
|
|
19910
|
+
}
|
|
19911
|
+
function writeInstallPref(pref) {
|
|
19912
|
+
mkdirSync7(CODEVECTOR_CONFIG_DIR, { recursive: true, mode: 448 });
|
|
19913
|
+
const tmp = `${INSTALL_PREF_FILE}.${process.pid}.tmp`;
|
|
19914
|
+
writeFileSync7(tmp, JSON.stringify(pref, null, 2));
|
|
19915
|
+
renameSync4(tmp, INSTALL_PREF_FILE);
|
|
19916
|
+
}
|
|
19917
|
+
|
|
19918
|
+
// src/commands/update.ts
|
|
19919
|
+
var PKG_NAME = "@codevector/cli";
|
|
19920
|
+
var updateCommand = defineCommand({
|
|
18938
19921
|
meta: {
|
|
18939
|
-
name: "
|
|
18940
|
-
description:
|
|
19922
|
+
name: "update",
|
|
19923
|
+
description: `Update ${PKG_NAME} to the latest version on npm. Uses the package manager that installed it (auto-detected on install) unless --with overrides.`
|
|
18941
19924
|
},
|
|
18942
|
-
|
|
18943
|
-
|
|
18944
|
-
|
|
18945
|
-
|
|
18946
|
-
|
|
18947
|
-
return;
|
|
19925
|
+
args: {
|
|
19926
|
+
with: {
|
|
19927
|
+
type: "string",
|
|
19928
|
+
description: "Package manager to invoke and remember for next time.",
|
|
19929
|
+
valueHint: "npm|pnpm|yarn"
|
|
18948
19930
|
}
|
|
18949
|
-
|
|
18950
|
-
|
|
18951
|
-
|
|
18952
|
-
|
|
18953
|
-
|
|
18954
|
-
|
|
18955
|
-
);
|
|
18956
|
-
const
|
|
18957
|
-
|
|
18958
|
-
|
|
18959
|
-
|
|
18960
|
-
|
|
18961
|
-
|
|
18962
|
-
|
|
19931
|
+
},
|
|
19932
|
+
async run({ args }) {
|
|
19933
|
+
ge("codevector update");
|
|
19934
|
+
R2.info(`Current version: ${package_default.version}`);
|
|
19935
|
+
const manager = await resolvePackageManager(args.with);
|
|
19936
|
+
const command = installCommand(manager);
|
|
19937
|
+
R2.info(`Using ${manager}: ${command.cmd} ${command.args.join(" ")}`);
|
|
19938
|
+
const result = spawnSync(command.cmd, command.args, { stdio: "inherit" });
|
|
19939
|
+
if (result.error) {
|
|
19940
|
+
throw new Error(
|
|
19941
|
+
`Failed to invoke ${command.cmd}: ${result.error.message}. Is ${command.cmd} on your PATH?`
|
|
19942
|
+
);
|
|
19943
|
+
}
|
|
19944
|
+
if (typeof result.status === "number" && result.status !== 0) {
|
|
19945
|
+
throw new Error(
|
|
19946
|
+
`${command.cmd} exited with status ${result.status}. The new version was not installed.`
|
|
18963
19947
|
);
|
|
18964
|
-
} catch (err) {
|
|
18965
|
-
s.stop("Gateway unreachable");
|
|
18966
|
-
R2.error(err instanceof ApiClientError ? err.message : String(err));
|
|
18967
|
-
process.exitCode = 1;
|
|
18968
19948
|
}
|
|
19949
|
+
R2.success("Update complete. Run `codevector --version` to confirm.");
|
|
19950
|
+
ye("Done.");
|
|
18969
19951
|
}
|
|
18970
19952
|
});
|
|
19953
|
+
async function resolvePackageManager(raw) {
|
|
19954
|
+
if (raw) {
|
|
19955
|
+
const pm = parsePackageManager(raw);
|
|
19956
|
+
if (!pm) {
|
|
19957
|
+
throw new Error(`Unsupported --with "${raw}". Use npm, pnpm, or yarn.`);
|
|
19958
|
+
}
|
|
19959
|
+
writeInstallPref({ packageManager: pm, source: "user", detectedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
19960
|
+
return pm;
|
|
19961
|
+
}
|
|
19962
|
+
const pref = readInstallPref();
|
|
19963
|
+
if (pref) return pref.packageManager;
|
|
19964
|
+
R2.info(
|
|
19965
|
+
`Couldn't detect which package manager installed ${PKG_NAME} (no record at ${INSTALL_PREF_FILE}).`
|
|
19966
|
+
);
|
|
19967
|
+
const picked = unwrap(
|
|
19968
|
+
await xe({
|
|
19969
|
+
message: "Which package manager should `update` use? (remembered for next time)",
|
|
19970
|
+
options: [
|
|
19971
|
+
{ value: "npm", label: "npm", hint: "npm install -g @codevector/cli@latest" },
|
|
19972
|
+
{ value: "pnpm", label: "pnpm", hint: "pnpm add -g @codevector/cli@latest" },
|
|
19973
|
+
{ value: "yarn", label: "yarn", hint: "yarn global add @codevector/cli@latest" }
|
|
19974
|
+
],
|
|
19975
|
+
initialValue: "npm"
|
|
19976
|
+
})
|
|
19977
|
+
);
|
|
19978
|
+
writeInstallPref({
|
|
19979
|
+
packageManager: picked,
|
|
19980
|
+
source: "user",
|
|
19981
|
+
detectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
19982
|
+
});
|
|
19983
|
+
return picked;
|
|
19984
|
+
}
|
|
19985
|
+
function parsePackageManager(value) {
|
|
19986
|
+
switch (value.trim()) {
|
|
19987
|
+
case "npm":
|
|
19988
|
+
case "pnpm":
|
|
19989
|
+
case "yarn":
|
|
19990
|
+
return value.trim();
|
|
19991
|
+
default:
|
|
19992
|
+
return void 0;
|
|
19993
|
+
}
|
|
19994
|
+
}
|
|
19995
|
+
function installCommand(manager) {
|
|
19996
|
+
const target = `${PKG_NAME}@latest`;
|
|
19997
|
+
switch (manager) {
|
|
19998
|
+
case "npm":
|
|
19999
|
+
return { cmd: "npm", args: ["install", "-g", target] };
|
|
20000
|
+
case "pnpm":
|
|
20001
|
+
return { cmd: "pnpm", args: ["add", "-g", target] };
|
|
20002
|
+
case "yarn":
|
|
20003
|
+
return { cmd: "yarn", args: ["global", "add", target] };
|
|
20004
|
+
}
|
|
20005
|
+
}
|
|
18971
20006
|
|
|
18972
20007
|
// src/commands/usage.ts
|
|
18973
20008
|
var usageCommand = defineCommand({
|
|
@@ -19056,52 +20091,6 @@ function buildQuery(args) {
|
|
|
19056
20091
|
return args.end ? { end: args.end } : {};
|
|
19057
20092
|
}
|
|
19058
20093
|
|
|
19059
|
-
// package.json
|
|
19060
|
-
var package_default = {
|
|
19061
|
-
name: "@codevector/cli",
|
|
19062
|
-
version: "0.3.3",
|
|
19063
|
-
description: "CodeVector CLI \u2014 installs and configures first-party coding-tool integrations.",
|
|
19064
|
-
license: "UNLICENSED",
|
|
19065
|
-
bin: {
|
|
19066
|
-
codevector: "./bin/codevector.mjs"
|
|
19067
|
-
},
|
|
19068
|
-
files: [
|
|
19069
|
-
"bin",
|
|
19070
|
-
"dist",
|
|
19071
|
-
"src/hooks"
|
|
19072
|
-
],
|
|
19073
|
-
type: "module",
|
|
19074
|
-
publishConfig: {
|
|
19075
|
-
access: "public"
|
|
19076
|
-
},
|
|
19077
|
-
scripts: {
|
|
19078
|
-
dev: "tsx src/index.ts",
|
|
19079
|
-
build: "tsup",
|
|
19080
|
-
"type-check": "tsc --noEmit",
|
|
19081
|
-
test: "vitest run",
|
|
19082
|
-
"test:watch": "vitest"
|
|
19083
|
-
},
|
|
19084
|
-
dependencies: {
|
|
19085
|
-
"@clack/prompts": "1.3.0",
|
|
19086
|
-
citty: "^0.2.2",
|
|
19087
|
-
hono: "4.12.16",
|
|
19088
|
-
"smol-toml": "^1.6.1"
|
|
19089
|
-
},
|
|
19090
|
-
devDependencies: {
|
|
19091
|
-
"@codevector/api": "workspace:*",
|
|
19092
|
-
"@codevector/common": "workspace:*",
|
|
19093
|
-
"@types/node": "25.6.0",
|
|
19094
|
-
tsup: "^8.5.1",
|
|
19095
|
-
tsx: "4.21.0",
|
|
19096
|
-
typescript: "6.0.3",
|
|
19097
|
-
vitest: "4.1.5",
|
|
19098
|
-
zod: "4.4.2"
|
|
19099
|
-
},
|
|
19100
|
-
engines: {
|
|
19101
|
-
node: ">=20"
|
|
19102
|
-
}
|
|
19103
|
-
};
|
|
19104
|
-
|
|
19105
20094
|
// src/commands/version.ts
|
|
19106
20095
|
var versionCommand = defineCommand({
|
|
19107
20096
|
meta: {
|
|
@@ -19113,6 +20102,89 @@ var versionCommand = defineCommand({
|
|
|
19113
20102
|
}
|
|
19114
20103
|
});
|
|
19115
20104
|
|
|
20105
|
+
// src/lib/update-notifier.ts
|
|
20106
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
|
|
20107
|
+
import { join as join11 } from "path";
|
|
20108
|
+
var PKG_NAME2 = "@codevector/cli";
|
|
20109
|
+
var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME2}/latest`;
|
|
20110
|
+
var CHECK_CACHE_FILE = join11(CODEVECTOR_CONFIG_DIR, "update-check.json");
|
|
20111
|
+
var CHECK_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
20112
|
+
var FETCH_TIMEOUT_MS = 2e3;
|
|
20113
|
+
function readCache() {
|
|
20114
|
+
if (!existsSync13(CHECK_CACHE_FILE)) return void 0;
|
|
20115
|
+
try {
|
|
20116
|
+
const raw = readFileSync11(CHECK_CACHE_FILE, "utf8");
|
|
20117
|
+
const parsed = JSON.parse(raw);
|
|
20118
|
+
if (typeof parsed.checkedAt !== "number") return void 0;
|
|
20119
|
+
return {
|
|
20120
|
+
latest: typeof parsed.latest === "string" ? parsed.latest : null,
|
|
20121
|
+
checkedAt: parsed.checkedAt
|
|
20122
|
+
};
|
|
20123
|
+
} catch {
|
|
20124
|
+
return void 0;
|
|
20125
|
+
}
|
|
20126
|
+
}
|
|
20127
|
+
function writeCache(cache) {
|
|
20128
|
+
try {
|
|
20129
|
+
mkdirSync8(CODEVECTOR_CONFIG_DIR, { recursive: true, mode: 448 });
|
|
20130
|
+
writeFileSync8(CHECK_CACHE_FILE, JSON.stringify(cache));
|
|
20131
|
+
} catch {
|
|
20132
|
+
}
|
|
20133
|
+
}
|
|
20134
|
+
function isNewer(current, latest) {
|
|
20135
|
+
const a = current.split(".").map((p2) => Number.parseInt(p2, 10));
|
|
20136
|
+
const b2 = latest.split(".").map((p2) => Number.parseInt(p2, 10));
|
|
20137
|
+
for (let i = 0; i < Math.max(a.length, b2.length); i++) {
|
|
20138
|
+
const ai = a[i] ?? 0;
|
|
20139
|
+
const bi = b2[i] ?? 0;
|
|
20140
|
+
if (Number.isNaN(ai) || Number.isNaN(bi)) return latest > current;
|
|
20141
|
+
if (bi > ai) return true;
|
|
20142
|
+
if (bi < ai) return false;
|
|
20143
|
+
}
|
|
20144
|
+
return false;
|
|
20145
|
+
}
|
|
20146
|
+
function printUpdateNoticeIfCached(currentVersion) {
|
|
20147
|
+
if (process.env.CODEVECTOR_NO_UPDATE_CHECK === "1") return;
|
|
20148
|
+
try {
|
|
20149
|
+
const cache = readCache();
|
|
20150
|
+
if (!cache || !cache.latest) return;
|
|
20151
|
+
if (isNewer(currentVersion, cache.latest)) {
|
|
20152
|
+
process.stderr.write(
|
|
20153
|
+
`\x1B[33m\u203A\x1B[0m A new version of @codevector/cli is available: ${currentVersion} \u2192 ${cache.latest}. Run \`codevector update\` to install.
|
|
20154
|
+
`
|
|
20155
|
+
);
|
|
20156
|
+
}
|
|
20157
|
+
} catch {
|
|
20158
|
+
}
|
|
20159
|
+
}
|
|
20160
|
+
function scheduleUpdateCheck() {
|
|
20161
|
+
if (process.env.CODEVECTOR_NO_UPDATE_CHECK === "1") return;
|
|
20162
|
+
const cache = readCache();
|
|
20163
|
+
const now = Date.now();
|
|
20164
|
+
if (cache && now - cache.checkedAt < CHECK_TTL_MS) return;
|
|
20165
|
+
void fetchLatestVersion().then((latest) => {
|
|
20166
|
+
writeCache({ latest, checkedAt: Date.now() });
|
|
20167
|
+
}).catch(() => {
|
|
20168
|
+
writeCache({ latest: cache?.latest ?? null, checkedAt: Date.now() });
|
|
20169
|
+
});
|
|
20170
|
+
}
|
|
20171
|
+
async function fetchLatestVersion() {
|
|
20172
|
+
const controller = new AbortController();
|
|
20173
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
20174
|
+
timer.unref?.();
|
|
20175
|
+
try {
|
|
20176
|
+
const res = await fetch(REGISTRY_URL, {
|
|
20177
|
+
signal: controller.signal,
|
|
20178
|
+
headers: { accept: "application/json" }
|
|
20179
|
+
});
|
|
20180
|
+
if (!res.ok) return null;
|
|
20181
|
+
const body = await res.json();
|
|
20182
|
+
return typeof body.version === "string" ? body.version : null;
|
|
20183
|
+
} finally {
|
|
20184
|
+
clearTimeout(timer);
|
|
20185
|
+
}
|
|
20186
|
+
}
|
|
20187
|
+
|
|
19116
20188
|
// src/index.ts
|
|
19117
20189
|
var main = defineCommand({
|
|
19118
20190
|
meta: {
|
|
@@ -19126,11 +20198,16 @@ var main = defineCommand({
|
|
|
19126
20198
|
init: initCommand,
|
|
19127
20199
|
doctor: doctorCommand,
|
|
19128
20200
|
status: statusCommand,
|
|
20201
|
+
system: systemCommand,
|
|
19129
20202
|
models: modelsCommand,
|
|
20203
|
+
profile: profileCommand,
|
|
20204
|
+
update: updateCommand,
|
|
19130
20205
|
usage: usageCommand,
|
|
19131
20206
|
version: versionCommand
|
|
19132
20207
|
}
|
|
19133
20208
|
});
|
|
20209
|
+
printUpdateNoticeIfCached(package_default.version);
|
|
20210
|
+
scheduleUpdateCheck();
|
|
19134
20211
|
runMain(main);
|
|
19135
20212
|
/*! Bundled license information:
|
|
19136
20213
|
|