@sleds/cli 0.1.50 → 0.1.52
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 +492 -65
- package/package.json +1 -1
package/dist/sleds.mjs
CHANGED
|
@@ -769,6 +769,14 @@ var init_verbs = __esm(() => {
|
|
|
769
769
|
app: "Work › Moving (the runs on each sled) · Record › Receipts once they land",
|
|
770
770
|
how: "Newest first: id, status, route, cost. Hand-offs meant for you are listed first."
|
|
771
771
|
},
|
|
772
|
+
{
|
|
773
|
+
id: "metrics",
|
|
774
|
+
group: "meter",
|
|
775
|
+
want: "See how a workspace or the whole org ships — DORA and batch size for a period",
|
|
776
|
+
mcp: "metrics {workspace?, range?, from?, to?} — range 2w · 1m · 3m · 6m · 1y, or from/to days",
|
|
777
|
+
app: "Metrics",
|
|
778
|
+
how: "Deploy frequency, lead time, change failure rate, time to recover and production deploys by batch size, each against the same length just before. A workspace gives one line; no workspace gives the org, one line per workspace you see."
|
|
779
|
+
},
|
|
772
780
|
{
|
|
773
781
|
id: "status",
|
|
774
782
|
group: "meter",
|
|
@@ -1616,6 +1624,128 @@ var init_format = __esm(() => {
|
|
|
1616
1624
|
OFFLINE_LINE = `${PREFIX}offline`;
|
|
1617
1625
|
});
|
|
1618
1626
|
|
|
1627
|
+
// ../../packages/shared/src/item/outcome.ts
|
|
1628
|
+
var OUTCOME_WINDOW_DAYS = 14, OUTCOME_WINDOW_MS;
|
|
1629
|
+
var init_outcome = __esm(() => {
|
|
1630
|
+
OUTCOME_WINDOW_MS = OUTCOME_WINDOW_DAYS * 86400000;
|
|
1631
|
+
});
|
|
1632
|
+
|
|
1633
|
+
// ../../packages/shared/src/deploys/metrics.ts
|
|
1634
|
+
var WEEK_MS;
|
|
1635
|
+
var init_metrics = __esm(() => {
|
|
1636
|
+
WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
|
1637
|
+
});
|
|
1638
|
+
|
|
1639
|
+
// ../../packages/shared/src/deploys/batchSize.ts
|
|
1640
|
+
var TIERS;
|
|
1641
|
+
var init_batchSize = __esm(() => {
|
|
1642
|
+
init_outcome();
|
|
1643
|
+
init_metrics();
|
|
1644
|
+
TIERS = ["S", "M", "L", "G"];
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
// ../../packages/shared/src/deploys/period.ts
|
|
1648
|
+
function periodChange(cur, prev, better) {
|
|
1649
|
+
if (cur == null || prev == null)
|
|
1650
|
+
return { pct: null, dir: "flat", tone: "neutral" };
|
|
1651
|
+
if (prev === 0)
|
|
1652
|
+
return { pct: null, dir: cur > 0 ? "up" : cur < 0 ? "down" : "flat", tone: "neutral" };
|
|
1653
|
+
const pct = (cur - prev) / Math.abs(prev) * 100;
|
|
1654
|
+
if (Math.abs(pct) < FLAT_PCT)
|
|
1655
|
+
return { pct, dir: "flat", tone: "neutral" };
|
|
1656
|
+
const dir = pct > 0 ? "up" : "down";
|
|
1657
|
+
return { pct, dir, tone: dir === better ? "success" : "error" };
|
|
1658
|
+
}
|
|
1659
|
+
var DAY_MS2, FLAT_PCT = 0.5;
|
|
1660
|
+
var init_period = __esm(() => {
|
|
1661
|
+
DAY_MS2 = 24 * 60 * 60 * 1000;
|
|
1662
|
+
});
|
|
1663
|
+
|
|
1664
|
+
// ../../packages/shared/src/deploys/report.ts
|
|
1665
|
+
function duration(ms) {
|
|
1666
|
+
const min = ms / 60000;
|
|
1667
|
+
if (min < 60)
|
|
1668
|
+
return `${Math.round(min)}m`;
|
|
1669
|
+
const hours = min / 60;
|
|
1670
|
+
if (hours < 48)
|
|
1671
|
+
return `${hours.toFixed(1)}h`;
|
|
1672
|
+
return `${(hours / 24).toFixed(1)}d`;
|
|
1673
|
+
}
|
|
1674
|
+
function change(pair, better) {
|
|
1675
|
+
const { current, previous } = pair;
|
|
1676
|
+
if (current == null)
|
|
1677
|
+
return "";
|
|
1678
|
+
if (previous == null)
|
|
1679
|
+
return " (none before)";
|
|
1680
|
+
const c = periodChange(current, previous, better);
|
|
1681
|
+
if (c.dir === "flat")
|
|
1682
|
+
return " (flat)";
|
|
1683
|
+
if (c.pct == null)
|
|
1684
|
+
return " (none before)";
|
|
1685
|
+
return ` (${c.pct > 0 ? "+" : "−"}${Math.round(Math.abs(c.pct))}%)`;
|
|
1686
|
+
}
|
|
1687
|
+
function timeFigure(label, pair) {
|
|
1688
|
+
if (pair.current == null)
|
|
1689
|
+
return `${label} none`;
|
|
1690
|
+
return `${label} ${duration(pair.current)}${change(pair, "down")}`;
|
|
1691
|
+
}
|
|
1692
|
+
function rateFigure(pair) {
|
|
1693
|
+
const { current, previous } = pair;
|
|
1694
|
+
if (current == null)
|
|
1695
|
+
return "failure rate none";
|
|
1696
|
+
const pct = Math.round(current * 100);
|
|
1697
|
+
if (previous == null)
|
|
1698
|
+
return `failure rate ${pct}% (none before)`;
|
|
1699
|
+
const pts = pct - Math.round(previous * 100);
|
|
1700
|
+
return `failure rate ${pct}% (${pts === 0 ? "flat" : `${pts > 0 ? "+" : "−"}${Math.abs(pts)} pts`})`;
|
|
1701
|
+
}
|
|
1702
|
+
function batchFigure(pair) {
|
|
1703
|
+
if (total(pair.current) === 0)
|
|
1704
|
+
return "batch none";
|
|
1705
|
+
const before = total(pair.previous) === 0 ? "none before" : `was ${tiers(pair.previous)}`;
|
|
1706
|
+
return `batch ${tiers(pair.current)} (${before})`;
|
|
1707
|
+
}
|
|
1708
|
+
function lineText(l) {
|
|
1709
|
+
const head = `${l.name} (${l.slug})`;
|
|
1710
|
+
if (l.production == null)
|
|
1711
|
+
return `${head} · no production environment set, so no deploy metrics`;
|
|
1712
|
+
const deploys = `${l.deploys.current} deploy${l.deploys.current === 1 ? "" : "s"}${change(l.deploys, "up")}`;
|
|
1713
|
+
return [
|
|
1714
|
+
`${head} · ${l.production}: ${deploys}`,
|
|
1715
|
+
timeFigure("lead time", l.leadTime),
|
|
1716
|
+
rateFigure(l.failRate),
|
|
1717
|
+
timeFigure("time to recover", l.recover),
|
|
1718
|
+
batchFigure(l.batch)
|
|
1719
|
+
].join(" · ");
|
|
1720
|
+
}
|
|
1721
|
+
function metricsText(r) {
|
|
1722
|
+
const sameYear = r.from.slice(0, 4) === r.to.slice(0, 4);
|
|
1723
|
+
const span = `${dayLabel(r.from, !sameYear)} – ${dayLabel(r.to, true)}`;
|
|
1724
|
+
const days = `${r.days} day${r.days === 1 ? "" : "s"}`;
|
|
1725
|
+
const header = `${r.scope === "org" ? "Org" : "Workspace"} · ${span} (${days}), against the ${days} before`;
|
|
1726
|
+
const lines = r.lines.length ? r.lines.map(lineText) : [r.scope === "org" ? "No workspaces in this org." : "No workspace."];
|
|
1727
|
+
return [header, ...lines].join(`
|
|
1728
|
+
`);
|
|
1729
|
+
}
|
|
1730
|
+
var DAY_MS3, METRICS_RANGES, tiers = (c) => TIERS.map((t) => `${t}${c[t]}`).join(" "), total = (c) => TIERS.reduce((n, t) => n + c[t], 0), dayLabel = (day, year) => new Date(`${day}T00:00:00Z`).toLocaleDateString("en-US", {
|
|
1731
|
+
month: "short",
|
|
1732
|
+
day: "numeric",
|
|
1733
|
+
...year ? { year: "numeric" } : {},
|
|
1734
|
+
timeZone: "UTC"
|
|
1735
|
+
});
|
|
1736
|
+
var init_report = __esm(() => {
|
|
1737
|
+
init_batchSize();
|
|
1738
|
+
init_period();
|
|
1739
|
+
DAY_MS3 = 24 * 60 * 60 * 1000;
|
|
1740
|
+
METRICS_RANGES = [
|
|
1741
|
+
{ key: "2w", days: 14 },
|
|
1742
|
+
{ key: "1m", days: 30 },
|
|
1743
|
+
{ key: "3m", days: 91 },
|
|
1744
|
+
{ key: "6m", days: 182 },
|
|
1745
|
+
{ key: "1y", days: 365 }
|
|
1746
|
+
];
|
|
1747
|
+
});
|
|
1748
|
+
|
|
1619
1749
|
// ../../packages/shared/src/guidance/model.ts
|
|
1620
1750
|
var CARD_FIELDS;
|
|
1621
1751
|
var init_model = __esm(() => {
|
|
@@ -2120,7 +2250,7 @@ var read = (title) => ({
|
|
|
2120
2250
|
destructiveHint: false,
|
|
2121
2251
|
idempotentHint: idempotent,
|
|
2122
2252
|
openWorldHint: false
|
|
2123
|
-
}),
|
|
2253
|
+
}), change2 = (title, idempotent = false) => ({
|
|
2124
2254
|
title,
|
|
2125
2255
|
readOnlyHint: false,
|
|
2126
2256
|
destructiveHint: true,
|
|
@@ -2130,6 +2260,7 @@ var read = (title) => ({
|
|
|
2130
2260
|
var init_annotations = __esm(() => {
|
|
2131
2261
|
TOOL_ANNOTATIONS = {
|
|
2132
2262
|
usage: read("Seat usage"),
|
|
2263
|
+
metrics: read("Delivery metrics"),
|
|
2133
2264
|
jobs: read("Overnight jobs"),
|
|
2134
2265
|
status: read("Where is it"),
|
|
2135
2266
|
touches: read("What it touches"),
|
|
@@ -2158,9 +2289,9 @@ var init_annotations = __esm(() => {
|
|
|
2158
2289
|
buddy: add("Pair with a buddy"),
|
|
2159
2290
|
pickup: add("Pick up a hand-off"),
|
|
2160
2291
|
reopen: add("Reopen an item", true),
|
|
2161
|
-
update:
|
|
2162
|
-
archive:
|
|
2163
|
-
withdraw:
|
|
2292
|
+
update: change2("Change an item", true),
|
|
2293
|
+
archive: change2("Archive an item", true),
|
|
2294
|
+
withdraw: change2("Withdraw a hand-off", true)
|
|
2164
2295
|
};
|
|
2165
2296
|
});
|
|
2166
2297
|
|
|
@@ -2421,19 +2552,23 @@ var init_plan2 = __esm(() => {
|
|
|
2421
2552
|
});
|
|
2422
2553
|
|
|
2423
2554
|
// ../../packages/shared/src/mcp/sled.ts
|
|
2424
|
-
function section(label, rows, now) {
|
|
2555
|
+
function section(label, rows, now, count = rows.length) {
|
|
2425
2556
|
if (rows.length === 0)
|
|
2426
2557
|
return null;
|
|
2427
|
-
|
|
2558
|
+
const total = Math.max(count, rows.length);
|
|
2559
|
+
const more = total > rows.length ? `
|
|
2560
|
+
|
|
2561
|
+
…and ${total - rows.length} more` : "";
|
|
2562
|
+
return `${label} (${total}):
|
|
2428
2563
|
|
|
2429
2564
|
${rows.map((r) => statusLine(r, now)).join(`
|
|
2430
2565
|
|
|
2431
|
-
`)}`;
|
|
2566
|
+
`)}${more}`;
|
|
2432
2567
|
}
|
|
2433
2568
|
function sledText(s, now) {
|
|
2434
2569
|
const parts = [
|
|
2435
2570
|
section("On your sled", s.mine, now),
|
|
2436
|
-
section("Proposed to you", s.proposed, now),
|
|
2571
|
+
section("Proposed to you", s.proposed, now, s.proposedCount),
|
|
2437
2572
|
section("Sent to you", s.sent, now)
|
|
2438
2573
|
].filter((p) => p !== null);
|
|
2439
2574
|
if (parts.length === 0)
|
|
@@ -2706,6 +2841,60 @@ async function usageTool(ctx) {
|
|
|
2706
2841
|
return { text: formatMeter(m, (ctx.now ?? Date.now)()).join(`
|
|
2707
2842
|
`) };
|
|
2708
2843
|
}
|
|
2844
|
+
function asMetricsReport(j) {
|
|
2845
|
+
if (!j || j.scope !== "workspace" && j.scope !== "org")
|
|
2846
|
+
return null;
|
|
2847
|
+
if (typeof j.from !== "string" || typeof j.to !== "string" || num3(j.days) === undefined)
|
|
2848
|
+
return null;
|
|
2849
|
+
if (!Array.isArray(j.lines) || !j.lines.every(isObject4))
|
|
2850
|
+
return null;
|
|
2851
|
+
return j;
|
|
2852
|
+
}
|
|
2853
|
+
async function metricsTool(ctx, args) {
|
|
2854
|
+
if (!ctx.client)
|
|
2855
|
+
return NOT_SET_UP;
|
|
2856
|
+
const qs = new URLSearchParams;
|
|
2857
|
+
for (const k of ["workspace", "range", "from", "to"]) {
|
|
2858
|
+
const v = str5(args[k])?.trim();
|
|
2859
|
+
if (v)
|
|
2860
|
+
qs.set(k, v);
|
|
2861
|
+
}
|
|
2862
|
+
const query = qs.toString();
|
|
2863
|
+
const path = query ? `/proxy/metrics?${query}` : "/proxy/metrics";
|
|
2864
|
+
const noReport = { text: "SLEDS answered without a metrics report.", isError: true };
|
|
2865
|
+
if (!ctx.client.getFull) {
|
|
2866
|
+
const j = await ctx.client.get(path);
|
|
2867
|
+
if (!j)
|
|
2868
|
+
return UNREACHABLE;
|
|
2869
|
+
const report = asMetricsReport(j);
|
|
2870
|
+
return report ? { text: metricsText(report) } : noReport;
|
|
2871
|
+
}
|
|
2872
|
+
const r = await ctx.client.getFull(path);
|
|
2873
|
+
if ("error" in r)
|
|
2874
|
+
return {
|
|
2875
|
+
text: `Control plane unreachable: ${r.error} → try again in a moment.`,
|
|
2876
|
+
isError: true
|
|
2877
|
+
};
|
|
2878
|
+
const why = errorMessage(r.json);
|
|
2879
|
+
if (r.status === 200) {
|
|
2880
|
+
const report = asMetricsReport(r.json);
|
|
2881
|
+
return report ? { text: metricsText(report) } : noReport;
|
|
2882
|
+
}
|
|
2883
|
+
const workspace = qs.get("workspace");
|
|
2884
|
+
if (r.status === 404)
|
|
2885
|
+
return {
|
|
2886
|
+
text: workspace ? `No workspace "${workspace}" that this seat sees. Leave workspace out for the whole org, one line per workspace.` : `${why ?? "Not found"} (HTTP 404).`,
|
|
2887
|
+
isError: true
|
|
2888
|
+
};
|
|
2889
|
+
if (r.status === 400)
|
|
2890
|
+
return { text: why ?? "Bad request (HTTP 400).", isError: true };
|
|
2891
|
+
if (r.status >= 500)
|
|
2892
|
+
return {
|
|
2893
|
+
text: `${why ?? "Control plane unreachable"} (HTTP ${r.status}) → try once more in a moment, then move on and say so.`,
|
|
2894
|
+
isError: true
|
|
2895
|
+
};
|
|
2896
|
+
return { text: `${why ?? "SLEDS refused it"} (HTTP ${r.status}).`, isError: true };
|
|
2897
|
+
}
|
|
2709
2898
|
function bandLine(band) {
|
|
2710
2899
|
if (!isObject4(band))
|
|
2711
2900
|
return null;
|
|
@@ -3328,7 +3517,12 @@ async function sledTool(ctx, args) {
|
|
|
3328
3517
|
return UNREACHABLE;
|
|
3329
3518
|
const rows = (k) => Array.isArray(r[k]) ? r[k].filter(isObject4) : [];
|
|
3330
3519
|
return {
|
|
3331
|
-
text: sledText({
|
|
3520
|
+
text: sledText({
|
|
3521
|
+
mine: rows("mine"),
|
|
3522
|
+
proposed: rows("proposed"),
|
|
3523
|
+
...typeof r.proposedCount === "number" ? { proposedCount: r.proposedCount } : {},
|
|
3524
|
+
sent: rows("sent")
|
|
3525
|
+
}, (ctx.now ?? Date.now)())
|
|
3332
3526
|
};
|
|
3333
3527
|
}
|
|
3334
3528
|
function checkWarningsOf(ctx, drafts) {
|
|
@@ -4300,6 +4494,8 @@ async function callTool(name, args, ctx) {
|
|
|
4300
4494
|
switch (name) {
|
|
4301
4495
|
case "usage":
|
|
4302
4496
|
return usageTool(ctx);
|
|
4497
|
+
case "metrics":
|
|
4498
|
+
return metricsTool(ctx, args);
|
|
4303
4499
|
case "estimate":
|
|
4304
4500
|
return estimateTool(ctx, args);
|
|
4305
4501
|
case "intake":
|
|
@@ -4439,6 +4635,7 @@ async function handleLine(line, ctx) {
|
|
|
4439
4635
|
}
|
|
4440
4636
|
var PROTOCOL_VERSION = "2025-06-18", SERVER_INFO, SERVER_INSTRUCTIONS, MCP_TIMEOUT_MS = 5000, sourceSchema, specSchema, TOOLS, VIEW_TOOLS, NOT_SET_UP, UNREACHABLE, isObject4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, str5 = (v) => typeof v === "string" ? v : undefined, errorMessage = (j) => isObject4(j?.error) ? str5(j.error.message) : str5(j?.error), proposalText = (t) => (t ?? "").replace(/\n*Nothing runs until a person says yes:[^\n]*$/, ""), PROPOSED_NEXT = (key) => `Nothing runs until a person approves it: Approve in the SLEDS app or on the item page, or \`sleds route approve ${key}\`. If you are a planning session, stop here.`, strList = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : undefined, RELATION_HOWS, UI_RESOURCES, response = (id, result) => JSON.stringify({ jsonrpc: "2.0", id, result }), errorResponse = (id, code, message) => JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
|
|
4441
4637
|
var init_server = __esm(() => {
|
|
4638
|
+
init_report();
|
|
4442
4639
|
init_worth();
|
|
4443
4640
|
init_intake();
|
|
4444
4641
|
init_model();
|
|
@@ -4506,6 +4703,32 @@ var init_server = __esm(() => {
|
|
|
4506
4703
|
description: "The SLEDS meter for this seat: built today, month against the ceiling, window and reset, allowance, queued/running/delivered jobs, the last wall, and the seat's own Pro/Max limit bars.",
|
|
4507
4704
|
inputSchema: { type: "object", properties: {} }
|
|
4508
4705
|
},
|
|
4706
|
+
{
|
|
4707
|
+
name: "metrics",
|
|
4708
|
+
description: "DORA and batch-size metrics for a period, against the same length just before it: deploy frequency, lead time, change failure rate, time to recover and production deploys by batch size. For one workspace, or — with no `workspace` — the whole org, one line per workspace. Only the workspaces this seat sees. The same days the Metrics page counts.",
|
|
4709
|
+
inputSchema: {
|
|
4710
|
+
type: "object",
|
|
4711
|
+
properties: {
|
|
4712
|
+
workspace: {
|
|
4713
|
+
type: "string",
|
|
4714
|
+
description: "The workspace's slug. Leave it out for the whole org."
|
|
4715
|
+
},
|
|
4716
|
+
range: {
|
|
4717
|
+
type: "string",
|
|
4718
|
+
enum: METRICS_RANGES.map((r) => r.key),
|
|
4719
|
+
description: "A preset period ending today; default 2w. Leave it out when giving from."
|
|
4720
|
+
},
|
|
4721
|
+
from: {
|
|
4722
|
+
type: "string",
|
|
4723
|
+
description: "First day of a custom period, YYYY-MM-DD (UTC). At most 366 days."
|
|
4724
|
+
},
|
|
4725
|
+
to: {
|
|
4726
|
+
type: "string",
|
|
4727
|
+
description: "Last day of a custom period, YYYY-MM-DD, included; default today."
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
},
|
|
4509
4732
|
{
|
|
4510
4733
|
name: "estimate",
|
|
4511
4734
|
description: "Call this BEFORE starting any build that will take more than a few minutes — before the first line of work, not after. Sizes the task: the org estimator's cost and time band with confidence and a spend cap, never a point figure. Pass a stable `source` (kind · project · doc · item) so the item has a home on the sled and the later `actual` finds it. Recorded, so actuals calibrate the next estimate.",
|
|
@@ -5443,12 +5666,6 @@ var init_recommend = __esm(() => {
|
|
|
5443
5666
|
var init_profile2 = __esm(() => {
|
|
5444
5667
|
init_profile();
|
|
5445
5668
|
});
|
|
5446
|
-
// ../../packages/shared/src/item/outcome.ts
|
|
5447
|
-
var OUTCOME_WINDOW_DAYS = 14, OUTCOME_WINDOW_MS;
|
|
5448
|
-
var init_outcome = __esm(() => {
|
|
5449
|
-
OUTCOME_WINDOW_MS = OUTCOME_WINDOW_DAYS * 86400000;
|
|
5450
|
-
});
|
|
5451
|
-
|
|
5452
5669
|
// ../../packages/shared/src/slack/mention.ts
|
|
5453
5670
|
var MENTION_HELP;
|
|
5454
5671
|
var init_mention = __esm(() => {
|
|
@@ -5472,11 +5689,20 @@ var init_copy = __esm(() => {
|
|
|
5472
5689
|
});
|
|
5473
5690
|
|
|
5474
5691
|
// ../../packages/shared/src/slack/agent.ts
|
|
5692
|
+
var REPLY_RULES;
|
|
5475
5693
|
var init_agent = __esm(() => {
|
|
5476
5694
|
init_intake();
|
|
5477
5695
|
init_brief();
|
|
5478
5696
|
init_copy();
|
|
5479
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
|
+
`);
|
|
5480
5706
|
});
|
|
5481
5707
|
|
|
5482
5708
|
// ../../packages/shared/src/slack/channel.ts
|
|
@@ -6534,30 +6760,12 @@ var init_deploys = __esm(() => {
|
|
|
6534
6760
|
SERVICE_RE = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,39}$/;
|
|
6535
6761
|
});
|
|
6536
6762
|
|
|
6537
|
-
// ../../packages/shared/src/deploys/metrics.ts
|
|
6538
|
-
var WEEK_MS;
|
|
6539
|
-
var init_metrics = __esm(() => {
|
|
6540
|
-
WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
|
6541
|
-
});
|
|
6542
|
-
|
|
6543
|
-
// ../../packages/shared/src/deploys/period.ts
|
|
6544
|
-
var DAY_MS2;
|
|
6545
|
-
var init_period = __esm(() => {
|
|
6546
|
-
DAY_MS2 = 24 * 60 * 60 * 1000;
|
|
6547
|
-
});
|
|
6548
|
-
|
|
6549
6763
|
// ../../packages/shared/src/deploys/stability.ts
|
|
6550
6764
|
var init_stability = __esm(() => {
|
|
6551
6765
|
init_outcome();
|
|
6552
6766
|
init_metrics();
|
|
6553
6767
|
});
|
|
6554
6768
|
|
|
6555
|
-
// ../../packages/shared/src/deploys/batchSize.ts
|
|
6556
|
-
var init_batchSize = __esm(() => {
|
|
6557
|
-
init_outcome();
|
|
6558
|
-
init_metrics();
|
|
6559
|
-
});
|
|
6560
|
-
|
|
6561
6769
|
// ../../packages/shared/src/newrelic/newrelic.ts
|
|
6562
6770
|
var init_newrelic = () => {};
|
|
6563
6771
|
|
|
@@ -7968,6 +8176,7 @@ var init_src = __esm(() => {
|
|
|
7968
8176
|
init_period();
|
|
7969
8177
|
init_stability();
|
|
7970
8178
|
init_batchSize();
|
|
8179
|
+
init_report();
|
|
7971
8180
|
init_sentry();
|
|
7972
8181
|
init_newrelic();
|
|
7973
8182
|
init_musher();
|
|
@@ -8345,7 +8554,13 @@ function parseParked(v) {
|
|
|
8345
8554
|
...typeof a.effort === "string" ? { effort: a.effort } : {}
|
|
8346
8555
|
};
|
|
8347
8556
|
}
|
|
8348
|
-
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
|
+
};
|
|
8349
8564
|
}
|
|
8350
8565
|
function parseRun(v) {
|
|
8351
8566
|
if (!isObject8(v))
|
|
@@ -8385,7 +8600,10 @@ function parseRun(v) {
|
|
|
8385
8600
|
decisionId: v.permission.decisionId,
|
|
8386
8601
|
options: Array.isArray(v.permission.options) ? v.permission.options.filter((x) => typeof x === "string") : [],
|
|
8387
8602
|
at: v.permission.at,
|
|
8388
|
-
...v.permission.onScreen === true ? { onScreen: true } : {}
|
|
8603
|
+
...v.permission.onScreen === true ? { onScreen: true } : {},
|
|
8604
|
+
...typeof v.permission.pressedAt === "number" ? { pressedAt: v.permission.pressedAt } : {},
|
|
8605
|
+
...typeof v.permission.presses === "number" ? { presses: v.permission.presses } : {},
|
|
8606
|
+
...v.permission.gaveUp === true ? { gaveUp: true } : {}
|
|
8389
8607
|
}
|
|
8390
8608
|
} : {},
|
|
8391
8609
|
...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 } } : {},
|
|
@@ -8692,6 +8910,7 @@ init_metrics();
|
|
|
8692
8910
|
init_period();
|
|
8693
8911
|
init_stability();
|
|
8694
8912
|
init_batchSize();
|
|
8913
|
+
init_report();
|
|
8695
8914
|
init_sentry();
|
|
8696
8915
|
init_newrelic();
|
|
8697
8916
|
init_musher();
|
|
@@ -11042,6 +11261,8 @@ var orcaLauncher = (o) => `#!/bin/sh
|
|
|
11042
11261
|
${execLine(agentShellCommand(o))}
|
|
11043
11262
|
`;
|
|
11044
11263
|
var orcaCommand = (launcher) => `sh ${shq2(launcher)}; exit`;
|
|
11264
|
+
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;
|
|
11265
|
+
var ESC = "\x1B";
|
|
11045
11266
|
var GONE = /exit|clos|gone|dead|stopp|kill/i;
|
|
11046
11267
|
var orcaTerminalLive = (status, stdout) => {
|
|
11047
11268
|
const env = parseOrcaJson(stdout);
|
|
@@ -11126,6 +11347,7 @@ function orcaRunner(exec, deps = {}) {
|
|
|
11126
11347
|
}
|
|
11127
11348
|
return env;
|
|
11128
11349
|
};
|
|
11350
|
+
const retries = new Map;
|
|
11129
11351
|
return {
|
|
11130
11352
|
name: "orca",
|
|
11131
11353
|
makesWorktree: true,
|
|
@@ -11177,10 +11399,51 @@ function orcaRunner(exec, deps = {}) {
|
|
|
11177
11399
|
return r.status === 0 ? r.stdout : "";
|
|
11178
11400
|
},
|
|
11179
11401
|
send(h, text) {
|
|
11180
|
-
const
|
|
11181
|
-
|
|
11182
|
-
|
|
11402
|
+
const key = `${h.id}
|
|
11403
|
+
${text}`;
|
|
11404
|
+
const attempt = (retry) => {
|
|
11405
|
+
const r = exec("orca", [
|
|
11406
|
+
"terminal",
|
|
11407
|
+
"send",
|
|
11408
|
+
"--terminal",
|
|
11409
|
+
h.id,
|
|
11410
|
+
"--text",
|
|
11411
|
+
text,
|
|
11412
|
+
"--enter",
|
|
11413
|
+
...retry ? ["--retry-request", retry] : [],
|
|
11414
|
+
"--json"
|
|
11415
|
+
]);
|
|
11416
|
+
const env = parseOrcaJson(r.stdout);
|
|
11417
|
+
const ok = r.status === 0 && env?.ok !== false;
|
|
11418
|
+
return { r, env, ok, id: ok ? null : orcaRequestId(env, `${r.stderr}
|
|
11419
|
+
${r.stdout}`) };
|
|
11420
|
+
};
|
|
11421
|
+
const prior = retries.get(key);
|
|
11422
|
+
let a = attempt(prior);
|
|
11423
|
+
if (!a.ok && a.id && a.id !== prior)
|
|
11424
|
+
a = attempt(a.id);
|
|
11425
|
+
if (a.ok) {
|
|
11426
|
+
retries.delete(key);
|
|
11427
|
+
return;
|
|
11428
|
+
}
|
|
11429
|
+
if (a.id)
|
|
11430
|
+
retries.set(key, a.id);
|
|
11431
|
+
else
|
|
11432
|
+
retries.delete(key);
|
|
11433
|
+
const why = orcaError(a.env) ?? (a.r.stderr.trim() || `exit ${a.r.status}`);
|
|
11434
|
+
throw new Error(`orca terminal send ${h.id} failed: ${why}`);
|
|
11435
|
+
},
|
|
11436
|
+
sendKey(h, key) {
|
|
11437
|
+
if (!isRunnerKey(key))
|
|
11438
|
+
throw new Error(`orca terminal send ${h.id}: no key ${JSON.stringify(key)}`);
|
|
11439
|
+
const what = `orca terminal send ${h.id} (key ${key})`;
|
|
11440
|
+
const send = (args) => orca(["terminal", "send", "--terminal", h.id, ...args, "--json"], what);
|
|
11441
|
+
if (key === "esc") {
|
|
11442
|
+
send(["--text", ESC]);
|
|
11443
|
+
return;
|
|
11183
11444
|
}
|
|
11445
|
+
send(["--text", key]);
|
|
11446
|
+
send(["--enter"]);
|
|
11184
11447
|
},
|
|
11185
11448
|
stop(h) {
|
|
11186
11449
|
exec("orca", ["terminal", "close", "--terminal", h.id]);
|
|
@@ -11248,7 +11511,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
11248
11511
|
name: flags.name,
|
|
11249
11512
|
os: host.os ?? process.platform,
|
|
11250
11513
|
runner: flags.runner,
|
|
11251
|
-
version: host.version ?? "0.1.
|
|
11514
|
+
version: host.version ?? "0.1.52" ?? "dev",
|
|
11252
11515
|
running: live.length,
|
|
11253
11516
|
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
11254
11517
|
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
@@ -12253,6 +12516,10 @@ function permissionsOf(s) {
|
|
|
12253
12516
|
const p = s;
|
|
12254
12517
|
return p && typeof p.openPermission === "function" && typeof p.clearPermission === "function" && typeof p.decisionOf === "function" ? s : null;
|
|
12255
12518
|
}
|
|
12519
|
+
function resumesOf(s) {
|
|
12520
|
+
const r = s;
|
|
12521
|
+
return r && typeof r.resumeParked === "function" ? s : null;
|
|
12522
|
+
}
|
|
12256
12523
|
var FAIL_LOG_MAX = 2000;
|
|
12257
12524
|
var UNREACHABLE3 = "SLEDS unreachable";
|
|
12258
12525
|
function keysIn(states, state) {
|
|
@@ -12437,6 +12704,9 @@ function profileOf(r) {
|
|
|
12437
12704
|
const atOnce = num5(p.atOnce);
|
|
12438
12705
|
if (atOnce !== undefined && atOnce >= 1)
|
|
12439
12706
|
out.atOnce = Math.round(atOnce);
|
|
12707
|
+
const seatAtOnce = num5(r.seatAtOnce);
|
|
12708
|
+
if (seatAtOnce !== undefined && Number.isInteger(seatAtOnce) && seatAtOnce >= 1)
|
|
12709
|
+
out.seatAtOnce = seatAtOnce;
|
|
12440
12710
|
if (typeof p.mcpStrict === "boolean")
|
|
12441
12711
|
out.mcpStrict = p.mcpStrict;
|
|
12442
12712
|
const holdCpu = num5(p.holdCpu);
|
|
@@ -12899,6 +13169,18 @@ function sledsSource(client, o) {
|
|
|
12899
13169
|
throw new Error(serverMessage(r));
|
|
12900
13170
|
return r.json.cleared === true;
|
|
12901
13171
|
},
|
|
13172
|
+
async resumeParked(runId, why, engine, leaseMin) {
|
|
13173
|
+
const r = await client.postFull("/proxy/run", { runId, engine, leaseMin, resumed: { why } });
|
|
13174
|
+
if (!r)
|
|
13175
|
+
throw new Error(`${UNREACHABLE3} — the resume not recorded`);
|
|
13176
|
+
if (r.status >= 300 || !r.json || r.json.ok === false)
|
|
13177
|
+
throw new Error(serverMessage(r));
|
|
13178
|
+
const leaseUntil = typeof r.json.leaseUntil === "number" ? r.json.leaseUntil : undefined;
|
|
13179
|
+
return {
|
|
13180
|
+
resumed: r.json.resumed === true,
|
|
13181
|
+
...leaseUntil !== undefined ? { leaseUntil } : {}
|
|
13182
|
+
};
|
|
13183
|
+
},
|
|
12902
13184
|
async decisionOf(item, decisionId) {
|
|
12903
13185
|
const route = await routeOf(item);
|
|
12904
13186
|
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject8) : [];
|
|
@@ -13491,6 +13773,7 @@ async function tick(deps) {
|
|
|
13491
13773
|
deps.providerHold = d.providerHold;
|
|
13492
13774
|
deps.draining = d.draining;
|
|
13493
13775
|
deps.atOnce = d.atOnce;
|
|
13776
|
+
deps.seatAtOnceNoted = d.seatAtOnceNoted;
|
|
13494
13777
|
deps.runner = d.runner;
|
|
13495
13778
|
deps.runnerRefused = d.runnerRefused;
|
|
13496
13779
|
}
|
|
@@ -13562,6 +13845,10 @@ async function tickOnce(d) {
|
|
|
13562
13845
|
try {
|
|
13563
13846
|
open = runner.status(run.handle) === "running";
|
|
13564
13847
|
} catch {}
|
|
13848
|
+
if (open && await answeredInSession(d, runner, run)) {
|
|
13849
|
+
keep.push(run);
|
|
13850
|
+
continue;
|
|
13851
|
+
}
|
|
13565
13852
|
if (open || liveAnswerer(run))
|
|
13566
13853
|
keep.push(run);
|
|
13567
13854
|
else
|
|
@@ -14086,7 +14373,20 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14086
14373
|
const dialog = runner.readsSession ? permissionDialog(shown) : null;
|
|
14087
14374
|
const p = run.permission;
|
|
14088
14375
|
if (p) {
|
|
14089
|
-
const gone = runner.readsSession && (p.onScreen ? !dialog : (run.seenAt ?? 0) > p.at);
|
|
14376
|
+
const gone = runner.readsSession && (p.onScreen ? !dialog : (run.seenAt ?? 0) > (p.pressedAt ?? p.at));
|
|
14377
|
+
const answered = () => {
|
|
14378
|
+
run.permission = undefined;
|
|
14379
|
+
run.answeredAt = d.now();
|
|
14380
|
+
if (markFile)
|
|
14381
|
+
clearPermissionMark(markFile);
|
|
14382
|
+
};
|
|
14383
|
+
if (p.gaveUp) {
|
|
14384
|
+
if (!gone)
|
|
14385
|
+
return true;
|
|
14386
|
+
d.log(`${at}: the permission dialog was answered in the terminal`);
|
|
14387
|
+
answered();
|
|
14388
|
+
return false;
|
|
14389
|
+
}
|
|
14090
14390
|
let now;
|
|
14091
14391
|
try {
|
|
14092
14392
|
now = await perms.decisionOf(run.item, p.decisionId);
|
|
@@ -14095,14 +14395,42 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14095
14395
|
return true;
|
|
14096
14396
|
}
|
|
14097
14397
|
if (now?.state === "answered" && now.answer) {
|
|
14098
|
-
if (
|
|
14099
|
-
|
|
14100
|
-
|
|
14398
|
+
if (p.pressedAt === undefined) {
|
|
14399
|
+
if (gone)
|
|
14400
|
+
d.log(`${at}: the permission was answered after its dialog closed — not pressed`);
|
|
14401
|
+
else {
|
|
14402
|
+
const pressed = pressAnswer(d, runner, run, p.options, now.answer);
|
|
14403
|
+
if (!pressed)
|
|
14404
|
+
return true;
|
|
14405
|
+
if (pressed === "key") {
|
|
14406
|
+
run.permission = { ...p, pressedAt: d.now(), presses: 1 };
|
|
14407
|
+
return true;
|
|
14408
|
+
}
|
|
14409
|
+
}
|
|
14410
|
+
answered();
|
|
14101
14411
|
return true;
|
|
14102
|
-
|
|
14103
|
-
|
|
14104
|
-
if (
|
|
14105
|
-
|
|
14412
|
+
}
|
|
14413
|
+
const key = permissionKey(now.answer) ?? now.answer;
|
|
14414
|
+
if (gone) {
|
|
14415
|
+
d.log(`${at}: the permission is answered — pressed ${key}; the session goes on`);
|
|
14416
|
+
answered();
|
|
14417
|
+
return false;
|
|
14418
|
+
}
|
|
14419
|
+
const presses = p.presses ?? 1;
|
|
14420
|
+
if (presses >= PRESS_TRIES) {
|
|
14421
|
+
const why = `pressed ${key} ${presses} times; the dialog stayed — answer it in the terminal`;
|
|
14422
|
+
try {
|
|
14423
|
+
await perms.clearPermission(run.runId, why, d.engine);
|
|
14424
|
+
} catch (e) {
|
|
14425
|
+
d.log(`${at}: could not clear the permission, trying next tick: ${message(e)}`);
|
|
14426
|
+
return true;
|
|
14427
|
+
}
|
|
14428
|
+
d.log(`${at}: ${why}`);
|
|
14429
|
+
run.permission = { ...p, gaveUp: true };
|
|
14430
|
+
return true;
|
|
14431
|
+
}
|
|
14432
|
+
if (pressAnswer(d, runner, run, p.options, now.answer) === "key")
|
|
14433
|
+
run.permission = { ...p, pressedAt: d.now(), presses: presses + 1 };
|
|
14106
14434
|
return true;
|
|
14107
14435
|
}
|
|
14108
14436
|
if (now?.state !== "open" && now?.state !== "escalated") {
|
|
@@ -14152,6 +14480,7 @@ async function settlePermission(d, runner, run, shown) {
|
|
|
14152
14480
|
d.log(`${at}: stopped at a permission dialog — it waits for a person (${runner.watchHint(run.handle)})`);
|
|
14153
14481
|
return true;
|
|
14154
14482
|
}
|
|
14483
|
+
var PRESS_TRIES = 3;
|
|
14155
14484
|
function pressAnswer(d, runner, run, options, answer) {
|
|
14156
14485
|
const at = ref(run);
|
|
14157
14486
|
const key = permissionKey(answer);
|
|
@@ -14162,13 +14491,15 @@ function pressAnswer(d, runner, run, options, answer) {
|
|
|
14162
14491
|
runner.sendKey(run.handle, key);
|
|
14163
14492
|
else
|
|
14164
14493
|
runner.send(run.handle, key);
|
|
14494
|
+
if (runner.readsSession)
|
|
14495
|
+
return "key";
|
|
14165
14496
|
d.log(`${at}: the permission is answered — pressed ${key}; the session goes on`);
|
|
14166
14497
|
} else {
|
|
14167
14498
|
runner.sendKey?.(run.handle, "esc");
|
|
14168
14499
|
const note = runner.send(run.handle, answer);
|
|
14169
14500
|
d.log(`${at}: the permission is answered in words — Esc, then typed in${note ? ` (${note})` : ""}`);
|
|
14170
14501
|
}
|
|
14171
|
-
return
|
|
14502
|
+
return "done";
|
|
14172
14503
|
} catch (e) {
|
|
14173
14504
|
d.log(`${at}: could not press the permission's answer, trying next tick: ${message(e)}`);
|
|
14174
14505
|
return false;
|
|
@@ -14337,10 +14668,25 @@ async function rereadAtOnce(d) {
|
|
|
14337
14668
|
try {
|
|
14338
14669
|
next = await d.rereadAtOnce(profileOf2(d));
|
|
14339
14670
|
} catch {}
|
|
14340
|
-
if (next
|
|
14671
|
+
if (next !== null && next !== d.atOnce) {
|
|
14672
|
+
d.atOnce = next;
|
|
14673
|
+
d.log(`at once now ${next}, from your engine profile`);
|
|
14674
|
+
}
|
|
14675
|
+
await sayAtOnceDisagrees(d);
|
|
14676
|
+
}
|
|
14677
|
+
async function sayAtOnceDisagrees(d) {
|
|
14678
|
+
const seat = (await profileOf2(d)())?.seatAtOnce;
|
|
14679
|
+
if (seat === undefined)
|
|
14341
14680
|
return;
|
|
14342
|
-
d.atOnce
|
|
14343
|
-
|
|
14681
|
+
if (seat === d.atOnce) {
|
|
14682
|
+
d.seatAtOnceNoted = undefined;
|
|
14683
|
+
return;
|
|
14684
|
+
}
|
|
14685
|
+
const pair = `${d.atOnce}/${seat}`;
|
|
14686
|
+
if (d.seatAtOnceNoted === pair)
|
|
14687
|
+
return;
|
|
14688
|
+
d.seatAtOnceNoted = pair;
|
|
14689
|
+
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`);
|
|
14344
14690
|
}
|
|
14345
14691
|
async function rereadRunner(d) {
|
|
14346
14692
|
if (!d.rereadRunner)
|
|
@@ -14394,10 +14740,53 @@ function stopOpen(d, run, runner) {
|
|
|
14394
14740
|
}
|
|
14395
14741
|
}
|
|
14396
14742
|
function holdParked(d, runner, run, question) {
|
|
14397
|
-
run.parked = { question, at: d.now() };
|
|
14743
|
+
run.parked = { question, at: d.now(), ...run.seen ? { screen: run.seen } : {} };
|
|
14398
14744
|
run.leaseUntil = undefined;
|
|
14399
14745
|
setLane(d, runner, run.handle, "parked");
|
|
14400
14746
|
}
|
|
14747
|
+
async function answeredInSession(d, runner, run) {
|
|
14748
|
+
const parked = run.parked;
|
|
14749
|
+
const resumes = resumesOf(d.source);
|
|
14750
|
+
if (!resumes || !runner.readsSession || !run.runId)
|
|
14751
|
+
return false;
|
|
14752
|
+
let print;
|
|
14753
|
+
try {
|
|
14754
|
+
print = fingerprint(runner.read(run.handle));
|
|
14755
|
+
} catch {
|
|
14756
|
+
return false;
|
|
14757
|
+
}
|
|
14758
|
+
if (print === parked.screen) {
|
|
14759
|
+
parked.still = true;
|
|
14760
|
+
return false;
|
|
14761
|
+
}
|
|
14762
|
+
const moved = parked.still === true;
|
|
14763
|
+
parked.screen = print;
|
|
14764
|
+
parked.still = false;
|
|
14765
|
+
if (!moved)
|
|
14766
|
+
return false;
|
|
14767
|
+
let r;
|
|
14768
|
+
try {
|
|
14769
|
+
r = await resumes.resumeParked(run.runId, "answered in the session", d.engine, d.leaseMin);
|
|
14770
|
+
} catch (e) {
|
|
14771
|
+
d.log(`${ref(run)}: the parked session moved on, but SLEDS did not hear it: ${message(e)}`);
|
|
14772
|
+
return false;
|
|
14773
|
+
}
|
|
14774
|
+
if (!r.resumed) {
|
|
14775
|
+
d.log(`${ref(run)}: the parked session moved on, but the node is no longer parked on its run`);
|
|
14776
|
+
return false;
|
|
14777
|
+
}
|
|
14778
|
+
stopAnswerer(d, run);
|
|
14779
|
+
const now = d.now();
|
|
14780
|
+
run.parked = undefined;
|
|
14781
|
+
run.seen = print;
|
|
14782
|
+
run.seenAt = now;
|
|
14783
|
+
run.seenTicks = 0;
|
|
14784
|
+
run.answeredAt = now;
|
|
14785
|
+
run.leaseUntil = r.leaseUntil ?? now + d.leaseMin * 60000;
|
|
14786
|
+
setLane(d, runner, run.handle, "working");
|
|
14787
|
+
d.log(`${ref(run)}: answered in the session — out of Needs you, running again`);
|
|
14788
|
+
return true;
|
|
14789
|
+
}
|
|
14401
14790
|
function setLane(d, runner, h, lane) {
|
|
14402
14791
|
try {
|
|
14403
14792
|
runner.lane?.(h, lane);
|
|
@@ -16973,7 +17362,7 @@ async function fetchVersion(o) {
|
|
|
16973
17362
|
const platform = o.platform ?? process.platform;
|
|
16974
17363
|
const arch = o.arch ?? process.arch;
|
|
16975
17364
|
const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
|
|
16976
|
-
const running = o.running ?? "0.1.
|
|
17365
|
+
const running = o.running ?? "0.1.52";
|
|
16977
17366
|
if (!publicKey)
|
|
16978
17367
|
return { ok: false, why: "no release key yet" };
|
|
16979
17368
|
if (!VERSION_RE2.test(o.version))
|
|
@@ -18557,7 +18946,7 @@ function engineClient(o, org) {
|
|
|
18557
18946
|
return fetchClient({
|
|
18558
18947
|
...src,
|
|
18559
18948
|
timeoutMs: ENGINE_TIMEOUT_MS,
|
|
18560
|
-
version: "0.1.
|
|
18949
|
+
version: "0.1.52"
|
|
18561
18950
|
});
|
|
18562
18951
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
18563
18952
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -18848,7 +19237,7 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
18848
19237
|
runner: deps.runner.name,
|
|
18849
19238
|
atOnce: flags.atOnce,
|
|
18850
19239
|
interval: flags.interval,
|
|
18851
|
-
cliVersion: "0.1.
|
|
19240
|
+
cliVersion: "0.1.52"
|
|
18852
19241
|
};
|
|
18853
19242
|
const beat = (checkedAt) => {
|
|
18854
19243
|
const m = deps.machine;
|
|
@@ -20705,7 +21094,7 @@ function engineClient2(o, org) {
|
|
|
20705
21094
|
return fetchClient({
|
|
20706
21095
|
...src,
|
|
20707
21096
|
timeoutMs: ENGINE_TIMEOUT_MS2,
|
|
20708
|
-
version: "0.1.
|
|
21097
|
+
version: "0.1.52"
|
|
20709
21098
|
});
|
|
20710
21099
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
20711
21100
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -21031,7 +21420,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
21031
21420
|
runner: deps.runner.name,
|
|
21032
21421
|
atOnce: flags.atOnce,
|
|
21033
21422
|
interval: flags.interval,
|
|
21034
|
-
cliVersion: "0.1.
|
|
21423
|
+
cliVersion: "0.1.52"
|
|
21035
21424
|
};
|
|
21036
21425
|
const beat = (checkedAt) => {
|
|
21037
21426
|
const m = deps.machine;
|
|
@@ -23119,7 +23508,7 @@ function contextFor(deps) {
|
|
|
23119
23508
|
...src,
|
|
23120
23509
|
fetchFn: deps.fetchFn,
|
|
23121
23510
|
timeoutMs: deps.timeoutMs,
|
|
23122
|
-
version: "0.1.
|
|
23511
|
+
version: "0.1.52"
|
|
23123
23512
|
}), deps.home, now) : null;
|
|
23124
23513
|
return {
|
|
23125
23514
|
channel: "code",
|
|
@@ -25633,14 +26022,16 @@ function routeReader(o, org) {
|
|
|
25633
26022
|
read: (k) => readOrSay(client, `/proxy/route?q=${encodeURIComponent(k)}`, k)
|
|
25634
26023
|
};
|
|
25635
26024
|
}
|
|
25636
|
-
var SLED_USAGE = "usage: sleds sled --json | sleds sled top <KEY> | sleds sled order <KEY>…";
|
|
26025
|
+
var SLED_USAGE = "usage: sleds sled --json | sleds sled top <KEY> | sleds sled order <KEY>… | sleds sled off <KEY> [--json]";
|
|
25637
26026
|
async function sledCmd(o) {
|
|
25638
26027
|
const log = o.log ?? console.log;
|
|
25639
26028
|
const error = o.error ?? console.error;
|
|
25640
26029
|
const top = o.argv[0] === "top" && o.argv.length === 2 && !o.argv[1]?.startsWith("-");
|
|
25641
26030
|
const keys = o.argv.slice(1);
|
|
25642
26031
|
const order = o.argv[0] === "order" && keys.length > 0 && keys.every((k) => k.trim() && !k.startsWith("-"));
|
|
25643
|
-
|
|
26032
|
+
const offArgs = o.argv.slice(1).filter((a) => a !== "--json");
|
|
26033
|
+
const off = o.argv[0] === "off" && offArgs.length === 1 && o.argv.length <= 3 && !!offArgs[0]?.trim() && !offArgs[0].startsWith("-");
|
|
26034
|
+
if (!top && !order && !off && (o.argv.length !== 1 || o.argv[0] !== "--json")) {
|
|
25644
26035
|
error(SLED_USAGE);
|
|
25645
26036
|
return 2;
|
|
25646
26037
|
}
|
|
@@ -25653,6 +26044,8 @@ async function sledCmd(o) {
|
|
|
25653
26044
|
return sledTop(client, o.argv[1], log, error);
|
|
25654
26045
|
if (order)
|
|
25655
26046
|
return sledOrder(client, keys, log, error);
|
|
26047
|
+
if (off)
|
|
26048
|
+
return sledOff(client, offArgs[0], o.argv.includes("--json"), log, error);
|
|
25656
26049
|
try {
|
|
25657
26050
|
log(JSON.stringify(await readOrSay(client, "/proxy/sled", "the sled")));
|
|
25658
26051
|
return 0;
|
|
@@ -25687,6 +26080,31 @@ async function sledOrder(client, keys, log, error) {
|
|
|
25687
26080
|
log(`${typeof r.json?.ordered === "number" ? r.json.ordered : keys.length} ordered on your sled`);
|
|
25688
26081
|
return 0;
|
|
25689
26082
|
}
|
|
26083
|
+
async function sledOff(client, key, json, log, error) {
|
|
26084
|
+
const r = await client.postFull("/proxy/sled/off", { project: key });
|
|
26085
|
+
if (!r) {
|
|
26086
|
+
error(`${key}: SLEDS unreachable — the sled is unchanged`);
|
|
26087
|
+
return 1;
|
|
26088
|
+
}
|
|
26089
|
+
if (r.status >= 300 || r.json?.ok === false) {
|
|
26090
|
+
error(typeof r.json?.error === "string" ? r.json.error : `${key}: HTTP ${r.status}`);
|
|
26091
|
+
return 1;
|
|
26092
|
+
}
|
|
26093
|
+
if (json) {
|
|
26094
|
+
log(JSON.stringify(r.json));
|
|
26095
|
+
return 0;
|
|
26096
|
+
}
|
|
26097
|
+
const k = typeof r.json?.key === "string" ? r.json.key : key;
|
|
26098
|
+
if (r.json?.changed === false) {
|
|
26099
|
+
log(`${k} was not on a sled`);
|
|
26100
|
+
return 0;
|
|
26101
|
+
}
|
|
26102
|
+
log(`${k} is off your sled — back in the pool`);
|
|
26103
|
+
const running = typeof r.json?.running === "number" ? r.json.running : 0;
|
|
26104
|
+
if (running > 0)
|
|
26105
|
+
log(`${running} running node${running === 1 ? "" : "s"} stopped`);
|
|
26106
|
+
return 0;
|
|
26107
|
+
}
|
|
25690
26108
|
|
|
25691
26109
|
// src/commands/run.ts
|
|
25692
26110
|
init_config();
|
|
@@ -27205,7 +27623,7 @@ var realPidAlive4 = (pid) => {
|
|
|
27205
27623
|
};
|
|
27206
27624
|
function machineClient(home, env) {
|
|
27207
27625
|
const src = meterSource(home, undefined, { env });
|
|
27208
|
-
return src ? fetchClient({ ...src, version: "0.1.
|
|
27626
|
+
return src ? fetchClient({ ...src, version: "0.1.52" }) : null;
|
|
27209
27627
|
}
|
|
27210
27628
|
async function noteAnswer2(home, a, now) {
|
|
27211
27629
|
try {
|
|
@@ -27825,6 +28243,7 @@ commands:
|
|
|
27825
28243
|
sled --json What is on your sled (mine with each route, proposed, sent), for a front end.
|
|
27826
28244
|
sleds sled top KEY put KEY first on your sled; the engine picks it next
|
|
27827
28245
|
sleds sled order KEY\u2026 those items in this order, in the places they hold; the rest stay
|
|
28246
|
+
sleds sled off KEY take KEY off your sled, back in the pool; its running nodes stop
|
|
27828
28247
|
route <key> Print an item's route: its nodes, what each waits on, what is ready, where each
|
|
27829
28248
|
run can be watched.
|
|
27830
28249
|
--dot Graphviz instead: \`sleds route QW-142 --dot | dot -Tpng -o route.png\`
|
|
@@ -28050,7 +28469,7 @@ var main = async (argv) => {
|
|
|
28050
28469
|
now: Date.now(),
|
|
28051
28470
|
stderr: (line) => console.error(line),
|
|
28052
28471
|
isTTY: !!process.stderr.isTTY,
|
|
28053
|
-
version: "0.1.
|
|
28472
|
+
version: "0.1.52"
|
|
28054
28473
|
});
|
|
28055
28474
|
switch (cmd) {
|
|
28056
28475
|
case "update":
|
|
@@ -28283,7 +28702,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
28283
28702
|
case "version":
|
|
28284
28703
|
case "--version":
|
|
28285
28704
|
case "-v":
|
|
28286
|
-
console.log("sleds 0.1.
|
|
28705
|
+
console.log("sleds 0.1.52");
|
|
28287
28706
|
return 0;
|
|
28288
28707
|
default:
|
|
28289
28708
|
console.error(`unknown command: ${cmd}
|
|
@@ -28304,10 +28723,18 @@ var isMain = () => {
|
|
|
28304
28723
|
return false;
|
|
28305
28724
|
}
|
|
28306
28725
|
};
|
|
28726
|
+
var drained = (stream) => new Promise((resolve) => {
|
|
28727
|
+
stream.once("error", () => resolve());
|
|
28728
|
+
stream.write("", () => resolve());
|
|
28729
|
+
});
|
|
28730
|
+
var exitDrained = async (code) => {
|
|
28731
|
+
await Promise.all([drained(process.stdout), drained(process.stderr)]);
|
|
28732
|
+
process.exit(code);
|
|
28733
|
+
};
|
|
28307
28734
|
if (isMain()) {
|
|
28308
|
-
main(process.argv.slice(2)).then((code) =>
|
|
28735
|
+
main(process.argv.slice(2)).then((code) => exitDrained(code), (err) => {
|
|
28309
28736
|
console.error(err instanceof Error ? err.message : String(err));
|
|
28310
|
-
|
|
28737
|
+
return exitDrained(1);
|
|
28311
28738
|
});
|
|
28312
28739
|
}
|
|
28313
28740
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleds/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.52",
|
|
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",
|