@sleds/cli 0.1.36 → 0.1.38
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 +250 -16
- package/package.json +1 -1
package/dist/sleds.mjs
CHANGED
|
@@ -6121,10 +6121,15 @@ var init_pack = __esm(() => {
|
|
|
6121
6121
|
init_sentry();
|
|
6122
6122
|
init_setup();
|
|
6123
6123
|
});
|
|
6124
|
+
// ../../packages/shared/src/pack/prHeader.ts
|
|
6125
|
+
var PR_HEADER_OPEN = "<!-- sleds:header -->", PR_HEADER_CLOSE = "<!-- /sleds:header -->";
|
|
6126
|
+
var init_prHeader = () => {};
|
|
6127
|
+
|
|
6124
6128
|
// ../../packages/shared/src/pack/index.ts
|
|
6125
6129
|
var init_pack2 = __esm(() => {
|
|
6126
6130
|
init_setup();
|
|
6127
6131
|
init_pack();
|
|
6132
|
+
init_prHeader();
|
|
6128
6133
|
});
|
|
6129
6134
|
|
|
6130
6135
|
// ../../packages/shared/src/newrelic/newrelic.ts
|
|
@@ -6523,6 +6528,9 @@ function nodePrompt(o) {
|
|
|
6523
6528
|
"",
|
|
6524
6529
|
`- Work on branch \`${o.branch}\` from the latest \`origin/${base}\` (create it if this checkout is not on it). One branch, one PR.`,
|
|
6525
6530
|
`- Open the PR against \`${base}\` with \`gh pr create${visual ? " --draft" : ""}\`${o.prTitle ? ` and title it exactly \`${o.prTitle}\` (the repo's CI checks it)` : ""}. Its body carries \`SLEDS-Node: ${claim.node}\` on the line under \`SLEDS-Source:\` when the pack names a source.`,
|
|
6531
|
+
...claim.pack.includes(PR_HEADER_OPEN) ? [
|
|
6532
|
+
`- The PR body starts with the pack's PR header block (\`${PR_HEADER_OPEN}\` … \`${PR_HEADER_CLOSE}\`, in its part 5), above everything else and as given; when you edit the body later, keep it on top.`
|
|
6533
|
+
] : [],
|
|
6526
6534
|
"- Run the repo's own gate before you push. Never merge: a person (or the musher, when the attachment says so) does.",
|
|
6527
6535
|
"- Stay inside this node's scope. Work another node needs goes in the PR description, not in this branch.",
|
|
6528
6536
|
`- End every comment and reply you post on the PR with the line \`${ENGINE_MARK}\`, so the engine knows it is yours and not a reviewer's.`,
|
|
@@ -6847,6 +6855,7 @@ function eventPrompt(o) {
|
|
|
6847
6855
|
}
|
|
6848
6856
|
var DEFAULT_SEAT = "\x00default", MAX_SEAT_AT_ONCE = 16, HOLD_DEFAULTS, DRAFT_NODE = "draft", BRANCH_FIELDS, PR_TITLE_FIELDS, ENGINE_MCP_SERVER = "sleds", RUN_TOKEN_ENV = "SLEDS_RUN_TOKEN", NO_RUN_TOKEN = "no run token from SLEDS: this session acts as the seat", SANDBOX_DOMAIN, SANDBOX_DEFAULT_ALLOW, toolName = (name, engineMcp) => engineMcp ? `mcp__${ENGINE_MCP_SERVER}__${name}` : name, ENGINE_MARK = "<!-- sleds:engine -->", VISUAL_PATH, APPROACH_SHAPE, AUTONOMY_SAYS, IRREVERSIBLE = "deleting or migrating data in place; deploying outside the playbook's window; anything that leaves the org (a message to a customer, a publish, a release, an email); spend past the band or the allowance; force-pushing or deleting a branch someone else holds; granting or removing access; changing the brief. When in doubt, it is irreversible.", oneLine = (s, max) => s.replace(/\s+/g, " ").trim().slice(0, max), VERDICT_SHAPE, DECIDER_RULES, codes = (xs) => xs.map((x) => `\`${x}\``).join(", "), RESOLVE_MAX_FILES = 8;
|
|
6849
6857
|
var init_engine = __esm(() => {
|
|
6858
|
+
init_prHeader();
|
|
6850
6859
|
init_route();
|
|
6851
6860
|
HOLD_DEFAULTS = {
|
|
6852
6861
|
holdCpu: 85,
|
|
@@ -7943,7 +7952,8 @@ function parseRun(v) {
|
|
|
7943
7952
|
...typeof v.pr.conflict === "string" ? { conflict: v.pr.conflict } : {},
|
|
7944
7953
|
...typeof v.pr.resolving === "string" ? { resolving: v.pr.resolving } : {},
|
|
7945
7954
|
...conflicted ? { conflicted } : {},
|
|
7946
|
-
...typeof v.pr.reviewed === "string" ? { reviewed: v.pr.reviewed } : {}
|
|
7955
|
+
...typeof v.pr.reviewed === "string" ? { reviewed: v.pr.reviewed } : {},
|
|
7956
|
+
...typeof v.pr.look === "string" ? { look: v.pr.look } : {}
|
|
7947
7957
|
}
|
|
7948
7958
|
} : {}
|
|
7949
7959
|
};
|
|
@@ -8014,6 +8024,7 @@ function parseLock(text) {
|
|
|
8014
8024
|
runner: typeof v.runner === "string" ? v.runner : "",
|
|
8015
8025
|
atOnce: n(v.atOnce, 1),
|
|
8016
8026
|
interval: n(v.interval, 0),
|
|
8027
|
+
...typeof v.cliVersion === "string" && v.cliVersion ? { cliVersion: v.cliVersion } : {},
|
|
8017
8028
|
...typeof v.checkedAt === "number" ? { checkedAt: v.checkedAt } : {},
|
|
8018
8029
|
...typeof v.nextCheckAt === "number" ? { nextCheckAt: v.nextCheckAt } : {},
|
|
8019
8030
|
...machine ? { machine } : {},
|
|
@@ -10329,15 +10340,28 @@ import { join as join15, resolve as resolve7 } from "node:path";
|
|
|
10329
10340
|
// src/engine/beat.ts
|
|
10330
10341
|
var BEAT_EVERY_MS = 60000;
|
|
10331
10342
|
var BEAT_ITEMS = 8;
|
|
10332
|
-
function beatBody(state, flags, host = {}) {
|
|
10343
|
+
function beatBody(state, flags, host = {}, cap = {}) {
|
|
10333
10344
|
const live = state.runs.filter((r) => !r.pr && !r.parked);
|
|
10345
|
+
const m = cap.machine;
|
|
10334
10346
|
return {
|
|
10335
10347
|
name: flags.name,
|
|
10336
10348
|
os: host.os ?? process.platform,
|
|
10337
10349
|
runner: flags.runner,
|
|
10338
|
-
version: host.version ?? "0.1.
|
|
10350
|
+
version: host.version ?? "0.1.38" ?? "dev",
|
|
10339
10351
|
running: live.length,
|
|
10340
|
-
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`)
|
|
10352
|
+
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
10353
|
+
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
10354
|
+
...m ? {
|
|
10355
|
+
machine: {
|
|
10356
|
+
cpuPct: m.cpuPct,
|
|
10357
|
+
load1: m.load1,
|
|
10358
|
+
cores: m.cores,
|
|
10359
|
+
loadPerCore: m.loadPerCore,
|
|
10360
|
+
pressure: m.pressure
|
|
10361
|
+
},
|
|
10362
|
+
level: cap.hold?.level ?? "calm",
|
|
10363
|
+
...cap.hold ? { allowed: cap.hold.allowed } : {}
|
|
10364
|
+
} : {}
|
|
10341
10365
|
};
|
|
10342
10366
|
}
|
|
10343
10367
|
async function postBeat(client, body) {
|
|
@@ -10635,6 +10659,15 @@ function prForBranch(exec, repoPath, branch) {
|
|
|
10635
10659
|
return { error: e instanceof Error ? e.message : String(e) };
|
|
10636
10660
|
}
|
|
10637
10661
|
}
|
|
10662
|
+
var URL_RE = /https:\/\/[^\s)>\]"']+/;
|
|
10663
|
+
var ARTIFACT_RE = /https:\/\/claude\.ai\/[^\s)>\]"']*artifact\/[^\s)>\]"']+/;
|
|
10664
|
+
function mockOf(body) {
|
|
10665
|
+
const header = /<!--\s*sleds:header\s*-->([\s\S]*?)<!--\s*\/sleds:header\s*-->/.exec(body)?.[1];
|
|
10666
|
+
const line = header?.split(`
|
|
10667
|
+
`).find((l) => /\*\*Mocks\*\*\s*:/i.test(l));
|
|
10668
|
+
const fromHeader = line ? URL_RE.exec(line)?.[0] : undefined;
|
|
10669
|
+
return fromHeader ?? ARTIFACT_RE.exec(body)?.[0];
|
|
10670
|
+
}
|
|
10638
10671
|
var FAILED = new Set([
|
|
10639
10672
|
"FAILURE",
|
|
10640
10673
|
"ERROR",
|
|
@@ -10680,6 +10713,7 @@ function parsePrView(stdout) {
|
|
|
10680
10713
|
pending++;
|
|
10681
10714
|
}
|
|
10682
10715
|
const mergeCommit = typeof o.mergeCommit === "object" && o.mergeCommit !== null ? o.mergeCommit.oid : undefined;
|
|
10716
|
+
const mock = typeof o.body === "string" ? mockOf(o.body) : undefined;
|
|
10683
10717
|
return {
|
|
10684
10718
|
state: o.state,
|
|
10685
10719
|
author: loginOf(o.author),
|
|
@@ -10690,6 +10724,8 @@ function parsePrView(stdout) {
|
|
|
10690
10724
|
reviewDecision: typeof o.reviewDecision === "string" ? o.reviewDecision : "",
|
|
10691
10725
|
feedback: 0,
|
|
10692
10726
|
authorFeedback: 0,
|
|
10727
|
+
draft: o.isDraft === true,
|
|
10728
|
+
...mock ? { mock } : {},
|
|
10693
10729
|
...typeof o.headRefOid === "string" && o.headRefOid ? { head: o.headRefOid } : {},
|
|
10694
10730
|
...typeof mergeCommit === "string" && mergeCommit ? { mergeCommit } : {}
|
|
10695
10731
|
};
|
|
@@ -10744,7 +10780,7 @@ function prView(exec, repoPath, url) {
|
|
|
10744
10780
|
"view",
|
|
10745
10781
|
url,
|
|
10746
10782
|
"--json",
|
|
10747
|
-
"state,author,statusCheckRollup,reviewDecision,comments,reviews,headRefOid,mergeable,baseRefName,mergeCommit"
|
|
10783
|
+
"state,author,statusCheckRollup,reviewDecision,comments,reviews,headRefOid,mergeable,baseRefName,mergeCommit,isDraft,body"
|
|
10748
10784
|
], { cwd: repoPath });
|
|
10749
10785
|
const view = r.status === 0 ? parsePrView(r.stdout) : null;
|
|
10750
10786
|
if (!view || view.state !== "OPEN")
|
|
@@ -11210,6 +11246,10 @@ init_machine();
|
|
|
11210
11246
|
|
|
11211
11247
|
// src/engine/sledsSource.ts
|
|
11212
11248
|
init_src();
|
|
11249
|
+
function looksOf(s) {
|
|
11250
|
+
const l = s;
|
|
11251
|
+
return l && typeof l.openLook === "function" && typeof l.clearLook === "function" ? s : null;
|
|
11252
|
+
}
|
|
11213
11253
|
var FAIL_LOG_MAX = 2000;
|
|
11214
11254
|
var UNREACHABLE2 = "SLEDS unreachable";
|
|
11215
11255
|
function keysIn(states, state) {
|
|
@@ -11351,20 +11391,34 @@ var PROFILE_TEXT = [
|
|
|
11351
11391
|
"reposDir",
|
|
11352
11392
|
"engine"
|
|
11353
11393
|
];
|
|
11394
|
+
var SHELL_TEXT = ["agent", "launcher"];
|
|
11354
11395
|
function profileOf(r) {
|
|
11355
11396
|
if (!r || r.ok === false || !isObject8(r.profile))
|
|
11356
11397
|
return null;
|
|
11357
11398
|
const p = r.profile;
|
|
11399
|
+
const member = isObject8(r.member) ? r.member : {};
|
|
11358
11400
|
const out = {
|
|
11359
11401
|
pickup: p.pickup === "auto" ? "auto" : "approve",
|
|
11360
11402
|
...HOLD_DEFAULTS2,
|
|
11361
11403
|
holdOff: p.holdOff === true
|
|
11362
11404
|
};
|
|
11363
11405
|
for (const k of PROFILE_TEXT) {
|
|
11406
|
+
if (SHELL_TEXT.includes(k))
|
|
11407
|
+
continue;
|
|
11364
11408
|
const v = str6(p[k])?.trim();
|
|
11365
11409
|
if (v)
|
|
11366
11410
|
out[k] = v;
|
|
11367
11411
|
}
|
|
11412
|
+
const notYours = [];
|
|
11413
|
+
for (const k of SHELL_TEXT) {
|
|
11414
|
+
const mine = str6(member[k])?.trim();
|
|
11415
|
+
if (mine)
|
|
11416
|
+
out[k] = mine;
|
|
11417
|
+
else if (str6(p[k])?.trim())
|
|
11418
|
+
notYours.push(k);
|
|
11419
|
+
}
|
|
11420
|
+
if (notYours.length)
|
|
11421
|
+
out.notYours = notYours;
|
|
11368
11422
|
const atOnce = num5(p.atOnce);
|
|
11369
11423
|
if (atOnce !== undefined && atOnce >= 1)
|
|
11370
11424
|
out.atOnce = Math.round(atOnce);
|
|
@@ -11724,6 +11778,36 @@ function sledsSource(client, o) {
|
|
|
11724
11778
|
throw new Error(serverMessage(r));
|
|
11725
11779
|
return eventOpenOf(r.json);
|
|
11726
11780
|
},
|
|
11781
|
+
async openLook(runId, look, engine) {
|
|
11782
|
+
const r = await client.postFull("/proxy/run", {
|
|
11783
|
+
runId,
|
|
11784
|
+
engine,
|
|
11785
|
+
event: {
|
|
11786
|
+
kind: "look",
|
|
11787
|
+
md: look.md,
|
|
11788
|
+
about: { prs: [look.pr], ...look.mock ? { mock: look.mock } : {} }
|
|
11789
|
+
}
|
|
11790
|
+
});
|
|
11791
|
+
if (!r)
|
|
11792
|
+
throw new Error(`${UNREACHABLE2} — the look not raised`);
|
|
11793
|
+
if (r.status >= 300 || !r.json || r.json.ok === false)
|
|
11794
|
+
throw new Error(serverMessage(r));
|
|
11795
|
+
const decisionId = str6(r.json.decisionId);
|
|
11796
|
+
const state = str6(r.json.state);
|
|
11797
|
+
return {
|
|
11798
|
+
opened: r.json.opened === true,
|
|
11799
|
+
...decisionId ? { decisionId } : {},
|
|
11800
|
+
...state ? { state } : {}
|
|
11801
|
+
};
|
|
11802
|
+
},
|
|
11803
|
+
async clearLook(runId, clear, engine) {
|
|
11804
|
+
const r = await client.postFull("/proxy/run", { runId, engine, clearLook: clear });
|
|
11805
|
+
if (!r)
|
|
11806
|
+
throw new Error(`${UNREACHABLE2} — the look not cleared`);
|
|
11807
|
+
if (r.status >= 300 || !r.json || r.json.ok === false)
|
|
11808
|
+
throw new Error(serverMessage(r));
|
|
11809
|
+
return r.json.cleared === true;
|
|
11810
|
+
},
|
|
11727
11811
|
async decisionOf(item, decisionId) {
|
|
11728
11812
|
const route = await routeOf(item);
|
|
11729
11813
|
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject8) : [];
|
|
@@ -12185,9 +12269,13 @@ async function tick(deps) {
|
|
|
12185
12269
|
deps.providerHold = d.providerHold;
|
|
12186
12270
|
deps.atOnce = d.atOnce;
|
|
12187
12271
|
}
|
|
12272
|
+
removeEndedMcpConfigs(deps, made);
|
|
12188
12273
|
}
|
|
12274
|
+
return report;
|
|
12275
|
+
}
|
|
12276
|
+
function removeEndedMcpConfigs(deps, made) {
|
|
12189
12277
|
if (!deps.removeMcpConfig || made.size === 0)
|
|
12190
|
-
return
|
|
12278
|
+
return;
|
|
12191
12279
|
const state = deps.readState();
|
|
12192
12280
|
const live = liveMcpConfigs(state);
|
|
12193
12281
|
for (const p of made) {
|
|
@@ -12205,7 +12293,6 @@ async function tick(deps) {
|
|
|
12205
12293
|
r.mcpConfig = undefined;
|
|
12206
12294
|
deps.writeState(state);
|
|
12207
12295
|
}
|
|
12208
|
-
return report;
|
|
12209
12296
|
}
|
|
12210
12297
|
async function tickOnce(d) {
|
|
12211
12298
|
d.tickProfile = profileOnce(d.readProfile);
|
|
@@ -13491,11 +13578,47 @@ var SELF_NUDGES = 2;
|
|
|
13491
13578
|
function reviewNudge(url, count) {
|
|
13492
13579
|
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.`;
|
|
13493
13580
|
}
|
|
13581
|
+
function lookQuestion(url, mock) {
|
|
13582
|
+
return `A draft PR waits for your look: ${url}.${mock ? ` The mock: ${mock}.` : " Its body names no mock; the PR is the place to look."} Looks good marks it ready for review.`;
|
|
13583
|
+
}
|
|
13584
|
+
async function judgeLook(d, run, view) {
|
|
13585
|
+
const looks = looksOf(d.source);
|
|
13586
|
+
const pr = run.pr;
|
|
13587
|
+
if (!looks || !run.runId)
|
|
13588
|
+
return;
|
|
13589
|
+
const draft = view.state === "OPEN" && view.draft;
|
|
13590
|
+
if (draft && !pr.look) {
|
|
13591
|
+
try {
|
|
13592
|
+
const r = await looks.openLook(run.runId, {
|
|
13593
|
+
md: lookQuestion(pr.url, view.mock),
|
|
13594
|
+
pr: pr.url,
|
|
13595
|
+
...view.mock ? { mock: view.mock } : {}
|
|
13596
|
+
}, d.engine);
|
|
13597
|
+
if (!r.decisionId)
|
|
13598
|
+
return;
|
|
13599
|
+
pr.look = r.decisionId;
|
|
13600
|
+
if (r.opened)
|
|
13601
|
+
d.log(`${ref(run)}: ${pr.url} is a draft — a look waits for a person`);
|
|
13602
|
+
} catch (e) {
|
|
13603
|
+
d.log(`${ref(run)}: could not raise the look on ${pr.url}: ${message(e)}`);
|
|
13604
|
+
}
|
|
13605
|
+
} else if (!draft && pr.look) {
|
|
13606
|
+
const why = view.state === "MERGED" ? "the PR merged" : view.state === "CLOSED" ? "the PR closed without a merge" : "the PR left draft";
|
|
13607
|
+
try {
|
|
13608
|
+
if (await looks.clearLook(run.runId, { pr: pr.url, why }, d.engine))
|
|
13609
|
+
d.log(`${ref(run)}: the look on ${pr.url} is cleared — ${why}`);
|
|
13610
|
+
pr.look = undefined;
|
|
13611
|
+
} catch (e) {
|
|
13612
|
+
d.log(`${ref(run)}: could not clear the look on ${pr.url}: ${message(e)}`);
|
|
13613
|
+
}
|
|
13614
|
+
}
|
|
13615
|
+
}
|
|
13494
13616
|
async function follow(d, state, run, claim, runner, finished, attention, changes, decided) {
|
|
13495
13617
|
const pr = run.pr;
|
|
13496
13618
|
const view = d.prView(d.exec, run.repoPath, pr.url);
|
|
13497
13619
|
if (!view)
|
|
13498
13620
|
return true;
|
|
13621
|
+
await judgeLook(d, run, view);
|
|
13499
13622
|
if (view.state === "MERGED") {
|
|
13500
13623
|
const landed = await ripple(d, state, run, claim, runner, pr.url, finished, decided, view.head, view.mergeCommit);
|
|
13501
13624
|
return !landed;
|
|
@@ -15407,6 +15530,8 @@ function flagsFromProfile(flags, given, profile, home) {
|
|
|
15407
15530
|
const out = { ...flags };
|
|
15408
15531
|
const used = [];
|
|
15409
15532
|
const skipped = [];
|
|
15533
|
+
for (const k of profile.notYours ?? [])
|
|
15534
|
+
skipped.push(`${k} (the workspace default — the engine runs only one you set yourself)`);
|
|
15410
15535
|
if (profile.atOnce !== undefined && !has("at-once")) {
|
|
15411
15536
|
out.atOnce = profile.atOnce;
|
|
15412
15537
|
used.push(`at-once ${profile.atOnce}`);
|
|
@@ -15797,7 +15922,8 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
15797
15922
|
startedAt: (o.now ?? Date.now)(),
|
|
15798
15923
|
runner: deps.runner.name,
|
|
15799
15924
|
atOnce: flags.atOnce,
|
|
15800
|
-
interval: flags.interval
|
|
15925
|
+
interval: flags.interval,
|
|
15926
|
+
cliVersion: "0.1.38"
|
|
15801
15927
|
};
|
|
15802
15928
|
const beat = (checkedAt) => {
|
|
15803
15929
|
const m = deps.machine;
|
|
@@ -17399,6 +17525,8 @@ function flagsFromProfile2(flags, given, profile, home) {
|
|
|
17399
17525
|
const out = { ...flags };
|
|
17400
17526
|
const used = [];
|
|
17401
17527
|
const skipped = [];
|
|
17528
|
+
for (const k of profile.notYours ?? [])
|
|
17529
|
+
skipped.push(`${k} (the workspace default — the engine runs only one you set yourself)`);
|
|
17402
17530
|
if (profile.atOnce !== undefined && !has("at-once")) {
|
|
17403
17531
|
out.atOnce = profile.atOnce;
|
|
17404
17532
|
used.push(`at-once ${profile.atOnce}`);
|
|
@@ -17827,7 +17955,8 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
17827
17955
|
startedAt: (o.now ?? Date.now)(),
|
|
17828
17956
|
runner: deps.runner.name,
|
|
17829
17957
|
atOnce: flags.atOnce,
|
|
17830
|
-
interval: flags.interval
|
|
17958
|
+
interval: flags.interval,
|
|
17959
|
+
cliVersion: "0.1.38"
|
|
17831
17960
|
};
|
|
17832
17961
|
const beat = (checkedAt) => {
|
|
17833
17962
|
const m = deps.machine;
|
|
@@ -18119,7 +18248,12 @@ var engineCmd = async (o) => {
|
|
|
18119
18248
|
const who = { name: flags.name, runner: runner.name };
|
|
18120
18249
|
afterTick = () => {
|
|
18121
18250
|
try {
|
|
18122
|
-
|
|
18251
|
+
const m = deps.machine;
|
|
18252
|
+
send(beatBody(deps.readState(), who, {}, {
|
|
18253
|
+
atOnce: deps.atOnce,
|
|
18254
|
+
...m?.last ? { machine: m.last } : {},
|
|
18255
|
+
...m?.hold && !m.off ? { hold: m.hold } : {}
|
|
18256
|
+
}));
|
|
18123
18257
|
} catch {}
|
|
18124
18258
|
};
|
|
18125
18259
|
}
|
|
@@ -18577,6 +18711,31 @@ function ago(at, now) {
|
|
|
18577
18711
|
// src/commands/engineList.ts
|
|
18578
18712
|
var ENGINE_LIST_USAGE = "usage: sleds engine list [--json]";
|
|
18579
18713
|
var str11 = (x) => typeof x === "string" ? x : "";
|
|
18714
|
+
var numOrNull = (x) => typeof x === "number" && Number.isFinite(x) ? x : null;
|
|
18715
|
+
function machineOf(x) {
|
|
18716
|
+
if (!x || typeof x !== "object")
|
|
18717
|
+
return null;
|
|
18718
|
+
const m = x;
|
|
18719
|
+
const out = { pressure: str11(m.pressure) || "unknown" };
|
|
18720
|
+
for (const k of ["cpuPct", "load1", "cores", "loadPerCore"]) {
|
|
18721
|
+
const n = numOrNull(m[k]);
|
|
18722
|
+
if (n !== null)
|
|
18723
|
+
out[k] = n;
|
|
18724
|
+
}
|
|
18725
|
+
return out;
|
|
18726
|
+
}
|
|
18727
|
+
var LEVELS = ["calm", "strained", "busy"];
|
|
18728
|
+
function workOf(x) {
|
|
18729
|
+
if (!Array.isArray(x))
|
|
18730
|
+
return [];
|
|
18731
|
+
return x.flatMap((w) => {
|
|
18732
|
+
if (!w || typeof w !== "object")
|
|
18733
|
+
return [];
|
|
18734
|
+
const o = w;
|
|
18735
|
+
const item = str11(o.item);
|
|
18736
|
+
return item ? [{ item, node: str11(o.node), title: typeof o.title === "string" ? o.title : null }] : [];
|
|
18737
|
+
});
|
|
18738
|
+
}
|
|
18580
18739
|
function engineRows(raw) {
|
|
18581
18740
|
const rows = Array.isArray(raw.engines) ? raw.engines : [];
|
|
18582
18741
|
return rows.flatMap((r) => {
|
|
@@ -18596,8 +18755,13 @@ function engineRows(raw) {
|
|
|
18596
18755
|
running: typeof e.running === "number" ? e.running : 0,
|
|
18597
18756
|
items: Array.isArray(e.items) ? e.items.filter((i) => typeof i === "string") : [],
|
|
18598
18757
|
seatKind: typeof e.seatKind === "string" ? e.seatKind : null,
|
|
18758
|
+
atOnce: numOrNull(e.atOnce),
|
|
18759
|
+
machine: machineOf(e.machine),
|
|
18760
|
+
level: LEVELS.find((l) => l === e.level) ?? null,
|
|
18761
|
+
allowed: numOrNull(e.allowed),
|
|
18599
18762
|
lastBeatAt: typeof e.lastBeatAt === "number" ? e.lastBeatAt : 0,
|
|
18600
|
-
state: e.state === "up" ? "up" : "down"
|
|
18763
|
+
state: e.state === "up" ? "up" : "down",
|
|
18764
|
+
work: workOf(e.work)
|
|
18601
18765
|
}
|
|
18602
18766
|
];
|
|
18603
18767
|
});
|
|
@@ -18608,7 +18772,10 @@ function engineListLines(rows, now) {
|
|
|
18608
18772
|
"no engines have beaten in this org — start one with `sleds engine` or `sleds engine install`"
|
|
18609
18773
|
];
|
|
18610
18774
|
return rows.map((r) => {
|
|
18611
|
-
const
|
|
18775
|
+
const slots = r.atOnce ? `${r.running} of ${r.atOnce} running` : `${r.running} running`;
|
|
18776
|
+
const parts = [r.name.replace(/^engine:/, ""), r.os || "?", r.state, slots];
|
|
18777
|
+
if (r.state === "up" && r.level && r.level !== "calm")
|
|
18778
|
+
parts.push(r.level);
|
|
18612
18779
|
if (r.state === "down" && r.lastBeatAt)
|
|
18613
18780
|
parts.push(`last beat ${ago(r.lastBeatAt, now)}`);
|
|
18614
18781
|
return clean(parts.join(" · "));
|
|
@@ -18767,6 +18934,7 @@ function engineStatus(i) {
|
|
|
18767
18934
|
...opt("runner", lock.runner || undefined),
|
|
18768
18935
|
atOnce: lock.atOnce,
|
|
18769
18936
|
interval: lock.interval,
|
|
18937
|
+
cliVersion: lock.cliVersion ?? "",
|
|
18770
18938
|
...opt("checkedAt", iso2(lock.checkedAt)),
|
|
18771
18939
|
...opt("nextCheckAt", alive ? iso2(lock.nextCheckAt) : undefined),
|
|
18772
18940
|
...opt("machine", lock.machine ? { ...lock.machine, at: new Date(lock.machine.at).toISOString() } : undefined),
|
|
@@ -20704,8 +20872,9 @@ var mcp = async (o) => {
|
|
|
20704
20872
|
(o.warn ?? ((line) => process.stderr.write(`${line}
|
|
20705
20873
|
`)))("sleds mcp: on this run's token (SLEDS_RUN_TOKEN), not the seat's");
|
|
20706
20874
|
let buffer = "";
|
|
20875
|
+
const decoder = new TextDecoder;
|
|
20707
20876
|
for await (const chunk of stdin) {
|
|
20708
|
-
buffer += typeof chunk === "string" ? chunk :
|
|
20877
|
+
buffer += typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
|
|
20709
20878
|
let nl = buffer.indexOf(`
|
|
20710
20879
|
`);
|
|
20711
20880
|
while (nl !== -1) {
|
|
@@ -20718,6 +20887,7 @@ var mcp = async (o) => {
|
|
|
20718
20887
|
`);
|
|
20719
20888
|
}
|
|
20720
20889
|
}
|
|
20890
|
+
buffer += decoder.decode();
|
|
20721
20891
|
if (buffer.trim().length > 0) {
|
|
20722
20892
|
const out = await handleLine2(buffer, { home: o.home, env });
|
|
20723
20893
|
if (out !== null)
|
|
@@ -21321,13 +21491,13 @@ init_src();
|
|
|
21321
21491
|
import { readFileSync as readFileSync24 } from "node:fs";
|
|
21322
21492
|
import { hostname as hostname12 } from "node:os";
|
|
21323
21493
|
var ARM_USAGE = "usage: sleds route arm <key> [--off] [--json] [--name <engine>] [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--mode <permission-mode>] [--model <id>] [--effort <e>] [--branch '<template>'] [--pr-title '<template>'] [--repos-dir <dir>]";
|
|
21324
|
-
var USAGE = "usage: sleds route <key> [--long | --dot | --json] | sleds route arm <key> [--off] [--json] | sleds route answer <key>/<node> --stdin | sleds route propose <key> --file <nodes.json> | sleds route approve <key> | sleds route redraft <key> | sleds route single <key> | sleds route decisions [<key>] [--flagged] | sleds route decision <key> <id> --seen | --answer --stdin [--route accept|keep|redraft] | --keep-route | --apply [--answer --stdin] | --overrule --stdin | sleds route run <key> [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir>] [--mode <permission-mode>] [--model <id>] [--branch '<template>'] [--pr-title '<template>'] [--once]";
|
|
21494
|
+
var USAGE = "usage: sleds route <key> [--long | --dot | --json] | sleds route arm <key> [--off] [--json] | sleds route answer <key>/<node> --stdin | sleds route propose <key> --file <nodes.json> | sleds route approve <key> | sleds route redraft <key> | sleds route single <key> | sleds route decisions [<key>] [--flagged] | sleds route decision <key> <id> --seen | --answer --stdin [--route accept|keep|redraft] | --keep-route | --apply [--answer --stdin] | --overrule --stdin | --ready | sleds route run <key> [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir>] [--mode <permission-mode>] [--model <id>] [--branch '<template>'] [--pr-title '<template>'] [--once]";
|
|
21325
21495
|
var ANSWER_USAGE = "usage: sleds route answer <key>/<node> <answer…> | sleds route answer <key>/<node> --stdin [--json]";
|
|
21326
21496
|
var PROPOSE_USAGE = "usage: sleds route propose <key> (--file <nodes.json> | --stdin) [--name <engine>] [--json]";
|
|
21327
21497
|
var APPROVE_USAGE = "usage: sleds route approve <key> [--file <nodes.json>] [--json]";
|
|
21328
21498
|
var REDRAFT_USAGE = "usage: sleds route redraft <key> [--json]";
|
|
21329
21499
|
var SINGLE_USAGE = "usage: sleds route single <key> [--json]";
|
|
21330
|
-
var DECISION_USAGE = "usage: sleds route decision <key> <id> --seen | sleds route decision <key> <id> (--answer | --overrule) (<answer…> | --stdin) | sleds route decision <key> <id> [--answer (<answer…> | --stdin)] --route accept|keep|redraft | sleds route decision <key> <id> --keep-route | sleds route decision <key> <id> --apply [--answer (<answer…> | --stdin)] [--json]";
|
|
21500
|
+
var DECISION_USAGE = "usage: sleds route decision <key> <id> --seen | sleds route decision <key> <id> (--answer | --overrule) (<answer…> | --stdin) | sleds route decision <key> <id> [--answer (<answer…> | --stdin)] --route accept|keep|redraft | sleds route decision <key> <id> --keep-route | sleds route decision <key> <id> --apply [--answer (<answer…> | --stdin)] | sleds route decision <key> <id> --ready [--json]";
|
|
21331
21501
|
var ROUTE_VERDICTS = ["accept", "keep", "redraft"];
|
|
21332
21502
|
function nodesFromJson(text) {
|
|
21333
21503
|
let parsed;
|
|
@@ -21656,6 +21826,8 @@ function appliedLine(key, applied) {
|
|
|
21656
21826
|
return a.changed === false ? `${key}: ${what} was already set — answered` : `${key}: set ${what} — answered`;
|
|
21657
21827
|
}
|
|
21658
21828
|
async function decisionCmd(o, argv) {
|
|
21829
|
+
if (argv.includes("--ready"))
|
|
21830
|
+
return readyCmd(o, argv);
|
|
21659
21831
|
const log = o.log ?? console.log;
|
|
21660
21832
|
const error = o.error ?? console.error;
|
|
21661
21833
|
const json = argv.includes("--json");
|
|
@@ -21709,6 +21881,68 @@ async function decisionCmd(o, argv) {
|
|
|
21709
21881
|
}
|
|
21710
21882
|
return said(o, key, json, r, () => log(seen ? `${key}: marked seen` : overrule ? `${key}: overruled — your answer stands in the log` : apply ? appliedLine(key, r.json?.applied) : answeredLine(key, r.json?.route ?? route, r.json?.held)));
|
|
21711
21883
|
}
|
|
21884
|
+
var LOOK_READY_ANSWER = "Looks good — marked ready for review.";
|
|
21885
|
+
function lookToReady(route, id) {
|
|
21886
|
+
const rows = Array.isArray(route?.decisions) ? route.decisions : [];
|
|
21887
|
+
const d = rows.find((r) => r.id === id);
|
|
21888
|
+
if (!d)
|
|
21889
|
+
return { error: `no decision ${id} on this item` };
|
|
21890
|
+
if (d.kind !== "look")
|
|
21891
|
+
return { error: `decision ${id} is not a look — --ready marks a look` };
|
|
21892
|
+
if (d.state !== "escalated")
|
|
21893
|
+
return { error: `decision ${id} is ${String(d.state)} — not a look you owe` };
|
|
21894
|
+
const about = d.about && typeof d.about === "object" ? d.about : {};
|
|
21895
|
+
const pr = Array.isArray(about.prs) ? about.prs.find((p) => typeof p === "string" && p) : undefined;
|
|
21896
|
+
return typeof pr === "string" ? { pr } : { error: `decision ${id} names no PR` };
|
|
21897
|
+
}
|
|
21898
|
+
async function readyCmd(o, argv) {
|
|
21899
|
+
const log = o.log ?? console.log;
|
|
21900
|
+
const error = o.error ?? console.error;
|
|
21901
|
+
const json = argv.includes("--json");
|
|
21902
|
+
const words = argv.filter((a) => a !== "--ready" && a !== "--json");
|
|
21903
|
+
const [key, id] = words;
|
|
21904
|
+
if (!key || !id || words.length !== 2 || words.some((w) => w.startsWith("--"))) {
|
|
21905
|
+
error(DECISION_USAGE);
|
|
21906
|
+
return 2;
|
|
21907
|
+
}
|
|
21908
|
+
const client = engineClient(o);
|
|
21909
|
+
if ("error" in client) {
|
|
21910
|
+
error(client.error);
|
|
21911
|
+
return 1;
|
|
21912
|
+
}
|
|
21913
|
+
const reader = routeReader(o);
|
|
21914
|
+
if ("error" in reader) {
|
|
21915
|
+
error(reader.error);
|
|
21916
|
+
return 1;
|
|
21917
|
+
}
|
|
21918
|
+
const route = await reader.read(key).catch((e) => {
|
|
21919
|
+
error(e instanceof Error ? e.message : String(e));
|
|
21920
|
+
return;
|
|
21921
|
+
});
|
|
21922
|
+
if (route === undefined)
|
|
21923
|
+
return 1;
|
|
21924
|
+
const look = lookToReady(route, id);
|
|
21925
|
+
if ("error" in look) {
|
|
21926
|
+
error(`${key}: ${look.error}`);
|
|
21927
|
+
return 1;
|
|
21928
|
+
}
|
|
21929
|
+
const gh = (o.exec ?? defaultExec)("gh", ["pr", "ready", look.pr]);
|
|
21930
|
+
if (gh.status !== 0) {
|
|
21931
|
+
error(gh.stderr.trim() || `gh pr ready ${look.pr} exited ${gh.status}`);
|
|
21932
|
+
error(`${key}: the look is not answered`);
|
|
21933
|
+
return 1;
|
|
21934
|
+
}
|
|
21935
|
+
const r = await client.postFull("/proxy/route/decision", {
|
|
21936
|
+
project: key,
|
|
21937
|
+
id,
|
|
21938
|
+
answer: LOOK_READY_ANSWER
|
|
21939
|
+
});
|
|
21940
|
+
if (!r) {
|
|
21941
|
+
error(`${key}: ${look.pr} is ready for review, but SLEDS is unreachable — the look is not answered`);
|
|
21942
|
+
return 1;
|
|
21943
|
+
}
|
|
21944
|
+
return said(o, key, json, r, () => log(`${key}: ${look.pr} marked ready for review — the look is answered`));
|
|
21945
|
+
}
|
|
21712
21946
|
var DECISIONS_USAGE = "usage: sleds route decisions [<key>] [--flagged] [--json]";
|
|
21713
21947
|
function decisionsLines(raw) {
|
|
21714
21948
|
const j = clean(raw);
|
|
@@ -24155,7 +24389,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
24155
24389
|
case "version":
|
|
24156
24390
|
case "--version":
|
|
24157
24391
|
case "-v":
|
|
24158
|
-
console.log("sleds 0.1.
|
|
24392
|
+
console.log("sleds 0.1.38");
|
|
24159
24393
|
return 0;
|
|
24160
24394
|
default:
|
|
24161
24395
|
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.38",
|
|
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",
|