@controlvector/cv-agent 1.5.0 → 1.7.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 +307 -38
- package/dist/bundle.cjs.map +4 -4
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +55 -1
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/setup.d.ts +13 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +249 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/utils/api.d.ts +15 -1
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +12 -4
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/config.d.ts +20 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +15 -0
- package/dist/utils/config.js.map +1 -1
- package/package.json +4 -1
package/dist/bundle.cjs
CHANGED
|
@@ -3036,8 +3036,11 @@ var {
|
|
|
3036
3036
|
Help
|
|
3037
3037
|
} = import_index.default;
|
|
3038
3038
|
|
|
3039
|
-
// src/commands/
|
|
3040
|
-
var
|
|
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");
|
|
3041
3044
|
|
|
3042
3045
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
3043
3046
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
@@ -3630,6 +3633,210 @@ function cleanMachineName(name) {
|
|
|
3630
3633
|
return name.trim().toLowerCase().replace(/\s+/g, "-");
|
|
3631
3634
|
}
|
|
3632
3635
|
|
|
3636
|
+
// src/commands/setup.ts
|
|
3637
|
+
var SHARED_CRED_DIR = (0, import_node_path.join)((0, import_node_os2.homedir)(), ".config", "controlvector");
|
|
3638
|
+
var SHARED_CRED_PATH = (0, import_node_path.join)(SHARED_CRED_DIR, "credentials.json");
|
|
3639
|
+
function readSharedCreds() {
|
|
3640
|
+
try {
|
|
3641
|
+
const data = JSON.parse((0, import_node_fs.readFileSync)(SHARED_CRED_PATH, "utf-8"));
|
|
3642
|
+
if (data.token && data.hub_url) return data;
|
|
3643
|
+
return null;
|
|
3644
|
+
} catch {
|
|
3645
|
+
return null;
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
function writeSharedCreds(creds) {
|
|
3649
|
+
(0, import_node_fs.mkdirSync)(SHARED_CRED_DIR, { recursive: true });
|
|
3650
|
+
(0, import_node_fs.writeFileSync)(SHARED_CRED_PATH, JSON.stringify(creds, null, 2) + "\n", { mode: 384 });
|
|
3651
|
+
}
|
|
3652
|
+
async function validateToken(hubUrl, token) {
|
|
3653
|
+
try {
|
|
3654
|
+
const controller = new AbortController();
|
|
3655
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
3656
|
+
const res = await fetch(`${hubUrl}/api/auth/me`, {
|
|
3657
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
3658
|
+
signal: controller.signal
|
|
3659
|
+
});
|
|
3660
|
+
clearTimeout(timeout);
|
|
3661
|
+
if (!res.ok) return null;
|
|
3662
|
+
const data = await res.json();
|
|
3663
|
+
return data.user?.username || data.user?.email || "unknown";
|
|
3664
|
+
} catch {
|
|
3665
|
+
return null;
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
function checkBinary(cmd) {
|
|
3669
|
+
try {
|
|
3670
|
+
return (0, import_node_child_process.execSync)(`${cmd} 2>&1`, { encoding: "utf8", timeout: 5e3 }).trim().split("\n")[0];
|
|
3671
|
+
} catch {
|
|
3672
|
+
return null;
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
async function runSetup() {
|
|
3676
|
+
const hubUrl = "https://api.hub.controlvector.io";
|
|
3677
|
+
const appUrl = "https://hub.controlvector.io";
|
|
3678
|
+
console.log();
|
|
3679
|
+
console.log(source_default.bold(" CV-Agent Setup"));
|
|
3680
|
+
console.log();
|
|
3681
|
+
console.log(" Checking environment...");
|
|
3682
|
+
const nodeVersion = checkBinary("node --version");
|
|
3683
|
+
const gitVersion = checkBinary("git --version");
|
|
3684
|
+
const claudeVersion = checkBinary("claude --version");
|
|
3685
|
+
console.log(` ${nodeVersion ? source_default.green("\u2713") : source_default.red("\u2717")} Node.js ${nodeVersion || "\u2014 not found"}`);
|
|
3686
|
+
console.log(` ${gitVersion ? source_default.green("\u2713") : source_default.red("\u2717")} Git ${gitVersion || "\u2014 not found"}`);
|
|
3687
|
+
console.log(` ${claudeVersion ? source_default.green("\u2713") : source_default.red("\u2717")} Claude Code ${claudeVersion || "\u2014 not found"}`);
|
|
3688
|
+
console.log();
|
|
3689
|
+
if (!nodeVersion || !gitVersion) {
|
|
3690
|
+
if (!nodeVersion) console.log(source_default.red(" Node.js required: https://nodejs.org"));
|
|
3691
|
+
if (!gitVersion) console.log(source_default.red(" Git required: https://git-scm.com"));
|
|
3692
|
+
process.exit(1);
|
|
3693
|
+
}
|
|
3694
|
+
if (!claudeVersion) {
|
|
3695
|
+
console.log(source_default.yellow(" Claude Code not found. Install with:"));
|
|
3696
|
+
console.log(source_default.cyan(" npm install -g @anthropic-ai/claude-code"));
|
|
3697
|
+
console.log();
|
|
3698
|
+
console.log(source_default.gray(" Continuing setup \u2014 you can install Claude Code later."));
|
|
3699
|
+
console.log();
|
|
3700
|
+
}
|
|
3701
|
+
let username;
|
|
3702
|
+
let token;
|
|
3703
|
+
const shared = readSharedCreds();
|
|
3704
|
+
if (shared) {
|
|
3705
|
+
const user = await validateToken(shared.hub_url, shared.token);
|
|
3706
|
+
if (user) {
|
|
3707
|
+
username = user;
|
|
3708
|
+
token = shared.token;
|
|
3709
|
+
console.log(source_default.green(" \u2713") + ` Authenticated as ${source_default.bold(user)}`);
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
if (!token) {
|
|
3713
|
+
const creds = await readCredentials();
|
|
3714
|
+
if (creds.CV_HUB_PAT) {
|
|
3715
|
+
const user = await validateToken(hubUrl, creds.CV_HUB_PAT);
|
|
3716
|
+
if (user) {
|
|
3717
|
+
username = user;
|
|
3718
|
+
token = creds.CV_HUB_PAT;
|
|
3719
|
+
console.log(source_default.green(" \u2713") + ` Authenticated as ${source_default.bold(user)} (from cv-hub credentials)`);
|
|
3720
|
+
writeSharedCreds({ hub_url: hubUrl, token, username, created_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
if (!token) {
|
|
3725
|
+
console.log(" Let's connect you to CV-Hub.");
|
|
3726
|
+
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
|
+
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."));
|
|
3752
|
+
process.exit(1);
|
|
3753
|
+
}
|
|
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
|
+
}
|
|
3760
|
+
console.log();
|
|
3761
|
+
console.log(" Claude.ai MCP connector:");
|
|
3762
|
+
const mcpUrl = `https://claude.ai/settings/integrations?add_mcp=${encodeURIComponent(`${hubUrl}/mcp`)}`;
|
|
3763
|
+
console.log(source_default.gray(` To connect Claude.ai to CV-Hub, visit:`));
|
|
3764
|
+
console.log(source_default.cyan(` ${mcpUrl}`));
|
|
3765
|
+
console.log();
|
|
3766
|
+
console.log(source_default.gray(' Click "Add Integration" \u2192 "Allow" when prompted.'));
|
|
3767
|
+
console.log(source_default.gray(" (You can do this later \u2014 setup will continue.)"));
|
|
3768
|
+
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);
|
|
3774
|
+
if (isGitRepo) {
|
|
3775
|
+
console.log(source_default.green(" \u2713") + ` Git repo found: ${repoName}`);
|
|
3776
|
+
} 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");
|
|
3780
|
+
}
|
|
3781
|
+
if (!hasClaudeMd) {
|
|
3782
|
+
const template = `# ${repoName}
|
|
3783
|
+
|
|
3784
|
+
## Overview
|
|
3785
|
+
[Describe your project here]
|
|
3786
|
+
|
|
3787
|
+
## Tech Stack
|
|
3788
|
+
[What languages/frameworks does this project use?]
|
|
3789
|
+
|
|
3790
|
+
## Build & Run
|
|
3791
|
+
[How to build and run this project]
|
|
3792
|
+
`;
|
|
3793
|
+
(0, import_node_fs.writeFileSync)((0, import_node_path.join)(cwd, "CLAUDE.md"), template);
|
|
3794
|
+
console.log(source_default.green(" \u2713") + " CLAUDE.md created");
|
|
3795
|
+
} else {
|
|
3796
|
+
console.log(source_default.green(" \u2713") + " CLAUDE.md present");
|
|
3797
|
+
}
|
|
3798
|
+
if (!hasCVDir) {
|
|
3799
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path.join)(cwd, ".cv"), { recursive: true });
|
|
3800
|
+
}
|
|
3801
|
+
if (token && username) {
|
|
3802
|
+
const gitHost = "git.hub.controlvector.io";
|
|
3803
|
+
const remoteUrl = `https://${gitHost}/${username}/${repoName}.git`;
|
|
3804
|
+
try {
|
|
3805
|
+
const existingRemote = (0, import_node_child_process.execSync)('git remote get-url cv-hub 2>/dev/null || echo ""', { cwd, encoding: "utf8" }).trim();
|
|
3806
|
+
if (!existingRemote) {
|
|
3807
|
+
(0, import_node_child_process.execSync)(`git remote add cv-hub ${remoteUrl}`, { cwd, stdio: "pipe" });
|
|
3808
|
+
console.log(source_default.green(" \u2713") + ` Remote added: cv-hub \u2192 ${remoteUrl}`);
|
|
3809
|
+
} else {
|
|
3810
|
+
console.log(source_default.green(" \u2713") + ` CV-Hub remote exists`);
|
|
3811
|
+
}
|
|
3812
|
+
} catch {
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
console.log();
|
|
3816
|
+
console.log(source_default.bold(" Setup Complete"));
|
|
3817
|
+
console.log(source_default.gray(" " + "\u2500".repeat(40)));
|
|
3818
|
+
console.log(` ${source_default.green("\u2713")} Authenticated as: ${source_default.cyan(username)}`);
|
|
3819
|
+
console.log(` ${source_default.green("\u2713")} Repository: ${source_default.cyan(repoName)}`);
|
|
3820
|
+
console.log(` ${source_default.green("\u2713")} CLAUDE.md: present`);
|
|
3821
|
+
console.log(source_default.gray(" " + "\u2500".repeat(40)));
|
|
3822
|
+
console.log();
|
|
3823
|
+
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.`);
|
|
3826
|
+
console.log();
|
|
3827
|
+
console.log(source_default.gray(` Dashboard: ${appUrl}`));
|
|
3828
|
+
console.log();
|
|
3829
|
+
}
|
|
3830
|
+
function setupCommand() {
|
|
3831
|
+
const cmd = new Command("setup");
|
|
3832
|
+
cmd.description("Set up CV-Agent \u2014 authentication, repo, and connections (start here)");
|
|
3833
|
+
cmd.action(runSetup);
|
|
3834
|
+
return cmd;
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3837
|
+
// src/commands/agent.ts
|
|
3838
|
+
var import_node_child_process5 = require("node:child_process");
|
|
3839
|
+
|
|
3633
3840
|
// src/utils/api.ts
|
|
3634
3841
|
async function apiCall(creds, method, path, body) {
|
|
3635
3842
|
const url = `${creds.CV_HUB_API}${path}`;
|
|
@@ -3643,7 +3850,7 @@ async function apiCall(creds, method, path, body) {
|
|
|
3643
3850
|
body: body ? JSON.stringify(body) : void 0
|
|
3644
3851
|
});
|
|
3645
3852
|
}
|
|
3646
|
-
async function registerExecutor(creds, machineName, workingDir, repositoryId) {
|
|
3853
|
+
async function registerExecutor(creds, machineName, workingDir, repositoryId, metadata) {
|
|
3647
3854
|
const body = {
|
|
3648
3855
|
name: `cva:${machineName}`,
|
|
3649
3856
|
machine_name: machineName,
|
|
@@ -3657,6 +3864,11 @@ async function registerExecutor(creds, machineName, workingDir, repositoryId) {
|
|
|
3657
3864
|
if (repositoryId) {
|
|
3658
3865
|
body.repository_id = repositoryId;
|
|
3659
3866
|
}
|
|
3867
|
+
if (metadata?.role) body.role = metadata.role;
|
|
3868
|
+
if (metadata?.dispatch_guard) body.dispatch_guard = metadata.dispatch_guard;
|
|
3869
|
+
if (metadata?.tags) body.tags = metadata.tags;
|
|
3870
|
+
if (metadata?.owner_project) body.owner_project = metadata.owner_project;
|
|
3871
|
+
if (metadata?.integration) body.integration = metadata.integration;
|
|
3660
3872
|
const res = await apiCall(creds, "POST", "/api/v1/executors", body);
|
|
3661
3873
|
if (!res.ok) {
|
|
3662
3874
|
const err = await res.text();
|
|
@@ -3830,10 +4042,10 @@ function parseClaudeCodeOutput(line) {
|
|
|
3830
4042
|
}
|
|
3831
4043
|
|
|
3832
4044
|
// src/commands/agent-git.ts
|
|
3833
|
-
var
|
|
4045
|
+
var import_node_child_process2 = require("node:child_process");
|
|
3834
4046
|
function gitExec(cmd, cwd) {
|
|
3835
4047
|
try {
|
|
3836
|
-
return (0,
|
|
4048
|
+
return (0, import_node_child_process2.execSync)(cmd, { cwd, encoding: "utf-8", timeout: 1e4 }).trim();
|
|
3837
4049
|
} catch {
|
|
3838
4050
|
return null;
|
|
3839
4051
|
}
|
|
@@ -3986,7 +4198,7 @@ function verifyGitRemote(cwd, task, gitHost) {
|
|
|
3986
4198
|
const currentRemote = gitExec("git remote get-url origin", cwd);
|
|
3987
4199
|
if (!currentRemote) {
|
|
3988
4200
|
try {
|
|
3989
|
-
(0,
|
|
4201
|
+
(0, import_node_child_process2.execSync)(`git remote add origin ${expectedRemote}`, { cwd, timeout: 5e3 });
|
|
3990
4202
|
} catch {
|
|
3991
4203
|
}
|
|
3992
4204
|
return { remoteName: "origin", remoteUrl: expectedRemote };
|
|
@@ -3996,7 +4208,7 @@ function verifyGitRemote(cwd, task, gitHost) {
|
|
|
3996
4208
|
}
|
|
3997
4209
|
if (currentRemote.includes(gitHost)) {
|
|
3998
4210
|
try {
|
|
3999
|
-
(0,
|
|
4211
|
+
(0, import_node_child_process2.execSync)(`git remote set-url origin ${expectedRemote}`, { cwd, timeout: 5e3 });
|
|
4000
4212
|
} catch {
|
|
4001
4213
|
}
|
|
4002
4214
|
return { remoteName: "origin", remoteUrl: expectedRemote };
|
|
@@ -4004,12 +4216,12 @@ function verifyGitRemote(cwd, task, gitHost) {
|
|
|
4004
4216
|
const cvRemote = gitExec("git remote get-url cv-hub", cwd);
|
|
4005
4217
|
if (!cvRemote) {
|
|
4006
4218
|
try {
|
|
4007
|
-
(0,
|
|
4219
|
+
(0, import_node_child_process2.execSync)(`git remote add cv-hub ${expectedRemote}`, { cwd, timeout: 5e3 });
|
|
4008
4220
|
} catch {
|
|
4009
4221
|
}
|
|
4010
4222
|
} else if (cvRemote !== expectedRemote) {
|
|
4011
4223
|
try {
|
|
4012
|
-
(0,
|
|
4224
|
+
(0, import_node_child_process2.execSync)(`git remote set-url cv-hub ${expectedRemote}`, { cwd, timeout: 5e3 });
|
|
4013
4225
|
} catch {
|
|
4014
4226
|
}
|
|
4015
4227
|
}
|
|
@@ -4072,6 +4284,15 @@ ${source_default.yellow("\u26A0")} ${label} failed, retrying in ${delay}s... (${
|
|
|
4072
4284
|
var import_fs2 = require("fs");
|
|
4073
4285
|
var import_os2 = require("os");
|
|
4074
4286
|
var import_path2 = require("path");
|
|
4287
|
+
async function readWorkspaceConfig(workspaceRoot) {
|
|
4288
|
+
try {
|
|
4289
|
+
const { readFile } = await import("fs/promises");
|
|
4290
|
+
const content = await readFile((0, import_path2.join)(workspaceRoot, ".cva", "agent.json"), "utf-8");
|
|
4291
|
+
return JSON.parse(content);
|
|
4292
|
+
} catch {
|
|
4293
|
+
return {};
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4075
4296
|
function getConfigPath() {
|
|
4076
4297
|
return (0, import_path2.join)((0, import_os2.homedir)(), ".config", "cva", "config.json");
|
|
4077
4298
|
}
|
|
@@ -4090,9 +4311,9 @@ async function writeConfig(config) {
|
|
|
4090
4311
|
}
|
|
4091
4312
|
|
|
4092
4313
|
// src/commands/git-safety.ts
|
|
4093
|
-
var
|
|
4314
|
+
var import_node_child_process3 = require("node:child_process");
|
|
4094
4315
|
function git(cmd, cwd) {
|
|
4095
|
-
return (0,
|
|
4316
|
+
return (0, import_node_child_process3.execSync)(cmd, { cwd, encoding: "utf8", timeout: 3e4 }).trim();
|
|
4096
4317
|
}
|
|
4097
4318
|
function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
|
|
4098
4319
|
const targetBranch = branch || "main";
|
|
@@ -4187,12 +4408,12 @@ Files: ${added} added, ${modified} modified, ${deleted} deleted`;
|
|
|
4187
4408
|
}
|
|
4188
4409
|
|
|
4189
4410
|
// src/commands/deploy-manifest.ts
|
|
4190
|
-
var
|
|
4191
|
-
var
|
|
4192
|
-
var
|
|
4411
|
+
var import_node_child_process4 = require("node:child_process");
|
|
4412
|
+
var import_node_fs2 = require("node:fs");
|
|
4413
|
+
var import_node_path2 = require("node:path");
|
|
4193
4414
|
function exec(cmd, cwd, timeoutMs = 3e5, env2) {
|
|
4194
4415
|
try {
|
|
4195
|
-
const stdout = (0,
|
|
4416
|
+
const stdout = (0, import_node_child_process4.execSync)(cmd, {
|
|
4196
4417
|
cwd,
|
|
4197
4418
|
encoding: "utf8",
|
|
4198
4419
|
timeout: timeoutMs,
|
|
@@ -4226,16 +4447,16 @@ async function checkHealth(url, timeoutSeconds) {
|
|
|
4226
4447
|
}
|
|
4227
4448
|
function getHeadCommit(cwd) {
|
|
4228
4449
|
try {
|
|
4229
|
-
return (0,
|
|
4450
|
+
return (0, import_node_child_process4.execSync)("git rev-parse HEAD", { cwd, encoding: "utf8", timeout: 5e3 }).trim();
|
|
4230
4451
|
} catch {
|
|
4231
4452
|
return null;
|
|
4232
4453
|
}
|
|
4233
4454
|
}
|
|
4234
4455
|
function loadDeployManifest(workspaceRoot) {
|
|
4235
|
-
const manifestPath = (0,
|
|
4236
|
-
if (!(0,
|
|
4456
|
+
const manifestPath = (0, import_node_path2.join)(workspaceRoot, ".cva", "deploy.json");
|
|
4457
|
+
if (!(0, import_node_fs2.existsSync)(manifestPath)) return null;
|
|
4237
4458
|
try {
|
|
4238
|
-
const raw = (0,
|
|
4459
|
+
const raw = (0, import_node_fs2.readFileSync)(manifestPath, "utf8");
|
|
4239
4460
|
const manifest = JSON.parse(raw);
|
|
4240
4461
|
if (!manifest.version || manifest.version < 1) {
|
|
4241
4462
|
console.log(" [deploy] Invalid manifest version");
|
|
@@ -4260,7 +4481,7 @@ async function postTaskDeploy(workspaceRoot, taskId, log) {
|
|
|
4260
4481
|
console.log(` [deploy] Building: ${buildStep.name}`);
|
|
4261
4482
|
log("lifecycle", `Building: ${buildStep.name}`);
|
|
4262
4483
|
const start = Date.now();
|
|
4263
|
-
const cwd = (0,
|
|
4484
|
+
const cwd = (0, import_node_path2.join)(workspaceRoot, buildStep.working_dir || ".");
|
|
4264
4485
|
const timeoutMs = (buildStep.timeout_seconds || 300) * 1e3;
|
|
4265
4486
|
const result = exec(buildStep.command, cwd, timeoutMs);
|
|
4266
4487
|
if (!result.ok) {
|
|
@@ -4351,7 +4572,7 @@ async function rollback(workspaceRoot, targetCommit, manifest, log) {
|
|
|
4351
4572
|
}
|
|
4352
4573
|
if (manifest.build?.steps) {
|
|
4353
4574
|
for (const step of manifest.build.steps) {
|
|
4354
|
-
exec(step.command, (0,
|
|
4575
|
+
exec(step.command, (0, import_node_path2.join)(workspaceRoot, step.working_dir || "."), (step.timeout_seconds || 300) * 1e3);
|
|
4355
4576
|
}
|
|
4356
4577
|
}
|
|
4357
4578
|
if (manifest.service?.restart_command) {
|
|
@@ -4381,7 +4602,7 @@ function containsAuthError(text) {
|
|
|
4381
4602
|
}
|
|
4382
4603
|
async function checkClaudeAuth() {
|
|
4383
4604
|
try {
|
|
4384
|
-
const output = (0,
|
|
4605
|
+
const output = (0, import_node_child_process5.execSync)("claude --version 2>&1", {
|
|
4385
4606
|
encoding: "utf8",
|
|
4386
4607
|
timeout: 1e4,
|
|
4387
4608
|
env: { ...process.env }
|
|
@@ -4592,7 +4813,7 @@ async function launchAutoApproveMode(prompt, options) {
|
|
|
4592
4813
|
if (sessionId && !isContinue) {
|
|
4593
4814
|
args.push("--session-id", sessionId);
|
|
4594
4815
|
}
|
|
4595
|
-
const child = (0,
|
|
4816
|
+
const child = (0, import_node_child_process5.spawn)("claude", args, {
|
|
4596
4817
|
cwd: options.cwd,
|
|
4597
4818
|
stdio: ["inherit", "pipe", "pipe"],
|
|
4598
4819
|
env: options.spawnEnv || { ...process.env }
|
|
@@ -4726,7 +4947,7 @@ ${source_default.red("!")} Claude Code auth failure (stderr): "${authError}"`);
|
|
|
4726
4947
|
}
|
|
4727
4948
|
async function launchRelayMode(prompt, options) {
|
|
4728
4949
|
return new Promise((resolve, reject) => {
|
|
4729
|
-
const child = (0,
|
|
4950
|
+
const child = (0, import_node_child_process5.spawn)("claude", [], {
|
|
4730
4951
|
cwd: options.cwd,
|
|
4731
4952
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4732
4953
|
env: options.spawnEnv || { ...process.env }
|
|
@@ -4952,19 +5173,19 @@ async function handleSelfUpdate(task, state, creds) {
|
|
|
4952
5173
|
let output = "";
|
|
4953
5174
|
if (source === "npm" || source.startsWith("npm:")) {
|
|
4954
5175
|
const pkg = source === "npm" ? "@controlvector/cv-agent@latest" : source.replace("npm:", "");
|
|
4955
|
-
output = (0,
|
|
5176
|
+
output = (0, import_node_child_process5.execSync)(`npm install -g ${pkg} 2>&1`, { encoding: "utf8", timeout: 12e4 });
|
|
4956
5177
|
} else if (source.startsWith("git:")) {
|
|
4957
5178
|
const repoPath = source.replace("git:", "");
|
|
4958
|
-
output = (0,
|
|
5179
|
+
output = (0, import_node_child_process5.execSync)(`cd ${repoPath} && git pull && npm install && npm run build && npm link 2>&1`, {
|
|
4959
5180
|
encoding: "utf8",
|
|
4960
5181
|
timeout: 3e5
|
|
4961
5182
|
});
|
|
4962
5183
|
} else {
|
|
4963
|
-
output = (0,
|
|
5184
|
+
output = (0, import_node_child_process5.execSync)(`npm install -g @controlvector/cv-agent@latest 2>&1`, { encoding: "utf8", timeout: 12e4 });
|
|
4964
5185
|
}
|
|
4965
5186
|
let newVersion = "unknown";
|
|
4966
5187
|
try {
|
|
4967
|
-
newVersion = (0,
|
|
5188
|
+
newVersion = (0, import_node_child_process5.execSync)("cva --version 2>/dev/null || echo unknown", { encoding: "utf8" }).trim();
|
|
4968
5189
|
} catch {
|
|
4969
5190
|
}
|
|
4970
5191
|
postTaskEvent(creds, task.id, {
|
|
@@ -4990,7 +5211,7 @@ async function handleSelfUpdate(task, state, creds) {
|
|
|
4990
5211
|
if (task.input?.constraints?.includes("restart")) {
|
|
4991
5212
|
console.log(source_default.yellow("Restarting agent with updated binary..."));
|
|
4992
5213
|
const args = process.argv.slice(1).join(" ");
|
|
4993
|
-
(0,
|
|
5214
|
+
(0, import_node_child_process5.execSync)(`nohup cva ${args} > /tmp/cva-restart.log 2>&1 &`, { stdio: "ignore" });
|
|
4994
5215
|
process.exit(0);
|
|
4995
5216
|
}
|
|
4996
5217
|
} catch (err) {
|
|
@@ -5022,7 +5243,7 @@ async function runAgent(options) {
|
|
|
5022
5243
|
process.exit(1);
|
|
5023
5244
|
}
|
|
5024
5245
|
try {
|
|
5025
|
-
(0,
|
|
5246
|
+
(0, import_node_child_process5.execSync)("claude --version", { stdio: "pipe", timeout: 5e3 });
|
|
5026
5247
|
} catch {
|
|
5027
5248
|
console.log();
|
|
5028
5249
|
console.log(source_default.red("Claude Code CLI not found.") + " Install it first:");
|
|
@@ -5051,7 +5272,7 @@ async function runAgent(options) {
|
|
|
5051
5272
|
currentAuthStatus = "api_key_fallback";
|
|
5052
5273
|
}
|
|
5053
5274
|
try {
|
|
5054
|
-
(0,
|
|
5275
|
+
(0, import_node_child_process5.execSync)("cv --version", { stdio: "pipe", timeout: 5e3 });
|
|
5055
5276
|
} catch {
|
|
5056
5277
|
console.log(source_default.yellow("!") + " cv-git CLI not found. Claude Code will fall back to raw git commands.");
|
|
5057
5278
|
console.log(` Install it: ${source_default.cyan("npm install -g @controlvector/cv-git")}`);
|
|
@@ -5071,7 +5292,7 @@ async function runAgent(options) {
|
|
|
5071
5292
|
}
|
|
5072
5293
|
let detectedRepoId;
|
|
5073
5294
|
try {
|
|
5074
|
-
const remoteUrl = (0,
|
|
5295
|
+
const remoteUrl = (0, import_node_child_process5.execSync)("git remote get-url origin 2>/dev/null", {
|
|
5075
5296
|
cwd: workingDir,
|
|
5076
5297
|
encoding: "utf8",
|
|
5077
5298
|
timeout: 5e3
|
|
@@ -5092,8 +5313,47 @@ async function runAgent(options) {
|
|
|
5092
5313
|
}
|
|
5093
5314
|
} catch {
|
|
5094
5315
|
}
|
|
5316
|
+
const wsConfig = await readWorkspaceConfig(workingDir);
|
|
5317
|
+
const globalConfig = await readConfig();
|
|
5318
|
+
const role = options.role || wsConfig.role || globalConfig.role || "development";
|
|
5319
|
+
const dispatchGuard = options.dispatchGuard || wsConfig.dispatch_guard || globalConfig.dispatch_guard || "open";
|
|
5320
|
+
const tags = (options.tags?.split(",") || wsConfig.tags || globalConfig.tags)?.map((t) => t.trim()).filter(Boolean);
|
|
5321
|
+
const ownerProject = options.ownerProject || wsConfig.owner_project || globalConfig.owner_project;
|
|
5322
|
+
let integration;
|
|
5323
|
+
if (options.integration || wsConfig.integration) {
|
|
5324
|
+
if (options.integration) {
|
|
5325
|
+
const safeTasks = options.safeTasks?.split(",").map((t) => t.trim()).filter(Boolean);
|
|
5326
|
+
const unsafeTasks = safeTasks ? ["code_change", "deploy", "test", "custom"].filter((t) => !safeTasks.includes(t)) : void 0;
|
|
5327
|
+
integration = {
|
|
5328
|
+
system: options.integration,
|
|
5329
|
+
description: options.integrationDescription || `Integrated into ${options.integration}`,
|
|
5330
|
+
service_port: options.integrationPort ? parseInt(options.integrationPort, 10) : void 0,
|
|
5331
|
+
safe_task_types: safeTasks,
|
|
5332
|
+
unsafe_task_types: unsafeTasks
|
|
5333
|
+
};
|
|
5334
|
+
} else if (wsConfig.integration) {
|
|
5335
|
+
integration = wsConfig.integration;
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
const executorMeta = {
|
|
5339
|
+
role,
|
|
5340
|
+
dispatch_guard: dispatchGuard,
|
|
5341
|
+
tags,
|
|
5342
|
+
owner_project: ownerProject,
|
|
5343
|
+
integration
|
|
5344
|
+
};
|
|
5345
|
+
if (role !== "development") {
|
|
5346
|
+
console.log(source_default.yellow(` Role: ${role}`));
|
|
5347
|
+
}
|
|
5348
|
+
if (integration) {
|
|
5349
|
+
console.log(source_default.yellow(` Integration: ${integration.system}${integration.service_port ? ` (port ${integration.service_port})` : ""}`));
|
|
5350
|
+
}
|
|
5351
|
+
if (dispatchGuard !== "open") {
|
|
5352
|
+
const guardIcon = dispatchGuard === "locked" ? "\u{1F512}" : "\u26A0\uFE0F";
|
|
5353
|
+
console.log(source_default.yellow(` Guard: ${guardIcon} ${dispatchGuard}`));
|
|
5354
|
+
}
|
|
5095
5355
|
const executor = await withRetry(
|
|
5096
|
-
() => registerExecutor(creds, machineName, workingDir, detectedRepoId),
|
|
5356
|
+
() => registerExecutor(creds, machineName, workingDir, detectedRepoId, executorMeta),
|
|
5097
5357
|
"Executor registration"
|
|
5098
5358
|
);
|
|
5099
5359
|
const mode = options.autoApprove ? "auto-approve" : "relay";
|
|
@@ -5441,6 +5701,14 @@ function agentCommand() {
|
|
|
5441
5701
|
cmd.option("--poll-interval <seconds>", "How often to check for tasks, minimum 3 (default: 5)", "5");
|
|
5442
5702
|
cmd.option("--working-dir <path>", "Working directory for Claude Code (default: current directory)", ".");
|
|
5443
5703
|
cmd.option("--auto-approve", "Pre-approve all tool permissions (uses -p mode)", false);
|
|
5704
|
+
cmd.option("--role <role>", "Executor role: development, production, ci, staging");
|
|
5705
|
+
cmd.option("--integration <system>", "System this executor is integrated into (e.g. nyx-forge)");
|
|
5706
|
+
cmd.option("--integration-description <desc>", "Description of the integration");
|
|
5707
|
+
cmd.option("--integration-port <port>", "Port the integrated service runs on");
|
|
5708
|
+
cmd.option("--safe-tasks <types>", "Comma-separated task types safe for this executor (e.g. review,research)");
|
|
5709
|
+
cmd.option("--dispatch-guard <guard>", "Dispatch guard: open, confirm, locked (default: open)");
|
|
5710
|
+
cmd.option("--tags <tags>", "Comma-separated tags for this executor");
|
|
5711
|
+
cmd.option("--owner-project <project>", "Project this executor belongs to");
|
|
5444
5712
|
cmd.action(async (opts) => {
|
|
5445
5713
|
await runAgent(opts);
|
|
5446
5714
|
});
|
|
@@ -5548,7 +5816,7 @@ function authCommand() {
|
|
|
5548
5816
|
}
|
|
5549
5817
|
|
|
5550
5818
|
// src/commands/remote.ts
|
|
5551
|
-
var
|
|
5819
|
+
var import_node_child_process6 = require("node:child_process");
|
|
5552
5820
|
function getGitHost(apiUrl) {
|
|
5553
5821
|
return apiUrl.replace(/^https?:\/\//, "").replace(/^api\./, "git.");
|
|
5554
5822
|
}
|
|
@@ -5563,16 +5831,16 @@ async function remoteAdd(ownerRepo) {
|
|
|
5563
5831
|
}
|
|
5564
5832
|
const remoteUrl = `https://${gitHost}/${owner}/${repo}.git`;
|
|
5565
5833
|
try {
|
|
5566
|
-
const existing = (0,
|
|
5834
|
+
const existing = (0, import_node_child_process6.execSync)("git remote get-url cvhub", { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
5567
5835
|
if (existing === remoteUrl) {
|
|
5568
5836
|
console.log(source_default.gray(`Remote 'cvhub' already set to ${remoteUrl}`));
|
|
5569
5837
|
return;
|
|
5570
5838
|
}
|
|
5571
|
-
(0,
|
|
5839
|
+
(0, import_node_child_process6.execSync)(`git remote set-url cvhub ${remoteUrl}`, { timeout: 5e3 });
|
|
5572
5840
|
console.log(source_default.green("Updated") + ` remote 'cvhub' -> ${remoteUrl}`);
|
|
5573
5841
|
} catch {
|
|
5574
5842
|
try {
|
|
5575
|
-
(0,
|
|
5843
|
+
(0, import_node_child_process6.execSync)(`git remote add cvhub ${remoteUrl}`, { timeout: 5e3 });
|
|
5576
5844
|
console.log(source_default.green("Added") + ` remote 'cvhub' -> ${remoteUrl}`);
|
|
5577
5845
|
} catch (err) {
|
|
5578
5846
|
console.log(source_default.red("Failed to add remote:") + ` ${err.message}`);
|
|
@@ -5764,7 +6032,8 @@ function statusCommand() {
|
|
|
5764
6032
|
|
|
5765
6033
|
// src/index.ts
|
|
5766
6034
|
var program2 = new Command();
|
|
5767
|
-
program2.name("cva").description(
|
|
6035
|
+
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.7.0" : "1.6.0");
|
|
6036
|
+
program2.addCommand(setupCommand());
|
|
5768
6037
|
program2.addCommand(agentCommand());
|
|
5769
6038
|
program2.addCommand(authCommand());
|
|
5770
6039
|
program2.addCommand(remoteCommand());
|