@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 +1103 -301
- package/dist/bundle.cjs.map +4 -4
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +130 -7
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/git-safety.d.ts +12 -6
- package/dist/commands/git-safety.d.ts.map +1 -1
- package/dist/commands/git-safety.js +114 -22
- package/dist/commands/git-safety.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +361 -45
- package/dist/commands/setup.js.map +1 -1
- package/dist/utils/api.d.ts +5 -1
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +78 -2
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/org-resolver.d.ts +37 -0
- package/dist/utils/org-resolver.d.ts.map +1 -0
- package/dist/utils/org-resolver.js +227 -0
- package/dist/utils/org-resolver.js.map +1 -0
- package/package.json +1 -1
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
|
|
3229
|
-
var
|
|
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
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
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
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
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
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
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
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
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
|
-
|
|
3444
|
-
|
|
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
|
-
|
|
3583
|
+
} catch {
|
|
3447
3584
|
}
|
|
3448
|
-
|
|
3449
|
-
|
|
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
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
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
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
}
|
|
3483
|
-
|
|
3484
|
-
|
|
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
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
if (
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
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
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
};
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
};
|
|
3514
|
-
|
|
3515
|
-
if (
|
|
3516
|
-
|
|
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
|
|
3519
|
-
|
|
3520
|
-
|
|
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
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
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
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
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
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
var
|
|
3537
|
-
var
|
|
3538
|
-
|
|
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
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
console.log(source_default.
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
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
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
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
|
-
|
|
3778
|
-
|
|
3779
|
-
console.log(
|
|
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(
|
|
3825
|
-
console.log(`
|
|
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
|
|
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
|
|
4456
|
-
if (
|
|
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
|
|
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] ${
|
|
5138
|
+
` [git-safety] ${safeLines.length} safe changes (${added} new, ${modified} modified, ${deleted} deleted) \u2014 committing now`
|
|
4478
5139
|
);
|
|
4479
|
-
|
|
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
|
|
4541
|
-
var
|
|
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,
|
|
4585
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
5977
|
+
resolve2({ exitCode: 137, stderr, output: fullOutput, authFailure });
|
|
5295
5978
|
} else {
|
|
5296
|
-
|
|
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
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
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((
|
|
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
|
-
|
|
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.
|
|
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());
|