@sleds/cli 0.1.52 → 0.1.54
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/sleds.mjs +154 -71
- package/package.json +1 -1
package/dist/sleds.mjs
CHANGED
|
@@ -8557,8 +8557,7 @@ function parseParked(v) {
|
|
|
8557
8557
|
return {
|
|
8558
8558
|
question: v.question,
|
|
8559
8559
|
at: v.at,
|
|
8560
|
-
...typeof v.
|
|
8561
|
-
...v.still === true ? { still: true } : {},
|
|
8560
|
+
...typeof v.words === "string" ? { words: v.words, ...v.still === true ? { still: true } : {} } : {},
|
|
8562
8561
|
...answerer ? { answerer } : {}
|
|
8563
8562
|
};
|
|
8564
8563
|
}
|
|
@@ -8601,7 +8600,9 @@ function parseRun(v) {
|
|
|
8601
8600
|
options: Array.isArray(v.permission.options) ? v.permission.options.filter((x) => typeof x === "string") : [],
|
|
8602
8601
|
at: v.permission.at,
|
|
8603
8602
|
...v.permission.onScreen === true ? { onScreen: true } : {},
|
|
8603
|
+
...typeof v.permission.dialog === "string" ? { dialog: v.permission.dialog } : {},
|
|
8604
8604
|
...typeof v.permission.pressedAt === "number" ? { pressedAt: v.permission.pressedAt } : {},
|
|
8605
|
+
...typeof v.permission.pressedOn === "string" ? { pressedOn: v.permission.pressedOn } : {},
|
|
8605
8606
|
...typeof v.permission.presses === "number" ? { presses: v.permission.presses } : {},
|
|
8606
8607
|
...v.permission.gaveUp === true ? { gaveUp: true } : {}
|
|
8607
8608
|
}
|
|
@@ -8615,12 +8616,21 @@ function parseRun(v) {
|
|
|
8615
8616
|
feedback: typeof v.pr.feedback === "number" ? v.pr.feedback : 0,
|
|
8616
8617
|
...typeof v.pr.authorFeedback === "number" ? { authorFeedback: v.pr.authorFeedback } : {},
|
|
8617
8618
|
...typeof v.pr.selfNudges === "number" ? { selfNudges: v.pr.selfNudges } : {},
|
|
8619
|
+
...isObject8(v.pr.feedbackRead) && typeof v.pr.feedbackRead.updatedAt === "string" && typeof v.pr.feedbackRead.all === "number" && typeof v.pr.feedbackRead.author === "number" && typeof v.pr.feedbackRead.at === "number" ? {
|
|
8620
|
+
feedbackRead: {
|
|
8621
|
+
updatedAt: v.pr.feedbackRead.updatedAt,
|
|
8622
|
+
all: v.pr.feedbackRead.all,
|
|
8623
|
+
author: v.pr.feedbackRead.author,
|
|
8624
|
+
at: v.pr.feedbackRead.at
|
|
8625
|
+
}
|
|
8626
|
+
} : {},
|
|
8618
8627
|
...v.pr.clear === true ? { clear: true } : {},
|
|
8619
8628
|
...typeof v.pr.ci === "string" ? { ci: v.pr.ci } : {},
|
|
8620
8629
|
...typeof v.pr.review === "string" ? { review: v.pr.review } : {},
|
|
8621
8630
|
...typeof v.pr.posted === "string" ? { posted: v.pr.posted } : {},
|
|
8622
8631
|
...Array.isArray(v.pr.failedHeads) ? { failedHeads: v.pr.failedHeads.filter((x) => typeof x === "string") } : {},
|
|
8623
8632
|
...typeof v.pr.conflict === "string" ? { conflict: v.pr.conflict } : {},
|
|
8633
|
+
...isObject8(v.pr.conflictCheck) && typeof v.pr.conflictCheck.head === "string" && typeof v.pr.conflictCheck.at === "number" ? { conflictCheck: { head: v.pr.conflictCheck.head, at: v.pr.conflictCheck.at } } : {},
|
|
8624
8634
|
...typeof v.pr.resolving === "string" ? { resolving: v.pr.resolving } : {},
|
|
8625
8635
|
...conflicted ? { conflicted } : {},
|
|
8626
8636
|
...typeof v.pr.reviewed === "string" ? { reviewed: v.pr.reviewed } : {},
|
|
@@ -10759,15 +10769,36 @@ var claudeAddDirFlag = (mainCheckout) => mainCheckout ? ` --add-dir=${shq(mainCh
|
|
|
10759
10769
|
var shq = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
10760
10770
|
|
|
10761
10771
|
// src/runners/exec.ts
|
|
10772
|
+
var EXEC_TIMEOUT_MS = 2 * 60000;
|
|
10773
|
+
var EXEC_TIMEOUT_STATUS = 124;
|
|
10774
|
+
var timedOut = (r) => r.error?.code === "ETIMEDOUT";
|
|
10775
|
+
var logTimeouts = (exec, log) => (cmd, args, o) => {
|
|
10776
|
+
const r = exec(cmd, args, o);
|
|
10777
|
+
if (r.status === EXEC_TIMEOUT_STATUS && isTimeout(r.stderr))
|
|
10778
|
+
log(`exec timed out: ${[cmd, ...args].join(" ")} — ${r.stderr.split(`
|
|
10779
|
+
`)[0]}`);
|
|
10780
|
+
return r;
|
|
10781
|
+
};
|
|
10762
10782
|
var defaultExec = (cmd, args, o) => {
|
|
10783
|
+
const timeoutMs = o?.timeoutMs ?? EXEC_TIMEOUT_MS;
|
|
10763
10784
|
const r = spawnSync3(cmd, [...args], {
|
|
10764
10785
|
cwd: o?.cwd,
|
|
10765
10786
|
input: o?.input,
|
|
10766
10787
|
env: o?.env ? { ...process.env, ...o.env } : undefined,
|
|
10767
10788
|
encoding: "utf8",
|
|
10768
10789
|
shell: false,
|
|
10769
|
-
maxBuffer: 16 * 1024 * 1024
|
|
10790
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
10791
|
+
timeout: timeoutMs,
|
|
10792
|
+
killSignal: "SIGKILL"
|
|
10770
10793
|
});
|
|
10794
|
+
if (timedOut(r)) {
|
|
10795
|
+
return {
|
|
10796
|
+
status: EXEC_TIMEOUT_STATUS,
|
|
10797
|
+
stdout: r.stdout ?? "",
|
|
10798
|
+
stderr: `${cmd}: timed out after ${timeoutMs / 1000}s and was killed${r.stderr ? `
|
|
10799
|
+
${r.stderr}` : ""}`
|
|
10800
|
+
};
|
|
10801
|
+
}
|
|
10771
10802
|
if (r.error) {
|
|
10772
10803
|
return { status: 127, stdout: r.stdout ?? "", stderr: `${cmd}: ${r.error.message}` };
|
|
10773
10804
|
}
|
|
@@ -11436,14 +11467,7 @@ ${r.stdout}`) };
|
|
|
11436
11467
|
sendKey(h, key) {
|
|
11437
11468
|
if (!isRunnerKey(key))
|
|
11438
11469
|
throw new Error(`orca terminal send ${h.id}: no key ${JSON.stringify(key)}`);
|
|
11439
|
-
|
|
11440
|
-
const send = (args) => orca(["terminal", "send", "--terminal", h.id, ...args, "--json"], what);
|
|
11441
|
-
if (key === "esc") {
|
|
11442
|
-
send(["--text", ESC]);
|
|
11443
|
-
return;
|
|
11444
|
-
}
|
|
11445
|
-
send(["--text", key]);
|
|
11446
|
-
send(["--enter"]);
|
|
11470
|
+
orca(["terminal", "send", "--terminal", h.id, "--text", key === "esc" ? ESC : key, "--json"], `orca terminal send ${h.id} (key ${key})`);
|
|
11447
11471
|
},
|
|
11448
11472
|
stop(h) {
|
|
11449
11473
|
exec("orca", ["terminal", "close", "--terminal", h.id]);
|
|
@@ -11511,7 +11535,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
11511
11535
|
name: flags.name,
|
|
11512
11536
|
os: host.os ?? process.platform,
|
|
11513
11537
|
runner: flags.runner,
|
|
11514
|
-
version: host.version ?? "0.1.
|
|
11538
|
+
version: host.version ?? "0.1.54" ?? "dev",
|
|
11515
11539
|
running: live.length,
|
|
11516
11540
|
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
11517
11541
|
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
@@ -11911,6 +11935,7 @@ function parsePrView(stdout) {
|
|
|
11911
11935
|
feedback: 0,
|
|
11912
11936
|
authorFeedback: 0,
|
|
11913
11937
|
draft: o.isDraft === true,
|
|
11938
|
+
updatedAt: typeof o.updatedAt === "string" ? o.updatedAt : "",
|
|
11914
11939
|
...mock ? { mock } : {},
|
|
11915
11940
|
...typeof o.headRefOid === "string" && o.headRefOid ? { head: o.headRefOid } : {},
|
|
11916
11941
|
...typeof mergeCommit === "string" && mergeCommit ? { mergeCommit } : {}
|
|
@@ -11959,20 +11984,24 @@ function prFeedback(exec, repoPath, url, author) {
|
|
|
11959
11984
|
}
|
|
11960
11985
|
return total;
|
|
11961
11986
|
}
|
|
11962
|
-
function prView(exec, repoPath, url) {
|
|
11987
|
+
function prView(exec, repoPath, url, last) {
|
|
11963
11988
|
try {
|
|
11964
11989
|
const r = exec("gh", [
|
|
11965
11990
|
"pr",
|
|
11966
11991
|
"view",
|
|
11967
11992
|
url,
|
|
11968
11993
|
"--json",
|
|
11969
|
-
"state,author,statusCheckRollup,reviewDecision,
|
|
11994
|
+
"state,author,statusCheckRollup,reviewDecision,headRefOid,mergeable,baseRefName,mergeCommit,isDraft,body,updatedAt"
|
|
11970
11995
|
], { cwd: repoPath });
|
|
11971
11996
|
const view = r.status === 0 ? parsePrView(r.stdout) : null;
|
|
11972
11997
|
if (!view || view.state !== "OPEN")
|
|
11973
11998
|
return view;
|
|
11974
|
-
|
|
11975
|
-
|
|
11999
|
+
let read = view.updatedAt && last?.updatedAt === view.updatedAt ? last : undefined;
|
|
12000
|
+
if (!read) {
|
|
12001
|
+
const f = prFeedback(exec, repoPath, url, view.author);
|
|
12002
|
+
read = f && { ...f, updatedAt: view.updatedAt };
|
|
12003
|
+
}
|
|
12004
|
+
return read ? { ...view, feedback: read.all, authorFeedback: read.author, read } : view;
|
|
11976
12005
|
} catch {
|
|
11977
12006
|
return null;
|
|
11978
12007
|
}
|
|
@@ -13011,26 +13040,28 @@ function sledsSource(client, o) {
|
|
|
13011
13040
|
});
|
|
13012
13041
|
if (r?.status !== 409)
|
|
13013
13042
|
return "running";
|
|
13043
|
+
let route;
|
|
13044
|
+
try {
|
|
13045
|
+
route = await routeOf(claim.item);
|
|
13046
|
+
} catch {
|
|
13047
|
+
route = null;
|
|
13048
|
+
}
|
|
13049
|
+
if (!isObject8(route))
|
|
13050
|
+
return "running";
|
|
13014
13051
|
if (claim.kind === "draft") {
|
|
13015
|
-
|
|
13016
|
-
|
|
13017
|
-
|
|
13018
|
-
|
|
13019
|
-
|
|
13020
|
-
if (isObject8(route?.draftParked))
|
|
13021
|
-
return "parked";
|
|
13022
|
-
} catch {}
|
|
13052
|
+
const filed = Array.isArray(route.nodes) && route.nodes.length > 0;
|
|
13053
|
+
if (filed || isObject8(route.proposed))
|
|
13054
|
+
return "done";
|
|
13055
|
+
if (isObject8(route.draftParked))
|
|
13056
|
+
return "parked";
|
|
13023
13057
|
return "lost";
|
|
13024
13058
|
}
|
|
13025
|
-
|
|
13026
|
-
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
if (state === "pr" || state === "landed" || state === "skipped")
|
|
13032
|
-
return "done";
|
|
13033
|
-
} catch {}
|
|
13059
|
+
const nodes = Array.isArray(route.nodes) ? route.nodes.filter(isObject8) : [];
|
|
13060
|
+
const state = nodes.find((n) => n.key === claim.node)?.state;
|
|
13061
|
+
if (state === "parked")
|
|
13062
|
+
return "parked";
|
|
13063
|
+
if (state === "pr" || state === "landed" || state === "skipped")
|
|
13064
|
+
return "done";
|
|
13034
13065
|
return "lost";
|
|
13035
13066
|
},
|
|
13036
13067
|
async report(claim, outcome, by) {
|
|
@@ -13526,6 +13557,7 @@ function fastForwardUntouched(exec, path, base, log) {
|
|
|
13526
13557
|
log?.(`${path}: fast-forwarded to origin/${base}`);
|
|
13527
13558
|
return true;
|
|
13528
13559
|
}
|
|
13560
|
+
var INSTALL_TIMEOUT_MS = 15 * 60000;
|
|
13529
13561
|
var MANAGERS = new Set(["pnpm", "npm", "yarn", "bun"]);
|
|
13530
13562
|
var INSTALL_VERBS = new Set(["install", "i", "ci"]);
|
|
13531
13563
|
function installArgv(command) {
|
|
@@ -13617,7 +13649,7 @@ function ensureInstalled(exec, path, fs, o = {}) {
|
|
|
13617
13649
|
return null;
|
|
13618
13650
|
const [cmd, ...args] = argv;
|
|
13619
13651
|
o.log?.(`${path}: no node_modules — running ${argv.join(" ")}`);
|
|
13620
|
-
const r = exec(cmd, args, { cwd: path });
|
|
13652
|
+
const r = exec(cmd, args, { cwd: path, timeoutMs: INSTALL_TIMEOUT_MS });
|
|
13621
13653
|
const ok = r.status === 0;
|
|
13622
13654
|
if (!ok)
|
|
13623
13655
|
o.log?.(`${path}: ${argv.join(" ")} failed (exit ${r.status}) — the session starts anyway: ${(r.stderr || r.stdout).trim().split(`
|
|
@@ -13701,6 +13733,9 @@ function fingerprint(text) {
|
|
|
13701
13733
|
}
|
|
13702
13734
|
return (h >>> 0).toString(16);
|
|
13703
13735
|
}
|
|
13736
|
+
function wordsPrint(screen) {
|
|
13737
|
+
return fingerprint(stripTuiChrome(screen));
|
|
13738
|
+
}
|
|
13704
13739
|
function sandboxFor(d, name, cwd, allow) {
|
|
13705
13740
|
if (!d.sandbox)
|
|
13706
13741
|
return {};
|
|
@@ -13967,7 +14002,7 @@ async function tickOnce(d) {
|
|
|
13967
14002
|
if (beat === "parked") {
|
|
13968
14003
|
const question = "the session parked itself; the question is on the route";
|
|
13969
14004
|
d.log(`${ref(run)}: parked with a question — the session waits for the answer (${runner.watchHint(run.handle)})`);
|
|
13970
|
-
holdParked(d, runner, run, question);
|
|
14005
|
+
holdParked(d, runner, run, question, shown);
|
|
13971
14006
|
finished.push({ item: run.item, node: run.node, outcome: { kind: "park", question } });
|
|
13972
14007
|
keep.push(run);
|
|
13973
14008
|
continue;
|
|
@@ -14002,7 +14037,7 @@ async function tickOnce(d) {
|
|
|
14002
14037
|
}
|
|
14003
14038
|
d.log(`${ref(run)}: ${why}, tries spent — parked for a person (${runner.watchHint(run.handle)})`);
|
|
14004
14039
|
run.provider = undefined;
|
|
14005
|
-
holdParked(d, runner, run, question);
|
|
14040
|
+
holdParked(d, runner, run, question, shown);
|
|
14006
14041
|
finished.push({ item: run.item, node: run.node, outcome });
|
|
14007
14042
|
keep.push(run);
|
|
14008
14043
|
continue;
|
|
@@ -14023,7 +14058,7 @@ async function tickOnce(d) {
|
|
|
14023
14058
|
continue;
|
|
14024
14059
|
}
|
|
14025
14060
|
d.log(asked ? `${ref(run)}: stopped on a question with no PR — parked with its last message as the question (${runner.watchHint(run.handle)})` : `${ref(run)}: idle ${d.idleMin} min with no PR — parked with its last message as the question (${runner.watchHint(run.handle)})`);
|
|
14026
|
-
holdParked(d, runner, run, question);
|
|
14061
|
+
holdParked(d, runner, run, question, shown);
|
|
14027
14062
|
finished.push({ item: run.item, node: run.node, outcome });
|
|
14028
14063
|
keep.push(run);
|
|
14029
14064
|
continue;
|
|
@@ -14364,6 +14399,10 @@ function permissionKey(answer) {
|
|
|
14364
14399
|
const m = /^\s*(\d|esc)\s*·/i.exec(answer);
|
|
14365
14400
|
return m ? m[1].toLowerCase() : null;
|
|
14366
14401
|
}
|
|
14402
|
+
function dialogPrint(dialog) {
|
|
14403
|
+
return [dialog.text, ...dialog.options.map((o) => `${o.key} · ${o.label}`)].join(`
|
|
14404
|
+
`);
|
|
14405
|
+
}
|
|
14367
14406
|
async function settlePermission(d, runner, run, shown) {
|
|
14368
14407
|
const perms = permissionsOf(d.source);
|
|
14369
14408
|
if (!perms || !run.runId)
|
|
@@ -14373,19 +14412,20 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14373
14412
|
const dialog = runner.readsSession ? permissionDialog(shown) : null;
|
|
14374
14413
|
const p = run.permission;
|
|
14375
14414
|
if (p) {
|
|
14376
|
-
const gone = runner.readsSession && (p.onScreen ? !dialog : (run.seenAt ?? 0) > (p.pressedAt ?? p.at));
|
|
14415
|
+
const gone = runner.readsSession && (p.onScreen ? !dialog || p.dialog !== undefined && dialogPrint(dialog) !== p.dialog || p.pressedOn !== undefined && fingerprint(shown) !== p.pressedOn : (run.seenAt ?? 0) > (p.pressedAt ?? p.at));
|
|
14377
14416
|
const answered = () => {
|
|
14378
14417
|
run.permission = undefined;
|
|
14379
14418
|
run.answeredAt = d.now();
|
|
14380
14419
|
if (markFile)
|
|
14381
14420
|
clearPermissionMark(markFile);
|
|
14382
14421
|
};
|
|
14422
|
+
const next = (held) => dialog ? settlePermission(d, runner, run, shown) : held;
|
|
14383
14423
|
if (p.gaveUp) {
|
|
14384
14424
|
if (!gone)
|
|
14385
14425
|
return true;
|
|
14386
14426
|
d.log(`${at}: the permission dialog was answered in the terminal`);
|
|
14387
14427
|
answered();
|
|
14388
|
-
return false;
|
|
14428
|
+
return next(false);
|
|
14389
14429
|
}
|
|
14390
14430
|
let now;
|
|
14391
14431
|
try {
|
|
@@ -14403,18 +14443,23 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14403
14443
|
if (!pressed)
|
|
14404
14444
|
return true;
|
|
14405
14445
|
if (pressed === "key") {
|
|
14406
|
-
run.permission = {
|
|
14446
|
+
run.permission = {
|
|
14447
|
+
...p,
|
|
14448
|
+
pressedAt: d.now(),
|
|
14449
|
+
pressedOn: fingerprint(shown),
|
|
14450
|
+
presses: 1
|
|
14451
|
+
};
|
|
14407
14452
|
return true;
|
|
14408
14453
|
}
|
|
14409
14454
|
}
|
|
14410
14455
|
answered();
|
|
14411
|
-
return true;
|
|
14456
|
+
return gone ? next(true) : true;
|
|
14412
14457
|
}
|
|
14413
14458
|
const key = permissionKey(now.answer) ?? now.answer;
|
|
14414
14459
|
if (gone) {
|
|
14415
14460
|
d.log(`${at}: the permission is answered — pressed ${key}; the session goes on`);
|
|
14416
14461
|
answered();
|
|
14417
|
-
return false;
|
|
14462
|
+
return next(false);
|
|
14418
14463
|
}
|
|
14419
14464
|
const presses = p.presses ?? 1;
|
|
14420
14465
|
if (presses >= PRESS_TRIES) {
|
|
@@ -14430,7 +14475,12 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14430
14475
|
return true;
|
|
14431
14476
|
}
|
|
14432
14477
|
if (pressAnswer(d, runner, run, p.options, now.answer) === "key")
|
|
14433
|
-
run.permission = {
|
|
14478
|
+
run.permission = {
|
|
14479
|
+
...p,
|
|
14480
|
+
pressedAt: d.now(),
|
|
14481
|
+
pressedOn: fingerprint(shown),
|
|
14482
|
+
presses: presses + 1
|
|
14483
|
+
};
|
|
14434
14484
|
return true;
|
|
14435
14485
|
}
|
|
14436
14486
|
if (now?.state !== "open" && now?.state !== "escalated") {
|
|
@@ -14447,7 +14497,7 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14447
14497
|
}
|
|
14448
14498
|
d.log(`${at}: the permission dialog closed before an answer — cleared`);
|
|
14449
14499
|
run.permission = undefined;
|
|
14450
|
-
return false;
|
|
14500
|
+
return next(false);
|
|
14451
14501
|
}
|
|
14452
14502
|
let mark = markFile ? readPermissionMark(markFile) : null;
|
|
14453
14503
|
if (mark && markFile && (!isToolPermission(mark.message) || runner.readsSession && choicePicker(shown))) {
|
|
@@ -14473,7 +14523,7 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14473
14523
|
decisionId: opened.decisionId,
|
|
14474
14524
|
options,
|
|
14475
14525
|
at: d.now(),
|
|
14476
|
-
...dialog ? { onScreen: true } : {}
|
|
14526
|
+
...dialog ? { onScreen: true, dialog: dialogPrint(dialog) } : {}
|
|
14477
14527
|
};
|
|
14478
14528
|
if (markFile)
|
|
14479
14529
|
clearPermissionMark(markFile);
|
|
@@ -14739,8 +14789,12 @@ function stopOpen(d, run, runner) {
|
|
|
14739
14789
|
d.log(`${ref(run)}: could not stop the left-open session: ${message(e)}`);
|
|
14740
14790
|
}
|
|
14741
14791
|
}
|
|
14742
|
-
function holdParked(d, runner, run, question) {
|
|
14743
|
-
run.parked = {
|
|
14792
|
+
function holdParked(d, runner, run, question, shown) {
|
|
14793
|
+
run.parked = {
|
|
14794
|
+
question,
|
|
14795
|
+
at: d.now(),
|
|
14796
|
+
...runner.readsSession ? { words: wordsPrint(shown) } : {}
|
|
14797
|
+
};
|
|
14744
14798
|
run.leaseUntil = undefined;
|
|
14745
14799
|
setLane(d, runner, run.handle, "parked");
|
|
14746
14800
|
}
|
|
@@ -14749,18 +14803,19 @@ async function answeredInSession(d, runner, run) {
|
|
|
14749
14803
|
const resumes = resumesOf(d.source);
|
|
14750
14804
|
if (!resumes || !runner.readsSession || !run.runId)
|
|
14751
14805
|
return false;
|
|
14752
|
-
let
|
|
14806
|
+
let shown;
|
|
14753
14807
|
try {
|
|
14754
|
-
|
|
14808
|
+
shown = runner.read(run.handle);
|
|
14755
14809
|
} catch {
|
|
14756
14810
|
return false;
|
|
14757
14811
|
}
|
|
14758
|
-
|
|
14812
|
+
const words = wordsPrint(shown);
|
|
14813
|
+
if (words === parked.words) {
|
|
14759
14814
|
parked.still = true;
|
|
14760
14815
|
return false;
|
|
14761
14816
|
}
|
|
14762
14817
|
const moved = parked.still === true;
|
|
14763
|
-
parked.
|
|
14818
|
+
parked.words = words;
|
|
14764
14819
|
parked.still = false;
|
|
14765
14820
|
if (!moved)
|
|
14766
14821
|
return false;
|
|
@@ -14778,7 +14833,7 @@ async function answeredInSession(d, runner, run) {
|
|
|
14778
14833
|
stopAnswerer(d, run);
|
|
14779
14834
|
const now = d.now();
|
|
14780
14835
|
run.parked = undefined;
|
|
14781
|
-
run.seen =
|
|
14836
|
+
run.seen = fingerprint(shown);
|
|
14782
14837
|
run.seenAt = now;
|
|
14783
14838
|
run.seenTicks = 0;
|
|
14784
14839
|
run.answeredAt = now;
|
|
@@ -15361,6 +15416,8 @@ function ciNudge(url, failing) {
|
|
|
15361
15416
|
return `CI failed on your PR (${failing.join(", ")}): ${url}. Read the failing logs (gh pr checks ${url}), fix the cause, run the repo's gate, and push to the same branch.`;
|
|
15362
15417
|
}
|
|
15363
15418
|
var SELF_NUDGES = 2;
|
|
15419
|
+
var FEEDBACK_REREAD_MS = 10 * 60000;
|
|
15420
|
+
var CONFLICT_RECHECK_MS = 10 * 60000;
|
|
15364
15421
|
function reviewNudge(url, count) {
|
|
15365
15422
|
return `New review feedback on your PR (${count} ${count === 1 ? "comment" : "comments"} from people so far): ${url}. Read all of it (gh pr view ${url} --comments, and the inline threads), answer each comment on its own thread with the fix or a reasoned reply, push, and leave the threads for the reviewer to resolve. End every comment and reply you post on the PR with the line ${ENGINE_MARK} so the engine knows it is yours and not the reviewer's.`;
|
|
15366
15423
|
}
|
|
@@ -15401,9 +15458,12 @@ async function judgeLook(d, run, view) {
|
|
|
15401
15458
|
}
|
|
15402
15459
|
async function follow(d, state, run, claim, runner, finished, attention, changes, decided) {
|
|
15403
15460
|
const pr = run.pr;
|
|
15404
|
-
const
|
|
15461
|
+
const last = pr.feedbackRead && d.now() - pr.feedbackRead.at < FEEDBACK_REREAD_MS ? pr.feedbackRead : undefined;
|
|
15462
|
+
const view = d.prView(d.exec, run.repoPath, pr.url, last);
|
|
15405
15463
|
if (!view)
|
|
15406
15464
|
return true;
|
|
15465
|
+
if (view.read && view.read !== last)
|
|
15466
|
+
pr.feedbackRead = { ...view.read, at: d.now() };
|
|
15407
15467
|
await judgeLook(d, run, view);
|
|
15408
15468
|
if (view.state === "MERGED") {
|
|
15409
15469
|
await dropPermission(d, run, "the PR merged");
|
|
@@ -15457,6 +15517,7 @@ async function follow(d, state, run, claim, runner, finished, attention, changes
|
|
|
15457
15517
|
else if (view.mergeable === "MERGEABLE") {
|
|
15458
15518
|
pr.resolving = undefined;
|
|
15459
15519
|
pr.conflicted = undefined;
|
|
15520
|
+
pr.conflictCheck = undefined;
|
|
15460
15521
|
}
|
|
15461
15522
|
if (view.feedback > pr.feedback) {
|
|
15462
15523
|
const what = `${view.feedback - pr.feedback} new review comment(s)`;
|
|
@@ -15696,10 +15757,15 @@ async function judgeConflict(d, state, run, view, attention, decided) {
|
|
|
15696
15757
|
const pr = run.pr;
|
|
15697
15758
|
if (!d.mergeTree)
|
|
15698
15759
|
return;
|
|
15760
|
+
const check = pr.conflictCheck;
|
|
15761
|
+
if (view.head && check?.head === view.head && !pr.resolving && d.now() - check.at < CONFLICT_RECHECK_MS)
|
|
15762
|
+
return;
|
|
15699
15763
|
const base = view.base || d.defaultBranch(d.exec, run.repoPath);
|
|
15700
15764
|
const mt = d.mergeTree(d.exec, run.repoPath, base, run.branch);
|
|
15701
15765
|
if (!mt)
|
|
15702
15766
|
return;
|
|
15767
|
+
if (view.head)
|
|
15768
|
+
pr.conflictCheck = { head: view.head, at: d.now() };
|
|
15703
15769
|
if (pr.resolving === mt.sha && mt.files.length > 0 && !sessionRuns(d, run.handle)) {
|
|
15704
15770
|
pr.resolving = undefined;
|
|
15705
15771
|
const what = `${pr.url} still conflicts with ${base} on ${mt.files.join(", ")} after its session had the brief`;
|
|
@@ -17362,7 +17428,7 @@ async function fetchVersion(o) {
|
|
|
17362
17428
|
const platform = o.platform ?? process.platform;
|
|
17363
17429
|
const arch = o.arch ?? process.arch;
|
|
17364
17430
|
const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
|
|
17365
|
-
const running = o.running ?? "0.1.
|
|
17431
|
+
const running = o.running ?? "0.1.54";
|
|
17366
17432
|
if (!publicKey)
|
|
17367
17433
|
return { ok: false, why: "no release key yet" };
|
|
17368
17434
|
if (!VERSION_RE2.test(o.version))
|
|
@@ -18946,7 +19012,7 @@ function engineClient(o, org) {
|
|
|
18946
19012
|
return fetchClient({
|
|
18947
19013
|
...src,
|
|
18948
19014
|
timeoutMs: ENGINE_TIMEOUT_MS,
|
|
18949
|
-
version: "0.1.
|
|
19015
|
+
version: "0.1.54"
|
|
18950
19016
|
});
|
|
18951
19017
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
18952
19018
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -19011,10 +19077,10 @@ function engineToken(o, org) {
|
|
|
19011
19077
|
}
|
|
19012
19078
|
var withToken = (token, now) => token ? { token, tokenNow: now } : {};
|
|
19013
19079
|
function engineDeps(o, flags, source, runner, stateName) {
|
|
19014
|
-
const
|
|
19080
|
+
const log = o.log ?? console.log;
|
|
19081
|
+
const exec = logTimeouts(guardGit(o.exec ?? defaultExec), log);
|
|
19015
19082
|
const cwd = o.cwd ?? process.cwd();
|
|
19016
19083
|
const exists = o.exists ?? realExists;
|
|
19017
|
-
const log = o.log ?? console.log;
|
|
19018
19084
|
const stateDir = engineStateDir(o, flags.org, flags.seat);
|
|
19019
19085
|
const file = statePath(stateDir, stateName);
|
|
19020
19086
|
const mcpOrg = flags.org && engineOrg(o, flags.org).seated ? flags.org : undefined;
|
|
@@ -19237,7 +19303,7 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
19237
19303
|
runner: deps.runner.name,
|
|
19238
19304
|
atOnce: flags.atOnce,
|
|
19239
19305
|
interval: flags.interval,
|
|
19240
|
-
cliVersion: "0.1.
|
|
19306
|
+
cliVersion: "0.1.54"
|
|
19241
19307
|
};
|
|
19242
19308
|
const beat = (checkedAt) => {
|
|
19243
19309
|
const m = deps.machine;
|
|
@@ -19429,7 +19495,7 @@ async function drive(o, flags, deps, until, beat) {
|
|
|
19429
19495
|
var SEAT_CHANGED_EXIT = 3;
|
|
19430
19496
|
function engineRunner(o, flags) {
|
|
19431
19497
|
const runnerFor = o.runnerFor ?? runnerFor2;
|
|
19432
|
-
return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
|
|
19498
|
+
return runnerFor(flags.runner, logTimeouts(guardGit(o.exec ?? defaultExec), o.log ?? console.log), {
|
|
19433
19499
|
...flags.runnerCmd ? { command: flags.runnerCmd } : {}
|
|
19434
19500
|
});
|
|
19435
19501
|
}
|
|
@@ -21094,7 +21160,7 @@ function engineClient2(o, org) {
|
|
|
21094
21160
|
return fetchClient({
|
|
21095
21161
|
...src,
|
|
21096
21162
|
timeoutMs: ENGINE_TIMEOUT_MS2,
|
|
21097
|
-
version: "0.1.
|
|
21163
|
+
version: "0.1.54"
|
|
21098
21164
|
});
|
|
21099
21165
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
21100
21166
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -21181,10 +21247,10 @@ function engineCredential(o) {
|
|
|
21181
21247
|
})?.kind;
|
|
21182
21248
|
}
|
|
21183
21249
|
function engineDeps2(o, flags, source, runner, stateName) {
|
|
21184
|
-
const
|
|
21250
|
+
const log = o.log ?? console.log;
|
|
21251
|
+
const exec = logTimeouts(guardGit(o.exec ?? defaultExec), log);
|
|
21185
21252
|
const cwd = o.cwd ?? process.cwd();
|
|
21186
21253
|
const exists = o.exists ?? realExists2;
|
|
21187
|
-
const log = o.log ?? console.log;
|
|
21188
21254
|
const stateDir = engineStateDir2(o, flags.org, flags.seat);
|
|
21189
21255
|
const file = statePath(stateDir, stateName);
|
|
21190
21256
|
const mcpOrg = flags.org && engineOrg2(o, flags.org).seated ? flags.org : undefined;
|
|
@@ -21420,7 +21486,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
21420
21486
|
runner: deps.runner.name,
|
|
21421
21487
|
atOnce: flags.atOnce,
|
|
21422
21488
|
interval: flags.interval,
|
|
21423
|
-
cliVersion: "0.1.
|
|
21489
|
+
cliVersion: "0.1.54"
|
|
21424
21490
|
};
|
|
21425
21491
|
const beat = (checkedAt) => {
|
|
21426
21492
|
const m = deps.machine;
|
|
@@ -21612,7 +21678,7 @@ async function drive2(o, flags, deps, until, beat) {
|
|
|
21612
21678
|
var SEAT_CHANGED_EXIT2 = 3;
|
|
21613
21679
|
function engineRunner2(o, flags) {
|
|
21614
21680
|
const runnerFor = o.runnerFor ?? runnerFor2;
|
|
21615
|
-
return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
|
|
21681
|
+
return runnerFor(flags.runner, logTimeouts(guardGit(o.exec ?? defaultExec), o.log ?? console.log), {
|
|
21616
21682
|
...flags.runnerCmd ? { command: flags.runnerCmd } : {}
|
|
21617
21683
|
});
|
|
21618
21684
|
}
|
|
@@ -23508,7 +23574,7 @@ function contextFor(deps) {
|
|
|
23508
23574
|
...src,
|
|
23509
23575
|
fetchFn: deps.fetchFn,
|
|
23510
23576
|
timeoutMs: deps.timeoutMs,
|
|
23511
|
-
version: "0.1.
|
|
23577
|
+
version: "0.1.54"
|
|
23512
23578
|
}), deps.home, now) : null;
|
|
23513
23579
|
return {
|
|
23514
23580
|
channel: "code",
|
|
@@ -26095,14 +26161,17 @@ async function sledOff(client, key, json, log, error) {
|
|
|
26095
26161
|
return 0;
|
|
26096
26162
|
}
|
|
26097
26163
|
const k = typeof r.json?.key === "string" ? r.json.key : key;
|
|
26164
|
+
const why = typeof r.json?.why === "string" && r.json.why.trim() ? r.json.why : null;
|
|
26098
26165
|
if (r.json?.changed === false) {
|
|
26099
|
-
|
|
26100
|
-
return
|
|
26166
|
+
error(why ?? `${k} was not on a sled`);
|
|
26167
|
+
return 1;
|
|
26101
26168
|
}
|
|
26102
26169
|
log(`${k} is off your sled — back in the pool`);
|
|
26103
26170
|
const running = typeof r.json?.running === "number" ? r.json.running : 0;
|
|
26104
26171
|
if (running > 0)
|
|
26105
26172
|
log(`${running} running node${running === 1 ? "" : "s"} stopped`);
|
|
26173
|
+
if (why)
|
|
26174
|
+
log(why);
|
|
26106
26175
|
return 0;
|
|
26107
26176
|
}
|
|
26108
26177
|
|
|
@@ -27623,7 +27692,7 @@ var realPidAlive4 = (pid) => {
|
|
|
27623
27692
|
};
|
|
27624
27693
|
function machineClient(home, env) {
|
|
27625
27694
|
const src = meterSource(home, undefined, { env });
|
|
27626
|
-
return src ? fetchClient({ ...src, version: "0.1.
|
|
27695
|
+
return src ? fetchClient({ ...src, version: "0.1.54" }) : null;
|
|
27627
27696
|
}
|
|
27628
27697
|
async function noteAnswer2(home, a, now) {
|
|
27629
27698
|
try {
|
|
@@ -28093,15 +28162,29 @@ var readConfig2 = (home) => {
|
|
|
28093
28162
|
|
|
28094
28163
|
// src/runners/exec.ts
|
|
28095
28164
|
import { spawn as spawn3, spawnSync as spawnSync10 } from "node:child_process";
|
|
28165
|
+
var EXEC_TIMEOUT_MS2 = 2 * 60000;
|
|
28166
|
+
var EXEC_TIMEOUT_STATUS2 = 124;
|
|
28167
|
+
var timedOut2 = (r) => r.error?.code === "ETIMEDOUT";
|
|
28096
28168
|
var defaultExec4 = (cmd, args, o) => {
|
|
28169
|
+
const timeoutMs = o?.timeoutMs ?? EXEC_TIMEOUT_MS2;
|
|
28097
28170
|
const r = spawnSync10(cmd, [...args], {
|
|
28098
28171
|
cwd: o?.cwd,
|
|
28099
28172
|
input: o?.input,
|
|
28100
28173
|
env: o?.env ? { ...process.env, ...o.env } : undefined,
|
|
28101
28174
|
encoding: "utf8",
|
|
28102
28175
|
shell: false,
|
|
28103
|
-
maxBuffer: 16 * 1024 * 1024
|
|
28176
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
28177
|
+
timeout: timeoutMs,
|
|
28178
|
+
killSignal: "SIGKILL"
|
|
28104
28179
|
});
|
|
28180
|
+
if (timedOut2(r)) {
|
|
28181
|
+
return {
|
|
28182
|
+
status: EXEC_TIMEOUT_STATUS2,
|
|
28183
|
+
stdout: r.stdout ?? "",
|
|
28184
|
+
stderr: `${cmd}: timed out after ${timeoutMs / 1000}s and was killed${r.stderr ? `
|
|
28185
|
+
${r.stderr}` : ""}`
|
|
28186
|
+
};
|
|
28187
|
+
}
|
|
28105
28188
|
if (r.error) {
|
|
28106
28189
|
return { status: 127, stdout: r.stdout ?? "", stderr: `${cmd}: ${r.error.message}` };
|
|
28107
28190
|
}
|
|
@@ -28469,7 +28552,7 @@ var main = async (argv) => {
|
|
|
28469
28552
|
now: Date.now(),
|
|
28470
28553
|
stderr: (line) => console.error(line),
|
|
28471
28554
|
isTTY: !!process.stderr.isTTY,
|
|
28472
|
-
version: "0.1.
|
|
28555
|
+
version: "0.1.54"
|
|
28473
28556
|
});
|
|
28474
28557
|
switch (cmd) {
|
|
28475
28558
|
case "update":
|
|
@@ -28702,7 +28785,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
28702
28785
|
case "version":
|
|
28703
28786
|
case "--version":
|
|
28704
28787
|
case "-v":
|
|
28705
|
-
console.log("sleds 0.1.
|
|
28788
|
+
console.log("sleds 0.1.54");
|
|
28706
28789
|
return 0;
|
|
28707
28790
|
default:
|
|
28708
28791
|
console.error(`unknown command: ${cmd}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleds/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.54",
|
|
4
4
|
"description": "SLEDS CLI — the cost and limits of AI agent work, decided at the wall. Point Claude Code at a SLEDS proxy; estimate before you run; hold, switch model, or run overnight when you hit a limit.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|