@controlvector/cv-agent 1.8.0 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bundle.cjs CHANGED
@@ -3834,18 +3834,84 @@ async function runSetup() {
3834
3834
  console.log(source_default.gray(' Click "Add Integration" \u2192 "Allow" when prompted.'));
3835
3835
  console.log(source_default.gray(" (You can do this later \u2014 setup will continue.)"));
3836
3836
  console.log();
3837
- const cwd = process.cwd();
3838
- const isGitRepo = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".git"));
3839
- const hasCVDir = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cv"));
3840
- const hasClaudeMd = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, "CLAUDE.md"));
3841
- const repoName = (0, import_node_path.basename)(cwd);
3837
+ let cwd = process.cwd();
3838
+ let isGitRepo = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".git"));
3839
+ let repoName = (0, import_node_path.basename)(cwd);
3842
3840
  if (isGitRepo) {
3843
3841
  console.log(source_default.green(" \u2713") + ` Git repo found: ${repoName}`);
3844
3842
  } else {
3845
- console.log(" Initializing git repository...");
3846
- (0, import_node_child_process.execSync)("git init && git checkout -b main", { cwd, stdio: "pipe" });
3847
- console.log(source_default.green(" \u2713") + " Git repo initialized");
3843
+ const readline = await import("node:readline");
3844
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
3845
+ console.log(" No git repository found in this directory.");
3846
+ console.log();
3847
+ console.log(` ${source_default.cyan("a")} \u2014 Initialize a new project here: ${cwd}`);
3848
+ console.log(` ${source_default.cyan("b")} \u2014 Clone an existing repo from CV-Hub`);
3849
+ console.log();
3850
+ const choice = await new Promise((resolve2) => {
3851
+ rl.question(" Choose [a/b]: ", (answer) => {
3852
+ rl.close();
3853
+ resolve2(answer.trim().toLowerCase() || "a");
3854
+ });
3855
+ });
3856
+ if (choice === "b" && token) {
3857
+ try {
3858
+ console.log(source_default.gray(" Fetching your repositories..."));
3859
+ const controller = new AbortController();
3860
+ const timeout = setTimeout(() => controller.abort(), 15e3);
3861
+ const res = await fetch(`${hubUrl}/api/v1/repos?limit=50`, {
3862
+ headers: { Authorization: `Bearer ${token}` },
3863
+ signal: controller.signal
3864
+ });
3865
+ clearTimeout(timeout);
3866
+ if (res.ok) {
3867
+ const data = await res.json();
3868
+ const repos = data.repositories || [];
3869
+ if (repos.length === 0) {
3870
+ console.log(source_default.yellow(" No repos found on CV-Hub. Initializing a new project instead."));
3871
+ } else {
3872
+ console.log();
3873
+ console.log(" Your CV-Hub repositories:");
3874
+ const displayRepos = repos.slice(0, 20);
3875
+ displayRepos.forEach((r, i) => {
3876
+ const desc = r.description ? source_default.gray(` \u2014 ${r.description.substring(0, 40)}`) : "";
3877
+ console.log(` ${source_default.cyan(String(i + 1).padStart(2))}. ${r.slug || r.name}${desc}`);
3878
+ });
3879
+ console.log();
3880
+ const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
3881
+ const selection = await new Promise((resolve2) => {
3882
+ rl2.question(` Select a repo [1-${displayRepos.length}]: `, (answer) => {
3883
+ rl2.close();
3884
+ resolve2(answer.trim());
3885
+ });
3886
+ });
3887
+ const idx = parseInt(selection, 10) - 1;
3888
+ if (idx >= 0 && idx < displayRepos.length) {
3889
+ const repo = displayRepos[idx];
3890
+ const gitHost = "git.hub.controlvector.io";
3891
+ const slug = repo.slug || repo.name;
3892
+ const cloneUrl = `https://${username}:${token}@${gitHost}/${username}/${slug}.git`;
3893
+ console.log(source_default.gray(` Cloning ${username}/${slug}...`));
3894
+ (0, import_node_child_process.execSync)(`git clone ${cloneUrl} ${slug}`, { cwd, stdio: "pipe", timeout: 6e4 });
3895
+ cwd = (0, import_node_path.join)(cwd, slug);
3896
+ process.chdir(cwd);
3897
+ repoName = slug;
3898
+ isGitRepo = true;
3899
+ console.log(source_default.green(" \u2713") + ` Cloned ${username}/${slug}`);
3900
+ }
3901
+ }
3902
+ }
3903
+ } catch (err) {
3904
+ console.log(source_default.yellow(` Could not fetch repos: ${err.message}. Initializing instead.`));
3905
+ }
3906
+ }
3907
+ if (!isGitRepo) {
3908
+ console.log(" Initializing git repository...");
3909
+ (0, import_node_child_process.execSync)("git init && git checkout -b main", { cwd, stdio: "pipe" });
3910
+ console.log(source_default.green(" \u2713") + " Git repo initialized");
3911
+ }
3848
3912
  }
3913
+ const hasClaudeMd = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, "CLAUDE.md"));
3914
+ const hasCVDir = (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cv"));
3849
3915
  if (!hasClaudeMd) {
3850
3916
  const template = `# ${repoName}
3851
3917
 
@@ -3933,16 +3999,76 @@ async function runSetup() {
3933
3999
  }
3934
4000
  }
3935
4001
  console.log();
4002
+ let agentStatus = "";
4003
+ const pidFile = (0, import_node_path.join)((0, import_node_os2.homedir)(), ".config", "controlvector", "agent.pid");
4004
+ let agentRunning = false;
4005
+ try {
4006
+ const pid = parseInt((0, import_node_fs.readFileSync)(pidFile, "utf-8").trim(), 10);
4007
+ if (pid > 0) {
4008
+ process.kill(pid, 0);
4009
+ agentRunning = true;
4010
+ agentStatus = `running (PID ${pid})`;
4011
+ console.log(source_default.green(" \u2713") + ` Agent already running (PID ${pid})`);
4012
+ }
4013
+ } catch {
4014
+ }
4015
+ if (!agentRunning) {
4016
+ const readline = await import("node:readline");
4017
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4018
+ const answer = await new Promise((resolve2) => {
4019
+ rl.question(" Start the CV-Agent daemon? (Y/n): ", (a) => {
4020
+ rl.close();
4021
+ resolve2(a.trim().toLowerCase() || "y");
4022
+ });
4023
+ });
4024
+ if (answer === "y" || answer === "yes" || answer === "") {
4025
+ const machName = (0, import_node_os2.hostname)().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
4026
+ console.log(source_default.gray(` Starting agent as "${machName}"...`));
4027
+ try {
4028
+ const { spawn: spawnChild } = await import("node:child_process");
4029
+ const child = spawnChild("cva", [
4030
+ "agent",
4031
+ "--auto-approve",
4032
+ "--machine",
4033
+ machName,
4034
+ "--working-dir",
4035
+ cwd
4036
+ ], {
4037
+ detached: true,
4038
+ stdio: "ignore",
4039
+ env: { ...process.env }
4040
+ });
4041
+ child.unref();
4042
+ if (child.pid) {
4043
+ (0, import_node_fs.mkdirSync)((0, import_node_path.join)((0, import_node_os2.homedir)(), ".config", "controlvector"), { recursive: true });
4044
+ (0, import_node_fs.writeFileSync)(pidFile, String(child.pid), { mode: 384 });
4045
+ agentStatus = `running (PID ${child.pid})`;
4046
+ console.log(source_default.green(" \u2713") + ` Agent started (PID ${child.pid}) \u2014 executor "${machName}"`);
4047
+ }
4048
+ } catch (err) {
4049
+ console.log(source_default.yellow(` Could not start agent: ${err.message}`));
4050
+ console.log(source_default.gray(" Start manually with: cva agent --auto-approve"));
4051
+ agentStatus = "not started";
4052
+ }
4053
+ } else {
4054
+ agentStatus = "not started";
4055
+ console.log(source_default.gray(" Start anytime with: cva agent --auto-approve"));
4056
+ }
4057
+ }
4058
+ console.log();
3936
4059
  console.log(source_default.bold(" Setup Complete"));
3937
4060
  console.log(source_default.gray(" " + "\u2500".repeat(40)));
3938
4061
  console.log(` ${source_default.green("\u2713")} Authenticated as: ${source_default.cyan(username)}`);
3939
4062
  console.log(` ${source_default.green("\u2713")} Repository: ${source_default.cyan(repoName)}`);
3940
4063
  console.log(` ${source_default.green("\u2713")} CLAUDE.md: present`);
4064
+ if (agentStatus.startsWith("running")) {
4065
+ console.log(` ${source_default.green("\u2713")} Agent daemon: ${source_default.cyan(agentStatus)}`);
4066
+ }
3941
4067
  console.log(source_default.gray(" " + "\u2500".repeat(40)));
3942
4068
  console.log();
3943
4069
  console.log(" What's next:");
3944
- console.log(` ${source_default.cyan("cva agent --auto-approve")} \u2014 Start listening for tasks`);
3945
- console.log(` Or open Claude.ai and dispatch a task to this repo.`);
4070
+ console.log(" Open Claude.ai and try:");
4071
+ console.log(source_default.cyan(` "Create a task in ${repoName} to add a hello world index.html"`));
3946
4072
  console.log();
3947
4073
  console.log(source_default.gray(` Dashboard: ${appUrl}`));
3948
4074
  console.log();
@@ -4432,11 +4558,78 @@ async function writeConfig(config) {
4432
4558
 
4433
4559
  // src/commands/git-safety.ts
4434
4560
  var import_node_child_process3 = require("node:child_process");
4561
+ var import_node_fs2 = require("node:fs");
4562
+ var import_node_path2 = require("node:path");
4563
+ var import_node_os3 = require("node:os");
4564
+ var DANGEROUS_PATTERNS = [
4565
+ ".claude/",
4566
+ ".claude.json",
4567
+ ".credentials",
4568
+ ".zsh_history",
4569
+ ".bash_history",
4570
+ ".zsh_sessions/",
4571
+ ".ssh/",
4572
+ ".gnupg/",
4573
+ ".npm/",
4574
+ ".config/",
4575
+ ".CFUserTextEncoding",
4576
+ "Library/",
4577
+ "Applications/",
4578
+ ".Trash/",
4579
+ ".DS_Store",
4580
+ "node_modules/",
4581
+ ".env",
4582
+ ".env.local",
4583
+ ".env.production"
4584
+ ];
4435
4585
  function git(cmd, cwd) {
4436
4586
  return (0, import_node_child_process3.execSync)(cmd, { cwd, encoding: "utf8", timeout: 3e4 }).trim();
4437
4587
  }
4588
+ function checkWorkspaceSafety(workspaceRoot) {
4589
+ const resolved = (0, import_node_path2.resolve)(workspaceRoot);
4590
+ const home = (0, import_node_path2.resolve)((0, import_node_os3.homedir)());
4591
+ if (resolved === home) {
4592
+ return `Workspace is user HOME directory (${home}). Refusing to auto-commit to prevent indexing personal files.`;
4593
+ }
4594
+ if (home.startsWith(resolved + "/")) {
4595
+ return `Workspace (${resolved}) is a parent of HOME. Refusing to auto-commit.`;
4596
+ }
4597
+ if (!(0, import_node_fs2.existsSync)((0, import_node_path2.join)(resolved, ".git"))) {
4598
+ return `No .git directory in ${resolved}. Not a git repository.`;
4599
+ }
4600
+ return null;
4601
+ }
4602
+ function filterDangerousFiles(statusLines) {
4603
+ const safe = [];
4604
+ const blocked = [];
4605
+ for (const line of statusLines) {
4606
+ const filePath = line.substring(3).trim();
4607
+ const isDangerous = DANGEROUS_PATTERNS.some(
4608
+ (pattern) => filePath.startsWith(pattern) || filePath.includes("/" + pattern)
4609
+ );
4610
+ if (isDangerous) {
4611
+ blocked.push(filePath);
4612
+ } else {
4613
+ safe.push(line);
4614
+ }
4615
+ }
4616
+ return { safe, blocked };
4617
+ }
4438
4618
  function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
4439
4619
  const targetBranch = branch || "main";
4620
+ const safetyError = checkWorkspaceSafety(workspaceRoot);
4621
+ if (safetyError) {
4622
+ console.log(` [git-safety] BLOCKED: ${safetyError}`);
4623
+ return {
4624
+ hadChanges: false,
4625
+ filesAdded: 0,
4626
+ filesModified: 0,
4627
+ filesDeleted: 0,
4628
+ pushed: false,
4629
+ skipped: true,
4630
+ skipReason: safetyError
4631
+ };
4632
+ }
4440
4633
  try {
4441
4634
  let statusOutput;
4442
4635
  try {
@@ -4444,8 +4637,8 @@ function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
4444
4637
  } catch {
4445
4638
  return { hadChanges: false, filesAdded: 0, filesModified: 0, filesDeleted: 0, pushed: false, error: "git status failed" };
4446
4639
  }
4447
- const lines = statusOutput.split("\n").filter(Boolean);
4448
- if (lines.length === 0) {
4640
+ const allLines = statusOutput.split("\n").filter(Boolean);
4641
+ if (allLines.length === 0) {
4449
4642
  try {
4450
4643
  const unpushed = git(`git log origin/${targetBranch}..HEAD --oneline 2>/dev/null`, workspaceRoot);
4451
4644
  if (unpushed) {
@@ -4457,8 +4650,16 @@ function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
4457
4650
  }
4458
4651
  return { hadChanges: false, filesAdded: 0, filesModified: 0, filesDeleted: 0, pushed: false };
4459
4652
  }
4653
+ const { safe: safeLines, blocked } = filterDangerousFiles(allLines);
4654
+ if (blocked.length > 0) {
4655
+ console.log(` [git-safety] Blocked ${blocked.length} sensitive file(s) from staging: ${blocked.slice(0, 5).join(", ")}${blocked.length > 5 ? "..." : ""}`);
4656
+ }
4657
+ if (safeLines.length === 0) {
4658
+ console.log(` [git-safety] All ${allLines.length} changed files were blocked by safety filter`);
4659
+ return { hadChanges: false, filesAdded: 0, filesModified: 0, filesDeleted: 0, pushed: false };
4660
+ }
4460
4661
  let added = 0, modified = 0, deleted = 0;
4461
- for (const line of lines) {
4662
+ for (const line of safeLines) {
4462
4663
  const code = line.substring(0, 2);
4463
4664
  if (code.includes("?")) added++;
4464
4665
  else if (code.includes("D")) deleted++;
@@ -4466,9 +4667,15 @@ function gitSafetyNet(workspaceRoot, taskTitle, taskId, branch) {
4466
4667
  else added++;
4467
4668
  }
4468
4669
  console.log(
4469
- ` [git-safety] ${lines.length} uncommitted changes (${added} new, ${modified} modified, ${deleted} deleted) \u2014 committing now`
4670
+ ` [git-safety] ${safeLines.length} safe changes (${added} new, ${modified} modified, ${deleted} deleted) \u2014 committing now`
4470
4671
  );
4471
- git("git add -A", workspaceRoot);
4672
+ for (const line of safeLines) {
4673
+ const filePath = line.substring(3).trim();
4674
+ try {
4675
+ git(`git add -- ${JSON.stringify(filePath)}`, workspaceRoot);
4676
+ } catch {
4677
+ }
4678
+ }
4472
4679
  const shortId = taskId.substring(0, 8);
4473
4680
  const commitMsg = `task: ${taskTitle} [${shortId}]
4474
4681
 
@@ -4529,8 +4736,8 @@ Files: ${added} added, ${modified} modified, ${deleted} deleted`;
4529
4736
 
4530
4737
  // src/commands/deploy-manifest.ts
4531
4738
  var import_node_child_process4 = require("node:child_process");
4532
- var import_node_fs2 = require("node:fs");
4533
- var import_node_path2 = require("node:path");
4739
+ var import_node_fs3 = require("node:fs");
4740
+ var import_node_path3 = require("node:path");
4534
4741
  function exec(cmd, cwd, timeoutMs = 3e5, env2) {
4535
4742
  try {
4536
4743
  const stdout = (0, import_node_child_process4.execSync)(cmd, {
@@ -4573,10 +4780,10 @@ function getHeadCommit(cwd) {
4573
4780
  }
4574
4781
  }
4575
4782
  function loadDeployManifest(workspaceRoot) {
4576
- const manifestPath = (0, import_node_path2.join)(workspaceRoot, ".cva", "deploy.json");
4577
- if (!(0, import_node_fs2.existsSync)(manifestPath)) return null;
4783
+ const manifestPath = (0, import_node_path3.join)(workspaceRoot, ".cva", "deploy.json");
4784
+ if (!(0, import_node_fs3.existsSync)(manifestPath)) return null;
4578
4785
  try {
4579
- const raw = (0, import_node_fs2.readFileSync)(manifestPath, "utf8");
4786
+ const raw = (0, import_node_fs3.readFileSync)(manifestPath, "utf8");
4580
4787
  const manifest = JSON.parse(raw);
4581
4788
  if (!manifest.version || manifest.version < 1) {
4582
4789
  console.log(" [deploy] Invalid manifest version");
@@ -4601,7 +4808,7 @@ async function postTaskDeploy(workspaceRoot, taskId, log) {
4601
4808
  console.log(` [deploy] Building: ${buildStep.name}`);
4602
4809
  log("lifecycle", `Building: ${buildStep.name}`);
4603
4810
  const start = Date.now();
4604
- const cwd = (0, import_node_path2.join)(workspaceRoot, buildStep.working_dir || ".");
4811
+ const cwd = (0, import_node_path3.join)(workspaceRoot, buildStep.working_dir || ".");
4605
4812
  const timeoutMs = (buildStep.timeout_seconds || 300) * 1e3;
4606
4813
  const result = exec(buildStep.command, cwd, timeoutMs);
4607
4814
  if (!result.ok) {
@@ -4692,7 +4899,7 @@ async function rollback(workspaceRoot, targetCommit, manifest, log) {
4692
4899
  }
4693
4900
  if (manifest.build?.steps) {
4694
4901
  for (const step of manifest.build.steps) {
4695
- exec(step.command, (0, import_node_path2.join)(workspaceRoot, step.working_dir || "."), (step.timeout_seconds || 300) * 1e3);
4902
+ exec(step.command, (0, import_node_path3.join)(workspaceRoot, step.working_dir || "."), (step.timeout_seconds || 300) * 1e3);
4696
4903
  }
4697
4904
  }
4698
4905
  if (manifest.service?.restart_command) {
@@ -4928,7 +5135,7 @@ async function launchAutoApproveMode(prompt, options) {
4928
5135
  let fullOutput = "";
4929
5136
  let lastProgressBytes = 0;
4930
5137
  const runOnce = (inputPrompt, isContinue) => {
4931
- return new Promise((resolve, reject) => {
5138
+ return new Promise((resolve2, reject) => {
4932
5139
  const args = isContinue ? ["-p", inputPrompt, "--continue", "--allowedTools", ...ALLOWED_TOOLS] : ["-p", inputPrompt, "--allowedTools", ...ALLOWED_TOOLS];
4933
5140
  if (sessionId && !isContinue) {
4934
5141
  args.push("--session-id", sessionId);
@@ -5027,7 +5234,7 @@ ${source_default.red("!")} Claude Code auth failure (stderr): "${authError}"`);
5027
5234
  });
5028
5235
  child.on("close", (code, signal) => {
5029
5236
  _activeChild = null;
5030
- resolve({
5237
+ resolve2({
5031
5238
  exitCode: signal === "SIGKILL" ? 137 : code ?? 1,
5032
5239
  stderr,
5033
5240
  output: fullOutput,
@@ -5066,7 +5273,7 @@ ${source_default.red("!")} Claude Code auth failure (stderr): "${authError}"`);
5066
5273
  return result;
5067
5274
  }
5068
5275
  async function launchRelayMode(prompt, options) {
5069
- return new Promise((resolve, reject) => {
5276
+ return new Promise((resolve2, reject) => {
5070
5277
  const child = (0, import_node_child_process5.spawn)("claude", [], {
5071
5278
  cwd: options.cwd,
5072
5279
  stdio: ["pipe", "pipe", "pipe"],
@@ -5259,9 +5466,9 @@ ${source_default.red("!")} Claude Code auth failure (stderr): "${authError}"`);
5259
5466
  child.on("close", (code, signal) => {
5260
5467
  _activeChild = null;
5261
5468
  if (signal === "SIGKILL") {
5262
- resolve({ exitCode: 137, stderr, output: fullOutput, authFailure });
5469
+ resolve2({ exitCode: 137, stderr, output: fullOutput, authFailure });
5263
5470
  } else {
5264
- resolve({ exitCode: code ?? 1, stderr, output: fullOutput, authFailure });
5471
+ resolve2({ exitCode: code ?? 1, stderr, output: fullOutput, authFailure });
5265
5472
  }
5266
5473
  });
5267
5474
  child.on("error", (err) => {
@@ -5362,14 +5569,45 @@ async function runAgent(options) {
5362
5569
  console.log();
5363
5570
  process.exit(1);
5364
5571
  }
5572
+ if (process.env.CV_DEBUG) {
5573
+ console.log(source_default.gray(` PATH: ${process.env.PATH}`));
5574
+ console.log(source_default.gray(` HOME: ${process.env.HOME}`));
5575
+ console.log(source_default.gray(` SHELL: ${process.env.SHELL}`));
5576
+ }
5577
+ let claudeBinary = "claude";
5365
5578
  try {
5366
5579
  (0, import_node_child_process5.execSync)("claude --version", { stdio: "pipe", timeout: 5e3 });
5367
5580
  } catch {
5368
- console.log();
5369
- console.log(source_default.red("Claude Code CLI not found.") + " Install it first:");
5370
- console.log(` ${source_default.cyan("npm install -g @anthropic-ai/claude-code")}`);
5371
- console.log();
5372
- process.exit(1);
5581
+ const candidates = [
5582
+ "/usr/local/bin/claude",
5583
+ "/opt/homebrew/bin/claude",
5584
+ `${process.env.HOME}/.npm-global/bin/claude`,
5585
+ `${process.env.HOME}/.nvm/versions/node/*/bin/claude`
5586
+ ];
5587
+ let found = false;
5588
+ for (const candidate of candidates) {
5589
+ try {
5590
+ const resolved = (0, import_node_child_process5.execSync)(`ls ${candidate} 2>/dev/null | head -1`, { encoding: "utf8", timeout: 3e3 }).trim();
5591
+ if (resolved) {
5592
+ (0, import_node_child_process5.execSync)(`${resolved} --version`, { stdio: "pipe", timeout: 5e3 });
5593
+ claudeBinary = resolved;
5594
+ found = true;
5595
+ console.log(source_default.yellow("!") + ` Claude Code found at ${resolved} (not on PATH)`);
5596
+ break;
5597
+ }
5598
+ } catch {
5599
+ }
5600
+ }
5601
+ if (!found) {
5602
+ console.log();
5603
+ console.log(source_default.red("Claude Code CLI not found.") + " Install it first:");
5604
+ console.log(` ${source_default.cyan("npm install -g @anthropic-ai/claude-code")}`);
5605
+ console.log();
5606
+ console.log(source_default.gray(` Current PATH: ${process.env.PATH}`));
5607
+ console.log(source_default.gray(" If running via Launch Agent, ensure PATH includes the directory where claude is installed."));
5608
+ console.log();
5609
+ process.exit(1);
5610
+ }
5373
5611
  }
5374
5612
  const { env: claudeEnv, usingApiKey } = await getClaudeEnv();
5375
5613
  const authCheck = await checkClaudeAuth();
@@ -5410,6 +5648,64 @@ async function runAgent(options) {
5410
5648
  console.log();
5411
5649
  }
5412
5650
  }
5651
+ {
5652
+ const isGitRepo = require("fs").existsSync(require("path").join(workingDir, ".git"));
5653
+ if (!isGitRepo) {
5654
+ console.log(source_default.gray(" Bootstrap: initializing git repo..."));
5655
+ try {
5656
+ (0, import_node_child_process5.execSync)("git init && git checkout -b main", { cwd: workingDir, stdio: "pipe" });
5657
+ } catch {
5658
+ }
5659
+ }
5660
+ const claudeMdPath = require("path").join(workingDir, "CLAUDE.md");
5661
+ if (!require("fs").existsSync(claudeMdPath)) {
5662
+ const name = require("path").basename(workingDir);
5663
+ const template = `# ${name}
5664
+
5665
+ ## Overview
5666
+ [Describe your project here]
5667
+
5668
+ ## Build & Run
5669
+ [How to build and run this project]
5670
+ `;
5671
+ try {
5672
+ require("fs").writeFileSync(claudeMdPath, template);
5673
+ console.log(source_default.gray(" Bootstrap: created CLAUDE.md"));
5674
+ } catch {
5675
+ }
5676
+ }
5677
+ const cvDir = require("path").join(workingDir, ".cv");
5678
+ if (!require("fs").existsSync(cvDir)) {
5679
+ try {
5680
+ require("fs").mkdirSync(cvDir, { recursive: true });
5681
+ } catch {
5682
+ }
5683
+ }
5684
+ if (creds.CV_HUB_PAT) {
5685
+ try {
5686
+ const existing = (0, import_node_child_process5.execSync)('git remote get-url cv-hub 2>/dev/null || echo ""', {
5687
+ cwd: workingDir,
5688
+ encoding: "utf8",
5689
+ timeout: 5e3
5690
+ }).trim();
5691
+ if (!existing) {
5692
+ const name = require("path").basename(workingDir);
5693
+ const gitHost = "git.hub.controlvector.io";
5694
+ let user = "user";
5695
+ try {
5696
+ const sharedPath = require("path").join(require("os").homedir(), ".config", "controlvector", "credentials.json");
5697
+ const shared = JSON.parse(require("fs").readFileSync(sharedPath, "utf-8"));
5698
+ if (shared.username) user = shared.username;
5699
+ } catch {
5700
+ }
5701
+ const remoteUrl = `https://${gitHost}/${user}/${name}.git`;
5702
+ (0, import_node_child_process5.execSync)(`git remote add cv-hub ${remoteUrl}`, { cwd: workingDir, stdio: "pipe" });
5703
+ console.log(source_default.gray(` Bootstrap: remote cv-hub \u2192 ${remoteUrl}`));
5704
+ }
5705
+ } catch {
5706
+ }
5707
+ }
5708
+ }
5413
5709
  let detectedRepoId;
5414
5710
  try {
5415
5711
  const remoteUrl = (0, import_node_child_process5.execSync)("git remote get-url origin 2>/dev/null", {
@@ -5865,7 +6161,7 @@ async function promptForToken() {
5865
6161
  input: process.stdin,
5866
6162
  output: process.stdout
5867
6163
  });
5868
- return new Promise((resolve) => {
6164
+ return new Promise((resolve2) => {
5869
6165
  rl.question("Enter your CV-Hub PAT token: ", (answer) => {
5870
6166
  rl.close();
5871
6167
  const token = answer.trim();
@@ -5873,7 +6169,7 @@ async function promptForToken() {
5873
6169
  console.log(source_default.red("No token provided."));
5874
6170
  process.exit(1);
5875
6171
  }
5876
- resolve(token);
6172
+ resolve2(token);
5877
6173
  });
5878
6174
  });
5879
6175
  }
@@ -6152,7 +6448,7 @@ function statusCommand() {
6152
6448
 
6153
6449
  // src/index.ts
6154
6450
  var program2 = new Command();
6155
- 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.8.0" : "1.6.0");
6451
+ 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.9.1" : "1.6.0");
6156
6452
  program2.addCommand(setupCommand());
6157
6453
  program2.addCommand(agentCommand());
6158
6454
  program2.addCommand(authCommand());