@controlvector/cv-agent 1.10.0 → 1.11.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/bundle.cjs CHANGED
@@ -6,9 +6,16 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
9
12
  var __commonJS = (cb, mod) => function __require() {
10
13
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
14
  };
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
12
19
  var __copyProps = (to, from, except, desc) => {
13
20
  if (from && typeof from === "object" || typeof from === "function") {
14
21
  for (let key of __getOwnPropNames(from))
@@ -3019,98 +3026,7 @@ var require_commander = __commonJS({
3019
3026
  }
3020
3027
  });
3021
3028
 
3022
- // node_modules/commander/esm.mjs
3023
- var import_index = __toESM(require_commander(), 1);
3024
- var {
3025
- program,
3026
- createCommand,
3027
- createArgument,
3028
- createOption,
3029
- CommanderError,
3030
- InvalidArgumentError,
3031
- InvalidOptionArgumentError,
3032
- // deprecated old name
3033
- Command,
3034
- Argument,
3035
- Option,
3036
- Help
3037
- } = import_index.default;
3038
-
3039
- // src/commands/setup.ts
3040
- var import_node_child_process = require("node:child_process");
3041
- var import_node_fs = require("node:fs");
3042
- var import_node_path = require("node:path");
3043
- var import_node_os2 = require("node:os");
3044
-
3045
3029
  // node_modules/chalk/source/vendor/ansi-styles/index.js
3046
- var ANSI_BACKGROUND_OFFSET = 10;
3047
- var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
3048
- var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
3049
- var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
3050
- var styles = {
3051
- modifier: {
3052
- reset: [0, 0],
3053
- // 21 isn't widely supported and 22 does the same thing
3054
- bold: [1, 22],
3055
- dim: [2, 22],
3056
- italic: [3, 23],
3057
- underline: [4, 24],
3058
- overline: [53, 55],
3059
- inverse: [7, 27],
3060
- hidden: [8, 28],
3061
- strikethrough: [9, 29]
3062
- },
3063
- color: {
3064
- black: [30, 39],
3065
- red: [31, 39],
3066
- green: [32, 39],
3067
- yellow: [33, 39],
3068
- blue: [34, 39],
3069
- magenta: [35, 39],
3070
- cyan: [36, 39],
3071
- white: [37, 39],
3072
- // Bright color
3073
- blackBright: [90, 39],
3074
- gray: [90, 39],
3075
- // Alias of `blackBright`
3076
- grey: [90, 39],
3077
- // Alias of `blackBright`
3078
- redBright: [91, 39],
3079
- greenBright: [92, 39],
3080
- yellowBright: [93, 39],
3081
- blueBright: [94, 39],
3082
- magentaBright: [95, 39],
3083
- cyanBright: [96, 39],
3084
- whiteBright: [97, 39]
3085
- },
3086
- bgColor: {
3087
- bgBlack: [40, 49],
3088
- bgRed: [41, 49],
3089
- bgGreen: [42, 49],
3090
- bgYellow: [43, 49],
3091
- bgBlue: [44, 49],
3092
- bgMagenta: [45, 49],
3093
- bgCyan: [46, 49],
3094
- bgWhite: [47, 49],
3095
- // Bright color
3096
- bgBlackBright: [100, 49],
3097
- bgGray: [100, 49],
3098
- // Alias of `bgBlackBright`
3099
- bgGrey: [100, 49],
3100
- // Alias of `bgBlackBright`
3101
- bgRedBright: [101, 49],
3102
- bgGreenBright: [102, 49],
3103
- bgYellowBright: [103, 49],
3104
- bgBlueBright: [104, 49],
3105
- bgMagentaBright: [105, 49],
3106
- bgCyanBright: [106, 49],
3107
- bgWhiteBright: [107, 49]
3108
- }
3109
- };
3110
- var modifierNames = Object.keys(styles.modifier);
3111
- var foregroundColorNames = Object.keys(styles.color);
3112
- var backgroundColorNames = Object.keys(styles.bgColor);
3113
- var colorNames = [...foregroundColorNames, ...backgroundColorNames];
3114
3030
  function assembleStyles() {
3115
3031
  const codes = /* @__PURE__ */ new Map();
3116
3032
  for (const [groupName, group] of Object.entries(styles)) {
@@ -3225,26 +3141,89 @@ function assembleStyles() {
3225
3141
  });
3226
3142
  return styles;
3227
3143
  }
3228
- var ansiStyles = assembleStyles();
3229
- var ansi_styles_default = ansiStyles;
3144
+ var ANSI_BACKGROUND_OFFSET, wrapAnsi16, wrapAnsi256, wrapAnsi16m, styles, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default;
3145
+ var init_ansi_styles = __esm({
3146
+ "node_modules/chalk/source/vendor/ansi-styles/index.js"() {
3147
+ ANSI_BACKGROUND_OFFSET = 10;
3148
+ wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
3149
+ wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
3150
+ wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
3151
+ styles = {
3152
+ modifier: {
3153
+ reset: [0, 0],
3154
+ // 21 isn't widely supported and 22 does the same thing
3155
+ bold: [1, 22],
3156
+ dim: [2, 22],
3157
+ italic: [3, 23],
3158
+ underline: [4, 24],
3159
+ overline: [53, 55],
3160
+ inverse: [7, 27],
3161
+ hidden: [8, 28],
3162
+ strikethrough: [9, 29]
3163
+ },
3164
+ color: {
3165
+ black: [30, 39],
3166
+ red: [31, 39],
3167
+ green: [32, 39],
3168
+ yellow: [33, 39],
3169
+ blue: [34, 39],
3170
+ magenta: [35, 39],
3171
+ cyan: [36, 39],
3172
+ white: [37, 39],
3173
+ // Bright color
3174
+ blackBright: [90, 39],
3175
+ gray: [90, 39],
3176
+ // Alias of `blackBright`
3177
+ grey: [90, 39],
3178
+ // Alias of `blackBright`
3179
+ redBright: [91, 39],
3180
+ greenBright: [92, 39],
3181
+ yellowBright: [93, 39],
3182
+ blueBright: [94, 39],
3183
+ magentaBright: [95, 39],
3184
+ cyanBright: [96, 39],
3185
+ whiteBright: [97, 39]
3186
+ },
3187
+ bgColor: {
3188
+ bgBlack: [40, 49],
3189
+ bgRed: [41, 49],
3190
+ bgGreen: [42, 49],
3191
+ bgYellow: [43, 49],
3192
+ bgBlue: [44, 49],
3193
+ bgMagenta: [45, 49],
3194
+ bgCyan: [46, 49],
3195
+ bgWhite: [47, 49],
3196
+ // Bright color
3197
+ bgBlackBright: [100, 49],
3198
+ bgGray: [100, 49],
3199
+ // Alias of `bgBlackBright`
3200
+ bgGrey: [100, 49],
3201
+ // Alias of `bgBlackBright`
3202
+ bgRedBright: [101, 49],
3203
+ bgGreenBright: [102, 49],
3204
+ bgYellowBright: [103, 49],
3205
+ bgBlueBright: [104, 49],
3206
+ bgMagentaBright: [105, 49],
3207
+ bgCyanBright: [106, 49],
3208
+ bgWhiteBright: [107, 49]
3209
+ }
3210
+ };
3211
+ modifierNames = Object.keys(styles.modifier);
3212
+ foregroundColorNames = Object.keys(styles.color);
3213
+ backgroundColorNames = Object.keys(styles.bgColor);
3214
+ colorNames = [...foregroundColorNames, ...backgroundColorNames];
3215
+ ansiStyles = assembleStyles();
3216
+ ansi_styles_default = ansiStyles;
3217
+ }
3218
+ });
3230
3219
 
3231
3220
  // node_modules/chalk/source/vendor/supports-color/index.js
3232
- var import_node_process = __toESM(require("node:process"), 1);
3233
- var import_node_os = __toESM(require("node:os"), 1);
3234
- var import_node_tty = __toESM(require("node:tty"), 1);
3235
3221
  function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : import_node_process.default.argv) {
3236
3222
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
3237
3223
  const position = argv.indexOf(prefix + flag);
3238
3224
  const terminatorPosition = argv.indexOf("--");
3239
3225
  return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
3240
3226
  }
3241
- var { env } = import_node_process.default;
3242
- var flagForceColor;
3243
- if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
3244
- flagForceColor = 0;
3245
- } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
3246
- flagForceColor = 1;
3247
- }
3248
3227
  function envForceColor() {
3249
3228
  if ("FORCE_COLOR" in env) {
3250
3229
  if (env.FORCE_COLOR === "true") {
@@ -3354,11 +3333,25 @@ function createSupportsColor(stream, options = {}) {
3354
3333
  });
3355
3334
  return translateLevel(level);
3356
3335
  }
3357
- var supportsColor = {
3358
- stdout: createSupportsColor({ isTTY: import_node_tty.default.isatty(1) }),
3359
- stderr: createSupportsColor({ isTTY: import_node_tty.default.isatty(2) })
3360
- };
3361
- var supports_color_default = supportsColor;
3336
+ var import_node_process, import_node_os, import_node_tty, env, flagForceColor, supportsColor, supports_color_default;
3337
+ var init_supports_color = __esm({
3338
+ "node_modules/chalk/source/vendor/supports-color/index.js"() {
3339
+ import_node_process = __toESM(require("node:process"), 1);
3340
+ import_node_os = __toESM(require("node:os"), 1);
3341
+ import_node_tty = __toESM(require("node:tty"), 1);
3342
+ ({ env } = import_node_process.default);
3343
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
3344
+ flagForceColor = 0;
3345
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
3346
+ flagForceColor = 1;
3347
+ }
3348
+ supportsColor = {
3349
+ stdout: createSupportsColor({ isTTY: import_node_tty.default.isatty(1) }),
3350
+ stderr: createSupportsColor({ isTTY: import_node_tty.default.isatty(2) })
3351
+ };
3352
+ supports_color_default = supportsColor;
3353
+ }
3354
+ });
3362
3355
 
3363
3356
  // node_modules/chalk/source/utilities.js
3364
3357
  function stringReplaceAll(string, substring, replacer) {
@@ -3389,153 +3382,389 @@ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
3389
3382
  returnValue += string.slice(endIndex);
3390
3383
  return returnValue;
3391
3384
  }
3385
+ var init_utilities = __esm({
3386
+ "node_modules/chalk/source/utilities.js"() {
3387
+ }
3388
+ });
3392
3389
 
3393
3390
  // node_modules/chalk/source/index.js
3394
- var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
3395
- var GENERATOR = Symbol("GENERATOR");
3396
- var STYLER = Symbol("STYLER");
3397
- var IS_EMPTY = Symbol("IS_EMPTY");
3398
- var levelMapping = [
3399
- "ansi",
3400
- "ansi",
3401
- "ansi256",
3402
- "ansi16m"
3403
- ];
3404
- var styles2 = /* @__PURE__ */ Object.create(null);
3405
- var applyOptions = (object, options = {}) => {
3406
- if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
3407
- throw new Error("The `level` option should be an integer from 0 to 3");
3408
- }
3409
- const colorLevel = stdoutColor ? stdoutColor.level : 0;
3410
- object.level = options.level === void 0 ? colorLevel : options.level;
3411
- };
3412
- var chalkFactory = (options) => {
3413
- const chalk2 = (...strings) => strings.join(" ");
3414
- applyOptions(chalk2, options);
3415
- Object.setPrototypeOf(chalk2, createChalk.prototype);
3416
- return chalk2;
3417
- };
3418
3391
  function createChalk(options) {
3419
3392
  return chalkFactory(options);
3420
3393
  }
3421
- Object.setPrototypeOf(createChalk.prototype, Function.prototype);
3422
- for (const [styleName, style] of Object.entries(ansi_styles_default)) {
3423
- styles2[styleName] = {
3424
- get() {
3425
- const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
3426
- Object.defineProperty(this, styleName, { value: builder });
3427
- return builder;
3394
+ var stdoutColor, stderrColor, GENERATOR, STYLER, IS_EMPTY, levelMapping, styles2, applyOptions, chalkFactory, getModelAnsi, usedModels, proto, createStyler, createBuilder, applyStyle, chalk, chalkStderr, source_default;
3395
+ var init_source = __esm({
3396
+ "node_modules/chalk/source/index.js"() {
3397
+ init_ansi_styles();
3398
+ init_supports_color();
3399
+ init_utilities();
3400
+ ({ stdout: stdoutColor, stderr: stderrColor } = supports_color_default);
3401
+ GENERATOR = Symbol("GENERATOR");
3402
+ STYLER = Symbol("STYLER");
3403
+ IS_EMPTY = Symbol("IS_EMPTY");
3404
+ levelMapping = [
3405
+ "ansi",
3406
+ "ansi",
3407
+ "ansi256",
3408
+ "ansi16m"
3409
+ ];
3410
+ styles2 = /* @__PURE__ */ Object.create(null);
3411
+ applyOptions = (object, options = {}) => {
3412
+ if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
3413
+ throw new Error("The `level` option should be an integer from 0 to 3");
3414
+ }
3415
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
3416
+ object.level = options.level === void 0 ? colorLevel : options.level;
3417
+ };
3418
+ chalkFactory = (options) => {
3419
+ const chalk2 = (...strings) => strings.join(" ");
3420
+ applyOptions(chalk2, options);
3421
+ Object.setPrototypeOf(chalk2, createChalk.prototype);
3422
+ return chalk2;
3423
+ };
3424
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
3425
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
3426
+ styles2[styleName] = {
3427
+ get() {
3428
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
3429
+ Object.defineProperty(this, styleName, { value: builder });
3430
+ return builder;
3431
+ }
3432
+ };
3428
3433
  }
3429
- };
3430
- }
3431
- styles2.visible = {
3432
- get() {
3433
- const builder = createBuilder(this, this[STYLER], true);
3434
- Object.defineProperty(this, "visible", { value: builder });
3435
- return builder;
3434
+ styles2.visible = {
3435
+ get() {
3436
+ const builder = createBuilder(this, this[STYLER], true);
3437
+ Object.defineProperty(this, "visible", { value: builder });
3438
+ return builder;
3439
+ }
3440
+ };
3441
+ getModelAnsi = (model, level, type, ...arguments_) => {
3442
+ if (model === "rgb") {
3443
+ if (level === "ansi16m") {
3444
+ return ansi_styles_default[type].ansi16m(...arguments_);
3445
+ }
3446
+ if (level === "ansi256") {
3447
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
3448
+ }
3449
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
3450
+ }
3451
+ if (model === "hex") {
3452
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
3453
+ }
3454
+ return ansi_styles_default[type][model](...arguments_);
3455
+ };
3456
+ usedModels = ["rgb", "hex", "ansi256"];
3457
+ for (const model of usedModels) {
3458
+ styles2[model] = {
3459
+ get() {
3460
+ const { level } = this;
3461
+ return function(...arguments_) {
3462
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
3463
+ return createBuilder(this, styler, this[IS_EMPTY]);
3464
+ };
3465
+ }
3466
+ };
3467
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
3468
+ styles2[bgModel] = {
3469
+ get() {
3470
+ const { level } = this;
3471
+ return function(...arguments_) {
3472
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
3473
+ return createBuilder(this, styler, this[IS_EMPTY]);
3474
+ };
3475
+ }
3476
+ };
3477
+ }
3478
+ proto = Object.defineProperties(() => {
3479
+ }, {
3480
+ ...styles2,
3481
+ level: {
3482
+ enumerable: true,
3483
+ get() {
3484
+ return this[GENERATOR].level;
3485
+ },
3486
+ set(level) {
3487
+ this[GENERATOR].level = level;
3488
+ }
3489
+ }
3490
+ });
3491
+ createStyler = (open, close, parent) => {
3492
+ let openAll;
3493
+ let closeAll;
3494
+ if (parent === void 0) {
3495
+ openAll = open;
3496
+ closeAll = close;
3497
+ } else {
3498
+ openAll = parent.openAll + open;
3499
+ closeAll = close + parent.closeAll;
3500
+ }
3501
+ return {
3502
+ open,
3503
+ close,
3504
+ openAll,
3505
+ closeAll,
3506
+ parent
3507
+ };
3508
+ };
3509
+ createBuilder = (self, _styler, _isEmpty) => {
3510
+ const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
3511
+ Object.setPrototypeOf(builder, proto);
3512
+ builder[GENERATOR] = self;
3513
+ builder[STYLER] = _styler;
3514
+ builder[IS_EMPTY] = _isEmpty;
3515
+ return builder;
3516
+ };
3517
+ applyStyle = (self, string) => {
3518
+ if (self.level <= 0 || !string) {
3519
+ return self[IS_EMPTY] ? "" : string;
3520
+ }
3521
+ let styler = self[STYLER];
3522
+ if (styler === void 0) {
3523
+ return string;
3524
+ }
3525
+ const { openAll, closeAll } = styler;
3526
+ if (string.includes("\x1B")) {
3527
+ while (styler !== void 0) {
3528
+ string = stringReplaceAll(string, styler.close, styler.open);
3529
+ styler = styler.parent;
3530
+ }
3531
+ }
3532
+ const lfIndex = string.indexOf("\n");
3533
+ if (lfIndex !== -1) {
3534
+ string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
3535
+ }
3536
+ return openAll + string + closeAll;
3537
+ };
3538
+ Object.defineProperties(createChalk.prototype, styles2);
3539
+ chalk = createChalk();
3540
+ chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
3541
+ source_default = chalk;
3436
3542
  }
3437
- };
3438
- var getModelAnsi = (model, level, type, ...arguments_) => {
3439
- if (model === "rgb") {
3440
- if (level === "ansi16m") {
3441
- return ansi_styles_default[type].ansi16m(...arguments_);
3543
+ });
3544
+
3545
+ // src/utils/org-resolver.ts
3546
+ var org_resolver_exports = {};
3547
+ __export(org_resolver_exports, {
3548
+ confirmAutoMatch: () => confirmAutoMatch,
3549
+ parseMultiOrgError: () => parseMultiOrgError,
3550
+ persistOrg: () => persistOrg,
3551
+ pickOrg: () => pickOrg,
3552
+ promptPersistScope: () => promptPersistScope,
3553
+ resolveOrg: () => resolveOrg,
3554
+ resolveToUUID: () => resolveToUUID
3555
+ });
3556
+ function resolveOrg(opts) {
3557
+ if (opts.cliFlag?.trim()) {
3558
+ return { value: opts.cliFlag.trim(), source: "cli" };
3559
+ }
3560
+ const envVal = process.env.CV_HUB_ORG?.trim();
3561
+ if (envVal) {
3562
+ return { value: envVal, source: "env" };
3563
+ }
3564
+ const cwd = opts.cwd || process.cwd();
3565
+ try {
3566
+ const repoConfigPath = (0, import_node_path2.join)(cwd, ".cva", "agent.json");
3567
+ if ((0, import_node_fs3.existsSync)(repoConfigPath)) {
3568
+ const config = JSON.parse((0, import_node_fs3.readFileSync)(repoConfigPath, "utf-8"));
3569
+ if (config.organization?.trim()) {
3570
+ return { value: config.organization.trim(), source: "repo-config" };
3571
+ }
3442
3572
  }
3443
- if (level === "ansi256") {
3444
- return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
3573
+ } catch {
3574
+ }
3575
+ try {
3576
+ const globalConfigPath = (0, import_node_path2.join)((0, import_node_os3.homedir)(), ".config", "cva", "config.json");
3577
+ if ((0, import_node_fs3.existsSync)(globalConfigPath)) {
3578
+ const config = JSON.parse((0, import_node_fs3.readFileSync)(globalConfigPath, "utf-8"));
3579
+ if (config.organization?.trim()) {
3580
+ return { value: config.organization.trim(), source: "global-config" };
3581
+ }
3445
3582
  }
3446
- return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
3583
+ } catch {
3447
3584
  }
3448
- if (model === "hex") {
3449
- return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
3585
+ return { value: "", source: null };
3586
+ }
3587
+ function resolveToUUID(identifier, orgs) {
3588
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3589
+ if (uuidRegex.test(identifier)) {
3590
+ const match = orgs.find((o) => o.id.toLowerCase() === identifier.toLowerCase());
3591
+ if (match) return match.id;
3592
+ }
3593
+ const slugMatch = orgs.find((o) => o.slug.toLowerCase() === identifier.toLowerCase());
3594
+ if (slugMatch) return slugMatch.id;
3595
+ throw new Error(
3596
+ `Organization "${identifier}" not found. Valid options: ${orgs.map((o) => o.slug).join(", ")}`
3597
+ );
3598
+ }
3599
+ function persistOrg(value, scope, cwd) {
3600
+ let configPath;
3601
+ if (scope === "repo") {
3602
+ const dir = (0, import_node_path2.join)(cwd || process.cwd(), ".cva");
3603
+ (0, import_node_fs3.mkdirSync)(dir, { recursive: true });
3604
+ configPath = (0, import_node_path2.join)(dir, "agent.json");
3605
+ } else {
3606
+ const dir = (0, import_node_path2.join)((0, import_node_os3.homedir)(), ".config", "cva");
3607
+ (0, import_node_fs3.mkdirSync)(dir, { recursive: true });
3608
+ configPath = (0, import_node_path2.join)(dir, "config.json");
3450
3609
  }
3451
- return ansi_styles_default[type][model](...arguments_);
3452
- };
3453
- var usedModels = ["rgb", "hex", "ansi256"];
3454
- for (const model of usedModels) {
3455
- styles2[model] = {
3456
- get() {
3457
- const { level } = this;
3458
- return function(...arguments_) {
3459
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
3460
- return createBuilder(this, styler, this[IS_EMPTY]);
3461
- };
3462
- }
3463
- };
3464
- const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
3465
- styles2[bgModel] = {
3466
- get() {
3467
- const { level } = this;
3468
- return function(...arguments_) {
3469
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
3470
- return createBuilder(this, styler, this[IS_EMPTY]);
3471
- };
3610
+ let existing = {};
3611
+ try {
3612
+ if ((0, import_node_fs3.existsSync)(configPath)) {
3613
+ existing = JSON.parse((0, import_node_fs3.readFileSync)(configPath, "utf-8"));
3472
3614
  }
3473
- };
3615
+ } catch {
3616
+ }
3617
+ existing.organization = value;
3618
+ const tmpPath = configPath + ".tmp";
3619
+ (0, import_node_fs3.writeFileSync)(tmpPath, JSON.stringify(existing, null, 2) + "\n", {
3620
+ mode: scope === "global" ? 384 : 420
3621
+ });
3622
+ (0, import_node_fs3.renameSync)(tmpPath, configPath);
3623
+ return configPath;
3474
3624
  }
3475
- var proto = Object.defineProperties(() => {
3476
- }, {
3477
- ...styles2,
3478
- level: {
3479
- enumerable: true,
3480
- get() {
3481
- return this[GENERATOR].level;
3482
- },
3483
- set(level) {
3484
- this[GENERATOR].level = level;
3625
+ async function promptPersistScope() {
3626
+ const readline = await import("node:readline");
3627
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
3628
+ console.log();
3629
+ console.log(source_default.gray(" Save this choice for next time?"));
3630
+ console.log(` ${source_default.cyan("r")}. Save to this repo's .cva/agent.json ${source_default.gray("(recommended)")}`);
3631
+ console.log(` ${source_default.cyan("g")}. Save globally to ~/.config/cva/config.json`);
3632
+ console.log(` ${source_default.cyan("n")}. Don't save \u2014 prompt again next time`);
3633
+ console.log();
3634
+ const input = await new Promise((resolve2) => {
3635
+ rl.question(" Choice [r/g/n] (default: r): ", (answer) => {
3636
+ rl.close();
3637
+ resolve2(answer.trim().toLowerCase() || "r");
3638
+ });
3639
+ });
3640
+ return input === "g" ? "global" : input === "n" ? "none" : "repo";
3641
+ }
3642
+ async function confirmAutoMatch(match, sourceSlug) {
3643
+ const readline = await import("node:readline");
3644
+ console.log();
3645
+ console.log(` Auto-matched organization: ${source_default.bold(match.name)} (${match.slug})`);
3646
+ console.log(source_default.gray(` from repo owner: ${sourceSlug}`));
3647
+ console.log();
3648
+ console.log(` Register executor under ${match.name}?`);
3649
+ console.log(` ${source_default.cyan("Y")} \u2014 yes, use ${match.name}`);
3650
+ console.log(` ${source_default.cyan("n")} \u2014 no, abort`);
3651
+ console.log(` ${source_default.cyan("p")} \u2014 show the full org list and pick manually`);
3652
+ console.log();
3653
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
3654
+ let attempts = 0;
3655
+ while (attempts < 2) {
3656
+ const input = await new Promise((resolve2) => {
3657
+ rl.question(" Choice [Y/n/p] (default: Y): ", (answer) => {
3658
+ resolve2(answer.trim().toLowerCase() || "y");
3659
+ });
3660
+ });
3661
+ if (input === "y" || input === "yes") {
3662
+ rl.close();
3663
+ return "accept";
3664
+ }
3665
+ if (input === "n" || input === "no") {
3666
+ rl.close();
3667
+ return "abort";
3668
+ }
3669
+ if (input === "p" || input === "pick") {
3670
+ rl.close();
3671
+ return "pick";
3672
+ }
3673
+ attempts++;
3674
+ if (attempts < 2) {
3675
+ console.log(source_default.yellow(" Invalid input. Enter Y, n, or p."));
3485
3676
  }
3486
3677
  }
3487
- });
3488
- var createStyler = (open, close, parent) => {
3489
- let openAll;
3490
- let closeAll;
3491
- if (parent === void 0) {
3492
- openAll = open;
3493
- closeAll = close;
3494
- } else {
3495
- openAll = parent.openAll + open;
3496
- closeAll = close + parent.closeAll;
3678
+ rl.close();
3679
+ return "abort";
3680
+ }
3681
+ async function pickOrg(orgs, opts) {
3682
+ if (!opts.interactive || !process.stdout.isTTY) {
3683
+ throw new Error(
3684
+ `CV-Hub requires organization selection. Set CV_HUB_ORG or pass --org. Valid slugs: ${orgs.map((o) => o.slug).join(", ")}`
3685
+ );
3497
3686
  }
3498
- return {
3499
- open,
3500
- close,
3501
- openAll,
3502
- closeAll,
3503
- parent
3504
- };
3505
- };
3506
- var createBuilder = (self, _styler, _isEmpty) => {
3507
- const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
3508
- Object.setPrototypeOf(builder, proto);
3509
- builder[GENERATOR] = self;
3510
- builder[STYLER] = _styler;
3511
- builder[IS_EMPTY] = _isEmpty;
3512
- return builder;
3513
- };
3514
- var applyStyle = (self, string) => {
3515
- if (self.level <= 0 || !string) {
3516
- return self[IS_EMPTY] ? "" : string;
3687
+ const readline = await import("node:readline");
3688
+ console.log();
3689
+ console.log(source_default.bold(" CV-Hub requires organization selection."));
3690
+ console.log(source_default.gray(" Which organization should this executor register under?"));
3691
+ console.log();
3692
+ orgs.forEach((o, i) => {
3693
+ console.log(` ${source_default.cyan(String(i + 1))}. ${o.name.padEnd(20)} (${source_default.gray(o.slug)})`);
3694
+ });
3695
+ console.log(` ${source_default.cyan("c")}. Cancel`);
3696
+ console.log();
3697
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
3698
+ const input = await new Promise((resolve2) => {
3699
+ rl.question(" Enter number, slug, or 'c': ", (answer) => {
3700
+ rl.close();
3701
+ resolve2(answer.trim());
3702
+ });
3703
+ });
3704
+ if (input.toLowerCase() === "c" || !input) {
3705
+ throw new Error("Registration aborted. Set CV_HUB_ORG or use --org to skip this prompt.");
3517
3706
  }
3518
- let styler = self[STYLER];
3519
- if (styler === void 0) {
3520
- return string;
3707
+ let chosen;
3708
+ const num = parseInt(input, 10);
3709
+ if (!isNaN(num) && num >= 1 && num <= orgs.length) {
3710
+ chosen = orgs[num - 1];
3711
+ } else {
3712
+ chosen = orgs.find((o) => o.slug.toLowerCase() === input.toLowerCase());
3713
+ }
3714
+ if (!chosen) {
3715
+ throw new Error(`"${input}" doesn't match any organization. Valid: ${orgs.map((o) => o.slug).join(", ")}`);
3521
3716
  }
3522
- const { openAll, closeAll } = styler;
3523
- if (string.includes("\x1B")) {
3524
- while (styler !== void 0) {
3525
- string = stringReplaceAll(string, styler.close, styler.open);
3526
- styler = styler.parent;
3717
+ console.log();
3718
+ console.log(` ${source_default.green("\u2713")} ${chosen.name} (${chosen.slug})`);
3719
+ const persistScope = await promptPersistScope();
3720
+ return { chosen, persistScope };
3721
+ }
3722
+ function parseMultiOrgError(status, body) {
3723
+ if (status !== 400) return null;
3724
+ try {
3725
+ const data = JSON.parse(body);
3726
+ const orgs = data?.error?.organizations;
3727
+ if (Array.isArray(orgs) && orgs.length > 0 && orgs[0]?.id && orgs[0]?.slug) {
3728
+ return orgs;
3527
3729
  }
3730
+ } catch {
3528
3731
  }
3529
- const lfIndex = string.indexOf("\n");
3530
- if (lfIndex !== -1) {
3531
- string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
3732
+ return null;
3733
+ }
3734
+ var import_node_fs3, import_node_path2, import_node_os3;
3735
+ var init_org_resolver = __esm({
3736
+ "src/utils/org-resolver.ts"() {
3737
+ "use strict";
3738
+ import_node_fs3 = require("node:fs");
3739
+ import_node_path2 = require("node:path");
3740
+ import_node_os3 = require("node:os");
3741
+ init_source();
3532
3742
  }
3533
- return openAll + string + closeAll;
3534
- };
3535
- Object.defineProperties(createChalk.prototype, styles2);
3536
- var chalk = createChalk();
3537
- var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
3538
- var source_default = chalk;
3743
+ });
3744
+
3745
+ // node_modules/commander/esm.mjs
3746
+ var import_index = __toESM(require_commander(), 1);
3747
+ var {
3748
+ program,
3749
+ createCommand,
3750
+ createArgument,
3751
+ createOption,
3752
+ CommanderError,
3753
+ InvalidArgumentError,
3754
+ InvalidOptionArgumentError,
3755
+ // deprecated old name
3756
+ Command,
3757
+ Argument,
3758
+ Option,
3759
+ Help
3760
+ } = import_index.default;
3761
+
3762
+ // src/commands/setup.ts
3763
+ var import_node_child_process = require("node:child_process");
3764
+ var import_node_fs = require("node:fs");
3765
+ var import_node_path = require("node:path");
3766
+ var import_node_os2 = require("node:os");
3767
+ init_source();
3539
3768
 
3540
3769
  // src/utils/credentials.ts
3541
3770
  var import_fs = require("fs");
@@ -3665,6 +3894,92 @@ async function validateToken(hubUrl, token) {
3665
3894
  return null;
3666
3895
  }
3667
3896
  }
3897
+ var DEVICE_CLIENT_ID = "cv-agent-cli";
3898
+ var DEVICE_SCOPES = "repo:read repo:write profile offline_access";
3899
+ var POLL_INTERVAL_MS = 5e3;
3900
+ var MAX_POLL_ATTEMPTS = 180;
3901
+ async function deviceAuthFlow(hubUrl, appUrl) {
3902
+ const authRes = await fetch(`${hubUrl}/oauth/device/authorize`, {
3903
+ method: "POST",
3904
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
3905
+ body: new URLSearchParams({
3906
+ client_id: DEVICE_CLIENT_ID,
3907
+ scope: DEVICE_SCOPES
3908
+ })
3909
+ });
3910
+ if (!authRes.ok) {
3911
+ const err = await authRes.json().catch(() => ({}));
3912
+ throw new Error(err.error_description || `Device auth failed: ${authRes.status}`);
3913
+ }
3914
+ const auth = await authRes.json();
3915
+ console.log(source_default.bold(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
3916
+ console.log(source_default.bold(" \u2502 CV-Hub Device Authorization \u2502"));
3917
+ console.log(source_default.bold(" \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"));
3918
+ console.log(source_default.bold(" \u2502 \u2502"));
3919
+ console.log(source_default.bold(" \u2502 Open this URL in your browser: \u2502"));
3920
+ console.log(source_default.bold(` \u2502 ${source_default.cyan(auth.verification_uri).padEnd(51)}\u2502`));
3921
+ console.log(source_default.bold(" \u2502 \u2502"));
3922
+ console.log(source_default.bold(" \u2502 Then enter this code: \u2502"));
3923
+ console.log(source_default.bold(` \u2502 ${source_default.white.bold(auth.user_code)} \u2502`));
3924
+ console.log(source_default.bold(" \u2502 \u2502"));
3925
+ console.log(source_default.bold(` \u2502 ${source_default.gray(`Expires in ${Math.floor(auth.expires_in / 60)} minutes`).padEnd(51)}\u2502`));
3926
+ console.log(source_default.bold(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
3927
+ console.log();
3928
+ try {
3929
+ const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
3930
+ (0, import_node_child_process.execSync)(`${openCmd} "${auth.verification_uri_complete}" 2>/dev/null`, { timeout: 5e3 });
3931
+ console.log(source_default.gray(" Browser opened. Waiting for authorization..."));
3932
+ } catch {
3933
+ console.log(source_default.gray(" Open the URL above in your browser."));
3934
+ }
3935
+ let interval = Math.max(auth.interval * 1e3, POLL_INTERVAL_MS);
3936
+ const expireTime = Date.now() + auth.expires_in * 1e3;
3937
+ for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt++) {
3938
+ await new Promise((r) => setTimeout(r, interval));
3939
+ if (Date.now() > expireTime) {
3940
+ throw new Error("Authorization timed out");
3941
+ }
3942
+ const remaining = Math.ceil((expireTime - Date.now()) / 1e3);
3943
+ const mins = Math.floor(remaining / 60);
3944
+ const secs = remaining % 60;
3945
+ process.stdout.write(`\r Waiting for authorization... (${mins}:${secs.toString().padStart(2, "0")} remaining) `);
3946
+ const tokenRes = await fetch(`${hubUrl}/oauth/token`, {
3947
+ method: "POST",
3948
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
3949
+ body: new URLSearchParams({
3950
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
3951
+ device_code: auth.device_code,
3952
+ client_id: DEVICE_CLIENT_ID
3953
+ })
3954
+ });
3955
+ const tokenData = await tokenRes.json();
3956
+ if (tokenData.access_token) {
3957
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
3958
+ let uname = "user";
3959
+ try {
3960
+ const userRes = await fetch(`${hubUrl}/oauth/userinfo`, {
3961
+ headers: { Authorization: `Bearer ${tokenData.access_token}` }
3962
+ });
3963
+ if (userRes.ok) {
3964
+ const userInfo = await userRes.json();
3965
+ uname = userInfo.preferred_username || userInfo.name || "user";
3966
+ }
3967
+ } catch {
3968
+ }
3969
+ return { token: tokenData.access_token, username: uname };
3970
+ }
3971
+ if (tokenData.error === "slow_down") {
3972
+ interval += 5e3;
3973
+ } else if (tokenData.error === "access_denied") {
3974
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
3975
+ throw new Error("Authorization denied by user");
3976
+ } else if (tokenData.error === "expired_token") {
3977
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
3978
+ throw new Error("Authorization expired");
3979
+ }
3980
+ }
3981
+ throw new Error("Authorization timed out");
3982
+ }
3668
3983
  function checkBinary(cmd) {
3669
3984
  try {
3670
3985
  return (0, import_node_child_process.execSync)(`${cmd} 2>&1`, { encoding: "utf8", timeout: 5e3 }).trim().split("\n")[0];
@@ -3724,38 +4039,20 @@ async function runSetup() {
3724
4039
  if (!token) {
3725
4040
  console.log(" Let's connect you to CV-Hub.");
3726
4041
  console.log();
3727
- const autoName = `${(0, import_node_os2.hostname)()}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
3728
- const tokenUrl = `${appUrl}/settings/tokens/new?name=${encodeURIComponent(autoName)}&scopes=agent,repo`;
3729
- console.log(source_default.gray(` Opening: ${tokenUrl}`));
3730
4042
  try {
3731
- const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
3732
- (0, import_node_child_process.execSync)(`${openCmd} "${tokenUrl}" 2>/dev/null`, { timeout: 5e3 });
3733
- } catch {
3734
- console.log(source_default.gray(" (Could not open browser \u2014 copy the URL above)"));
3735
- }
3736
- console.log();
3737
- const readline = await import("node:readline");
3738
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
3739
- token = await new Promise((resolve) => {
3740
- rl.question(" Paste your token here: ", (answer) => {
3741
- rl.close();
3742
- resolve(answer.trim());
3743
- });
3744
- });
3745
- if (!token) {
3746
- console.log(source_default.red(" No token provided. Run cva setup again."));
3747
- process.exit(1);
3748
- }
3749
- const user = await validateToken(hubUrl, token);
3750
- if (!user) {
3751
- console.log(source_default.red(" Token validation failed. Check your token and try again."));
4043
+ const deviceResult = await deviceAuthFlow(hubUrl, appUrl);
4044
+ token = deviceResult.token;
4045
+ username = deviceResult.username;
4046
+ console.log(source_default.green(" \u2713") + ` Authenticated as ${source_default.bold(username)}`);
4047
+ writeSharedCreds({ hub_url: hubUrl, token, username, created_at: (/* @__PURE__ */ new Date()).toISOString() });
4048
+ await writeCredentialField("CV_HUB_PAT", token);
4049
+ await writeCredentialField("CV_HUB_API", hubUrl);
4050
+ } catch (err) {
4051
+ console.log(source_default.red(` Authentication failed: ${err.message}`));
4052
+ console.log(source_default.gray(" You can retry with: cva setup"));
4053
+ console.log(source_default.gray(" Or manually: cva auth login --token <your-pat>"));
3752
4054
  process.exit(1);
3753
4055
  }
3754
- username = user;
3755
- console.log(source_default.green(" \u2713") + ` Authenticated as ${source_default.bold(user)}`);
3756
- writeSharedCreds({ hub_url: hubUrl, token, username, created_at: (/* @__PURE__ */ new Date()).toISOString() });
3757
- await writeCredentialField("CV_HUB_PAT", token);
3758
- await writeCredentialField("CV_HUB_API", hubUrl);
3759
4056
  }
3760
4057
  console.log();
3761
4058
  console.log(" Claude.ai MCP connector:");
@@ -3766,18 +4063,84 @@ async function runSetup() {
3766
4063
  console.log(source_default.gray(' Click "Add Integration" \u2192 "Allow" when prompted.'));
3767
4064
  console.log(source_default.gray(" (You can do this later \u2014 setup will continue.)"));
3768
4065
  console.log();
3769
- const cwd = process.cwd();
3770
- const isGitRepo = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".git"));
3771
- const hasCVDir = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cv"));
3772
- const hasClaudeMd = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, "CLAUDE.md"));
3773
- const repoName = (0, import_node_path.basename)(cwd);
4066
+ let cwd = process.cwd();
4067
+ let isGitRepo = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".git"));
4068
+ let repoName = (0, import_node_path.basename)(cwd);
3774
4069
  if (isGitRepo) {
3775
4070
  console.log(source_default.green(" \u2713") + ` Git repo found: ${repoName}`);
3776
4071
  } else {
3777
- console.log(" Initializing git repository...");
3778
- (0, import_node_child_process.execSync)("git init && git checkout -b main", { cwd, stdio: "pipe" });
3779
- console.log(source_default.green(" \u2713") + " Git repo initialized");
4072
+ const readline = await import("node:readline");
4073
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4074
+ console.log(" No git repository found in this directory.");
4075
+ console.log();
4076
+ console.log(` ${source_default.cyan("a")} \u2014 Initialize a new project here: ${cwd}`);
4077
+ console.log(` ${source_default.cyan("b")} \u2014 Clone an existing repo from CV-Hub`);
4078
+ console.log();
4079
+ const choice = await new Promise((resolve2) => {
4080
+ rl.question(" Choose [a/b]: ", (answer) => {
4081
+ rl.close();
4082
+ resolve2(answer.trim().toLowerCase() || "a");
4083
+ });
4084
+ });
4085
+ if (choice === "b" && token) {
4086
+ try {
4087
+ console.log(source_default.gray(" Fetching your repositories..."));
4088
+ const controller = new AbortController();
4089
+ const timeout = setTimeout(() => controller.abort(), 15e3);
4090
+ const res = await fetch(`${hubUrl}/api/v1/repos?limit=50`, {
4091
+ headers: { Authorization: `Bearer ${token}` },
4092
+ signal: controller.signal
4093
+ });
4094
+ clearTimeout(timeout);
4095
+ if (res.ok) {
4096
+ const data = await res.json();
4097
+ const repos = data.repositories || [];
4098
+ if (repos.length === 0) {
4099
+ console.log(source_default.yellow(" No repos found on CV-Hub. Initializing a new project instead."));
4100
+ } else {
4101
+ console.log();
4102
+ console.log(" Your CV-Hub repositories:");
4103
+ const displayRepos = repos.slice(0, 20);
4104
+ displayRepos.forEach((r, i) => {
4105
+ const desc = r.description ? source_default.gray(` \u2014 ${r.description.substring(0, 40)}`) : "";
4106
+ console.log(` ${source_default.cyan(String(i + 1).padStart(2))}. ${r.slug || r.name}${desc}`);
4107
+ });
4108
+ console.log();
4109
+ const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
4110
+ const selection = await new Promise((resolve2) => {
4111
+ rl2.question(` Select a repo [1-${displayRepos.length}]: `, (answer) => {
4112
+ rl2.close();
4113
+ resolve2(answer.trim());
4114
+ });
4115
+ });
4116
+ const idx = parseInt(selection, 10) - 1;
4117
+ if (idx >= 0 && idx < displayRepos.length) {
4118
+ const repo = displayRepos[idx];
4119
+ const gitHost = "git.hub.controlvector.io";
4120
+ const slug = repo.slug || repo.name;
4121
+ const cloneUrl = `https://${username}:${token}@${gitHost}/${username}/${slug}.git`;
4122
+ console.log(source_default.gray(` Cloning ${username}/${slug}...`));
4123
+ (0, import_node_child_process.execSync)(`git clone ${cloneUrl} ${slug}`, { cwd, stdio: "pipe", timeout: 6e4 });
4124
+ cwd = (0, import_node_path.join)(cwd, slug);
4125
+ process.chdir(cwd);
4126
+ repoName = slug;
4127
+ isGitRepo = true;
4128
+ console.log(source_default.green(" \u2713") + ` Cloned ${username}/${slug}`);
4129
+ }
4130
+ }
4131
+ }
4132
+ } catch (err) {
4133
+ console.log(source_default.yellow(` Could not fetch repos: ${err.message}. Initializing instead.`));
4134
+ }
4135
+ }
4136
+ if (!isGitRepo) {
4137
+ console.log(" Initializing git repository...");
4138
+ (0, import_node_child_process.execSync)("git init && git checkout -b main", { cwd, stdio: "pipe" });
4139
+ console.log(source_default.green(" \u2713") + " Git repo initialized");
4140
+ }
3780
4141
  }
4142
+ const hasClaudeMd = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, "CLAUDE.md"));
4143
+ const hasCVDir = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cv"));
3781
4144
  if (!hasClaudeMd) {
3782
4145
  const template = `# ${repoName}
3783
4146
 
@@ -3795,6 +4158,41 @@ async function runSetup() {
3795
4158
  } else {
3796
4159
  console.log(source_default.green(" \u2713") + " CLAUDE.md present");
3797
4160
  }
4161
+ const gitignorePath = (0, import_node_path.join)(cwd, ".gitignore");
4162
+ const CREDENTIAL_PATTERNS = [
4163
+ "# Credentials and secrets (auto-added by cv-agent)",
4164
+ ".env",
4165
+ ".env.*",
4166
+ ".claude/",
4167
+ ".claude.json",
4168
+ ".credentials*",
4169
+ "*.pem",
4170
+ "*.key",
4171
+ ".ssh/",
4172
+ ".gnupg/",
4173
+ ".npm/",
4174
+ ".config/",
4175
+ ".zsh_history",
4176
+ ".bash_history",
4177
+ ".zsh_sessions/",
4178
+ "node_modules/",
4179
+ ".DS_Store"
4180
+ ];
4181
+ try {
4182
+ let gitignoreContent = "";
4183
+ if ((0, import_node_fs.existsSync)(gitignorePath)) {
4184
+ gitignoreContent = (0, import_node_fs.readFileSync)(gitignorePath, "utf-8");
4185
+ }
4186
+ const missing = CREDENTIAL_PATTERNS.filter((p) => !gitignoreContent.includes(p));
4187
+ if (missing.length > 0) {
4188
+ const addition = (gitignoreContent && !gitignoreContent.endsWith("\n") ? "\n" : "") + missing.join("\n") + "\n";
4189
+ (0, import_node_fs.writeFileSync)(gitignorePath, gitignoreContent + addition);
4190
+ console.log(source_default.green(" \u2713") + " .gitignore updated with credential protection");
4191
+ } else {
4192
+ console.log(source_default.green(" \u2713") + " .gitignore has credential protection");
4193
+ }
4194
+ } catch {
4195
+ }
3798
4196
  if (!hasCVDir) {
3799
4197
  (0, import_node_fs.mkdirSync)((0, import_node_path.join)(cwd, ".cv"), { recursive: true });
3800
4198
  }
@@ -3804,6 +4202,22 @@ async function runSetup() {
3804
4202
  try {
3805
4203
  const existingRemote = (0, import_node_child_process.execSync)('git remote get-url cv-hub 2>/dev/null || echo ""', { cwd, encoding: "utf8" }).trim();
3806
4204
  if (!existingRemote) {
4205
+ try {
4206
+ const controller = new AbortController();
4207
+ const timeout = setTimeout(() => controller.abort(), 15e3);
4208
+ await fetch(`${hubUrl}/api/v1/user/repos`, {
4209
+ method: "POST",
4210
+ headers: {
4211
+ Authorization: `Bearer ${token}`,
4212
+ "Content-Type": "application/json"
4213
+ },
4214
+ body: JSON.stringify({ name: repoName, auto_init: false }),
4215
+ signal: controller.signal
4216
+ });
4217
+ clearTimeout(timeout);
4218
+ console.log(source_default.green(" \u2713") + ` Repo created on CV-Hub: ${username}/${repoName}`);
4219
+ } catch {
4220
+ }
3807
4221
  (0, import_node_child_process.execSync)(`git remote add cv-hub ${remoteUrl}`, { cwd, stdio: "pipe" });
3808
4222
  console.log(source_default.green(" \u2713") + ` Remote added: cv-hub \u2192 ${remoteUrl}`);
3809
4223
  } else {
@@ -3811,6 +4225,99 @@ async function runSetup() {
3811
4225
  }
3812
4226
  } catch {
3813
4227
  }
4228
+ try {
4229
+ const credStorePath = (0, import_node_path.join)((0, import_node_os2.homedir)(), ".git-credentials");
4230
+ const credLine = `https://${username}:${token}@${gitHost}`;
4231
+ let existing = "";
4232
+ try {
4233
+ existing = (0, import_node_fs.readFileSync)(credStorePath, "utf-8");
4234
+ } catch {
4235
+ }
4236
+ if (!existing.includes(gitHost)) {
4237
+ (0, import_node_fs.writeFileSync)(credStorePath, existing + credLine + "\n", { mode: 384 });
4238
+ }
4239
+ (0, import_node_child_process.execSync)(`git config --global credential.helper store`, { stdio: "pipe" });
4240
+ } catch {
4241
+ }
4242
+ try {
4243
+ (0, import_node_child_process.execSync)("git log --oneline -1", { cwd, stdio: "pipe" });
4244
+ const status = (0, import_node_child_process.execSync)("git status --porcelain", { cwd, encoding: "utf8" }).trim();
4245
+ if (status) {
4246
+ (0, import_node_child_process.execSync)("git add -A", { cwd, stdio: "pipe" });
4247
+ (0, import_node_child_process.execSync)('git commit -m "chore: cv-agent setup"', { cwd, stdio: "pipe" });
4248
+ console.log(source_default.green(" \u2713") + " Changes committed");
4249
+ }
4250
+ } catch {
4251
+ try {
4252
+ (0, import_node_child_process.execSync)("git add -A", { cwd, stdio: "pipe" });
4253
+ (0, import_node_child_process.execSync)('git commit -m "Initial commit via cv-agent"', { cwd, stdio: "pipe" });
4254
+ console.log(source_default.green(" \u2713") + " Initial commit created");
4255
+ } catch {
4256
+ }
4257
+ }
4258
+ try {
4259
+ (0, import_node_child_process.execSync)("git push -u cv-hub main 2>&1", { cwd, stdio: "pipe", timeout: 3e4 });
4260
+ console.log(source_default.green(" \u2713") + " Pushed to CV-Hub");
4261
+ } catch {
4262
+ console.log(source_default.gray(" (Push skipped \u2014 you can push later with: git push cv-hub main)"));
4263
+ }
4264
+ }
4265
+ console.log();
4266
+ let agentStatus = "";
4267
+ const pidFile = (0, import_node_path.join)((0, import_node_os2.homedir)(), ".config", "controlvector", "agent.pid");
4268
+ let agentRunning = false;
4269
+ try {
4270
+ const pid = parseInt((0, import_node_fs.readFileSync)(pidFile, "utf-8").trim(), 10);
4271
+ if (pid > 0) {
4272
+ process.kill(pid, 0);
4273
+ agentRunning = true;
4274
+ agentStatus = `running (PID ${pid})`;
4275
+ console.log(source_default.green(" \u2713") + ` Agent already running (PID ${pid})`);
4276
+ }
4277
+ } catch {
4278
+ }
4279
+ if (!agentRunning) {
4280
+ const readline = await import("node:readline");
4281
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4282
+ const answer = await new Promise((resolve2) => {
4283
+ rl.question(" Start the CV-Agent daemon? (Y/n): ", (a) => {
4284
+ rl.close();
4285
+ resolve2(a.trim().toLowerCase() || "y");
4286
+ });
4287
+ });
4288
+ if (answer === "y" || answer === "yes" || answer === "") {
4289
+ const machName = (0, import_node_os2.hostname)().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
4290
+ console.log(source_default.gray(` Starting agent as "${machName}"...`));
4291
+ try {
4292
+ const { spawn: spawnChild } = await import("node:child_process");
4293
+ const child = spawnChild("cva", [
4294
+ "agent",
4295
+ "--auto-approve",
4296
+ "--machine",
4297
+ machName,
4298
+ "--working-dir",
4299
+ cwd
4300
+ ], {
4301
+ detached: true,
4302
+ stdio: "ignore",
4303
+ env: { ...process.env }
4304
+ });
4305
+ child.unref();
4306
+ if (child.pid) {
4307
+ (0, import_node_fs.mkdirSync)((0, import_node_path.join)((0, import_node_os2.homedir)(), ".config", "controlvector"), { recursive: true });
4308
+ (0, import_node_fs.writeFileSync)(pidFile, String(child.pid), { mode: 384 });
4309
+ agentStatus = `running (PID ${child.pid})`;
4310
+ console.log(source_default.green(" \u2713") + ` Agent started (PID ${child.pid}) \u2014 executor "${machName}"`);
4311
+ }
4312
+ } catch (err) {
4313
+ console.log(source_default.yellow(` Could not start agent: ${err.message}`));
4314
+ console.log(source_default.gray(" Start manually with: cva agent --auto-approve"));
4315
+ agentStatus = "not started";
4316
+ }
4317
+ } else {
4318
+ agentStatus = "not started";
4319
+ console.log(source_default.gray(" Start anytime with: cva agent --auto-approve"));
4320
+ }
3814
4321
  }
3815
4322
  console.log();
3816
4323
  console.log(source_default.bold(" Setup Complete"));
@@ -3818,11 +4325,14 @@ async function runSetup() {
3818
4325
  console.log(` ${source_default.green("\u2713")} Authenticated as: ${source_default.cyan(username)}`);
3819
4326
  console.log(` ${source_default.green("\u2713")} Repository: ${source_default.cyan(repoName)}`);
3820
4327
  console.log(` ${source_default.green("\u2713")} CLAUDE.md: present`);
4328
+ if (agentStatus.startsWith("running")) {
4329
+ console.log(` ${source_default.green("\u2713")} Agent daemon: ${source_default.cyan(agentStatus)}`);
4330
+ }
3821
4331
  console.log(source_default.gray(" " + "\u2500".repeat(40)));
3822
4332
  console.log();
3823
4333
  console.log(" What's next:");
3824
- console.log(` ${source_default.cyan("cva agent --auto-approve")} \u2014 Start listening for tasks`);
3825
- console.log(` Or open Claude.ai and dispatch a task to this repo.`);
4334
+ console.log(" Open Claude.ai and try:");
4335
+ console.log(source_default.cyan(` "Create a task in ${repoName} to add a hello world index.html"`));
3826
4336
  console.log();
3827
4337
  console.log(source_default.gray(` Dashboard: ${appUrl}`));
3828
4338
  console.log();
@@ -3838,6 +4348,7 @@ function setupCommand() {
3838
4348
  var import_node_child_process5 = require("node:child_process");
3839
4349
  var os3 = __toESM(require("node:os"));
3840
4350
  var path2 = __toESM(require("node:path"));
4351
+ init_source();
3841
4352
 
3842
4353
  // src/utils/event-queue.ts
3843
4354
  var import_node_fs2 = require("node:fs");
@@ -3966,6 +4477,7 @@ function sleep(ms) {
3966
4477
  }
3967
4478
 
3968
4479
  // src/utils/api.ts
4480
+ init_source();
3969
4481
  async function apiCall(creds, method, path3, body) {
3970
4482
  const url = `${creds.CV_HUB_API}${path3}`;
3971
4483
  const headers = {
@@ -3978,7 +4490,16 @@ async function apiCall(creds, method, path3, body) {
3978
4490
  body: body ? JSON.stringify(body) : void 0
3979
4491
  });
3980
4492
  }
3981
- async function registerExecutor(creds, machineName, workingDir, repositoryId, metadata) {
4493
+ async function registerExecutor(creds, machineName, workingDir, repositoryId, metadata, orgOptions) {
4494
+ const {
4495
+ resolveOrg: resolveOrg2,
4496
+ resolveToUUID: resolveToUUID2,
4497
+ pickOrg: pickOrg2,
4498
+ confirmAutoMatch: confirmAutoMatch2,
4499
+ promptPersistScope: promptPersistScope2,
4500
+ persistOrg: persistOrg2,
4501
+ parseMultiOrgError: parseMultiOrgError2
4502
+ } = await Promise.resolve().then(() => (init_org_resolver(), org_resolver_exports));
3982
4503
  const body = {
3983
4504
  name: `cva:${machineName}`,
3984
4505
  machine_name: machineName,
@@ -3997,7 +4518,70 @@ async function registerExecutor(creds, machineName, workingDir, repositoryId, me
3997
4518
  if (metadata?.tags) body.tags = metadata.tags;
3998
4519
  if (metadata?.owner_project) body.owner_project = metadata.owner_project;
3999
4520
  if (metadata?.integration) body.integration = metadata.integration;
4000
- const res = await apiCall(creds, "POST", "/api/v1/executors", body);
4521
+ const resolved = resolveOrg2({
4522
+ cliFlag: orgOptions?.cliFlag,
4523
+ cwd: orgOptions?.cwd || workingDir
4524
+ });
4525
+ let res = await apiCall(creds, "POST", "/api/v1/executors", body);
4526
+ if (res.status === 400) {
4527
+ const errBody = await res.text();
4528
+ const orgs = parseMultiOrgError2(res.status, errBody);
4529
+ if (orgs) {
4530
+ if (resolved.value) {
4531
+ try {
4532
+ const orgId = resolveToUUID2(resolved.value, orgs);
4533
+ body.organization_id = orgId;
4534
+ res = await apiCall(creds, "POST", "/api/v1/executors", body);
4535
+ } catch (e) {
4536
+ throw new Error(
4537
+ `Organization "${resolved.value}" (from ${resolved.source}) is invalid. ${e.message}`
4538
+ );
4539
+ }
4540
+ }
4541
+ let autoMatchHandled = false;
4542
+ if (!resolved.value && orgOptions?.repoOwnerSlug) {
4543
+ const match = orgs.find(
4544
+ (o) => o.slug.toLowerCase() === orgOptions.repoOwnerSlug.toLowerCase()
4545
+ );
4546
+ if (match) {
4547
+ if (!process.stdout.isTTY) {
4548
+ throw new Error(
4549
+ `Auto-matched "${match.slug}" from repo owner, but running non-interactively. Set CV_HUB_ORG=${match.slug} or pass --org ${match.slug} to confirm, or pick a different org from: ${orgs.map((o) => o.slug).join(", ")}.`
4550
+ );
4551
+ }
4552
+ const decision = await confirmAutoMatch2(match, orgOptions.repoOwnerSlug);
4553
+ if (decision === "accept") {
4554
+ const scope = await promptPersistScope2();
4555
+ if (scope !== "none") {
4556
+ const savedPath = persistOrg2(match.slug, scope, orgOptions?.cwd || workingDir);
4557
+ console.log(source_default.gray(` Saved to ${savedPath}`));
4558
+ }
4559
+ body.organization_id = match.id;
4560
+ res = await apiCall(creds, "POST", "/api/v1/executors", body);
4561
+ autoMatchHandled = true;
4562
+ } else if (decision === "abort") {
4563
+ throw new Error(
4564
+ "Registration aborted. Set CV_HUB_ORG or use --org to choose an org non-interactively."
4565
+ );
4566
+ }
4567
+ }
4568
+ }
4569
+ if (!autoMatchHandled && !res.ok) {
4570
+ const picked = await pickOrg2(orgs, {
4571
+ interactive: true,
4572
+ cwd: orgOptions?.cwd || workingDir
4573
+ });
4574
+ if (picked.persistScope !== "none") {
4575
+ const savedPath = persistOrg2(picked.chosen.slug, picked.persistScope, orgOptions?.cwd || workingDir);
4576
+ console.log(source_default.gray(` Saved to ${savedPath}`));
4577
+ }
4578
+ body.organization_id = picked.chosen.id;
4579
+ res = await apiCall(creds, "POST", "/api/v1/executors", body);
4580
+ }
4581
+ } else {
4582
+ throw new Error(`Failed to register executor: ${res.status} ${errBody}`);
4583
+ }
4584
+ }
4001
4585
  if (!res.ok) {
4002
4586
  const err = await res.text();
4003
4587
  throw new Error(`Failed to register executor: ${res.status} ${err}`);
@@ -4357,6 +4941,7 @@ function verifyGitRemote(cwd, task, gitHost) {
4357
4941
  }
4358
4942
 
4359
4943
  // src/utils/display.ts
4944
+ init_source();
4360
4945
  function formatDuration(ms) {
4361
4946
  const s = Math.floor(ms / 1e3);
4362
4947
  if (s < 60) return `${s}s`;
@@ -4393,6 +4978,7 @@ function updateStatusLine(idle, poll, completedCount, failedCount) {
4393
4978
  }
4394
4979
 
4395
4980
  // src/utils/retry.ts
4981
+ init_source();
4396
4982
  async function withRetry(fn, label, maxRetries = 3) {
4397
4983
  for (let i = 0; i < maxRetries; i++) {
4398
4984
  try {
@@ -4440,11 +5026,78 @@ async function writeConfig(config) {
4440
5026
 
4441
5027
  // src/commands/git-safety.ts
4442
5028
  var import_node_child_process3 = require("node:child_process");
5029
+ var import_node_fs4 = require("node:fs");
5030
+ var import_node_path3 = require("node:path");
5031
+ var import_node_os4 = require("node:os");
5032
+ var DANGEROUS_PATTERNS = [
5033
+ ".claude/",
5034
+ ".claude.json",
5035
+ ".credentials",
5036
+ ".zsh_history",
5037
+ ".bash_history",
5038
+ ".zsh_sessions/",
5039
+ ".ssh/",
5040
+ ".gnupg/",
5041
+ ".npm/",
5042
+ ".config/",
5043
+ ".CFUserTextEncoding",
5044
+ "Library/",
5045
+ "Applications/",
5046
+ ".Trash/",
5047
+ ".DS_Store",
5048
+ "node_modules/",
5049
+ ".env",
5050
+ ".env.local",
5051
+ ".env.production"
5052
+ ];
4443
5053
  function git(cmd, cwd) {
4444
5054
  return (0, import_node_child_process3.execSync)(cmd, { cwd, encoding: "utf8", timeout: 3e4 }).trim();
4445
5055
  }
5056
+ function checkWorkspaceSafety(workspaceRoot) {
5057
+ const resolved = (0, import_node_path3.resolve)(workspaceRoot);
5058
+ const home = (0, import_node_path3.resolve)((0, import_node_os4.homedir)());
5059
+ if (resolved === home) {
5060
+ return `Workspace is user HOME directory (${home}). Refusing to auto-commit to prevent indexing personal files.`;
5061
+ }
5062
+ if (home.startsWith(resolved + "/")) {
5063
+ return `Workspace (${resolved}) is a parent of HOME. Refusing to auto-commit.`;
5064
+ }
5065
+ if (!(0, import_node_fs4.existsSync)((0, import_node_path3.join)(resolved, ".git"))) {
5066
+ return `No .git directory in ${resolved}. Not a git repository.`;
5067
+ }
5068
+ return null;
5069
+ }
5070
+ function filterDangerousFiles(statusLines) {
5071
+ const safe = [];
5072
+ const blocked = [];
5073
+ for (const line of statusLines) {
5074
+ const filePath = line.substring(3).trim();
5075
+ const isDangerous = DANGEROUS_PATTERNS.some(
5076
+ (pattern) => filePath.startsWith(pattern) || filePath.includes("/" + pattern)
5077
+ );
5078
+ if (isDangerous) {
5079
+ blocked.push(filePath);
5080
+ } else {
5081
+ safe.push(line);
5082
+ }
5083
+ }
5084
+ return { safe, blocked };
5085
+ }
4446
5086
  function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
4447
5087
  const targetBranch = branch || "main";
5088
+ const safetyError = checkWorkspaceSafety(workspaceRoot);
5089
+ if (safetyError) {
5090
+ console.log(` [git-safety] BLOCKED: ${safetyError}`);
5091
+ return {
5092
+ hadChanges: false,
5093
+ filesAdded: 0,
5094
+ filesModified: 0,
5095
+ filesDeleted: 0,
5096
+ pushed: false,
5097
+ skipped: true,
5098
+ skipReason: safetyError
5099
+ };
5100
+ }
4448
5101
  try {
4449
5102
  let statusOutput;
4450
5103
  try {
@@ -4452,8 +5105,8 @@ function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
4452
5105
  } catch {
4453
5106
  return { hadChanges: false, filesAdded: 0, filesModified: 0, filesDeleted: 0, pushed: false, error: "git status failed" };
4454
5107
  }
4455
- const lines = statusOutput.split("\n").filter(Boolean);
4456
- if (lines.length === 0) {
5108
+ const allLines = statusOutput.split("\n").filter(Boolean);
5109
+ if (allLines.length === 0) {
4457
5110
  try {
4458
5111
  const unpushed = git(`git log origin/${targetBranch}..HEAD --oneline 2>/dev/null`, workspaceRoot);
4459
5112
  if (unpushed) {
@@ -4465,8 +5118,16 @@ function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
4465
5118
  }
4466
5119
  return { hadChanges: false, filesAdded: 0, filesModified: 0, filesDeleted: 0, pushed: false };
4467
5120
  }
5121
+ const { safe: safeLines, blocked } = filterDangerousFiles(allLines);
5122
+ if (blocked.length > 0) {
5123
+ console.log(` [git-safety] Blocked ${blocked.length} sensitive file(s) from staging: ${blocked.slice(0, 5).join(", ")}${blocked.length > 5 ? "..." : ""}`);
5124
+ }
5125
+ if (safeLines.length === 0) {
5126
+ console.log(` [git-safety] All ${allLines.length} changed files were blocked by safety filter`);
5127
+ return { hadChanges: false, filesAdded: 0, filesModified: 0, filesDeleted: 0, pushed: false };
5128
+ }
4468
5129
  let added = 0, modified = 0, deleted = 0;
4469
- for (const line of lines) {
5130
+ for (const line of safeLines) {
4470
5131
  const code = line.substring(0, 2);
4471
5132
  if (code.includes("?")) added++;
4472
5133
  else if (code.includes("D")) deleted++;
@@ -4474,9 +5135,15 @@ function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
4474
5135
  else added++;
4475
5136
  }
4476
5137
  console.log(
4477
- ` [git-safety] ${lines.length} uncommitted changes (${added} new, ${modified} modified, ${deleted} deleted) \u2014 committing now`
5138
+ ` [git-safety] ${safeLines.length} safe changes (${added} new, ${modified} modified, ${deleted} deleted) \u2014 committing now`
4478
5139
  );
4479
- git("git add -A", workspaceRoot);
5140
+ for (const line of safeLines) {
5141
+ const filePath = line.substring(3).trim();
5142
+ try {
5143
+ git(`git add -- ${JSON.stringify(filePath)}`, workspaceRoot);
5144
+ } catch {
5145
+ }
5146
+ }
4480
5147
  const shortId = taskId.substring(0, 8);
4481
5148
  const commitMsg = `task: ${taskTitle} [${shortId}]
4482
5149
 
@@ -4537,8 +5204,8 @@ Files: ${added} added, ${modified} modified, ${deleted} deleted`;
4537
5204
 
4538
5205
  // src/commands/deploy-manifest.ts
4539
5206
  var import_node_child_process4 = require("node:child_process");
4540
- var import_node_fs3 = require("node:fs");
4541
- var import_node_path2 = require("node:path");
5207
+ var import_node_fs5 = require("node:fs");
5208
+ var import_node_path4 = require("node:path");
4542
5209
  function exec(cmd, cwd, timeoutMs = 3e5, env2) {
4543
5210
  try {
4544
5211
  const stdout = (0, import_node_child_process4.execSync)(cmd, {
@@ -4581,10 +5248,10 @@ function getHeadCommit(cwd) {
4581
5248
  }
4582
5249
  }
4583
5250
  function loadDeployManifest(workspaceRoot) {
4584
- const manifestPath = (0, import_node_path2.join)(workspaceRoot, ".cva", "deploy.json");
4585
- if (!(0, import_node_fs3.existsSync)(manifestPath)) return null;
5251
+ const manifestPath = (0, import_node_path4.join)(workspaceRoot, ".cva", "deploy.json");
5252
+ if (!(0, import_node_fs5.existsSync)(manifestPath)) return null;
4586
5253
  try {
4587
- const raw = (0, import_node_fs3.readFileSync)(manifestPath, "utf8");
5254
+ const raw = (0, import_node_fs5.readFileSync)(manifestPath, "utf8");
4588
5255
  const manifest = JSON.parse(raw);
4589
5256
  if (!manifest.version || manifest.version < 1) {
4590
5257
  console.log(" [deploy] Invalid manifest version");
@@ -4609,7 +5276,7 @@ async function postTaskDeploy(workspaceRoot, taskId, log) {
4609
5276
  console.log(` [deploy] Building: ${buildStep.name}`);
4610
5277
  log("lifecycle", `Building: ${buildStep.name}`);
4611
5278
  const start = Date.now();
4612
- const cwd = (0, import_node_path2.join)(workspaceRoot, buildStep.working_dir || ".");
5279
+ const cwd = (0, import_node_path4.join)(workspaceRoot, buildStep.working_dir || ".");
4613
5280
  const timeoutMs = (buildStep.timeout_seconds || 300) * 1e3;
4614
5281
  const result = exec(buildStep.command, cwd, timeoutMs);
4615
5282
  if (!result.ok) {
@@ -4700,7 +5367,7 @@ async function rollback(workspaceRoot, targetCommit, manifest, log) {
4700
5367
  }
4701
5368
  if (manifest.build?.steps) {
4702
5369
  for (const step of manifest.build.steps) {
4703
- exec(step.command, (0, import_node_path2.join)(workspaceRoot, step.working_dir || "."), (step.timeout_seconds || 300) * 1e3);
5370
+ exec(step.command, (0, import_node_path4.join)(workspaceRoot, step.working_dir || "."), (step.timeout_seconds || 300) * 1e3);
4704
5371
  }
4705
5372
  }
4706
5373
  if (manifest.service?.restart_command) {
@@ -4858,6 +5525,22 @@ Target repository: ${task.owner}/${task.repo}
4858
5525
  `;
4859
5526
  prompt += `
4860
5527
 
5528
+ ## Security \u2014 NEVER Commit Secrets
5529
+ `;
5530
+ prompt += `Do NOT add, commit, or push any of the following:
5531
+ `;
5532
+ prompt += `- API keys, tokens, passwords, or credentials
5533
+ `;
5534
+ prompt += `- .env files, .credentials files, .claude/ directory
5535
+ `;
5536
+ prompt += `- SSH keys (.ssh/), GPG keys (.gnupg/)
5537
+ `;
5538
+ prompt += `- Shell history (.zsh_history, .bash_history)
5539
+ `;
5540
+ prompt += `If you need to reference an API key, use an environment variable placeholder.
5541
+ `;
5542
+ prompt += `
5543
+
4861
5544
  ---
4862
5545
  `;
4863
5546
  prompt += `When complete, provide a brief summary of what you accomplished.
@@ -4937,7 +5620,7 @@ async function launchAutoApproveMode(prompt, options) {
4937
5620
  let lastProgressBytes = 0;
4938
5621
  let totalBytesStreamed = 0;
4939
5622
  const runOnce = (inputPrompt, isContinue) => {
4940
- return new Promise((resolve, reject) => {
5623
+ return new Promise((resolve2, reject) => {
4941
5624
  const args = isContinue ? ["-p", inputPrompt, "--continue", "--allowedTools", ...ALLOWED_TOOLS] : ["-p", inputPrompt, "--allowedTools", ...ALLOWED_TOOLS];
4942
5625
  if (sessionId && !isContinue) {
4943
5626
  args.push("--session-id", sessionId);
@@ -5047,7 +5730,7 @@ ${source_default.red("!")} Claude Code auth failure (stderr): "${authError}"`);
5047
5730
  });
5048
5731
  child.on("close", (code, signal) => {
5049
5732
  _activeChild = null;
5050
- resolve({
5733
+ resolve2({
5051
5734
  exitCode: signal === "SIGKILL" ? 137 : code ?? 1,
5052
5735
  stderr,
5053
5736
  output: fullOutput,
@@ -5086,7 +5769,7 @@ ${source_default.red("!")} Claude Code auth failure (stderr): "${authError}"`);
5086
5769
  return result;
5087
5770
  }
5088
5771
  async function launchRelayMode(prompt, options) {
5089
- return new Promise((resolve, reject) => {
5772
+ return new Promise((resolve2, reject) => {
5090
5773
  const child = (0, import_node_child_process5.spawn)("claude", [], {
5091
5774
  cwd: options.cwd,
5092
5775
  stdio: ["pipe", "pipe", "pipe"],
@@ -5291,9 +5974,9 @@ ${source_default.red("!")} Claude Code auth failure (stderr): "${authError}"`);
5291
5974
  child.on("close", (code, signal) => {
5292
5975
  _activeChild = null;
5293
5976
  if (signal === "SIGKILL") {
5294
- resolve({ exitCode: 137, stderr, output: fullOutput, authFailure });
5977
+ resolve2({ exitCode: 137, stderr, output: fullOutput, authFailure });
5295
5978
  } else {
5296
- resolve({ exitCode: code ?? 1, stderr, output: fullOutput, authFailure });
5979
+ resolve2({ exitCode: code ?? 1, stderr, output: fullOutput, authFailure });
5297
5980
  }
5298
5981
  });
5299
5982
  child.on("error", (err) => {
@@ -5394,14 +6077,45 @@ async function runAgent(options) {
5394
6077
  console.log();
5395
6078
  process.exit(1);
5396
6079
  }
6080
+ if (process.env.CV_DEBUG) {
6081
+ console.log(source_default.gray(` PATH: ${process.env.PATH}`));
6082
+ console.log(source_default.gray(` HOME: ${process.env.HOME}`));
6083
+ console.log(source_default.gray(` SHELL: ${process.env.SHELL}`));
6084
+ }
6085
+ let claudeBinary = "claude";
5397
6086
  try {
5398
6087
  (0, import_node_child_process5.execSync)("claude --version", { stdio: "pipe", timeout: 5e3 });
5399
6088
  } catch {
5400
- console.log();
5401
- console.log(source_default.red("Claude Code CLI not found.") + " Install it first:");
5402
- console.log(` ${source_default.cyan("npm install -g @anthropic-ai/claude-code")}`);
5403
- console.log();
5404
- process.exit(1);
6089
+ const candidates = [
6090
+ "/usr/local/bin/claude",
6091
+ "/opt/homebrew/bin/claude",
6092
+ `${process.env.HOME}/.npm-global/bin/claude`,
6093
+ `${process.env.HOME}/.nvm/versions/node/*/bin/claude`
6094
+ ];
6095
+ let found = false;
6096
+ for (const candidate of candidates) {
6097
+ try {
6098
+ const resolved = (0, import_node_child_process5.execSync)(`ls ${candidate} 2>/dev/null | head -1`, { encoding: "utf8", timeout: 3e3 }).trim();
6099
+ if (resolved) {
6100
+ (0, import_node_child_process5.execSync)(`${resolved} --version`, { stdio: "pipe", timeout: 5e3 });
6101
+ claudeBinary = resolved;
6102
+ found = true;
6103
+ console.log(source_default.yellow("!") + ` Claude Code found at ${resolved} (not on PATH)`);
6104
+ break;
6105
+ }
6106
+ } catch {
6107
+ }
6108
+ }
6109
+ if (!found) {
6110
+ console.log();
6111
+ console.log(source_default.red("Claude Code CLI not found.") + " Install it first:");
6112
+ console.log(` ${source_default.cyan("npm install -g @anthropic-ai/claude-code")}`);
6113
+ console.log();
6114
+ console.log(source_default.gray(` Current PATH: ${process.env.PATH}`));
6115
+ console.log(source_default.gray(" If running via Launch Agent, ensure PATH includes the directory where claude is installed."));
6116
+ console.log();
6117
+ process.exit(1);
6118
+ }
5405
6119
  }
5406
6120
  const { env: claudeEnv, usingApiKey } = await getClaudeEnv();
5407
6121
  const authCheck = await checkClaudeAuth();
@@ -5442,7 +6156,82 @@ async function runAgent(options) {
5442
6156
  console.log();
5443
6157
  }
5444
6158
  }
6159
+ {
6160
+ const isGitRepo = require("fs").existsSync(require("path").join(workingDir, ".git"));
6161
+ if (!isGitRepo) {
6162
+ console.log(source_default.gray(" Bootstrap: initializing git repo..."));
6163
+ try {
6164
+ (0, import_node_child_process5.execSync)("git init && git checkout -b main", { cwd: workingDir, stdio: "pipe" });
6165
+ } catch {
6166
+ }
6167
+ }
6168
+ const claudeMdPath = require("path").join(workingDir, "CLAUDE.md");
6169
+ if (!require("fs").existsSync(claudeMdPath)) {
6170
+ const name = require("path").basename(workingDir);
6171
+ const template = `# ${name}
6172
+
6173
+ ## Overview
6174
+ [Describe your project here]
6175
+
6176
+ ## Build & Run
6177
+ [How to build and run this project]
6178
+ `;
6179
+ try {
6180
+ require("fs").writeFileSync(claudeMdPath, template);
6181
+ console.log(source_default.gray(" Bootstrap: created CLAUDE.md"));
6182
+ } catch {
6183
+ }
6184
+ }
6185
+ const gitignorePath = require("path").join(workingDir, ".gitignore");
6186
+ try {
6187
+ const fs4 = require("fs");
6188
+ const credPatterns = ".env\n.env.*\n.claude/\n.claude.json\n.credentials*\n*.pem\n*.key\n.ssh/\n.gnupg/\n.npm/\n.config/\n.zsh_history\n.bash_history\nnode_modules/\n.DS_Store\n";
6189
+ let existing = "";
6190
+ try {
6191
+ existing = fs4.readFileSync(gitignorePath, "utf-8");
6192
+ } catch {
6193
+ }
6194
+ if (!existing.includes(".claude/")) {
6195
+ const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
6196
+ fs4.writeFileSync(gitignorePath, existing + prefix + "# Credentials (auto-added by cv-agent)\n" + credPatterns);
6197
+ console.log(source_default.gray(" Bootstrap: .gitignore credential protection added"));
6198
+ }
6199
+ } catch {
6200
+ }
6201
+ const cvDir = require("path").join(workingDir, ".cv");
6202
+ if (!require("fs").existsSync(cvDir)) {
6203
+ try {
6204
+ require("fs").mkdirSync(cvDir, { recursive: true });
6205
+ } catch {
6206
+ }
6207
+ }
6208
+ if (creds.CV_HUB_PAT) {
6209
+ try {
6210
+ const existing = (0, import_node_child_process5.execSync)('git remote get-url cv-hub 2>/dev/null || echo ""', {
6211
+ cwd: workingDir,
6212
+ encoding: "utf8",
6213
+ timeout: 5e3
6214
+ }).trim();
6215
+ if (!existing) {
6216
+ const name = require("path").basename(workingDir);
6217
+ const gitHost = "git.hub.controlvector.io";
6218
+ let user = "user";
6219
+ try {
6220
+ const sharedPath = require("path").join(require("os").homedir(), ".config", "controlvector", "credentials.json");
6221
+ const shared = JSON.parse(require("fs").readFileSync(sharedPath, "utf-8"));
6222
+ if (shared.username) user = shared.username;
6223
+ } catch {
6224
+ }
6225
+ const remoteUrl = `https://${gitHost}/${user}/${name}.git`;
6226
+ (0, import_node_child_process5.execSync)(`git remote add cv-hub ${remoteUrl}`, { cwd: workingDir, stdio: "pipe" });
6227
+ console.log(source_default.gray(` Bootstrap: remote cv-hub \u2192 ${remoteUrl}`));
6228
+ }
6229
+ } catch {
6230
+ }
6231
+ }
6232
+ }
5445
6233
  let detectedRepoId;
6234
+ let detectedOwnerSlug;
5446
6235
  try {
5447
6236
  const remoteUrl = (0, import_node_child_process5.execSync)("git remote get-url origin 2>/dev/null", {
5448
6237
  cwd: workingDir,
@@ -5454,6 +6243,7 @@ async function runAgent(options) {
5454
6243
  );
5455
6244
  if (cvHubMatch) {
5456
6245
  const [, repoOwner, repoSlug] = cvHubMatch;
6246
+ detectedOwnerSlug = repoOwner;
5457
6247
  try {
5458
6248
  const repoData = await resolveRepoId(creds, repoOwner, repoSlug);
5459
6249
  if (repoData?.id) {
@@ -5465,6 +6255,9 @@ async function runAgent(options) {
5465
6255
  }
5466
6256
  } catch {
5467
6257
  }
6258
+ if (options.org) {
6259
+ detectedOwnerSlug = options.org;
6260
+ }
5468
6261
  const wsConfig = await readWorkspaceConfig(workingDir);
5469
6262
  const globalConfig = await readConfig();
5470
6263
  const role = options.role || wsConfig.role || globalConfig.role || "development";
@@ -5505,7 +6298,11 @@ async function runAgent(options) {
5505
6298
  console.log(source_default.yellow(` Guard: ${guardIcon} ${dispatchGuard}`));
5506
6299
  }
5507
6300
  const executor = await withRetry(
5508
- () => registerExecutor(creds, machineName, workingDir, detectedRepoId, executorMeta),
6301
+ () => registerExecutor(creds, machineName, workingDir, detectedRepoId, executorMeta, {
6302
+ cliFlag: options.org,
6303
+ repoOwnerSlug: detectedOwnerSlug,
6304
+ cwd: workingDir
6305
+ }),
5509
6306
  "Executor registration"
5510
6307
  );
5511
6308
  const mode = options.autoApprove ? "auto-approve" : "relay";
@@ -5873,6 +6670,7 @@ function agentCommand() {
5873
6670
  cmd.option("--dispatch-guard <guard>", "Dispatch guard: open, confirm, locked (default: open)");
5874
6671
  cmd.option("--tags <tags>", "Comma-separated tags for this executor");
5875
6672
  cmd.option("--owner-project <project>", "Project this executor belongs to");
6673
+ cmd.option("--org <slug>", "Organization slug (auto-detected from repo owner if omitted)");
5876
6674
  cmd.action(async (opts) => {
5877
6675
  await runAgent(opts);
5878
6676
  });
@@ -5880,6 +6678,7 @@ function agentCommand() {
5880
6678
  }
5881
6679
 
5882
6680
  // src/commands/auth.ts
6681
+ init_source();
5883
6682
  async function authLogin(opts) {
5884
6683
  const token = opts.token || await promptForToken();
5885
6684
  const apiUrl = opts.apiUrl || "https://api.hub.controlvector.io";
@@ -5909,7 +6708,7 @@ async function promptForToken() {
5909
6708
  input: process.stdin,
5910
6709
  output: process.stdout
5911
6710
  });
5912
- return new Promise((resolve) => {
6711
+ return new Promise((resolve2) => {
5913
6712
  rl.question("Enter your CV-Hub PAT token: ", (answer) => {
5914
6713
  rl.close();
5915
6714
  const token = answer.trim();
@@ -5917,7 +6716,7 @@ async function promptForToken() {
5917
6716
  console.log(source_default.red("No token provided."));
5918
6717
  process.exit(1);
5919
6718
  }
5920
- resolve(token);
6719
+ resolve2(token);
5921
6720
  });
5922
6721
  });
5923
6722
  }
@@ -5981,6 +6780,7 @@ function authCommand() {
5981
6780
 
5982
6781
  // src/commands/remote.ts
5983
6782
  var import_node_child_process6 = require("node:child_process");
6783
+ init_source();
5984
6784
  function getGitHost(apiUrl) {
5985
6785
  return apiUrl.replace(/^https?:\/\//, "").replace(/^api\./, "git.");
5986
6786
  }
@@ -6049,6 +6849,7 @@ function remoteCommand() {
6049
6849
  }
6050
6850
 
6051
6851
  // src/commands/task.ts
6852
+ init_source();
6052
6853
  async function taskList(opts) {
6053
6854
  const creds = await readCredentials();
6054
6855
  if (!creds.CV_HUB_PAT) {
@@ -6140,6 +6941,7 @@ function taskCommand() {
6140
6941
  }
6141
6942
 
6142
6943
  // src/commands/status.ts
6944
+ init_source();
6143
6945
  async function showStatus() {
6144
6946
  const creds = await readCredentials();
6145
6947
  if (!creds.CV_HUB_PAT) {
@@ -6196,7 +6998,7 @@ function statusCommand() {
6196
6998
 
6197
6999
  // src/index.ts
6198
7000
  var program2 = new Command();
6199
- program2.name("cva").description('CV-Hub Agent \u2014 bridges Claude Code with CV-Hub task dispatch.\n\nRun "cva setup" to get started.').version(true ? "1.10.0" : "1.6.0");
7001
+ program2.name("cva").description('CV-Hub Agent \u2014 bridges Claude Code with CV-Hub task dispatch.\n\nRun "cva setup" to get started.').version(true ? "1.11.0" : "1.6.0");
6200
7002
  program2.addCommand(setupCommand());
6201
7003
  program2.addCommand(agentCommand());
6202
7004
  program2.addCommand(authCommand());