@groupchatai/claude-runner 0.4.6 → 0.4.8
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 +112 -133
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -114,6 +114,12 @@ ${comment.body}`
|
|
|
114
114
|
);
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
+
const existingPrUrl = detail.pullRequestUrl ?? detail.task.pullRequestUrl;
|
|
118
|
+
if (existingPrUrl) {
|
|
119
|
+
parts.push(`
|
|
120
|
+
## Existing Pull Request
|
|
121
|
+
${existingPrUrl}`);
|
|
122
|
+
}
|
|
117
123
|
if (detail.task.dueDate) {
|
|
118
124
|
let dueStr = new Date(detail.task.dueDate).toLocaleDateString();
|
|
119
125
|
if (detail.task.dueTime != null) {
|
|
@@ -126,12 +132,18 @@ ${comment.body}`
|
|
|
126
132
|
parts.push(`
|
|
127
133
|
Due: ${dueStr}`);
|
|
128
134
|
}
|
|
135
|
+
const prRules = existingPrUrl ? [
|
|
136
|
+
`- This task already has a PR: ${existingPrUrl}. Push your changes to the EXISTING branch. Do NOT create a new PR.`,
|
|
137
|
+
"- You may push to existing branches and contribute to existing PRs."
|
|
138
|
+
] : [
|
|
139
|
+
"- When you have made code changes, you MUST create a new branch, commit your changes, push to the remote, and open a PR using `gh pr create`. Do NOT skip PR creation \u2014 always open a real PR.",
|
|
140
|
+
"- You may push to existing branches and contribute to existing PRs."
|
|
141
|
+
];
|
|
129
142
|
parts.push(
|
|
130
143
|
[
|
|
131
144
|
"\n---",
|
|
132
145
|
"RULES:",
|
|
133
|
-
|
|
134
|
-
"- You may push to existing branches and contribute to existing PRs.",
|
|
146
|
+
...prRules,
|
|
135
147
|
"- NEVER run `gh pr merge`. Do NOT merge any PR.",
|
|
136
148
|
"- NEVER run `gh pr close`. Do NOT close any PR.",
|
|
137
149
|
"- NEVER run `git push --force` or `git push -f`. No force pushes.",
|
|
@@ -154,8 +166,7 @@ function pidTag(pid) {
|
|
|
154
166
|
return ` ${C.pid}[pid ${pid}]${C.reset}`;
|
|
155
167
|
}
|
|
156
168
|
function padForTag(pid) {
|
|
157
|
-
|
|
158
|
-
return " ".repeat(tagLen);
|
|
169
|
+
return " ".repeat(8 + String(pid).length);
|
|
159
170
|
}
|
|
160
171
|
function wrapLines(tag, pad, text, color) {
|
|
161
172
|
const lines = text.split("\n").filter((l) => l.trim());
|
|
@@ -277,13 +288,16 @@ function clampUserFacingDetail(text, maxChars) {
|
|
|
277
288
|
function stripAnsi(text) {
|
|
278
289
|
return text.replace(/\x1b\[[0-9;]*m/g, "");
|
|
279
290
|
}
|
|
291
|
+
function errMsg(err) {
|
|
292
|
+
return err instanceof Error ? err.message : String(err);
|
|
293
|
+
}
|
|
294
|
+
function normalizeEpochMs(raw) {
|
|
295
|
+
if (typeof raw !== "number" || !Number.isFinite(raw)) return null;
|
|
296
|
+
return raw > 1e10 ? raw : raw * 1e3;
|
|
297
|
+
}
|
|
280
298
|
function formatAnthropicRateLimitPayload(o) {
|
|
281
299
|
const rateLimitTypeRaw = typeof o.rateLimitType === "string" ? o.rateLimitType.replace(/_/g, " ") : "unknown";
|
|
282
|
-
const
|
|
283
|
-
let resetMs = null;
|
|
284
|
-
if (typeof rawReset === "number" && Number.isFinite(rawReset)) {
|
|
285
|
-
resetMs = rawReset > 1e10 ? rawReset : rawReset * 1e3;
|
|
286
|
-
}
|
|
300
|
+
const resetMs = normalizeEpochMs(o.resetsAt);
|
|
287
301
|
const status = typeof o.status === "string" ? o.status : null;
|
|
288
302
|
const overageReason = typeof o.overageDisabledReason === "string" ? o.overageDisabledReason : null;
|
|
289
303
|
const parts = [`Rate limit (${rateLimitTypeRaw})`];
|
|
@@ -304,9 +318,8 @@ function safeFormatRateLimitPayload(o) {
|
|
|
304
318
|
return formatAnthropicRateLimitPayload(o);
|
|
305
319
|
} catch {
|
|
306
320
|
const rt = typeof o.rateLimitType === "string" ? o.rateLimitType : "unknown";
|
|
307
|
-
const
|
|
308
|
-
if (
|
|
309
|
-
const ms = rawReset > 1e10 ? rawReset : rawReset * 1e3;
|
|
321
|
+
const ms = normalizeEpochMs(o.resetsAt);
|
|
322
|
+
if (ms !== null) {
|
|
310
323
|
return `Rate limit (${rt}) \u2014 resets at ${new Date(ms).toISOString()} UTC`;
|
|
311
324
|
}
|
|
312
325
|
return `Rate limit (${rt})`;
|
|
@@ -314,7 +327,23 @@ function safeFormatRateLimitPayload(o) {
|
|
|
314
327
|
}
|
|
315
328
|
function parseClaudeNdjsonEvents(rawOutput) {
|
|
316
329
|
const events = [];
|
|
317
|
-
|
|
330
|
+
const cleaned = stripAnsi(rawOutput).trim();
|
|
331
|
+
try {
|
|
332
|
+
const parsed = JSON.parse(cleaned);
|
|
333
|
+
if (Array.isArray(parsed)) {
|
|
334
|
+
for (const item of parsed) {
|
|
335
|
+
if (item && typeof item === "object" && typeof item.type === "string") {
|
|
336
|
+
events.push(item);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return events;
|
|
340
|
+
}
|
|
341
|
+
if (parsed && typeof parsed === "object" && typeof parsed.type === "string") {
|
|
342
|
+
return [parsed];
|
|
343
|
+
}
|
|
344
|
+
} catch {
|
|
345
|
+
}
|
|
346
|
+
for (const line of cleaned.split("\n")) {
|
|
318
347
|
const t = line.trim();
|
|
319
348
|
if (!t.startsWith("{")) continue;
|
|
320
349
|
try {
|
|
@@ -330,8 +359,7 @@ function parseClaudeNdjsonEvents(rawOutput) {
|
|
|
330
359
|
function isRateLimitEventBlocking(ev) {
|
|
331
360
|
const info = ev.rate_limit_info;
|
|
332
361
|
if (!info || typeof info !== "object" || Array.isArray(info)) return true;
|
|
333
|
-
|
|
334
|
-
return !(typeof status === "string" && status === "allowed");
|
|
362
|
+
return info.status !== "allowed";
|
|
335
363
|
}
|
|
336
364
|
function extractRateLimitRetryInfo(events) {
|
|
337
365
|
for (const ev of events) {
|
|
@@ -339,9 +367,8 @@ function extractRateLimitRetryInfo(events) {
|
|
|
339
367
|
if (!isRateLimitEventBlocking(ev)) continue;
|
|
340
368
|
const info = ev.rate_limit_info;
|
|
341
369
|
if (!info || typeof info !== "object" || Array.isArray(info)) continue;
|
|
342
|
-
const
|
|
343
|
-
if (
|
|
344
|
-
const ms = raw > 1e10 ? raw : raw * 1e3;
|
|
370
|
+
const ms = normalizeEpochMs(info.resetsAt);
|
|
371
|
+
if (ms === null) continue;
|
|
345
372
|
return { errorType: "rate_limit", retryAfterMs: ms };
|
|
346
373
|
}
|
|
347
374
|
return null;
|
|
@@ -382,11 +409,7 @@ function claudeRunShouldReportAsError(exitCode, events) {
|
|
|
382
409
|
return false;
|
|
383
410
|
}
|
|
384
411
|
function compactTaskErrorForApi(detail) {
|
|
385
|
-
|
|
386
|
-
if (/^rate limit \(/i.test(s)) {
|
|
387
|
-
return s.split(/\s*—\s*/)[0]?.trim() ?? s;
|
|
388
|
-
}
|
|
389
|
-
return s;
|
|
412
|
+
return detail.trim();
|
|
390
413
|
}
|
|
391
414
|
function spawnClaudeCode(prompt, config, runOptions, resumeSessionId, cwdOverride) {
|
|
392
415
|
const format = config.verbose ? "stream-json" : "json";
|
|
@@ -435,31 +458,32 @@ function spawnClaudeCode(prompt, config, runOptions, resumeSessionId, cwdOverrid
|
|
|
435
458
|
const match = combined.match(GITHUB_PR_URL_RE);
|
|
436
459
|
if (match) capturedPrUrl = match[match.length - 1];
|
|
437
460
|
}
|
|
461
|
+
function processLine(trimmed) {
|
|
462
|
+
try {
|
|
463
|
+
const event = JSON.parse(trimmed);
|
|
464
|
+
if (event.type === "system" && event.subtype === "init" && event.session_id) {
|
|
465
|
+
capturedSessionId = event.session_id;
|
|
466
|
+
}
|
|
467
|
+
if (event.type === "result") lastResultJson = trimmed;
|
|
468
|
+
checkEventForPrUrl(event);
|
|
469
|
+
if (config.verbose) {
|
|
470
|
+
const formatted = formatStreamEvent(event, pid);
|
|
471
|
+
if (formatted) console.log(formatted);
|
|
472
|
+
}
|
|
473
|
+
} catch {
|
|
474
|
+
if (config.verbose) {
|
|
475
|
+
console.log(`${pidTag(pid)} ${C.dim}${trimmed}${C.reset}`);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
438
479
|
child.stdout?.on("data", (data) => {
|
|
439
480
|
chunks.push(data);
|
|
440
|
-
|
|
441
|
-
lineBuf += text;
|
|
481
|
+
lineBuf += data.toString("utf-8");
|
|
442
482
|
const lines = lineBuf.split("\n");
|
|
443
483
|
lineBuf = lines.pop() ?? "";
|
|
444
484
|
for (const line of lines) {
|
|
445
485
|
const trimmed = line.trim();
|
|
446
|
-
if (
|
|
447
|
-
try {
|
|
448
|
-
const event = JSON.parse(trimmed);
|
|
449
|
-
if (event.type === "system" && event.subtype === "init" && event.session_id) {
|
|
450
|
-
capturedSessionId = event.session_id;
|
|
451
|
-
}
|
|
452
|
-
if (event.type === "result") lastResultJson = trimmed;
|
|
453
|
-
checkEventForPrUrl(event);
|
|
454
|
-
if (config.verbose) {
|
|
455
|
-
const formatted = formatStreamEvent(event, pid);
|
|
456
|
-
if (formatted) console.log(formatted);
|
|
457
|
-
}
|
|
458
|
-
} catch {
|
|
459
|
-
if (config.verbose) {
|
|
460
|
-
console.log(`${pidTag(pid)} ${C.dim}${trimmed}${C.reset}`);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
486
|
+
if (trimmed) processLine(trimmed);
|
|
463
487
|
}
|
|
464
488
|
});
|
|
465
489
|
child.stderr?.on("data", (data) => {
|
|
@@ -471,24 +495,8 @@ function spawnClaudeCode(prompt, config, runOptions, resumeSessionId, cwdOverrid
|
|
|
471
495
|
});
|
|
472
496
|
child.on("error", (err) => reject(new Error(`Failed to spawn claude: ${err.message}`)));
|
|
473
497
|
child.on("close", (code) => {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const event = JSON.parse(lineBuf.trim());
|
|
477
|
-
if (event.type === "system" && event.subtype === "init" && event.session_id) {
|
|
478
|
-
capturedSessionId = event.session_id;
|
|
479
|
-
}
|
|
480
|
-
if (event.type === "result") lastResultJson = lineBuf.trim();
|
|
481
|
-
checkEventForPrUrl(event);
|
|
482
|
-
if (config.verbose) {
|
|
483
|
-
const formatted = formatStreamEvent(event, pid);
|
|
484
|
-
if (formatted) console.log(formatted);
|
|
485
|
-
}
|
|
486
|
-
} catch {
|
|
487
|
-
if (config.verbose) {
|
|
488
|
-
console.log(`${pidTag(pid)} ${C.dim}${lineBuf.trim()}${C.reset}`);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
498
|
+
const remaining = lineBuf.trim();
|
|
499
|
+
if (remaining) processLine(remaining);
|
|
492
500
|
const rawOutput = Buffer.concat(chunks).toString("utf-8");
|
|
493
501
|
const stdout = config.verbose ? lastResultJson || rawOutput : rawOutput;
|
|
494
502
|
const stderr = Buffer.concat(errChunks).toString("utf-8");
|
|
@@ -558,10 +566,9 @@ function extractPullRequestUrlFromText(text) {
|
|
|
558
566
|
return void 0;
|
|
559
567
|
}
|
|
560
568
|
function extractPullRequestUrlFromOutput(stdout) {
|
|
561
|
-
const
|
|
562
|
-
if (
|
|
563
|
-
const
|
|
564
|
-
const found = extractPullRequestUrlFromText(text);
|
|
569
|
+
const resultText = extractResultText(stdout);
|
|
570
|
+
if (resultText !== stdout) {
|
|
571
|
+
const found = extractPullRequestUrlFromText(resultText);
|
|
565
572
|
if (found) return found;
|
|
566
573
|
}
|
|
567
574
|
return extractPullRequestUrlFromText(stdout);
|
|
@@ -645,25 +652,16 @@ function createWorktree(repoDir, taskId, existingBranch) {
|
|
|
645
652
|
async function resolveExistingPrBranch(detail, workDir) {
|
|
646
653
|
try {
|
|
647
654
|
if (detail.branchName) return detail.branchName;
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
"gh",
|
|
652
|
-
["pr", "view", detail.pullRequestUrl, "--json", "headRefName", "--jq", ".headRefName"],
|
|
653
|
-
workDir
|
|
654
|
-
);
|
|
655
|
-
if (branch2?.trim()) return branch2.trim();
|
|
656
|
-
} catch {
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
const prUrls = [];
|
|
655
|
+
const candidatePrUrls = [];
|
|
656
|
+
if (detail.pullRequestUrl) candidatePrUrls.push(detail.pullRequestUrl);
|
|
657
|
+
if (detail.task.pullRequestUrl) candidatePrUrls.push(detail.task.pullRequestUrl);
|
|
660
658
|
for (const item of detail.activity) {
|
|
661
659
|
if (item.body) {
|
|
662
660
|
const matches = item.body.match(GITHUB_PR_URL_RE);
|
|
663
|
-
if (matches)
|
|
661
|
+
if (matches) candidatePrUrls.push(...matches);
|
|
664
662
|
}
|
|
665
663
|
}
|
|
666
|
-
const prUrl =
|
|
664
|
+
const prUrl = candidatePrUrls[0];
|
|
667
665
|
if (!prUrl) return void 0;
|
|
668
666
|
const branch = await runShellCommand(
|
|
669
667
|
"gh",
|
|
@@ -753,7 +751,7 @@ async function removeWorktree(workDir, info) {
|
|
|
753
751
|
}
|
|
754
752
|
return true;
|
|
755
753
|
} catch (err) {
|
|
756
|
-
console.error(` Failed to remove ${info.name}: ${err
|
|
754
|
+
console.error(` Failed to remove ${info.name}: ${errMsg(err)}`);
|
|
757
755
|
return false;
|
|
758
756
|
}
|
|
759
757
|
}
|
|
@@ -931,7 +929,7 @@ async function processRun(client, run, config, worktreeDir, detail) {
|
|
|
931
929
|
try {
|
|
932
930
|
await client.startRun(run.id, startMsg);
|
|
933
931
|
} catch (err) {
|
|
934
|
-
const msg =
|
|
932
|
+
const msg = errMsg(err);
|
|
935
933
|
if (msg.includes("not pending") || msg.includes("not PENDING") || msg.includes("400")) {
|
|
936
934
|
log(`\u23ED Run was already claimed, skipping.`);
|
|
937
935
|
return;
|
|
@@ -940,11 +938,13 @@ async function processRun(client, run, config, worktreeDir, detail) {
|
|
|
940
938
|
}
|
|
941
939
|
log("\u25B6 Run started");
|
|
942
940
|
const effectiveCwd = worktreeDir ?? config.workDir;
|
|
943
|
-
let
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
941
|
+
let lastClaude = {
|
|
942
|
+
stderr: "",
|
|
943
|
+
stdout: "",
|
|
944
|
+
rawOutput: "",
|
|
945
|
+
exitCode: null,
|
|
946
|
+
sessionId: void 0
|
|
947
|
+
};
|
|
948
948
|
try {
|
|
949
949
|
if (!worktreeDir && runOptions.branch) {
|
|
950
950
|
log(`\u{1F33F} Checking out branch: ${runOptions.branch}`);
|
|
@@ -974,28 +974,14 @@ async function processRun(client, run, config, worktreeDir, detail) {
|
|
|
974
974
|
);
|
|
975
975
|
log(`\u{1F916} Claude Code spawned (pid ${child.pid})${isFollowUp ? " (follow-up)" : ""}`);
|
|
976
976
|
let { stdout, rawOutput, stderr, exitCode, sessionId, streamPrUrl } = await output;
|
|
977
|
-
|
|
978
|
-
lastClaudeStdout = stdout;
|
|
979
|
-
lastClaudeRawOutput = rawOutput;
|
|
980
|
-
lastClaudeExitCode = exitCode;
|
|
981
|
-
lastClaudeSessionId = sessionId;
|
|
977
|
+
lastClaude = { stderr, stdout, rawOutput, exitCode, sessionId };
|
|
982
978
|
if (exitCode !== 0 && isFollowUp) {
|
|
983
979
|
log(`\u26A0 Session resume failed, retrying with fresh session\u2026`);
|
|
984
980
|
sessionCache.delete(run.taskId);
|
|
985
981
|
const retry = spawnClaudeCode(prompt, config, runOptions, void 0, effectiveCwd);
|
|
986
982
|
log(`\u{1F916} Claude Code spawned (pid ${retry.process.pid}) (fresh)`);
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
rawOutput = retryResult.rawOutput;
|
|
990
|
-
stderr = retryResult.stderr;
|
|
991
|
-
exitCode = retryResult.exitCode;
|
|
992
|
-
sessionId = retryResult.sessionId;
|
|
993
|
-
streamPrUrl = retryResult.streamPrUrl;
|
|
994
|
-
lastClaudeStderr = stderr;
|
|
995
|
-
lastClaudeStdout = stdout;
|
|
996
|
-
lastClaudeRawOutput = rawOutput;
|
|
997
|
-
lastClaudeExitCode = exitCode;
|
|
998
|
-
lastClaudeSessionId = sessionId;
|
|
983
|
+
({ stdout, rawOutput, stderr, exitCode, sessionId, streamPrUrl } = await retry.output);
|
|
984
|
+
lastClaude = { stderr, stdout, rawOutput, exitCode, sessionId };
|
|
999
985
|
}
|
|
1000
986
|
if (sessionId) {
|
|
1001
987
|
sessionCache.set(run.taskId, sessionId);
|
|
@@ -1068,11 +1054,11 @@ async function processRun(client, run, config, worktreeDir, detail) {
|
|
|
1068
1054
|
if (pullRequestUrl) logGreen(`\u{1F517} PR: ${pullRequestUrl}`);
|
|
1069
1055
|
logGreen(`\u2705 Run completed`);
|
|
1070
1056
|
} catch (err) {
|
|
1071
|
-
const message =
|
|
1057
|
+
const message = errMsg(err);
|
|
1072
1058
|
const stack = err instanceof Error ? err.stack : void 0;
|
|
1073
|
-
const stderrDbg = truncateClaudeDebugString(stripAnsi(
|
|
1074
|
-
const stdoutDbg = truncateClaudeDebugString(stripAnsi(
|
|
1075
|
-
const rawDbg = truncateClaudeDebugString(stripAnsi(
|
|
1059
|
+
const stderrDbg = truncateClaudeDebugString(stripAnsi(lastClaude.stderr));
|
|
1060
|
+
const stdoutDbg = truncateClaudeDebugString(stripAnsi(lastClaude.stdout));
|
|
1061
|
+
const rawDbg = truncateClaudeDebugString(stripAnsi(lastClaude.rawOutput));
|
|
1076
1062
|
if (process.env.GCA_DEBUG_CLAUDE_RAW === "1") {
|
|
1077
1063
|
logClaudeRawFailureJson({
|
|
1078
1064
|
runId: run.id,
|
|
@@ -1080,8 +1066,8 @@ async function processRun(client, run, config, worktreeDir, detail) {
|
|
|
1080
1066
|
taskTitle: run.taskTitle,
|
|
1081
1067
|
thrownMessage: message,
|
|
1082
1068
|
thrownStack: stack ?? null,
|
|
1083
|
-
exitCode:
|
|
1084
|
-
sessionId:
|
|
1069
|
+
exitCode: lastClaude.exitCode,
|
|
1070
|
+
sessionId: lastClaude.sessionId ?? null,
|
|
1085
1071
|
note: "Thrown before or after Claude finished; fields may be empty.",
|
|
1086
1072
|
stderr: stderrDbg.text,
|
|
1087
1073
|
stderrMeta: { fullLength: stderrDbg.fullLength, truncated: stderrDbg.truncated },
|
|
@@ -1185,6 +1171,7 @@ function parseArgs() {
|
|
|
1185
1171
|
workDir: process.cwd(),
|
|
1186
1172
|
pollInterval: 3e4,
|
|
1187
1173
|
maxConcurrent: 5,
|
|
1174
|
+
command: "run",
|
|
1188
1175
|
poll: false,
|
|
1189
1176
|
dryRun: false,
|
|
1190
1177
|
once: false,
|
|
@@ -1234,20 +1221,23 @@ function parseArgs() {
|
|
|
1234
1221
|
config.useWorktrees = false;
|
|
1235
1222
|
break;
|
|
1236
1223
|
case "cleanup":
|
|
1224
|
+
config.command = "cleanup";
|
|
1237
1225
|
break;
|
|
1238
1226
|
default:
|
|
1239
1227
|
console.error(`Unknown argument: ${arg}`);
|
|
1240
1228
|
process.exit(1);
|
|
1241
1229
|
}
|
|
1242
1230
|
}
|
|
1243
|
-
if (
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1231
|
+
if (config.command !== "cleanup") {
|
|
1232
|
+
if (!config.token) {
|
|
1233
|
+
console.error("Error: No agent token found.");
|
|
1234
|
+
console.error(" Add GCA_TOKEN=gca_... to .env.local, or pass --token gca_...");
|
|
1235
|
+
process.exit(1);
|
|
1236
|
+
}
|
|
1237
|
+
if (!config.token.startsWith("gca_")) {
|
|
1238
|
+
console.error(`Error: Token must start with gca_ (got "${config.token.slice(0, 8)}\u2026")`);
|
|
1239
|
+
process.exit(1);
|
|
1240
|
+
}
|
|
1251
1241
|
}
|
|
1252
1242
|
return config;
|
|
1253
1243
|
}
|
|
@@ -1448,7 +1438,7 @@ async function runWithPolling(client, config, scheduler) {
|
|
|
1448
1438
|
const pending = await client.listPendingRuns();
|
|
1449
1439
|
handlePendingRuns(pending, scheduler, client, config);
|
|
1450
1440
|
} catch (err) {
|
|
1451
|
-
console.error(`Poll error: ${err
|
|
1441
|
+
console.error(`Poll error: ${errMsg(err)}`);
|
|
1452
1442
|
}
|
|
1453
1443
|
while (!scheduler.isEmpty()) await sleep(1e3);
|
|
1454
1444
|
return;
|
|
@@ -1458,7 +1448,7 @@ async function runWithPolling(client, config, scheduler) {
|
|
|
1458
1448
|
const pending = await client.listPendingRuns();
|
|
1459
1449
|
handlePendingRuns(pending, scheduler, client, config);
|
|
1460
1450
|
} catch (err) {
|
|
1461
|
-
const msg =
|
|
1451
|
+
const msg = errMsg(err);
|
|
1462
1452
|
if (config.verbose || !msg.includes("fetch")) {
|
|
1463
1453
|
console.error(`Poll error: ${msg}`);
|
|
1464
1454
|
}
|
|
@@ -1466,29 +1456,18 @@ async function runWithPolling(client, config, scheduler) {
|
|
|
1466
1456
|
await sleep(config.pollInterval);
|
|
1467
1457
|
}
|
|
1468
1458
|
}
|
|
1469
|
-
function wantsVersionOnly(argv) {
|
|
1470
|
-
return argv.some((a) => a === "--version" || a === "-v" || a === "-version");
|
|
1471
|
-
}
|
|
1472
1459
|
async function main() {
|
|
1473
|
-
const
|
|
1474
|
-
if (
|
|
1475
|
-
|
|
1476
|
-
}
|
|
1477
|
-
if (process.argv.includes("cleanup")) {
|
|
1478
|
-
loadEnvFile();
|
|
1479
|
-
const workDir = process.cwd();
|
|
1480
|
-
const workDirIdx = process.argv.indexOf("--work-dir");
|
|
1481
|
-
const resolvedDir = workDirIdx >= 0 ? path.resolve(process.argv[workDirIdx + 1] ?? ".") : workDir;
|
|
1482
|
-
await interactiveCleanup(resolvedDir);
|
|
1460
|
+
const config = parseArgs();
|
|
1461
|
+
if (config.command === "cleanup") {
|
|
1462
|
+
await interactiveCleanup(config.workDir);
|
|
1483
1463
|
return;
|
|
1484
1464
|
}
|
|
1485
|
-
const config = parseArgs();
|
|
1486
1465
|
const client = new GroupChatAgentClient(config.apiUrl, config.token);
|
|
1487
1466
|
let me;
|
|
1488
1467
|
try {
|
|
1489
1468
|
me = await client.getMe();
|
|
1490
1469
|
} catch (err) {
|
|
1491
|
-
console.error("Failed to authenticate:", err
|
|
1470
|
+
console.error("Failed to authenticate:", errMsg(err));
|
|
1492
1471
|
process.exit(1);
|
|
1493
1472
|
}
|
|
1494
1473
|
console.log(`
|