@sleds/cli 0.1.51 → 0.1.53
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 +346 -63
- package/package.json +1 -1
package/dist/sleds.mjs
CHANGED
|
@@ -5689,11 +5689,20 @@ var init_copy = __esm(() => {
|
|
|
5689
5689
|
});
|
|
5690
5690
|
|
|
5691
5691
|
// ../../packages/shared/src/slack/agent.ts
|
|
5692
|
+
var REPLY_RULES;
|
|
5692
5693
|
var init_agent = __esm(() => {
|
|
5693
5694
|
init_intake();
|
|
5694
5695
|
init_brief();
|
|
5695
5696
|
init_copy();
|
|
5696
5697
|
init_mention();
|
|
5698
|
+
REPLY_RULES = [
|
|
5699
|
+
"How to answer this reply:",
|
|
5700
|
+
'- If it answers nothing and changes nothing — thanks, "noted", "copy", "will do", or people talking to each other — set quiet to true and post nothing.',
|
|
5701
|
+
"- Never ask a question the thread already asked. If it is still open, say only what is still needed, once, in a few words.",
|
|
5702
|
+
"- If someone in the thread already gave the cause or a fix, do not ask the poster for details it makes moot. Say in one line what is left, or set quiet.",
|
|
5703
|
+
"- Keep it to what changed and what is next. No recap of the ask."
|
|
5704
|
+
].join(`
|
|
5705
|
+
`);
|
|
5697
5706
|
});
|
|
5698
5707
|
|
|
5699
5708
|
// ../../packages/shared/src/slack/channel.ts
|
|
@@ -8545,7 +8554,13 @@ function parseParked(v) {
|
|
|
8545
8554
|
...typeof a.effort === "string" ? { effort: a.effort } : {}
|
|
8546
8555
|
};
|
|
8547
8556
|
}
|
|
8548
|
-
return {
|
|
8557
|
+
return {
|
|
8558
|
+
question: v.question,
|
|
8559
|
+
at: v.at,
|
|
8560
|
+
...typeof v.screen === "string" ? { screen: v.screen } : {},
|
|
8561
|
+
...v.still === true ? { still: true } : {},
|
|
8562
|
+
...answerer ? { answerer } : {}
|
|
8563
|
+
};
|
|
8549
8564
|
}
|
|
8550
8565
|
function parseRun(v) {
|
|
8551
8566
|
if (!isObject8(v))
|
|
@@ -8585,7 +8600,11 @@ function parseRun(v) {
|
|
|
8585
8600
|
decisionId: v.permission.decisionId,
|
|
8586
8601
|
options: Array.isArray(v.permission.options) ? v.permission.options.filter((x) => typeof x === "string") : [],
|
|
8587
8602
|
at: v.permission.at,
|
|
8588
|
-
...v.permission.onScreen === true ? { onScreen: true } : {}
|
|
8603
|
+
...v.permission.onScreen === true ? { onScreen: true } : {},
|
|
8604
|
+
...typeof v.permission.dialog === "string" ? { dialog: v.permission.dialog } : {},
|
|
8605
|
+
...typeof v.permission.pressedAt === "number" ? { pressedAt: v.permission.pressedAt } : {},
|
|
8606
|
+
...typeof v.permission.presses === "number" ? { presses: v.permission.presses } : {},
|
|
8607
|
+
...v.permission.gaveUp === true ? { gaveUp: true } : {}
|
|
8589
8608
|
}
|
|
8590
8609
|
} : {},
|
|
8591
8610
|
...isObject8(v.provider) && typeof v.provider.why === "string" && typeof v.provider.since === "number" && typeof v.provider.tries === "number" ? { provider: { why: v.provider.why, since: v.provider.since, tries: v.provider.tries } } : {},
|
|
@@ -8597,12 +8616,21 @@ function parseRun(v) {
|
|
|
8597
8616
|
feedback: typeof v.pr.feedback === "number" ? v.pr.feedback : 0,
|
|
8598
8617
|
...typeof v.pr.authorFeedback === "number" ? { authorFeedback: v.pr.authorFeedback } : {},
|
|
8599
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
|
+
} : {},
|
|
8600
8627
|
...v.pr.clear === true ? { clear: true } : {},
|
|
8601
8628
|
...typeof v.pr.ci === "string" ? { ci: v.pr.ci } : {},
|
|
8602
8629
|
...typeof v.pr.review === "string" ? { review: v.pr.review } : {},
|
|
8603
8630
|
...typeof v.pr.posted === "string" ? { posted: v.pr.posted } : {},
|
|
8604
8631
|
...Array.isArray(v.pr.failedHeads) ? { failedHeads: v.pr.failedHeads.filter((x) => typeof x === "string") } : {},
|
|
8605
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 } } : {},
|
|
8606
8634
|
...typeof v.pr.resolving === "string" ? { resolving: v.pr.resolving } : {},
|
|
8607
8635
|
...conflicted ? { conflicted } : {},
|
|
8608
8636
|
...typeof v.pr.reviewed === "string" ? { reviewed: v.pr.reviewed } : {},
|
|
@@ -10741,15 +10769,36 @@ var claudeAddDirFlag = (mainCheckout) => mainCheckout ? ` --add-dir=${shq(mainCh
|
|
|
10741
10769
|
var shq = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
10742
10770
|
|
|
10743
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
|
+
};
|
|
10744
10782
|
var defaultExec = (cmd, args, o) => {
|
|
10783
|
+
const timeoutMs = o?.timeoutMs ?? EXEC_TIMEOUT_MS;
|
|
10745
10784
|
const r = spawnSync3(cmd, [...args], {
|
|
10746
10785
|
cwd: o?.cwd,
|
|
10747
10786
|
input: o?.input,
|
|
10748
10787
|
env: o?.env ? { ...process.env, ...o.env } : undefined,
|
|
10749
10788
|
encoding: "utf8",
|
|
10750
10789
|
shell: false,
|
|
10751
|
-
maxBuffer: 16 * 1024 * 1024
|
|
10790
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
10791
|
+
timeout: timeoutMs,
|
|
10792
|
+
killSignal: "SIGKILL"
|
|
10752
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
|
+
}
|
|
10753
10802
|
if (r.error) {
|
|
10754
10803
|
return { status: 127, stdout: r.stdout ?? "", stderr: `${cmd}: ${r.error.message}` };
|
|
10755
10804
|
}
|
|
@@ -11243,6 +11292,8 @@ var orcaLauncher = (o) => `#!/bin/sh
|
|
|
11243
11292
|
${execLine(agentShellCommand(o))}
|
|
11244
11293
|
`;
|
|
11245
11294
|
var orcaCommand = (launcher) => `sh ${shq2(launcher)}; exit`;
|
|
11295
|
+
var orcaRequestId = (env, text) => str8(obj(obj(env?.error)?.data)?.orchestrationRequestId) ?? text.match(/--retry-request ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i)?.[1] ?? null;
|
|
11296
|
+
var ESC = "\x1B";
|
|
11246
11297
|
var GONE = /exit|clos|gone|dead|stopp|kill/i;
|
|
11247
11298
|
var orcaTerminalLive = (status, stdout) => {
|
|
11248
11299
|
const env = parseOrcaJson(stdout);
|
|
@@ -11327,6 +11378,7 @@ function orcaRunner(exec, deps = {}) {
|
|
|
11327
11378
|
}
|
|
11328
11379
|
return env;
|
|
11329
11380
|
};
|
|
11381
|
+
const retries = new Map;
|
|
11330
11382
|
return {
|
|
11331
11383
|
name: "orca",
|
|
11332
11384
|
makesWorktree: true,
|
|
@@ -11378,10 +11430,44 @@ function orcaRunner(exec, deps = {}) {
|
|
|
11378
11430
|
return r.status === 0 ? r.stdout : "";
|
|
11379
11431
|
},
|
|
11380
11432
|
send(h, text) {
|
|
11381
|
-
const
|
|
11382
|
-
|
|
11383
|
-
|
|
11433
|
+
const key = `${h.id}
|
|
11434
|
+
${text}`;
|
|
11435
|
+
const attempt = (retry) => {
|
|
11436
|
+
const r = exec("orca", [
|
|
11437
|
+
"terminal",
|
|
11438
|
+
"send",
|
|
11439
|
+
"--terminal",
|
|
11440
|
+
h.id,
|
|
11441
|
+
"--text",
|
|
11442
|
+
text,
|
|
11443
|
+
"--enter",
|
|
11444
|
+
...retry ? ["--retry-request", retry] : [],
|
|
11445
|
+
"--json"
|
|
11446
|
+
]);
|
|
11447
|
+
const env = parseOrcaJson(r.stdout);
|
|
11448
|
+
const ok = r.status === 0 && env?.ok !== false;
|
|
11449
|
+
return { r, env, ok, id: ok ? null : orcaRequestId(env, `${r.stderr}
|
|
11450
|
+
${r.stdout}`) };
|
|
11451
|
+
};
|
|
11452
|
+
const prior = retries.get(key);
|
|
11453
|
+
let a = attempt(prior);
|
|
11454
|
+
if (!a.ok && a.id && a.id !== prior)
|
|
11455
|
+
a = attempt(a.id);
|
|
11456
|
+
if (a.ok) {
|
|
11457
|
+
retries.delete(key);
|
|
11458
|
+
return;
|
|
11384
11459
|
}
|
|
11460
|
+
if (a.id)
|
|
11461
|
+
retries.set(key, a.id);
|
|
11462
|
+
else
|
|
11463
|
+
retries.delete(key);
|
|
11464
|
+
const why = orcaError(a.env) ?? (a.r.stderr.trim() || `exit ${a.r.status}`);
|
|
11465
|
+
throw new Error(`orca terminal send ${h.id} failed: ${why}`);
|
|
11466
|
+
},
|
|
11467
|
+
sendKey(h, key) {
|
|
11468
|
+
if (!isRunnerKey(key))
|
|
11469
|
+
throw new Error(`orca terminal send ${h.id}: no key ${JSON.stringify(key)}`);
|
|
11470
|
+
orca(["terminal", "send", "--terminal", h.id, "--text", key === "esc" ? ESC : key, "--json"], `orca terminal send ${h.id} (key ${key})`);
|
|
11385
11471
|
},
|
|
11386
11472
|
stop(h) {
|
|
11387
11473
|
exec("orca", ["terminal", "close", "--terminal", h.id]);
|
|
@@ -11449,7 +11535,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
11449
11535
|
name: flags.name,
|
|
11450
11536
|
os: host.os ?? process.platform,
|
|
11451
11537
|
runner: flags.runner,
|
|
11452
|
-
version: host.version ?? "0.1.
|
|
11538
|
+
version: host.version ?? "0.1.53" ?? "dev",
|
|
11453
11539
|
running: live.length,
|
|
11454
11540
|
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
11455
11541
|
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
@@ -11849,6 +11935,7 @@ function parsePrView(stdout) {
|
|
|
11849
11935
|
feedback: 0,
|
|
11850
11936
|
authorFeedback: 0,
|
|
11851
11937
|
draft: o.isDraft === true,
|
|
11938
|
+
updatedAt: typeof o.updatedAt === "string" ? o.updatedAt : "",
|
|
11852
11939
|
...mock ? { mock } : {},
|
|
11853
11940
|
...typeof o.headRefOid === "string" && o.headRefOid ? { head: o.headRefOid } : {},
|
|
11854
11941
|
...typeof mergeCommit === "string" && mergeCommit ? { mergeCommit } : {}
|
|
@@ -11897,20 +11984,24 @@ function prFeedback(exec, repoPath, url, author) {
|
|
|
11897
11984
|
}
|
|
11898
11985
|
return total;
|
|
11899
11986
|
}
|
|
11900
|
-
function prView(exec, repoPath, url) {
|
|
11987
|
+
function prView(exec, repoPath, url, last) {
|
|
11901
11988
|
try {
|
|
11902
11989
|
const r = exec("gh", [
|
|
11903
11990
|
"pr",
|
|
11904
11991
|
"view",
|
|
11905
11992
|
url,
|
|
11906
11993
|
"--json",
|
|
11907
|
-
"state,author,statusCheckRollup,reviewDecision,
|
|
11994
|
+
"state,author,statusCheckRollup,reviewDecision,headRefOid,mergeable,baseRefName,mergeCommit,isDraft,body,updatedAt"
|
|
11908
11995
|
], { cwd: repoPath });
|
|
11909
11996
|
const view = r.status === 0 ? parsePrView(r.stdout) : null;
|
|
11910
11997
|
if (!view || view.state !== "OPEN")
|
|
11911
11998
|
return view;
|
|
11912
|
-
|
|
11913
|
-
|
|
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;
|
|
11914
12005
|
} catch {
|
|
11915
12006
|
return null;
|
|
11916
12007
|
}
|
|
@@ -12454,6 +12545,10 @@ function permissionsOf(s) {
|
|
|
12454
12545
|
const p = s;
|
|
12455
12546
|
return p && typeof p.openPermission === "function" && typeof p.clearPermission === "function" && typeof p.decisionOf === "function" ? s : null;
|
|
12456
12547
|
}
|
|
12548
|
+
function resumesOf(s) {
|
|
12549
|
+
const r = s;
|
|
12550
|
+
return r && typeof r.resumeParked === "function" ? s : null;
|
|
12551
|
+
}
|
|
12457
12552
|
var FAIL_LOG_MAX = 2000;
|
|
12458
12553
|
var UNREACHABLE3 = "SLEDS unreachable";
|
|
12459
12554
|
function keysIn(states, state) {
|
|
@@ -12638,6 +12733,9 @@ function profileOf(r) {
|
|
|
12638
12733
|
const atOnce = num5(p.atOnce);
|
|
12639
12734
|
if (atOnce !== undefined && atOnce >= 1)
|
|
12640
12735
|
out.atOnce = Math.round(atOnce);
|
|
12736
|
+
const seatAtOnce = num5(r.seatAtOnce);
|
|
12737
|
+
if (seatAtOnce !== undefined && Number.isInteger(seatAtOnce) && seatAtOnce >= 1)
|
|
12738
|
+
out.seatAtOnce = seatAtOnce;
|
|
12641
12739
|
if (typeof p.mcpStrict === "boolean")
|
|
12642
12740
|
out.mcpStrict = p.mcpStrict;
|
|
12643
12741
|
const holdCpu = num5(p.holdCpu);
|
|
@@ -12942,26 +13040,28 @@ function sledsSource(client, o) {
|
|
|
12942
13040
|
});
|
|
12943
13041
|
if (r?.status !== 409)
|
|
12944
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";
|
|
12945
13051
|
if (claim.kind === "draft") {
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
|
|
12949
|
-
|
|
12950
|
-
|
|
12951
|
-
if (isObject8(route?.draftParked))
|
|
12952
|
-
return "parked";
|
|
12953
|
-
} 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";
|
|
12954
13057
|
return "lost";
|
|
12955
13058
|
}
|
|
12956
|
-
|
|
12957
|
-
|
|
12958
|
-
|
|
12959
|
-
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
if (state === "pr" || state === "landed" || state === "skipped")
|
|
12963
|
-
return "done";
|
|
12964
|
-
} 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";
|
|
12965
13065
|
return "lost";
|
|
12966
13066
|
},
|
|
12967
13067
|
async report(claim, outcome, by) {
|
|
@@ -13100,6 +13200,18 @@ function sledsSource(client, o) {
|
|
|
13100
13200
|
throw new Error(serverMessage(r));
|
|
13101
13201
|
return r.json.cleared === true;
|
|
13102
13202
|
},
|
|
13203
|
+
async resumeParked(runId, why, engine, leaseMin) {
|
|
13204
|
+
const r = await client.postFull("/proxy/run", { runId, engine, leaseMin, resumed: { why } });
|
|
13205
|
+
if (!r)
|
|
13206
|
+
throw new Error(`${UNREACHABLE3} — the resume not recorded`);
|
|
13207
|
+
if (r.status >= 300 || !r.json || r.json.ok === false)
|
|
13208
|
+
throw new Error(serverMessage(r));
|
|
13209
|
+
const leaseUntil = typeof r.json.leaseUntil === "number" ? r.json.leaseUntil : undefined;
|
|
13210
|
+
return {
|
|
13211
|
+
resumed: r.json.resumed === true,
|
|
13212
|
+
...leaseUntil !== undefined ? { leaseUntil } : {}
|
|
13213
|
+
};
|
|
13214
|
+
},
|
|
13103
13215
|
async decisionOf(item, decisionId) {
|
|
13104
13216
|
const route = await routeOf(item);
|
|
13105
13217
|
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject8) : [];
|
|
@@ -13445,6 +13557,7 @@ function fastForwardUntouched(exec, path, base, log) {
|
|
|
13445
13557
|
log?.(`${path}: fast-forwarded to origin/${base}`);
|
|
13446
13558
|
return true;
|
|
13447
13559
|
}
|
|
13560
|
+
var INSTALL_TIMEOUT_MS = 15 * 60000;
|
|
13448
13561
|
var MANAGERS = new Set(["pnpm", "npm", "yarn", "bun"]);
|
|
13449
13562
|
var INSTALL_VERBS = new Set(["install", "i", "ci"]);
|
|
13450
13563
|
function installArgv(command) {
|
|
@@ -13536,7 +13649,7 @@ function ensureInstalled(exec, path, fs, o = {}) {
|
|
|
13536
13649
|
return null;
|
|
13537
13650
|
const [cmd, ...args] = argv;
|
|
13538
13651
|
o.log?.(`${path}: no node_modules — running ${argv.join(" ")}`);
|
|
13539
|
-
const r = exec(cmd, args, { cwd: path });
|
|
13652
|
+
const r = exec(cmd, args, { cwd: path, timeoutMs: INSTALL_TIMEOUT_MS });
|
|
13540
13653
|
const ok = r.status === 0;
|
|
13541
13654
|
if (!ok)
|
|
13542
13655
|
o.log?.(`${path}: ${argv.join(" ")} failed (exit ${r.status}) — the session starts anyway: ${(r.stderr || r.stdout).trim().split(`
|
|
@@ -13692,6 +13805,7 @@ async function tick(deps) {
|
|
|
13692
13805
|
deps.providerHold = d.providerHold;
|
|
13693
13806
|
deps.draining = d.draining;
|
|
13694
13807
|
deps.atOnce = d.atOnce;
|
|
13808
|
+
deps.seatAtOnceNoted = d.seatAtOnceNoted;
|
|
13695
13809
|
deps.runner = d.runner;
|
|
13696
13810
|
deps.runnerRefused = d.runnerRefused;
|
|
13697
13811
|
}
|
|
@@ -13763,6 +13877,10 @@ async function tickOnce(d) {
|
|
|
13763
13877
|
try {
|
|
13764
13878
|
open = runner.status(run.handle) === "running";
|
|
13765
13879
|
} catch {}
|
|
13880
|
+
if (open && await answeredInSession(d, runner, run)) {
|
|
13881
|
+
keep.push(run);
|
|
13882
|
+
continue;
|
|
13883
|
+
}
|
|
13766
13884
|
if (open || liveAnswerer(run))
|
|
13767
13885
|
keep.push(run);
|
|
13768
13886
|
else
|
|
@@ -14278,6 +14396,10 @@ function permissionKey(answer) {
|
|
|
14278
14396
|
const m = /^\s*(\d|esc)\s*·/i.exec(answer);
|
|
14279
14397
|
return m ? m[1].toLowerCase() : null;
|
|
14280
14398
|
}
|
|
14399
|
+
function dialogPrint(dialog) {
|
|
14400
|
+
return [dialog.text, ...dialog.options.map((o) => `${o.key} · ${o.label}`)].join(`
|
|
14401
|
+
`);
|
|
14402
|
+
}
|
|
14281
14403
|
async function settlePermission(d, runner, run, shown) {
|
|
14282
14404
|
const perms = permissionsOf(d.source);
|
|
14283
14405
|
if (!perms || !run.runId)
|
|
@@ -14287,7 +14409,21 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14287
14409
|
const dialog = runner.readsSession ? permissionDialog(shown) : null;
|
|
14288
14410
|
const p = run.permission;
|
|
14289
14411
|
if (p) {
|
|
14290
|
-
const gone = runner.readsSession && (p.onScreen ? !dialog : (run.seenAt ?? 0) > p.at);
|
|
14412
|
+
const gone = runner.readsSession && (p.onScreen ? !dialog || p.dialog !== undefined && dialogPrint(dialog) !== p.dialog : (run.seenAt ?? 0) > (p.pressedAt ?? p.at));
|
|
14413
|
+
const answered = () => {
|
|
14414
|
+
run.permission = undefined;
|
|
14415
|
+
run.answeredAt = d.now();
|
|
14416
|
+
if (markFile)
|
|
14417
|
+
clearPermissionMark(markFile);
|
|
14418
|
+
};
|
|
14419
|
+
const next = (held) => dialog ? settlePermission(d, runner, run, shown) : held;
|
|
14420
|
+
if (p.gaveUp) {
|
|
14421
|
+
if (!gone)
|
|
14422
|
+
return true;
|
|
14423
|
+
d.log(`${at}: the permission dialog was answered in the terminal`);
|
|
14424
|
+
answered();
|
|
14425
|
+
return next(false);
|
|
14426
|
+
}
|
|
14291
14427
|
let now;
|
|
14292
14428
|
try {
|
|
14293
14429
|
now = await perms.decisionOf(run.item, p.decisionId);
|
|
@@ -14296,14 +14432,42 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14296
14432
|
return true;
|
|
14297
14433
|
}
|
|
14298
14434
|
if (now?.state === "answered" && now.answer) {
|
|
14299
|
-
if (
|
|
14300
|
-
|
|
14301
|
-
|
|
14435
|
+
if (p.pressedAt === undefined) {
|
|
14436
|
+
if (gone)
|
|
14437
|
+
d.log(`${at}: the permission was answered after its dialog closed — not pressed`);
|
|
14438
|
+
else {
|
|
14439
|
+
const pressed = pressAnswer(d, runner, run, p.options, now.answer);
|
|
14440
|
+
if (!pressed)
|
|
14441
|
+
return true;
|
|
14442
|
+
if (pressed === "key") {
|
|
14443
|
+
run.permission = { ...p, pressedAt: d.now(), presses: 1 };
|
|
14444
|
+
return true;
|
|
14445
|
+
}
|
|
14446
|
+
}
|
|
14447
|
+
answered();
|
|
14448
|
+
return gone ? next(true) : true;
|
|
14449
|
+
}
|
|
14450
|
+
const key = permissionKey(now.answer) ?? now.answer;
|
|
14451
|
+
if (gone) {
|
|
14452
|
+
d.log(`${at}: the permission is answered — pressed ${key}; the session goes on`);
|
|
14453
|
+
answered();
|
|
14454
|
+
return next(false);
|
|
14455
|
+
}
|
|
14456
|
+
const presses = p.presses ?? 1;
|
|
14457
|
+
if (presses >= PRESS_TRIES) {
|
|
14458
|
+
const why = `pressed ${key} ${presses} times; the dialog stayed — answer it in the terminal`;
|
|
14459
|
+
try {
|
|
14460
|
+
await perms.clearPermission(run.runId, why, d.engine);
|
|
14461
|
+
} catch (e) {
|
|
14462
|
+
d.log(`${at}: could not clear the permission, trying next tick: ${message(e)}`);
|
|
14463
|
+
return true;
|
|
14464
|
+
}
|
|
14465
|
+
d.log(`${at}: ${why}`);
|
|
14466
|
+
run.permission = { ...p, gaveUp: true };
|
|
14302
14467
|
return true;
|
|
14303
|
-
|
|
14304
|
-
run.
|
|
14305
|
-
|
|
14306
|
-
clearPermissionMark(markFile);
|
|
14468
|
+
}
|
|
14469
|
+
if (pressAnswer(d, runner, run, p.options, now.answer) === "key")
|
|
14470
|
+
run.permission = { ...p, pressedAt: d.now(), presses: presses + 1 };
|
|
14307
14471
|
return true;
|
|
14308
14472
|
}
|
|
14309
14473
|
if (now?.state !== "open" && now?.state !== "escalated") {
|
|
@@ -14320,7 +14484,7 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14320
14484
|
}
|
|
14321
14485
|
d.log(`${at}: the permission dialog closed before an answer — cleared`);
|
|
14322
14486
|
run.permission = undefined;
|
|
14323
|
-
return false;
|
|
14487
|
+
return next(false);
|
|
14324
14488
|
}
|
|
14325
14489
|
let mark = markFile ? readPermissionMark(markFile) : null;
|
|
14326
14490
|
if (mark && markFile && (!isToolPermission(mark.message) || runner.readsSession && choicePicker(shown))) {
|
|
@@ -14346,13 +14510,14 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14346
14510
|
decisionId: opened.decisionId,
|
|
14347
14511
|
options,
|
|
14348
14512
|
at: d.now(),
|
|
14349
|
-
...dialog ? { onScreen: true } : {}
|
|
14513
|
+
...dialog ? { onScreen: true, dialog: dialogPrint(dialog) } : {}
|
|
14350
14514
|
};
|
|
14351
14515
|
if (markFile)
|
|
14352
14516
|
clearPermissionMark(markFile);
|
|
14353
14517
|
d.log(`${at}: stopped at a permission dialog — it waits for a person (${runner.watchHint(run.handle)})`);
|
|
14354
14518
|
return true;
|
|
14355
14519
|
}
|
|
14520
|
+
var PRESS_TRIES = 3;
|
|
14356
14521
|
function pressAnswer(d, runner, run, options, answer) {
|
|
14357
14522
|
const at = ref(run);
|
|
14358
14523
|
const key = permissionKey(answer);
|
|
@@ -14363,13 +14528,15 @@ function pressAnswer(d, runner, run, options, answer) {
|
|
|
14363
14528
|
runner.sendKey(run.handle, key);
|
|
14364
14529
|
else
|
|
14365
14530
|
runner.send(run.handle, key);
|
|
14531
|
+
if (runner.readsSession)
|
|
14532
|
+
return "key";
|
|
14366
14533
|
d.log(`${at}: the permission is answered — pressed ${key}; the session goes on`);
|
|
14367
14534
|
} else {
|
|
14368
14535
|
runner.sendKey?.(run.handle, "esc");
|
|
14369
14536
|
const note = runner.send(run.handle, answer);
|
|
14370
14537
|
d.log(`${at}: the permission is answered in words — Esc, then typed in${note ? ` (${note})` : ""}`);
|
|
14371
14538
|
}
|
|
14372
|
-
return
|
|
14539
|
+
return "done";
|
|
14373
14540
|
} catch (e) {
|
|
14374
14541
|
d.log(`${at}: could not press the permission's answer, trying next tick: ${message(e)}`);
|
|
14375
14542
|
return false;
|
|
@@ -14538,10 +14705,25 @@ async function rereadAtOnce(d) {
|
|
|
14538
14705
|
try {
|
|
14539
14706
|
next = await d.rereadAtOnce(profileOf2(d));
|
|
14540
14707
|
} catch {}
|
|
14541
|
-
if (next
|
|
14708
|
+
if (next !== null && next !== d.atOnce) {
|
|
14709
|
+
d.atOnce = next;
|
|
14710
|
+
d.log(`at once now ${next}, from your engine profile`);
|
|
14711
|
+
}
|
|
14712
|
+
await sayAtOnceDisagrees(d);
|
|
14713
|
+
}
|
|
14714
|
+
async function sayAtOnceDisagrees(d) {
|
|
14715
|
+
const seat = (await profileOf2(d)())?.seatAtOnce;
|
|
14716
|
+
if (seat === undefined)
|
|
14717
|
+
return;
|
|
14718
|
+
if (seat === d.atOnce) {
|
|
14719
|
+
d.seatAtOnceNoted = undefined;
|
|
14720
|
+
return;
|
|
14721
|
+
}
|
|
14722
|
+
const pair = `${d.atOnce}/${seat}`;
|
|
14723
|
+
if (d.seatAtOnceNoted === pair)
|
|
14542
14724
|
return;
|
|
14543
|
-
d.
|
|
14544
|
-
d.log(`at once
|
|
14725
|
+
d.seatAtOnceNoted = pair;
|
|
14726
|
+
d.log(seat < d.atOnce ? `at once ${d.atOnce} on the engine, but this seat allows ${seat} — the server refuses a claim past ${seat} on it; set it in Settings` : `at once ${d.atOnce} on the engine, but this seat allows ${seat} — the engine takes only ${d.atOnce}; set it in Settings`);
|
|
14545
14727
|
}
|
|
14546
14728
|
async function rereadRunner(d) {
|
|
14547
14729
|
if (!d.rereadRunner)
|
|
@@ -14595,10 +14777,53 @@ function stopOpen(d, run, runner) {
|
|
|
14595
14777
|
}
|
|
14596
14778
|
}
|
|
14597
14779
|
function holdParked(d, runner, run, question) {
|
|
14598
|
-
run.parked = { question, at: d.now() };
|
|
14780
|
+
run.parked = { question, at: d.now(), ...run.seen ? { screen: run.seen } : {} };
|
|
14599
14781
|
run.leaseUntil = undefined;
|
|
14600
14782
|
setLane(d, runner, run.handle, "parked");
|
|
14601
14783
|
}
|
|
14784
|
+
async function answeredInSession(d, runner, run) {
|
|
14785
|
+
const parked = run.parked;
|
|
14786
|
+
const resumes = resumesOf(d.source);
|
|
14787
|
+
if (!resumes || !runner.readsSession || !run.runId)
|
|
14788
|
+
return false;
|
|
14789
|
+
let print;
|
|
14790
|
+
try {
|
|
14791
|
+
print = fingerprint(runner.read(run.handle));
|
|
14792
|
+
} catch {
|
|
14793
|
+
return false;
|
|
14794
|
+
}
|
|
14795
|
+
if (print === parked.screen) {
|
|
14796
|
+
parked.still = true;
|
|
14797
|
+
return false;
|
|
14798
|
+
}
|
|
14799
|
+
const moved = parked.still === true;
|
|
14800
|
+
parked.screen = print;
|
|
14801
|
+
parked.still = false;
|
|
14802
|
+
if (!moved)
|
|
14803
|
+
return false;
|
|
14804
|
+
let r;
|
|
14805
|
+
try {
|
|
14806
|
+
r = await resumes.resumeParked(run.runId, "answered in the session", d.engine, d.leaseMin);
|
|
14807
|
+
} catch (e) {
|
|
14808
|
+
d.log(`${ref(run)}: the parked session moved on, but SLEDS did not hear it: ${message(e)}`);
|
|
14809
|
+
return false;
|
|
14810
|
+
}
|
|
14811
|
+
if (!r.resumed) {
|
|
14812
|
+
d.log(`${ref(run)}: the parked session moved on, but the node is no longer parked on its run`);
|
|
14813
|
+
return false;
|
|
14814
|
+
}
|
|
14815
|
+
stopAnswerer(d, run);
|
|
14816
|
+
const now = d.now();
|
|
14817
|
+
run.parked = undefined;
|
|
14818
|
+
run.seen = print;
|
|
14819
|
+
run.seenAt = now;
|
|
14820
|
+
run.seenTicks = 0;
|
|
14821
|
+
run.answeredAt = now;
|
|
14822
|
+
run.leaseUntil = r.leaseUntil ?? now + d.leaseMin * 60000;
|
|
14823
|
+
setLane(d, runner, run.handle, "working");
|
|
14824
|
+
d.log(`${ref(run)}: answered in the session — out of Needs you, running again`);
|
|
14825
|
+
return true;
|
|
14826
|
+
}
|
|
14602
14827
|
function setLane(d, runner, h, lane) {
|
|
14603
14828
|
try {
|
|
14604
14829
|
runner.lane?.(h, lane);
|
|
@@ -15173,6 +15398,8 @@ function ciNudge(url, failing) {
|
|
|
15173
15398
|
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.`;
|
|
15174
15399
|
}
|
|
15175
15400
|
var SELF_NUDGES = 2;
|
|
15401
|
+
var FEEDBACK_REREAD_MS = 10 * 60000;
|
|
15402
|
+
var CONFLICT_RECHECK_MS = 10 * 60000;
|
|
15176
15403
|
function reviewNudge(url, count) {
|
|
15177
15404
|
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.`;
|
|
15178
15405
|
}
|
|
@@ -15213,9 +15440,12 @@ async function judgeLook(d, run, view) {
|
|
|
15213
15440
|
}
|
|
15214
15441
|
async function follow(d, state, run, claim, runner, finished, attention, changes, decided) {
|
|
15215
15442
|
const pr = run.pr;
|
|
15216
|
-
const
|
|
15443
|
+
const last = pr.feedbackRead && d.now() - pr.feedbackRead.at < FEEDBACK_REREAD_MS ? pr.feedbackRead : undefined;
|
|
15444
|
+
const view = d.prView(d.exec, run.repoPath, pr.url, last);
|
|
15217
15445
|
if (!view)
|
|
15218
15446
|
return true;
|
|
15447
|
+
if (view.read && view.read !== last)
|
|
15448
|
+
pr.feedbackRead = { ...view.read, at: d.now() };
|
|
15219
15449
|
await judgeLook(d, run, view);
|
|
15220
15450
|
if (view.state === "MERGED") {
|
|
15221
15451
|
await dropPermission(d, run, "the PR merged");
|
|
@@ -15269,6 +15499,7 @@ async function follow(d, state, run, claim, runner, finished, attention, changes
|
|
|
15269
15499
|
else if (view.mergeable === "MERGEABLE") {
|
|
15270
15500
|
pr.resolving = undefined;
|
|
15271
15501
|
pr.conflicted = undefined;
|
|
15502
|
+
pr.conflictCheck = undefined;
|
|
15272
15503
|
}
|
|
15273
15504
|
if (view.feedback > pr.feedback) {
|
|
15274
15505
|
const what = `${view.feedback - pr.feedback} new review comment(s)`;
|
|
@@ -15508,10 +15739,15 @@ async function judgeConflict(d, state, run, view, attention, decided) {
|
|
|
15508
15739
|
const pr = run.pr;
|
|
15509
15740
|
if (!d.mergeTree)
|
|
15510
15741
|
return;
|
|
15742
|
+
const check = pr.conflictCheck;
|
|
15743
|
+
if (view.head && check?.head === view.head && !pr.resolving && d.now() - check.at < CONFLICT_RECHECK_MS)
|
|
15744
|
+
return;
|
|
15511
15745
|
const base = view.base || d.defaultBranch(d.exec, run.repoPath);
|
|
15512
15746
|
const mt = d.mergeTree(d.exec, run.repoPath, base, run.branch);
|
|
15513
15747
|
if (!mt)
|
|
15514
15748
|
return;
|
|
15749
|
+
if (view.head)
|
|
15750
|
+
pr.conflictCheck = { head: view.head, at: d.now() };
|
|
15515
15751
|
if (pr.resolving === mt.sha && mt.files.length > 0 && !sessionRuns(d, run.handle)) {
|
|
15516
15752
|
pr.resolving = undefined;
|
|
15517
15753
|
const what = `${pr.url} still conflicts with ${base} on ${mt.files.join(", ")} after its session had the brief`;
|
|
@@ -17174,7 +17410,7 @@ async function fetchVersion(o) {
|
|
|
17174
17410
|
const platform = o.platform ?? process.platform;
|
|
17175
17411
|
const arch = o.arch ?? process.arch;
|
|
17176
17412
|
const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
|
|
17177
|
-
const running = o.running ?? "0.1.
|
|
17413
|
+
const running = o.running ?? "0.1.53";
|
|
17178
17414
|
if (!publicKey)
|
|
17179
17415
|
return { ok: false, why: "no release key yet" };
|
|
17180
17416
|
if (!VERSION_RE2.test(o.version))
|
|
@@ -18758,7 +18994,7 @@ function engineClient(o, org) {
|
|
|
18758
18994
|
return fetchClient({
|
|
18759
18995
|
...src,
|
|
18760
18996
|
timeoutMs: ENGINE_TIMEOUT_MS,
|
|
18761
|
-
version: "0.1.
|
|
18997
|
+
version: "0.1.53"
|
|
18762
18998
|
});
|
|
18763
18999
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
18764
19000
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -18823,10 +19059,10 @@ function engineToken(o, org) {
|
|
|
18823
19059
|
}
|
|
18824
19060
|
var withToken = (token, now) => token ? { token, tokenNow: now } : {};
|
|
18825
19061
|
function engineDeps(o, flags, source, runner, stateName) {
|
|
18826
|
-
const
|
|
19062
|
+
const log = o.log ?? console.log;
|
|
19063
|
+
const exec = logTimeouts(guardGit(o.exec ?? defaultExec), log);
|
|
18827
19064
|
const cwd = o.cwd ?? process.cwd();
|
|
18828
19065
|
const exists = o.exists ?? realExists;
|
|
18829
|
-
const log = o.log ?? console.log;
|
|
18830
19066
|
const stateDir = engineStateDir(o, flags.org, flags.seat);
|
|
18831
19067
|
const file = statePath(stateDir, stateName);
|
|
18832
19068
|
const mcpOrg = flags.org && engineOrg(o, flags.org).seated ? flags.org : undefined;
|
|
@@ -19049,7 +19285,7 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
19049
19285
|
runner: deps.runner.name,
|
|
19050
19286
|
atOnce: flags.atOnce,
|
|
19051
19287
|
interval: flags.interval,
|
|
19052
|
-
cliVersion: "0.1.
|
|
19288
|
+
cliVersion: "0.1.53"
|
|
19053
19289
|
};
|
|
19054
19290
|
const beat = (checkedAt) => {
|
|
19055
19291
|
const m = deps.machine;
|
|
@@ -19241,7 +19477,7 @@ async function drive(o, flags, deps, until, beat) {
|
|
|
19241
19477
|
var SEAT_CHANGED_EXIT = 3;
|
|
19242
19478
|
function engineRunner(o, flags) {
|
|
19243
19479
|
const runnerFor = o.runnerFor ?? runnerFor2;
|
|
19244
|
-
return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
|
|
19480
|
+
return runnerFor(flags.runner, logTimeouts(guardGit(o.exec ?? defaultExec), o.log ?? console.log), {
|
|
19245
19481
|
...flags.runnerCmd ? { command: flags.runnerCmd } : {}
|
|
19246
19482
|
});
|
|
19247
19483
|
}
|
|
@@ -20906,7 +21142,7 @@ function engineClient2(o, org) {
|
|
|
20906
21142
|
return fetchClient({
|
|
20907
21143
|
...src,
|
|
20908
21144
|
timeoutMs: ENGINE_TIMEOUT_MS2,
|
|
20909
|
-
version: "0.1.
|
|
21145
|
+
version: "0.1.53"
|
|
20910
21146
|
});
|
|
20911
21147
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
20912
21148
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -20993,10 +21229,10 @@ function engineCredential(o) {
|
|
|
20993
21229
|
})?.kind;
|
|
20994
21230
|
}
|
|
20995
21231
|
function engineDeps2(o, flags, source, runner, stateName) {
|
|
20996
|
-
const
|
|
21232
|
+
const log = o.log ?? console.log;
|
|
21233
|
+
const exec = logTimeouts(guardGit(o.exec ?? defaultExec), log);
|
|
20997
21234
|
const cwd = o.cwd ?? process.cwd();
|
|
20998
21235
|
const exists = o.exists ?? realExists2;
|
|
20999
|
-
const log = o.log ?? console.log;
|
|
21000
21236
|
const stateDir = engineStateDir2(o, flags.org, flags.seat);
|
|
21001
21237
|
const file = statePath(stateDir, stateName);
|
|
21002
21238
|
const mcpOrg = flags.org && engineOrg2(o, flags.org).seated ? flags.org : undefined;
|
|
@@ -21232,7 +21468,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
21232
21468
|
runner: deps.runner.name,
|
|
21233
21469
|
atOnce: flags.atOnce,
|
|
21234
21470
|
interval: flags.interval,
|
|
21235
|
-
cliVersion: "0.1.
|
|
21471
|
+
cliVersion: "0.1.53"
|
|
21236
21472
|
};
|
|
21237
21473
|
const beat = (checkedAt) => {
|
|
21238
21474
|
const m = deps.machine;
|
|
@@ -21424,7 +21660,7 @@ async function drive2(o, flags, deps, until, beat) {
|
|
|
21424
21660
|
var SEAT_CHANGED_EXIT2 = 3;
|
|
21425
21661
|
function engineRunner2(o, flags) {
|
|
21426
21662
|
const runnerFor = o.runnerFor ?? runnerFor2;
|
|
21427
|
-
return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
|
|
21663
|
+
return runnerFor(flags.runner, logTimeouts(guardGit(o.exec ?? defaultExec), o.log ?? console.log), {
|
|
21428
21664
|
...flags.runnerCmd ? { command: flags.runnerCmd } : {}
|
|
21429
21665
|
});
|
|
21430
21666
|
}
|
|
@@ -23320,7 +23556,7 @@ function contextFor(deps) {
|
|
|
23320
23556
|
...src,
|
|
23321
23557
|
fetchFn: deps.fetchFn,
|
|
23322
23558
|
timeoutMs: deps.timeoutMs,
|
|
23323
|
-
version: "0.1.
|
|
23559
|
+
version: "0.1.53"
|
|
23324
23560
|
}), deps.home, now) : null;
|
|
23325
23561
|
return {
|
|
23326
23562
|
channel: "code",
|
|
@@ -25834,14 +26070,16 @@ function routeReader(o, org) {
|
|
|
25834
26070
|
read: (k) => readOrSay(client, `/proxy/route?q=${encodeURIComponent(k)}`, k)
|
|
25835
26071
|
};
|
|
25836
26072
|
}
|
|
25837
|
-
var SLED_USAGE = "usage: sleds sled --json | sleds sled top <KEY> | sleds sled order <KEY>…";
|
|
26073
|
+
var SLED_USAGE = "usage: sleds sled --json | sleds sled top <KEY> | sleds sled order <KEY>… | sleds sled off <KEY> [--json]";
|
|
25838
26074
|
async function sledCmd(o) {
|
|
25839
26075
|
const log = o.log ?? console.log;
|
|
25840
26076
|
const error = o.error ?? console.error;
|
|
25841
26077
|
const top = o.argv[0] === "top" && o.argv.length === 2 && !o.argv[1]?.startsWith("-");
|
|
25842
26078
|
const keys = o.argv.slice(1);
|
|
25843
26079
|
const order = o.argv[0] === "order" && keys.length > 0 && keys.every((k) => k.trim() && !k.startsWith("-"));
|
|
25844
|
-
|
|
26080
|
+
const offArgs = o.argv.slice(1).filter((a) => a !== "--json");
|
|
26081
|
+
const off = o.argv[0] === "off" && offArgs.length === 1 && o.argv.length <= 3 && !!offArgs[0]?.trim() && !offArgs[0].startsWith("-");
|
|
26082
|
+
if (!top && !order && !off && (o.argv.length !== 1 || o.argv[0] !== "--json")) {
|
|
25845
26083
|
error(SLED_USAGE);
|
|
25846
26084
|
return 2;
|
|
25847
26085
|
}
|
|
@@ -25854,6 +26092,8 @@ async function sledCmd(o) {
|
|
|
25854
26092
|
return sledTop(client, o.argv[1], log, error);
|
|
25855
26093
|
if (order)
|
|
25856
26094
|
return sledOrder(client, keys, log, error);
|
|
26095
|
+
if (off)
|
|
26096
|
+
return sledOff(client, offArgs[0], o.argv.includes("--json"), log, error);
|
|
25857
26097
|
try {
|
|
25858
26098
|
log(JSON.stringify(await readOrSay(client, "/proxy/sled", "the sled")));
|
|
25859
26099
|
return 0;
|
|
@@ -25888,6 +26128,34 @@ async function sledOrder(client, keys, log, error) {
|
|
|
25888
26128
|
log(`${typeof r.json?.ordered === "number" ? r.json.ordered : keys.length} ordered on your sled`);
|
|
25889
26129
|
return 0;
|
|
25890
26130
|
}
|
|
26131
|
+
async function sledOff(client, key, json, log, error) {
|
|
26132
|
+
const r = await client.postFull("/proxy/sled/off", { project: key });
|
|
26133
|
+
if (!r) {
|
|
26134
|
+
error(`${key}: SLEDS unreachable — the sled is unchanged`);
|
|
26135
|
+
return 1;
|
|
26136
|
+
}
|
|
26137
|
+
if (r.status >= 300 || r.json?.ok === false) {
|
|
26138
|
+
error(typeof r.json?.error === "string" ? r.json.error : `${key}: HTTP ${r.status}`);
|
|
26139
|
+
return 1;
|
|
26140
|
+
}
|
|
26141
|
+
if (json) {
|
|
26142
|
+
log(JSON.stringify(r.json));
|
|
26143
|
+
return 0;
|
|
26144
|
+
}
|
|
26145
|
+
const k = typeof r.json?.key === "string" ? r.json.key : key;
|
|
26146
|
+
const why = typeof r.json?.why === "string" && r.json.why.trim() ? r.json.why : null;
|
|
26147
|
+
if (r.json?.changed === false) {
|
|
26148
|
+
error(why ?? `${k} was not on a sled`);
|
|
26149
|
+
return 1;
|
|
26150
|
+
}
|
|
26151
|
+
log(`${k} is off your sled — back in the pool`);
|
|
26152
|
+
const running = typeof r.json?.running === "number" ? r.json.running : 0;
|
|
26153
|
+
if (running > 0)
|
|
26154
|
+
log(`${running} running node${running === 1 ? "" : "s"} stopped`);
|
|
26155
|
+
if (why)
|
|
26156
|
+
log(why);
|
|
26157
|
+
return 0;
|
|
26158
|
+
}
|
|
25891
26159
|
|
|
25892
26160
|
// src/commands/run.ts
|
|
25893
26161
|
init_config();
|
|
@@ -27406,7 +27674,7 @@ var realPidAlive4 = (pid) => {
|
|
|
27406
27674
|
};
|
|
27407
27675
|
function machineClient(home, env) {
|
|
27408
27676
|
const src = meterSource(home, undefined, { env });
|
|
27409
|
-
return src ? fetchClient({ ...src, version: "0.1.
|
|
27677
|
+
return src ? fetchClient({ ...src, version: "0.1.53" }) : null;
|
|
27410
27678
|
}
|
|
27411
27679
|
async function noteAnswer2(home, a, now) {
|
|
27412
27680
|
try {
|
|
@@ -27876,15 +28144,29 @@ var readConfig2 = (home) => {
|
|
|
27876
28144
|
|
|
27877
28145
|
// src/runners/exec.ts
|
|
27878
28146
|
import { spawn as spawn3, spawnSync as spawnSync10 } from "node:child_process";
|
|
28147
|
+
var EXEC_TIMEOUT_MS2 = 2 * 60000;
|
|
28148
|
+
var EXEC_TIMEOUT_STATUS2 = 124;
|
|
28149
|
+
var timedOut2 = (r) => r.error?.code === "ETIMEDOUT";
|
|
27879
28150
|
var defaultExec4 = (cmd, args, o) => {
|
|
28151
|
+
const timeoutMs = o?.timeoutMs ?? EXEC_TIMEOUT_MS2;
|
|
27880
28152
|
const r = spawnSync10(cmd, [...args], {
|
|
27881
28153
|
cwd: o?.cwd,
|
|
27882
28154
|
input: o?.input,
|
|
27883
28155
|
env: o?.env ? { ...process.env, ...o.env } : undefined,
|
|
27884
28156
|
encoding: "utf8",
|
|
27885
28157
|
shell: false,
|
|
27886
|
-
maxBuffer: 16 * 1024 * 1024
|
|
28158
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
28159
|
+
timeout: timeoutMs,
|
|
28160
|
+
killSignal: "SIGKILL"
|
|
27887
28161
|
});
|
|
28162
|
+
if (timedOut2(r)) {
|
|
28163
|
+
return {
|
|
28164
|
+
status: EXEC_TIMEOUT_STATUS2,
|
|
28165
|
+
stdout: r.stdout ?? "",
|
|
28166
|
+
stderr: `${cmd}: timed out after ${timeoutMs / 1000}s and was killed${r.stderr ? `
|
|
28167
|
+
${r.stderr}` : ""}`
|
|
28168
|
+
};
|
|
28169
|
+
}
|
|
27888
28170
|
if (r.error) {
|
|
27889
28171
|
return { status: 127, stdout: r.stdout ?? "", stderr: `${cmd}: ${r.error.message}` };
|
|
27890
28172
|
}
|
|
@@ -28026,6 +28308,7 @@ commands:
|
|
|
28026
28308
|
sled --json What is on your sled (mine with each route, proposed, sent), for a front end.
|
|
28027
28309
|
sleds sled top KEY put KEY first on your sled; the engine picks it next
|
|
28028
28310
|
sleds sled order KEY\u2026 those items in this order, in the places they hold; the rest stay
|
|
28311
|
+
sleds sled off KEY take KEY off your sled, back in the pool; its running nodes stop
|
|
28029
28312
|
route <key> Print an item's route: its nodes, what each waits on, what is ready, where each
|
|
28030
28313
|
run can be watched.
|
|
28031
28314
|
--dot Graphviz instead: \`sleds route QW-142 --dot | dot -Tpng -o route.png\`
|
|
@@ -28251,7 +28534,7 @@ var main = async (argv) => {
|
|
|
28251
28534
|
now: Date.now(),
|
|
28252
28535
|
stderr: (line) => console.error(line),
|
|
28253
28536
|
isTTY: !!process.stderr.isTTY,
|
|
28254
|
-
version: "0.1.
|
|
28537
|
+
version: "0.1.53"
|
|
28255
28538
|
});
|
|
28256
28539
|
switch (cmd) {
|
|
28257
28540
|
case "update":
|
|
@@ -28484,7 +28767,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
28484
28767
|
case "version":
|
|
28485
28768
|
case "--version":
|
|
28486
28769
|
case "-v":
|
|
28487
|
-
console.log("sleds 0.1.
|
|
28770
|
+
console.log("sleds 0.1.53");
|
|
28488
28771
|
return 0;
|
|
28489
28772
|
default:
|
|
28490
28773
|
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.53",
|
|
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",
|