@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/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(x, y) {
41
- if (!y) return `${CSI2}${x + 1}G`;
42
- return `${CSI2}${y + 1};${x + 1}H`;
40
+ to(x3, y) {
41
+ if (!y) return `${CSI2}${x3 + 1}G`;
42
+ return `${CSI2}${y + 1};${x3 + 1}H`;
43
43
  },
44
- move(x, y) {
44
+ move(x3, y) {
45
45
  let ret = "";
46
- if (x < 0) ret += `${CSI2}${-x}D`;
47
- else if (x > 0) ret += `${CSI2}${x}C`;
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((c2, i) => linePrefix + c2[i === 0 ? "padStart" : "padEnd"](maxLength[i])).join(" ")).join("\n");
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 = (c2, r = 39) => (t) => noColor ? t : `\x1B[${c2}m${t}\x1B[${r}m`;
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.0/node_modules/@clack/core/dist/index.mjs
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 S, stdin as D } from "process";
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 = (x) => {
574
- return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
573
+ var isFullWidth = (x3) => {
574
+ return x3 === 12288 || x3 >= 65281 && x3 <= 65376 || x3 >= 65504 && x3 <= 65510;
575
575
  };
576
- var isWideNotCJKTNotEmoji = (x) => {
577
- return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
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.0/node_modules/@clack/core/dist/index.mjs
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 d(r, t, s) {
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 ? d(n, t < 0 ? -1 : 1, s) : n;
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 = S, overwrite: s = true, hideCursor: e2 = true } = {}) {
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 f = u === "return" ? 0 : -1, y = u === "return" ? -1 : 0;
941
- b.moveCursor(t, f, y, () => {
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 n = A(r ?? S);
955
- return wrapAnsi(t, n - s.length, { hard: true, trim: false }).split(`
956
- `).map((o, u) => {
957
- const a = i ? i(o, u) : o;
958
- return `${u === 0 ? e2 : s}${a}`;
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 p = class {
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 = S, render: n, signal: o, ...u } = t;
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 nt = class extends p {
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 ? d(s, 1, this.options) : s, this.on("key", (e2) => {
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 = d(this.cursor, -1, this.options);
1137
+ this.cursor = f(this.cursor, -1, this.options);
1121
1138
  break;
1122
1139
  case "down":
1123
1140
  case "right":
1124
- this.cursor = d(this.cursor, 1, this.options);
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 p {
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 p {
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 ? d(e2, 1, this.options) : e2, this.changeValue(), this.on("cursor", (i) => {
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 = d(this.cursor, -1, this.options);
1190
+ this.cursor = f(this.cursor, -1, this.options);
1174
1191
  break;
1175
1192
  case "down":
1176
1193
  case "right":
1177
- this.cursor = d(this.cursor, 1, this.options);
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 p {
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.3.0/node_modules/@clack/prompts/dist/index.mjs
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 j2 from "process";
1223
+ import V2 from "process";
1207
1224
  var import_sisteransi2 = __toESM(require_src(), 1);
1208
- import { existsSync as zt, lstatSync as wt, readdirSync as Qt } from "fs";
1209
- import { dirname as bt, join as Zt } from "path";
1210
- function te() {
1211
- return j2.platform !== "win32" ? j2.env.TERM !== "linux" : !!j2.env.CI || !!j2.env.WT_SESSION || !!j2.env.TERMINUS_SUBLIME || j2.env.ConEmuTask === "{cmd::Cmder}" || j2.env.TERM_PROGRAM === "Terminus-Sublime" || j2.env.TERM_PROGRAM === "vscode" || j2.env.TERM === "xterm-256color" || j2.env.TERM === "alacritty" || j2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
1212
- }
1213
- var tt = te();
1214
- var at2 = () => process.env.CI === "true";
1215
- var w2 = (t, r) => tt ? t : r;
1216
- var _t = w2("\u25C6", "*");
1217
- var ot2 = w2("\u25A0", "x");
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 F = w2("\u25C7", "o");
1236
+ var H = w2("\u25C7", "o");
1220
1237
  var lt = w2("\u250C", "T");
1221
1238
  var $ = w2("\u2502", "|");
1222
- var E2 = w2("\u2514", "\u2014");
1223
- var It = w2("\u2510", "T");
1224
- var Et = w2("\u2518", "\u2014");
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 H = w2("\u25CB", " ");
1243
+ var U = w2("\u25CB", " ");
1227
1244
  var et2 = w2("\u25FB", "[\u2022]");
1228
- var U = w2("\u25FC", "[+]");
1229
- var J = w2("\u25FB", "[ ]");
1230
- var Gt = w2("\u25AA", "\u2022");
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 xt = w2("\u251C", "+");
1250
+ var Gt = w2("\u251C", "+");
1234
1251
  var $t = w2("\u256F", "+");
1235
1252
  var dt = w2("\u2570", "+");
1236
- var Ot = w2("\u256D", "+");
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 M = (t) => {
1258
+ var P = (t) => {
1242
1259
  switch (t) {
1243
1260
  case "initial":
1244
1261
  case "active":
1245
- return e("cyan", _t);
1262
+ return e("cyan", Tt);
1246
1263
  case "cancel":
1247
- return e("red", ot2);
1264
+ return e("red", at2);
1248
1265
  case "error":
1249
1266
  return e("yellow", ut2);
1250
1267
  case "submit":
1251
- return e("green", F);
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 ee = (t, r, s, i, u) => {
1268
- let n = r, o = 0;
1269
- for (let c2 = s; c2 < i; c2++) {
1270
- const a = t[c2];
1271
- if (n = n - a.length, o++, n <= u) break;
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 Y2 = ({ cursor: t, options: r, style: s, output: i = process.stdout, maxItems: u = Number.POSITIVE_INFINITY, columnPadding: n = 0, rowPadding: o = 4 }) => {
1276
- const c2 = A(i) - n, a = L(i), l = e("dim", "..."), d2 = Math.max(a - o, 0), y = Math.max(Math.min(u, d2), 5);
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 >= y - 3 && (p2 = Math.max(Math.min(t - y + 3, r.length - y), 0));
1279
- let m = y < r.length && p2 > 0, g = y < r.length && p2 + y < r.length;
1280
- const S2 = Math.min(p2 + y, r.length), h2 = [];
1281
- let f = 0;
1282
- m && f++, g && f++;
1283
- const v2 = p2 + (m ? 1 : 0), T = S2 - (g ? 1 : 0);
1284
- for (let b2 = v2; b2 < T; b2++) {
1285
- const G2 = wrapAnsi(s(r[b2], b2 === t), c2, { hard: true, trim: false }).split(`
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
- h2.push(G2), f += G2.length;
1288
- }
1289
- if (f > d2) {
1290
- let b2 = 0, G2 = 0, x = f;
1291
- const A2 = t - v2, P = (N, D2) => ee(h2, x, N, D2, d2);
1292
- m ? ({ lineCount: x, removals: b2 } = P(0, A2), x > d2 && ({ lineCount: x, removals: G2 } = P(A2 + 1, h2.length))) : ({ lineCount: x, removals: G2 } = P(A2 + 1, h2.length), x > d2 && ({ lineCount: x, removals: b2 } = P(0, A2))), b2 > 0 && (m = true, h2.splice(0, b2)), G2 > 0 && (g = true, h2.splice(h2.length - G2, G2));
1293
- }
1294
- const C2 = [];
1295
- m && C2.push(l);
1296
- for (const b2 of h2) for (const G2 of b2) C2.push(G2);
1297
- return g && C2.push(l), C2;
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: r = e("gray", $), secondarySymbol: s = e("gray", $), output: i = process.stdout, spacing: u = 1, withGuide: n } = {}) => {
1300
- const o = [], c2 = n ?? h.withGuide, a = c2 ? s : "", l = c2 ? `${r} ` : "", d2 = c2 ? `${s} ` : "";
1301
- for (let p2 = 0; p2 < u; p2++) o.push(a);
1302
- const y = Array.isArray(t) ? t : t.split(`
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 (y.length > 0) {
1305
- const [p2, ...m] = y;
1306
- p2.length > 0 ? o.push(`${l}${p2}`) : o.push(c2 ? r : "");
1307
- for (const g of m) g.length > 0 ? o.push(`${d2}${g}`) : o.push(c2 ? s : "");
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
- i.write(`${o.join(`
1353
+ r.write(`${a.join(`
1310
1354
  `)}
1311
1355
  `);
1312
- }, info: (t, r) => {
1313
- R2.message(t, { ...r, symbol: e("blue", ht2) });
1314
- }, success: (t, r) => {
1315
- R2.message(t, { ...r, symbol: e("green", pt) });
1316
- }, step: (t, r) => {
1317
- R2.message(t, { ...r, symbol: e("green", F) });
1318
- }, warn: (t, r) => {
1319
- R2.message(t, { ...r, symbol: e("yellow", mt) });
1320
- }, warning: (t, r) => {
1321
- R2.warn(t, r);
1322
- }, error: (t, r) => {
1323
- R2.message(t, { ...r, symbol: e("red", gt) });
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 = "", r) => {
1326
- const s = r?.output ?? process.stdout, i = r?.withGuide ?? h.withGuide ? `${e("gray", E2)} ` : "";
1327
- s.write(`${i}${e("red", t)}
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 = "", r) => {
1332
- const s = r?.output ?? process.stdout, i = r?.withGuide ?? h.withGuide ? `${e("gray", lt)} ` : "";
1333
- s.write(`${i}${t}
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 = "", r) => {
1337
- const s = r?.output ?? process.stdout, i = r?.withGuide ?? h.withGuide ? `${e("gray", $)}
1338
- ${e("gray", E2)} ` : "";
1339
- s.write(`${i}${t}
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, r) => t.split(`
1344
- `).map((s) => r(s)).join(`
1387
+ var Q2 = (t, i) => t.split(`
1388
+ `).map((s) => i(s)).join(`
1345
1389
  `);
1346
1390
  var ve = (t) => {
1347
- const r = (i, u) => {
1348
- const n = i.label ?? String(i.value);
1349
- return u === "disabled" ? `${e("gray", J)} ${Q2(n, (o) => e(["strikethrough", "gray"], o))}${i.hint ? ` ${e("dim", `(${i.hint ?? "disabled"})`)}` : ""}` : u === "active" ? `${e("cyan", et2)} ${n}${i.hint ? ` ${e("dim", `(${i.hint})`)}` : ""}` : u === "selected" ? `${e("green", U)} ${Q2(n, (o) => e("dim", o))}${i.hint ? ` ${e("dim", `(${i.hint})`)}` : ""}` : u === "cancelled" ? `${Q2(n, (o) => e(["strikethrough", "dim"], o))}` : u === "active-selected" ? `${e("green", U)} ${n}${i.hint ? ` ${e("dim", `(${i.hint})`)}` : ""}` : u === "submitted" ? `${Q2(n, (o) => e("dim", o))}` : `${e("dim", J)} ${Q2(n, (o) => e("dim", o))}`;
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(i) {
1352
- if (s && (i === void 0 || i.length === 0)) return `Please select at least one option.
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 i = t.withGuide ?? h.withGuide, u = W(t.output, t.message, i ? `${yt(this.state)} ` : "", `${M(this.state)} `), n = `${i ? `${e("gray", $)}
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
- `, o = this.value ?? [], c2 = (a, l) => {
1358
- if (a.disabled) return r(a, "disabled");
1359
- const d2 = o.includes(a.value);
1360
- return l && d2 ? r(a, "active-selected") : d2 ? r(a, "selected") : r(a, l ? "active" : "inactive");
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 a = this.options.filter(({ value: d2 }) => o.includes(d2)).map((d2) => r(d2, "submitted")).join(e("dim", ", ")) || e("dim", "none"), l = W(t.output, a, i ? `${e("gray", $)} ` : "");
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 a = this.options.filter(({ value: d2 }) => o.includes(d2)).map((d2) => r(d2, "cancelled")).join(e("dim", ", "));
1369
- if (a.trim() === "") return `${n}${e("gray", $)}`;
1370
- const l = W(t.output, a, i ? `${e("gray", $)} ` : "");
1371
- return `${n}${l}${i ? `
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 a = i ? `${e("yellow", $)} ` : "", l = this.error.split(`
1376
- `).map((p2, m) => m === 0 ? `${i ? `${e("yellow", E2)} ` : ""}${e("yellow", p2)}` : ` ${p2}`).join(`
1377
- `), d2 = n.split(`
1378
- `).length, y = l.split(`
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}${a}${Y2({ output: t.output, options: this.options, cursor: this.cursor, maxItems: t.maxItems, columnPadding: a.length, rowPadding: d2 + y, style: c2 }).join(`
1381
- ${a}`)}
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 a = i ? `${e("cyan", $)} ` : "", l = n.split(`
1387
- `).length, d2 = i ? 2 : 1;
1388
- return `${n}${a}${Y2({ output: t.output, options: this.options, cursor: this.cursor, maxItems: t.maxItems, columnPadding: a.length, rowPadding: l + d2, style: c2 }).join(`
1389
- ${a}`)}
1390
- ${i ? e("cyan", E2) : ""}
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, r, s) => {
1398
- const i = { hard: true, trim: false }, u = wrapAnsi(t, r, i).split(`
1399
- `), n = u.reduce((a, l) => Math.max(dist_default2(l), a), 0), o = u.map(s).reduce((a, l) => Math.max(dist_default2(l), a), 0), c2 = r - (o - n);
1400
- return wrapAnsi(t, c2, i);
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 = "", r = "", s) => {
1403
- const i = s?.output ?? j2.stdout, u = s?.withGuide ?? h.withGuide, n = s?.format ?? we, o = ["", ...be(t, A(i) - 6, n).split(`
1404
- `).map(n), ""], c2 = dist_default2(r), a = Math.max(o.reduce((p2, m) => {
1405
- const g = dist_default2(m);
1406
- return g > p2 ? g : p2;
1407
- }, 0), c2) + 2, l = o.map((p2) => `${e("gray", $)} ${p2}${" ".repeat(a - dist_default2(p2))}${e("gray", $)}`).join(`
1408
- `), d2 = u ? `${e("gray", $)}
1409
- ` : "", y = u ? xt : dt;
1410
- i.write(`${d2}${e("green", F)} ${e("reset", r)} ${e("gray", st.repeat(Math.max(a - c2 - 1, 1)) + ct)}
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", y + st.repeat(a + 2) + $t)}
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 ?? Gt, signal: t.signal, input: t.input, output: t.output, render() {
1416
- const r = t.withGuide ?? h.withGuide, s = `${r ? `${e("gray", $)}
1417
- ` : ""}${M(this.state)} ${t.message}
1418
- `, i = this.userInputWithCursor, u = this.masked;
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 = r ? `${e("yellow", $)} ` : "", o = r ? `${e("yellow", E2)} ` : "", c2 = u ?? "";
1465
+ const n = i ? `${e("yellow", $)} ` : "", a = i ? `${e("yellow", x2)} ` : "", c = u ?? "";
1422
1466
  return t.clearOnError && this.clear(), `${s.trim()}
1423
- ${n}${c2}
1424
- ${o}${e("yellow", this.error)}
1467
+ ${n}${c}
1468
+ ${a}${e("yellow", this.error)}
1425
1469
  `;
1426
1470
  }
1427
1471
  case "submit": {
1428
- const n = r ? `${e("gray", $)} ` : "", o = u ? e("dim", u) : "";
1429
- return `${s}${n}${o}`;
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 = r ? `${e("gray", $)} ` : "", o = u ? e(["strikethrough", "dim"], u) : "";
1433
- return `${s}${n}${o}${u && r ? `
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 = r ? `${e("cyan", $)} ` : "", o = r ? e("cyan", E2) : "";
1438
- return `${s}${n}${i}
1439
- ${o}
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 _e = (t) => e("magenta", t);
1445
- var ft = ({ indicator: t = "dots", onCancel: r, output: s = process.stdout, cancelMessage: i, errorMessage: u, frames: n = tt ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], delay: o = tt ? 80 : 120, signal: c2, ...a } = {}) => {
1446
- const l = at2();
1447
- let d2, y, p2 = false, m = false, g = "", S2, h2 = performance.now();
1448
- const f = A(s), v2 = a?.styleFrame ?? _e, T = (I) => {
1449
- const V2 = I > 1 ? u ?? h.messages.error : i ?? h.messages.cancel;
1450
- m = I === 1, p2 && (W2(V2, I), m && typeof r == "function" && r());
1451
- }, C2 = () => T(2), b2 = () => T(1), G2 = () => {
1452
- process.on("uncaughtExceptionMonitor", C2), process.on("unhandledRejection", C2), process.on("SIGINT", b2), process.on("SIGTERM", b2), process.on("exit", T), c2 && c2.addEventListener("abort", b2);
1453
- }, x = () => {
1454
- process.removeListener("uncaughtExceptionMonitor", C2), process.removeListener("unhandledRejection", C2), process.removeListener("SIGINT", b2), process.removeListener("SIGTERM", b2), process.removeListener("exit", T), c2 && c2.removeEventListener("abort", b2);
1455
- }, A2 = () => {
1456
- if (S2 === void 0) return;
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 I = wrapAnsi(S2, f, { hard: true, trim: false }).split(`
1503
+ const _ = wrapAnsi(I, y, { hard: true, trim: false }).split(`
1460
1504
  `);
1461
- I.length > 1 && s.write(import_sisteransi2.cursor.up(I.length - 1)), s.write(import_sisteransi2.cursor.to(0)), s.write(import_sisteransi2.erase.down());
1462
- }, P = (I) => I.replace(/\.+$/, ""), N = (I) => {
1463
- const V2 = (performance.now() - I) / 1e3, B = Math.floor(V2 / 60), L2 = Math.floor(V2 % 60);
1464
- return B > 0 ? `[${B}m ${L2}s]` : `[${L2}s]`;
1465
- }, D2 = a.withGuide ?? h.withGuide, rt2 = (I = "") => {
1466
- p2 = true, d2 = R({ output: s }), g = P(I), h2 = performance.now(), D2 && s.write(`${e("gray", $)}
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 V2 = 0, B = 0;
1469
- G2(), y = setInterval(() => {
1470
- if (l && g === S2) return;
1471
- A2(), S2 = g;
1472
- const L2 = v2(n[V2]);
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 = `${L2} ${g}...`;
1475
- else if (t === "timer") Z = `${L2} ${g} ${N(h2)}`;
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(B)).slice(0, 3);
1478
- Z = `${L2} ${g}${kt}`;
1521
+ const kt = ".".repeat(Math.floor(L2)).slice(0, 3);
1522
+ Z = `${D2} ${h2}${kt}`;
1479
1523
  }
1480
- const Nt = wrapAnsi(Z, f, { hard: true, trim: false });
1481
- s.write(Nt), V2 = V2 + 1 < n.length ? V2 + 1 : 0, B = B < 4 ? B + 0.125 : 0;
1482
- }, o);
1483
- }, W2 = (I = "", V2 = 0, B = false) => {
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(y), A2();
1486
- const L2 = V2 === 0 ? e("green", F) : V2 === 1 ? e("red", ot2) : e("red", ut2);
1487
- g = I ?? g, B || (t === "timer" ? s.write(`${L2} ${g} ${N(h2)}
1488
- `) : s.write(`${L2} ${g}
1489
- `)), x(), d2();
1490
- };
1491
- return { start: rt2, stop: (I = "") => W2(I, 0), message: (I = "") => {
1492
- g = P(I ?? g);
1493
- }, cancel: (I = "") => W2(I, 1), error: (I = "") => W2(I, 2), clear: () => W2("", 0, true), get isCancelled() {
1494
- return m;
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 Vt = { light: w2("\u2500", "-"), heavy: w2("\u2501", "="), block: w2("\u2588", "#") };
1498
- var it2 = (t, r) => t.includes(`
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) => r(s)).join(`
1501
- `) : r(t);
1502
- var Ee = (t) => {
1503
- const r = (s, i) => {
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 (i) {
1549
+ switch (r) {
1506
1550
  case "disabled":
1507
- return `${e("gray", H)} ${it2(u, (n) => e("gray", n))}${s.hint ? ` ${e("dim", `(${s.hint ?? "disabled"})`)}` : ""}`;
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", H)} ${it2(u, (n) => e("dim", n))}`;
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, i = `${M(this.state)} `, u = `${yt(this.state)} `, n = W(t.output, t.message, u, i), o = `${s ? `${e("gray", $)}
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 c2 = s ? `${e("gray", $)} ` : "", a = W(t.output, r(this.options[this.cursor], "selected"), c2);
1525
- return `${o}${a}`;
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 c2 = s ? `${e("gray", $)} ` : "", a = W(t.output, r(this.options[this.cursor], "cancelled"), c2);
1529
- return `${o}${a}${s ? `
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 c2 = s ? `${e("cyan", $)} ` : "", a = s ? e("cyan", E2) : "", l = o.split(`
1534
- `).length, d2 = s ? 2 : 1;
1535
- return `${o}${c2}${Y2({ output: t.output, cursor: this.cursor, options: this.options, maxItems: t.maxItems, columnPadding: c2.length, rowPadding: l + d2, style: (y, p2) => r(y, y.disabled ? "disabled" : p2 ? "active" : "inactive") }).join(`
1536
- ${c2}`)}
1537
- ${a}
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 jt = `${e("gray", $)} `;
1544
- var Re = (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() {
1545
- const r = t?.withGuide ?? h.withGuide, s = `${`${r ? `${e("gray", $)}
1546
- ` : ""}${M(this.state)} `}${t.message}
1547
- `, i = t.placeholder ? e("inverse", t.placeholder[0]) + e("dim", t.placeholder.slice(1)) : e(["inverse", "hidden"], "_"), u = this.userInput ? this.userInputWithCursor : i, n = this.value ?? "";
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 o = this.error ? ` ${e("yellow", this.error)}` : "", c2 = r ? `${e("yellow", $)} ` : "", a = r ? e("yellow", E2) : "";
1594
+ const a = this.error ? ` ${e("yellow", this.error)}` : "", c = i ? `${e("yellow", $)} ` : "", o = i ? e("yellow", x2) : "";
1551
1595
  return `${s.trim()}
1552
- ${c2}${u}
1553
- ${a}${o}
1596
+ ${c}${u}
1597
+ ${o}${a}
1554
1598
  `;
1555
1599
  }
1556
1600
  case "submit": {
1557
- const o = n ? ` ${e("dim", n)}` : "", c2 = r ? e("gray", $) : "";
1558
- return `${s}${c2}${o}`;
1601
+ const a = n ? ` ${e("dim", n)}` : "", c = i ? e("gray", $) : "";
1602
+ return `${s}${c}${a}`;
1559
1603
  }
1560
1604
  case "cancel": {
1561
- const o = n ? ` ${e(["strikethrough", "dim"], n)}` : "", c2 = r ? e("gray", $) : "";
1562
- return `${s}${c2}${o}${n.trim() ? `
1563
- ${c2}` : ""}`;
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 o = r ? `${e("cyan", $)} ` : "", c2 = r ? e("cyan", E2) : "";
1567
- return `${s}${o}${u}
1568
- ${c2}
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 { chmodSync, mkdirSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
1998
- import { readFile } from "fs/promises";
1999
- import { dirname } from "path";
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(x, startIndex = 0) {
3160
- if (x.aborted === true)
3210
+ function aborted(x3, startIndex = 0) {
3211
+ if (x3.aborted === true)
3161
3212
  return true;
3162
- for (let i = startIndex; i < x.issues.length; i++) {
3163
- if (x.issues[i]?.continue !== true) {
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(x, startIndex = 0) {
3170
- if (x.aborted === true)
3220
+ function explicitlyAborted(x3, startIndex = 0) {
3221
+ if (x3.aborted === true)
3171
3222
  return true;
3172
- for (let i = startIndex; i < x.issues.length; i++) {
3173
- if (x.issues[i]?.continue === false) {
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((x) => x);
4251
- const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length));
4252
- const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x);
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((x) => ` ${x}`)];
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, (c2) => c2 === "-" ? "+" : "/");
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 isObject5 = isObject2;
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 (!isObject5(input)) {
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 isObject5 = isObject2;
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 (!isObject5(input)) {
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(([, f]) => f.l && f.r).map(([k2]) => k2);
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((x) => x !== void 0)) : void 0;
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 d2 = def;
6315
- if (!d2._cachedInner)
6316
- d2._cachedInner = def.getter();
6317
- return d2._cachedInner;
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 f = { ...pm, ...this._map.get(schema) };
12353
- return Object.keys(f).length ? f : void 0;
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((m) => ({ contentMediaType: m }));
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((x, i) => process2(x, ctx, {
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((x, i) => process2(x, ctx, {
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(d2) {
14810
- return _default2(this, d2);
14860
+ default(d) {
14861
+ return _default2(this, d);
14811
14862
  },
14812
- prefault(d2) {
14813
- return prefault(this, d2);
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 c2 = inst._zod.bag;
15311
- inst.minDate = c2.minimum ? new Date(c2.minimum) : null;
15312
- inst.maxDate = c2.maximum ? new Date(c2.maximum) : null;
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/lib/credentials.ts
16521
- var CredentialsFileSchema = external_exports.object({
16522
- apiKey: external_exports.string().min(1),
16523
- gatewayUrl: external_exports.url(),
16524
- userId: external_exports.uuid(),
16525
- email: external_exports.email(),
16526
- savedAt: external_exports.iso.datetime()
16527
- });
16528
- function writeCredentials(creds) {
16529
- const payload = {
16530
- ...creds,
16531
- savedAt: (/* @__PURE__ */ new Date()).toISOString()
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 parsed = CredentialsFileSchema.parse(payload);
16534
- const dir = dirname(CREDENTIALS_FILE);
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 tmp = `${CREDENTIALS_FILE}.${process.pid}.tmp`;
16541
- writeFileSync(tmp, JSON.stringify(parsed, null, 2), { mode: 384 });
16542
- try {
16543
- chmodSync(tmp, 384);
16544
- } catch {
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
- async function readCredentials() {
16550
- let raw;
16551
- try {
16552
- raw = await readFile(CREDENTIALS_FILE, "utf8");
16553
- } catch (err) {
16554
- if (err.code === "ENOENT") return null;
16555
- throw err;
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
- let parsed;
16558
- try {
16559
- parsed = JSON.parse(raw);
16560
- } catch {
16561
- throw new Error(
16562
- `${CREDENTIALS_FILE} is not valid JSON. Run \`codevector logout\` and re-login.`
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 CredentialsFileSchema.parse(parsed);
16747
+ return out;
16566
16748
  }
16567
- function deleteCredentials() {
16568
- try {
16569
- rmSync(CREDENTIALS_FILE);
16570
- return true;
16571
- } catch (err) {
16572
- if (err.code === "ENOENT") return false;
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 credentialsFileModeOk() {
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
- const stats = statSync(CREDENTIALS_FILE);
16579
- const mode = stats.mode & 511;
16580
- return mode === 384;
16782
+ writeFileSync2(path, `${existing}${prefix}${trimmed}
16783
+ `);
16784
+ return true;
16581
16785
  } catch {
16582
16786
  return false;
16583
16787
  }
16584
16788
  }
16585
- function maskApiKey(key) {
16586
- if (key.length <= 12) return "********";
16587
- return `${key.slice(0, 5)}\u2026${key.slice(-4)}`;
16588
- }
16589
-
16590
- // src/lib/prompt.ts
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 value;
16796
+ return false;
16597
16797
  }
16598
- async function promptText(message, placeholder) {
16599
- return unwrap(
16600
- await Re({
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 = writeCredentials({
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
- run() {
16671
- const removed = deleteCredentials();
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("No credentials were found. Nothing to do.");
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 homedir6 } from "os";
17543
+ import { homedir as homedir5 } from "os";
16757
17544
 
16758
17545
  // src/lib/hooks.ts
16759
- import { chmodSync as chmodSync2, copyFileSync, existsSync, mkdirSync as mkdirSync2 } from "fs";
16760
- import { dirname as dirname2, join as join2 } from "path";
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 = dirname2(fileURLToPath(import.meta.url));
17550
+ const here = dirname4(fileURLToPath(import.meta.url));
16764
17551
  const candidates = [
16765
- join2(here, "hooks", "acceptance.sh"),
17552
+ join5(here, "hooks", "acceptance.sh"),
16766
17553
  // production — dist/hooks/…
16767
- join2(here, "..", "hooks", "acceptance.sh")
17554
+ join5(here, "..", "hooks", "acceptance.sh")
16768
17555
  // dev — src/hooks/…
16769
17556
  ];
16770
17557
  for (const candidate of candidates) {
16771
- if (existsSync(candidate)) return candidate;
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
- mkdirSync2(HOOKS_DIR, { recursive: true, mode: 448 });
17565
+ mkdirSync4(HOOKS_DIR, { recursive: true, mode: 448 });
16779
17566
  copyFileSync(bundledHookSource(), ACCEPTANCE_HOOK_FILE);
16780
17567
  try {
16781
- chmodSync2(ACCEPTANCE_HOOK_FILE, 493);
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 existsSync2, readFileSync } from "fs";
16790
- import { join as join3 } from "path";
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 = join3(cwd, ".codevector.json");
16830
- if (!existsSync2(path)) return null;
17616
+ const path = join6(cwd, ".codevector.json");
17617
+ if (!existsSync5(path)) return null;
16831
17618
  try {
16832
- const parsed = JSON.parse(readFileSync(path, "utf8"));
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 existsSync3,
17034
- mkdirSync as mkdirSync4,
17035
- readFileSync as readFileSync3,
17645
+ existsSync as existsSync6,
17646
+ mkdirSync as mkdirSync5,
17647
+ readFileSync as readFileSync7,
17036
17648
  renameSync as renameSync3,
17037
- statSync as statSync3,
17038
- writeFileSync as writeFileSync3
17649
+ statSync as statSync4,
17650
+ writeFileSync as writeFileSync5
17039
17651
  } from "fs";
17040
- import { dirname as dirname4, join as join5 } from "path";
17041
- import { homedir as homedir3 } from "os";
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 c2 = str[i];
17099
- if (c2 === "\n")
17710
+ let c = str[i];
17711
+ if (c === "\n")
17100
17712
  return i;
17101
- if (c2 === "\r" && str[i + 1] === "\n")
17713
+ if (c === "\r" && str[i + 1] === "\n")
17102
17714
  return i + 1;
17103
- if (c2 < " " && c2 !== " " || c2 === "\x7F") {
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 c2;
17725
+ let c;
17114
17726
  while (1) {
17115
- while ((c2 = str[ptr]) === " " || c2 === " " || !banNewLines && (c2 === "\n" || c2 === "\r" && str[ptr + 1] === "\n"))
17727
+ while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
17116
17728
  ptr++;
17117
- if (banComments || c2 !== "#")
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 c2 = str[i];
17130
- if (c2 === "#") {
17741
+ let c = str[i];
17742
+ if (c === "#") {
17131
17743
  i = indexOfNewline(str, i);
17132
- } else if (c2 === sep) {
17744
+ } else if (c === sep) {
17133
17745
  return i + 1;
17134
- } else if (c2 === end || banNewLines && (c2 === "\n" || c2 === "\r" && str[i + 1] === "\n")) {
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 c2 = str[ptr++];
17285
- if (c2 === "\n" || c2 === "\r" && str[ptr] === "\n") {
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 (c2 < " " && c2 !== " " || c2 === "\x7F") {
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 (c2 === "x" || c2 === "u" || c2 === "U") {
17301
- let code = str.slice(ptr, ptr += c2 === "x" ? 2 : c2 === "u" ? 4 : 8);
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 && (c2 === "\n" || c2 === " " || c2 === " " || c2 === "\r")) {
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 (c2 in ESC_MAP) {
17326
- parsed += ESC_MAP[c2];
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 && c2 === "\\") {
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 c2 = str[ptr];
17411
- if (c2 === "[" || c2 === "{") {
17412
- let [value, endPtr2] = c2 === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
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 (c2 === '"' || c2 === "'") {
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 c2 = str[ptr = ++dot];
17474
- if (c2 !== " " && c2 !== " ") {
17475
- if (c2 === '"' || c2 === "'") {
17476
- if (c2 === str[ptr + 1] && c2 === str[ptr + 2]) {
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 c2;
18144
+ let c;
17533
18145
  ptr++;
17534
- while ((c2 = str[ptr++]) !== "}" && c2) {
17535
- if (c2 === ",") {
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 (c2 === "#")
18152
+ } else if (c === "#")
17541
18153
  ptr = skipComment(str, ptr);
17542
- else if (c2 !== " " && c2 !== " " && c2 !== "\n" && c2 !== "\r") {
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 (!c2) {
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 c2;
18195
+ let c;
17584
18196
  ptr++;
17585
- while ((c2 = str[ptr++]) !== "]" && c2) {
17586
- if (c2 === ",") {
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 (c2 === "#")
18203
+ } else if (c === "#")
17592
18204
  ptr = skipComment(str, ptr);
17593
- else if (c2 !== " " && c2 !== " " && c2 !== "\n" && c2 !== "\r") {
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 (!c2) {
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 m = meta3;
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
- m = (state = m[k2]).c;
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
- m = m[l].c;
18237
+ m2 = m2[l].c;
17626
18238
  }
17627
18239
  }
17628
18240
  k2 = key[i];
17629
- if ((hasOwn = Object.hasOwn(t, k2)) && m[k2]?.t === 0 && m[k2]?.d) {
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(m, k2, { enumerable: true, configurable: true, writable: true });
18247
+ Object.defineProperty(m2, k2, { enumerable: true, configurable: true, writable: true });
17636
18248
  }
17637
- m[k2] = {
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 = m[k2];
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 m = meta3;
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
- m = p2[2];
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
- m,
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 ENV_VAR_NAME = "CODEVECTOR_GATEWAY_KEY";
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
- if (scope !== "user") {
17884
- return {
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 = isObject3(merged.model_providers) ? { ...merged.model_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: ENV_VAR_NAME,
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((m) => m.slug === model.slug);
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
- const envPath = qwenEnvPath(scope);
18269
- mergeEnvFile(envPath, { [ENV_VAR_NAME3]: apiKey });
18270
- notes.push(`API key written to ${envPath} (chmod 600).`);
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(".qwen/")) {
18274
- notes.push("Added `.qwen/` to .gitignore.");
18528
+ if (ensureGitignored(".codex/config.toml")) {
18529
+ notes.push("Added `.codex/config.toml` to .gitignore.");
18275
18530
  }
18276
18531
  }
18277
18532
  return {
18278
- tool: "qwen-code",
18533
+ tool: "codex",
18279
18534
  status: "configured",
18280
18535
  path,
18281
18536
  scope,
18282
- notes: notes.length > 0 ? notes.join(" ") : void 0
18537
+ notes: notes.join(" ")
18283
18538
  };
18284
18539
  };
18285
- function qwenSettingsPath(scope) {
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 join8(homedir5(), ".qwen");
18543
+ return join7(homedir4(), ".codex", "config.toml");
18295
18544
  case "project":
18296
18545
  case "local":
18297
- return join8(userCwd(), ".qwen");
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 trimRightSlash5(url2) {
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", "qwen-code", "codex"];
18312
- var SCOPES = ["local", "project", "user"];
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, qwen-code, codex, all."
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), project, user.",
18327
- valueHint: "local|project|user"
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 creds = await readCredentials();
18336
- if (!creds) {
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((m) => ({
18374
- slug: m.slug,
18375
- displayName: m.displayName,
18376
- contextWindow: m.contextWindow,
18377
- maxOutputTokens: m.maxOutputTokens,
18378
- maxInputTokens: m.maxInputTokens,
18379
- inputPricePerMtok: m.inputPricePerMtok,
18380
- cachedInputPricePerMtok: m.cachedInputPricePerMtok,
18381
- cacheWritePricePerMtok: m.cacheWritePricePerMtok,
18382
- reasoningPricePerMtok: m.reasoningPricePerMtok,
18383
- outputPricePerMtok: m.outputPricePerMtok,
18384
- supportsReasoning: m.supportsReasoning,
18385
- supportsAttachment: m.supportsAttachment,
18386
- supportsToolCall: m.supportsToolCall,
18387
- supportsTemperature: m.supportsTemperature,
18388
- inputModalities: m.inputModalities,
18389
- outputModalities: m.outputModalities,
18390
- releaseDate: m.releaseDate,
18391
- family: m.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 Ee({
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 scope === "user" ? relativizeHomeAndCwd(codexConfigPath()) : `${relativizeHomeAndCwd(codexConfigPath())} (codex is user-scope only)`;
18784
+ return relativizeHomeAndCwd(codexConfigPath(scope));
18484
18785
  }
18485
18786
  }
18486
18787
  function relativizeHomeAndCwd(absolutePath) {
18487
- const home = homedir6();
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((m) => m.kind === "chat").map((m) => ({
18510
- slug: m.slug,
18511
- providerKind: m.providerKind,
18512
- displayName: m.displayName,
18513
- contextWindow: m.contextWindow,
18514
- maxOutputTokens: m.maxOutputTokens,
18515
- maxInputTokens: m.maxInputTokens,
18516
- inputPricePerMtok: m.inputPricePerMtok,
18517
- cachedInputPricePerMtok: m.cachedInputPricePerMtok,
18518
- cacheWritePricePerMtok: m.cacheWritePricePerMtok,
18519
- reasoningPricePerMtok: m.reasoningPricePerMtok,
18520
- outputPricePerMtok: m.outputPricePerMtok,
18521
- supportsReasoning: m.supportsReasoning,
18522
- supportsAttachment: m.supportsAttachment,
18523
- supportsToolCall: m.supportsToolCall,
18524
- supportsTemperature: m.supportsTemperature,
18525
- inputModalities: m.inputModalities,
18526
- outputModalities: m.outputModalities,
18527
- releaseDate: m.releaseDate,
18528
- family: m.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 Ee({
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((m) => ({
18556
- value: m.slug,
18557
- label: m.slug,
18558
- hint: `${m.displayName}${m.providerKind ? ` \xB7 ${m.providerKind}` : ""}`
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((m) => m.slug === picked);
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 readFileSync7, statSync as statSync4 } from "fs";
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 = statSync4(ACCEPTANCE_HOOK_FILE).mode & 511;
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((c2) => c2.level === "fail")) {
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(readFileSync7(path, "utf8"));
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((c2) => {
18672
- const icon = c2.level === "ok" ? "\u2713" : c2.level === "warn" ? "!" : "\u2717";
18673
- const detail = c2.detail ? ` \u2014 ${c2.detail}` : "";
18674
- return `${icon} ${c2.label}${detail}`;
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 c2 of checks) {
18679
- if (c2.level === "fail") R2.error(c2.label);
18680
- else if (c2.level === "warn") R2.warn(c2.label);
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 writeFileSync7 } from "fs";
18986
+ import { existsSync as existsSync8, writeFileSync as writeFileSync6 } from "fs";
18686
18987
  import { execFileSync as execFileSync2 } from "child_process";
18687
- import { join as join9 } from "path";
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 = join9(cwd, ".codevector.json");
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 projectName = args.project ?? deriveProjectName(cwd);
18715
- if (!projectName) {
18716
- throw new Error(
18717
- "Could not derive projectName from git remote. Pass --project <name> explicitly."
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 ticketPattern = args["ticket-pattern"] ?? DEFAULT_TICKET_PATTERN2;
18721
- writeFileSync7(target, `${JSON.stringify({ projectName, ticketPattern }, null, 2)}
18722
- `, {
18723
- mode: 420
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
- R2.success(`Wrote ${target}`);
18726
- R2.info(`projectName: ${projectName}`);
18727
- R2.info(`ticketPattern: ${ticketPattern}`);
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
- function deriveProjectName(cwd) {
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 out = execFileSync2("git", ["remote", "get-url", "origin"], {
18733
- encoding: "utf8",
18734
- cwd,
18735
- stdio: ["ignore", "pipe", "ignore"],
18736
- timeout: 2e3
18737
- }).trim();
18738
- return out ? repoSlugFromRemote(out) : null;
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 null;
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
- // src/lib/table.ts
18745
- function renderTable(headers, rows) {
18746
- const widths = headers.map(
18747
- (h2, i) => Math.max(h2.length, ...rows.map((row) => (row[i] ?? "").length))
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/sync-models.ts
18757
- var SCOPES2 = ["local", "project", "user"];
18758
- var modelsSyncCommand = defineCommand({
19504
+ // src/commands/status.ts
19505
+ var statusCommand = defineCommand({
18759
19506
  meta: {
18760
- name: "sync",
18761
- description: "Refresh the model list (with names, costs, context limits) in an existing opencode.json."
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({ args }) {
19510
+ async run() {
18776
19511
  const creds = await readCredentials();
18777
19512
  if (!creds) {
18778
- throw new Error("Not signed in. Run `codevector auth login` first.");
19513
+ R2.warn("Not signed in. Run `codevector auth login` to get started.");
19514
+ process.exitCode = 1;
19515
+ return;
18779
19516
  }
18780
- ge("Sync models");
18781
- const target = await resolveTarget(args);
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("Loading reachable models\u2026");
18785
- let reachable;
19526
+ s.start("Reaching gateway\u2026");
18786
19527
  try {
18787
19528
  const res = await call(parseResponse(client.models.$get()));
18788
- reachable = res.data.filter((m) => m.kind === "chat").map((m) => ({
18789
- slug: m.slug,
18790
- displayName: m.displayName,
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("Could not load models");
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
- async function resolveTarget(args) {
18827
- if (args.path) return args.path;
18828
- if (args.scope) {
18829
- if (!isScope2(args.scope)) {
18830
- throw new Error(`Invalid --scope "${args.scope}". Use one of: ${SCOPES2.join(", ")}.`);
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
- return opencodeSettingsPath(args.scope);
19585
+ if (collected.length === 0) continue;
19586
+ runs.push({ timestamp: ts, dir, entries: collected });
18833
19587
  }
18834
- const picked = unwrap(
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 isScope2(value) {
18848
- return SCOPES2.includes(value);
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/models.ts
18852
- var modelsListCommand = defineCommand({
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: "list",
18855
- description: "List models you can reach through the gateway."
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
- kind: {
19698
+ timestamp: {
18859
19699
  type: "string",
18860
- description: "Filter by kind: chat or embedding.",
18861
- valueHint: "chat|embedding"
19700
+ description: "Specific backup timestamp (directory name under ~/.codevector/backups/)."
18862
19701
  },
18863
- json: {
19702
+ latest: {
18864
19703
  type: "boolean",
18865
- description: "Emit raw JSON (for scripting)."
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
- const creds = await readCredentials();
18870
- if (!creds) {
18871
- R2.warn("Not signed in. Run `codevector auth login` to get started.");
18872
- process.exitCode = 1;
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
- const kindFilter = args.kind;
18876
- if (kindFilter && kindFilter !== "chat" && kindFilter !== "embedding") {
18877
- throw new Error(`Invalid --kind "${kindFilter}". Use "chat" or "embedding".`);
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
- const client = gatewayClient(creds.gatewayUrl, creds.apiKey, 1e4);
18880
- const s = args.json ? null : ft();
18881
- s?.start("Loading models\u2026");
18882
- try {
18883
- const res = await call(parseResponse(client.models.$get()));
18884
- const filtered = kindFilter ? res.data.filter((m) => m.kind === kindFilter) : res.data;
18885
- s?.stop(`${filtered.length} model${filtered.length === 1 ? "" : "s"} reachable`);
18886
- if (args.json) {
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
- if (filtered.length === 0) {
18892
- R2.info(
18893
- kindFilter ? `No ${kindFilter} models available. Ask your gateway admin to grant access.` : "No models available. Ask your gateway admin to grant access."
18894
- );
18895
- return;
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
- var modelsCommand = defineCommand({
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: "models",
18928
- description: "List and manage models."
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
- list: modelsListCommand,
18932
- sync: modelsSyncCommand
19831
+ configure: systemConfigureCommand,
19832
+ restore: systemRestoreCommand
18933
19833
  }
18934
19834
  });
18935
19835
 
18936
- // src/commands/status.ts
18937
- var statusCommand = defineCommand({
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: "status",
18940
- description: "Show current login + gateway reachability."
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
- async run() {
18943
- const creds = await readCredentials();
18944
- if (!creds) {
18945
- R2.warn("Not signed in. Run `codevector auth login` to get started.");
18946
- process.exitCode = 1;
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
- Se(
18950
- `Signed in as ${creds.email}
18951
- Gateway: ${creds.gatewayUrl}
18952
- API key: ${maskApiKey(creds.apiKey)}
18953
- Last saved: ${creds.savedAt}`,
18954
- "Credentials"
18955
- );
18956
- const client = gatewayClient(creds.gatewayUrl, creds.apiKey, 1e4);
18957
- const s = ft();
18958
- s.start("Reaching gateway\u2026");
18959
- try {
18960
- const res = await call(parseResponse(client.models.$get()));
18961
- s.stop(
18962
- 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.`
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