@sleds/cli 0.1.68 → 0.1.70
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 +319 -90
- package/package.json +1 -1
package/dist/sleds.mjs
CHANGED
|
@@ -295,6 +295,16 @@ var init_sledSort = __esm(() => {
|
|
|
295
295
|
function slugify(text, max = 63) {
|
|
296
296
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, max);
|
|
297
297
|
}
|
|
298
|
+
|
|
299
|
+
// ../../packages/shared/src/workspaceLook.ts
|
|
300
|
+
var init_workspaceLook = () => {};
|
|
301
|
+
|
|
302
|
+
// ../../packages/shared/src/org/brand.ts
|
|
303
|
+
var BRAND_LOGO_MAX_BYTES;
|
|
304
|
+
var init_brand = __esm(() => {
|
|
305
|
+
init_workspaceLook();
|
|
306
|
+
BRAND_LOGO_MAX_BYTES = 1024 * 1024;
|
|
307
|
+
});
|
|
298
308
|
// ../../packages/shared/src/seat/agents.ts
|
|
299
309
|
var init_agents = () => {};
|
|
300
310
|
// ../../packages/shared/src/seat/burn.ts
|
|
@@ -1107,6 +1117,9 @@ function norm(label) {
|
|
|
1107
1117
|
function plain(s) {
|
|
1108
1118
|
return s.replace(/[*_`~]+/g, "").replace(/\s+/g, " ").trim();
|
|
1109
1119
|
}
|
|
1120
|
+
function isNoAnswer(s) {
|
|
1121
|
+
return !s || /^(n\/?a|none|no|nil|null|-+|—|tbd|\?+)\.?$/i.test(s.trim());
|
|
1122
|
+
}
|
|
1110
1123
|
function titleOf(s, max = 80) {
|
|
1111
1124
|
const t = plain(s);
|
|
1112
1125
|
const first = /^(.+?[.!?])(\s|$)/.exec(t)?.[1] ?? t;
|
|
@@ -1290,9 +1303,9 @@ function draftBrief(input) {
|
|
|
1290
1303
|
const byKey = form ? {
|
|
1291
1304
|
touches: form.touches,
|
|
1292
1305
|
demand: form.demand,
|
|
1293
|
-
...form.expected ? { done: form.expected } : {}
|
|
1306
|
+
...form.expected && !isNoAnswer(form.expected) ? { done: form.expected } : {}
|
|
1294
1307
|
} : parsed.byKey;
|
|
1295
|
-
const fromText = form?.summary ? form.summary : form?.ask ? form.ask : askFrom(text, preamble);
|
|
1308
|
+
const fromText = form?.summary && !isNoAnswer(form.summary) ? form.summary : form?.ask ? form.ask : askFrom(text, preamble);
|
|
1296
1309
|
const askText = a.ask?.trim() || (fromText ? titleOf(fromText) : undefined);
|
|
1297
1310
|
if (!askText)
|
|
1298
1311
|
return null;
|
|
@@ -4481,6 +4494,7 @@ async function actualTool(ctx, args, to = { path: "/proxy/estimate/actual" }) {
|
|
|
4481
4494
|
...num3(args.usd) !== undefined ? { actualUsd: num3(args.usd) } : {},
|
|
4482
4495
|
...args.usd === null ? { actualUsd: null } : {},
|
|
4483
4496
|
...str5(args.state) ? { state: str5(args.state) } : {},
|
|
4497
|
+
...args.devVerified === true ? { devVerified: true } : {},
|
|
4484
4498
|
...Object.keys(work).length > 0 ? { work } : {}
|
|
4485
4499
|
};
|
|
4486
4500
|
const res = await ctx.client.postFull(to.path, body);
|
|
@@ -5529,6 +5543,10 @@ var init_server = __esm(() => {
|
|
|
5529
5543
|
type: "string",
|
|
5530
5544
|
description: "started · done · merged · shipped · parked (default: done when minutes or finishedAt are given)."
|
|
5531
5545
|
},
|
|
5546
|
+
devVerified: {
|
|
5547
|
+
type: "boolean",
|
|
5548
|
+
description: "true when you verified it yourself — the finish skips verification (the workspace's QA column) and the merge lands it as before. Never set it by rule."
|
|
5549
|
+
},
|
|
5532
5550
|
phases: {
|
|
5533
5551
|
type: "object",
|
|
5534
5552
|
description: "Minutes by phase; total defaults to their sum when `minutes` is absent.",
|
|
@@ -5619,6 +5637,10 @@ var init_server = __esm(() => {
|
|
|
5619
5637
|
type: "string",
|
|
5620
5638
|
description: "started · done · merged · shipped · parked (default: done when minutes or finishedAt are given)."
|
|
5621
5639
|
},
|
|
5640
|
+
devVerified: {
|
|
5641
|
+
type: "boolean",
|
|
5642
|
+
description: "true when you verified it yourself — the finish skips verification (the workspace's QA column) and the merge lands it as before. Never set it by rule."
|
|
5643
|
+
},
|
|
5622
5644
|
phases: {
|
|
5623
5645
|
type: "object",
|
|
5624
5646
|
description: "Minutes by phase; total defaults to their sum when `minutes` is absent.",
|
|
@@ -5668,6 +5690,10 @@ var init_server = __esm(() => {
|
|
|
5668
5690
|
feature: { type: "string" },
|
|
5669
5691
|
ref: { type: "string", description: "Where the output lives: PR url, commit, doc." },
|
|
5670
5692
|
state: { type: "string", description: "done · merged · shipped (default: done)." },
|
|
5693
|
+
devVerified: {
|
|
5694
|
+
type: "boolean",
|
|
5695
|
+
description: "true when you verified it yourself — the finish skips verification (the workspace's QA column) and the merge lands it as before. Never set it by rule."
|
|
5696
|
+
},
|
|
5671
5697
|
model: { type: "string" },
|
|
5672
5698
|
sessionId: { type: "string" },
|
|
5673
5699
|
node: {
|
|
@@ -8174,9 +8200,6 @@ var init_effort = __esm(() => {
|
|
|
8174
8200
|
EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
8175
8201
|
});
|
|
8176
8202
|
|
|
8177
|
-
// ../../packages/shared/src/workspaceLook.ts
|
|
8178
|
-
var init_workspaceLook = () => {};
|
|
8179
|
-
|
|
8180
8203
|
// src/settings.ts
|
|
8181
8204
|
import { execFileSync } from "node:child_process";
|
|
8182
8205
|
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -8806,6 +8829,7 @@ var init_src = __esm(() => {
|
|
|
8806
8829
|
init_sledConfig();
|
|
8807
8830
|
init_sledSort();
|
|
8808
8831
|
init_gate();
|
|
8832
|
+
init_brand();
|
|
8809
8833
|
init_agents();
|
|
8810
8834
|
init_burn();
|
|
8811
8835
|
init_cowork();
|
|
@@ -9301,6 +9325,7 @@ function parseRun(v) {
|
|
|
9301
9325
|
}
|
|
9302
9326
|
} : {},
|
|
9303
9327
|
...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 } } : {},
|
|
9328
|
+
...isObject8(v.atPrompt) && typeof v.atPrompt.since === "number" && typeof v.atPrompt.text === "string" ? { atPrompt: { since: v.atPrompt.since, text: v.atPrompt.text } } : {},
|
|
9304
9329
|
...parked ? { parked } : {},
|
|
9305
9330
|
...isObject8(v.pr) && typeof v.pr.url === "string" ? {
|
|
9306
9331
|
pr: {
|
|
@@ -9586,6 +9611,7 @@ init_envelope();
|
|
|
9586
9611
|
init_sledConfig();
|
|
9587
9612
|
init_sledSort();
|
|
9588
9613
|
init_gate();
|
|
9614
|
+
init_brand();
|
|
9589
9615
|
init_agents();
|
|
9590
9616
|
init_burn();
|
|
9591
9617
|
init_cowork();
|
|
@@ -11563,7 +11589,20 @@ var mainCheckoutOf = (gitCommonDir, cwd) => {
|
|
|
11563
11589
|
const main = dir.slice(0, -"/.git".length);
|
|
11564
11590
|
return main && main !== cwd.replace(/\/+$/, "") ? main : null;
|
|
11565
11591
|
};
|
|
11566
|
-
var
|
|
11592
|
+
var trimDir = (dir) => dir.replace(/\/+$/, "") || "/";
|
|
11593
|
+
var within = (path, dir) => {
|
|
11594
|
+
const p = trimDir(path);
|
|
11595
|
+
const d = trimDir(dir);
|
|
11596
|
+
return p === d || p.startsWith(d === "/" ? "/" : `${d}/`);
|
|
11597
|
+
};
|
|
11598
|
+
var sessionReadDirs = (o) => {
|
|
11599
|
+
const cwd = trimDir(o.cwd);
|
|
11600
|
+
const dirs = [o.mainCheckout, ...o.worktrees ?? [], o.pnpmStore].filter((d) => !!d?.trim()).map(trimDir);
|
|
11601
|
+
return [...new Set(dirs)].filter((d) => d !== cwd);
|
|
11602
|
+
};
|
|
11603
|
+
var readOnlyDirs = (readDirs, cwd, keep = []) => readDirs.filter((d) => ![cwd, ...keep].some((p) => within(p, d)));
|
|
11604
|
+
var readOnlyDenyRules = (dirs) => dirs.map((d) => `Edit(${absRule(d)})`);
|
|
11605
|
+
var claudeAddDirFlag = (dirs = []) => dirs.map((d) => ` --add-dir=${shq(d)}`).join("");
|
|
11567
11606
|
var shq = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
11568
11607
|
|
|
11569
11608
|
// src/runners/exec.ts
|
|
@@ -11609,15 +11648,15 @@ var agentShellCommand = (o) => {
|
|
|
11609
11648
|
const prompt = `"$(cat ${shq2(o.promptFile)})"`;
|
|
11610
11649
|
const agent = o.agent?.trim();
|
|
11611
11650
|
if (agent)
|
|
11612
|
-
return `${sandboxedAgent(agent, o.sandbox, o.
|
|
11651
|
+
return `${sandboxedAgent(agent, o.sandbox, o.readDirs)} ${prompt}`;
|
|
11613
11652
|
const model = o.model ? ` --model ${shq2(o.model)}` : "";
|
|
11614
11653
|
const effort = o.effort ? ` --effort ${shq2(o.effort)}` : "";
|
|
11615
|
-
return `${sandboxedAgent("claude", o.sandbox, o.
|
|
11654
|
+
return `${sandboxedAgent("claude", o.sandbox, o.readDirs)}${hookSettingsFlag(o)}${mcpConfigFlag(o)} --permission-mode ${shq2(o.permissionMode)}${model}${effort} ${prompt}`;
|
|
11616
11655
|
};
|
|
11617
11656
|
var execLine = (cmd) => /^[A-Za-z_][A-Za-z0-9_]*=/.test(cmd) ? `exec env ${cmd}` : `exec ${cmd}`;
|
|
11618
|
-
var sandboxedAgent = (agent, sandbox,
|
|
11657
|
+
var sandboxedAgent = (agent, sandbox, readDirs) => {
|
|
11619
11658
|
const kind = sandboxAgentKind(agent);
|
|
11620
|
-
const line = kind === "claude" ? `${agent}${claudeAddDirFlag(
|
|
11659
|
+
const line = kind === "claude" ? `${agent}${claudeAddDirFlag(readDirs)}` : agent;
|
|
11621
11660
|
if (!sandbox)
|
|
11622
11661
|
return line;
|
|
11623
11662
|
if (kind === "claude")
|
|
@@ -12340,7 +12379,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
12340
12379
|
name: flags.name,
|
|
12341
12380
|
os: host.os ?? process.platform,
|
|
12342
12381
|
runner: flags.runner,
|
|
12343
|
-
version: host.version ?? "0.1.
|
|
12382
|
+
version: host.version ?? "0.1.70" ?? "dev",
|
|
12344
12383
|
running: live.length,
|
|
12345
12384
|
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
12346
12385
|
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
@@ -14580,21 +14619,65 @@ function permissionDialog(screen) {
|
|
|
14580
14619
|
if (t && !isRule(raw[i]) && !DIALOG_FOOTER.test(t) && !isFooter(t))
|
|
14581
14620
|
return null;
|
|
14582
14621
|
}
|
|
14622
|
+
return { text: dialogBody(raw, lines, q), options };
|
|
14623
|
+
}
|
|
14624
|
+
function dialogBody(raw, lines, last) {
|
|
14583
14625
|
let from = 0;
|
|
14584
|
-
for (let j =
|
|
14626
|
+
for (let j = last;j >= 0; j--) {
|
|
14585
14627
|
const t = lines[j].trim();
|
|
14586
14628
|
if (isRule(raw[j]) || /^⏺/.test(t) || /^⎿/.test(t)) {
|
|
14587
14629
|
from = j + 1;
|
|
14588
14630
|
break;
|
|
14589
14631
|
}
|
|
14590
14632
|
}
|
|
14591
|
-
const body = lines.slice(from,
|
|
14592
|
-
const
|
|
14593
|
-
|
|
14633
|
+
const body = lines.slice(from, last + 1);
|
|
14634
|
+
const inked = body.filter((l) => l.trim());
|
|
14635
|
+
if (!inked.length)
|
|
14636
|
+
return "";
|
|
14637
|
+
const indent = Math.min(...inked.map((l) => /^\s*/.exec(l)[0].length));
|
|
14638
|
+
return body.map((l) => l.slice(indent)).join(`
|
|
14594
14639
|
`).replace(/\n{3,}/g, `
|
|
14595
14640
|
|
|
14596
14641
|
`).trim();
|
|
14597
|
-
|
|
14642
|
+
}
|
|
14643
|
+
var CURSOR_CHOICE = /^❯\s*\d\.\s/;
|
|
14644
|
+
var CANCEL_FOOTER = /\besc to cancel\b/i;
|
|
14645
|
+
function stoppedAtPrompt(screen) {
|
|
14646
|
+
const dialog = permissionDialog(screen);
|
|
14647
|
+
if (dialog)
|
|
14648
|
+
return { text: dialog.text };
|
|
14649
|
+
const raw = screen.split(`
|
|
14650
|
+
`);
|
|
14651
|
+
const lines = raw.map(unbox);
|
|
14652
|
+
let c = -1;
|
|
14653
|
+
for (let i = lines.length - 1;i >= 0; i--)
|
|
14654
|
+
if (CURSOR_CHOICE.test(lines[i].trim())) {
|
|
14655
|
+
c = i;
|
|
14656
|
+
break;
|
|
14657
|
+
}
|
|
14658
|
+
if (c < 0)
|
|
14659
|
+
return null;
|
|
14660
|
+
let footer = -1;
|
|
14661
|
+
for (let i = c + 1;i < lines.length; i++) {
|
|
14662
|
+
const t = lines[i].trim();
|
|
14663
|
+
if (/^⏺/.test(t) || isPrompt(t) && !CURSOR_CHOICE.test(t))
|
|
14664
|
+
return null;
|
|
14665
|
+
if (footer < 0 && CANCEL_FOOTER.test(t))
|
|
14666
|
+
footer = i;
|
|
14667
|
+
else if (footer >= 0 && t && !isRule(raw[i]) && !isFooter(t) && !DIALOG_FOOTER.test(t))
|
|
14668
|
+
return null;
|
|
14669
|
+
}
|
|
14670
|
+
if (footer < 0 && !choicePicker(screen))
|
|
14671
|
+
return null;
|
|
14672
|
+
let first = c;
|
|
14673
|
+
for (let i = c;i >= 0 && c - i < PICKER_REACH; i--)
|
|
14674
|
+
if (/^(?:❯\s*)?1\.\s/.test(lines[i].trim())) {
|
|
14675
|
+
first = i;
|
|
14676
|
+
break;
|
|
14677
|
+
}
|
|
14678
|
+
const text = dialogBody(raw, lines, first - 1) || lines.slice(first, c + 1).map((l) => l.trim()).join(`
|
|
14679
|
+
`);
|
|
14680
|
+
return { text };
|
|
14598
14681
|
}
|
|
14599
14682
|
var PROVIDER_FAILURES = [
|
|
14600
14683
|
["connection lost", /\bconnection (?:lost|error)\b/i],
|
|
@@ -14955,21 +15038,29 @@ function fingerprint(text) {
|
|
|
14955
15038
|
function wordsPrint(screen) {
|
|
14956
15039
|
return fingerprint(stripTuiChrome(screen));
|
|
14957
15040
|
}
|
|
14958
|
-
function sandboxFor(d, name, cwd, allow) {
|
|
15041
|
+
function sandboxFor(d, name, cwd, allow, readOnly) {
|
|
14959
15042
|
if (!d.sandbox)
|
|
14960
15043
|
return {};
|
|
14961
15044
|
if (!d.writeSandboxSettings)
|
|
14962
15045
|
throw new Error("sessions are sandboxed, but nothing writes their settings — not started");
|
|
14963
|
-
return { sandbox: d.writeSandboxSettings(name, cwd, allow) };
|
|
15046
|
+
return { sandbox: d.writeSandboxSettings(name, cwd, allow, readOnly) };
|
|
14964
15047
|
}
|
|
14965
|
-
function hooksFor(d, name, allow) {
|
|
15048
|
+
function hooksFor(d, name, allow, readOnly) {
|
|
14966
15049
|
if (d.sandbox || !d.writeHookSettings)
|
|
14967
15050
|
return {};
|
|
14968
|
-
return { settingsFile: d.writeHookSettings(name, allow) };
|
|
15051
|
+
return { settingsFile: d.writeHookSettings(name, allow, readOnly) };
|
|
14969
15052
|
}
|
|
14970
|
-
function
|
|
14971
|
-
|
|
14972
|
-
|
|
15053
|
+
function wallsFor(d, name, cwd, allow) {
|
|
15054
|
+
let readDirs = [];
|
|
15055
|
+
try {
|
|
15056
|
+
readDirs = d.readDirsOf?.(cwd) ?? [];
|
|
15057
|
+
} catch {}
|
|
15058
|
+
const readOnly = readOnlyDirs(readDirs, cwd);
|
|
15059
|
+
return {
|
|
15060
|
+
...sandboxFor(d, name, cwd, allow, readOnly),
|
|
15061
|
+
...hooksFor(d, name, allow, readOnly),
|
|
15062
|
+
...readDirs.length ? { readDirs } : {}
|
|
15063
|
+
};
|
|
14973
15064
|
}
|
|
14974
15065
|
function engineMcpConfigFor(d, name, runToken, at, cwd) {
|
|
14975
15066
|
if (d.source.name !== "sleds" || d.agent?.trim() || !d.writeMcpConfig)
|
|
@@ -15216,7 +15307,9 @@ async function tickOnce(d) {
|
|
|
15216
15307
|
idle = false;
|
|
15217
15308
|
asked = false;
|
|
15218
15309
|
failing = null;
|
|
15219
|
-
|
|
15310
|
+
run.atPrompt = undefined;
|
|
15311
|
+
} else if (runner.readsSession)
|
|
15312
|
+
notePrompt(d, runner, run, shown);
|
|
15220
15313
|
const retry = failing !== null && (run.provider?.tries ?? 0) < PROVIDER_RETRIES;
|
|
15221
15314
|
if (idle || failing || needsHeartbeat(run.leaseUntil, d.now(), d.leaseMin)) {
|
|
15222
15315
|
let beat;
|
|
@@ -15519,9 +15612,7 @@ async function tickOnce(d) {
|
|
|
15519
15612
|
...launch.effort && !launch.agent ? { effort: launch.effort } : {},
|
|
15520
15613
|
...launch.agent ? { agent: launch.agent } : {},
|
|
15521
15614
|
...mcpConfig ? { mcpConfig, ...d.strictMcp ? { strictMcp: true } : {} } : {},
|
|
15522
|
-
...
|
|
15523
|
-
...hooksFor(d, name, allow),
|
|
15524
|
-
...mainCheckoutFor(d, worktree),
|
|
15615
|
+
...wallsFor(d, name, worktree, allow),
|
|
15525
15616
|
...claim.group ? { group: claim.group } : {}
|
|
15526
15617
|
};
|
|
15527
15618
|
} catch (e) {
|
|
@@ -15813,6 +15904,17 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
15813
15904
|
d.log(`${at}: stopped at a permission dialog — it waits for a person (${runner.watchHint(run.handle)})`);
|
|
15814
15905
|
return true;
|
|
15815
15906
|
}
|
|
15907
|
+
function notePrompt(d, runner, run, shown) {
|
|
15908
|
+
if (!shown)
|
|
15909
|
+
return;
|
|
15910
|
+
const prompt = stoppedAtPrompt(shown);
|
|
15911
|
+
if (!prompt || run.atPrompt && run.atPrompt.text !== prompt.text)
|
|
15912
|
+
run.atPrompt = undefined;
|
|
15913
|
+
if (!prompt || run.atPrompt || !run.seenTicks)
|
|
15914
|
+
return;
|
|
15915
|
+
run.atPrompt = { since: d.now(), text: prompt.text };
|
|
15916
|
+
d.log(`${ref(run)}: stopped at a prompt the engine cannot answer — answer it in the terminal (${runner.watchHint(run.handle)})`);
|
|
15917
|
+
}
|
|
15816
15918
|
var PRESS_TRIES = 3;
|
|
15817
15919
|
function pressAnswer(d, runner, run, options, answer) {
|
|
15818
15920
|
const at = ref(run);
|
|
@@ -16398,9 +16500,7 @@ async function startAnswerer(d, answers, run) {
|
|
|
16398
16500
|
permissionMode: d.permissionMode,
|
|
16399
16501
|
...launchOptions(launch),
|
|
16400
16502
|
...mcpConfig ? { mcpConfig, ...d.strictMcp ? { strictMcp: true } : {} } : {},
|
|
16401
|
-
...
|
|
16402
|
-
...hooksFor(d, name),
|
|
16403
|
-
...mainCheckoutFor(d, run.handle.cwd),
|
|
16503
|
+
...wallsFor(d, name, run.handle.cwd),
|
|
16404
16504
|
...run.group ? { group: run.group } : {}
|
|
16405
16505
|
});
|
|
16406
16506
|
} catch (e) {
|
|
@@ -16608,9 +16708,7 @@ async function startDraft(d, claim, why, state, started, finished) {
|
|
|
16608
16708
|
permissionMode: d.permissionMode,
|
|
16609
16709
|
...launchOptions(launch),
|
|
16610
16710
|
...mcpConfig ? { mcpConfig, ...d.strictMcp ? { strictMcp: true } : {} } : {},
|
|
16611
|
-
...
|
|
16612
|
-
...hooksFor(d, name),
|
|
16613
|
-
...mainCheckoutFor(d, worktree)
|
|
16711
|
+
...wallsFor(d, name, worktree)
|
|
16614
16712
|
});
|
|
16615
16713
|
} catch (e) {
|
|
16616
16714
|
d.log(`${at}: could not start the drafter: ${message(e)}`);
|
|
@@ -16789,9 +16887,7 @@ async function startMock(d, claim, state, started, finished) {
|
|
|
16789
16887
|
promptFile: d.writePrompt(name, prompt),
|
|
16790
16888
|
permissionMode: d.permissionMode,
|
|
16791
16889
|
...launchOptions(launch),
|
|
16792
|
-
...
|
|
16793
|
-
...hooksFor(d, name, allow),
|
|
16794
|
-
...mainCheckoutFor(d, worktree)
|
|
16890
|
+
...wallsFor(d, name, worktree, allow)
|
|
16795
16891
|
});
|
|
16796
16892
|
} catch (e) {
|
|
16797
16893
|
await fail(`the engine could not start the session: ${message(e)}`);
|
|
@@ -17678,9 +17774,7 @@ function restartInWorktree(d, run, name, prompt, base) {
|
|
|
17678
17774
|
permissionMode: d.permissionMode,
|
|
17679
17775
|
...launchOptions(launch),
|
|
17680
17776
|
...run.mcpConfig ? { mcpConfig: run.mcpConfig, ...d.strictMcp ? { strictMcp: true } : {} } : {},
|
|
17681
|
-
...
|
|
17682
|
-
...hooksFor(d, name),
|
|
17683
|
-
...mainCheckoutFor(d, run.handle.cwd),
|
|
17777
|
+
...wallsFor(d, name, run.handle.cwd),
|
|
17684
17778
|
...run.group ? { group: run.group } : {}
|
|
17685
17779
|
};
|
|
17686
17780
|
run.handle = runner.makesWorktree ? runner.reopen(run.handle, o) : runner.start(o);
|
|
@@ -17814,9 +17908,7 @@ async function startEventAnswerer(d, answers, state, dec, decided) {
|
|
|
17814
17908
|
permissionMode: d.permissionMode,
|
|
17815
17909
|
...launchOptions(launch),
|
|
17816
17910
|
...mcpConfig ? { mcpConfig, ...d.strictMcp ? { strictMcp: true } : {} } : {},
|
|
17817
|
-
...
|
|
17818
|
-
...hooksFor(d, name),
|
|
17819
|
-
...mainCheckoutFor(d, worktree)
|
|
17911
|
+
...wallsFor(d, name, worktree)
|
|
17820
17912
|
});
|
|
17821
17913
|
} catch (e) {
|
|
17822
17914
|
d.log(`${at}: could not start the ${KIND_SAYS[kind]} answerer — it goes to a person: ${message(e)}`);
|
|
@@ -18344,8 +18436,8 @@ ${renderTranscript(messages)}`;
|
|
|
18344
18436
|
var headlessScript = (o, log) => {
|
|
18345
18437
|
const prompt = `"$(cat ${shq2(o.promptFile)})"`;
|
|
18346
18438
|
const agent = o.agent?.trim();
|
|
18347
|
-
const cmd = agent ? `${sandboxedAgent(agent, o.sandbox, o.
|
|
18348
|
-
`${sandboxedAgent("claude", o.sandbox, o.
|
|
18439
|
+
const cmd = agent ? `${sandboxedAgent(agent, o.sandbox, o.readDirs)} ${prompt}` : [
|
|
18440
|
+
`${sandboxedAgent("claude", o.sandbox, o.readDirs)} -p`,
|
|
18349
18441
|
prompt,
|
|
18350
18442
|
...o.mcpConfig ? [mcpConfigFlag(o).trim()] : [],
|
|
18351
18443
|
"--output-format stream-json --verbose",
|
|
@@ -19224,7 +19316,7 @@ async function fetchVersion(o) {
|
|
|
19224
19316
|
const platform = o.platform ?? process.platform;
|
|
19225
19317
|
const arch = o.arch ?? process.arch;
|
|
19226
19318
|
const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
|
|
19227
|
-
const running = o.running ?? "0.1.
|
|
19319
|
+
const running = o.running ?? "0.1.70";
|
|
19228
19320
|
if (!publicKey)
|
|
19229
19321
|
return { ok: false, why: "no release key yet" };
|
|
19230
19322
|
if (!VERSION_RE2.test(o.version))
|
|
@@ -20450,7 +20542,7 @@ function engineUpdater(o) {
|
|
|
20450
20542
|
|
|
20451
20543
|
// src/version.ts
|
|
20452
20544
|
function cliVersion(env) {
|
|
20453
|
-
return "0.1.
|
|
20545
|
+
return "0.1.70";
|
|
20454
20546
|
}
|
|
20455
20547
|
|
|
20456
20548
|
// src/commands/update.ts
|
|
@@ -20836,7 +20928,7 @@ function engineClient(o, org, breaker) {
|
|
|
20836
20928
|
...src,
|
|
20837
20929
|
...breaker ? { fetchFn: breaker.fetch } : {},
|
|
20838
20930
|
timeoutMs: ENGINE_TIMEOUT_MS,
|
|
20839
|
-
version: "0.1.
|
|
20931
|
+
version: "0.1.70"
|
|
20840
20932
|
});
|
|
20841
20933
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
20842
20934
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -20912,6 +21004,7 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20912
21004
|
const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve9(cwd, d));
|
|
20913
21005
|
const { branch, prTitle } = flags;
|
|
20914
21006
|
const hooksDir = join25(stateDir, "hooks");
|
|
21007
|
+
const pnpmStores = new Map;
|
|
20915
21008
|
const permissionMark = (name) => join25(hooksDir, `${name}.permission.json`);
|
|
20916
21009
|
const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
|
|
20917
21010
|
return {
|
|
@@ -20935,7 +21028,7 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20935
21028
|
...flags.strictMcp ? { strictMcp: true } : {},
|
|
20936
21029
|
...flags.sandbox ? {
|
|
20937
21030
|
sandbox: true,
|
|
20938
|
-
writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
|
|
21031
|
+
writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow, readOnly) => {
|
|
20939
21032
|
const gitCommonDir = gitCommonDirOf(exec, cwd);
|
|
20940
21033
|
const dir = join25(stateDir, "sandbox");
|
|
20941
21034
|
mkdirSync18(dir, { recursive: true, mode: 448 });
|
|
@@ -20947,6 +21040,12 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20947
21040
|
walls.permissions.allow = [
|
|
20948
21041
|
...new Set([...walls.permissions.allow, ...allow ?? []])
|
|
20949
21042
|
];
|
|
21043
|
+
walls.permissions.deny = [
|
|
21044
|
+
...new Set([
|
|
21045
|
+
...walls.permissions.deny,
|
|
21046
|
+
...readOnlyDenyRules(readOnlyDirs(readOnly ?? [], cwd, [gitCommonDir]))
|
|
21047
|
+
])
|
|
21048
|
+
];
|
|
20950
21049
|
const settings = withHook(name, { ...walls });
|
|
20951
21050
|
writeFileSync16(p, `${JSON.stringify(settings, null, 2)}
|
|
20952
21051
|
`, { mode: 384 });
|
|
@@ -20954,23 +21053,22 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20954
21053
|
return { settingsFile: p, gitCommonDir };
|
|
20955
21054
|
})
|
|
20956
21055
|
} : {},
|
|
20957
|
-
writeHookSettings: (name, allow) => {
|
|
21056
|
+
writeHookSettings: (name, allow, readOnly) => {
|
|
20958
21057
|
mkdirSync18(hooksDir, { recursive: true, mode: 448 });
|
|
20959
21058
|
const p = join25(hooksDir, `${name}.json`);
|
|
20960
|
-
const
|
|
21059
|
+
const deny = readOnlyDenyRules(readOnly ?? []);
|
|
21060
|
+
const permissions = {
|
|
21061
|
+
...allow?.length ? { allow: [...allow] } : {},
|
|
21062
|
+
...deny.length ? { deny } : {}
|
|
21063
|
+
};
|
|
21064
|
+
const base = Object.keys(permissions).length ? { permissions } : {};
|
|
20961
21065
|
writeFileSync16(p, `${JSON.stringify(withHook(name, base), null, 2)}
|
|
20962
21066
|
`, { mode: 384 });
|
|
20963
21067
|
chmodSync5(p, 384);
|
|
20964
21068
|
return p;
|
|
20965
21069
|
},
|
|
20966
21070
|
permissionMark,
|
|
20967
|
-
|
|
20968
|
-
try {
|
|
20969
|
-
return mainCheckoutOf(gitCommonDirOf(exec, cwd), cwd);
|
|
20970
|
-
} catch {
|
|
20971
|
-
return null;
|
|
20972
|
-
}
|
|
20973
|
-
}),
|
|
21071
|
+
readDirsOf: o.readDirsOf ?? ((dir) => engineReadDirs(exec, dir, exists, pnpmStores)),
|
|
20974
21072
|
...branch ? { branchOf: (claim) => branchFor(branch, claim) } : {},
|
|
20975
21073
|
...prTitle ? { prTitleOf: (claim) => prTitleFor(prTitle, claim) } : {},
|
|
20976
21074
|
now: o.now ?? Date.now,
|
|
@@ -21072,6 +21170,52 @@ function gitCommonDirOf(exec, cwd) {
|
|
|
21072
21170
|
throw new Error(`git has no common dir for ${cwd}, so the sandbox has nowhere to commit`);
|
|
21073
21171
|
return resolve9(cwd, dir);
|
|
21074
21172
|
}
|
|
21173
|
+
function worktreeListPaths(porcelain) {
|
|
21174
|
+
return porcelain.split(/\n\s*\n/).map((block) => block.split(`
|
|
21175
|
+
`).map((l) => l.trim())).filter((lines) => !lines.some((l) => l === "bare" || l.startsWith("prunable"))).flatMap((lines) => {
|
|
21176
|
+
const wt = lines.find((l) => l.startsWith("worktree "));
|
|
21177
|
+
return wt ? [wt.slice("worktree ".length)] : [];
|
|
21178
|
+
});
|
|
21179
|
+
}
|
|
21180
|
+
var PNPM_STORE_TIMEOUT_MS = 1e4;
|
|
21181
|
+
function engineReadDirs(exec, cwd, exists, stores) {
|
|
21182
|
+
let common = null;
|
|
21183
|
+
try {
|
|
21184
|
+
common = gitCommonDirOf(exec, cwd);
|
|
21185
|
+
} catch {}
|
|
21186
|
+
const worktrees = (() => {
|
|
21187
|
+
try {
|
|
21188
|
+
const r = exec("git", ["-C", cwd, "worktree", "list", "--porcelain"]);
|
|
21189
|
+
return r.status === 0 ? worktreeListPaths(r.stdout) : [];
|
|
21190
|
+
} catch {
|
|
21191
|
+
return [];
|
|
21192
|
+
}
|
|
21193
|
+
})();
|
|
21194
|
+
const pnpmStore = (() => {
|
|
21195
|
+
try {
|
|
21196
|
+
if (!exists(join25(cwd, "pnpm-lock.yaml")))
|
|
21197
|
+
return null;
|
|
21198
|
+
const key = common ?? cwd;
|
|
21199
|
+
const known = stores.get(key);
|
|
21200
|
+
if (known)
|
|
21201
|
+
return known;
|
|
21202
|
+
const r = exec("pnpm", ["store", "path"], { cwd, timeoutMs: PNPM_STORE_TIMEOUT_MS });
|
|
21203
|
+
const dir = r.status === 0 ? r.stdout.split(`
|
|
21204
|
+
`).map((l) => l.trim()).filter((l) => l.startsWith("/")).pop() : undefined;
|
|
21205
|
+
if (dir)
|
|
21206
|
+
stores.set(key, dir);
|
|
21207
|
+
return dir ?? null;
|
|
21208
|
+
} catch {
|
|
21209
|
+
return null;
|
|
21210
|
+
}
|
|
21211
|
+
})();
|
|
21212
|
+
return sessionReadDirs({
|
|
21213
|
+
mainCheckout: common ? mainCheckoutOf(common, cwd) : null,
|
|
21214
|
+
worktrees,
|
|
21215
|
+
pnpmStore,
|
|
21216
|
+
cwd
|
|
21217
|
+
});
|
|
21218
|
+
}
|
|
21075
21219
|
var LENT_NEEDS_SANDBOX = "a lent engine runs every session sandboxed (spec 48 rule 10) — add --sandbox to --lent-by";
|
|
21076
21220
|
function lenderHome(accountHome, lentBy) {
|
|
21077
21221
|
return isAbsolute3(lentBy) ? resolve9(lentBy) : join25(dirname16(accountHome), lentBy);
|
|
@@ -21142,7 +21286,7 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
21142
21286
|
runner: deps.runner.name,
|
|
21143
21287
|
atOnce: flags.atOnce,
|
|
21144
21288
|
interval: flags.interval,
|
|
21145
|
-
cliVersion: "0.1.
|
|
21289
|
+
cliVersion: "0.1.70"
|
|
21146
21290
|
};
|
|
21147
21291
|
const beat = (checkedAt) => {
|
|
21148
21292
|
const m = deps.machine;
|
|
@@ -23020,7 +23164,7 @@ function engineClient2(o, org, breaker) {
|
|
|
23020
23164
|
...src,
|
|
23021
23165
|
...breaker ? { fetchFn: breaker.fetch } : {},
|
|
23022
23166
|
timeoutMs: ENGINE_TIMEOUT_MS2,
|
|
23023
|
-
version: "0.1.
|
|
23167
|
+
version: "0.1.70"
|
|
23024
23168
|
});
|
|
23025
23169
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
23026
23170
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -23118,6 +23262,7 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
23118
23262
|
const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve11(cwd, d));
|
|
23119
23263
|
const { branch, prTitle } = flags;
|
|
23120
23264
|
const hooksDir = join28(stateDir, "hooks");
|
|
23265
|
+
const pnpmStores = new Map;
|
|
23121
23266
|
const permissionMark = (name) => join28(hooksDir, `${name}.permission.json`);
|
|
23122
23267
|
const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
|
|
23123
23268
|
return {
|
|
@@ -23141,7 +23286,7 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
23141
23286
|
...flags.strictMcp ? { strictMcp: true } : {},
|
|
23142
23287
|
...flags.sandbox ? {
|
|
23143
23288
|
sandbox: true,
|
|
23144
|
-
writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
|
|
23289
|
+
writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow, readOnly) => {
|
|
23145
23290
|
const gitCommonDir = gitCommonDirOf2(exec, cwd);
|
|
23146
23291
|
const dir = join28(stateDir, "sandbox");
|
|
23147
23292
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
@@ -23153,6 +23298,12 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
23153
23298
|
walls.permissions.allow = [
|
|
23154
23299
|
...new Set([...walls.permissions.allow, ...allow ?? []])
|
|
23155
23300
|
];
|
|
23301
|
+
walls.permissions.deny = [
|
|
23302
|
+
...new Set([
|
|
23303
|
+
...walls.permissions.deny,
|
|
23304
|
+
...readOnlyDenyRules(readOnlyDirs(readOnly ?? [], cwd, [gitCommonDir]))
|
|
23305
|
+
])
|
|
23306
|
+
];
|
|
23156
23307
|
const settings = withHook(name, { ...walls });
|
|
23157
23308
|
writeFileSync20(p, `${JSON.stringify(settings, null, 2)}
|
|
23158
23309
|
`, { mode: 384 });
|
|
@@ -23160,23 +23311,22 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
23160
23311
|
return { settingsFile: p, gitCommonDir };
|
|
23161
23312
|
})
|
|
23162
23313
|
} : {},
|
|
23163
|
-
writeHookSettings: (name, allow) => {
|
|
23314
|
+
writeHookSettings: (name, allow, readOnly) => {
|
|
23164
23315
|
mkdirSync21(hooksDir, { recursive: true, mode: 448 });
|
|
23165
23316
|
const p = join28(hooksDir, `${name}.json`);
|
|
23166
|
-
const
|
|
23317
|
+
const deny = readOnlyDenyRules(readOnly ?? []);
|
|
23318
|
+
const permissions = {
|
|
23319
|
+
...allow?.length ? { allow: [...allow] } : {},
|
|
23320
|
+
...deny.length ? { deny } : {}
|
|
23321
|
+
};
|
|
23322
|
+
const base = Object.keys(permissions).length ? { permissions } : {};
|
|
23167
23323
|
writeFileSync20(p, `${JSON.stringify(withHook(name, base), null, 2)}
|
|
23168
23324
|
`, { mode: 384 });
|
|
23169
23325
|
chmodSync6(p, 384);
|
|
23170
23326
|
return p;
|
|
23171
23327
|
},
|
|
23172
23328
|
permissionMark,
|
|
23173
|
-
|
|
23174
|
-
try {
|
|
23175
|
-
return mainCheckoutOf(gitCommonDirOf2(exec, cwd), cwd);
|
|
23176
|
-
} catch {
|
|
23177
|
-
return null;
|
|
23178
|
-
}
|
|
23179
|
-
}),
|
|
23329
|
+
readDirsOf: o.readDirsOf ?? ((dir) => engineReadDirs2(exec, dir, exists, pnpmStores)),
|
|
23180
23330
|
...branch ? { branchOf: (claim) => branchFor(branch, claim) } : {},
|
|
23181
23331
|
...prTitle ? { prTitleOf: (claim) => prTitleFor(prTitle, claim) } : {},
|
|
23182
23332
|
now: o.now ?? Date.now,
|
|
@@ -23278,6 +23428,52 @@ function gitCommonDirOf2(exec, cwd) {
|
|
|
23278
23428
|
throw new Error(`git has no common dir for ${cwd}, so the sandbox has nowhere to commit`);
|
|
23279
23429
|
return resolve11(cwd, dir);
|
|
23280
23430
|
}
|
|
23431
|
+
function worktreeListPaths2(porcelain) {
|
|
23432
|
+
return porcelain.split(/\n\s*\n/).map((block) => block.split(`
|
|
23433
|
+
`).map((l) => l.trim())).filter((lines) => !lines.some((l) => l === "bare" || l.startsWith("prunable"))).flatMap((lines) => {
|
|
23434
|
+
const wt = lines.find((l) => l.startsWith("worktree "));
|
|
23435
|
+
return wt ? [wt.slice("worktree ".length)] : [];
|
|
23436
|
+
});
|
|
23437
|
+
}
|
|
23438
|
+
var PNPM_STORE_TIMEOUT_MS2 = 1e4;
|
|
23439
|
+
function engineReadDirs2(exec, cwd, exists, stores) {
|
|
23440
|
+
let common = null;
|
|
23441
|
+
try {
|
|
23442
|
+
common = gitCommonDirOf2(exec, cwd);
|
|
23443
|
+
} catch {}
|
|
23444
|
+
const worktrees = (() => {
|
|
23445
|
+
try {
|
|
23446
|
+
const r = exec("git", ["-C", cwd, "worktree", "list", "--porcelain"]);
|
|
23447
|
+
return r.status === 0 ? worktreeListPaths2(r.stdout) : [];
|
|
23448
|
+
} catch {
|
|
23449
|
+
return [];
|
|
23450
|
+
}
|
|
23451
|
+
})();
|
|
23452
|
+
const pnpmStore = (() => {
|
|
23453
|
+
try {
|
|
23454
|
+
if (!exists(join28(cwd, "pnpm-lock.yaml")))
|
|
23455
|
+
return null;
|
|
23456
|
+
const key = common ?? cwd;
|
|
23457
|
+
const known = stores.get(key);
|
|
23458
|
+
if (known)
|
|
23459
|
+
return known;
|
|
23460
|
+
const r = exec("pnpm", ["store", "path"], { cwd, timeoutMs: PNPM_STORE_TIMEOUT_MS2 });
|
|
23461
|
+
const dir = r.status === 0 ? r.stdout.split(`
|
|
23462
|
+
`).map((l) => l.trim()).filter((l) => l.startsWith("/")).pop() : undefined;
|
|
23463
|
+
if (dir)
|
|
23464
|
+
stores.set(key, dir);
|
|
23465
|
+
return dir ?? null;
|
|
23466
|
+
} catch {
|
|
23467
|
+
return null;
|
|
23468
|
+
}
|
|
23469
|
+
})();
|
|
23470
|
+
return sessionReadDirs({
|
|
23471
|
+
mainCheckout: common ? mainCheckoutOf(common, cwd) : null,
|
|
23472
|
+
worktrees,
|
|
23473
|
+
pnpmStore,
|
|
23474
|
+
cwd
|
|
23475
|
+
});
|
|
23476
|
+
}
|
|
23281
23477
|
function sandboxRefusal(flags) {
|
|
23282
23478
|
if (flags.lentBy && !flags.sandbox)
|
|
23283
23479
|
return LENT_NEEDS_SANDBOX2;
|
|
@@ -23361,7 +23557,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
23361
23557
|
runner: deps.runner.name,
|
|
23362
23558
|
atOnce: flags.atOnce,
|
|
23363
23559
|
interval: flags.interval,
|
|
23364
|
-
cliVersion: "0.1.
|
|
23560
|
+
cliVersion: "0.1.70"
|
|
23365
23561
|
};
|
|
23366
23562
|
const beat = (checkedAt) => {
|
|
23367
23563
|
const m = deps.machine;
|
|
@@ -24582,7 +24778,8 @@ function engineStatus(i) {
|
|
|
24582
24778
|
...opt("leaseUntil", iso2(r.leaseUntil)),
|
|
24583
24779
|
...opt("runId", r.runId),
|
|
24584
24780
|
...opt("parked", r.parked?.question),
|
|
24585
|
-
...opt("answerer", answererOf(r))
|
|
24781
|
+
...opt("answerer", answererOf(r)),
|
|
24782
|
+
...opt("atPrompt", r.atPrompt ? { since: iso2(r.atPrompt.since) ?? new Date(0).toISOString(), text: r.atPrompt.text } : undefined)
|
|
24586
24783
|
});
|
|
24587
24784
|
}
|
|
24588
24785
|
return {
|
|
@@ -24639,7 +24836,7 @@ function statusLines(s, now) {
|
|
|
24639
24836
|
}
|
|
24640
24837
|
lines.push(`running ${s.running.length}`);
|
|
24641
24838
|
for (const r of s.running)
|
|
24642
|
-
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" : `${r.kind === "mock" ? "drawing a mock · " : ""}${ago(r.startedAt)}`} · watch: ${r.watch}`);
|
|
24839
|
+
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" : r.atPrompt ? `at a prompt · ${ago(r.atPrompt.since)}` : `${r.kind === "mock" ? "drawing a mock · " : ""}${ago(r.startedAt)}`} · watch: ${r.watch}`);
|
|
24643
24840
|
lines.push(`following ${s.following.length}`);
|
|
24644
24841
|
for (const f of s.following) {
|
|
24645
24842
|
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" : f.autoMerge ? " · merge when ready" : ""}`);
|
|
@@ -25472,7 +25669,7 @@ function contextFor(deps) {
|
|
|
25472
25669
|
...src,
|
|
25473
25670
|
fetchFn: deps.fetchFn,
|
|
25474
25671
|
timeoutMs: deps.timeoutMs,
|
|
25475
|
-
version: "0.1.
|
|
25672
|
+
version: "0.1.70"
|
|
25476
25673
|
}), deps.home, now) : null;
|
|
25477
25674
|
return {
|
|
25478
25675
|
channel: "code",
|
|
@@ -30288,16 +30485,20 @@ function readOrgInfo(json) {
|
|
|
30288
30485
|
const org = isObj7(json.org) ? str16(json.org.slug) : str16(json.org);
|
|
30289
30486
|
if (!org)
|
|
30290
30487
|
return "no org";
|
|
30291
|
-
const
|
|
30292
|
-
for (const e of Array.isArray(json.
|
|
30488
|
+
const bySlug = new Map;
|
|
30489
|
+
for (const e of Array.isArray(json.envs) ? json.envs : []) {
|
|
30293
30490
|
if (!isObj7(e) || !str16(e.slug))
|
|
30294
30491
|
continue;
|
|
30295
|
-
const
|
|
30492
|
+
const slug = str16(e.slug).toLowerCase();
|
|
30493
|
+
const env = bySlug.get(slug) ?? { slug, production: false };
|
|
30494
|
+
if (e.production === true)
|
|
30495
|
+
env.production = true;
|
|
30296
30496
|
const ld = str16(e.launchDarklyEnv);
|
|
30297
|
-
if (ld)
|
|
30497
|
+
if (ld && !env.launchDarklyEnv)
|
|
30298
30498
|
env.launchDarklyEnv = ld;
|
|
30299
|
-
|
|
30499
|
+
bySlug.set(slug, env);
|
|
30300
30500
|
}
|
|
30501
|
+
const environments = [...bySlug.values()];
|
|
30301
30502
|
const strings = (v) => Array.isArray(v) ? v.map((x) => str16(x)).filter(Boolean) : [];
|
|
30302
30503
|
return {
|
|
30303
30504
|
org,
|
|
@@ -30337,17 +30538,28 @@ function pickLdProject(given, info) {
|
|
|
30337
30538
|
};
|
|
30338
30539
|
}
|
|
30339
30540
|
var num9 = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
30340
|
-
|
|
30341
|
-
const c = { inserted: 0, existing: 0, skipped: 0 };
|
|
30541
|
+
function countsOf(json) {
|
|
30542
|
+
const c = { inserted: 0, existing: 0, skipped: 0, pulls: 0, skips: [] };
|
|
30342
30543
|
if (!isObj7(json))
|
|
30343
30544
|
return c;
|
|
30344
|
-
const
|
|
30345
|
-
|
|
30346
|
-
|
|
30347
|
-
|
|
30348
|
-
|
|
30545
|
+
const rows = (v) => isObj7(v) ? num9(v.deploys) + num9(v.flags) : num9(v);
|
|
30546
|
+
c.inserted = rows(json.inserted);
|
|
30547
|
+
c.existing = rows(json.existing);
|
|
30548
|
+
c.skipped = rows(json.skipped);
|
|
30549
|
+
c.pulls = isObj7(json.inserted) ? num9(json.inserted.pulls) : num9(json.pulls);
|
|
30550
|
+
for (const s of Array.isArray(json.skips) ? json.skips : []) {
|
|
30551
|
+
const w = isObj7(s) ? str16(s.why) : "";
|
|
30552
|
+
const count = isObj7(s) ? num9(s.count) : 0;
|
|
30553
|
+
if (w && count > 0)
|
|
30554
|
+
c.skips.push({ why: w, count });
|
|
30349
30555
|
}
|
|
30350
30556
|
return c;
|
|
30557
|
+
}
|
|
30558
|
+
var mergeSkips = (...lists) => {
|
|
30559
|
+
const by = new Map;
|
|
30560
|
+
for (const s of lists.flat())
|
|
30561
|
+
by.set(s.why, (by.get(s.why) ?? 0) + s.count);
|
|
30562
|
+
return [...by.entries()].map(([w, count]) => ({ why: w, count })).sort((a, b) => b.count - a.count);
|
|
30351
30563
|
};
|
|
30352
30564
|
var why3 = (json, status) => isObj7(json) && typeof json.error === "string" ? json.error : `HTTP ${status}`;
|
|
30353
30565
|
async function importSleuth(o) {
|
|
@@ -30506,7 +30718,9 @@ async function importSleuth(o) {
|
|
|
30506
30718
|
posted: 0,
|
|
30507
30719
|
inserted: 0,
|
|
30508
30720
|
existing: 0,
|
|
30509
|
-
skipped
|
|
30721
|
+
skipped,
|
|
30722
|
+
prs: 0,
|
|
30723
|
+
serverSkips: []
|
|
30510
30724
|
};
|
|
30511
30725
|
o.onMapping?.(result);
|
|
30512
30726
|
for (let b = 0;b < result.batches; b++) {
|
|
@@ -30531,6 +30745,8 @@ async function importSleuth(o) {
|
|
|
30531
30745
|
result.inserted += n.inserted;
|
|
30532
30746
|
result.existing += n.existing;
|
|
30533
30747
|
result.skipped += n.skipped;
|
|
30748
|
+
result.prs += n.pulls;
|
|
30749
|
+
result.serverSkips = mergeSkips(result.serverSkips, n.skips);
|
|
30534
30750
|
if ((b + 1) % 10 === 0 || b + 1 === result.batches)
|
|
30535
30751
|
log(` ${at} · ${result.posted} rows sent`);
|
|
30536
30752
|
}
|
|
@@ -30555,6 +30771,18 @@ function historyLine(r) {
|
|
|
30555
30771
|
return ` PR history: ${missing} merged PRs without a first commit — SLEDS is reading them from GitHub, paced; lead time fills in as it goes`;
|
|
30556
30772
|
return missing ? ` PR history: ${missing} merged PRs without a first commit — not reading them: connect GitHub (Settings › Integrations), then re-run` : " PR history: every merged PR has its first commit";
|
|
30557
30773
|
}
|
|
30774
|
+
function summaryLines(r) {
|
|
30775
|
+
const tail = `already there ${r.existing}, skipped ${r.skipped}`;
|
|
30776
|
+
const out = [
|
|
30777
|
+
r.dryRun ? ` would write ~${r.inserted}, ${tail} · ~${r.prs} PRs — run again without --dry-run to write` : ` wrote ${r.inserted}, ${tail} · ${r.prs} PRs`
|
|
30778
|
+
];
|
|
30779
|
+
if (r.serverSkips.length) {
|
|
30780
|
+
out.push("", " server skipped, and why:");
|
|
30781
|
+
for (const s of r.serverSkips)
|
|
30782
|
+
out.push(` ${String(s.count).padStart(6)} ${s.why}`);
|
|
30783
|
+
}
|
|
30784
|
+
return out;
|
|
30785
|
+
}
|
|
30558
30786
|
function mappingTable(r) {
|
|
30559
30787
|
const head = [
|
|
30560
30788
|
"Sleuth deployment",
|
|
@@ -31162,7 +31390,8 @@ var importCmd = async (o, { words, flags, all }) => {
|
|
|
31162
31390
|
log(JSON.stringify(result));
|
|
31163
31391
|
return code;
|
|
31164
31392
|
}
|
|
31165
|
-
|
|
31393
|
+
for (const l of summaryLines(result))
|
|
31394
|
+
log(l);
|
|
31166
31395
|
const history = historyLine(result);
|
|
31167
31396
|
if (history)
|
|
31168
31397
|
(result.historyError ? error : log)(history);
|
|
@@ -32040,7 +32269,7 @@ var realPidAlive4 = (pid) => {
|
|
|
32040
32269
|
};
|
|
32041
32270
|
function machineClient(home, env) {
|
|
32042
32271
|
const src = meterSource(home, undefined, { env });
|
|
32043
|
-
return src ? fetchClient({ ...src, version: "0.1.
|
|
32272
|
+
return src ? fetchClient({ ...src, version: "0.1.70" }) : null;
|
|
32044
32273
|
}
|
|
32045
32274
|
async function noteAnswer2(home, a, now) {
|
|
32046
32275
|
try {
|
|
@@ -32991,7 +33220,7 @@ var main = async (argv) => {
|
|
|
32991
33220
|
now: Date.now(),
|
|
32992
33221
|
stderr: (line) => console.error(line),
|
|
32993
33222
|
isTTY: !!process.stderr.isTTY,
|
|
32994
|
-
version: "0.1.
|
|
33223
|
+
version: "0.1.70"
|
|
32995
33224
|
});
|
|
32996
33225
|
switch (cmd) {
|
|
32997
33226
|
case "update":
|
|
@@ -33255,7 +33484,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
33255
33484
|
case "version":
|
|
33256
33485
|
case "--version":
|
|
33257
33486
|
case "-v":
|
|
33258
|
-
console.log("sleds 0.1.
|
|
33487
|
+
console.log("sleds 0.1.70");
|
|
33259
33488
|
return 0;
|
|
33260
33489
|
default:
|
|
33261
33490
|
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.70",
|
|
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",
|