@autoclawd/autoclawd 1.1.4 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -712,6 +712,7 @@ import { PassThrough } from "stream";
712
712
  import { homedir as homedir3, platform } from "os";
713
713
  import { join as join4 } from "path";
714
714
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
715
+ import { execSync as execSync2 } from "child_process";
715
716
  var docker = new Docker();
716
717
  async function checkDockerAvailable() {
717
718
  try {
@@ -770,7 +771,10 @@ async function createContainer(opts) {
770
771
  NanoCpus: dockerConfig.cpus ? dockerConfig.cpus * 1e9 : void 0,
771
772
  NetworkMode: dockerConfig.network ?? "bridge"
772
773
  },
773
- Env: ["HOME=/root"]
774
+ Env: [
775
+ "HOME=/root",
776
+ ...process.env.ANTHROPIC_API_KEY ? [`ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY}`] : []
777
+ ]
774
778
  });
775
779
  await container.start();
776
780
  log.info(`Container ${name} started (${container.id.slice(0, 12)})`);
@@ -911,16 +915,33 @@ async function copyClaudeCredentials(container) {
911
915
  "-c",
912
916
  "mkdir -p /home/autoclawd/.claude && chown autoclawd /home/autoclawd/.claude"
913
917
  ]);
918
+ let credJson;
914
919
  const credFile = join4(home, ".claude", ".credentials.json");
915
920
  if (existsSync3(credFile)) {
916
- const content = readFileSync2(credFile, "utf-8");
917
- const b64 = Buffer.from(content).toString("base64");
921
+ credJson = readFileSync2(credFile, "utf-8");
922
+ log.debug("Read credentials from file");
923
+ } else if (platform() === "darwin") {
924
+ try {
925
+ credJson = execSync2('security find-generic-password -s "Claude Code-credentials" -w', {
926
+ stdio: "pipe",
927
+ encoding: "utf-8",
928
+ timeout: 5e3
929
+ }).trim();
930
+ log.debug("Read credentials from macOS Keychain");
931
+ } catch {
932
+ }
933
+ }
934
+ if (credJson) {
935
+ const b64 = Buffer.from(credJson).toString("base64");
918
936
  await exec(container, [
919
937
  "sh",
920
938
  "-c",
921
939
  `echo '${b64}' | base64 -d > /home/autoclawd/.claude/.credentials.json && chown autoclawd /home/autoclawd/.claude/.credentials.json`
922
940
  ]);
923
- log.debug("Copied .credentials.json");
941
+ } else if (process.env.ANTHROPIC_API_KEY) {
942
+ log.debug("Using ANTHROPIC_API_KEY env var for container auth");
943
+ } else {
944
+ log.warn("No Claude credentials found. Run: claude (to log in)");
924
945
  }
925
946
  const settingsFile = join4(home, ".claude", "settings.json");
926
947
  if (existsSync3(settingsFile)) {
@@ -1199,7 +1220,7 @@ async function commitAndPush(container, opts) {
1199
1220
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
1200
1221
  import { join as join6 } from "path";
1201
1222
  import { tmpdir as tmpdir2 } from "os";
1202
- import { execSync as execSync2 } from "child_process";
1223
+ import { execSync as execSync3 } from "child_process";
1203
1224
 
1204
1225
  // src/db.ts
1205
1226
  import Database from "better-sqlite3";
@@ -1387,7 +1408,7 @@ function detectDefaultBranch2(repoUrl, githubToken) {
1387
1408
  const askpass = createAskpass2(githubToken);
1388
1409
  const authedUrl = repoUrl.replace("https://", "https://x-access-token@");
1389
1410
  try {
1390
- const output = execSync2(
1411
+ const output = execSync3(
1391
1412
  `git ls-remote --symref -- ${authedUrl} HEAD`,
1392
1413
  { stdio: "pipe", timeout: 3e4, env: gitEnv2(askpass.path), encoding: "utf-8" }
1393
1414
  );
@@ -1411,14 +1432,14 @@ async function pushScaffold(opts) {
1411
1432
  }
1412
1433
  writeFileSync2(join6(scaffoldDir, "README.md"), readmeLines.join("\n") + "\n");
1413
1434
  writeFileSync2(join6(scaffoldDir, ".autoclawd.yaml"), "base: main\n");
1414
- execSync2("git init", { cwd: scaffoldDir, stdio: "pipe", env });
1415
- execSync2("git checkout -b main", { cwd: scaffoldDir, stdio: "pipe", env });
1416
- execSync2('git config user.email "autoclawd@users.noreply.github.com"', { cwd: scaffoldDir, stdio: "pipe", env });
1417
- execSync2('git config user.name "autoclawd"', { cwd: scaffoldDir, stdio: "pipe", env });
1418
- execSync2("git add .", { cwd: scaffoldDir, stdio: "pipe", env });
1419
- execSync2('git commit -m "chore: initial scaffold"', { cwd: scaffoldDir, stdio: "pipe", env });
1420
- execSync2(`git remote add origin ${authedUrl}`, { cwd: scaffoldDir, stdio: "pipe", env });
1421
- execSync2("git push -u origin main", { cwd: scaffoldDir, stdio: "pipe", timeout: 6e4, env });
1435
+ execSync3("git init", { cwd: scaffoldDir, stdio: "pipe", env });
1436
+ execSync3("git checkout -b main", { cwd: scaffoldDir, stdio: "pipe", env });
1437
+ execSync3('git config user.email "autoclawd@users.noreply.github.com"', { cwd: scaffoldDir, stdio: "pipe", env });
1438
+ execSync3('git config user.name "autoclawd"', { cwd: scaffoldDir, stdio: "pipe", env });
1439
+ execSync3("git add .", { cwd: scaffoldDir, stdio: "pipe", env });
1440
+ execSync3('git commit -m "chore: initial scaffold"', { cwd: scaffoldDir, stdio: "pipe", env });
1441
+ execSync3(`git remote add origin ${authedUrl}`, { cwd: scaffoldDir, stdio: "pipe", env });
1442
+ execSync3("git push -u origin main", { cwd: scaffoldDir, stdio: "pipe", timeout: 6e4, env });
1422
1443
  } finally {
1423
1444
  rmSync2(scaffoldDir, { recursive: true, force: true });
1424
1445
  rmSync2(askpass.dir, { recursive: true, force: true });
@@ -1431,7 +1452,7 @@ async function cloneToTemp(repoUrl, baseBranch, githubToken) {
1431
1452
  const askpass = createAskpass2(githubToken);
1432
1453
  const authedUrl = repoUrl.replace("https://", "https://x-access-token@");
1433
1454
  try {
1434
- execSync2(`git clone --depth=50 -b ${baseBranch} -- ${authedUrl} ${workDir}`, {
1455
+ execSync3(`git clone --depth=50 -b ${baseBranch} -- ${authedUrl} ${workDir}`, {
1435
1456
  stdio: "pipe",
1436
1457
  timeout: 12e4,
1437
1458
  env: gitEnv2(askpass.path)
@@ -1608,7 +1629,7 @@ async function executeTicket(opts) {
1608
1629
  throw err;
1609
1630
  }
1610
1631
  }
1611
- execSync2(`git checkout -B ${branchName} --`, { cwd: workDir, stdio: "pipe" });
1632
+ execSync3(`git checkout -B ${branchName} --`, { cwd: workDir, stdio: "pipe" });
1612
1633
  container = await createContainer({
1613
1634
  dockerConfig: docker2,
1614
1635
  workspacePath: workDir,
@@ -2397,7 +2418,7 @@ function printHistoryTable(records) {
2397
2418
  }
2398
2419
 
2399
2420
  // src/deps.ts
2400
- import { execSync as execSync3 } from "child_process";
2421
+ import { execSync as execSync4 } from "child_process";
2401
2422
  import { existsSync as existsSync6 } from "fs";
2402
2423
  import { join as join8 } from "path";
2403
2424
  import { homedir as homedir5 } from "os";
@@ -2417,7 +2438,7 @@ function checkDeps() {
2417
2438
  {
2418
2439
  name: "Claude credentials",
2419
2440
  installed: hasClaudeAuth(),
2420
- instructions: "Run: claude (and complete the login flow)"
2441
+ instructions: 'export ANTHROPIC_API_KEY="sk-ant-..." (from console.anthropic.com)\n Or run: claude (and complete the login flow)'
2421
2442
  },
2422
2443
  {
2423
2444
  name: "cloudflared",
@@ -2427,21 +2448,26 @@ function checkDeps() {
2427
2448
  ];
2428
2449
  }
2429
2450
  function hasClaudeAuth() {
2430
- const credPaths = [
2431
- join8(homedir5(), ".claude", ".credentials.json"),
2432
- join8(homedir5(), ".claude", "credentials.json")
2433
- ];
2434
- if (credPaths.some((p) => existsSync6(p))) return true;
2435
- try {
2436
- execSync3("claude --version", { stdio: "pipe", timeout: 5e3 });
2437
- return existsSync6(join8(homedir5(), ".claude"));
2438
- } catch {
2439
- return false;
2451
+ if (process.env.ANTHROPIC_API_KEY) return true;
2452
+ const home = homedir5();
2453
+ if (existsSync6(join8(home, ".claude", ".credentials.json"))) return true;
2454
+ if (existsSync6(join8(home, ".claude", "credentials.json"))) return true;
2455
+ if (process.platform === "darwin") {
2456
+ try {
2457
+ const result = execSync4('security find-generic-password -s "Claude Code-credentials" -w', {
2458
+ stdio: "pipe",
2459
+ encoding: "utf-8",
2460
+ timeout: 5e3
2461
+ });
2462
+ if (result.trim()) return true;
2463
+ } catch {
2464
+ }
2440
2465
  }
2466
+ return false;
2441
2467
  }
2442
2468
  function commandExists(cmd) {
2443
2469
  try {
2444
- execSync3(`which ${cmd}`, { stdio: "pipe" });
2470
+ execSync4(`which ${cmd}`, { stdio: "pipe" });
2445
2471
  return true;
2446
2472
  } catch {
2447
2473
  return false;
@@ -2449,7 +2475,7 @@ function commandExists(cmd) {
2449
2475
  }
2450
2476
  function isDockerRunning() {
2451
2477
  try {
2452
- execSync3("docker info", { stdio: "pipe", timeout: 1e4 });
2478
+ execSync4("docker info", { stdio: "pipe", timeout: 1e4 });
2453
2479
  return true;
2454
2480
  } catch {
2455
2481
  return false;
@@ -2458,7 +2484,7 @@ function isDockerRunning() {
2458
2484
 
2459
2485
  // src/index.ts
2460
2486
  import { existsSync as existsSync7, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, readFileSync as readFileSync4, unlinkSync } from "fs";
2461
- import { execSync as execSync4, spawn as spawn2 } from "child_process";
2487
+ import { execSync as execSync5, spawn as spawn2 } from "child_process";
2462
2488
  import { createInterface } from "readline";
2463
2489
  import { join as join9 } from "path";
2464
2490
  import { homedir as homedir6 } from "os";
@@ -2516,7 +2542,7 @@ program.command("serve").description("Start webhook server with auto-tunnel").op
2516
2542
  await checkDockerAvailable();
2517
2543
  if (!checkClaudeCredentials()) {
2518
2544
  throw new Error(
2519
- "Claude Code credentials not found (~/.claude/.credentials.json)\nRun: claude (and complete login) to create credentials"
2545
+ 'Claude Code credentials not found.\nEither: export ANTHROPIC_API_KEY="sk-ant-..." (recommended for macOS)\nOr: run claude (and complete login) to create ~/.claude/.credentials.json'
2520
2546
  );
2521
2547
  }
2522
2548
  const orphans = await cleanupOrphanedContainers();
@@ -2582,7 +2608,7 @@ program.command("watch").description("Poll Linear for tickets (no webhook/tunnel
2582
2608
  await checkDockerAvailable();
2583
2609
  if (!checkClaudeCredentials()) {
2584
2610
  throw new Error(
2585
- "Claude Code credentials not found (~/.claude/.credentials.json)\nRun: claude (and complete login) to create credentials"
2611
+ 'Claude Code credentials not found.\nEither: export ANTHROPIC_API_KEY="sk-ant-..." (recommended for macOS)\nOr: run claude (and complete login) to create ~/.claude/.credentials.json'
2586
2612
  );
2587
2613
  }
2588
2614
  const orphans = await cleanupOrphanedContainers();
@@ -2655,7 +2681,7 @@ program.command("run <ticket>").description("Run a single ticket (e.g. autoclawd
2655
2681
  await checkDockerAvailable();
2656
2682
  if (!checkClaudeCredentials()) {
2657
2683
  throw new Error(
2658
- "Claude Code credentials not found (~/.claude/.credentials.json)\nRun: claude (and complete login) to create credentials"
2684
+ 'Claude Code credentials not found.\nEither: export ANTHROPIC_API_KEY="sk-ant-..." (recommended for macOS)\nOr: run claude (and complete login) to create ~/.claude/.credentials.json'
2659
2685
  );
2660
2686
  }
2661
2687
  const octokit = createOctokit(config);
@@ -2689,7 +2715,7 @@ Expected: https://github.com/owner/repo/pull/123`);
2689
2715
  await checkDockerAvailable();
2690
2716
  if (!checkClaudeCredentials()) {
2691
2717
  throw new Error(
2692
- "Claude Code credentials not found (~/.claude/.credentials.json)\nRun: claude (and complete login) to create credentials"
2718
+ 'Claude Code credentials not found.\nEither: export ANTHROPIC_API_KEY="sk-ant-..." (recommended for macOS)\nOr: run claude (and complete login) to create ~/.claude/.credentials.json'
2693
2719
  );
2694
2720
  }
2695
2721
  const octokit = createOctokit(config);
@@ -2710,7 +2736,7 @@ program.command("retry [ticket]").description("Retry a failed ticket (e.g. autoc
2710
2736
  await checkDockerAvailable();
2711
2737
  if (!checkClaudeCredentials()) {
2712
2738
  throw new Error(
2713
- "Claude Code credentials not found (~/.claude/.credentials.json)\nRun: claude (and complete login) to create credentials"
2739
+ 'Claude Code credentials not found.\nEither: export ANTHROPIC_API_KEY="sk-ant-..." (recommended for macOS)\nOr: run claude (and complete login) to create ~/.claude/.credentials.json'
2714
2740
  );
2715
2741
  }
2716
2742
  const linearClient = createLinearClient(config);
@@ -2861,19 +2887,22 @@ program.command("history").description("Show run history").option("-n, --limit <
2861
2887
  }
2862
2888
  });
2863
2889
  function checkClaudeCredentials() {
2890
+ if (process.env.ANTHROPIC_API_KEY) return true;
2864
2891
  const home = homedir6();
2865
2892
  if (existsSync7(join9(home, ".claude", ".credentials.json"))) return true;
2866
2893
  if (existsSync7(join9(home, ".claude", "credentials.json"))) return true;
2867
- if (existsSync7(join9(home, ".claude")) && commandExistsSync("claude")) return true;
2868
- return false;
2869
- }
2870
- function commandExistsSync(cmd) {
2871
- try {
2872
- execSync4(`which ${cmd}`, { stdio: "pipe" });
2873
- return true;
2874
- } catch {
2875
- return false;
2894
+ if (process.platform === "darwin") {
2895
+ try {
2896
+ const result = execSync5('security find-generic-password -s "Claude Code-credentials" -w', {
2897
+ stdio: "pipe",
2898
+ encoding: "utf-8",
2899
+ timeout: 5e3
2900
+ });
2901
+ if (result.trim()) return true;
2902
+ } catch {
2903
+ }
2876
2904
  }
2905
+ return false;
2877
2906
  }
2878
2907
  async function validateGitHubToken(token) {
2879
2908
  try {
@@ -2947,7 +2976,7 @@ program.command("init").description("Set up autoclawd interactively").action(asy
2947
2976
  }
2948
2977
  let ghToken = "";
2949
2978
  try {
2950
- ghToken = execSync4("gh auth token", { encoding: "utf-8" }).trim();
2979
+ ghToken = execSync5("gh auth token", { encoding: "utf-8" }).trim();
2951
2980
  log.success(`GitHub token detected from gh CLI`);
2952
2981
  } catch {
2953
2982
  ghToken = await ask("GitHub personal access token");