@sleds/cli 0.1.54 → 0.1.56
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 +225 -73
- package/package.json +1 -1
package/dist/sleds.mjs
CHANGED
|
@@ -2565,9 +2565,18 @@ ${rows.map((r) => statusLine(r, now)).join(`
|
|
|
2565
2565
|
|
|
2566
2566
|
`)}${more}`;
|
|
2567
2567
|
}
|
|
2568
|
+
function mineSection(rows, now, count) {
|
|
2569
|
+
if (rows.length === 0)
|
|
2570
|
+
return null;
|
|
2571
|
+
return `On your sled (${count ?? rows.length}):
|
|
2572
|
+
|
|
2573
|
+
${rows.map((r) => statusLine(r, now)).join(`
|
|
2574
|
+
|
|
2575
|
+
`)}`;
|
|
2576
|
+
}
|
|
2568
2577
|
function sledText(s, now) {
|
|
2569
2578
|
const parts = [
|
|
2570
|
-
|
|
2579
|
+
mineSection(s.mine, now, s.mineCount),
|
|
2571
2580
|
section("Proposed to you", s.proposed, now, s.proposedCount),
|
|
2572
2581
|
section("Sent to you", s.sent, now)
|
|
2573
2582
|
].filter((p) => p !== null);
|
|
@@ -3519,6 +3528,7 @@ async function sledTool(ctx, args) {
|
|
|
3519
3528
|
return {
|
|
3520
3529
|
text: sledText({
|
|
3521
3530
|
mine: rows("mine"),
|
|
3531
|
+
...typeof r.mineCount === "number" ? { mineCount: r.mineCount } : {},
|
|
3522
3532
|
proposed: rows("proposed"),
|
|
3523
3533
|
...typeof r.proposedCount === "number" ? { proposedCount: r.proposedCount } : {},
|
|
3524
3534
|
sent: rows("sent")
|
|
@@ -8558,6 +8568,7 @@ function parseParked(v) {
|
|
|
8558
8568
|
question: v.question,
|
|
8559
8569
|
at: v.at,
|
|
8560
8570
|
...typeof v.words === "string" ? { words: v.words, ...v.still === true ? { still: true } : {} } : {},
|
|
8571
|
+
...typeof v.seatFull === "string" && v.seatFull ? { seatFull: v.seatFull } : {},
|
|
8561
8572
|
...answerer ? { answerer } : {}
|
|
8562
8573
|
};
|
|
8563
8574
|
}
|
|
@@ -11535,7 +11546,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
11535
11546
|
name: flags.name,
|
|
11536
11547
|
os: host.os ?? process.platform,
|
|
11537
11548
|
runner: flags.runner,
|
|
11538
|
-
version: host.version ?? "0.1.
|
|
11549
|
+
version: host.version ?? "0.1.56" ?? "dev",
|
|
11539
11550
|
running: live.length,
|
|
11540
11551
|
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
11541
11552
|
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
@@ -11936,6 +11947,7 @@ function parsePrView(stdout) {
|
|
|
11936
11947
|
authorFeedback: 0,
|
|
11937
11948
|
draft: o.isDraft === true,
|
|
11938
11949
|
updatedAt: typeof o.updatedAt === "string" ? o.updatedAt : "",
|
|
11950
|
+
queued: typeof o.autoMergeRequest === "object" && o.autoMergeRequest !== null,
|
|
11939
11951
|
...mock ? { mock } : {},
|
|
11940
11952
|
...typeof o.headRefOid === "string" && o.headRefOid ? { head: o.headRefOid } : {},
|
|
11941
11953
|
...typeof mergeCommit === "string" && mergeCommit ? { mergeCommit } : {}
|
|
@@ -11984,6 +11996,27 @@ function prFeedback(exec, repoPath, url, author) {
|
|
|
11984
11996
|
}
|
|
11985
11997
|
return total;
|
|
11986
11998
|
}
|
|
11999
|
+
var MERGE_QUEUE_QUERY = "query($url: URI!) { resource(url: $url) { ... on PullRequest { mergeQueueEntry { state } } } }";
|
|
12000
|
+
function prInMergeQueue(exec, repoPath, url) {
|
|
12001
|
+
try {
|
|
12002
|
+
const r = exec("gh", [
|
|
12003
|
+
"api",
|
|
12004
|
+
"graphql",
|
|
12005
|
+
"-f",
|
|
12006
|
+
`query=${MERGE_QUEUE_QUERY}`,
|
|
12007
|
+
"-f",
|
|
12008
|
+
`url=${url}`,
|
|
12009
|
+
"--jq",
|
|
12010
|
+
".data.resource.mergeQueueEntry != null"
|
|
12011
|
+
], { cwd: repoPath });
|
|
12012
|
+
if (r.status !== 0)
|
|
12013
|
+
return null;
|
|
12014
|
+
const out = r.stdout.trim();
|
|
12015
|
+
return out === "true" ? true : out === "false" ? false : null;
|
|
12016
|
+
} catch {
|
|
12017
|
+
return null;
|
|
12018
|
+
}
|
|
12019
|
+
}
|
|
11987
12020
|
function prView(exec, repoPath, url, last) {
|
|
11988
12021
|
try {
|
|
11989
12022
|
const r = exec("gh", [
|
|
@@ -11991,11 +12024,13 @@ function prView(exec, repoPath, url, last) {
|
|
|
11991
12024
|
"view",
|
|
11992
12025
|
url,
|
|
11993
12026
|
"--json",
|
|
11994
|
-
"state,author,statusCheckRollup,reviewDecision,headRefOid,mergeable,baseRefName,mergeCommit,isDraft,body,updatedAt"
|
|
12027
|
+
"state,author,statusCheckRollup,reviewDecision,headRefOid,mergeable,baseRefName,mergeCommit,isDraft,body,updatedAt,autoMergeRequest"
|
|
11995
12028
|
], { cwd: repoPath });
|
|
11996
|
-
const
|
|
11997
|
-
if (!
|
|
11998
|
-
return
|
|
12029
|
+
const parsed = r.status === 0 ? parsePrView(r.stdout) : null;
|
|
12030
|
+
if (!parsed || parsed.state !== "OPEN")
|
|
12031
|
+
return parsed;
|
|
12032
|
+
const ready = !parsed.queued && parsed.failing.length === 0 && parsed.pending === 0 && parsed.reviewDecision === "APPROVED";
|
|
12033
|
+
const view = ready && prInMergeQueue(exec, repoPath, url) === true ? { ...parsed, queued: true } : parsed;
|
|
11999
12034
|
let read = view.updatedAt && last?.updatedAt === view.updatedAt ? last : undefined;
|
|
12000
12035
|
if (!read) {
|
|
12001
12036
|
const f = prFeedback(exec, repoPath, url, view.author);
|
|
@@ -13207,9 +13242,12 @@ function sledsSource(client, o) {
|
|
|
13207
13242
|
if (r.status >= 300 || !r.json || r.json.ok === false)
|
|
13208
13243
|
throw new Error(serverMessage(r));
|
|
13209
13244
|
const leaseUntil = typeof r.json.leaseUntil === "number" ? r.json.leaseUntil : undefined;
|
|
13245
|
+
const resumed = r.json.resumed === true;
|
|
13246
|
+
const seatFull = !resumed && typeof r.json.seatFull === "string" ? r.json.seatFull : "";
|
|
13210
13247
|
return {
|
|
13211
|
-
resumed
|
|
13212
|
-
...leaseUntil !== undefined ? { leaseUntil } : {}
|
|
13248
|
+
resumed,
|
|
13249
|
+
...leaseUntil !== undefined ? { leaseUntil } : {},
|
|
13250
|
+
...seatFull ? { seatFull } : {}
|
|
13213
13251
|
};
|
|
13214
13252
|
},
|
|
13215
13253
|
async decisionOf(item, decisionId) {
|
|
@@ -13880,14 +13918,18 @@ async function tickOnce(d) {
|
|
|
13880
13918
|
try {
|
|
13881
13919
|
open = runner.status(run.handle) === "running";
|
|
13882
13920
|
} catch {}
|
|
13883
|
-
if (open &&
|
|
13884
|
-
|
|
13921
|
+
if (!open && !liveAnswerer(run)) {
|
|
13922
|
+
d.log(`${ref(run)}: the parked session closed — its answer will start a new one`);
|
|
13885
13923
|
continue;
|
|
13886
13924
|
}
|
|
13887
|
-
if (
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13925
|
+
if (await parkedBeat(d, run, claim) === "done") {
|
|
13926
|
+
d.log(`${ref(run)}: no longer waits for an answer — its node was skipped`);
|
|
13927
|
+
stopAnswerer(d, run);
|
|
13928
|
+
continue;
|
|
13929
|
+
}
|
|
13930
|
+
if (open)
|
|
13931
|
+
await answeredInSession(d, runner, run);
|
|
13932
|
+
keep.push(run);
|
|
13891
13933
|
continue;
|
|
13892
13934
|
}
|
|
13893
13935
|
if (run.pr) {
|
|
@@ -14084,7 +14126,25 @@ async function tickOnce(d) {
|
|
|
14084
14126
|
state.decisions = kept;
|
|
14085
14127
|
save();
|
|
14086
14128
|
}
|
|
14087
|
-
|
|
14129
|
+
let items;
|
|
14130
|
+
try {
|
|
14131
|
+
items = await d.source.read();
|
|
14132
|
+
} catch (e) {
|
|
14133
|
+
if (e instanceof SeatTokenError)
|
|
14134
|
+
throw e;
|
|
14135
|
+
save();
|
|
14136
|
+
return {
|
|
14137
|
+
started: [],
|
|
14138
|
+
finished,
|
|
14139
|
+
...counts(state),
|
|
14140
|
+
attention,
|
|
14141
|
+
done: false,
|
|
14142
|
+
items: [],
|
|
14143
|
+
changes,
|
|
14144
|
+
decisions: decided,
|
|
14145
|
+
readFailed: message(e)
|
|
14146
|
+
};
|
|
14147
|
+
}
|
|
14088
14148
|
const takeNone = seat.gone;
|
|
14089
14149
|
for (const it of items)
|
|
14090
14150
|
if (it.draft && !takeNone && !startsHeld(d))
|
|
@@ -14325,18 +14385,23 @@ async function tickOnce(d) {
|
|
|
14325
14385
|
started.push({ item: claim.item, node: claim.node, watch, watchTarget: watchTarget(handle) });
|
|
14326
14386
|
}
|
|
14327
14387
|
const done = items.length > 0 && items.every((i) => i.landed) && state.runs.length === 0;
|
|
14328
|
-
const following = state.runs.filter((r) => r.pr).length;
|
|
14329
|
-
const parked = state.runs.filter((r) => r.parked).length;
|
|
14330
14388
|
return {
|
|
14331
14389
|
started,
|
|
14332
14390
|
finished,
|
|
14333
|
-
|
|
14334
|
-
following,
|
|
14391
|
+
...counts(state),
|
|
14335
14392
|
attention,
|
|
14336
14393
|
done,
|
|
14337
14394
|
items,
|
|
14338
14395
|
changes,
|
|
14339
|
-
decisions: decided
|
|
14396
|
+
decisions: decided
|
|
14397
|
+
};
|
|
14398
|
+
}
|
|
14399
|
+
function counts(state) {
|
|
14400
|
+
const following = state.runs.filter((r) => r.pr).length;
|
|
14401
|
+
const parked = state.runs.filter((r) => r.parked).length;
|
|
14402
|
+
return {
|
|
14403
|
+
running: state.runs.length - following - parked,
|
|
14404
|
+
following,
|
|
14340
14405
|
followed: state.runs.flatMap((r) => r.pr ? [{ item: r.item, node: r.node, url: r.pr.url, ...r.pr.ci ? { ci: r.pr.ci } : {} }] : [])
|
|
14341
14406
|
};
|
|
14342
14407
|
}
|
|
@@ -14810,15 +14875,20 @@ async function answeredInSession(d, runner, run) {
|
|
|
14810
14875
|
return false;
|
|
14811
14876
|
}
|
|
14812
14877
|
const words = wordsPrint(shown);
|
|
14813
|
-
|
|
14814
|
-
|
|
14815
|
-
|
|
14878
|
+
const waiting = parked.seatFull !== undefined;
|
|
14879
|
+
if (waiting) {
|
|
14880
|
+
parked.words = words;
|
|
14881
|
+
} else {
|
|
14882
|
+
if (words === parked.words) {
|
|
14883
|
+
parked.still = true;
|
|
14884
|
+
return false;
|
|
14885
|
+
}
|
|
14886
|
+
const moved = parked.still === true;
|
|
14887
|
+
parked.words = words;
|
|
14888
|
+
parked.still = false;
|
|
14889
|
+
if (!moved)
|
|
14890
|
+
return false;
|
|
14816
14891
|
}
|
|
14817
|
-
const moved = parked.still === true;
|
|
14818
|
-
parked.words = words;
|
|
14819
|
-
parked.still = false;
|
|
14820
|
-
if (!moved)
|
|
14821
|
-
return false;
|
|
14822
14892
|
let r;
|
|
14823
14893
|
try {
|
|
14824
14894
|
r = await resumes.resumeParked(run.runId, "answered in the session", d.engine, d.leaseMin);
|
|
@@ -14826,7 +14896,14 @@ async function answeredInSession(d, runner, run) {
|
|
|
14826
14896
|
d.log(`${ref(run)}: the parked session moved on, but SLEDS did not hear it: ${message(e)}`);
|
|
14827
14897
|
return false;
|
|
14828
14898
|
}
|
|
14899
|
+
if (!r.resumed && r.seatFull) {
|
|
14900
|
+
if (!waiting)
|
|
14901
|
+
d.log(`${ref(run)}: answered in the session, but ${r.seatFull} — stays in Needs you until a slot frees`);
|
|
14902
|
+
parked.seatFull = r.seatFull;
|
|
14903
|
+
return false;
|
|
14904
|
+
}
|
|
14829
14905
|
if (!r.resumed) {
|
|
14906
|
+
parked.seatFull = undefined;
|
|
14830
14907
|
d.log(`${ref(run)}: the parked session moved on, but the node is no longer parked on its run`);
|
|
14831
14908
|
return false;
|
|
14832
14909
|
}
|
|
@@ -15203,6 +15280,14 @@ async function endUnposted(d, answers, a, runner, at, over) {
|
|
|
15203
15280
|
return false;
|
|
15204
15281
|
}
|
|
15205
15282
|
}
|
|
15283
|
+
async function parkedBeat(d, run, claim) {
|
|
15284
|
+
try {
|
|
15285
|
+
return await d.source.heartbeat(claim);
|
|
15286
|
+
} catch (e) {
|
|
15287
|
+
d.log(`${ref(run)}: heartbeat failed, retrying next tick: ${message(e)}`);
|
|
15288
|
+
return "running";
|
|
15289
|
+
}
|
|
15290
|
+
}
|
|
15206
15291
|
function stopAnswerer(d, run) {
|
|
15207
15292
|
const a = liveAnswerer(run);
|
|
15208
15293
|
if (!a)
|
|
@@ -15538,16 +15623,22 @@ async function follow(d, state, run, claim, runner, finished, attention, changes
|
|
|
15538
15623
|
pr.failing = view.failing;
|
|
15539
15624
|
pr.feedback = Math.max(pr.feedback, view.feedback);
|
|
15540
15625
|
pr.authorFeedback = Math.max(pr.authorFeedback ?? 0, view.authorFeedback) || undefined;
|
|
15541
|
-
const
|
|
15626
|
+
const queued = view.queued;
|
|
15627
|
+
if (queued && !pr.queued)
|
|
15628
|
+
d.log(`${ref(run)}: ${pr.url} is queued to merge`);
|
|
15629
|
+
else if (!queued && pr.queued)
|
|
15630
|
+
d.log(`${ref(run)}: ${pr.url} left the merge queue`);
|
|
15631
|
+
pr.queued = queued || undefined;
|
|
15632
|
+
const clear = view.failing.length === 0 && view.pending === 0 && view.reviewDecision === "APPROVED" && !queued;
|
|
15542
15633
|
if (clear && !pr.clear) {
|
|
15543
15634
|
d.log(`${ref(run)}: ${pr.url} is green and approved — ready for your merge call`);
|
|
15544
15635
|
attention.push({ ...at, what: "green and approved: ready for a merge" });
|
|
15545
15636
|
}
|
|
15546
15637
|
pr.clear = clear;
|
|
15547
15638
|
const prRead = d.source.prRead;
|
|
15548
|
-
const posted = `${ci}|${review}|${clear}`;
|
|
15639
|
+
const posted = `${ci}|${review}|${clear}|${queued}`;
|
|
15549
15640
|
if (prRead && posted !== pr.posted) {
|
|
15550
|
-
const read = { ci, ...review ? { review } : {}, clear };
|
|
15641
|
+
const read = { ci, ...review ? { review } : {}, clear, queued };
|
|
15551
15642
|
if (await prRead.call(d.source, run.item, run.node, read))
|
|
15552
15643
|
pr.posted = posted;
|
|
15553
15644
|
}
|
|
@@ -16305,6 +16396,41 @@ async function settleEvent(d, events, state, dec, attention, decided) {
|
|
|
16305
16396
|
|
|
16306
16397
|
// src/commands/engine.ts
|
|
16307
16398
|
init_machine();
|
|
16399
|
+
|
|
16400
|
+
// src/engine/sledsBreaker.ts
|
|
16401
|
+
var SLEDS_DOWN_ERROR = "SledsDownError";
|
|
16402
|
+
function why(e) {
|
|
16403
|
+
const name = e instanceof Error ? e.name : "";
|
|
16404
|
+
return name === "TimeoutError" || name === "AbortError" ? "timed out" : "could not be reached";
|
|
16405
|
+
}
|
|
16406
|
+
function sledsBreaker(fetchFn = fetch) {
|
|
16407
|
+
let down = null;
|
|
16408
|
+
let pass = 0;
|
|
16409
|
+
return {
|
|
16410
|
+
async fetch(input, init) {
|
|
16411
|
+
if (down !== null) {
|
|
16412
|
+
const e = new Error(`skipped — SLEDS ${down} earlier this tick`);
|
|
16413
|
+
e.name = SLEDS_DOWN_ERROR;
|
|
16414
|
+
throw e;
|
|
16415
|
+
}
|
|
16416
|
+
const started = pass;
|
|
16417
|
+
try {
|
|
16418
|
+
return await fetchFn(input, init);
|
|
16419
|
+
} catch (e) {
|
|
16420
|
+
if (started === pass && down === null)
|
|
16421
|
+
down = why(e);
|
|
16422
|
+
throw e;
|
|
16423
|
+
}
|
|
16424
|
+
},
|
|
16425
|
+
reset() {
|
|
16426
|
+
down = null;
|
|
16427
|
+
pass++;
|
|
16428
|
+
},
|
|
16429
|
+
tripped: () => down
|
|
16430
|
+
};
|
|
16431
|
+
}
|
|
16432
|
+
|
|
16433
|
+
// src/commands/engine.ts
|
|
16308
16434
|
init_state();
|
|
16309
16435
|
init_meter();
|
|
16310
16436
|
|
|
@@ -17428,7 +17554,7 @@ async function fetchVersion(o) {
|
|
|
17428
17554
|
const platform = o.platform ?? process.platform;
|
|
17429
17555
|
const arch = o.arch ?? process.arch;
|
|
17430
17556
|
const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
|
|
17431
|
-
const running = o.running ?? "0.1.
|
|
17557
|
+
const running = o.running ?? "0.1.56";
|
|
17432
17558
|
if (!publicKey)
|
|
17433
17559
|
return { ok: false, why: "no release key yet" };
|
|
17434
17560
|
if (!VERSION_RE2.test(o.version))
|
|
@@ -19003,7 +19129,7 @@ async function withProfile(client, flags, given, home, retry) {
|
|
|
19003
19129
|
}
|
|
19004
19130
|
var NOT_SET_UP2 = "SLEDS is not set up on this machine. Run `sleds init` first.";
|
|
19005
19131
|
var ENGINE_TIMEOUT_MS = 15000;
|
|
19006
|
-
function engineClient(o, org) {
|
|
19132
|
+
function engineClient(o, org, breaker) {
|
|
19007
19133
|
if (o.client)
|
|
19008
19134
|
return o.client;
|
|
19009
19135
|
const env = o.env ?? process.env;
|
|
@@ -19011,8 +19137,9 @@ function engineClient(o, org) {
|
|
|
19011
19137
|
if (src)
|
|
19012
19138
|
return fetchClient({
|
|
19013
19139
|
...src,
|
|
19140
|
+
...breaker ? { fetchFn: breaker.fetch } : {},
|
|
19014
19141
|
timeoutMs: ENGINE_TIMEOUT_MS,
|
|
19015
|
-
version: "0.1.
|
|
19142
|
+
version: "0.1.56"
|
|
19016
19143
|
});
|
|
19017
19144
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
19018
19145
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -19030,9 +19157,9 @@ function engineOrg(o, flag) {
|
|
|
19030
19157
|
known.delete(slug);
|
|
19031
19158
|
return { slug, seated: Boolean(cfg.orgs?.[slug]), sole: known.size === 0 };
|
|
19032
19159
|
}
|
|
19033
|
-
function orgClient(o, flag) {
|
|
19160
|
+
function orgClient(o, flag, breaker) {
|
|
19034
19161
|
const org = engineOrg(o, flag);
|
|
19035
|
-
return engineClient(o, org.seated ? org.slug ?? undefined : flag);
|
|
19162
|
+
return engineClient(o, org.seated ? org.slug ?? undefined : flag, breaker);
|
|
19036
19163
|
}
|
|
19037
19164
|
function realPidAlive2(pid) {
|
|
19038
19165
|
try {
|
|
@@ -19303,7 +19430,7 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
19303
19430
|
runner: deps.runner.name,
|
|
19304
19431
|
atOnce: flags.atOnce,
|
|
19305
19432
|
interval: flags.interval,
|
|
19306
|
-
cliVersion: "0.1.
|
|
19433
|
+
cliVersion: "0.1.56"
|
|
19307
19434
|
};
|
|
19308
19435
|
const beat = (checkedAt) => {
|
|
19309
19436
|
const m = deps.machine;
|
|
@@ -19384,35 +19511,42 @@ async function drive(o, flags, deps, until, beat) {
|
|
|
19384
19511
|
await until.beforeFirstTick?.();
|
|
19385
19512
|
for (;; ) {
|
|
19386
19513
|
let report = null;
|
|
19514
|
+
let why;
|
|
19515
|
+
until.breaker?.reset();
|
|
19387
19516
|
try {
|
|
19388
19517
|
report = await tick(deps);
|
|
19518
|
+
why = report.readFailed;
|
|
19389
19519
|
} catch (e) {
|
|
19520
|
+
why = e instanceof Error ? e.message : String(e);
|
|
19521
|
+
}
|
|
19522
|
+
if (why !== undefined) {
|
|
19390
19523
|
down++;
|
|
19391
|
-
const why = e instanceof Error ? e.message : String(e);
|
|
19392
19524
|
if (down === 1 || flags.once)
|
|
19393
19525
|
event({
|
|
19394
19526
|
kind: "sleds-down",
|
|
19395
19527
|
text: why,
|
|
19396
19528
|
...flags.once ? {} : { aside: `· retrying every ${flags.interval} s` }
|
|
19397
19529
|
});
|
|
19398
|
-
if (flags.once)
|
|
19530
|
+
if (flags.once && !report)
|
|
19399
19531
|
return 1;
|
|
19400
19532
|
}
|
|
19401
19533
|
beat(now());
|
|
19402
|
-
const leave = await until.afterTick?.(report !== null);
|
|
19534
|
+
const leave = await until.afterTick?.(report !== null && !report.readFailed);
|
|
19403
19535
|
if (typeof leave === "number") {
|
|
19404
19536
|
if (statusShown)
|
|
19405
19537
|
write("\r\x1B[2K");
|
|
19406
19538
|
return leave;
|
|
19407
19539
|
}
|
|
19408
19540
|
if (report) {
|
|
19409
|
-
if (
|
|
19410
|
-
|
|
19411
|
-
|
|
19412
|
-
|
|
19413
|
-
|
|
19414
|
-
|
|
19415
|
-
|
|
19541
|
+
if (!report.readFailed) {
|
|
19542
|
+
if (down > 0)
|
|
19543
|
+
event({
|
|
19544
|
+
kind: "sleds-back",
|
|
19545
|
+
text: "back",
|
|
19546
|
+
aside: `after ${down} failed ${down === 1 ? "read" : "reads"}`
|
|
19547
|
+
});
|
|
19548
|
+
down = 0;
|
|
19549
|
+
}
|
|
19416
19550
|
running = report.running;
|
|
19417
19551
|
if (report.seatChanged || report.tokenChanged) {
|
|
19418
19552
|
if (statusShown)
|
|
@@ -19462,6 +19596,8 @@ async function drive(o, flags, deps, until, beat) {
|
|
|
19462
19596
|
pr: a.url
|
|
19463
19597
|
});
|
|
19464
19598
|
}
|
|
19599
|
+
if (flags.once && report.readFailed)
|
|
19600
|
+
return 1;
|
|
19465
19601
|
if (until.done && report.done) {
|
|
19466
19602
|
if (statusShown)
|
|
19467
19603
|
write("\r\x1B[2K");
|
|
@@ -21151,7 +21287,7 @@ async function withProfile2(client, flags, given, home, retry) {
|
|
|
21151
21287
|
}
|
|
21152
21288
|
var NOT_SET_UP3 = "SLEDS is not set up on this machine. Run `sleds init` first.";
|
|
21153
21289
|
var ENGINE_TIMEOUT_MS2 = 15000;
|
|
21154
|
-
function engineClient2(o, org) {
|
|
21290
|
+
function engineClient2(o, org, breaker) {
|
|
21155
21291
|
if (o.client)
|
|
21156
21292
|
return o.client;
|
|
21157
21293
|
const env = o.env ?? process.env;
|
|
@@ -21159,8 +21295,9 @@ function engineClient2(o, org) {
|
|
|
21159
21295
|
if (src)
|
|
21160
21296
|
return fetchClient({
|
|
21161
21297
|
...src,
|
|
21298
|
+
...breaker ? { fetchFn: breaker.fetch } : {},
|
|
21162
21299
|
timeoutMs: ENGINE_TIMEOUT_MS2,
|
|
21163
|
-
version: "0.1.
|
|
21300
|
+
version: "0.1.56"
|
|
21164
21301
|
});
|
|
21165
21302
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
21166
21303
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -21178,9 +21315,9 @@ function engineOrg2(o, flag) {
|
|
|
21178
21315
|
known.delete(slug);
|
|
21179
21316
|
return { slug, seated: Boolean(cfg.orgs?.[slug]), sole: known.size === 0 };
|
|
21180
21317
|
}
|
|
21181
|
-
function orgClient2(o, flag) {
|
|
21318
|
+
function orgClient2(o, flag, breaker) {
|
|
21182
21319
|
const org = engineOrg2(o, flag);
|
|
21183
|
-
return engineClient2(o, org.seated ? org.slug ?? undefined : flag);
|
|
21320
|
+
return engineClient2(o, org.seated ? org.slug ?? undefined : flag, breaker);
|
|
21184
21321
|
}
|
|
21185
21322
|
async function jiraWritesAtStart(gate, epic) {
|
|
21186
21323
|
const no = await gate.ask({
|
|
@@ -21486,7 +21623,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
21486
21623
|
runner: deps.runner.name,
|
|
21487
21624
|
atOnce: flags.atOnce,
|
|
21488
21625
|
interval: flags.interval,
|
|
21489
|
-
cliVersion: "0.1.
|
|
21626
|
+
cliVersion: "0.1.56"
|
|
21490
21627
|
};
|
|
21491
21628
|
const beat = (checkedAt) => {
|
|
21492
21629
|
const m = deps.machine;
|
|
@@ -21567,35 +21704,42 @@ async function drive2(o, flags, deps, until, beat) {
|
|
|
21567
21704
|
await until.beforeFirstTick?.();
|
|
21568
21705
|
for (;; ) {
|
|
21569
21706
|
let report = null;
|
|
21707
|
+
let why;
|
|
21708
|
+
until.breaker?.reset();
|
|
21570
21709
|
try {
|
|
21571
21710
|
report = await tick(deps);
|
|
21711
|
+
why = report.readFailed;
|
|
21572
21712
|
} catch (e) {
|
|
21713
|
+
why = e instanceof Error ? e.message : String(e);
|
|
21714
|
+
}
|
|
21715
|
+
if (why !== undefined) {
|
|
21573
21716
|
down++;
|
|
21574
|
-
const why = e instanceof Error ? e.message : String(e);
|
|
21575
21717
|
if (down === 1 || flags.once)
|
|
21576
21718
|
event({
|
|
21577
21719
|
kind: "sleds-down",
|
|
21578
21720
|
text: why,
|
|
21579
21721
|
...flags.once ? {} : { aside: `· retrying every ${flags.interval} s` }
|
|
21580
21722
|
});
|
|
21581
|
-
if (flags.once)
|
|
21723
|
+
if (flags.once && !report)
|
|
21582
21724
|
return 1;
|
|
21583
21725
|
}
|
|
21584
21726
|
beat(now());
|
|
21585
|
-
const leave = await until.afterTick?.(report !== null);
|
|
21727
|
+
const leave = await until.afterTick?.(report !== null && !report.readFailed);
|
|
21586
21728
|
if (typeof leave === "number") {
|
|
21587
21729
|
if (statusShown)
|
|
21588
21730
|
write("\r\x1B[2K");
|
|
21589
21731
|
return leave;
|
|
21590
21732
|
}
|
|
21591
21733
|
if (report) {
|
|
21592
|
-
if (
|
|
21593
|
-
|
|
21594
|
-
|
|
21595
|
-
|
|
21596
|
-
|
|
21597
|
-
|
|
21598
|
-
|
|
21734
|
+
if (!report.readFailed) {
|
|
21735
|
+
if (down > 0)
|
|
21736
|
+
event({
|
|
21737
|
+
kind: "sleds-back",
|
|
21738
|
+
text: "back",
|
|
21739
|
+
aside: `after ${down} failed ${down === 1 ? "read" : "reads"}`
|
|
21740
|
+
});
|
|
21741
|
+
down = 0;
|
|
21742
|
+
}
|
|
21599
21743
|
running = report.running;
|
|
21600
21744
|
if (report.seatChanged || report.tokenChanged) {
|
|
21601
21745
|
if (statusShown)
|
|
@@ -21645,6 +21789,8 @@ async function drive2(o, flags, deps, until, beat) {
|
|
|
21645
21789
|
pr: a.url
|
|
21646
21790
|
});
|
|
21647
21791
|
}
|
|
21792
|
+
if (flags.once && report.readFailed)
|
|
21793
|
+
return 1;
|
|
21648
21794
|
if (until.done && report.done) {
|
|
21649
21795
|
if (statusShown)
|
|
21650
21796
|
write("\r\x1B[2K");
|
|
@@ -21720,17 +21866,22 @@ var engineCmd = async (o) => {
|
|
|
21720
21866
|
error(kept.refused);
|
|
21721
21867
|
return 1;
|
|
21722
21868
|
}
|
|
21869
|
+
const breaker = sledsBreaker(o.fetch);
|
|
21723
21870
|
let client;
|
|
21724
21871
|
let pickup;
|
|
21725
21872
|
if (!flags.jira && (o.client || !o.source)) {
|
|
21726
|
-
const c = orgClient2(o, given);
|
|
21873
|
+
const c = orgClient2(o, given, breaker);
|
|
21727
21874
|
if ("error" in c) {
|
|
21728
21875
|
error(c.error);
|
|
21729
21876
|
return 1;
|
|
21730
21877
|
}
|
|
21731
21878
|
client = c;
|
|
21879
|
+
const sleep = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
21732
21880
|
const p = await withProfile2(c, flags, parsed.given, o.home, {
|
|
21733
|
-
sleep:
|
|
21881
|
+
sleep: async (ms) => {
|
|
21882
|
+
await sleep(ms);
|
|
21883
|
+
breaker.reset();
|
|
21884
|
+
}
|
|
21734
21885
|
});
|
|
21735
21886
|
flags = p.flags;
|
|
21736
21887
|
pickup = p.pickup;
|
|
@@ -21766,7 +21917,7 @@ var engineCmd = async (o) => {
|
|
|
21766
21917
|
error(missing);
|
|
21767
21918
|
return 1;
|
|
21768
21919
|
}
|
|
21769
|
-
const c = o.client ?? orgClient2(o, given);
|
|
21920
|
+
const c = o.client ?? orgClient2(o, given, breaker);
|
|
21770
21921
|
if ("error" in c) {
|
|
21771
21922
|
error(`--jira asks SLEDS before every write to Jira (spec 39), so it needs a seat: ${c.error}`);
|
|
21772
21923
|
return 1;
|
|
@@ -21899,7 +22050,7 @@ var engineCmd = async (o) => {
|
|
|
21899
22050
|
};
|
|
21900
22051
|
}
|
|
21901
22052
|
try {
|
|
21902
|
-
return await driveEngine2(o, flags, deps, { afterTick, beforeFirstTick });
|
|
22053
|
+
return await driveEngine2(o, flags, deps, { afterTick, beforeFirstTick, breaker });
|
|
21903
22054
|
} finally {
|
|
21904
22055
|
watch.stop();
|
|
21905
22056
|
}
|
|
@@ -22671,6 +22822,7 @@ function engineStatus(i) {
|
|
|
22671
22822
|
failing: r.pr.failing,
|
|
22672
22823
|
...opt("review", r.pr.review || undefined),
|
|
22673
22824
|
mergeable: r.pr.clear === true,
|
|
22825
|
+
queued: r.pr.queued === true,
|
|
22674
22826
|
...opt("conflict", conflictOf(r, i.state.decisions, i.watchOf))
|
|
22675
22827
|
});
|
|
22676
22828
|
continue;
|
|
@@ -22748,7 +22900,7 @@ function statusLines(s, now) {
|
|
|
22748
22900
|
lines.push(` ${r.item}/${r.node} ${r.title} · ${r.answerer ? `parked, the decider answers${r.answerer.model ? ` on ${r.answerer.model}` : ""}${r.answerer.effort ? ` · ${r.answerer.effort}` : ""}` : r.parked ? "parked, waiting for your answer" : ago(r.startedAt)} · watch: ${r.watch}`);
|
|
22749
22901
|
lines.push(`following ${s.following.length}`);
|
|
22750
22902
|
for (const f of s.following) {
|
|
22751
|
-
lines.push(` ${f.item}/${f.node} ${f.pr}${f.checks ? ` checks ${f.checks}` : ""}${f.review ? ` · ${f.review}` : ""}${f.mergeable ? " · ready for your merge" : ""}`);
|
|
22903
|
+
lines.push(` ${f.item}/${f.node} ${f.pr}${f.checks ? ` checks ${f.checks}` : ""}${f.review ? ` · ${f.review}` : ""}${f.mergeable ? " · ready for your merge" : ""}${f.queued ? " · queued to merge" : ""}`);
|
|
22752
22904
|
const c = f.conflict;
|
|
22753
22905
|
if (c)
|
|
22754
22906
|
lines.push(` conflict on ${c.files.join(", ")}${c.cause ? ` · ${c.cause}` : ""} · ${CONFLICT_STAGE[c.stage]} · since ${ago(c.since)} ago${c.watch ? ` · watch: ${c.watch}` : ""}`);
|
|
@@ -23574,7 +23726,7 @@ function contextFor(deps) {
|
|
|
23574
23726
|
...src,
|
|
23575
23727
|
fetchFn: deps.fetchFn,
|
|
23576
23728
|
timeoutMs: deps.timeoutMs,
|
|
23577
|
-
version: "0.1.
|
|
23729
|
+
version: "0.1.56"
|
|
23578
23730
|
}), deps.home, now) : null;
|
|
23579
23731
|
return {
|
|
23580
23732
|
channel: "code",
|
|
@@ -26299,7 +26451,7 @@ function parseSeatRevokeArgs(argv) {
|
|
|
26299
26451
|
}
|
|
26300
26452
|
return { box, yes, json };
|
|
26301
26453
|
}
|
|
26302
|
-
function
|
|
26454
|
+
function why2(j, status) {
|
|
26303
26455
|
if (typeof j?.reason === "string")
|
|
26304
26456
|
return j.reason;
|
|
26305
26457
|
if (typeof j?.error === "string")
|
|
@@ -26337,7 +26489,7 @@ async function seatRevokeCmd(o) {
|
|
|
26337
26489
|
return ok ? 0 : 1;
|
|
26338
26490
|
}
|
|
26339
26491
|
if (!ok) {
|
|
26340
|
-
error(clean(`nothing revoked — ${
|
|
26492
|
+
error(clean(`nothing revoked — ${why2(r.json, r.status)}`));
|
|
26341
26493
|
return 1;
|
|
26342
26494
|
}
|
|
26343
26495
|
const label = typeof r.json?.label === "string" ? r.json.label : a.box ? `box:${a.box}` : "";
|
|
@@ -27692,7 +27844,7 @@ var realPidAlive4 = (pid) => {
|
|
|
27692
27844
|
};
|
|
27693
27845
|
function machineClient(home, env) {
|
|
27694
27846
|
const src = meterSource(home, undefined, { env });
|
|
27695
|
-
return src ? fetchClient({ ...src, version: "0.1.
|
|
27847
|
+
return src ? fetchClient({ ...src, version: "0.1.56" }) : null;
|
|
27696
27848
|
}
|
|
27697
27849
|
async function noteAnswer2(home, a, now) {
|
|
27698
27850
|
try {
|
|
@@ -28552,7 +28704,7 @@ var main = async (argv) => {
|
|
|
28552
28704
|
now: Date.now(),
|
|
28553
28705
|
stderr: (line) => console.error(line),
|
|
28554
28706
|
isTTY: !!process.stderr.isTTY,
|
|
28555
|
-
version: "0.1.
|
|
28707
|
+
version: "0.1.56"
|
|
28556
28708
|
});
|
|
28557
28709
|
switch (cmd) {
|
|
28558
28710
|
case "update":
|
|
@@ -28785,7 +28937,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
28785
28937
|
case "version":
|
|
28786
28938
|
case "--version":
|
|
28787
28939
|
case "-v":
|
|
28788
|
-
console.log("sleds 0.1.
|
|
28940
|
+
console.log("sleds 0.1.56");
|
|
28789
28941
|
return 0;
|
|
28790
28942
|
default:
|
|
28791
28943
|
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.56",
|
|
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",
|