@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 +75 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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: [
|
|
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
|
-
|
|
917
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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: "
|
|
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
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
if (
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
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 =
|
|
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");
|