@sleds/cli 0.1.71 → 0.1.73
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 +1312 -948
- package/package.json +1 -1
package/dist/sleds.mjs
CHANGED
|
@@ -5878,16 +5878,22 @@ var init_recommend = __esm(() => {
|
|
|
5878
5878
|
var init_profile2 = __esm(() => {
|
|
5879
5879
|
init_profile();
|
|
5880
5880
|
});
|
|
5881
|
+
// ../../packages/shared/src/slack/verification.ts
|
|
5882
|
+
var init_verification = () => {};
|
|
5883
|
+
|
|
5881
5884
|
// ../../packages/shared/src/slack/mention.ts
|
|
5882
|
-
var MENTION_HELP;
|
|
5885
|
+
var HELD_STAGES, MENTION_HELP;
|
|
5883
5886
|
var init_mention = __esm(() => {
|
|
5884
5887
|
init_intake();
|
|
5885
5888
|
init_brief();
|
|
5889
|
+
init_verification();
|
|
5890
|
+
HELD_STAGES = new Set(["on_sled", "verification"]);
|
|
5886
5891
|
MENTION_HELP = [
|
|
5887
5892
|
"Here's what I can do:",
|
|
5888
5893
|
"• *@SLEDS file this*: turn the message above into a request for engineering",
|
|
5889
5894
|
"• *@SLEDS status*: see where something stands",
|
|
5890
|
-
"You can also ask me to *watch* or *mute* a thread, or *run QW-123*."
|
|
5895
|
+
"You can also ask me to *watch* or *mute* a thread, or *run QW-123*.",
|
|
5896
|
+
"When something waits for checking: *pass QW-123*, or *fail QW-123* and what's wrong."
|
|
5891
5897
|
].join(`
|
|
5892
5898
|
`);
|
|
5893
5899
|
});
|
|
@@ -6974,7 +6980,7 @@ var init_sentry = () => {};
|
|
|
6974
6980
|
var init_outside = () => {};
|
|
6975
6981
|
|
|
6976
6982
|
// ../../packages/shared/src/pack/pack.ts
|
|
6977
|
-
var LANDING_GAP_MS;
|
|
6983
|
+
var SIGNED_MOCK_LINE = "- signed mock:", RELATED_MOCK_LINE = "- approved mock on", APPROVED_MOCK_HEADING = "### The approved mock", LANDING_GAP_MS;
|
|
6978
6984
|
var init_pack = __esm(() => {
|
|
6979
6985
|
init_flags();
|
|
6980
6986
|
init_profile();
|
|
@@ -7637,6 +7643,50 @@ var init_say = __esm(() => {
|
|
|
7637
7643
|
];
|
|
7638
7644
|
});
|
|
7639
7645
|
|
|
7646
|
+
// ../../packages/shared/src/route/look.ts
|
|
7647
|
+
function lookComparisonOf(body) {
|
|
7648
|
+
const at = body.indexOf(LOOK_OPEN);
|
|
7649
|
+
if (at < 0)
|
|
7650
|
+
return;
|
|
7651
|
+
const end = body.indexOf(LOOK_CLOSE, at + LOOK_OPEN.length);
|
|
7652
|
+
if (end < 0)
|
|
7653
|
+
return;
|
|
7654
|
+
const block = body.slice(at + LOOK_OPEN.length, end);
|
|
7655
|
+
const differences = [];
|
|
7656
|
+
for (const line of block.split(`
|
|
7657
|
+
`)) {
|
|
7658
|
+
const m = CHECK.exec(line);
|
|
7659
|
+
if (m?.[2])
|
|
7660
|
+
differences.push({ text: m[2], fixed: m[1] !== " " });
|
|
7661
|
+
}
|
|
7662
|
+
return { shots: block.match(IMAGE)?.length ?? 0, differences };
|
|
7663
|
+
}
|
|
7664
|
+
function lookComparisonLines(c) {
|
|
7665
|
+
const open = c.differences.filter((d) => !d.fixed);
|
|
7666
|
+
const fixed = c.differences.length - open.length;
|
|
7667
|
+
const shots = c.shots > 0 ? "The PR sets the preview's screenshots beside the mock." : "The PR's comparison carries no screenshots — check the preview against the mock yourself.";
|
|
7668
|
+
if (c.differences.length === 0)
|
|
7669
|
+
return `${shots} The session found no differences from the mock.`;
|
|
7670
|
+
const listed = open.slice(0, LOOK_LISTED).map((d) => `- ${d.text.slice(0, 140)}`);
|
|
7671
|
+
const more = open.length > LOOK_LISTED ? [`- …and ${open.length - LOOK_LISTED} more`] : [];
|
|
7672
|
+
const head = open.length ? `${open.length} ${open.length === 1 ? "difference" : "differences"} from the mock still open${fixed ? ` (${fixed} fixed)` : ""}:` : `All ${fixed} ${fixed === 1 ? "difference" : "differences"} from the mock are marked fixed.`;
|
|
7673
|
+
return [`${shots} ${head}`, ...listed, ...more].join(`
|
|
7674
|
+
`);
|
|
7675
|
+
}
|
|
7676
|
+
function lookComparisonPrompt(item) {
|
|
7677
|
+
return [
|
|
7678
|
+
`- Before the look, compare what you built to the approved mock — the person looking must not have to eyeball it. Once the draft PR's preview is up (the Vercel check or its bot comment on the PR), screenshot the preview with Playwright (\`pnpm dlx playwright screenshot --full-page --viewport-size "1440,900" <url> preview-<screen>.png\`; \`pnpm dlx playwright install chromium\` first if it has no browser) on each screen the mock shows, at the mock's width. If the preview asks for a sign-in Playwright cannot pass, screenshot the same screens from \`pnpm dev\` and say so in the block.`,
|
|
7679
|
+
`- Put each screenshot (and the mock, when it is an image) on the item with \`sleds attach ${item} --file <shot.png>\`; it prints the link to use in the PR body.`,
|
|
7680
|
+
`- In the PR body, under the header, add one block between \`${LOOK_OPEN}\` and \`${LOOK_CLOSE}\`: a table with the mock and the preview side by side, one row per screen (\`| Mock | Preview |\`, each cell an image), then **Differences from the mock** as a checklist — one \`- [ ]\` line for every difference you see: anything missing, added, moved, resized, restyled, a different colour, copy or data. List what you mean to fix too; check a line (\`- [x]\`) only once a push fixed it, and update the block each time. If you find none after checking each part of the mock, write \`No differences found.\` in place of the checklist. The engine raises the look from this block and lists the open lines to the person.`
|
|
7681
|
+
].join(`
|
|
7682
|
+
`);
|
|
7683
|
+
}
|
|
7684
|
+
var LOOK_OPEN = "<!-- sleds:look -->", LOOK_CLOSE = "<!-- /sleds:look -->", CHECK, IMAGE, LOOK_LISTED = 12;
|
|
7685
|
+
var init_look = __esm(() => {
|
|
7686
|
+
CHECK = /^\s*[-*]\s+\[([ xX])\]\s+(.+?)\s*$/;
|
|
7687
|
+
IMAGE = /!\[[^\]]*\]\([^)\s]+[^)]*\)|<img\s[^>]*src=/gi;
|
|
7688
|
+
});
|
|
7689
|
+
|
|
7640
7690
|
// ../../packages/shared/src/route/engine.ts
|
|
7641
7691
|
function seatSlots(atOnce) {
|
|
7642
7692
|
if (typeof atOnce !== "number" || !Number.isFinite(atOnce))
|
|
@@ -7804,6 +7854,32 @@ function visualSurface(pack) {
|
|
|
7804
7854
|
return pack.split(`
|
|
7805
7855
|
`).filter((l) => /^\s*-\s*(\*\*)?touches(\*\*)?\s*:/i.test(l)).some((l) => VISUAL_PATH.test(l.replace(/^[^:]*:/, " ")));
|
|
7806
7856
|
}
|
|
7857
|
+
function approvedMockIn(pack) {
|
|
7858
|
+
const lines = pack.split(`
|
|
7859
|
+
`).map((l) => l.trim());
|
|
7860
|
+
if (lines.some((l) => l === APPROVED_MOCK_HEADING || l.startsWith(SIGNED_MOCK_LINE)))
|
|
7861
|
+
return { kind: "own" };
|
|
7862
|
+
const related = lines.filter((l) => l.startsWith(RELATED_MOCK_LINE));
|
|
7863
|
+
return related.length ? { kind: "related", lines: related } : null;
|
|
7864
|
+
}
|
|
7865
|
+
function mockLines(visual, pack, parkTool) {
|
|
7866
|
+
const approved = approvedMockIn(pack);
|
|
7867
|
+
const draftRule = `If a person's answer says to draw one, it is a draft, not the design: label it \`${ENGINE_DRAFT_LABEL}\` on the header's Mocks line (\`[${ENGINE_DRAFT_LABEL}](url)\`), in the PR body, and in the artifact's own title and first heading.`;
|
|
7868
|
+
const ask = parkTool ? `park with the SLEDS \`${parkTool}\` tool before you write any code` : "write the question as the last thing you say and stop, before you write any code";
|
|
7869
|
+
const stop = `${ask}: say which screen it changes, that the pack names no approved mock (none signed on this item, its parent, siblings or related items), and offer the options — a link to the approved design to build to, a yes to draw an engine draft for the look, or hold until a mock is signed.`;
|
|
7870
|
+
const compare = visual ? "" : `, and the built preview's screenshots beside it with every difference from the mock as a \`- [ ]\` checklist, between \`${LOOK_OPEN}\` and \`${LOOK_CLOSE}\` (SL-2213)`;
|
|
7871
|
+
if (approved?.kind === "own")
|
|
7872
|
+
return [
|
|
7873
|
+
`- ${visual ? "This node has a visual surface, and" : "If the change turns out to have a visual surface:"} the item has a signed mock (\`The approved mock\` at the top of part 1 of the pack: the pinned copy as signed, and what changed since). Build to it — do not draw your own; where that block says the mock changed since approval, it says what to do. Put its link on the header's Mocks line and say in the PR body "Built to the approved mock: <its name>". ${visual ? "Open the PR as a draft (`gh pr create --draft`) with a screenshot of the built screen beside the mock; a person looks there and marks it ready." : `Open the PR as a draft (\`gh pr create --draft\`) with the mock in its body${compare}.`}`
|
|
7874
|
+
];
|
|
7875
|
+
if (approved?.kind === "related")
|
|
7876
|
+
return [
|
|
7877
|
+
`- ${visual ? "This node has a visual surface, and" : "If the change turns out to have a visual surface:"} no mock is signed on this item, but a related item has an approved one (the \`approved mock on\` line in part 1 of the pack: ${approved.lines.map((l) => `\`${l.slice(RELATED_MOCK_LINE.length).split(":")[0]?.trim()}\``).join(", ")}). If it covers the screen this node changes, build to it — do not draw your own — and say so at the top of the PR body: "Built to <key>'s approved mock: <its link>", with the link on the header's Mocks line. If it does not cover this screen, ${stop} ${draftRule} Open the PR as a draft (\`gh pr create --draft\`) with the mock in its body${compare || " and a screenshot of the built screen"}.`
|
|
7878
|
+
];
|
|
7879
|
+
return [
|
|
7880
|
+
visual ? `- This node has a visual surface and the pack names no approved mock. Before building, ${stop} ${draftRule} The look happens on the PR, not in chat: open it as a draft (\`gh pr create --draft\`) with the mock in its body, and a person looks there and marks it ready.` : `- If the change turns out to have a visual surface, the pack names no approved mock: ${stop} ${draftRule} The look happens on the PR, not in chat: open it as a draft (\`gh pr create --draft\`) with the mock — a screenshot or the artifact link — in its body${compare}.`
|
|
7881
|
+
];
|
|
7882
|
+
}
|
|
7807
7883
|
function packItemLink(pack) {
|
|
7808
7884
|
const at = pack.indexOf(PR_HEADER_OPEN);
|
|
7809
7885
|
if (at < 0)
|
|
@@ -7848,8 +7924,10 @@ function nodePrompt(o) {
|
|
|
7848
7924
|
"- Stay inside this node's scope. Work another node needs goes in the PR description, not in this branch.",
|
|
7849
7925
|
`- 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.`,
|
|
7850
7926
|
"- The approved brief and this route are the go-ahead: a person said yes to them before this session started. Build, commit, push and open the PR; a park is for a question the record does not settle, not for a go-ahead to build or push.",
|
|
7851
|
-
visual
|
|
7927
|
+
...mockLines(visual, claim.pack, o.sledsTools && claim.runId ? toolName("run", o.engineMcp) : null)
|
|
7852
7928
|
];
|
|
7929
|
+
if (visual)
|
|
7930
|
+
lines.push(lookComparisonPrompt(claim.item));
|
|
7853
7931
|
const lookBar = lookBarLine(claim);
|
|
7854
7932
|
if (lookBar)
|
|
7855
7933
|
lines.push(lookBar);
|
|
@@ -7907,16 +7985,22 @@ ${claim.pack.trim()}
|
|
|
7907
7985
|
}
|
|
7908
7986
|
function mockPrompt(o) {
|
|
7909
7987
|
const base = o.base ?? "main";
|
|
7988
|
+
const r = o.revise;
|
|
7989
|
+
const reviseLines = r ? [
|
|
7990
|
+
`- This run revises the item's current mock, \`${r.name}\`: read its HTML at \`${r.path}\` first. Draw its next version, not a new mock — the same screen, the same design tokens and components — and keep everything the brief does not ask to change.`,
|
|
7991
|
+
`- Say what changed from \`${r.name}\` in a short note inside the HTML. Leave \`${r.path}\` as it is: the next version goes only to \`${o.out}\`.`
|
|
7992
|
+
] : [];
|
|
7910
7993
|
const lines = [
|
|
7911
7994
|
`You are drawing a mock for ${o.item} — "${o.title}"${o.engine ? ` — started by ${o.engine}` : ""}. Nobody is at the keyboard: a person signs the mock before the build gets its nodes.`,
|
|
7912
7995
|
"",
|
|
7996
|
+
...reviseLines,
|
|
7913
7997
|
"- Draw one self-contained HTML file: CSS and JS inline, no other files, nothing loaded from the network. Build it from the repo's real design tokens and components (read them in the code: colors, type, spacing, radii) and data shaped like the real thing.",
|
|
7914
7998
|
"- Draw it on the screen the change lives on: find that page or component in this checkout and show it as it is today, with the change in place, so a person can compare it with the product. If the change has no screen of its own, draw the one a person sees it from.",
|
|
7915
7999
|
`- Write the HTML only to \`${o.out}\` — that one file, outside this checkout. Write nothing anywhere else.`,
|
|
7916
8000
|
`- Change no code: this checkout is \`origin/${base}\`, for reading. Do not edit, create or delete a file in it, and make no branch, commit, push or PR. The engine checks: a checkout left changed, or a commit, fails the run and nothing is attached.`,
|
|
7917
8001
|
"- Draw no bar or link back to the item: `/a/` adds the item's bar (its key, title and Open in SLEDS) when it serves the mock.",
|
|
7918
8002
|
"- Ask nobody: a mock run cannot park. Where the brief leaves something open, draw the plainest reading and say it in a short note inside the HTML.",
|
|
7919
|
-
"- Once the file is written, stop. The engine reads it and attaches it to the item as its mock, marked as the next version."
|
|
8003
|
+
r ? `- Once the file is written, stop. The engine reads it and attaches it to the item as the next version of \`${r.name}\`.` : "- Once the file is written, stop. The engine reads it and attaches it to the item as its mock, marked as the next version."
|
|
7920
8004
|
];
|
|
7921
8005
|
return `${lines.join(`
|
|
7922
8006
|
`)}
|
|
@@ -8190,10 +8274,12 @@ function eventPrompt(o) {
|
|
|
8190
8274
|
return reviewPrompt({ ...o, event });
|
|
8191
8275
|
return ciTwicePrompt({ ...o, event });
|
|
8192
8276
|
}
|
|
8193
|
-
var DEFAULT_SEAT = "\x00default", MAX_SEAT_AT_ONCE = 16, HOLD_DEFAULTS, DRAFT_NODE = "draft", MOCK_NODE = "mock", 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, HEADER_ITEM_LINK, 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;
|
|
8277
|
+
var DEFAULT_SEAT = "\x00default", MAX_SEAT_AT_ONCE = 16, HOLD_DEFAULTS, DRAFT_NODE = "draft", MOCK_NODE = "mock", 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, ENGINE_DRAFT_LABEL = "Engine draft — not the approved mock", HEADER_ITEM_LINK, 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;
|
|
8194
8278
|
var init_engine = __esm(() => {
|
|
8195
8279
|
init_mockBar();
|
|
8280
|
+
init_pack();
|
|
8196
8281
|
init_prHeader();
|
|
8282
|
+
init_look();
|
|
8197
8283
|
init_route();
|
|
8198
8284
|
HOLD_DEFAULTS = {
|
|
8199
8285
|
holdCpu: 85,
|
|
@@ -8857,86 +8943,6 @@ var init_config = __esm(() => {
|
|
|
8857
8943
|
init_settings();
|
|
8858
8944
|
});
|
|
8859
8945
|
|
|
8860
|
-
// src/meter.ts
|
|
8861
|
-
import { createHash } from "node:crypto";
|
|
8862
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync6, renameSync as renameSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
8863
|
-
import { join as join6 } from "node:path";
|
|
8864
|
-
var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, meterCachePath = (home) => join6(configDir(home), "meter.json"), meterCacheKey = (src) => createHash("sha256").update(`${src.proxyUrl}
|
|
8865
|
-
${src.token}`).digest("hex").slice(0, 16), readMeterCache = (home, now, source) => {
|
|
8866
|
-
const p = meterCachePath(home);
|
|
8867
|
-
if (!existsSync6(p))
|
|
8868
|
-
return null;
|
|
8869
|
-
try {
|
|
8870
|
-
const raw = JSON.parse(readFileSync6(p, "utf8"));
|
|
8871
|
-
if (!isObject7(raw))
|
|
8872
|
-
return null;
|
|
8873
|
-
if (source !== undefined && raw.source !== source)
|
|
8874
|
-
return null;
|
|
8875
|
-
const fetchedAt = num4(raw.fetchedAt);
|
|
8876
|
-
if (fetchedAt === undefined || now - fetchedAt >= METER_CACHE_TTL_MS || fetchedAt > now)
|
|
8877
|
-
return null;
|
|
8878
|
-
return parseMeter(raw.meter);
|
|
8879
|
-
} catch {
|
|
8880
|
-
return null;
|
|
8881
|
-
}
|
|
8882
|
-
}, writeMeterCache = (home, meter, now, source) => {
|
|
8883
|
-
const dir = configDir(home);
|
|
8884
|
-
mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
8885
|
-
const target = meterCachePath(home);
|
|
8886
|
-
const tmp = `${target}.${process.pid}.tmp`;
|
|
8887
|
-
const file = { fetchedAt: now, meter, ...source ? { source } : {} };
|
|
8888
|
-
writeFileSync6(tmp, `${JSON.stringify(file)}
|
|
8889
|
-
`, { mode: 384 });
|
|
8890
|
-
renameSync3(tmp, target);
|
|
8891
|
-
}, fetchMeter = async (o) => {
|
|
8892
|
-
const fetchFn = o.fetchFn ?? fetch;
|
|
8893
|
-
try {
|
|
8894
|
-
const res = await fetchFn(`${o.proxyUrl}/proxy/meter`, {
|
|
8895
|
-
headers: { authorization: `Bearer ${o.token}` },
|
|
8896
|
-
signal: AbortSignal.timeout(o.timeoutMs ?? METER_TIMEOUT_MS)
|
|
8897
|
-
});
|
|
8898
|
-
if (!res.ok)
|
|
8899
|
-
return null;
|
|
8900
|
-
return parseMeter(await res.json());
|
|
8901
|
-
} catch {
|
|
8902
|
-
return null;
|
|
8903
|
-
}
|
|
8904
|
-
}, meterSource = (home, tokenOverride, org) => {
|
|
8905
|
-
const cfg = readConfig(home);
|
|
8906
|
-
const settings = existsSync6(settingsPath(home)) ? readSettings(home) : {};
|
|
8907
|
-
const inSettings = readProxy(settings);
|
|
8908
|
-
const proxyUrl = inSettings?.url ?? cfg.proxyUrl;
|
|
8909
|
-
const picked = selectOrg(cfg, org?.flag, org?.env ?? process.env);
|
|
8910
|
-
if (picked.from === "flag" || picked.from === "env") {
|
|
8911
|
-
const token = tokenOverride ?? picked.seat?.token;
|
|
8912
|
-
return proxyUrl && token ? { proxyUrl, token } : null;
|
|
8913
|
-
}
|
|
8914
|
-
const token = tokenOverride ?? inSettings?.token ?? cfg.token;
|
|
8915
|
-
return proxyUrl && token ? { proxyUrl, token } : null;
|
|
8916
|
-
}, loadMeter = async (o) => {
|
|
8917
|
-
const now = o.now ?? Date.now();
|
|
8918
|
-
const src = meterSource(o.home, undefined, { env: o.env });
|
|
8919
|
-
if (!src)
|
|
8920
|
-
return null;
|
|
8921
|
-
const key = meterCacheKey(src);
|
|
8922
|
-
const cached = readMeterCache(o.home, now, key);
|
|
8923
|
-
if (cached)
|
|
8924
|
-
return cached;
|
|
8925
|
-
const fresh = await fetchMeter({ ...src, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs });
|
|
8926
|
-
if (fresh) {
|
|
8927
|
-
try {
|
|
8928
|
-
writeMeterCache(o.home, fresh, now, key);
|
|
8929
|
-
} catch {}
|
|
8930
|
-
}
|
|
8931
|
-
return fresh;
|
|
8932
|
-
};
|
|
8933
|
-
var init_meter = __esm(() => {
|
|
8934
|
-
init_format();
|
|
8935
|
-
init_config();
|
|
8936
|
-
init_settings();
|
|
8937
|
-
init_format();
|
|
8938
|
-
});
|
|
8939
|
-
|
|
8940
8946
|
// ../../packages/shared/src/index.ts
|
|
8941
8947
|
var init_src = __esm(() => {
|
|
8942
8948
|
init_pricing();
|
|
@@ -8966,6 +8972,7 @@ var init_src = __esm(() => {
|
|
|
8966
8972
|
init_agent();
|
|
8967
8973
|
init_copy();
|
|
8968
8974
|
init_channel();
|
|
8975
|
+
init_verification();
|
|
8969
8976
|
init_productHits();
|
|
8970
8977
|
init_model();
|
|
8971
8978
|
init_parse();
|
|
@@ -9005,6 +9012,7 @@ var init_src = __esm(() => {
|
|
|
9005
9012
|
init_reshape();
|
|
9006
9013
|
init_say();
|
|
9007
9014
|
init_engine();
|
|
9015
|
+
init_look();
|
|
9008
9016
|
init_sources();
|
|
9009
9017
|
init_verdict();
|
|
9010
9018
|
init_seatNeeded();
|
|
@@ -9015,7 +9023,7 @@ var init_src = __esm(() => {
|
|
|
9015
9023
|
});
|
|
9016
9024
|
|
|
9017
9025
|
// src/engine/json.ts
|
|
9018
|
-
var
|
|
9026
|
+
var isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), str7 = (v) => typeof v === "string" ? v : undefined, num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
9019
9027
|
|
|
9020
9028
|
// src/engine/machine.ts
|
|
9021
9029
|
import { cpus as osCpus, loadavg as osLoadavg } from "node:os";
|
|
@@ -9118,7 +9126,7 @@ function machineAllows(sample, atOnce, thresholds = DEFAULT_THRESHOLDS, prev) {
|
|
|
9118
9126
|
};
|
|
9119
9127
|
}
|
|
9120
9128
|
function parseMachineSample(v) {
|
|
9121
|
-
if (!
|
|
9129
|
+
if (!isObject7(v))
|
|
9122
9130
|
return;
|
|
9123
9131
|
const { at, cpuPct, load1, cores, loadPerCore, pressure } = v;
|
|
9124
9132
|
const nums = [at, cpuPct, load1, cores, loadPerCore];
|
|
@@ -9134,7 +9142,7 @@ function parseMachineSample(v) {
|
|
|
9134
9142
|
};
|
|
9135
9143
|
}
|
|
9136
9144
|
function parseMachineHold(v) {
|
|
9137
|
-
if (!
|
|
9145
|
+
if (!isObject7(v) || v.reason !== "machine busy")
|
|
9138
9146
|
return;
|
|
9139
9147
|
if (v.level !== "strained" && v.level !== "busy")
|
|
9140
9148
|
return;
|
|
@@ -9157,36 +9165,36 @@ var init_machine = __esm(() => {
|
|
|
9157
9165
|
|
|
9158
9166
|
// src/engine/state.ts
|
|
9159
9167
|
import {
|
|
9160
|
-
existsSync as
|
|
9168
|
+
existsSync as existsSync6,
|
|
9161
9169
|
linkSync,
|
|
9162
|
-
mkdirSync as
|
|
9163
|
-
readFileSync as
|
|
9164
|
-
renameSync as
|
|
9170
|
+
mkdirSync as mkdirSync6,
|
|
9171
|
+
readFileSync as readFileSync6,
|
|
9172
|
+
renameSync as renameSync3,
|
|
9165
9173
|
rmSync,
|
|
9166
|
-
writeFileSync as
|
|
9174
|
+
writeFileSync as writeFileSync6
|
|
9167
9175
|
} from "node:fs";
|
|
9168
|
-
import { dirname as
|
|
9176
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
9169
9177
|
function engineSlug(engine) {
|
|
9170
9178
|
return slugify(engine.replace(/^engine:/, ""), 80) || "engine";
|
|
9171
9179
|
}
|
|
9172
9180
|
function orgStateDir(stateDir, org) {
|
|
9173
|
-
return org ?
|
|
9181
|
+
return org ? join7(stateDir, "orgs", slugify(org, 80) || "org") : stateDir;
|
|
9174
9182
|
}
|
|
9175
9183
|
function adoptLegacyState(stateDir, org, engine, pidAlive) {
|
|
9176
9184
|
const from = statePath(stateDir, engine);
|
|
9177
9185
|
const to = statePath(orgStateDir(stateDir, org), engine);
|
|
9178
|
-
if (!
|
|
9186
|
+
if (!existsSync6(from) || existsSync6(to))
|
|
9179
9187
|
return false;
|
|
9180
9188
|
const held = readLock(lockPath(stateDir, engine));
|
|
9181
9189
|
if (held && pidAlive(held.pid))
|
|
9182
9190
|
return false;
|
|
9183
|
-
|
|
9184
|
-
|
|
9191
|
+
mkdirSync6(dirname5(to), { recursive: true, mode: 448 });
|
|
9192
|
+
renameSync3(from, to);
|
|
9185
9193
|
return true;
|
|
9186
9194
|
}
|
|
9187
9195
|
function seatStateDir(orgDir, email) {
|
|
9188
9196
|
const slug = email?.trim() ? slugify(email.trim(), 80) : "";
|
|
9189
|
-
return slug ?
|
|
9197
|
+
return slug ? join7(orgDir, "seats", slug) : orgDir;
|
|
9190
9198
|
}
|
|
9191
9199
|
function adoptOrgState(orgDir, email, engine, pidAlive) {
|
|
9192
9200
|
const seatDir = seatStateDir(orgDir, email);
|
|
@@ -9194,23 +9202,23 @@ function adoptOrgState(orgDir, email, engine, pidAlive) {
|
|
|
9194
9202
|
return false;
|
|
9195
9203
|
const from = statePath(orgDir, engine);
|
|
9196
9204
|
const to = statePath(seatDir, engine);
|
|
9197
|
-
if (!
|
|
9205
|
+
if (!existsSync6(from) || existsSync6(to))
|
|
9198
9206
|
return false;
|
|
9199
9207
|
const held = readLock(lockPath(orgDir, engine));
|
|
9200
9208
|
if (held && pidAlive(held.pid))
|
|
9201
9209
|
return false;
|
|
9202
|
-
|
|
9203
|
-
|
|
9210
|
+
mkdirSync6(dirname5(to), { recursive: true, mode: 448 });
|
|
9211
|
+
renameSync3(from, to);
|
|
9204
9212
|
return true;
|
|
9205
9213
|
}
|
|
9206
9214
|
function statePath(stateDir, engine) {
|
|
9207
|
-
return
|
|
9215
|
+
return join7(stateDir, `${engineSlug(engine)}.json`);
|
|
9208
9216
|
}
|
|
9209
9217
|
function lockPath(stateDir, engine) {
|
|
9210
|
-
return
|
|
9218
|
+
return join7(stateDir, `${engineSlug(engine)}.lock`);
|
|
9211
9219
|
}
|
|
9212
9220
|
function parseHandle(handle) {
|
|
9213
|
-
if (!
|
|
9221
|
+
if (!isObject7(handle))
|
|
9214
9222
|
return null;
|
|
9215
9223
|
if (typeof handle.runner !== "string" || typeof handle.id !== "string")
|
|
9216
9224
|
return null;
|
|
@@ -9222,14 +9230,14 @@ function parseHandle(handle) {
|
|
|
9222
9230
|
cwd: handle.cwd,
|
|
9223
9231
|
...typeof handle.log === "string" ? { log: handle.log } : {},
|
|
9224
9232
|
...typeof handle.group === "string" ? { group: handle.group } : {},
|
|
9225
|
-
...
|
|
9233
|
+
...isObject7(handle.own) && typeof handle.own.branch === "string" && typeof handle.own.head === "string" ? { own: { branch: handle.own.branch, head: handle.own.head } } : {}
|
|
9226
9234
|
};
|
|
9227
9235
|
}
|
|
9228
9236
|
function parseDecisionEvent(v) {
|
|
9229
|
-
if (!
|
|
9237
|
+
if (!isObject7(v) || typeof v.node !== "string" || typeof v.pr !== "string")
|
|
9230
9238
|
return null;
|
|
9231
9239
|
if (v.kind === "landed") {
|
|
9232
|
-
const downstream = Array.isArray(v.downstream) ? v.downstream.filter(
|
|
9240
|
+
const downstream = Array.isArray(v.downstream) ? v.downstream.filter(isObject7).flatMap((n) => typeof n.key === "string" ? [
|
|
9233
9241
|
{
|
|
9234
9242
|
key: n.key,
|
|
9235
9243
|
title: typeof n.title === "string" ? n.title : n.key,
|
|
@@ -9293,7 +9301,7 @@ function parseDecisionEvent(v) {
|
|
|
9293
9301
|
return null;
|
|
9294
9302
|
}
|
|
9295
9303
|
function parsePlan(v) {
|
|
9296
|
-
if (!
|
|
9304
|
+
if (!isObject7(v))
|
|
9297
9305
|
return;
|
|
9298
9306
|
const plan = {
|
|
9299
9307
|
...typeof v.approach === "string" ? { approach: v.approach } : {},
|
|
@@ -9304,7 +9312,7 @@ function parsePlan(v) {
|
|
|
9304
9312
|
return Object.keys(plan).length ? plan : undefined;
|
|
9305
9313
|
}
|
|
9306
9314
|
function parseDecision(v) {
|
|
9307
|
-
if (!
|
|
9315
|
+
if (!isObject7(v))
|
|
9308
9316
|
return null;
|
|
9309
9317
|
const { item, node, decisionId, repoPath, cwd } = v;
|
|
9310
9318
|
if (typeof item !== "string" || typeof node !== "string")
|
|
@@ -9314,7 +9322,7 @@ function parseDecision(v) {
|
|
|
9314
9322
|
const event = parseDecisionEvent(v.event);
|
|
9315
9323
|
if (!event)
|
|
9316
9324
|
return null;
|
|
9317
|
-
const a =
|
|
9325
|
+
const a = isObject7(v.answerer) ? v.answerer : null;
|
|
9318
9326
|
const handle = a ? parseHandle(a.handle) : null;
|
|
9319
9327
|
return {
|
|
9320
9328
|
item,
|
|
@@ -9338,7 +9346,7 @@ function parseDecision(v) {
|
|
|
9338
9346
|
};
|
|
9339
9347
|
}
|
|
9340
9348
|
function parseConflicted(v) {
|
|
9341
|
-
if (!
|
|
9349
|
+
if (!isObject7(v) || typeof v.base !== "string" || typeof v.since !== "number")
|
|
9342
9350
|
return;
|
|
9343
9351
|
const at = (k) => typeof v[k] === "number" ? { [k]: v[k] } : {};
|
|
9344
9352
|
return {
|
|
@@ -9353,19 +9361,19 @@ function parseConflicted(v) {
|
|
|
9353
9361
|
};
|
|
9354
9362
|
}
|
|
9355
9363
|
function parseMerged(v) {
|
|
9356
|
-
if (!
|
|
9364
|
+
if (!isObject7(v))
|
|
9357
9365
|
return null;
|
|
9358
9366
|
const { item, node, url, repoPath } = v;
|
|
9359
9367
|
return typeof item === "string" && typeof node === "string" && typeof url === "string" && typeof repoPath === "string" ? { item, node, url, repoPath } : null;
|
|
9360
9368
|
}
|
|
9361
9369
|
function parseParked(v) {
|
|
9362
|
-
if (!
|
|
9370
|
+
if (!isObject7(v) || typeof v.question !== "string" || typeof v.at !== "number")
|
|
9363
9371
|
return;
|
|
9364
9372
|
const a = v.answerer;
|
|
9365
9373
|
let answerer;
|
|
9366
|
-
if (
|
|
9374
|
+
if (isObject7(a) && (a.ended === "answered" || a.ended === "escalated" || a.ended === "none")) {
|
|
9367
9375
|
answerer = { ended: a.ended };
|
|
9368
|
-
} else if (
|
|
9376
|
+
} else if (isObject7(a) && typeof a.decisionId === "string" && typeof a.runId === "string" && typeof a.until === "number") {
|
|
9369
9377
|
const handle = parseHandle(a.handle);
|
|
9370
9378
|
if (handle)
|
|
9371
9379
|
answerer = {
|
|
@@ -9387,7 +9395,7 @@ function parseParked(v) {
|
|
|
9387
9395
|
};
|
|
9388
9396
|
}
|
|
9389
9397
|
function parseRun(v) {
|
|
9390
|
-
if (!
|
|
9398
|
+
if (!isObject7(v))
|
|
9391
9399
|
return null;
|
|
9392
9400
|
const { item, node, title, branch, repoPath, startedAt } = v;
|
|
9393
9401
|
if (typeof item !== "string" || typeof node !== "string")
|
|
@@ -9398,13 +9406,13 @@ function parseRun(v) {
|
|
|
9398
9406
|
if (!handle)
|
|
9399
9407
|
return null;
|
|
9400
9408
|
const parked = parseParked(v.parked);
|
|
9401
|
-
const conflicted =
|
|
9409
|
+
const conflicted = isObject7(v.pr) ? parseConflicted(v.pr.conflicted) : undefined;
|
|
9402
9410
|
return {
|
|
9403
9411
|
item,
|
|
9404
9412
|
node,
|
|
9405
9413
|
title: typeof title === "string" ? title : "",
|
|
9406
9414
|
...v.kind === "draft" || v.kind === "mock" ? { kind: v.kind } : {},
|
|
9407
|
-
...
|
|
9415
|
+
...isObject7(v.mock) && typeof v.mock.out === "string" && typeof v.mock.base === "string" ? {
|
|
9408
9416
|
mock: {
|
|
9409
9417
|
out: v.mock.out,
|
|
9410
9418
|
base: v.mock.base,
|
|
@@ -9417,7 +9425,7 @@ function parseRun(v) {
|
|
|
9417
9425
|
...typeof v.leaseUntil === "number" ? { leaseUntil: v.leaseUntil } : {},
|
|
9418
9426
|
...typeof v.mcpConfig === "string" ? { mcpConfig: v.mcpConfig } : {},
|
|
9419
9427
|
...v.onRunToken === true ? { onRunToken: true } : {},
|
|
9420
|
-
...
|
|
9428
|
+
...isObject7(v.group) && typeof v.group.key === "string" && typeof v.group.title === "string" ? { group: { key: v.group.key, title: v.group.title } } : {},
|
|
9421
9429
|
...typeof v.ticket === "string" ? { ticket: v.ticket } : {},
|
|
9422
9430
|
branch,
|
|
9423
9431
|
repoPath,
|
|
@@ -9428,7 +9436,7 @@ function parseRun(v) {
|
|
|
9428
9436
|
...typeof v.seenTicks === "number" ? { seenTicks: v.seenTicks } : {},
|
|
9429
9437
|
...typeof v.answeredAt === "number" ? { answeredAt: v.answeredAt } : {},
|
|
9430
9438
|
...typeof v.band === "string" ? { band: v.band } : {},
|
|
9431
|
-
...
|
|
9439
|
+
...isObject7(v.permission) && typeof v.permission.decisionId === "string" && typeof v.permission.at === "number" ? {
|
|
9432
9440
|
permission: {
|
|
9433
9441
|
decisionId: v.permission.decisionId,
|
|
9434
9442
|
options: Array.isArray(v.permission.options) ? v.permission.options.filter((x) => typeof x === "string") : [],
|
|
@@ -9441,17 +9449,17 @@ function parseRun(v) {
|
|
|
9441
9449
|
...v.permission.gaveUp === true ? { gaveUp: true } : {}
|
|
9442
9450
|
}
|
|
9443
9451
|
} : {},
|
|
9444
|
-
...
|
|
9445
|
-
...
|
|
9452
|
+
...isObject7(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 } } : {},
|
|
9453
|
+
...isObject7(v.atPrompt) && typeof v.atPrompt.since === "number" && typeof v.atPrompt.text === "string" ? { atPrompt: { since: v.atPrompt.since, text: v.atPrompt.text } } : {},
|
|
9446
9454
|
...parked ? { parked } : {},
|
|
9447
|
-
...
|
|
9455
|
+
...isObject7(v.pr) && typeof v.pr.url === "string" ? {
|
|
9448
9456
|
pr: {
|
|
9449
9457
|
url: v.pr.url,
|
|
9450
9458
|
failing: Array.isArray(v.pr.failing) ? v.pr.failing.filter((x) => typeof x === "string") : [],
|
|
9451
9459
|
feedback: typeof v.pr.feedback === "number" ? v.pr.feedback : 0,
|
|
9452
9460
|
...typeof v.pr.authorFeedback === "number" ? { authorFeedback: v.pr.authorFeedback } : {},
|
|
9453
9461
|
...typeof v.pr.selfNudges === "number" ? { selfNudges: v.pr.selfNudges } : {},
|
|
9454
|
-
...
|
|
9462
|
+
...isObject7(v.pr.feedbackRead) && typeof v.pr.feedbackRead.updatedAt === "string" && typeof v.pr.feedbackRead.all === "number" && typeof v.pr.feedbackRead.author === "number" && typeof v.pr.feedbackRead.at === "number" ? {
|
|
9455
9463
|
feedbackRead: {
|
|
9456
9464
|
updatedAt: v.pr.feedbackRead.updatedAt,
|
|
9457
9465
|
all: v.pr.feedbackRead.all,
|
|
@@ -9467,13 +9475,14 @@ function parseRun(v) {
|
|
|
9467
9475
|
...typeof v.pr.posted === "string" ? { posted: v.pr.posted } : {},
|
|
9468
9476
|
...Array.isArray(v.pr.failedHeads) ? { failedHeads: v.pr.failedHeads.filter((x) => typeof x === "string") } : {},
|
|
9469
9477
|
...typeof v.pr.conflict === "string" ? { conflict: v.pr.conflict } : {},
|
|
9470
|
-
...
|
|
9478
|
+
...isObject7(v.pr.conflictCheck) && typeof v.pr.conflictCheck.head === "string" && typeof v.pr.conflictCheck.at === "number" ? { conflictCheck: { head: v.pr.conflictCheck.head, at: v.pr.conflictCheck.at } } : {},
|
|
9471
9479
|
...typeof v.pr.resolving === "string" ? { resolving: v.pr.resolving } : {},
|
|
9472
9480
|
...conflicted ? { conflicted } : {},
|
|
9473
9481
|
...typeof v.pr.reviewed === "string" ? { reviewed: v.pr.reviewed } : {},
|
|
9474
9482
|
...typeof v.pr.look === "string" ? { look: v.pr.look } : {},
|
|
9483
|
+
...typeof v.pr.lookWait === "number" ? { lookWait: v.pr.lookWait } : {},
|
|
9475
9484
|
...typeof v.pr.instructAt === "number" ? { instructAt: v.pr.instructAt } : {},
|
|
9476
|
-
...
|
|
9485
|
+
...isObject7(v.pr.instructed) && Array.isArray(v.pr.instructed.ids) && (v.pr.instructed.how === "told" || v.pr.instructed.how === "restarted") ? {
|
|
9477
9486
|
instructed: {
|
|
9478
9487
|
ids: v.pr.instructed.ids.filter((x) => typeof x === "string"),
|
|
9479
9488
|
how: v.pr.instructed.how
|
|
@@ -9488,11 +9497,11 @@ function parseRun(v) {
|
|
|
9488
9497
|
function parseState(text) {
|
|
9489
9498
|
try {
|
|
9490
9499
|
const raw = JSON.parse(text);
|
|
9491
|
-
if (!
|
|
9500
|
+
if (!isObject7(raw) || !Array.isArray(raw.runs))
|
|
9492
9501
|
return { runs: [] };
|
|
9493
9502
|
const decisions = Array.isArray(raw.decisions) ? raw.decisions.map(parseDecision).filter((x) => x !== null) : [];
|
|
9494
9503
|
const merged = Array.isArray(raw.merged) ? raw.merged.map(parseMerged).filter((x) => x !== null) : [];
|
|
9495
|
-
const slowStarts =
|
|
9504
|
+
const slowStarts = isObject7(raw.slowStarts) ? Object.fromEntries(Object.entries(raw.slowStarts).filter((e) => typeof e[1] === "number" && e[1] > 0)) : {};
|
|
9496
9505
|
return {
|
|
9497
9506
|
runs: raw.runs.map(parseRun).filter((r) => r !== null),
|
|
9498
9507
|
...decisions.length ? { decisions } : {},
|
|
@@ -9506,14 +9515,14 @@ function parseState(text) {
|
|
|
9506
9515
|
function stateVersion(text) {
|
|
9507
9516
|
try {
|
|
9508
9517
|
const raw = JSON.parse(text);
|
|
9509
|
-
return
|
|
9518
|
+
return isObject7(raw) && typeof raw.v === "number" ? raw.v : 1;
|
|
9510
9519
|
} catch {
|
|
9511
9520
|
return 1;
|
|
9512
9521
|
}
|
|
9513
9522
|
}
|
|
9514
9523
|
function readState(path) {
|
|
9515
9524
|
try {
|
|
9516
|
-
return parseState(
|
|
9525
|
+
return parseState(readFileSync6(path, "utf8"));
|
|
9517
9526
|
} catch {
|
|
9518
9527
|
return { runs: [] };
|
|
9519
9528
|
}
|
|
@@ -9521,7 +9530,7 @@ function readState(path) {
|
|
|
9521
9530
|
function readStateFile(path) {
|
|
9522
9531
|
let text;
|
|
9523
9532
|
try {
|
|
9524
|
-
text =
|
|
9533
|
+
text = readFileSync6(path, "utf8");
|
|
9525
9534
|
} catch {
|
|
9526
9535
|
return { state: { runs: [] } };
|
|
9527
9536
|
}
|
|
@@ -9533,18 +9542,18 @@ function readStateFile(path) {
|
|
|
9533
9542
|
return { state: parseState(text) };
|
|
9534
9543
|
}
|
|
9535
9544
|
function writeState(path, state) {
|
|
9536
|
-
|
|
9545
|
+
mkdirSync6(dirname5(path), { recursive: true, mode: 448 });
|
|
9537
9546
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
9538
|
-
|
|
9547
|
+
writeFileSync6(tmp, `${JSON.stringify({ v: STATE_VERSION, ...state }, null, 2)}
|
|
9539
9548
|
`, {
|
|
9540
9549
|
mode: 384
|
|
9541
9550
|
});
|
|
9542
|
-
|
|
9551
|
+
renameSync3(tmp, path);
|
|
9543
9552
|
}
|
|
9544
9553
|
function parseLock(text) {
|
|
9545
9554
|
try {
|
|
9546
9555
|
const v = JSON.parse(text);
|
|
9547
|
-
if (!
|
|
9556
|
+
if (!isObject7(v))
|
|
9548
9557
|
return null;
|
|
9549
9558
|
const { engine, pid, host, startedAt } = v;
|
|
9550
9559
|
if (typeof engine !== "string" || typeof host !== "string")
|
|
@@ -9555,7 +9564,7 @@ function parseLock(text) {
|
|
|
9555
9564
|
const machine = parseMachineSample(v.machine);
|
|
9556
9565
|
const hold = parseMachineHold(v.hold);
|
|
9557
9566
|
const rh = v.runnerHold;
|
|
9558
|
-
const runnerHold =
|
|
9567
|
+
const runnerHold = isObject7(rh) && typeof rh.why === "string" && rh.why && typeof rh.since === "number" ? { why: rh.why, since: rh.since } : undefined;
|
|
9559
9568
|
return {
|
|
9560
9569
|
v: n(v.v, 1),
|
|
9561
9570
|
engine,
|
|
@@ -9579,24 +9588,24 @@ function parseLock(text) {
|
|
|
9579
9588
|
}
|
|
9580
9589
|
function readLock(path) {
|
|
9581
9590
|
try {
|
|
9582
|
-
return parseLock(
|
|
9591
|
+
return parseLock(readFileSync6(path, "utf8"));
|
|
9583
9592
|
} catch {
|
|
9584
9593
|
return null;
|
|
9585
9594
|
}
|
|
9586
9595
|
}
|
|
9587
9596
|
function writeLock(path, lock) {
|
|
9588
|
-
|
|
9597
|
+
mkdirSync6(dirname5(path), { recursive: true, mode: 448 });
|
|
9589
9598
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
9590
|
-
|
|
9599
|
+
writeFileSync6(tmp, `${JSON.stringify(lock, null, 2)}
|
|
9591
9600
|
`, { mode: 384 });
|
|
9592
|
-
|
|
9601
|
+
renameSync3(tmp, path);
|
|
9593
9602
|
}
|
|
9594
9603
|
function claimLock(path, lock, pidAlive) {
|
|
9595
9604
|
const live = (held) => held !== null && held.host === lock.host && held.pid !== lock.pid && pidAlive(held.pid);
|
|
9596
|
-
|
|
9605
|
+
mkdirSync6(dirname5(path), { recursive: true, mode: 448 });
|
|
9597
9606
|
const tmp = `${path}.${lock.pid}.tmp`;
|
|
9598
9607
|
const aside = `${path}.${lock.pid}.stale`;
|
|
9599
|
-
|
|
9608
|
+
writeFileSync6(tmp, `${JSON.stringify(lock, null, 2)}
|
|
9600
9609
|
`, { mode: 384 });
|
|
9601
9610
|
try {
|
|
9602
9611
|
for (let i = 0;i < 3; i++) {
|
|
@@ -9611,7 +9620,7 @@ function claimLock(path, lock, pidAlive) {
|
|
|
9611
9620
|
if (live(held))
|
|
9612
9621
|
return held;
|
|
9613
9622
|
try {
|
|
9614
|
-
|
|
9623
|
+
renameSync3(path, aside);
|
|
9615
9624
|
} catch (e) {
|
|
9616
9625
|
if (e.code === "ENOENT")
|
|
9617
9626
|
continue;
|
|
@@ -9636,7 +9645,7 @@ function clearLock(path, pid) {
|
|
|
9636
9645
|
rmSync(path, { force: true });
|
|
9637
9646
|
}
|
|
9638
9647
|
function removedEnginesPath(seatDir) {
|
|
9639
|
-
return
|
|
9648
|
+
return join7(seatDir, "removed-engines.json");
|
|
9640
9649
|
}
|
|
9641
9650
|
function parseRemovedEngines(text) {
|
|
9642
9651
|
let raw;
|
|
@@ -9645,10 +9654,10 @@ function parseRemovedEngines(text) {
|
|
|
9645
9654
|
} catch {
|
|
9646
9655
|
return [];
|
|
9647
9656
|
}
|
|
9648
|
-
const list =
|
|
9657
|
+
const list = isObject7(raw) && Array.isArray(raw.engines) ? raw.engines : [];
|
|
9649
9658
|
const out = [];
|
|
9650
9659
|
for (const e of list) {
|
|
9651
|
-
if (!
|
|
9660
|
+
if (!isObject7(e) || typeof e.name !== "string" || !e.name)
|
|
9652
9661
|
continue;
|
|
9653
9662
|
if (!Array.isArray(e.args) || !e.args.every((a) => typeof a === "string"))
|
|
9654
9663
|
continue;
|
|
@@ -9663,7 +9672,7 @@ function parseRemovedEngines(text) {
|
|
|
9663
9672
|
}
|
|
9664
9673
|
function readRemovedEngines(seatDir) {
|
|
9665
9674
|
try {
|
|
9666
|
-
return parseRemovedEngines(
|
|
9675
|
+
return parseRemovedEngines(readFileSync6(removedEnginesPath(seatDir), "utf8"));
|
|
9667
9676
|
} catch {
|
|
9668
9677
|
return [];
|
|
9669
9678
|
}
|
|
@@ -9674,8 +9683,8 @@ function writeRemovedEngines(seatDir, engines) {
|
|
|
9674
9683
|
rmSync(path, { force: true });
|
|
9675
9684
|
return;
|
|
9676
9685
|
}
|
|
9677
|
-
|
|
9678
|
-
|
|
9686
|
+
mkdirSync6(seatDir, { recursive: true, mode: 448 });
|
|
9687
|
+
writeFileSync6(path, `${JSON.stringify({ v: 1, engines }, null, 2)}
|
|
9679
9688
|
`, { mode: 384 });
|
|
9680
9689
|
}
|
|
9681
9690
|
var STATE_VERSION = 1, strs = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
@@ -9684,6 +9693,86 @@ var init_state = __esm(() => {
|
|
|
9684
9693
|
init_machine();
|
|
9685
9694
|
});
|
|
9686
9695
|
|
|
9696
|
+
// src/meter.ts
|
|
9697
|
+
import { createHash } from "node:crypto";
|
|
9698
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync7, renameSync as renameSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
9699
|
+
import { join as join8 } from "node:path";
|
|
9700
|
+
var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num5 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, meterCachePath = (home) => join8(configDir(home), "meter.json"), meterCacheKey = (src) => createHash("sha256").update(`${src.proxyUrl}
|
|
9701
|
+
${src.token}`).digest("hex").slice(0, 16), readMeterCache = (home, now, source) => {
|
|
9702
|
+
const p = meterCachePath(home);
|
|
9703
|
+
if (!existsSync7(p))
|
|
9704
|
+
return null;
|
|
9705
|
+
try {
|
|
9706
|
+
const raw = JSON.parse(readFileSync7(p, "utf8"));
|
|
9707
|
+
if (!isObject8(raw))
|
|
9708
|
+
return null;
|
|
9709
|
+
if (source !== undefined && raw.source !== source)
|
|
9710
|
+
return null;
|
|
9711
|
+
const fetchedAt = num5(raw.fetchedAt);
|
|
9712
|
+
if (fetchedAt === undefined || now - fetchedAt >= METER_CACHE_TTL_MS || fetchedAt > now)
|
|
9713
|
+
return null;
|
|
9714
|
+
return parseMeter(raw.meter);
|
|
9715
|
+
} catch {
|
|
9716
|
+
return null;
|
|
9717
|
+
}
|
|
9718
|
+
}, writeMeterCache = (home, meter, now, source) => {
|
|
9719
|
+
const dir = configDir(home);
|
|
9720
|
+
mkdirSync7(dir, { recursive: true, mode: 448 });
|
|
9721
|
+
const target = meterCachePath(home);
|
|
9722
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
9723
|
+
const file = { fetchedAt: now, meter, ...source ? { source } : {} };
|
|
9724
|
+
writeFileSync7(tmp, `${JSON.stringify(file)}
|
|
9725
|
+
`, { mode: 384 });
|
|
9726
|
+
renameSync4(tmp, target);
|
|
9727
|
+
}, fetchMeter = async (o) => {
|
|
9728
|
+
const fetchFn = o.fetchFn ?? fetch;
|
|
9729
|
+
try {
|
|
9730
|
+
const res = await fetchFn(`${o.proxyUrl}/proxy/meter`, {
|
|
9731
|
+
headers: { authorization: `Bearer ${o.token}` },
|
|
9732
|
+
signal: AbortSignal.timeout(o.timeoutMs ?? METER_TIMEOUT_MS)
|
|
9733
|
+
});
|
|
9734
|
+
if (!res.ok)
|
|
9735
|
+
return null;
|
|
9736
|
+
return parseMeter(await res.json());
|
|
9737
|
+
} catch {
|
|
9738
|
+
return null;
|
|
9739
|
+
}
|
|
9740
|
+
}, meterSource = (home, tokenOverride, org) => {
|
|
9741
|
+
const cfg = readConfig(home);
|
|
9742
|
+
const settings = existsSync7(settingsPath(home)) ? readSettings(home) : {};
|
|
9743
|
+
const inSettings = readProxy(settings);
|
|
9744
|
+
const proxyUrl = inSettings?.url ?? cfg.proxyUrl;
|
|
9745
|
+
const picked = selectOrg(cfg, org?.flag, org?.env ?? process.env);
|
|
9746
|
+
if (picked.from === "flag" || picked.from === "env") {
|
|
9747
|
+
const token = tokenOverride ?? picked.seat?.token;
|
|
9748
|
+
return proxyUrl && token ? { proxyUrl, token } : null;
|
|
9749
|
+
}
|
|
9750
|
+
const token = tokenOverride ?? inSettings?.token ?? cfg.token;
|
|
9751
|
+
return proxyUrl && token ? { proxyUrl, token } : null;
|
|
9752
|
+
}, loadMeter = async (o) => {
|
|
9753
|
+
const now = o.now ?? Date.now();
|
|
9754
|
+
const src = meterSource(o.home, undefined, { env: o.env });
|
|
9755
|
+
if (!src)
|
|
9756
|
+
return null;
|
|
9757
|
+
const key = meterCacheKey(src);
|
|
9758
|
+
const cached = readMeterCache(o.home, now, key);
|
|
9759
|
+
if (cached)
|
|
9760
|
+
return cached;
|
|
9761
|
+
const fresh = await fetchMeter({ ...src, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs });
|
|
9762
|
+
if (fresh) {
|
|
9763
|
+
try {
|
|
9764
|
+
writeMeterCache(o.home, fresh, now, key);
|
|
9765
|
+
} catch {}
|
|
9766
|
+
}
|
|
9767
|
+
return fresh;
|
|
9768
|
+
};
|
|
9769
|
+
var init_meter = __esm(() => {
|
|
9770
|
+
init_format();
|
|
9771
|
+
init_config();
|
|
9772
|
+
init_settings();
|
|
9773
|
+
init_format();
|
|
9774
|
+
});
|
|
9775
|
+
|
|
9687
9776
|
// src/seat.ts
|
|
9688
9777
|
var SEAT_POST_MIN_INTERVAL_MS2, readStdin2 = (timeoutMs, stdin = process.stdin) => new Promise((resolve) => {
|
|
9689
9778
|
if (stdin.isTTY) {
|
|
@@ -9748,6 +9837,7 @@ init_mention();
|
|
|
9748
9837
|
init_agent();
|
|
9749
9838
|
init_copy();
|
|
9750
9839
|
init_channel();
|
|
9840
|
+
init_verification();
|
|
9751
9841
|
init_productHits();
|
|
9752
9842
|
init_model();
|
|
9753
9843
|
init_parse();
|
|
@@ -9787,6 +9877,7 @@ init_routeFix();
|
|
|
9787
9877
|
init_reshape();
|
|
9788
9878
|
init_say();
|
|
9789
9879
|
init_engine();
|
|
9880
|
+
init_look();
|
|
9790
9881
|
init_sources();
|
|
9791
9882
|
init_verdict();
|
|
9792
9883
|
init_seatNeeded();
|
|
@@ -10066,339 +10157,10 @@ function runCodex(home, args, deps = {}) {
|
|
|
10066
10157
|
return r.status ?? 1;
|
|
10067
10158
|
}
|
|
10068
10159
|
|
|
10069
|
-
// src/commands/
|
|
10070
|
-
|
|
10160
|
+
// src/commands/attach.ts
|
|
10161
|
+
init_server();
|
|
10071
10162
|
import { readFileSync as readFileSync16, statSync as statSync7 } from "node:fs";
|
|
10072
|
-
import { basename as
|
|
10073
|
-
|
|
10074
|
-
// src/musher.ts
|
|
10075
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
10076
|
-
import { createPublicKey, verify as cryptoVerify } from "node:crypto";
|
|
10077
|
-
import { basename as basename2, dirname as dirname5, join as join7 } from "node:path";
|
|
10078
|
-
var MUSHER_LABEL = "ai.sleds.musher";
|
|
10079
|
-
var MUSHER_INTERVAL_S = 300;
|
|
10080
|
-
var DEFAULT_PERMISSION_MODE = "acceptEdits";
|
|
10081
|
-
var PERMISSION_MODES = [
|
|
10082
|
-
"acceptEdits",
|
|
10083
|
-
"auto",
|
|
10084
|
-
"bypassPermissions",
|
|
10085
|
-
"default",
|
|
10086
|
-
"dontAsk",
|
|
10087
|
-
"plan"
|
|
10088
|
-
];
|
|
10089
|
-
var DEFAULT_TIMEOUT_MINUTES = 90;
|
|
10090
|
-
var SUMMARY_MAX = 2000;
|
|
10091
|
-
var musherLabel = (env = process.env) => {
|
|
10092
|
-
const sh = env.SLEDS_HOME?.trim();
|
|
10093
|
-
if (!sh)
|
|
10094
|
-
return MUSHER_LABEL;
|
|
10095
|
-
const tag = basename2(sh).replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]+/g, "-") || "seat";
|
|
10096
|
-
return `${MUSHER_LABEL}.${tag}`;
|
|
10097
|
-
};
|
|
10098
|
-
var musherPlistPath = (home, env = process.env) => join7(home, "Library", "LaunchAgents", `${musherLabel(env)}.plist`);
|
|
10099
|
-
var musherLogPath = (configDir) => join7(configDir, "musher.log");
|
|
10100
|
-
var xmlEscape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
10101
|
-
var musherPath = (home, execPath, currentPath = "") => {
|
|
10102
|
-
const parts = [
|
|
10103
|
-
dirname5(execPath),
|
|
10104
|
-
join7(home, ".sleds", "bin"),
|
|
10105
|
-
join7(home, ".local", "bin"),
|
|
10106
|
-
join7(home, ".bun", "bin"),
|
|
10107
|
-
"/opt/homebrew/bin",
|
|
10108
|
-
"/usr/local/bin",
|
|
10109
|
-
"/usr/bin",
|
|
10110
|
-
"/bin",
|
|
10111
|
-
...currentPath.split(":").filter(Boolean)
|
|
10112
|
-
];
|
|
10113
|
-
return [...new Set(parts)].join(":");
|
|
10114
|
-
};
|
|
10115
|
-
var buildMusherPlist = (o) => {
|
|
10116
|
-
const label = o.label ?? MUSHER_LABEL;
|
|
10117
|
-
const args = [...o.sledsArgv, "musher", "tick"].map((a) => ` <string>${xmlEscape(a)}</string>`).join(`
|
|
10118
|
-
`);
|
|
10119
|
-
const env = Object.entries(o.env).filter(([, v]) => v !== "").map(([k, v]) => ` <key>${xmlEscape(k)}</key>
|
|
10120
|
-
<string>${xmlEscape(v)}</string>`).join(`
|
|
10121
|
-
`);
|
|
10122
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
10123
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
10124
|
-
<plist version="1.0">
|
|
10125
|
-
<dict>
|
|
10126
|
-
<key>Label</key>
|
|
10127
|
-
<string>${label}</string>
|
|
10128
|
-
<key>ProgramArguments</key>
|
|
10129
|
-
<array>
|
|
10130
|
-
${args}
|
|
10131
|
-
</array>
|
|
10132
|
-
<key>EnvironmentVariables</key>
|
|
10133
|
-
<dict>
|
|
10134
|
-
${env}
|
|
10135
|
-
</dict>
|
|
10136
|
-
<key>StartInterval</key>
|
|
10137
|
-
<integer>${MUSHER_INTERVAL_S}</integer>
|
|
10138
|
-
<key>RunAtLoad</key>
|
|
10139
|
-
<true/>
|
|
10140
|
-
<key>StandardOutPath</key>
|
|
10141
|
-
<string>${xmlEscape(o.logPath)}</string>
|
|
10142
|
-
<key>StandardErrorPath</key>
|
|
10143
|
-
<string>${xmlEscape(o.logPath)}</string>
|
|
10144
|
-
</dict>
|
|
10145
|
-
</plist>
|
|
10146
|
-
`;
|
|
10147
|
-
};
|
|
10148
|
-
var RESUME_PROMPT = [
|
|
10149
|
-
"SLEDS musher: the usage limit that stopped this session has reset, and the seat's owner",
|
|
10150
|
-
"scheduled this unattended run to continue it. Pick up exactly where the session left off:",
|
|
10151
|
-
"finish the task that was in flight, run the checks you would normally run, follow the repo's",
|
|
10152
|
-
"own conventions for branches and commits, and do not start unrelated work. If you are blocked",
|
|
10153
|
-
"on a decision only the owner can make, stop there and say so. Finish with a summary under",
|
|
10154
|
-
"200 words: what was done, what remains, anything the owner must decide."
|
|
10155
|
-
].join(" ");
|
|
10156
|
-
var NO_SESSION_PROMPT = [
|
|
10157
|
-
"SLEDS musher: a deferred job started on this seat, but no Claude Code session was recorded",
|
|
10158
|
-
"to resume. Do not guess at work. Reply with one line saying so, and stop."
|
|
10159
|
-
].join(" ");
|
|
10160
|
-
var claudeArgs = (o) => [
|
|
10161
|
-
"-p",
|
|
10162
|
-
o.sessionId ? RESUME_PROMPT : NO_SESSION_PROMPT,
|
|
10163
|
-
...o.sessionId ? ["--resume", o.sessionId] : [],
|
|
10164
|
-
...o.model ? ["--model", o.model] : [],
|
|
10165
|
-
"--output-format",
|
|
10166
|
-
"json",
|
|
10167
|
-
"--permission-mode",
|
|
10168
|
-
o.permissionMode
|
|
10169
|
-
];
|
|
10170
|
-
var parseClaudeOutput = (stdout, exitCode) => {
|
|
10171
|
-
const lines = stdout.split(`
|
|
10172
|
-
`).map((l) => l.trim()).filter(Boolean);
|
|
10173
|
-
for (let i = lines.length - 1;i >= 0; i--) {
|
|
10174
|
-
const line = lines[i] ?? "";
|
|
10175
|
-
if (!line.startsWith("{"))
|
|
10176
|
-
continue;
|
|
10177
|
-
try {
|
|
10178
|
-
const j = JSON.parse(line);
|
|
10179
|
-
if (j.type !== "result" && typeof j.result !== "string")
|
|
10180
|
-
continue;
|
|
10181
|
-
const isError = j.is_error === true || typeof j.subtype === "string" && j.subtype !== "success";
|
|
10182
|
-
const text = typeof j.result === "string" ? j.result : "";
|
|
10183
|
-
const models = j.modelUsage;
|
|
10184
|
-
const model = typeof j.model === "string" ? j.model : models && typeof models === "object" ? Object.keys(models)[0] : undefined;
|
|
10185
|
-
return {
|
|
10186
|
-
ok: !isError && exitCode === 0,
|
|
10187
|
-
summary: (text || (isError ? "Claude Code reported an error" : "")).slice(0, SUMMARY_MAX),
|
|
10188
|
-
...typeof j.session_id === "string" ? { sessionId: j.session_id } : {},
|
|
10189
|
-
...model ? { model } : {},
|
|
10190
|
-
...typeof j.duration_ms === "number" ? { durationMs: j.duration_ms } : {},
|
|
10191
|
-
...typeof j.total_cost_usd === "number" ? { costUsd: j.total_cost_usd } : {}
|
|
10192
|
-
};
|
|
10193
|
-
} catch {}
|
|
10194
|
-
}
|
|
10195
|
-
const tail = lines.slice(-5).join(" ").slice(0, SUMMARY_MAX);
|
|
10196
|
-
return { ok: false, summary: tail || `claude exited ${exitCode ?? "without a code"}` };
|
|
10197
|
-
};
|
|
10198
|
-
var defaultExecCapture = (cmd, args, o) => {
|
|
10199
|
-
const r = spawnSync2(cmd, [...args], {
|
|
10200
|
-
cwd: o.cwd,
|
|
10201
|
-
encoding: "utf8",
|
|
10202
|
-
timeout: o.timeoutMs,
|
|
10203
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
10204
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
10205
|
-
env: { ...process.env, SLEDS_MUSHER: "1" }
|
|
10206
|
-
});
|
|
10207
|
-
const timedOut = r.error?.code === "ETIMEDOUT";
|
|
10208
|
-
return {
|
|
10209
|
-
stdout: r.stdout ?? "",
|
|
10210
|
-
stderr: r.stderr ?? "",
|
|
10211
|
-
status: r.status,
|
|
10212
|
-
...timedOut ? { timedOut } : r.error ? { error: r.error.message } : {}
|
|
10213
|
-
};
|
|
10214
|
-
};
|
|
10215
|
-
var musherClient = (o) => {
|
|
10216
|
-
const fetchFn = o.fetchFn ?? fetch;
|
|
10217
|
-
const headers = { authorization: `Bearer ${o.token}`, "content-type": "application/json" };
|
|
10218
|
-
const call = async (path, body) => {
|
|
10219
|
-
try {
|
|
10220
|
-
const res = await fetchFn(`${o.proxyUrl}${path}`, {
|
|
10221
|
-
method: body === undefined ? "GET" : "POST",
|
|
10222
|
-
headers,
|
|
10223
|
-
...body === undefined ? {} : { body: JSON.stringify(body) },
|
|
10224
|
-
signal: AbortSignal.timeout(o.timeoutMs ?? 1e4)
|
|
10225
|
-
});
|
|
10226
|
-
if (!res.ok)
|
|
10227
|
-
return null;
|
|
10228
|
-
return await res.json();
|
|
10229
|
-
} catch {
|
|
10230
|
-
return null;
|
|
10231
|
-
}
|
|
10232
|
-
};
|
|
10233
|
-
return {
|
|
10234
|
-
list: () => call("/proxy/musher"),
|
|
10235
|
-
start: (jobId, local) => call("/proxy/musher/start", { jobId, ...local }),
|
|
10236
|
-
finish: async (input) => await call("/proxy/musher/finish", input) !== null,
|
|
10237
|
-
defer: (input) => call("/proxy/defer", input),
|
|
10238
|
-
attestation: (jobId) => call(`/proxy/attest/${encodeURIComponent(jobId)}`)
|
|
10239
|
-
};
|
|
10240
|
-
};
|
|
10241
|
-
var gitHead = (cwd, exec) => {
|
|
10242
|
-
if (!cwd)
|
|
10243
|
-
return null;
|
|
10244
|
-
const r = exec("git", ["rev-parse", "HEAD"], { cwd, timeoutMs: 5000 });
|
|
10245
|
-
const sha = r.stdout.trim();
|
|
10246
|
-
return r.status === 0 && /^[0-9a-f]{40}$/.test(sha) ? sha : null;
|
|
10247
|
-
};
|
|
10248
|
-
var gitNewCommits = (cwd, before, after, exec) => {
|
|
10249
|
-
if (!cwd || !after || after === before)
|
|
10250
|
-
return [];
|
|
10251
|
-
if (!before)
|
|
10252
|
-
return [after];
|
|
10253
|
-
const r = exec("git", ["rev-list", `${before}..${after}`], { cwd, timeoutMs: 5000 });
|
|
10254
|
-
if (r.status !== 0)
|
|
10255
|
-
return [after];
|
|
10256
|
-
return r.stdout.split(`
|
|
10257
|
-
`).map((l) => l.trim()).filter((l) => /^[0-9a-f]{40}$/.test(l)).slice(0, 40);
|
|
10258
|
-
};
|
|
10259
|
-
var collectOutputs = (commits, summary) => {
|
|
10260
|
-
const out = commits.map((c) => `git:${c}`);
|
|
10261
|
-
for (const m of summary.matchAll(/https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+/g))
|
|
10262
|
-
if (!out.includes(`pr:${m[0]}`))
|
|
10263
|
-
out.push(`pr:${m[0]}`);
|
|
10264
|
-
return out.slice(0, 50);
|
|
10265
|
-
};
|
|
10266
|
-
var runJob = async (o) => {
|
|
10267
|
-
const log = o.log ?? (() => {});
|
|
10268
|
-
const sessionId = o.job.claudeSessionId ?? o.fallbackSession?.id ?? null;
|
|
10269
|
-
const cwd = o.job.cwd ?? o.fallbackSession?.cwd ?? undefined;
|
|
10270
|
-
const started = await o.client.start(o.job.jobId, {
|
|
10271
|
-
...sessionId ? { claudeSessionId: sessionId } : {},
|
|
10272
|
-
...cwd ? { cwd } : {},
|
|
10273
|
-
host: o.host
|
|
10274
|
-
});
|
|
10275
|
-
if (!started)
|
|
10276
|
-
return { kind: "skipped", reason: "control plane unreachable" };
|
|
10277
|
-
if (!started.ok)
|
|
10278
|
-
return { kind: "skipped", reason: started.reason };
|
|
10279
|
-
const model = o.job.model ?? started.model ?? o.fallbackSession?.model ?? null;
|
|
10280
|
-
const args = claudeArgs({ sessionId, model, permissionMode: o.permissionMode });
|
|
10281
|
-
log(`musher: running job ${o.job.jobId} (${sessionId ? `resume ${sessionId}` : "no session"}${model ? ` · ${model}` : ""}${cwd ? ` · ${cwd}` : ""})`);
|
|
10282
|
-
const exec = o.exec ?? defaultExecCapture;
|
|
10283
|
-
const headBefore = gitHead(cwd, exec);
|
|
10284
|
-
const t0 = Date.now();
|
|
10285
|
-
const r = exec(o.claudePath, args, { cwd, timeoutMs: o.timeoutMs });
|
|
10286
|
-
const durationMs = Date.now() - t0;
|
|
10287
|
-
const result = r.error ? { ok: false, summary: `could not run ${o.claudePath}: ${r.error}` } : parseClaudeOutput(r.stdout, r.status);
|
|
10288
|
-
if (!r.error && (r.timedOut || r.status === null)) {
|
|
10289
|
-
result.ok = false;
|
|
10290
|
-
result.summary = `timed out after ${Math.round(o.timeoutMs / 60000)} min. ${result.summary}`.trim();
|
|
10291
|
-
}
|
|
10292
|
-
const outputs = collectOutputs(gitNewCommits(cwd, headBefore, gitHead(cwd, exec), exec), result.summary);
|
|
10293
|
-
await o.client.finish({
|
|
10294
|
-
jobId: o.job.jobId,
|
|
10295
|
-
runId: started.runId,
|
|
10296
|
-
ok: result.ok,
|
|
10297
|
-
summary: result.summary,
|
|
10298
|
-
...outputs.length ? { outputs } : {},
|
|
10299
|
-
...result.model ?? model ? { model: result.model ?? model } : {},
|
|
10300
|
-
durationMs: result.durationMs ?? durationMs,
|
|
10301
|
-
...result.sessionId ?? sessionId ? { claudeSessionId: result.sessionId ?? sessionId } : {}
|
|
10302
|
-
});
|
|
10303
|
-
log(`musher: job ${o.job.jobId} ${result.ok ? "delivered" : "failed"} in ${Math.round(durationMs / 1000)}s`);
|
|
10304
|
-
return { kind: "ran", ok: result.ok, summary: result.summary, durationMs, outputs };
|
|
10305
|
-
};
|
|
10306
|
-
var verifyAttestation = (payload, sig, publicKeyB64) => {
|
|
10307
|
-
try {
|
|
10308
|
-
const pub = createPublicKey({
|
|
10309
|
-
key: Buffer.from(publicKeyB64, "base64"),
|
|
10310
|
-
format: "der",
|
|
10311
|
-
type: "spki"
|
|
10312
|
-
});
|
|
10313
|
-
const raw = Buffer.from(sig.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
10314
|
-
return cryptoVerify(null, Buffer.from(payload, "utf8"), pub, raw);
|
|
10315
|
-
} catch {
|
|
10316
|
-
return false;
|
|
10317
|
-
}
|
|
10318
|
-
};
|
|
10319
|
-
var parsePayload = (payload) => {
|
|
10320
|
-
const out = {};
|
|
10321
|
-
for (const line of payload.split(`
|
|
10322
|
-
`).slice(1)) {
|
|
10323
|
-
const eq = line.indexOf("=");
|
|
10324
|
-
if (eq > 0)
|
|
10325
|
-
out[line.slice(0, eq)] = line.slice(eq + 1);
|
|
10326
|
-
}
|
|
10327
|
-
return out;
|
|
10328
|
-
};
|
|
10329
|
-
|
|
10330
|
-
// src/switch.ts
|
|
10331
|
-
init_settings();
|
|
10332
|
-
var isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
10333
|
-
var envOf2 = (settings) => isObject8(settings.env) ? settings.env : {};
|
|
10334
|
-
var capturePriorEnv = (settings) => {
|
|
10335
|
-
const env = envOf2(settings);
|
|
10336
|
-
const prior = { hadEnv: isObject8(settings.env) };
|
|
10337
|
-
const url = env[BASE_URL_KEY];
|
|
10338
|
-
const token = env[AUTH_TOKEN_KEY];
|
|
10339
|
-
if (typeof url === "string")
|
|
10340
|
-
prior[BASE_URL_KEY] = url;
|
|
10341
|
-
if (typeof token === "string")
|
|
10342
|
-
prior[AUTH_TOKEN_KEY] = token;
|
|
10343
|
-
return prior;
|
|
10344
|
-
};
|
|
10345
|
-
var switchOn = (settings, cfg) => applyProxy(settings, cfg);
|
|
10346
|
-
var switchOff = (settings, prior) => {
|
|
10347
|
-
const hadEnv = prior.hadEnv === true;
|
|
10348
|
-
const stripped = removeProxy(settings);
|
|
10349
|
-
const env = { ...envOf2(stripped) };
|
|
10350
|
-
const url = prior[BASE_URL_KEY];
|
|
10351
|
-
const token = prior[AUTH_TOKEN_KEY];
|
|
10352
|
-
if (url !== undefined)
|
|
10353
|
-
env[BASE_URL_KEY] = url;
|
|
10354
|
-
if (token !== undefined)
|
|
10355
|
-
env[AUTH_TOKEN_KEY] = token;
|
|
10356
|
-
if (Object.keys(env).length === 0 && !hadEnv) {
|
|
10357
|
-
const { env: _env, ...rest } = stripped;
|
|
10358
|
-
return rest;
|
|
10359
|
-
}
|
|
10360
|
-
return { ...stripped, env };
|
|
10361
|
-
};
|
|
10362
|
-
var envToRestore = (priors, proxyUrls) => priors.find((p) => p !== undefined && !isSledsProxyEnv({ env: p }, proxyUrls)) ?? {};
|
|
10363
|
-
var RELATIVE = /^\+(?:(\d+)h)?(?:(\d+)m)?$/;
|
|
10364
|
-
var parseUntilReset = (input, nowMs) => {
|
|
10365
|
-
const trimmed = input.trim();
|
|
10366
|
-
const rel = RELATIVE.exec(trimmed);
|
|
10367
|
-
let deadline;
|
|
10368
|
-
if (rel) {
|
|
10369
|
-
const hours = Number(rel[1] ?? 0);
|
|
10370
|
-
const minutes = Number(rel[2] ?? 0);
|
|
10371
|
-
if (hours === 0 && minutes === 0) {
|
|
10372
|
-
throw new Error(`--until-reset: "${input}" is zero; use something like +5h or +90m`);
|
|
10373
|
-
}
|
|
10374
|
-
deadline = nowMs + (hours * 60 + minutes) * 60000;
|
|
10375
|
-
} else {
|
|
10376
|
-
deadline = Date.parse(trimmed);
|
|
10377
|
-
if (Number.isNaN(deadline)) {
|
|
10378
|
-
throw new Error(`--until-reset: "${input}" is not +<n>h[<n>m] or an ISO timestamp`);
|
|
10379
|
-
}
|
|
10380
|
-
}
|
|
10381
|
-
if (deadline <= nowMs) {
|
|
10382
|
-
throw new Error(`--until-reset: ${trimmed} is in the past`);
|
|
10383
|
-
}
|
|
10384
|
-
return deadline;
|
|
10385
|
-
};
|
|
10386
|
-
var formatLocal = (ms, tz) => new Intl.DateTimeFormat("en-US", {
|
|
10387
|
-
month: "short",
|
|
10388
|
-
day: "numeric",
|
|
10389
|
-
hour: "numeric",
|
|
10390
|
-
minute: "2-digit",
|
|
10391
|
-
timeZoneName: "short",
|
|
10392
|
-
...tz ? { timeZone: tz } : {}
|
|
10393
|
-
}).format(new Date(ms));
|
|
10394
|
-
var formatDuration = (ms) => {
|
|
10395
|
-
const total = Math.max(0, Math.round(ms / 60000));
|
|
10396
|
-
const h = Math.floor(total / 60);
|
|
10397
|
-
const m = total % 60;
|
|
10398
|
-
if (h === 0)
|
|
10399
|
-
return `${m}m`;
|
|
10400
|
-
return m === 0 ? `${h}h` : `${h}h ${m}m`;
|
|
10401
|
-
};
|
|
10163
|
+
import { basename as basename6 } from "node:path";
|
|
10402
10164
|
|
|
10403
10165
|
// src/commands/engine.ts
|
|
10404
10166
|
init_src();
|
|
@@ -10415,7 +10177,7 @@ import {
|
|
|
10415
10177
|
writeFileSync as writeFileSync15
|
|
10416
10178
|
} from "node:fs";
|
|
10417
10179
|
import { hostname, tmpdir, userInfo } from "node:os";
|
|
10418
|
-
import { dirname as
|
|
10180
|
+
import { dirname as dirname14, isAbsolute as isAbsolute3, join as join23, resolve as resolve8 } from "node:path";
|
|
10419
10181
|
|
|
10420
10182
|
// src/engine/beat.ts
|
|
10421
10183
|
var BEAT_EVERY_MS = 60000;
|
|
@@ -10427,7 +10189,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
10427
10189
|
name: flags.name,
|
|
10428
10190
|
os: host.os ?? process.platform,
|
|
10429
10191
|
runner: flags.runner,
|
|
10430
|
-
version: host.version ?? "0.1.
|
|
10192
|
+
version: host.version ?? "0.1.73" ?? "dev",
|
|
10431
10193
|
running: live.length,
|
|
10432
10194
|
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
10433
10195
|
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
@@ -10487,7 +10249,7 @@ function beater(client, now, everyMs = BEAT_EVERY_MS) {
|
|
|
10487
10249
|
|
|
10488
10250
|
// src/engine/credential.ts
|
|
10489
10251
|
import { homedir } from "node:os";
|
|
10490
|
-
import { join as
|
|
10252
|
+
import { join as join6 } from "node:path";
|
|
10491
10253
|
var API_KEY_VAR = "ANTHROPIC_API_KEY";
|
|
10492
10254
|
var SEAT_TOKEN_VAR = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
10493
10255
|
function namesVar(text, name) {
|
|
@@ -10501,7 +10263,7 @@ function namesVar(text, name) {
|
|
|
10501
10263
|
});
|
|
10502
10264
|
}
|
|
10503
10265
|
function loginPath(env, home = homedir()) {
|
|
10504
|
-
return
|
|
10266
|
+
return join6(env.CLAUDE_CONFIG_DIR?.trim() || join6(home, ".claude"), ".credentials.json");
|
|
10505
10267
|
}
|
|
10506
10268
|
function detectCredential(env, o) {
|
|
10507
10269
|
const file = o.boxEnvText ?? "";
|
|
@@ -10552,7 +10314,7 @@ function clean(v) {
|
|
|
10552
10314
|
return stripControl(v);
|
|
10553
10315
|
if (Array.isArray(v))
|
|
10554
10316
|
return v.map(clean);
|
|
10555
|
-
if (
|
|
10317
|
+
if (isObject7(v))
|
|
10556
10318
|
return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, clean(x)]));
|
|
10557
10319
|
return v;
|
|
10558
10320
|
}
|
|
@@ -10567,18 +10329,18 @@ function routeView(raw, o) {
|
|
|
10567
10329
|
const r = clean(raw);
|
|
10568
10330
|
const width = Math.max(60, o.width ?? 100);
|
|
10569
10331
|
const key = str7(r.key) ?? str7(r.project) ?? "?";
|
|
10570
|
-
const nodes = (Array.isArray(r.nodes) ? r.nodes : []).filter(
|
|
10332
|
+
const nodes = (Array.isArray(r.nodes) ? r.nodes : []).filter(isObject7);
|
|
10571
10333
|
if (nodes.length === 0)
|
|
10572
10334
|
return `${c.bold(key)} has no route — it runs as one node. Draft one with the \`route\` tool, or on the item.`;
|
|
10573
|
-
const states =
|
|
10574
|
-
const runs = (Array.isArray(r.runs) ? r.runs : []).filter(
|
|
10335
|
+
const states = isObject7(r.states) ? r.states : {};
|
|
10336
|
+
const runs = (Array.isArray(r.runs) ? r.runs : []).filter(isObject7);
|
|
10575
10337
|
const stateFor = (n) => str7(states[String(n.key)]) ?? str7(n.state) ?? "pending";
|
|
10576
10338
|
const title = str7(r.title) ?? "";
|
|
10577
10339
|
const line = str7(r.line) ?? "";
|
|
10578
10340
|
const out = [
|
|
10579
10341
|
`${c.bold(key)} ${clip3(title, width - key.length - line.length - 6)} ${c.dim(line)}`
|
|
10580
10342
|
];
|
|
10581
|
-
const open = (Array.isArray(r.blockers) ? r.blockers : []).filter(
|
|
10343
|
+
const open = (Array.isArray(r.blockers) ? r.blockers : []).filter(isObject7).filter((b) => b.landed !== true).map((b) => String(b.key));
|
|
10582
10344
|
if (open.length)
|
|
10583
10345
|
out.push(c.yellow(`waits on ${open.join(", ")} — an item that has not landed`));
|
|
10584
10346
|
const order = waves(nodes.map((n) => ({ key: String(n.key), blockedBy: strings(n.blockedBy) }))) ?? [nodes.map((n) => String(n.key))];
|
|
@@ -10921,6 +10683,7 @@ function parsePrView(stdout) {
|
|
|
10921
10683
|
}
|
|
10922
10684
|
const mergeCommit = typeof o.mergeCommit === "object" && o.mergeCommit !== null ? o.mergeCommit.oid : undefined;
|
|
10923
10685
|
const mock = typeof o.body === "string" ? mockOf(o.body) : undefined;
|
|
10686
|
+
const comparison = typeof o.body === "string" ? lookComparisonOf(o.body) : undefined;
|
|
10924
10687
|
return {
|
|
10925
10688
|
state: o.state,
|
|
10926
10689
|
author: loginOf(o.author),
|
|
@@ -10936,6 +10699,7 @@ function parsePrView(stdout) {
|
|
|
10936
10699
|
autoMerge: typeof o.autoMergeRequest === "object" && o.autoMergeRequest !== null,
|
|
10937
10700
|
queued: false,
|
|
10938
10701
|
...mock ? { mock } : {},
|
|
10702
|
+
...comparison ? { comparison } : {},
|
|
10939
10703
|
...typeof o.headRefOid === "string" && o.headRefOid ? { head: o.headRefOid } : {},
|
|
10940
10704
|
...typeof mergeCommit === "string" && mergeCommit ? { mergeCommit } : {}
|
|
10941
10705
|
};
|
|
@@ -11142,17 +10906,17 @@ function repoOf(summary) {
|
|
|
11142
10906
|
return /\(([^()\s]+)\)\s*$/.exec(summary)?.[1];
|
|
11143
10907
|
}
|
|
11144
10908
|
var categoryOf = (fields) => {
|
|
11145
|
-
if (!
|
|
10909
|
+
if (!isObject7(fields) || !isObject7(fields.status))
|
|
11146
10910
|
return "new";
|
|
11147
10911
|
const cat = fields.status.statusCategory;
|
|
11148
|
-
return
|
|
10912
|
+
return isObject7(cat) && str7(cat.key) || "new";
|
|
11149
10913
|
};
|
|
11150
10914
|
function jiraNode(issue) {
|
|
11151
|
-
const fields =
|
|
10915
|
+
const fields = isObject7(issue.fields) ? issue.fields : {};
|
|
11152
10916
|
const key = String(issue.key);
|
|
11153
10917
|
const summary = str7(fields.summary) ?? key;
|
|
11154
|
-
const links = Array.isArray(fields.issuelinks) ? fields.issuelinks.filter(
|
|
11155
|
-
const blockers = links.filter((l) =>
|
|
10918
|
+
const links = Array.isArray(fields.issuelinks) ? fields.issuelinks.filter(isObject7) : [];
|
|
10919
|
+
const blockers = links.filter((l) => isObject7(l.type) && l.type.name === "Blocks" && isObject7(l.inwardIssue)).map((l) => {
|
|
11156
10920
|
const inward = l.inwardIssue;
|
|
11157
10921
|
return { issue: String(inward.key), category: categoryOf(inward.fields) };
|
|
11158
10922
|
});
|
|
@@ -11191,7 +10955,7 @@ function adfText(doc) {
|
|
|
11191
10955
|
out.push(n);
|
|
11192
10956
|
return;
|
|
11193
10957
|
}
|
|
11194
|
-
if (!
|
|
10958
|
+
if (!isObject7(n))
|
|
11195
10959
|
return;
|
|
11196
10960
|
if (n.type === "text" && typeof n.text === "string")
|
|
11197
10961
|
out.push(n.text);
|
|
@@ -11272,7 +11036,7 @@ function jiraSource(o) {
|
|
|
11272
11036
|
} catch {
|
|
11273
11037
|
json = null;
|
|
11274
11038
|
}
|
|
11275
|
-
return { ok: res.ok, status: res.status, json:
|
|
11039
|
+
return { ok: res.ok, status: res.status, json: isObject7(json) ? json : null };
|
|
11276
11040
|
};
|
|
11277
11041
|
const errorOf = (r) => {
|
|
11278
11042
|
const msgs = Array.isArray(r.json?.errorMessages) ? r.json.errorMessages : [];
|
|
@@ -11289,7 +11053,7 @@ function jiraSource(o) {
|
|
|
11289
11053
|
if (!r.ok)
|
|
11290
11054
|
throw new Error(`Jira: could not read ${epic}'s children — ${errorOf(r)}`);
|
|
11291
11055
|
if (Array.isArray(r.json?.issues))
|
|
11292
|
-
issues.push(...r.json.issues.filter(
|
|
11056
|
+
issues.push(...r.json.issues.filter(isObject7));
|
|
11293
11057
|
token = str7(r.json?.nextPageToken);
|
|
11294
11058
|
if (!token || r.json?.isLast === true)
|
|
11295
11059
|
break;
|
|
@@ -11318,8 +11082,8 @@ function jiraSource(o) {
|
|
|
11318
11082
|
};
|
|
11319
11083
|
const transitionTo = async (issue, category) => {
|
|
11320
11084
|
const t = await call(`/rest/api/3/issue/${issue}/transitions`);
|
|
11321
|
-
const list = Array.isArray(t.json?.transitions) ? t.json.transitions.filter(
|
|
11322
|
-
const hit = list.find((x) =>
|
|
11085
|
+
const list = Array.isArray(t.json?.transitions) ? t.json.transitions.filter(isObject7) : [];
|
|
11086
|
+
const hit = list.find((x) => isObject7(x.to) && categoryOf({ status: x.to }) === category && x.id !== undefined);
|
|
11323
11087
|
if (!hit)
|
|
11324
11088
|
return { ok: false };
|
|
11325
11089
|
const r = await write(issue, "status", "transitions", { transition: { id: String(hit.id) } });
|
|
@@ -11442,12 +11206,12 @@ import {
|
|
|
11442
11206
|
statSync,
|
|
11443
11207
|
writeFileSync as writeFileSync8
|
|
11444
11208
|
} from "node:fs";
|
|
11445
|
-
import { dirname as
|
|
11209
|
+
import { dirname as dirname6, join as join9 } from "node:path";
|
|
11446
11210
|
var SEAT_POST_MIN_DELTA_PCT = 1;
|
|
11447
11211
|
var SEAT_POST_MIN_INTERVAL_MS = 5 * 60000;
|
|
11448
11212
|
var SEAT_POST_TIMEOUT_MS = 1500;
|
|
11449
11213
|
var STDIN_TIMEOUT_MS = 300;
|
|
11450
|
-
var
|
|
11214
|
+
var isObject9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
11451
11215
|
var num6 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
11452
11216
|
var EPOCH_MS_THRESHOLD = 100000000000;
|
|
11453
11217
|
var parseResetsAt = (v) => {
|
|
@@ -11464,7 +11228,7 @@ var parseResetsAt = (v) => {
|
|
|
11464
11228
|
return;
|
|
11465
11229
|
};
|
|
11466
11230
|
var parseBar = (v) => {
|
|
11467
|
-
if (!
|
|
11231
|
+
if (!isObject9(v))
|
|
11468
11232
|
return;
|
|
11469
11233
|
const usedPct = num6(v.used_percentage) ?? num6(v.usedPct);
|
|
11470
11234
|
const resetsAt = parseResetsAt(v.resets_at ?? v.resetsAt);
|
|
@@ -11473,14 +11237,14 @@ var parseBar = (v) => {
|
|
|
11473
11237
|
return { usedPct, resetsAt };
|
|
11474
11238
|
};
|
|
11475
11239
|
var parseSeatWindow = (raw, capturedAt) => {
|
|
11476
|
-
if (!
|
|
11240
|
+
if (!isObject9(raw))
|
|
11477
11241
|
return null;
|
|
11478
|
-
const limits =
|
|
11242
|
+
const limits = isObject9(raw.rate_limits) ? raw.rate_limits : raw;
|
|
11479
11243
|
const fiveHour = parseBar(limits.five_hour ?? limits.fiveHour);
|
|
11480
11244
|
const sevenDay = parseBar(limits.seven_day ?? limits.sevenDay);
|
|
11481
11245
|
const spendLimit = parseBar(limits.spend_limit ?? limits.spendLimit);
|
|
11482
11246
|
const models = {};
|
|
11483
|
-
if (
|
|
11247
|
+
if (isObject9(limits.models))
|
|
11484
11248
|
for (const [k, v] of Object.entries(limits.models)) {
|
|
11485
11249
|
const bar = parseBar(v);
|
|
11486
11250
|
if (bar)
|
|
@@ -11540,11 +11304,11 @@ var formatSeatFragment = (w, now = Date.now()) => {
|
|
|
11540
11304
|
};
|
|
11541
11305
|
var APPROACHING_PCT = 90;
|
|
11542
11306
|
var SEAT_FILE = "seat.json";
|
|
11543
|
-
var legacySeatStatePath = (home) =>
|
|
11307
|
+
var legacySeatStatePath = (home) => join9(configDir(home), SEAT_FILE);
|
|
11544
11308
|
var seatStatePath = (home, key) => {
|
|
11545
11309
|
if (!key?.org?.trim() && !key?.email?.trim())
|
|
11546
11310
|
return legacySeatStatePath(home);
|
|
11547
|
-
return
|
|
11311
|
+
return join9(seatStateDir(orgStateDir(configDir(home), key.org?.trim()), key.email), SEAT_FILE);
|
|
11548
11312
|
};
|
|
11549
11313
|
var seatKeyFor = (home, env = process.env, org) => {
|
|
11550
11314
|
const { slug, seat } = selectOrg(readConfig(home), org, env);
|
|
@@ -11554,16 +11318,16 @@ var allSeatStatePaths = (home) => {
|
|
|
11554
11318
|
const root = configDir(home);
|
|
11555
11319
|
const dirs = (d) => {
|
|
11556
11320
|
try {
|
|
11557
|
-
return readdirSync(d, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) =>
|
|
11321
|
+
return readdirSync(d, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => join9(d, e.name));
|
|
11558
11322
|
} catch {
|
|
11559
11323
|
return [];
|
|
11560
11324
|
}
|
|
11561
11325
|
};
|
|
11562
|
-
const keyed = dirs(
|
|
11563
|
-
|
|
11564
|
-
...dirs(
|
|
11326
|
+
const keyed = dirs(join9(root, "orgs")).flatMap((org) => [
|
|
11327
|
+
join9(org, SEAT_FILE),
|
|
11328
|
+
...dirs(join9(org, "seats")).map((seat) => join9(seat, SEAT_FILE))
|
|
11565
11329
|
]);
|
|
11566
|
-
const noOrg = dirs(
|
|
11330
|
+
const noOrg = dirs(join9(root, "seats")).map((seat) => join9(seat, SEAT_FILE));
|
|
11567
11331
|
return [legacySeatStatePath(home), ...[...keyed, ...noOrg].filter((p) => existsSync8(p))];
|
|
11568
11332
|
};
|
|
11569
11333
|
var adoptLegacySeatState = (home, target) => {
|
|
@@ -11571,12 +11335,12 @@ var adoptLegacySeatState = (home, target) => {
|
|
|
11571
11335
|
if (target === legacy || existsSync8(target) || !existsSync8(legacy))
|
|
11572
11336
|
return;
|
|
11573
11337
|
try {
|
|
11574
|
-
mkdirSync8(
|
|
11338
|
+
mkdirSync8(dirname6(target), { recursive: true, mode: 448 });
|
|
11575
11339
|
renameSync5(legacy, target);
|
|
11576
11340
|
} catch {}
|
|
11577
11341
|
};
|
|
11578
11342
|
var parseWindowStored = (v) => {
|
|
11579
|
-
if (!
|
|
11343
|
+
if (!isObject9(v))
|
|
11580
11344
|
return;
|
|
11581
11345
|
const capturedAt = num6(v.capturedAt);
|
|
11582
11346
|
if (capturedAt === undefined)
|
|
@@ -11584,7 +11348,7 @@ var parseWindowStored = (v) => {
|
|
|
11584
11348
|
return parseSeatWindow(v, capturedAt) ?? undefined;
|
|
11585
11349
|
};
|
|
11586
11350
|
var parseSeatState = (raw) => {
|
|
11587
|
-
if (!
|
|
11351
|
+
if (!isObject9(raw))
|
|
11588
11352
|
return {};
|
|
11589
11353
|
const out = {};
|
|
11590
11354
|
const window = parseWindowStored(raw.window);
|
|
@@ -11593,7 +11357,7 @@ var parseSeatState = (raw) => {
|
|
|
11593
11357
|
const lastPostedAt = num6(raw.lastPostedAt);
|
|
11594
11358
|
if (lastPostedAt !== undefined)
|
|
11595
11359
|
out.lastPostedAt = lastPostedAt;
|
|
11596
|
-
if (
|
|
11360
|
+
if (isObject9(raw.lastPosted)) {
|
|
11597
11361
|
const lp = {};
|
|
11598
11362
|
const f = num6(raw.lastPosted.fiveHour);
|
|
11599
11363
|
const s = num6(raw.lastPosted.sevenDay);
|
|
@@ -11609,11 +11373,11 @@ var parseSeatState = (raw) => {
|
|
|
11609
11373
|
const lastWallResetsAt = num6(raw.lastWallResetsAt);
|
|
11610
11374
|
if (lastWallResetsAt !== undefined)
|
|
11611
11375
|
out.lastWallResetsAt = lastWallResetsAt;
|
|
11612
|
-
if (
|
|
11376
|
+
if (isObject9(raw.warned)) {
|
|
11613
11377
|
const warned = {};
|
|
11614
11378
|
for (const bar of ["fiveHour", "sevenDay", "spendLimit", "credits"]) {
|
|
11615
11379
|
const w = raw.warned[bar];
|
|
11616
|
-
if (!
|
|
11380
|
+
if (!isObject9(w))
|
|
11617
11381
|
continue;
|
|
11618
11382
|
const entry = {};
|
|
11619
11383
|
const ap = num6(w.approaching);
|
|
@@ -11626,11 +11390,11 @@ var parseSeatState = (raw) => {
|
|
|
11626
11390
|
}
|
|
11627
11391
|
out.warned = warned;
|
|
11628
11392
|
}
|
|
11629
|
-
if (
|
|
11393
|
+
if (isObject9(raw.told)) {
|
|
11630
11394
|
const told = {};
|
|
11631
11395
|
for (const bar of ["fiveHour", "sevenDay", "spendLimit", "credits"]) {
|
|
11632
11396
|
const w = raw.told[bar];
|
|
11633
|
-
if (!
|
|
11397
|
+
if (!isObject9(w))
|
|
11634
11398
|
continue;
|
|
11635
11399
|
const entry = {};
|
|
11636
11400
|
const ap = num6(w.approaching);
|
|
@@ -11643,7 +11407,7 @@ var parseSeatState = (raw) => {
|
|
|
11643
11407
|
}
|
|
11644
11408
|
out.told = told;
|
|
11645
11409
|
}
|
|
11646
|
-
if (
|
|
11410
|
+
if (isObject9(raw.transcriptScan) && typeof raw.transcriptScan.path === "string") {
|
|
11647
11411
|
const offset = num6(raw.transcriptScan.offset);
|
|
11648
11412
|
const hitAt = num6(raw.transcriptScan.hitAt);
|
|
11649
11413
|
out.transcriptScan = {
|
|
@@ -11655,9 +11419,9 @@ var parseSeatState = (raw) => {
|
|
|
11655
11419
|
const session = parseSeatSession(raw.session);
|
|
11656
11420
|
if (session)
|
|
11657
11421
|
out.session = session;
|
|
11658
|
-
if (
|
|
11422
|
+
if (isObject9(raw.cockpit) && raw.cockpit.kind === "cmux") {
|
|
11659
11423
|
const c = { kind: "cmux" };
|
|
11660
|
-
if (
|
|
11424
|
+
if (isObject9(raw.cockpit.lines)) {
|
|
11661
11425
|
const lines = {};
|
|
11662
11426
|
for (const [k, v] of Object.entries(raw.cockpit.lines))
|
|
11663
11427
|
if (typeof v === "string")
|
|
@@ -11667,9 +11431,9 @@ var parseSeatState = (raw) => {
|
|
|
11667
11431
|
if (raw.cockpit.progress === true)
|
|
11668
11432
|
c.progress = true;
|
|
11669
11433
|
const f = raw.cockpit.feed;
|
|
11670
|
-
if (
|
|
11434
|
+
if (isObject9(f) && num6(f.at) !== undefined) {
|
|
11671
11435
|
const strs = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
11672
|
-
const j =
|
|
11436
|
+
const j = isObject9(f.jobs) ? f.jobs : {};
|
|
11673
11437
|
c.feed = {
|
|
11674
11438
|
at: num6(f.at),
|
|
11675
11439
|
handoffs: strs(f.handoffs),
|
|
@@ -11685,7 +11449,7 @@ var parseSeatState = (raw) => {
|
|
|
11685
11449
|
}
|
|
11686
11450
|
out.cockpit = c;
|
|
11687
11451
|
}
|
|
11688
|
-
if (
|
|
11452
|
+
if (isObject9(raw.estimate)) {
|
|
11689
11453
|
const e = raw.estimate;
|
|
11690
11454
|
const project = typeof e.project === "string" ? e.project : undefined;
|
|
11691
11455
|
const [lo, hi, lm, hm, at] = [e.lowUsd, e.highUsd, e.lowMin, e.highMin, e.at].map(num6);
|
|
@@ -11695,7 +11459,7 @@ var parseSeatState = (raw) => {
|
|
|
11695
11459
|
return out;
|
|
11696
11460
|
};
|
|
11697
11461
|
var parseSeatSession = (v) => {
|
|
11698
|
-
if (!
|
|
11462
|
+
if (!isObject9(v) || typeof v.id !== "string" || !v.id)
|
|
11699
11463
|
return;
|
|
11700
11464
|
const at = num6(v.at);
|
|
11701
11465
|
if (at === undefined)
|
|
@@ -11713,12 +11477,12 @@ var seatSessionFromStdin = (text, now) => {
|
|
|
11713
11477
|
return null;
|
|
11714
11478
|
try {
|
|
11715
11479
|
const raw = JSON.parse(trimmed);
|
|
11716
|
-
if (!
|
|
11480
|
+
if (!isObject9(raw) || typeof raw.session_id !== "string" || !raw.session_id)
|
|
11717
11481
|
return null;
|
|
11718
11482
|
const out = { id: raw.session_id, at: now };
|
|
11719
11483
|
if (typeof raw.cwd === "string" && raw.cwd)
|
|
11720
11484
|
out.cwd = raw.cwd;
|
|
11721
|
-
const model =
|
|
11485
|
+
const model = isObject9(raw.model) ? raw.model.id : raw.model;
|
|
11722
11486
|
if (typeof model === "string" && model)
|
|
11723
11487
|
out.model = model;
|
|
11724
11488
|
return out;
|
|
@@ -11752,7 +11516,7 @@ var readSeatState = (home, key) => {
|
|
|
11752
11516
|
};
|
|
11753
11517
|
var writeSeatState = (home, state, key) => {
|
|
11754
11518
|
const target = seatStatePath(home, key);
|
|
11755
|
-
mkdirSync8(
|
|
11519
|
+
mkdirSync8(dirname6(target), { recursive: true, mode: 448 });
|
|
11756
11520
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
11757
11521
|
writeFileSync8(tmp, `${JSON.stringify(state)}
|
|
11758
11522
|
`, { mode: 384 });
|
|
@@ -11828,7 +11592,7 @@ var entryText = (v) => {
|
|
|
11828
11592
|
return v;
|
|
11829
11593
|
if (!Array.isArray(v))
|
|
11830
11594
|
return "";
|
|
11831
|
-
return v.map((b) =>
|
|
11595
|
+
return v.map((b) => isObject9(b) && b.type === "text" && typeof b.text === "string" ? b.text : "").join(`
|
|
11832
11596
|
`);
|
|
11833
11597
|
};
|
|
11834
11598
|
var isCreditsLine = (line) => {
|
|
@@ -11840,9 +11604,9 @@ var isCreditsLine = (line) => {
|
|
|
11840
11604
|
} catch {
|
|
11841
11605
|
return false;
|
|
11842
11606
|
}
|
|
11843
|
-
if (!
|
|
11607
|
+
if (!isObject9(raw))
|
|
11844
11608
|
return false;
|
|
11845
|
-
const message =
|
|
11609
|
+
const message = isObject9(raw.message) ? raw.message : undefined;
|
|
11846
11610
|
const texts = raw.type === "system" ? [entryText(raw.content), entryText(raw.text)] : raw.type === "assistant" && raw.isApiErrorMessage === true ? [entryText(message?.content)] : [];
|
|
11847
11611
|
return texts.some((t) => CREDITS_LINE.test(t));
|
|
11848
11612
|
};
|
|
@@ -11851,7 +11615,7 @@ var creditsHitIn = (text) => text.split(`
|
|
|
11851
11615
|
var transcriptPathFromStdin = (text) => {
|
|
11852
11616
|
try {
|
|
11853
11617
|
const raw = JSON.parse(text.trim());
|
|
11854
|
-
return
|
|
11618
|
+
return isObject9(raw) && typeof raw.transcript_path === "string" && raw.transcript_path ? raw.transcript_path : null;
|
|
11855
11619
|
} catch {
|
|
11856
11620
|
return null;
|
|
11857
11621
|
}
|
|
@@ -11943,11 +11707,11 @@ var readStdin = (timeoutMs, stdin = process.stdin) => new Promise((resolve) => {
|
|
|
11943
11707
|
init_config();
|
|
11944
11708
|
init_meter();
|
|
11945
11709
|
var HOOK_STDIN_TIMEOUT_MS = 1000;
|
|
11946
|
-
var
|
|
11710
|
+
var isObject10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
11947
11711
|
var notificationType = (text) => {
|
|
11948
11712
|
try {
|
|
11949
11713
|
const raw = JSON.parse(text);
|
|
11950
|
-
if (!
|
|
11714
|
+
if (!isObject10(raw))
|
|
11951
11715
|
return;
|
|
11952
11716
|
return typeof raw.notification_type === "string" ? raw.notification_type : undefined;
|
|
11953
11717
|
} catch {
|
|
@@ -11956,7 +11720,7 @@ var notificationType = (text) => {
|
|
|
11956
11720
|
};
|
|
11957
11721
|
|
|
11958
11722
|
// src/commands/permissionEvent.ts
|
|
11959
|
-
var
|
|
11723
|
+
var isObject11 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
11960
11724
|
var NOT_A_TOOL = new Set(["askuserquestion", "exitplanmode", "enterplanmode"]);
|
|
11961
11725
|
var isToolPermission = (message) => {
|
|
11962
11726
|
const tool = /permission to use\s+(.+?)\.?\s*$/i.exec(message)?.[1];
|
|
@@ -11965,7 +11729,7 @@ var isToolPermission = (message) => {
|
|
|
11965
11729
|
var readPermissionMark = (file) => {
|
|
11966
11730
|
try {
|
|
11967
11731
|
const raw = JSON.parse(readFileSync9(file, "utf8"));
|
|
11968
|
-
if (!
|
|
11732
|
+
if (!isObject11(raw) || typeof raw.at !== "number")
|
|
11969
11733
|
return null;
|
|
11970
11734
|
return { message: typeof raw.message === "string" ? raw.message : "", at: raw.at };
|
|
11971
11735
|
} catch {
|
|
@@ -11977,9 +11741,9 @@ var clearPermissionMark = (file) => {
|
|
|
11977
11741
|
};
|
|
11978
11742
|
|
|
11979
11743
|
// src/runners/exec.ts
|
|
11980
|
-
import { spawn, spawnSync as
|
|
11744
|
+
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
11981
11745
|
import { closeSync as closeSync2, fstatSync, openSync as openSync2, readSync as readSync2 } from "node:fs";
|
|
11982
|
-
import { basename as
|
|
11746
|
+
import { basename as basename2, dirname as dirname7, join as join10 } from "node:path";
|
|
11983
11747
|
|
|
11984
11748
|
// src/runners/sandbox.ts
|
|
11985
11749
|
var absRule = (dir) => `/${dir.replace(/\/+$/, "")}/**`;
|
|
@@ -12068,7 +11832,7 @@ var logTimeouts = (exec, log) => (cmd, args, o) => {
|
|
|
12068
11832
|
};
|
|
12069
11833
|
var defaultExec = (cmd, args, o) => {
|
|
12070
11834
|
const timeoutMs = o?.timeoutMs ?? EXEC_TIMEOUT_MS;
|
|
12071
|
-
const r =
|
|
11835
|
+
const r = spawnSync2(cmd, [...args], {
|
|
12072
11836
|
cwd: o?.cwd,
|
|
12073
11837
|
input: o?.input,
|
|
12074
11838
|
env: o?.env ? { ...process.env, ...o.env } : undefined,
|
|
@@ -12156,8 +11920,8 @@ var readLogTail = (path) => {
|
|
|
12156
11920
|
}
|
|
12157
11921
|
};
|
|
12158
11922
|
var logPathFor = (promptFile, ext, dir) => {
|
|
12159
|
-
const base =
|
|
12160
|
-
return
|
|
11923
|
+
const base = basename2(promptFile).replace(/\.md$/i, "");
|
|
11924
|
+
return join10(dir ?? dirname7(promptFile), `${base}.${ext}`);
|
|
12161
11925
|
};
|
|
12162
11926
|
var tailText = (s, bytes = 4096) => {
|
|
12163
11927
|
if (s.length <= bytes)
|
|
@@ -12208,9 +11972,9 @@ function eventOpenOf(j) {
|
|
|
12208
11972
|
var answerNode = (node) => `${node}-answer`;
|
|
12209
11973
|
var AUTONOMIES = ["ask", "decide_and_flag", "decide"];
|
|
12210
11974
|
function loggedDecision(d) {
|
|
12211
|
-
if (!
|
|
11975
|
+
if (!isObject7(d) || d.state !== "answered" || !isObject7(d.answer))
|
|
12212
11976
|
return null;
|
|
12213
|
-
const q =
|
|
11977
|
+
const q = isObject7(d.question) ? str7(d.question.md) : undefined;
|
|
12214
11978
|
const md = str7(d.answer.md);
|
|
12215
11979
|
if (!q || !md)
|
|
12216
11980
|
return null;
|
|
@@ -12344,30 +12108,38 @@ function mocksOf(s) {
|
|
|
12344
12108
|
return m && typeof m.finishMock === "function" && typeof m.failMock === "function" ? s : null;
|
|
12345
12109
|
}
|
|
12346
12110
|
function mockRunOf(row) {
|
|
12347
|
-
const m =
|
|
12348
|
-
return { asked:
|
|
12111
|
+
const m = isObject7(row.mockRun) ? row.mockRun : {};
|
|
12112
|
+
return { asked: isObject7(m.asked), running: isObject7(m.running) };
|
|
12349
12113
|
}
|
|
12350
12114
|
function askedMocks(r) {
|
|
12351
|
-
const mine = Array.isArray(r.mine) ? r.mine.filter(
|
|
12115
|
+
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
|
|
12352
12116
|
return mine.filter((row) => {
|
|
12353
12117
|
const m = mockRunOf(row);
|
|
12354
12118
|
return m.asked && !m.running;
|
|
12355
12119
|
});
|
|
12356
12120
|
}
|
|
12357
12121
|
function mockBandText(b) {
|
|
12358
|
-
const lo =
|
|
12359
|
-
const hi =
|
|
12122
|
+
const lo = num4(b.lowMin);
|
|
12123
|
+
const hi = num4(b.highMin);
|
|
12360
12124
|
return lo !== undefined && hi !== undefined ? `${lo}–${hi} min` : undefined;
|
|
12361
12125
|
}
|
|
12126
|
+
function reviseOf(v) {
|
|
12127
|
+
if (!isObject7(v))
|
|
12128
|
+
return;
|
|
12129
|
+
const assetId = str7(v.assetId);
|
|
12130
|
+
const name = str7(v.name);
|
|
12131
|
+
const url = str7(v.url);
|
|
12132
|
+
return assetId && name && url ? { assetId, name, url } : undefined;
|
|
12133
|
+
}
|
|
12362
12134
|
function instructionsFrom(waiting) {
|
|
12363
12135
|
if (!Array.isArray(waiting))
|
|
12364
12136
|
return [];
|
|
12365
|
-
return waiting.filter(
|
|
12137
|
+
return waiting.filter(isObject7).flatMap((w) => {
|
|
12366
12138
|
const id = str7(w.id);
|
|
12367
12139
|
const md = str7(w.md);
|
|
12368
12140
|
if (!id || !md)
|
|
12369
12141
|
return [];
|
|
12370
|
-
const f =
|
|
12142
|
+
const f = isObject7(w.finding) ? w.finding : null;
|
|
12371
12143
|
const kind = f?.kind === "review" || f?.kind === "bot" ? f.kind : null;
|
|
12372
12144
|
const url = f ? str7(f.url) : undefined;
|
|
12373
12145
|
const by = f ? str7(f.by) : undefined;
|
|
@@ -12391,11 +12163,11 @@ function statesLanded(states) {
|
|
|
12391
12163
|
return all.length > 0 && all.every((s) => s === "landed" || s === "skipped") && all.some((s) => s === "landed");
|
|
12392
12164
|
}
|
|
12393
12165
|
function armedTerms(armed) {
|
|
12394
|
-
if (!
|
|
12166
|
+
if (!isObject7(armed))
|
|
12395
12167
|
return { seatIds: [] };
|
|
12396
|
-
const atOnce =
|
|
12168
|
+
const atOnce = num4(armed.atOnce);
|
|
12397
12169
|
const runner = str7(armed.runner);
|
|
12398
|
-
const seatAtOnce = Array.isArray(armed.seatAtOnce) ? armed.seatAtOnce.map((x) =>
|
|
12170
|
+
const seatAtOnce = Array.isArray(armed.seatAtOnce) ? armed.seatAtOnce.map((x) => num4(x) ?? 1) : undefined;
|
|
12399
12171
|
return {
|
|
12400
12172
|
...atOnce !== undefined ? { atOnce } : {},
|
|
12401
12173
|
seatIds: strings(armed.seatIds),
|
|
@@ -12447,10 +12219,10 @@ async function readOrSay(client, path, what) {
|
|
|
12447
12219
|
function routeItem(q, r) {
|
|
12448
12220
|
if (!r || r.ok === false)
|
|
12449
12221
|
throw new Error(`${q}: not found on SLEDS, or ${UNREACHABLE3} — check the key and the token`);
|
|
12450
|
-
const nodes = Array.isArray(r.nodes) ? r.nodes.filter(
|
|
12222
|
+
const nodes = Array.isArray(r.nodes) ? r.nodes.filter(isObject7) : [];
|
|
12451
12223
|
if (nodes.length === 0)
|
|
12452
12224
|
throw new Error(`${q} has no route — draft one with the \`route\` tool first`);
|
|
12453
|
-
const states =
|
|
12225
|
+
const states = isObject7(r.states) ? r.states : {};
|
|
12454
12226
|
const found = nodes.filter((n) => n.state === "running").map((n) => String(n.key));
|
|
12455
12227
|
const running = found.length > 0 ? found : keysIn(states, "running");
|
|
12456
12228
|
const held = heldOf(r, running);
|
|
@@ -12464,12 +12236,12 @@ function routeItem(q, r) {
|
|
|
12464
12236
|
};
|
|
12465
12237
|
}
|
|
12466
12238
|
function heldOf(r, running) {
|
|
12467
|
-
const runs = Array.isArray(r?.runs) ? r.runs.filter(
|
|
12239
|
+
const runs = Array.isArray(r?.runs) ? r.runs.filter(isObject7) : [];
|
|
12468
12240
|
return runs.flatMap((x) => {
|
|
12469
12241
|
const node = str7(x.node);
|
|
12470
12242
|
const runId = str7(x.runId);
|
|
12471
12243
|
const engine = str7(x.engine);
|
|
12472
|
-
const startedAt =
|
|
12244
|
+
const startedAt = num4(x.startedAt);
|
|
12473
12245
|
if (!node || !running.includes(node) || !runId || !engine || startedAt === undefined)
|
|
12474
12246
|
return [];
|
|
12475
12247
|
return [{ node, runId, engine, startedAt }];
|
|
@@ -12478,7 +12250,7 @@ function heldOf(r, running) {
|
|
|
12478
12250
|
function groupOf(j, item) {
|
|
12479
12251
|
if (!j || j.ok === false)
|
|
12480
12252
|
return null;
|
|
12481
|
-
const parent =
|
|
12253
|
+
const parent = isObject7(j.parent) ? j.parent : null;
|
|
12482
12254
|
const parentKey = str7(parent?.key)?.trim();
|
|
12483
12255
|
if (parent && parentKey)
|
|
12484
12256
|
return { key: parentKey, title: str7(parent.title) ?? parentKey };
|
|
@@ -12489,7 +12261,7 @@ function groupOf(j, item) {
|
|
|
12489
12261
|
function runOf(v) {
|
|
12490
12262
|
if (!Array.isArray(v))
|
|
12491
12263
|
return;
|
|
12492
|
-
return v.filter(
|
|
12264
|
+
return v.filter(isObject7).flatMap((x) => {
|
|
12493
12265
|
const repo = str7(x.repo)?.trim();
|
|
12494
12266
|
if (!repo)
|
|
12495
12267
|
return [];
|
|
@@ -12503,21 +12275,21 @@ function sameEngine(a, b) {
|
|
|
12503
12275
|
return bare(a) === bare(b);
|
|
12504
12276
|
}
|
|
12505
12277
|
function armedFor(armed, engine) {
|
|
12506
|
-
if (!
|
|
12278
|
+
if (!isObject7(armed))
|
|
12507
12279
|
return false;
|
|
12508
12280
|
const where = str7(armed.engine);
|
|
12509
12281
|
return !engine || !where?.trim() || sameEngine(where, engine);
|
|
12510
12282
|
}
|
|
12511
12283
|
function sledItems(r, armedOnly, engine) {
|
|
12512
|
-
const mine = Array.isArray(r.mine) ? r.mine.filter(
|
|
12284
|
+
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
|
|
12513
12285
|
const out = [];
|
|
12514
12286
|
for (const row of mine) {
|
|
12515
12287
|
const route = row.route;
|
|
12516
|
-
if (!
|
|
12288
|
+
if (!isObject7(route))
|
|
12517
12289
|
continue;
|
|
12518
12290
|
if (armedOnly && !armedFor(route.armed, engine))
|
|
12519
12291
|
continue;
|
|
12520
|
-
const states =
|
|
12292
|
+
const states = isObject7(route.states) ? route.states : {};
|
|
12521
12293
|
out.push({
|
|
12522
12294
|
item: str7(row.key) ?? String(row.project),
|
|
12523
12295
|
ready: strings(route.ready),
|
|
@@ -12551,10 +12323,10 @@ var PROFILE_TEXT = [
|
|
|
12551
12323
|
];
|
|
12552
12324
|
var SHELL_TEXT = ["agent", "launcher", "mode"];
|
|
12553
12325
|
function profileOf(r) {
|
|
12554
|
-
if (!r || r.ok === false || !
|
|
12326
|
+
if (!r || r.ok === false || !isObject7(r.profile))
|
|
12555
12327
|
return null;
|
|
12556
12328
|
const p = r.profile;
|
|
12557
|
-
const member =
|
|
12329
|
+
const member = isObject7(r.member) ? r.member : {};
|
|
12558
12330
|
const out = {
|
|
12559
12331
|
pickup: p.pickup === "auto" && member.pickup === "auto" ? "auto" : "approve",
|
|
12560
12332
|
...HOLD_DEFAULTS2,
|
|
@@ -12577,23 +12349,23 @@ function profileOf(r) {
|
|
|
12577
12349
|
}
|
|
12578
12350
|
if (p.pickup === "auto" && out.pickup !== "auto")
|
|
12579
12351
|
notYours.push("pickup");
|
|
12580
|
-
const atOnce =
|
|
12352
|
+
const atOnce = num4(p.atOnce);
|
|
12581
12353
|
if (atOnce !== undefined && atOnce >= 1)
|
|
12582
12354
|
out.atOnce = Math.round(atOnce);
|
|
12583
|
-
const seatAtOnce =
|
|
12355
|
+
const seatAtOnce = num4(r.seatAtOnce);
|
|
12584
12356
|
if (seatAtOnce !== undefined && Number.isInteger(seatAtOnce) && seatAtOnce >= 1)
|
|
12585
12357
|
out.seatAtOnce = seatAtOnce;
|
|
12586
12358
|
if (typeof p.mcpStrict === "boolean")
|
|
12587
12359
|
out.mcpStrict = p.mcpStrict;
|
|
12588
|
-
const holdCpu =
|
|
12360
|
+
const holdCpu = num4(p.holdCpu);
|
|
12589
12361
|
if (holdCpu !== undefined && holdCpu > 0 && holdCpu <= 100)
|
|
12590
12362
|
out.holdCpu = holdCpu;
|
|
12591
|
-
const holdLoad =
|
|
12363
|
+
const holdLoad = num4(p.holdLoad);
|
|
12592
12364
|
if (holdLoad !== undefined && holdLoad > 0)
|
|
12593
12365
|
out.holdLoad = holdLoad;
|
|
12594
12366
|
if (p.holdPressure === "warn" || p.holdPressure === "critical")
|
|
12595
12367
|
out.holdPressure = p.holdPressure;
|
|
12596
|
-
const drainMaxMin =
|
|
12368
|
+
const drainMaxMin = num4(p.drainMaxMin);
|
|
12597
12369
|
if (drainMaxMin !== undefined && Number.isInteger(drainMaxMin) && drainMaxMin >= 0)
|
|
12598
12370
|
out.drainMaxMin = drainMaxMin;
|
|
12599
12371
|
if (Array.isArray(p.mcpAllow)) {
|
|
@@ -12622,12 +12394,12 @@ async function readProfile(client) {
|
|
|
12622
12394
|
}
|
|
12623
12395
|
}
|
|
12624
12396
|
function nextPickup(r, o) {
|
|
12625
|
-
const mine = Array.isArray(r.mine) ? r.mine.filter(
|
|
12397
|
+
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
|
|
12626
12398
|
for (const row of mine) {
|
|
12627
12399
|
const route = row.route;
|
|
12628
|
-
if (!
|
|
12400
|
+
if (!isObject7(route) || !armedFor(route.armed, o.engine))
|
|
12629
12401
|
continue;
|
|
12630
|
-
const states =
|
|
12402
|
+
const states = isObject7(route.states) ? route.states : {};
|
|
12631
12403
|
if (statesLanded(states))
|
|
12632
12404
|
continue;
|
|
12633
12405
|
if (strings(route.ready).length > 0)
|
|
@@ -12637,15 +12409,15 @@ function nextPickup(r, o) {
|
|
|
12637
12409
|
return null;
|
|
12638
12410
|
for (const row of mine) {
|
|
12639
12411
|
const route = row.route;
|
|
12640
|
-
if (!
|
|
12412
|
+
if (!isObject7(route) || isObject7(route.armed) || route.draftParked)
|
|
12641
12413
|
continue;
|
|
12642
12414
|
if (isPrMirror(row.source))
|
|
12643
12415
|
continue;
|
|
12644
12416
|
if (route.packable === false)
|
|
12645
12417
|
continue;
|
|
12646
|
-
if (
|
|
12418
|
+
if (isObject7(route.elsewhere))
|
|
12647
12419
|
continue;
|
|
12648
|
-
const states =
|
|
12420
|
+
const states = isObject7(route.states) ? route.states : {};
|
|
12649
12421
|
if (statesLanded(states) || keysIn(states, "running").length > 0)
|
|
12650
12422
|
continue;
|
|
12651
12423
|
if (strings(route.ready).length > 0 || redraftDue(route))
|
|
@@ -12654,45 +12426,45 @@ function nextPickup(r, o) {
|
|
|
12654
12426
|
return null;
|
|
12655
12427
|
}
|
|
12656
12428
|
function sledRunning(r) {
|
|
12657
|
-
const mine = Array.isArray(r) ? r : Array.isArray(r.mine) ? r.mine.filter(
|
|
12429
|
+
const mine = Array.isArray(r) ? r : Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
|
|
12658
12430
|
let running = 0;
|
|
12659
12431
|
for (const row of mine) {
|
|
12660
12432
|
const route = row.route;
|
|
12661
|
-
if (
|
|
12433
|
+
if (isObject7(route) && route.drafting === true)
|
|
12662
12434
|
running++;
|
|
12663
12435
|
if (mockRunOf(row).running)
|
|
12664
12436
|
running++;
|
|
12665
|
-
if (!
|
|
12437
|
+
if (!isObject7(route) || !isObject7(route.armed))
|
|
12666
12438
|
continue;
|
|
12667
|
-
running += keysIn(
|
|
12439
|
+
running += keysIn(isObject7(route.states) ? route.states : {}, "running").length;
|
|
12668
12440
|
}
|
|
12669
12441
|
return running;
|
|
12670
12442
|
}
|
|
12671
12443
|
function armedDrafts(r, engine) {
|
|
12672
|
-
const mine = Array.isArray(r.mine) ? r.mine.filter(
|
|
12444
|
+
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
|
|
12673
12445
|
return mine.filter((row) => {
|
|
12674
12446
|
const route = row.route;
|
|
12675
|
-
if (!
|
|
12447
|
+
if (!isObject7(route) || !armedFor(route.armed, engine) || route.implicit !== true)
|
|
12676
12448
|
return false;
|
|
12677
12449
|
if (route.drafting === true || route.proposed === true || route.draftParked)
|
|
12678
12450
|
return false;
|
|
12679
|
-
if (
|
|
12451
|
+
if (isObject7(route.elsewhere))
|
|
12680
12452
|
return false;
|
|
12681
12453
|
if (strings(route.needsRoute).length === 0 || isPrMirror(row.source))
|
|
12682
12454
|
return false;
|
|
12683
|
-
const states =
|
|
12455
|
+
const states = isObject7(route.states) ? route.states : {};
|
|
12684
12456
|
return !statesLanded(states) && keysIn(states, "running").length === 0;
|
|
12685
12457
|
});
|
|
12686
12458
|
}
|
|
12687
12459
|
function redraftDue(route) {
|
|
12688
|
-
return
|
|
12460
|
+
return isObject7(route) && isObject7(route.redraft) && route.drafting !== true && route.proposed !== true;
|
|
12689
12461
|
}
|
|
12690
12462
|
function routeText(route, states) {
|
|
12691
|
-
const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(
|
|
12463
|
+
const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject7) : [];
|
|
12692
12464
|
if (nodes.length > 0)
|
|
12693
12465
|
return nodes.map((n) => `${String(n.key)} · ${str7(n.title) ?? String(n.key)} — ${str7(n.state) ?? "ready"}`).join(`
|
|
12694
12466
|
`);
|
|
12695
|
-
return Object.entries(
|
|
12467
|
+
return Object.entries(isObject7(states) ? states : {}).map(([k, v]) => `${k} — ${String(v)}`).join(`
|
|
12696
12468
|
`);
|
|
12697
12469
|
}
|
|
12698
12470
|
function sledsSource(client, o) {
|
|
@@ -12707,7 +12479,7 @@ function sledsSource(client, o) {
|
|
|
12707
12479
|
if (!row)
|
|
12708
12480
|
return null;
|
|
12709
12481
|
const item = str7(row.key) ?? String(row.project);
|
|
12710
|
-
const why =
|
|
12482
|
+
const why = isObject7(row.route) ? strings(row.route.needsRoute) : [];
|
|
12711
12483
|
if (why.length > 0 || redraftDue(row.route))
|
|
12712
12484
|
return draft(row, item, why);
|
|
12713
12485
|
const a = await client.postFull("/proxy/route/arm", { project: str7(row.project) ?? item });
|
|
@@ -12717,12 +12489,12 @@ function sledsSource(client, o) {
|
|
|
12717
12489
|
}
|
|
12718
12490
|
const armed = a.json?.armed;
|
|
12719
12491
|
if (!armedFor(armed, engine)) {
|
|
12720
|
-
o.log?.(`Pickup: Auto armed ${item} for ${
|
|
12492
|
+
o.log?.(`Pickup: Auto armed ${item} for ${isObject7(armed) ? str7(armed.engine) : "another engine"}`);
|
|
12721
12493
|
return null;
|
|
12722
12494
|
}
|
|
12723
12495
|
o.log?.(`Pickup: Auto armed ${item}, the next ready item on your sled`);
|
|
12724
|
-
const route =
|
|
12725
|
-
const states =
|
|
12496
|
+
const route = isObject7(row.route) ? row.route : {};
|
|
12497
|
+
const states = isObject7(route.states) ? route.states : {};
|
|
12726
12498
|
return {
|
|
12727
12499
|
item,
|
|
12728
12500
|
ready: strings(route.ready),
|
|
@@ -12733,7 +12505,7 @@ function sledsSource(client, o) {
|
|
|
12733
12505
|
}
|
|
12734
12506
|
async function draft(row, item, why, started = false) {
|
|
12735
12507
|
const project = str7(row.project) ?? item;
|
|
12736
|
-
const pending =
|
|
12508
|
+
const pending = isObject7(row.route) && isObject7(row.route.redraft) ? row.route.redraft : null;
|
|
12737
12509
|
const runner = typeof o.runner === "function" ? o.runner() : o.runner;
|
|
12738
12510
|
const r = await client.postFull("/proxy/route", {
|
|
12739
12511
|
project,
|
|
@@ -12751,22 +12523,22 @@ function sledsSource(client, o) {
|
|
|
12751
12523
|
let brief = null;
|
|
12752
12524
|
try {
|
|
12753
12525
|
brief = await client.get(`/proxy/route?q=${encodeURIComponent(project)}&draft=1`);
|
|
12754
|
-
pack = (
|
|
12526
|
+
pack = (isObject7(brief?.draft) ? str7(brief.draft.pack) : undefined) ?? "";
|
|
12755
12527
|
} catch {
|
|
12756
12528
|
pack = "";
|
|
12757
12529
|
}
|
|
12758
12530
|
let redraft;
|
|
12759
12531
|
if (pending) {
|
|
12760
|
-
const full =
|
|
12532
|
+
const full = isObject7(brief?.redraft) ? brief.redraft : {};
|
|
12761
12533
|
redraft = {
|
|
12762
12534
|
md: str7(full.md) ?? str7(pending.md) ?? "",
|
|
12763
12535
|
by: str7(full.by) ?? "a person",
|
|
12764
12536
|
decision: str7(full.decisionId) ?? str7(pending.decisionId) ?? "",
|
|
12765
|
-
route: routeText(brief,
|
|
12537
|
+
route: routeText(brief, isObject7(row.route) ? row.route.states : null)
|
|
12766
12538
|
};
|
|
12767
12539
|
}
|
|
12768
12540
|
o.log?.(redraft ? `${item}: planning the route again from ${redraft.by}'s answer — it waits for a yes` : `${started ? `${item}: Start` : "Pickup: Auto"} is planning ${started ? "its" : `${item}'s`} route first (${why.join(", ")}) — it waits for a yes`);
|
|
12769
|
-
const leaseUntil =
|
|
12541
|
+
const leaseUntil = num4(j.leaseUntil);
|
|
12770
12542
|
const claim = {
|
|
12771
12543
|
item,
|
|
12772
12544
|
node: DRAFT_NODE,
|
|
@@ -12827,9 +12599,10 @@ function sledsSource(client, o) {
|
|
|
12827
12599
|
mockRefused.delete(item);
|
|
12828
12600
|
const j = r.json;
|
|
12829
12601
|
const key = str7(j.key) ?? item;
|
|
12830
|
-
const band =
|
|
12602
|
+
const band = isObject7(j.band) ? mockBandText(j.band) : undefined;
|
|
12831
12603
|
o.log?.(`Pickup: Auto is drawing ${key}'s mock — a no-code session${band ? `, sized ${band}` : ""}`);
|
|
12832
|
-
const leaseUntil =
|
|
12604
|
+
const leaseUntil = num4(j.leaseUntil);
|
|
12605
|
+
const revise = reviseOf(j.revise);
|
|
12833
12606
|
return {
|
|
12834
12607
|
item: key,
|
|
12835
12608
|
node: MOCK_NODE,
|
|
@@ -12840,7 +12613,8 @@ function sledsSource(client, o) {
|
|
|
12840
12613
|
runId: str7(j.runId),
|
|
12841
12614
|
...leaseUntil !== undefined ? { leaseUntil } : {},
|
|
12842
12615
|
...str7(j.seatId) ? { seatId: str7(j.seatId) } : {},
|
|
12843
|
-
...str7(j.runToken) ? { runToken: str7(j.runToken) } : {}
|
|
12616
|
+
...str7(j.runToken) ? { runToken: str7(j.runToken) } : {},
|
|
12617
|
+
...revise ? { revise } : {}
|
|
12844
12618
|
};
|
|
12845
12619
|
}
|
|
12846
12620
|
async function postMock(body, what) {
|
|
@@ -12895,10 +12669,10 @@ function sledsSource(client, o) {
|
|
|
12895
12669
|
profileRead ??= readProfile(client);
|
|
12896
12670
|
return profileRead;
|
|
12897
12671
|
};
|
|
12898
|
-
const mine = Array.isArray(r.mine) ? r.mine.filter(
|
|
12672
|
+
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
|
|
12899
12673
|
for (const row of mine) {
|
|
12900
12674
|
const route = row.route;
|
|
12901
|
-
if (!
|
|
12675
|
+
if (!isObject7(route) || !armedFor(route.armed, o.engine) || !redraftDue(route))
|
|
12902
12676
|
continue;
|
|
12903
12677
|
const item = str7(row.key) ?? String(row.project);
|
|
12904
12678
|
const claimed = await draft(row, item, strings(route.needsRoute));
|
|
@@ -12918,7 +12692,7 @@ function sledsSource(client, o) {
|
|
|
12918
12692
|
it.ready = [];
|
|
12919
12693
|
if (room <= 0)
|
|
12920
12694
|
continue;
|
|
12921
|
-
const route =
|
|
12695
|
+
const route = isObject7(row.route) ? row.route : {};
|
|
12922
12696
|
const claimed = await draft(row, item, strings(route.needsRoute), true);
|
|
12923
12697
|
if (claimed?.draft && it) {
|
|
12924
12698
|
it.draft = claimed.draft;
|
|
@@ -12959,17 +12733,17 @@ function sledsSource(client, o) {
|
|
|
12959
12733
|
});
|
|
12960
12734
|
if (!r)
|
|
12961
12735
|
return { ok: false, error: UNREACHABLE3 };
|
|
12962
|
-
const taken = Array.isArray(r.json?.taken) ? r.json.taken.filter(
|
|
12736
|
+
const taken = Array.isArray(r.json?.taken) ? r.json.taken.filter(isObject7) : [];
|
|
12963
12737
|
const hit = taken.find((x) => x.node === node) ?? taken[0];
|
|
12964
12738
|
if (r.status >= 400 || !hit) {
|
|
12965
|
-
const failed = Array.isArray(r.json?.failed) ? r.json.failed.filter(
|
|
12739
|
+
const failed = Array.isArray(r.json?.failed) ? r.json.failed.filter(isObject7) : [];
|
|
12966
12740
|
return { ok: false, error: str7(failed[0]?.error) ?? serverMessage(r) };
|
|
12967
12741
|
}
|
|
12968
12742
|
let repos = strings(hit.repos);
|
|
12969
12743
|
if (!Array.isArray(hit.repos)) {
|
|
12970
12744
|
try {
|
|
12971
12745
|
const route = await routeOf(item);
|
|
12972
|
-
const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(
|
|
12746
|
+
const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject7) : [];
|
|
12973
12747
|
repos = strings(nodes.find((n) => n.key === (str7(hit.node) ?? node))?.repos);
|
|
12974
12748
|
} catch {
|
|
12975
12749
|
repos = [];
|
|
@@ -12981,7 +12755,7 @@ function sledsSource(client, o) {
|
|
|
12981
12755
|
} catch {
|
|
12982
12756
|
group = null;
|
|
12983
12757
|
}
|
|
12984
|
-
const leaseUntil =
|
|
12758
|
+
const leaseUntil = num4(hit.leaseUntil);
|
|
12985
12759
|
const runToken = str7(hit.runToken) ?? (taken.length === 1 ? str7(r.json?.runToken) : undefined);
|
|
12986
12760
|
const run = runOf(hit.run);
|
|
12987
12761
|
const claim = {
|
|
@@ -13020,17 +12794,17 @@ function sledsSource(client, o) {
|
|
|
13020
12794
|
} catch {
|
|
13021
12795
|
route = null;
|
|
13022
12796
|
}
|
|
13023
|
-
if (!
|
|
12797
|
+
if (!isObject7(route))
|
|
13024
12798
|
return "running";
|
|
13025
12799
|
if (claim.kind === "draft") {
|
|
13026
12800
|
const filed = Array.isArray(route.nodes) && route.nodes.length > 0;
|
|
13027
|
-
if (filed ||
|
|
12801
|
+
if (filed || isObject7(route.proposed) || isObject7(route.elsewhere))
|
|
13028
12802
|
return "done";
|
|
13029
|
-
if (
|
|
12803
|
+
if (isObject7(route.draftParked))
|
|
13030
12804
|
return "parked";
|
|
13031
12805
|
return "lost";
|
|
13032
12806
|
}
|
|
13033
|
-
const nodes = Array.isArray(route.nodes) ? route.nodes.filter(
|
|
12807
|
+
const nodes = Array.isArray(route.nodes) ? route.nodes.filter(isObject7) : [];
|
|
13034
12808
|
const state = nodes.find((n) => n.key === claim.node)?.state;
|
|
13035
12809
|
if (state === "parked")
|
|
13036
12810
|
return "parked";
|
|
@@ -13078,7 +12852,7 @@ function sledsSource(client, o) {
|
|
|
13078
12852
|
},
|
|
13079
12853
|
async openDecision(item, node) {
|
|
13080
12854
|
const route = await routeOf(item);
|
|
13081
|
-
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(
|
|
12855
|
+
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject7) : [];
|
|
13082
12856
|
const open = decisions.find((x) => x.state === "open" && x.node === node);
|
|
13083
12857
|
return open ? str7(open.id) ?? null : null;
|
|
13084
12858
|
},
|
|
@@ -13113,11 +12887,11 @@ function sledsSource(client, o) {
|
|
|
13113
12887
|
return "running";
|
|
13114
12888
|
try {
|
|
13115
12889
|
const route = await routeOf(a.item);
|
|
13116
|
-
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(
|
|
12890
|
+
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject7) : [];
|
|
13117
12891
|
const d = decisions.find((x) => x.id === a.decisionId);
|
|
13118
|
-
if (d?.state === "answered" &&
|
|
12892
|
+
if (d?.state === "answered" && isObject7(d.answerer) && d.answerer.verdict === "answered")
|
|
13119
12893
|
return "answered";
|
|
13120
|
-
if (d?.state === "answered" &&
|
|
12894
|
+
if (d?.state === "answered" && isObject7(d.answerer) && d.answerer.verdict === "released")
|
|
13121
12895
|
return "released";
|
|
13122
12896
|
if (d?.state === "escalated")
|
|
13123
12897
|
return "escalated";
|
|
@@ -13200,16 +12974,16 @@ function sledsSource(client, o) {
|
|
|
13200
12974
|
},
|
|
13201
12975
|
async decisionOf(item, decisionId) {
|
|
13202
12976
|
const route = await routeOf(item);
|
|
13203
|
-
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(
|
|
12977
|
+
const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject7) : [];
|
|
13204
12978
|
const d = decisions.find((x) => x.id === decisionId);
|
|
13205
12979
|
if (!d)
|
|
13206
12980
|
return null;
|
|
13207
|
-
const answer =
|
|
12981
|
+
const answer = isObject7(d.answer) ? str7(d.answer.md) : undefined;
|
|
13208
12982
|
return { state: str7(d.state) ?? "", ...answer ? { answer } : {} };
|
|
13209
12983
|
},
|
|
13210
12984
|
async routeBriefs(item) {
|
|
13211
12985
|
const route = await routeOf(item);
|
|
13212
|
-
const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(
|
|
12986
|
+
const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject7) : [];
|
|
13213
12987
|
return nodes.flatMap((n) => {
|
|
13214
12988
|
const key = str7(n.key);
|
|
13215
12989
|
const { plan } = nodePlanOf(n.plan);
|
|
@@ -13499,9 +13273,9 @@ function providerFailure(screen) {
|
|
|
13499
13273
|
// src/engine/worktree.ts
|
|
13500
13274
|
init_src();
|
|
13501
13275
|
import { appendFileSync, existsSync as existsSync9, mkdirSync as mkdirSync10 } from "node:fs";
|
|
13502
|
-
import { dirname as
|
|
13276
|
+
import { dirname as dirname8, isAbsolute, join as join11 } from "node:path";
|
|
13503
13277
|
function worktreePath(repoPath, name) {
|
|
13504
|
-
return
|
|
13278
|
+
return join11(repoPath, ".worktrees", name);
|
|
13505
13279
|
}
|
|
13506
13280
|
var fail2 = (what, r) => new Error(`${what} failed: ${(r.stderr || r.stdout).trim() || `exit ${r.status}`}`);
|
|
13507
13281
|
function defaultBranch(exec, repoPath) {
|
|
@@ -13524,7 +13298,7 @@ function defaultBranch(exec, repoPath) {
|
|
|
13524
13298
|
var realWorktreeFs = {
|
|
13525
13299
|
exists: existsSync9,
|
|
13526
13300
|
append: (p, text) => {
|
|
13527
|
-
mkdirSync10(
|
|
13301
|
+
mkdirSync10(dirname8(p), { recursive: true });
|
|
13528
13302
|
appendFileSync(p, text);
|
|
13529
13303
|
}
|
|
13530
13304
|
};
|
|
@@ -13536,7 +13310,7 @@ function ensureIgnored(exec, repoPath, fs = realWorktreeFs) {
|
|
|
13536
13310
|
if (common.status !== 0)
|
|
13537
13311
|
return;
|
|
13538
13312
|
const dir = common.stdout.trim();
|
|
13539
|
-
const exclude =
|
|
13313
|
+
const exclude = join11(isAbsolute(dir) ? dir : join11(repoPath, dir), "info", "exclude");
|
|
13540
13314
|
fs.append(exclude, `
|
|
13541
13315
|
# sleds engine: one worktree per route node
|
|
13542
13316
|
.worktrees/
|
|
@@ -13548,7 +13322,7 @@ function ensureWorktree(exec, repoPath, branch, path, base = "main", fs = realWo
|
|
|
13548
13322
|
return path;
|
|
13549
13323
|
}
|
|
13550
13324
|
function makeWorktree(exec, repoPath, branch, path, base, fs, log) {
|
|
13551
|
-
if (fs.exists(
|
|
13325
|
+
if (fs.exists(join11(path, ".git"))) {
|
|
13552
13326
|
fastForwardUntouched(exec, path, base, log);
|
|
13553
13327
|
return path;
|
|
13554
13328
|
}
|
|
@@ -13643,13 +13417,13 @@ function installArgv(command) {
|
|
|
13643
13417
|
return rest.every((a) => INSTALL_FLAGS.has(a)) ? argv : null;
|
|
13644
13418
|
}
|
|
13645
13419
|
function lockfileInstall(path, exists) {
|
|
13646
|
-
if (exists(
|
|
13420
|
+
if (exists(join11(path, "pnpm-lock.yaml")))
|
|
13647
13421
|
return ["pnpm", "install", "--frozen-lockfile"];
|
|
13648
|
-
if (exists(
|
|
13422
|
+
if (exists(join11(path, "bun.lock")) || exists(join11(path, "bun.lockb")))
|
|
13649
13423
|
return ["bun", "install", "--frozen-lockfile"];
|
|
13650
|
-
if (exists(
|
|
13424
|
+
if (exists(join11(path, "yarn.lock")))
|
|
13651
13425
|
return ["yarn", "install", "--frozen-lockfile"];
|
|
13652
|
-
if (exists(
|
|
13426
|
+
if (exists(join11(path, "package-lock.json")))
|
|
13653
13427
|
return ["npm", "ci"];
|
|
13654
13428
|
return null;
|
|
13655
13429
|
}
|
|
@@ -13707,7 +13481,7 @@ function claimRunOf(run, repo) {
|
|
|
13707
13481
|
};
|
|
13708
13482
|
}
|
|
13709
13483
|
function ensureInstalled(exec, path, fs, o = {}) {
|
|
13710
|
-
if (!fs.exists(
|
|
13484
|
+
if (!fs.exists(join11(path, "package.json")) || fs.exists(join11(path, "node_modules")))
|
|
13711
13485
|
return null;
|
|
13712
13486
|
const argv = installArgv(o.command) ?? lockfileInstall(path, fs.exists);
|
|
13713
13487
|
if (!argv)
|
|
@@ -13722,7 +13496,7 @@ function ensureInstalled(exec, path, fs, o = {}) {
|
|
|
13722
13496
|
return { argv, ok };
|
|
13723
13497
|
}
|
|
13724
13498
|
function ensureDetachedWorktree(exec, repoPath, path, base = "main", fs = realWorktreeFs) {
|
|
13725
|
-
if (fs.exists(
|
|
13499
|
+
if (fs.exists(join11(path, ".git")))
|
|
13726
13500
|
return path;
|
|
13727
13501
|
ensureIgnored(exec, repoPath, fs);
|
|
13728
13502
|
const f = exec("git", ["-C", repoPath, "fetch", "origin", base]);
|
|
@@ -15665,16 +15439,18 @@ async function startMock(d, claim, state, started, finished) {
|
|
|
15665
15439
|
base = d.defaultBranch(d.exec, repoPath);
|
|
15666
15440
|
const worktree = d.runner.makesWorktree ? repoPath : d.ensureDraftWorktree(d.exec, repoPath, worktreePath(repoPath, name), base) ?? worktreePath(repoPath, name);
|
|
15667
15441
|
out = d.mockOut(name);
|
|
15442
|
+
const revise = await currentMock(d, claim, out, at);
|
|
15668
15443
|
const prompt = mockPrompt({
|
|
15669
15444
|
item: claim.item,
|
|
15670
15445
|
title: claim.title,
|
|
15671
15446
|
pack: claim.pack,
|
|
15672
15447
|
out,
|
|
15673
15448
|
base,
|
|
15674
|
-
engine: d.engine
|
|
15449
|
+
engine: d.engine,
|
|
15450
|
+
...revise ? { revise } : {}
|
|
15675
15451
|
});
|
|
15676
15452
|
launch = nodeLaunchFor(d, at);
|
|
15677
|
-
const allow = [`Edit(/${out})`];
|
|
15453
|
+
const allow = [`Edit(/${out})`, ...revise ? [`Read(/${revise.path})`] : []];
|
|
15678
15454
|
handle = d.runner.start({
|
|
15679
15455
|
name,
|
|
15680
15456
|
repoPath,
|
|
@@ -15716,6 +15492,31 @@ async function startMock(d, claim, state, started, finished) {
|
|
|
15716
15492
|
}
|
|
15717
15493
|
started.push({ item: claim.item, node: MOCK_NODE, watch, watchTarget: watchTarget(handle) });
|
|
15718
15494
|
}
|
|
15495
|
+
function currentMockPath(out) {
|
|
15496
|
+
return `${out.replace(/\.html$/i, "")}.current.html`;
|
|
15497
|
+
}
|
|
15498
|
+
async function currentMock(d, claim, out, at) {
|
|
15499
|
+
const r = claim.revise;
|
|
15500
|
+
if (!r)
|
|
15501
|
+
return;
|
|
15502
|
+
const fresh = (why) => {
|
|
15503
|
+
d.log(`${at}: could not read ${r.name} to revise it (${why}) — drawing a fresh mock`);
|
|
15504
|
+
return;
|
|
15505
|
+
};
|
|
15506
|
+
if (!d.fetchMock || !d.writeMock)
|
|
15507
|
+
return fresh("this engine cannot fetch mocks");
|
|
15508
|
+
try {
|
|
15509
|
+
const html = await d.fetchMock(r.url);
|
|
15510
|
+
if (!html)
|
|
15511
|
+
return fresh(`nothing came back from ${r.url}`);
|
|
15512
|
+
const path = currentMockPath(out);
|
|
15513
|
+
d.writeMock(path, html);
|
|
15514
|
+
d.log(`${at}: revising ${r.name} — its current HTML is at ${path}`);
|
|
15515
|
+
return { name: r.name, path };
|
|
15516
|
+
} catch (e) {
|
|
15517
|
+
return fresh(message(e));
|
|
15518
|
+
}
|
|
15519
|
+
}
|
|
15719
15520
|
function mockChangedCode(exec, cwd, base) {
|
|
15720
15521
|
const status = exec("git", ["-C", cwd, "status", "--porcelain"]);
|
|
15721
15522
|
if (status.status !== 0)
|
|
@@ -15890,9 +15691,16 @@ ${instructionNudge(url, items)}`;
|
|
|
15890
15691
|
function reviewNudge(url, count) {
|
|
15891
15692
|
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.`;
|
|
15892
15693
|
}
|
|
15893
|
-
function lookQuestion(url, mock) {
|
|
15894
|
-
|
|
15694
|
+
function lookQuestion(url, mock, comparison) {
|
|
15695
|
+
const head = `A draft PR waits for your look: ${url}.${mock ? ` The mock: ${mock}.` : " Its body names no mock; the PR is the place to look."}`;
|
|
15696
|
+
const compared = comparison ? lookComparisonLines(comparison) : "No comparison came: the PR does not set the preview beside the mock — compare them yourself before it goes on.";
|
|
15697
|
+
return `${head}
|
|
15698
|
+
|
|
15699
|
+
${compared}
|
|
15700
|
+
|
|
15701
|
+
Looks good marks it ready for review.`;
|
|
15895
15702
|
}
|
|
15703
|
+
var LOOK_WAIT_MS = 30 * 60000;
|
|
15896
15704
|
async function judgeLook(d, run, view) {
|
|
15897
15705
|
const looks = looksOf(d.source);
|
|
15898
15706
|
const pr = run.pr;
|
|
@@ -15900,15 +15708,25 @@ async function judgeLook(d, run, view) {
|
|
|
15900
15708
|
return;
|
|
15901
15709
|
const draft = view.state === "OPEN" && view.draft;
|
|
15902
15710
|
if (draft && !pr.look) {
|
|
15711
|
+
if (!view.comparison) {
|
|
15712
|
+
if (pr.lookWait === undefined) {
|
|
15713
|
+
pr.lookWait = d.now();
|
|
15714
|
+
d.log(`${ref(run)}: ${pr.url} is a draft — the look waits for the preview's comparison`);
|
|
15715
|
+
return;
|
|
15716
|
+
}
|
|
15717
|
+
if (d.now() - pr.lookWait < LOOK_WAIT_MS)
|
|
15718
|
+
return;
|
|
15719
|
+
}
|
|
15903
15720
|
try {
|
|
15904
15721
|
const r = await looks.openLook(run.runId, {
|
|
15905
|
-
md: lookQuestion(pr.url, view.mock),
|
|
15722
|
+
md: lookQuestion(pr.url, view.mock, view.comparison),
|
|
15906
15723
|
pr: pr.url,
|
|
15907
15724
|
...view.mock ? { mock: view.mock } : {}
|
|
15908
15725
|
}, d.engine);
|
|
15909
15726
|
if (!r.decisionId)
|
|
15910
15727
|
return;
|
|
15911
15728
|
pr.look = r.decisionId;
|
|
15729
|
+
pr.lookWait = undefined;
|
|
15912
15730
|
if (r.opened)
|
|
15913
15731
|
d.log(`${ref(run)}: ${pr.url} is a draft — a look waits for a person`);
|
|
15914
15732
|
} catch (e) {
|
|
@@ -15924,6 +15742,8 @@ async function judgeLook(d, run, view) {
|
|
|
15924
15742
|
d.log(`${ref(run)}: could not clear the look on ${pr.url}: ${message(e)}`);
|
|
15925
15743
|
}
|
|
15926
15744
|
}
|
|
15745
|
+
if (!draft)
|
|
15746
|
+
pr.lookWait = undefined;
|
|
15927
15747
|
}
|
|
15928
15748
|
async function follow(d, state, run, claim, runner, finished, attention, changes, decided) {
|
|
15929
15749
|
const pr = run.pr;
|
|
@@ -16864,7 +16684,7 @@ async function settleEvent(d, events, state, dec, attention, decided) {
|
|
|
16864
16684
|
init_machine();
|
|
16865
16685
|
|
|
16866
16686
|
// src/engine/repos.ts
|
|
16867
|
-
import { basename as
|
|
16687
|
+
import { basename as basename3, dirname as dirname9, join as join12 } from "node:path";
|
|
16868
16688
|
function splitReposDirs(raw) {
|
|
16869
16689
|
return (raw ?? "").split(/[:\n]/).map((d) => d.trim()).filter(Boolean);
|
|
16870
16690
|
}
|
|
@@ -16876,7 +16696,7 @@ function resolveRepoPath(o) {
|
|
|
16876
16696
|
error: `No repo for ${o.repos.length ? o.repos.join(", ") : "this node"}: --repo ${o.repo} is not a git checkout. Clone the repo there, or start the engine with --repo set to a clone.`
|
|
16877
16697
|
};
|
|
16878
16698
|
}
|
|
16879
|
-
const names = o.repos.map((r) =>
|
|
16699
|
+
const names = o.repos.map((r) => basename3(r.trim())).filter(Boolean);
|
|
16880
16700
|
const dirs = o.reposDirs ?? [];
|
|
16881
16701
|
if (dirs.length === 0 || names.length === 0) {
|
|
16882
16702
|
if (insideCheckout(o.cwd, o.exists))
|
|
@@ -16891,21 +16711,21 @@ function resolveRepoPath(o) {
|
|
|
16891
16711
|
if (name.startsWith("."))
|
|
16892
16712
|
continue;
|
|
16893
16713
|
for (const dir of dirs) {
|
|
16894
|
-
const p =
|
|
16895
|
-
if (o.exists(
|
|
16714
|
+
const p = join12(dir, name);
|
|
16715
|
+
if (o.exists(join12(p, ".git")))
|
|
16896
16716
|
return p;
|
|
16897
16717
|
}
|
|
16898
16718
|
}
|
|
16899
16719
|
const want = o.repos.join(", ");
|
|
16900
|
-
const where = names.flatMap((n) => dirs.map((d) =>
|
|
16720
|
+
const where = names.flatMap((n) => dirs.map((d) => join12(d, n))).join(" or ");
|
|
16901
16721
|
return {
|
|
16902
16722
|
error: `No checkout of ${want} on this engine's machine: expected ${where}. Clone it there (or pass --repo).`
|
|
16903
16723
|
};
|
|
16904
16724
|
}
|
|
16905
|
-
var isRoot = (p) =>
|
|
16725
|
+
var isRoot = (p) => dirname9(p) === p;
|
|
16906
16726
|
function insideCheckout(dir, exists) {
|
|
16907
|
-
for (let d = dir;!isRoot(d); d =
|
|
16908
|
-
if (exists(
|
|
16727
|
+
for (let d = dir;!isRoot(d); d = dirname9(d)) {
|
|
16728
|
+
if (exists(join12(d, ".git")))
|
|
16909
16729
|
return true;
|
|
16910
16730
|
}
|
|
16911
16731
|
return false;
|
|
@@ -16950,7 +16770,7 @@ init_meter();
|
|
|
16950
16770
|
|
|
16951
16771
|
// src/runners/gitGuard.ts
|
|
16952
16772
|
import { statSync as statSync2 } from "node:fs";
|
|
16953
|
-
import { basename as
|
|
16773
|
+
import { basename as basename4, dirname as dirname10, join as join13, resolve as resolve6 } from "node:path";
|
|
16954
16774
|
var GIT_GUARD_ENV = {
|
|
16955
16775
|
GIT_CONFIG_COUNT: "4",
|
|
16956
16776
|
GIT_CONFIG_KEY_0: "core.fsmonitor",
|
|
@@ -16983,13 +16803,13 @@ var isFile = (p) => statSync2(p, { throwIfNoEntry: false })?.isFile() ?? false;
|
|
|
16983
16803
|
var isDir = (p) => statSync2(p, { throwIfNoEntry: false })?.isDirectory() ?? false;
|
|
16984
16804
|
function ownGitDirs(dir, stat = { isFile, isDir }) {
|
|
16985
16805
|
const wt = resolve6(dir);
|
|
16986
|
-
if (
|
|
16806
|
+
if (basename4(dirname10(wt)) !== ".worktrees")
|
|
16987
16807
|
return null;
|
|
16988
|
-
const common =
|
|
16989
|
-
if (!stat.isFile(
|
|
16808
|
+
const common = join13(dirname10(dirname10(wt)), ".git");
|
|
16809
|
+
if (!stat.isFile(join13(wt, ".git")) || !stat.isDir(common))
|
|
16990
16810
|
return null;
|
|
16991
16811
|
return {
|
|
16992
|
-
GIT_DIR:
|
|
16812
|
+
GIT_DIR: join13(common, "worktrees", basename4(wt)),
|
|
16993
16813
|
GIT_COMMON_DIR: common,
|
|
16994
16814
|
GIT_WORK_TREE: wt
|
|
16995
16815
|
};
|
|
@@ -16999,14 +16819,14 @@ var callDir = (args, cwd) => {
|
|
|
16999
16819
|
return args[0] === "-C" && args[1] ? resolve6(base, args[1]) : base;
|
|
17000
16820
|
};
|
|
17001
16821
|
var GUARDED = new Set(["git", "gh"]);
|
|
17002
|
-
var guardGit = (exec, guard = gitGuardEnv) => (cmd, args, o) => GUARDED.has(
|
|
16822
|
+
var guardGit = (exec, guard = gitGuardEnv) => (cmd, args, o) => GUARDED.has(basename4(cmd)) ? exec(cmd, args, {
|
|
17003
16823
|
...o,
|
|
17004
16824
|
env: { ...o?.env, ...guard(), ...ownGitDirs(callDir(args, o?.cwd)) }
|
|
17005
16825
|
}) : exec(cmd, args, o);
|
|
17006
16826
|
|
|
17007
16827
|
// src/runners/cmux.ts
|
|
17008
16828
|
import { existsSync as existsSync10, rmSync as rmSync3, writeFileSync as writeFileSync10 } from "node:fs";
|
|
17009
|
-
import { delimiter, join as
|
|
16829
|
+
import { delimiter, join as join14 } from "node:path";
|
|
17010
16830
|
|
|
17011
16831
|
// src/keychain.ts
|
|
17012
16832
|
var CMUX_KEYCHAIN_SERVICE = "ai.sleds.cmux";
|
|
@@ -17037,7 +16857,7 @@ var clearCmuxPassword = (exec) => exec("security", ["delete-generic-password", .
|
|
|
17037
16857
|
var CMUX_APP_BIN = "/Applications/cmux.app/Contents/Resources/bin/cmux";
|
|
17038
16858
|
var resolveCmuxBin = (exists = existsSync10, path = process.env.PATH ?? "") => {
|
|
17039
16859
|
for (const dir of path.split(delimiter)) {
|
|
17040
|
-
if (dir && exists(
|
|
16860
|
+
if (dir && exists(join14(dir, "cmux")))
|
|
17041
16861
|
return "cmux";
|
|
17042
16862
|
}
|
|
17043
16863
|
return exists(CMUX_APP_BIN) ? CMUX_APP_BIN : "cmux";
|
|
@@ -18052,7 +17872,7 @@ ${renderTranscript(eventMessages(all))}`;
|
|
|
18052
17872
|
|
|
18053
17873
|
// src/runners/orca.ts
|
|
18054
17874
|
import { existsSync as existsSync11, lstatSync, readlinkSync, writeFileSync as writeFileSync11 } from "node:fs";
|
|
18055
|
-
import { join as
|
|
17875
|
+
import { join as join15, resolve as resolve7 } from "node:path";
|
|
18056
17876
|
var obj3 = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
18057
17877
|
var str11 = (v) => typeof v === "string" && v.length > 0 ? v : null;
|
|
18058
17878
|
var parseOrcaJson = (stdout) => {
|
|
@@ -18115,7 +17935,7 @@ var realFs = { lstat: lstatSync, readlink: readlinkSync, exists: existsSync11 };
|
|
|
18115
17935
|
var ORCA_LINK_FIX = "reinstall Orca's shell command from Orca (it links `orca` onto your PATH)";
|
|
18116
17936
|
function danglingOrca(path, fs) {
|
|
18117
17937
|
for (const dir of path.split(":").filter(Boolean)) {
|
|
18118
|
-
const link =
|
|
17938
|
+
const link = join15(dir, "orca");
|
|
18119
17939
|
try {
|
|
18120
17940
|
if (!fs.lstat(link).isSymbolicLink())
|
|
18121
17941
|
return null;
|
|
@@ -18413,9 +18233,9 @@ function restoreRunner(name, exec = defaultExec) {
|
|
|
18413
18233
|
|
|
18414
18234
|
// src/runtime.ts
|
|
18415
18235
|
import { homedir as homedir2 } from "node:os";
|
|
18416
|
-
import { join as
|
|
18236
|
+
import { join as join16, win32 } from "node:path";
|
|
18417
18237
|
var isCompiled = (argv1 = process.argv[1]) => Boolean(argv1 && (argv1.startsWith("/$bunfs/") || argv1.startsWith("B:\\~BUN\\")));
|
|
18418
|
-
var sledsLink = (home = homedir2(), platform = process.platform) => platform === "win32" ? win32.join(process.env.LOCALAPPDATA ?? win32.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") :
|
|
18238
|
+
var sledsLink = (home = homedir2(), platform = process.platform) => platform === "win32" ? win32.join(process.env.LOCALAPPDATA ?? win32.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join16(home, ".sleds", "bin", "sleds");
|
|
18419
18239
|
|
|
18420
18240
|
// src/commands/engine.ts
|
|
18421
18241
|
init_settings();
|
|
@@ -18434,7 +18254,7 @@ import {
|
|
|
18434
18254
|
writeSync as writeSync2
|
|
18435
18255
|
} from "node:fs";
|
|
18436
18256
|
import { homedir as homedir7 } from "node:os";
|
|
18437
|
-
import { join as
|
|
18257
|
+
import { join as join22 } from "node:path";
|
|
18438
18258
|
|
|
18439
18259
|
// ../../packages/shared/src/updates/manifest.ts
|
|
18440
18260
|
var CLI_PLATFORMS = [
|
|
@@ -18546,14 +18366,14 @@ import {
|
|
|
18546
18366
|
var RELEASE_PUBLIC_KEY = "MCowBQYDK2VwAyEADIZiQghghQlN6WoLDF9xLmqMeFSQL4crcCBT4wINNCc=";
|
|
18547
18367
|
|
|
18548
18368
|
// ../../packages/shared/src/updates/verify.ts
|
|
18549
|
-
import { createPrivateKey, createPublicKey
|
|
18369
|
+
import { createPrivateKey, createPublicKey, sign, verify } from "node:crypto";
|
|
18550
18370
|
var B64_RE = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
18551
18371
|
function verifyManifest(text, signatureB64, publicKeySpkiB64) {
|
|
18552
18372
|
try {
|
|
18553
18373
|
const sig = signatureB64.trim();
|
|
18554
18374
|
if (!B64_RE.test(sig))
|
|
18555
18375
|
return false;
|
|
18556
|
-
const key =
|
|
18376
|
+
const key = createPublicKey({
|
|
18557
18377
|
key: Buffer.from(publicKeySpkiB64, "base64"),
|
|
18558
18378
|
format: "der",
|
|
18559
18379
|
type: "spki"
|
|
@@ -18577,12 +18397,12 @@ import {
|
|
|
18577
18397
|
writeFileSync as writeFileSync12
|
|
18578
18398
|
} from "node:fs";
|
|
18579
18399
|
import { homedir as homedir3 } from "node:os";
|
|
18580
|
-
import { dirname as
|
|
18400
|
+
import { dirname as dirname11, join as join17, win32 as win322 } from "node:path";
|
|
18581
18401
|
var UPDATE_LOCK_STALE_MS = 10 * 60000;
|
|
18582
18402
|
function sledsRoot(home = homedir3(), platform = process.platform) {
|
|
18583
|
-
return platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds") :
|
|
18403
|
+
return platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds") : join17(home, ".sleds");
|
|
18584
18404
|
}
|
|
18585
|
-
var pathFor = (platform) => platform === "win32" ? win322 : { join:
|
|
18405
|
+
var pathFor = (platform) => platform === "win32" ? win322 : { join: join17 };
|
|
18586
18406
|
function versionDir(home, v, platform = process.platform) {
|
|
18587
18407
|
return pathFor(platform).join(sledsRoot(home, platform), "versions", v);
|
|
18588
18408
|
}
|
|
@@ -18655,7 +18475,7 @@ function readUpdateState(home) {
|
|
|
18655
18475
|
}
|
|
18656
18476
|
function writeUpdateState(home, s) {
|
|
18657
18477
|
const path = updateStatePath(home);
|
|
18658
|
-
mkdirSync11(
|
|
18478
|
+
mkdirSync11(dirname11(path), { recursive: true, mode: 448 });
|
|
18659
18479
|
const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
18660
18480
|
writeFileSync12(tmp, `${JSON.stringify(s, null, 2)}
|
|
18661
18481
|
`, { mode: 384 });
|
|
@@ -18733,7 +18553,7 @@ function breakStale(path, seen, token) {
|
|
|
18733
18553
|
async function withUpdateLock(home, fn, o = {}) {
|
|
18734
18554
|
const waitMs = o.waitMs ?? 30000;
|
|
18735
18555
|
const path = updateLockPath(home);
|
|
18736
|
-
mkdirSync11(
|
|
18556
|
+
mkdirSync11(dirname11(path), { recursive: true, mode: 448 });
|
|
18737
18557
|
const token = randomUUID();
|
|
18738
18558
|
const tmp = `${path}.${token}.tmp`;
|
|
18739
18559
|
writeFileSync12(tmp, `${JSON.stringify({ pid: process.pid, at: Date.now(), token })}
|
|
@@ -18812,7 +18632,7 @@ async function fetchVersion(o) {
|
|
|
18812
18632
|
const platform = o.platform ?? process.platform;
|
|
18813
18633
|
const arch = o.arch ?? process.arch;
|
|
18814
18634
|
const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
|
|
18815
|
-
const running = o.running ?? "0.1.
|
|
18635
|
+
const running = o.running ?? "0.1.73";
|
|
18816
18636
|
if (!publicKey)
|
|
18817
18637
|
return { ok: false, why: "no release key yet" };
|
|
18818
18638
|
if (!VERSION_RE2.test(o.version))
|
|
@@ -18907,19 +18727,19 @@ import {
|
|
|
18907
18727
|
writeFileSync as writeFileSync14
|
|
18908
18728
|
} from "node:fs";
|
|
18909
18729
|
import { homedir as homedir4 } from "node:os";
|
|
18910
|
-
import { basename as
|
|
18730
|
+
import { basename as basename5, delimiter as delimiter2, dirname as dirname12, isAbsolute as isAbsolute2, join as join20, relative } from "node:path";
|
|
18911
18731
|
|
|
18912
18732
|
// src/commands/engineSystemd.ts
|
|
18913
|
-
import { join as
|
|
18733
|
+
import { join as join18 } from "node:path";
|
|
18914
18734
|
var BOX_ENV_UNIT_PATH = "%h/.config/sleds/box.env";
|
|
18915
18735
|
function boxEnvPath(home) {
|
|
18916
|
-
return
|
|
18736
|
+
return join18(home, ".config", "sleds", "box.env");
|
|
18917
18737
|
}
|
|
18918
18738
|
function engineUnitDir(home) {
|
|
18919
|
-
return
|
|
18739
|
+
return join18(home, ".config", "systemd", "user");
|
|
18920
18740
|
}
|
|
18921
18741
|
function engineUnitPath(home, label) {
|
|
18922
|
-
return
|
|
18742
|
+
return join18(engineUnitDir(home), `${label}.service`);
|
|
18923
18743
|
}
|
|
18924
18744
|
function systemdQuote(s) {
|
|
18925
18745
|
const body = s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/%/g, "%%").replace(/\$/g, "$$$$");
|
|
@@ -18959,20 +18779,20 @@ function parseEngineUnit(text) {
|
|
|
18959
18779
|
}
|
|
18960
18780
|
|
|
18961
18781
|
// src/schedule.ts
|
|
18962
|
-
import { spawnSync as
|
|
18782
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
18963
18783
|
import { existsSync as existsSync13, mkdirSync as mkdirSync13, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "node:fs";
|
|
18964
|
-
import { join as
|
|
18784
|
+
import { join as join19 } from "node:path";
|
|
18965
18785
|
var REVERT_LABEL = "ai.sleds.revert";
|
|
18966
18786
|
var defaultExec2 = (cmd, args) => {
|
|
18967
|
-
const r =
|
|
18787
|
+
const r = spawnSync3(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
|
|
18968
18788
|
if (r.error)
|
|
18969
18789
|
return { ok: false, stderr: r.error.message };
|
|
18970
18790
|
return { ok: r.status === 0, stderr: r.stderr ?? "" };
|
|
18971
18791
|
};
|
|
18972
|
-
var plistPath = (home) =>
|
|
18973
|
-
var
|
|
18792
|
+
var plistPath = (home) => join19(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
|
|
18793
|
+
var xmlEscape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
18974
18794
|
var buildLaunchdPlist = (sledsArgv, deadline) => {
|
|
18975
|
-
const args = [...sledsArgv, "off"].map((a) => ` <string>${
|
|
18795
|
+
const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape(a)}</string>`).join(`
|
|
18976
18796
|
`);
|
|
18977
18797
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
18978
18798
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -19008,7 +18828,7 @@ var scheduleRevert = (d, deadlineMs) => {
|
|
|
19008
18828
|
if (d.platform === "darwin") {
|
|
19009
18829
|
const p = plistPath(d.home);
|
|
19010
18830
|
try {
|
|
19011
|
-
mkdirSync13(
|
|
18831
|
+
mkdirSync13(join19(d.home, "Library", "LaunchAgents"), { recursive: true });
|
|
19012
18832
|
d.exec("launchctl", ["unload", p]);
|
|
19013
18833
|
writeFileSync13(p, buildLaunchdPlist(d.sledsArgv, deadline));
|
|
19014
18834
|
const r = d.exec("launchctl", ["load", p]);
|
|
@@ -19060,9 +18880,9 @@ var HOOK_SUBS = [
|
|
|
19060
18880
|
"stop-event",
|
|
19061
18881
|
"permission-event"
|
|
19062
18882
|
];
|
|
19063
|
-
var migrateBakDir = (home) =>
|
|
19064
|
-
var manifestPath = (home) =>
|
|
19065
|
-
var
|
|
18883
|
+
var migrateBakDir = (home) => join20(sledsRoot(home), "migrate.bak");
|
|
18884
|
+
var manifestPath = (home) => join20(migrateBakDir(home), "manifest.json");
|
|
18885
|
+
var xmlEscape2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
19066
18886
|
var xmlUnescape = (s) => s.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
19067
18887
|
var shQuote = (s) => /^[\w./~-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
|
|
19068
18888
|
function rewritePlist(text, link) {
|
|
@@ -19083,7 +18903,7 @@ function rewritePlist(text, link) {
|
|
|
19083
18903
|
return null;
|
|
19084
18904
|
const from = bodyAt + first.index;
|
|
19085
18905
|
const to = bodyAt + last.index + last[0].length;
|
|
19086
|
-
return `${text.slice(0, from)}<string>${
|
|
18906
|
+
return `${text.slice(0, from)}<string>${xmlEscape2(link)}</string>${text.slice(to)}`;
|
|
19087
18907
|
}
|
|
19088
18908
|
function rewriteUnit(text, link) {
|
|
19089
18909
|
const line = /^ExecStart=(.*)$/m.exec(text);
|
|
@@ -19161,15 +18981,15 @@ function rewriteSettings(text, link) {
|
|
|
19161
18981
|
}
|
|
19162
18982
|
var listDir = (dir, keep) => {
|
|
19163
18983
|
try {
|
|
19164
|
-
return readdirSync2(dir).filter(keep).sort().map((n) =>
|
|
18984
|
+
return readdirSync2(dir).filter(keep).sort().map((n) => join20(dir, n));
|
|
19165
18985
|
} catch {
|
|
19166
18986
|
return [];
|
|
19167
18987
|
}
|
|
19168
18988
|
};
|
|
19169
18989
|
function unitFiles(home) {
|
|
19170
|
-
const agents = listDir(
|
|
18990
|
+
const agents = listDir(join20(home, "Library", "LaunchAgents"), (n) => n.startsWith("ai.sleds.") && n.endsWith(".plist")).map((path) => ({
|
|
19171
18991
|
path,
|
|
19172
|
-
...
|
|
18992
|
+
...basename5(path).startsWith("ai.sleds.revert") ? {} : { reload: "launchd" }
|
|
19173
18993
|
}));
|
|
19174
18994
|
const units = listDir(engineUnitDir(home), (n) => n.startsWith("ai.sleds.") && n.endsWith(".service")).map((path) => ({ path, reload: "systemd" }));
|
|
19175
18995
|
return [...agents, ...units];
|
|
@@ -19179,7 +18999,7 @@ function unitClaudeDir(text) {
|
|
|
19179
18999
|
return plist ? xmlUnescape(plist) : undefined;
|
|
19180
19000
|
}
|
|
19181
19001
|
function claudeDirs(home, env) {
|
|
19182
|
-
const dirs = [
|
|
19002
|
+
const dirs = [join20(home, ".claude"), claudeDir(home, env)];
|
|
19183
19003
|
for (const u of unitFiles(home)) {
|
|
19184
19004
|
try {
|
|
19185
19005
|
const d = unitClaudeDir(readFileSync13(u.path, "utf8"));
|
|
@@ -19203,7 +19023,7 @@ function migrationPlan(home, link, env = process.env) {
|
|
|
19203
19023
|
out.push({ ...u, text: next });
|
|
19204
19024
|
}
|
|
19205
19025
|
for (const dir of claudeDirs(home, env)) {
|
|
19206
|
-
const path =
|
|
19026
|
+
const path = join20(dir, "settings.json");
|
|
19207
19027
|
let text;
|
|
19208
19028
|
try {
|
|
19209
19029
|
text = readFileSync13(path, "utf8");
|
|
@@ -19218,7 +19038,7 @@ function migrationPlan(home, link, env = process.env) {
|
|
|
19218
19038
|
}
|
|
19219
19039
|
var backupFor = (home, path) => {
|
|
19220
19040
|
const rel = relative(home, path);
|
|
19221
|
-
return rel.startsWith("..") || isAbsolute2(rel) ?
|
|
19041
|
+
return rel.startsWith("..") || isAbsolute2(rel) ? join20(migrateBakDir(home), "abs", path) : join20(migrateBakDir(home), rel);
|
|
19222
19042
|
};
|
|
19223
19043
|
function writeKeepingMode(path, text) {
|
|
19224
19044
|
let mode = 420;
|
|
@@ -19235,7 +19055,7 @@ function copyInto(from, to) {
|
|
|
19235
19055
|
renameSync9(tmp, to);
|
|
19236
19056
|
}
|
|
19237
19057
|
function pointLink(link, bin) {
|
|
19238
|
-
mkdirSync14(
|
|
19058
|
+
mkdirSync14(dirname12(link), { recursive: true, mode: 448 });
|
|
19239
19059
|
const tmp = `${link}.tmp`;
|
|
19240
19060
|
rmSync7(tmp, { force: true });
|
|
19241
19061
|
symlinkSync(bin, tmp);
|
|
@@ -19260,7 +19080,7 @@ function reloadScript(lock, files) {
|
|
|
19260
19080
|
for (const a of agents)
|
|
19261
19081
|
lines.push(`launchctl unload ${shQuote(a.path)} 2>/dev/null; launchctl load ${shQuote(a.path)}`);
|
|
19262
19082
|
if (units.length)
|
|
19263
|
-
lines.push("systemctl --user daemon-reload", `systemctl --user --no-block restart ${units.map((u) => shQuote(
|
|
19083
|
+
lines.push("systemctl --user daemon-reload", `systemctl --user --no-block restart ${units.map((u) => shQuote(basename5(u.path))).join(" ")}`);
|
|
19264
19084
|
if (!lines.length)
|
|
19265
19085
|
return null;
|
|
19266
19086
|
return [
|
|
@@ -19354,7 +19174,7 @@ async function migrateToBinary(o) {
|
|
|
19354
19174
|
rmSync7(migrateBakDir(home), { recursive: true, force: true });
|
|
19355
19175
|
for (const p of plan) {
|
|
19356
19176
|
const backup = backupFor(home, p.path);
|
|
19357
|
-
mkdirSync14(
|
|
19177
|
+
mkdirSync14(dirname12(backup), { recursive: true, mode: 448 });
|
|
19358
19178
|
copyFileSync(p.path, backup);
|
|
19359
19179
|
manifest.files.push({ path: p.path, backup, ...p.reload ? { reload: p.reload } : {} });
|
|
19360
19180
|
}
|
|
@@ -19388,7 +19208,7 @@ async function migrateToBinary(o) {
|
|
|
19388
19208
|
log(`sleds stays on the npm install: ${result.why}`);
|
|
19389
19209
|
return { ok: false, why: result.why };
|
|
19390
19210
|
}
|
|
19391
|
-
const binDir =
|
|
19211
|
+
const binDir = dirname12(link);
|
|
19392
19212
|
if (!(env.PATH ?? "").split(delimiter2).includes(binDir))
|
|
19393
19213
|
log(`${binDir} is not on your PATH — add it in your shell profile to run this sleds from a terminal (sleds never edits it)`);
|
|
19394
19214
|
reload(home, result.files, detach);
|
|
@@ -19408,10 +19228,10 @@ import {
|
|
|
19408
19228
|
symlinkSync as symlinkSync2
|
|
19409
19229
|
} from "node:fs";
|
|
19410
19230
|
import { homedir as homedir5 } from "node:os";
|
|
19411
|
-
import { dirname as
|
|
19231
|
+
import { dirname as dirname13, join as join21 } from "node:path";
|
|
19412
19232
|
var NO_PREVIOUS = "no previous version on this machine";
|
|
19413
19233
|
function allStateFiles(home = homedir5(), env = process.env) {
|
|
19414
|
-
const roots = [...new Set([configDir(home, env),
|
|
19234
|
+
const roots = [...new Set([configDir(home, env), join21(home, ".config", "sleds")])];
|
|
19415
19235
|
const out = [];
|
|
19416
19236
|
const walk = (dir) => {
|
|
19417
19237
|
let names;
|
|
@@ -19422,20 +19242,20 @@ function allStateFiles(home = homedir5(), env = process.env) {
|
|
|
19422
19242
|
}
|
|
19423
19243
|
for (const n of names.sort())
|
|
19424
19244
|
if (n.endsWith(".json") && n !== "removed-engines.json")
|
|
19425
|
-
out.push(
|
|
19245
|
+
out.push(join21(dir, n));
|
|
19426
19246
|
for (const sub of ["orgs", "seats"]) {
|
|
19427
19247
|
let kids;
|
|
19428
19248
|
try {
|
|
19429
|
-
kids = readdirSync3(
|
|
19249
|
+
kids = readdirSync3(join21(dir, sub));
|
|
19430
19250
|
} catch {
|
|
19431
19251
|
continue;
|
|
19432
19252
|
}
|
|
19433
19253
|
for (const k of kids.sort())
|
|
19434
|
-
walk(
|
|
19254
|
+
walk(join21(dir, sub, k));
|
|
19435
19255
|
}
|
|
19436
19256
|
};
|
|
19437
19257
|
for (const r of roots)
|
|
19438
|
-
walk(
|
|
19258
|
+
walk(join21(r, "engine"));
|
|
19439
19259
|
return out;
|
|
19440
19260
|
}
|
|
19441
19261
|
var backupPath2 = (file, v) => `${file}.${v}.bak`;
|
|
@@ -19449,7 +19269,7 @@ function pointBinAt(home, v, platform) {
|
|
|
19449
19269
|
const target = versionBin(home, v, platform);
|
|
19450
19270
|
if (!existsSync14(target))
|
|
19451
19271
|
throw new Error(`${target} is missing — sleds ${v} is not downloaded`);
|
|
19452
|
-
mkdirSync15(
|
|
19272
|
+
mkdirSync15(dirname13(bin), { recursive: true, mode: 448 });
|
|
19453
19273
|
if (platform === "win32") {
|
|
19454
19274
|
replaceAside(bin, target);
|
|
19455
19275
|
return;
|
|
@@ -19521,7 +19341,7 @@ function applyConfirm(s, home, o = {}) {
|
|
|
19521
19341
|
if (!s.current)
|
|
19522
19342
|
return;
|
|
19523
19343
|
for (const f of o.stateFiles ?? allStateFiles(home)) {
|
|
19524
|
-
const dir =
|
|
19344
|
+
const dir = dirname13(f);
|
|
19525
19345
|
const prefix = `${f.slice(dir.length + 1)}.`;
|
|
19526
19346
|
let names;
|
|
19527
19347
|
try {
|
|
@@ -19531,10 +19351,10 @@ function applyConfirm(s, home, o = {}) {
|
|
|
19531
19351
|
}
|
|
19532
19352
|
for (const n of names)
|
|
19533
19353
|
if (n.startsWith(prefix) && n.endsWith(".bak"))
|
|
19534
|
-
rmSync8(
|
|
19354
|
+
rmSync8(join21(dir, n), { force: true });
|
|
19535
19355
|
}
|
|
19536
19356
|
const keep = new Set([s.current, s.previous, s.drain?.to].filter(Boolean));
|
|
19537
|
-
const versions =
|
|
19357
|
+
const versions = dirname13(versionDir(home, s.current, platform));
|
|
19538
19358
|
let names = [];
|
|
19539
19359
|
try {
|
|
19540
19360
|
names = readdirSync3(versions);
|
|
@@ -19803,7 +19623,7 @@ async function machineAnswer(client, tokens) {
|
|
|
19803
19623
|
var FETCH_LOCK_TOUCH_MS = 30000;
|
|
19804
19624
|
async function fetchOnce(o) {
|
|
19805
19625
|
const dir = versionDir(o.home, o.version, o.platform);
|
|
19806
|
-
const lock =
|
|
19626
|
+
const lock = join22(dir, "fetch.lock");
|
|
19807
19627
|
mkdirSync16(dir, { recursive: true, mode: 493 });
|
|
19808
19628
|
let fd;
|
|
19809
19629
|
try {
|
|
@@ -20038,7 +19858,7 @@ function engineUpdater(o) {
|
|
|
20038
19858
|
|
|
20039
19859
|
// src/version.ts
|
|
20040
19860
|
function cliVersion(env) {
|
|
20041
|
-
return "0.1.
|
|
19861
|
+
return "0.1.73";
|
|
20042
19862
|
}
|
|
20043
19863
|
|
|
20044
19864
|
// src/commands/update.ts
|
|
@@ -20329,7 +20149,7 @@ function flagsFromProfile(flags, given, profile, home) {
|
|
|
20329
20149
|
}
|
|
20330
20150
|
}
|
|
20331
20151
|
if (profile.reposDir && !has("repos-dir") && !has("repo")) {
|
|
20332
|
-
out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ?
|
|
20152
|
+
out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join23(home, d.slice(1)) : d).join(":");
|
|
20333
20153
|
used.push(`repos ${profile.reposDir}`);
|
|
20334
20154
|
}
|
|
20335
20155
|
if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
|
|
@@ -20424,7 +20244,7 @@ function engineClient(o, org, breaker) {
|
|
|
20424
20244
|
...src,
|
|
20425
20245
|
...breaker ? { fetchFn: breaker.fetch } : {},
|
|
20426
20246
|
timeoutMs: ENGINE_TIMEOUT_MS,
|
|
20427
|
-
version: "0.1.
|
|
20247
|
+
version: "0.1.73"
|
|
20428
20248
|
});
|
|
20429
20249
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
20430
20250
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -20464,12 +20284,12 @@ function memberMcpConfigs(o, cwd) {
|
|
|
20464
20284
|
});
|
|
20465
20285
|
const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
|
|
20466
20286
|
return [
|
|
20467
|
-
read(claudeDir ?
|
|
20468
|
-
...cwd ? [read(
|
|
20287
|
+
read(claudeDir ? join23(claudeDir, ".claude.json") : join23(o.home, ".claude.json")),
|
|
20288
|
+
...cwd ? [read(join23(cwd, ".mcp.json"))] : []
|
|
20469
20289
|
];
|
|
20470
20290
|
}
|
|
20471
20291
|
function engineStateDir(o, org, seat) {
|
|
20472
|
-
return seatStateDir(orgStateDir(o.stateDir ??
|
|
20292
|
+
return seatStateDir(orgStateDir(o.stateDir ?? join23(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
|
|
20473
20293
|
}
|
|
20474
20294
|
function engineSeat(o, org) {
|
|
20475
20295
|
try {
|
|
@@ -20499,9 +20319,9 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20499
20319
|
const repo = flags.repo ? resolve8(cwd, flags.repo) : undefined;
|
|
20500
20320
|
const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve8(cwd, d));
|
|
20501
20321
|
const { branch, prTitle } = flags;
|
|
20502
|
-
const hooksDir =
|
|
20322
|
+
const hooksDir = join23(stateDir, "hooks");
|
|
20503
20323
|
const pnpmStores = new Map;
|
|
20504
|
-
const permissionMark = (name) =>
|
|
20324
|
+
const permissionMark = (name) => join23(hooksDir, `${name}.permission.json`);
|
|
20505
20325
|
const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
|
|
20506
20326
|
return {
|
|
20507
20327
|
source,
|
|
@@ -20526,9 +20346,9 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20526
20346
|
sandbox: true,
|
|
20527
20347
|
writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow, readOnly) => {
|
|
20528
20348
|
const gitCommonDir = gitCommonDirOf(exec, cwd);
|
|
20529
|
-
const dir =
|
|
20349
|
+
const dir = join23(stateDir, "sandbox");
|
|
20530
20350
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
20531
|
-
const p =
|
|
20351
|
+
const p = join23(dir, `${name}.json`);
|
|
20532
20352
|
const walls = engineSandboxSettings(o.home, o.env ?? process.env, gitCommonDir, [
|
|
20533
20353
|
...SANDBOX_DEFAULT_ALLOW,
|
|
20534
20354
|
...flags.sandboxAllow ?? []
|
|
@@ -20551,7 +20371,7 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20551
20371
|
} : {},
|
|
20552
20372
|
writeHookSettings: (name, allow, readOnly) => {
|
|
20553
20373
|
mkdirSync17(hooksDir, { recursive: true, mode: 448 });
|
|
20554
|
-
const p =
|
|
20374
|
+
const p = join23(hooksDir, `${name}.json`);
|
|
20555
20375
|
const deny = readOnlyDenyRules(readOnly ?? []);
|
|
20556
20376
|
const permissions = {
|
|
20557
20377
|
...allow?.length ? { allow: [...allow] } : {},
|
|
@@ -20578,9 +20398,9 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20578
20398
|
exists
|
|
20579
20399
|
}),
|
|
20580
20400
|
writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
|
|
20581
|
-
const dir =
|
|
20401
|
+
const dir = join23(stateDir, "mcp");
|
|
20582
20402
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
20583
|
-
const p =
|
|
20403
|
+
const p = join23(dir, `${name}.json`);
|
|
20584
20404
|
let others = {};
|
|
20585
20405
|
if (flags.strictMcp && flags.mcpAllow?.length) {
|
|
20586
20406
|
const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs(o, worktree));
|
|
@@ -20596,16 +20416,16 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20596
20416
|
}),
|
|
20597
20417
|
removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync10(p, { force: true })),
|
|
20598
20418
|
writePrompt: o.writePrompt ?? ((name, text) => {
|
|
20599
|
-
const dir =
|
|
20419
|
+
const dir = join23(stateDir, "prompts");
|
|
20600
20420
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
20601
|
-
const p =
|
|
20421
|
+
const p = join23(dir, `${name}.md`);
|
|
20602
20422
|
writeFileSync15(p, text, { mode: 384 });
|
|
20603
20423
|
return p;
|
|
20604
20424
|
}),
|
|
20605
20425
|
mockOut: (name) => {
|
|
20606
|
-
const dir =
|
|
20426
|
+
const dir = join23(tmpdir(), "sleds-mocks");
|
|
20607
20427
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
20608
|
-
const p =
|
|
20428
|
+
const p = join23(dir, `${name}.html`);
|
|
20609
20429
|
rmSync10(p, { force: true });
|
|
20610
20430
|
return p;
|
|
20611
20431
|
},
|
|
@@ -20616,6 +20436,15 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20616
20436
|
return null;
|
|
20617
20437
|
}
|
|
20618
20438
|
},
|
|
20439
|
+
fetchMock: async (url) => {
|
|
20440
|
+
try {
|
|
20441
|
+
const r = await fetch(url, { signal: AbortSignal.timeout(15000) });
|
|
20442
|
+
return r.ok ? await r.text() : null;
|
|
20443
|
+
} catch {
|
|
20444
|
+
return null;
|
|
20445
|
+
}
|
|
20446
|
+
},
|
|
20447
|
+
writeMock: (p, html) => writeFileSync15(p, html, { mode: 384 }),
|
|
20619
20448
|
ensureWorktree: (e, repoPath, branch, path, base, install) => ensureWorktree(e, repoPath, branch, path, base, o.worktreeFs ?? { ...realWorktreeFs, exists }, { ...install ? { command: install } : {}, log: o.log ?? console.log }),
|
|
20620
20449
|
ensureDraftWorktree: (e, repoPath, path, base) => ensureDetachedWorktree(e, repoPath, path, base, o.worktreeFs ?? { ...realWorktreeFs, exists }),
|
|
20621
20450
|
defaultBranch,
|
|
@@ -20640,14 +20469,14 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
20640
20469
|
}
|
|
20641
20470
|
function sandboxDenyRead(home, env) {
|
|
20642
20471
|
return {
|
|
20643
|
-
dirs: [...new Set([configDir(home, env),
|
|
20472
|
+
dirs: [...new Set([configDir(home, env), join23(home, ".config", "sleds")])],
|
|
20644
20473
|
files: [
|
|
20645
20474
|
...new Set([
|
|
20646
20475
|
tokenPath(home, env),
|
|
20647
|
-
|
|
20476
|
+
join23(home, ".sleds-token"),
|
|
20648
20477
|
settingsPath(home, env),
|
|
20649
20478
|
backupPath(home, env),
|
|
20650
|
-
|
|
20479
|
+
join23(claudeDir(home, env), "settings.local.json")
|
|
20651
20480
|
])
|
|
20652
20481
|
]
|
|
20653
20482
|
};
|
|
@@ -20689,7 +20518,7 @@ function engineReadDirs(exec, cwd, exists, stores) {
|
|
|
20689
20518
|
})();
|
|
20690
20519
|
const pnpmStore = (() => {
|
|
20691
20520
|
try {
|
|
20692
|
-
if (!exists(
|
|
20521
|
+
if (!exists(join23(cwd, "pnpm-lock.yaml")))
|
|
20693
20522
|
return null;
|
|
20694
20523
|
const key = common ?? cwd;
|
|
20695
20524
|
const known = stores.get(key);
|
|
@@ -20714,7 +20543,7 @@ function engineReadDirs(exec, cwd, exists, stores) {
|
|
|
20714
20543
|
}
|
|
20715
20544
|
var LENT_NEEDS_SANDBOX = "a lent engine runs every session sandboxed (spec 48 rule 10) — add --sandbox to --lent-by";
|
|
20716
20545
|
function lenderHome(accountHome, lentBy) {
|
|
20717
|
-
return isAbsolute3(lentBy) ? resolve8(lentBy) :
|
|
20546
|
+
return isAbsolute3(lentBy) ? resolve8(lentBy) : join23(dirname14(accountHome), lentBy);
|
|
20718
20547
|
}
|
|
20719
20548
|
function lentHomeProblems(accountHome, lentBy, modeOf) {
|
|
20720
20549
|
const lender = lenderHome(accountHome, lentBy);
|
|
@@ -20782,7 +20611,7 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
20782
20611
|
runner: deps.runner.name,
|
|
20783
20612
|
atOnce: flags.atOnce,
|
|
20784
20613
|
interval: flags.interval,
|
|
20785
|
-
cliVersion: "0.1.
|
|
20614
|
+
cliVersion: "0.1.73"
|
|
20786
20615
|
};
|
|
20787
20616
|
const beat = (checkedAt) => {
|
|
20788
20617
|
const m = deps.machine;
|
|
@@ -21004,126 +20833,562 @@ function parsePauseArgs(argv, host) {
|
|
|
21004
20833
|
} else
|
|
21005
20834
|
return { error: `unknown argument ${a}` };
|
|
21006
20835
|
}
|
|
21007
|
-
return {
|
|
21008
|
-
name: got.name ?? defaultEngineName(host),
|
|
21009
|
-
json,
|
|
21010
|
-
...got.org ? { org: got.org } : {},
|
|
21011
|
-
...got.why ? { why: got.why } : {}
|
|
21012
|
-
};
|
|
21013
|
-
}
|
|
21014
|
-
var isRunning = (r) => !r.pr && !r.parked;
|
|
21015
|
-
async function releaseRunning(o) {
|
|
21016
|
-
const state = o.read();
|
|
21017
|
-
const out = { released: 0, kept: [], errors: [] };
|
|
21018
|
-
const gone = new Set;
|
|
21019
|
-
for (const run of state.runs.filter(isRunning)) {
|
|
21020
|
-
const at = `${run.item}/${run.node}`;
|
|
21021
|
-
const runner = o.runnerFor ? o.runnerFor(run.handle.runner, o.exec) : restoreRunner(run.handle.runner, o.exec);
|
|
21022
|
-
try {
|
|
21023
|
-
runner?.stop(run.handle);
|
|
21024
|
-
} catch (e) {
|
|
21025
|
-
o.log(`${at}: could not stop the session: ${e instanceof Error ? e.message : String(e)}`);
|
|
21026
|
-
}
|
|
21027
|
-
try {
|
|
21028
|
-
await o.source.report(claimOf(run), { kind: "release", why: o.why }, o.engine);
|
|
21029
|
-
} catch (e) {
|
|
21030
|
-
out.errors.push(`${at}: ${e instanceof Error ? e.message : String(e)}`);
|
|
21031
|
-
continue;
|
|
21032
|
-
}
|
|
21033
|
-
gone.add(run);
|
|
21034
|
-
out.released++;
|
|
21035
|
-
out.kept.push(run.handle.cwd);
|
|
21036
|
-
if (run.mcpConfig)
|
|
21037
|
-
rmSync10(run.mcpConfig, { force: true });
|
|
20836
|
+
return {
|
|
20837
|
+
name: got.name ?? defaultEngineName(host),
|
|
20838
|
+
json,
|
|
20839
|
+
...got.org ? { org: got.org } : {},
|
|
20840
|
+
...got.why ? { why: got.why } : {}
|
|
20841
|
+
};
|
|
20842
|
+
}
|
|
20843
|
+
var isRunning = (r) => !r.pr && !r.parked;
|
|
20844
|
+
async function releaseRunning(o) {
|
|
20845
|
+
const state = o.read();
|
|
20846
|
+
const out = { released: 0, kept: [], errors: [] };
|
|
20847
|
+
const gone = new Set;
|
|
20848
|
+
for (const run of state.runs.filter(isRunning)) {
|
|
20849
|
+
const at = `${run.item}/${run.node}`;
|
|
20850
|
+
const runner = o.runnerFor ? o.runnerFor(run.handle.runner, o.exec) : restoreRunner(run.handle.runner, o.exec);
|
|
20851
|
+
try {
|
|
20852
|
+
runner?.stop(run.handle);
|
|
20853
|
+
} catch (e) {
|
|
20854
|
+
o.log(`${at}: could not stop the session: ${e instanceof Error ? e.message : String(e)}`);
|
|
20855
|
+
}
|
|
20856
|
+
try {
|
|
20857
|
+
await o.source.report(claimOf(run), { kind: "release", why: o.why }, o.engine);
|
|
20858
|
+
} catch (e) {
|
|
20859
|
+
out.errors.push(`${at}: ${e instanceof Error ? e.message : String(e)}`);
|
|
20860
|
+
continue;
|
|
20861
|
+
}
|
|
20862
|
+
gone.add(run);
|
|
20863
|
+
out.released++;
|
|
20864
|
+
out.kept.push(run.handle.cwd);
|
|
20865
|
+
if (run.mcpConfig)
|
|
20866
|
+
rmSync10(run.mcpConfig, { force: true });
|
|
20867
|
+
}
|
|
20868
|
+
if (gone.size)
|
|
20869
|
+
o.write({ ...state, runs: state.runs.filter((r) => !gone.has(r)) });
|
|
20870
|
+
return out;
|
|
20871
|
+
}
|
|
20872
|
+
var PAUSE_WAIT_MS = 90000;
|
|
20873
|
+
async function enginePauseCmd(o) {
|
|
20874
|
+
const log = o.log ?? console.log;
|
|
20875
|
+
const error = o.error ?? console.error;
|
|
20876
|
+
const host = o.host ?? hostname();
|
|
20877
|
+
const parsed = parsePauseArgs(o.argv, host);
|
|
20878
|
+
if ("error" in parsed) {
|
|
20879
|
+
error(parsed.error);
|
|
20880
|
+
error(ENGINE_PAUSE_USAGE);
|
|
20881
|
+
return 2;
|
|
20882
|
+
}
|
|
20883
|
+
const engine = `engine:${parsed.name}`;
|
|
20884
|
+
const which = engineOrg(o, parsed.org);
|
|
20885
|
+
const org = which.slug && (which.seated || parsed.org) ? which.slug : null;
|
|
20886
|
+
const seat = engineSeat(o, org ?? undefined) ?? null;
|
|
20887
|
+
const seatDir = engineStateDir(o, org, seat);
|
|
20888
|
+
const orgDir = engineStateDir(o, org);
|
|
20889
|
+
const has = (d) => realExists(statePath(d, engine)) || realExists(lockPath(d, engine));
|
|
20890
|
+
const dir = !has(seatDir) && has(orgDir) ? orgDir : seatDir;
|
|
20891
|
+
const alive = o.pidAlive ?? realPidAlive2;
|
|
20892
|
+
const sleep = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
20893
|
+
const kill = o.kill ?? ((pid, sig) => void process.kill(pid, sig));
|
|
20894
|
+
const lock = readLock(lockPath(dir, engine));
|
|
20895
|
+
let stopped = false;
|
|
20896
|
+
if (lock && lock.host === host && lock.pid !== process.pid && alive(lock.pid)) {
|
|
20897
|
+
try {
|
|
20898
|
+
kill(lock.pid, "SIGTERM");
|
|
20899
|
+
} catch {}
|
|
20900
|
+
for (let waited = 0;alive(lock.pid) && waited < PAUSE_WAIT_MS; waited += 250)
|
|
20901
|
+
await sleep(250);
|
|
20902
|
+
if (alive(lock.pid)) {
|
|
20903
|
+
error(`${engine} (pid ${lock.pid}) did not stop within ${PAUSE_WAIT_MS / 1000} s — nothing was paused. Try again, or stop it by hand.`);
|
|
20904
|
+
return 1;
|
|
20905
|
+
}
|
|
20906
|
+
stopped = true;
|
|
20907
|
+
}
|
|
20908
|
+
const file = statePath(dir, engine);
|
|
20909
|
+
const state = readState(file);
|
|
20910
|
+
const result = {
|
|
20911
|
+
released: 0,
|
|
20912
|
+
kept: [],
|
|
20913
|
+
following: 0,
|
|
20914
|
+
parked: 0,
|
|
20915
|
+
stopped,
|
|
20916
|
+
errors: []
|
|
20917
|
+
};
|
|
20918
|
+
result.following = state.runs.filter((r) => r.pr).length;
|
|
20919
|
+
result.parked = state.runs.filter((r) => r.parked).length;
|
|
20920
|
+
let source = o.source;
|
|
20921
|
+
if (state.runs.some(isRunning) && !source) {
|
|
20922
|
+
const c = orgClient(o, parsed.org);
|
|
20923
|
+
if ("error" in c) {
|
|
20924
|
+
error(c.error);
|
|
20925
|
+
return 1;
|
|
20926
|
+
}
|
|
20927
|
+
source = sledsSource(c, { engine, log });
|
|
20928
|
+
}
|
|
20929
|
+
if (source) {
|
|
20930
|
+
const r = await releaseRunning({
|
|
20931
|
+
read: () => state,
|
|
20932
|
+
write: (next) => writeState(file, next),
|
|
20933
|
+
source,
|
|
20934
|
+
engine,
|
|
20935
|
+
why: parsed.why ?? `paused on ${defaultEngineName(host)} (sleds engine pause)`,
|
|
20936
|
+
exec: guardGit(o.exec ?? defaultExec),
|
|
20937
|
+
...o.runnerFor ? { runnerFor: o.runnerFor } : {},
|
|
20938
|
+
log
|
|
20939
|
+
});
|
|
20940
|
+
result.released = r.released;
|
|
20941
|
+
result.kept = r.kept;
|
|
20942
|
+
result.errors = r.errors;
|
|
20943
|
+
}
|
|
20944
|
+
if (parsed.json)
|
|
20945
|
+
log(JSON.stringify(result, null, 2));
|
|
20946
|
+
else {
|
|
20947
|
+
const n = (k, one) => `${k} ${one}${k === 1 ? "" : "s"}`;
|
|
20948
|
+
log(`${engine} paused${seat ? ` (${seat})` : ""}: ${stopped ? "the engine stopped" : "the engine was not running"} · ${n(result.released, "session")} released · ${n(result.following, "PR")} still followed · ${n(result.parked, "parked session")} kept`);
|
|
20949
|
+
for (const w of result.kept)
|
|
20950
|
+
log(` kept ${w}`);
|
|
20951
|
+
for (const e of result.errors)
|
|
20952
|
+
error(` not released, retry with \`sleds engine pause\`: ${e}`);
|
|
20953
|
+
}
|
|
20954
|
+
return result.errors.length ? 1 : 0;
|
|
20955
|
+
}
|
|
20956
|
+
|
|
20957
|
+
// src/commands/attach.ts
|
|
20958
|
+
var ATTACH_USAGE = "usage: sleds attach <key> --file <path> [--kind screenshot|prototype|spec|doc|other] [--mock] [--json]";
|
|
20959
|
+
var ATTACH_MAX_BYTES = 4 * 1024 * 1024;
|
|
20960
|
+
var KINDS2 = new Set(["spec", "prototype", "screenshot", "doc", "other"]);
|
|
20961
|
+
function parseAttachArgs(argv) {
|
|
20962
|
+
let key;
|
|
20963
|
+
let file;
|
|
20964
|
+
let kind;
|
|
20965
|
+
let mock = false;
|
|
20966
|
+
let json = false;
|
|
20967
|
+
for (let i = 0;i < argv.length; i++) {
|
|
20968
|
+
const a = argv[i];
|
|
20969
|
+
if (a === "--json")
|
|
20970
|
+
json = true;
|
|
20971
|
+
else if (a === "--mock")
|
|
20972
|
+
mock = true;
|
|
20973
|
+
else if (a === "--file" || a === "--kind") {
|
|
20974
|
+
const value = argv[i + 1];
|
|
20975
|
+
if (value === undefined || value.startsWith("--"))
|
|
20976
|
+
return { error: `${a} needs a value` };
|
|
20977
|
+
if (a === "--file")
|
|
20978
|
+
file = value;
|
|
20979
|
+
else if (KINDS2.has(value))
|
|
20980
|
+
kind = value;
|
|
20981
|
+
else
|
|
20982
|
+
return { error: `--kind is one of ${[...KINDS2].join(", ")}` };
|
|
20983
|
+
i++;
|
|
20984
|
+
} else if (a.startsWith("--"))
|
|
20985
|
+
return { error: `unknown flag ${a}` };
|
|
20986
|
+
else if (key === undefined)
|
|
20987
|
+
key = a;
|
|
20988
|
+
else
|
|
20989
|
+
return { error: `one item and one --file at a time (${a}?)` };
|
|
20990
|
+
}
|
|
20991
|
+
if (!key)
|
|
20992
|
+
return { error: "which item?" };
|
|
20993
|
+
if (!file)
|
|
20994
|
+
return { error: "--file names the file to put on the item" };
|
|
20995
|
+
return { key, file, ...kind ? { kind } : {}, mock, json };
|
|
20996
|
+
}
|
|
20997
|
+
function attachEncoding(mime) {
|
|
20998
|
+
return /^text\/|^application\/json$|^image\/svg\+xml$/.test(mime) ? "text" : "base64";
|
|
20999
|
+
}
|
|
21000
|
+
async function attachCmd(o) {
|
|
21001
|
+
const log = o.log ?? console.log;
|
|
21002
|
+
const error = o.error ?? console.error;
|
|
21003
|
+
const a = parseAttachArgs(o.argv);
|
|
21004
|
+
if ("error" in a) {
|
|
21005
|
+
error(a.error);
|
|
21006
|
+
error(ATTACH_USAGE);
|
|
21007
|
+
return 2;
|
|
21008
|
+
}
|
|
21009
|
+
let bytes;
|
|
21010
|
+
try {
|
|
21011
|
+
if (!o.readFile && statSync7(a.file).size > ATTACH_MAX_BYTES) {
|
|
21012
|
+
error(`${a.file}: a file on an item is at most 4 MB`);
|
|
21013
|
+
return 1;
|
|
21014
|
+
}
|
|
21015
|
+
bytes = (o.readFile ?? readFileSync16)(a.file);
|
|
21016
|
+
} catch {
|
|
21017
|
+
error(`${a.file}: cannot read it`);
|
|
21018
|
+
return 1;
|
|
21019
|
+
}
|
|
21020
|
+
if (bytes.byteLength > ATTACH_MAX_BYTES) {
|
|
21021
|
+
error(`${a.file}: a file on an item is at most 4 MB`);
|
|
21022
|
+
return 1;
|
|
21023
|
+
}
|
|
21024
|
+
const name = basename6(a.file);
|
|
21025
|
+
const mime = mimeFromName(name);
|
|
21026
|
+
const encoding = attachEncoding(mime);
|
|
21027
|
+
const client = engineClient({ home: o.home, ...o.client ? { client: o.client } : {} });
|
|
21028
|
+
if ("error" in client) {
|
|
21029
|
+
error(client.error);
|
|
21030
|
+
return 1;
|
|
21031
|
+
}
|
|
21032
|
+
const r = await client.postFull("/proxy/asset", {
|
|
21033
|
+
project: a.key,
|
|
21034
|
+
name,
|
|
21035
|
+
mime,
|
|
21036
|
+
content: encoding === "base64" ? bytes.toString("base64") : bytes.toString("utf8"),
|
|
21037
|
+
...encoding === "base64" ? { encoding } : {},
|
|
21038
|
+
...a.kind ? { kind: a.kind } : {},
|
|
21039
|
+
...a.mock ? { mock: true } : {}
|
|
21040
|
+
});
|
|
21041
|
+
if (!r) {
|
|
21042
|
+
error(`${a.key}: SLEDS unreachable — nothing stored`);
|
|
21043
|
+
return 1;
|
|
21044
|
+
}
|
|
21045
|
+
if (a.json)
|
|
21046
|
+
log(JSON.stringify(r.json ?? { ok: false, error: `HTTP ${r.status}` }));
|
|
21047
|
+
if (r.status >= 300) {
|
|
21048
|
+
const why = typeof r.json?.error === "string" ? r.json.error : `HTTP ${r.status}`;
|
|
21049
|
+
if (!a.json)
|
|
21050
|
+
error(r.status === 404 && !r.json ? `${a.key}: SLEDS does not know this seat — run \`sleds init\`` : `${a.key}: ${why}`);
|
|
21051
|
+
return 1;
|
|
21052
|
+
}
|
|
21053
|
+
const url = typeof r.json?.url === "string" ? r.json.url : "";
|
|
21054
|
+
if (!a.json)
|
|
21055
|
+
log(url || `${name} is on ${a.key}`);
|
|
21056
|
+
return 0;
|
|
21057
|
+
}
|
|
21058
|
+
|
|
21059
|
+
// src/commands/verify.ts
|
|
21060
|
+
init_meter();
|
|
21061
|
+
import { readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
|
|
21062
|
+
import { basename as basename8, extname } from "node:path";
|
|
21063
|
+
|
|
21064
|
+
// src/musher.ts
|
|
21065
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
21066
|
+
import { createPublicKey as createPublicKey2, verify as cryptoVerify } from "node:crypto";
|
|
21067
|
+
import { basename as basename7, dirname as dirname15, join as join24 } from "node:path";
|
|
21068
|
+
var MUSHER_LABEL = "ai.sleds.musher";
|
|
21069
|
+
var MUSHER_INTERVAL_S = 300;
|
|
21070
|
+
var DEFAULT_PERMISSION_MODE = "acceptEdits";
|
|
21071
|
+
var PERMISSION_MODES = [
|
|
21072
|
+
"acceptEdits",
|
|
21073
|
+
"auto",
|
|
21074
|
+
"bypassPermissions",
|
|
21075
|
+
"default",
|
|
21076
|
+
"dontAsk",
|
|
21077
|
+
"plan"
|
|
21078
|
+
];
|
|
21079
|
+
var DEFAULT_TIMEOUT_MINUTES = 90;
|
|
21080
|
+
var SUMMARY_MAX = 2000;
|
|
21081
|
+
var musherLabel = (env = process.env) => {
|
|
21082
|
+
const sh = env.SLEDS_HOME?.trim();
|
|
21083
|
+
if (!sh)
|
|
21084
|
+
return MUSHER_LABEL;
|
|
21085
|
+
const tag = basename7(sh).replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]+/g, "-") || "seat";
|
|
21086
|
+
return `${MUSHER_LABEL}.${tag}`;
|
|
21087
|
+
};
|
|
21088
|
+
var musherPlistPath = (home, env = process.env) => join24(home, "Library", "LaunchAgents", `${musherLabel(env)}.plist`);
|
|
21089
|
+
var musherLogPath = (configDir) => join24(configDir, "musher.log");
|
|
21090
|
+
var xmlEscape3 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
21091
|
+
var musherPath = (home, execPath, currentPath = "") => {
|
|
21092
|
+
const parts = [
|
|
21093
|
+
dirname15(execPath),
|
|
21094
|
+
join24(home, ".sleds", "bin"),
|
|
21095
|
+
join24(home, ".local", "bin"),
|
|
21096
|
+
join24(home, ".bun", "bin"),
|
|
21097
|
+
"/opt/homebrew/bin",
|
|
21098
|
+
"/usr/local/bin",
|
|
21099
|
+
"/usr/bin",
|
|
21100
|
+
"/bin",
|
|
21101
|
+
...currentPath.split(":").filter(Boolean)
|
|
21102
|
+
];
|
|
21103
|
+
return [...new Set(parts)].join(":");
|
|
21104
|
+
};
|
|
21105
|
+
var buildMusherPlist = (o) => {
|
|
21106
|
+
const label = o.label ?? MUSHER_LABEL;
|
|
21107
|
+
const args = [...o.sledsArgv, "musher", "tick"].map((a) => ` <string>${xmlEscape3(a)}</string>`).join(`
|
|
21108
|
+
`);
|
|
21109
|
+
const env = Object.entries(o.env).filter(([, v]) => v !== "").map(([k, v]) => ` <key>${xmlEscape3(k)}</key>
|
|
21110
|
+
<string>${xmlEscape3(v)}</string>`).join(`
|
|
21111
|
+
`);
|
|
21112
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
21113
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
21114
|
+
<plist version="1.0">
|
|
21115
|
+
<dict>
|
|
21116
|
+
<key>Label</key>
|
|
21117
|
+
<string>${label}</string>
|
|
21118
|
+
<key>ProgramArguments</key>
|
|
21119
|
+
<array>
|
|
21120
|
+
${args}
|
|
21121
|
+
</array>
|
|
21122
|
+
<key>EnvironmentVariables</key>
|
|
21123
|
+
<dict>
|
|
21124
|
+
${env}
|
|
21125
|
+
</dict>
|
|
21126
|
+
<key>StartInterval</key>
|
|
21127
|
+
<integer>${MUSHER_INTERVAL_S}</integer>
|
|
21128
|
+
<key>RunAtLoad</key>
|
|
21129
|
+
<true/>
|
|
21130
|
+
<key>StandardOutPath</key>
|
|
21131
|
+
<string>${xmlEscape3(o.logPath)}</string>
|
|
21132
|
+
<key>StandardErrorPath</key>
|
|
21133
|
+
<string>${xmlEscape3(o.logPath)}</string>
|
|
21134
|
+
</dict>
|
|
21135
|
+
</plist>
|
|
21136
|
+
`;
|
|
21137
|
+
};
|
|
21138
|
+
var RESUME_PROMPT = [
|
|
21139
|
+
"SLEDS musher: the usage limit that stopped this session has reset, and the seat's owner",
|
|
21140
|
+
"scheduled this unattended run to continue it. Pick up exactly where the session left off:",
|
|
21141
|
+
"finish the task that was in flight, run the checks you would normally run, follow the repo's",
|
|
21142
|
+
"own conventions for branches and commits, and do not start unrelated work. If you are blocked",
|
|
21143
|
+
"on a decision only the owner can make, stop there and say so. Finish with a summary under",
|
|
21144
|
+
"200 words: what was done, what remains, anything the owner must decide."
|
|
21145
|
+
].join(" ");
|
|
21146
|
+
var NO_SESSION_PROMPT = [
|
|
21147
|
+
"SLEDS musher: a deferred job started on this seat, but no Claude Code session was recorded",
|
|
21148
|
+
"to resume. Do not guess at work. Reply with one line saying so, and stop."
|
|
21149
|
+
].join(" ");
|
|
21150
|
+
var claudeArgs = (o) => [
|
|
21151
|
+
"-p",
|
|
21152
|
+
o.sessionId ? RESUME_PROMPT : NO_SESSION_PROMPT,
|
|
21153
|
+
...o.sessionId ? ["--resume", o.sessionId] : [],
|
|
21154
|
+
...o.model ? ["--model", o.model] : [],
|
|
21155
|
+
"--output-format",
|
|
21156
|
+
"json",
|
|
21157
|
+
"--permission-mode",
|
|
21158
|
+
o.permissionMode
|
|
21159
|
+
];
|
|
21160
|
+
var parseClaudeOutput = (stdout, exitCode) => {
|
|
21161
|
+
const lines = stdout.split(`
|
|
21162
|
+
`).map((l) => l.trim()).filter(Boolean);
|
|
21163
|
+
for (let i = lines.length - 1;i >= 0; i--) {
|
|
21164
|
+
const line = lines[i] ?? "";
|
|
21165
|
+
if (!line.startsWith("{"))
|
|
21166
|
+
continue;
|
|
21167
|
+
try {
|
|
21168
|
+
const j = JSON.parse(line);
|
|
21169
|
+
if (j.type !== "result" && typeof j.result !== "string")
|
|
21170
|
+
continue;
|
|
21171
|
+
const isError = j.is_error === true || typeof j.subtype === "string" && j.subtype !== "success";
|
|
21172
|
+
const text = typeof j.result === "string" ? j.result : "";
|
|
21173
|
+
const models = j.modelUsage;
|
|
21174
|
+
const model = typeof j.model === "string" ? j.model : models && typeof models === "object" ? Object.keys(models)[0] : undefined;
|
|
21175
|
+
return {
|
|
21176
|
+
ok: !isError && exitCode === 0,
|
|
21177
|
+
summary: (text || (isError ? "Claude Code reported an error" : "")).slice(0, SUMMARY_MAX),
|
|
21178
|
+
...typeof j.session_id === "string" ? { sessionId: j.session_id } : {},
|
|
21179
|
+
...model ? { model } : {},
|
|
21180
|
+
...typeof j.duration_ms === "number" ? { durationMs: j.duration_ms } : {},
|
|
21181
|
+
...typeof j.total_cost_usd === "number" ? { costUsd: j.total_cost_usd } : {}
|
|
21182
|
+
};
|
|
21183
|
+
} catch {}
|
|
21184
|
+
}
|
|
21185
|
+
const tail = lines.slice(-5).join(" ").slice(0, SUMMARY_MAX);
|
|
21186
|
+
return { ok: false, summary: tail || `claude exited ${exitCode ?? "without a code"}` };
|
|
21187
|
+
};
|
|
21188
|
+
var defaultExecCapture = (cmd, args, o) => {
|
|
21189
|
+
const r = spawnSync4(cmd, [...args], {
|
|
21190
|
+
cwd: o.cwd,
|
|
21191
|
+
encoding: "utf8",
|
|
21192
|
+
timeout: o.timeoutMs,
|
|
21193
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
21194
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
21195
|
+
env: { ...process.env, SLEDS_MUSHER: "1" }
|
|
21196
|
+
});
|
|
21197
|
+
const timedOut = r.error?.code === "ETIMEDOUT";
|
|
21198
|
+
return {
|
|
21199
|
+
stdout: r.stdout ?? "",
|
|
21200
|
+
stderr: r.stderr ?? "",
|
|
21201
|
+
status: r.status,
|
|
21202
|
+
...timedOut ? { timedOut } : r.error ? { error: r.error.message } : {}
|
|
21203
|
+
};
|
|
21204
|
+
};
|
|
21205
|
+
var musherClient = (o) => {
|
|
21206
|
+
const fetchFn = o.fetchFn ?? fetch;
|
|
21207
|
+
const headers = { authorization: `Bearer ${o.token}`, "content-type": "application/json" };
|
|
21208
|
+
const call = async (path, body) => {
|
|
21209
|
+
try {
|
|
21210
|
+
const res = await fetchFn(`${o.proxyUrl}${path}`, {
|
|
21211
|
+
method: body === undefined ? "GET" : "POST",
|
|
21212
|
+
headers,
|
|
21213
|
+
...body === undefined ? {} : { body: JSON.stringify(body) },
|
|
21214
|
+
signal: AbortSignal.timeout(o.timeoutMs ?? 1e4)
|
|
21215
|
+
});
|
|
21216
|
+
if (!res.ok)
|
|
21217
|
+
return null;
|
|
21218
|
+
return await res.json();
|
|
21219
|
+
} catch {
|
|
21220
|
+
return null;
|
|
21221
|
+
}
|
|
21222
|
+
};
|
|
21223
|
+
return {
|
|
21224
|
+
list: () => call("/proxy/musher"),
|
|
21225
|
+
start: (jobId, local) => call("/proxy/musher/start", { jobId, ...local }),
|
|
21226
|
+
finish: async (input) => await call("/proxy/musher/finish", input) !== null,
|
|
21227
|
+
defer: (input) => call("/proxy/defer", input),
|
|
21228
|
+
attestation: (jobId) => call(`/proxy/attest/${encodeURIComponent(jobId)}`)
|
|
21229
|
+
};
|
|
21230
|
+
};
|
|
21231
|
+
var gitHead = (cwd, exec) => {
|
|
21232
|
+
if (!cwd)
|
|
21233
|
+
return null;
|
|
21234
|
+
const r = exec("git", ["rev-parse", "HEAD"], { cwd, timeoutMs: 5000 });
|
|
21235
|
+
const sha = r.stdout.trim();
|
|
21236
|
+
return r.status === 0 && /^[0-9a-f]{40}$/.test(sha) ? sha : null;
|
|
21237
|
+
};
|
|
21238
|
+
var gitNewCommits = (cwd, before, after, exec) => {
|
|
21239
|
+
if (!cwd || !after || after === before)
|
|
21240
|
+
return [];
|
|
21241
|
+
if (!before)
|
|
21242
|
+
return [after];
|
|
21243
|
+
const r = exec("git", ["rev-list", `${before}..${after}`], { cwd, timeoutMs: 5000 });
|
|
21244
|
+
if (r.status !== 0)
|
|
21245
|
+
return [after];
|
|
21246
|
+
return r.stdout.split(`
|
|
21247
|
+
`).map((l) => l.trim()).filter((l) => /^[0-9a-f]{40}$/.test(l)).slice(0, 40);
|
|
21248
|
+
};
|
|
21249
|
+
var collectOutputs = (commits, summary) => {
|
|
21250
|
+
const out = commits.map((c) => `git:${c}`);
|
|
21251
|
+
for (const m of summary.matchAll(/https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+/g))
|
|
21252
|
+
if (!out.includes(`pr:${m[0]}`))
|
|
21253
|
+
out.push(`pr:${m[0]}`);
|
|
21254
|
+
return out.slice(0, 50);
|
|
21255
|
+
};
|
|
21256
|
+
var runJob = async (o) => {
|
|
21257
|
+
const log = o.log ?? (() => {});
|
|
21258
|
+
const sessionId = o.job.claudeSessionId ?? o.fallbackSession?.id ?? null;
|
|
21259
|
+
const cwd = o.job.cwd ?? o.fallbackSession?.cwd ?? undefined;
|
|
21260
|
+
const started = await o.client.start(o.job.jobId, {
|
|
21261
|
+
...sessionId ? { claudeSessionId: sessionId } : {},
|
|
21262
|
+
...cwd ? { cwd } : {},
|
|
21263
|
+
host: o.host
|
|
21264
|
+
});
|
|
21265
|
+
if (!started)
|
|
21266
|
+
return { kind: "skipped", reason: "control plane unreachable" };
|
|
21267
|
+
if (!started.ok)
|
|
21268
|
+
return { kind: "skipped", reason: started.reason };
|
|
21269
|
+
const model = o.job.model ?? started.model ?? o.fallbackSession?.model ?? null;
|
|
21270
|
+
const args = claudeArgs({ sessionId, model, permissionMode: o.permissionMode });
|
|
21271
|
+
log(`musher: running job ${o.job.jobId} (${sessionId ? `resume ${sessionId}` : "no session"}${model ? ` · ${model}` : ""}${cwd ? ` · ${cwd}` : ""})`);
|
|
21272
|
+
const exec = o.exec ?? defaultExecCapture;
|
|
21273
|
+
const headBefore = gitHead(cwd, exec);
|
|
21274
|
+
const t0 = Date.now();
|
|
21275
|
+
const r = exec(o.claudePath, args, { cwd, timeoutMs: o.timeoutMs });
|
|
21276
|
+
const durationMs = Date.now() - t0;
|
|
21277
|
+
const result = r.error ? { ok: false, summary: `could not run ${o.claudePath}: ${r.error}` } : parseClaudeOutput(r.stdout, r.status);
|
|
21278
|
+
if (!r.error && (r.timedOut || r.status === null)) {
|
|
21279
|
+
result.ok = false;
|
|
21280
|
+
result.summary = `timed out after ${Math.round(o.timeoutMs / 60000)} min. ${result.summary}`.trim();
|
|
21281
|
+
}
|
|
21282
|
+
const outputs = collectOutputs(gitNewCommits(cwd, headBefore, gitHead(cwd, exec), exec), result.summary);
|
|
21283
|
+
await o.client.finish({
|
|
21284
|
+
jobId: o.job.jobId,
|
|
21285
|
+
runId: started.runId,
|
|
21286
|
+
ok: result.ok,
|
|
21287
|
+
summary: result.summary,
|
|
21288
|
+
...outputs.length ? { outputs } : {},
|
|
21289
|
+
...result.model ?? model ? { model: result.model ?? model } : {},
|
|
21290
|
+
durationMs: result.durationMs ?? durationMs,
|
|
21291
|
+
...result.sessionId ?? sessionId ? { claudeSessionId: result.sessionId ?? sessionId } : {}
|
|
21292
|
+
});
|
|
21293
|
+
log(`musher: job ${o.job.jobId} ${result.ok ? "delivered" : "failed"} in ${Math.round(durationMs / 1000)}s`);
|
|
21294
|
+
return { kind: "ran", ok: result.ok, summary: result.summary, durationMs, outputs };
|
|
21295
|
+
};
|
|
21296
|
+
var verifyAttestation = (payload, sig, publicKeyB64) => {
|
|
21297
|
+
try {
|
|
21298
|
+
const pub = createPublicKey2({
|
|
21299
|
+
key: Buffer.from(publicKeyB64, "base64"),
|
|
21300
|
+
format: "der",
|
|
21301
|
+
type: "spki"
|
|
21302
|
+
});
|
|
21303
|
+
const raw = Buffer.from(sig.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
21304
|
+
return cryptoVerify(null, Buffer.from(payload, "utf8"), pub, raw);
|
|
21305
|
+
} catch {
|
|
21306
|
+
return false;
|
|
21307
|
+
}
|
|
21308
|
+
};
|
|
21309
|
+
var parsePayload = (payload) => {
|
|
21310
|
+
const out = {};
|
|
21311
|
+
for (const line of payload.split(`
|
|
21312
|
+
`).slice(1)) {
|
|
21313
|
+
const eq = line.indexOf("=");
|
|
21314
|
+
if (eq > 0)
|
|
21315
|
+
out[line.slice(0, eq)] = line.slice(eq + 1);
|
|
21038
21316
|
}
|
|
21039
|
-
if (gone.size)
|
|
21040
|
-
o.write({ ...state, runs: state.runs.filter((r) => !gone.has(r)) });
|
|
21041
21317
|
return out;
|
|
21042
|
-
}
|
|
21043
|
-
|
|
21044
|
-
|
|
21045
|
-
|
|
21046
|
-
|
|
21047
|
-
|
|
21048
|
-
|
|
21049
|
-
|
|
21050
|
-
|
|
21051
|
-
|
|
21052
|
-
|
|
21318
|
+
};
|
|
21319
|
+
|
|
21320
|
+
// src/switch.ts
|
|
21321
|
+
init_settings();
|
|
21322
|
+
var isObject12 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
21323
|
+
var envOf2 = (settings) => isObject12(settings.env) ? settings.env : {};
|
|
21324
|
+
var capturePriorEnv = (settings) => {
|
|
21325
|
+
const env = envOf2(settings);
|
|
21326
|
+
const prior = { hadEnv: isObject12(settings.env) };
|
|
21327
|
+
const url = env[BASE_URL_KEY];
|
|
21328
|
+
const token = env[AUTH_TOKEN_KEY];
|
|
21329
|
+
if (typeof url === "string")
|
|
21330
|
+
prior[BASE_URL_KEY] = url;
|
|
21331
|
+
if (typeof token === "string")
|
|
21332
|
+
prior[AUTH_TOKEN_KEY] = token;
|
|
21333
|
+
return prior;
|
|
21334
|
+
};
|
|
21335
|
+
var switchOn = (settings, cfg) => applyProxy(settings, cfg);
|
|
21336
|
+
var switchOff = (settings, prior) => {
|
|
21337
|
+
const hadEnv = prior.hadEnv === true;
|
|
21338
|
+
const stripped = removeProxy(settings);
|
|
21339
|
+
const env = { ...envOf2(stripped) };
|
|
21340
|
+
const url = prior[BASE_URL_KEY];
|
|
21341
|
+
const token = prior[AUTH_TOKEN_KEY];
|
|
21342
|
+
if (url !== undefined)
|
|
21343
|
+
env[BASE_URL_KEY] = url;
|
|
21344
|
+
if (token !== undefined)
|
|
21345
|
+
env[AUTH_TOKEN_KEY] = token;
|
|
21346
|
+
if (Object.keys(env).length === 0 && !hadEnv) {
|
|
21347
|
+
const { env: _env, ...rest } = stripped;
|
|
21348
|
+
return rest;
|
|
21053
21349
|
}
|
|
21054
|
-
|
|
21055
|
-
|
|
21056
|
-
|
|
21057
|
-
|
|
21058
|
-
|
|
21059
|
-
const
|
|
21060
|
-
const
|
|
21061
|
-
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
if (lock && lock.host === host && lock.pid !== process.pid && alive(lock.pid)) {
|
|
21068
|
-
try {
|
|
21069
|
-
kill(lock.pid, "SIGTERM");
|
|
21070
|
-
} catch {}
|
|
21071
|
-
for (let waited = 0;alive(lock.pid) && waited < PAUSE_WAIT_MS; waited += 250)
|
|
21072
|
-
await sleep(250);
|
|
21073
|
-
if (alive(lock.pid)) {
|
|
21074
|
-
error(`${engine} (pid ${lock.pid}) did not stop within ${PAUSE_WAIT_MS / 1000} s — nothing was paused. Try again, or stop it by hand.`);
|
|
21075
|
-
return 1;
|
|
21350
|
+
return { ...stripped, env };
|
|
21351
|
+
};
|
|
21352
|
+
var envToRestore = (priors, proxyUrls) => priors.find((p) => p !== undefined && !isSledsProxyEnv({ env: p }, proxyUrls)) ?? {};
|
|
21353
|
+
var RELATIVE = /^\+(?:(\d+)h)?(?:(\d+)m)?$/;
|
|
21354
|
+
var parseUntilReset = (input, nowMs) => {
|
|
21355
|
+
const trimmed = input.trim();
|
|
21356
|
+
const rel = RELATIVE.exec(trimmed);
|
|
21357
|
+
let deadline;
|
|
21358
|
+
if (rel) {
|
|
21359
|
+
const hours = Number(rel[1] ?? 0);
|
|
21360
|
+
const minutes = Number(rel[2] ?? 0);
|
|
21361
|
+
if (hours === 0 && minutes === 0) {
|
|
21362
|
+
throw new Error(`--until-reset: "${input}" is zero; use something like +5h or +90m`);
|
|
21076
21363
|
}
|
|
21077
|
-
|
|
21078
|
-
}
|
|
21079
|
-
|
|
21080
|
-
|
|
21081
|
-
|
|
21082
|
-
released: 0,
|
|
21083
|
-
kept: [],
|
|
21084
|
-
following: 0,
|
|
21085
|
-
parked: 0,
|
|
21086
|
-
stopped,
|
|
21087
|
-
errors: []
|
|
21088
|
-
};
|
|
21089
|
-
result.following = state.runs.filter((r) => r.pr).length;
|
|
21090
|
-
result.parked = state.runs.filter((r) => r.parked).length;
|
|
21091
|
-
let source = o.source;
|
|
21092
|
-
if (state.runs.some(isRunning) && !source) {
|
|
21093
|
-
const c = orgClient(o, parsed.org);
|
|
21094
|
-
if ("error" in c) {
|
|
21095
|
-
error(c.error);
|
|
21096
|
-
return 1;
|
|
21364
|
+
deadline = nowMs + (hours * 60 + minutes) * 60000;
|
|
21365
|
+
} else {
|
|
21366
|
+
deadline = Date.parse(trimmed);
|
|
21367
|
+
if (Number.isNaN(deadline)) {
|
|
21368
|
+
throw new Error(`--until-reset: "${input}" is not +<n>h[<n>m] or an ISO timestamp`);
|
|
21097
21369
|
}
|
|
21098
|
-
source = sledsSource(c, { engine, log });
|
|
21099
|
-
}
|
|
21100
|
-
if (source) {
|
|
21101
|
-
const r = await releaseRunning({
|
|
21102
|
-
read: () => state,
|
|
21103
|
-
write: (next) => writeState(file, next),
|
|
21104
|
-
source,
|
|
21105
|
-
engine,
|
|
21106
|
-
why: parsed.why ?? `paused on ${defaultEngineName(host)} (sleds engine pause)`,
|
|
21107
|
-
exec: guardGit(o.exec ?? defaultExec),
|
|
21108
|
-
...o.runnerFor ? { runnerFor: o.runnerFor } : {},
|
|
21109
|
-
log
|
|
21110
|
-
});
|
|
21111
|
-
result.released = r.released;
|
|
21112
|
-
result.kept = r.kept;
|
|
21113
|
-
result.errors = r.errors;
|
|
21114
21370
|
}
|
|
21115
|
-
if (
|
|
21116
|
-
|
|
21117
|
-
else {
|
|
21118
|
-
const n = (k, one) => `${k} ${one}${k === 1 ? "" : "s"}`;
|
|
21119
|
-
log(`${engine} paused${seat ? ` (${seat})` : ""}: ${stopped ? "the engine stopped" : "the engine was not running"} · ${n(result.released, "session")} released · ${n(result.following, "PR")} still followed · ${n(result.parked, "parked session")} kept`);
|
|
21120
|
-
for (const w of result.kept)
|
|
21121
|
-
log(` kept ${w}`);
|
|
21122
|
-
for (const e of result.errors)
|
|
21123
|
-
error(` not released, retry with \`sleds engine pause\`: ${e}`);
|
|
21371
|
+
if (deadline <= nowMs) {
|
|
21372
|
+
throw new Error(`--until-reset: ${trimmed} is in the past`);
|
|
21124
21373
|
}
|
|
21125
|
-
return
|
|
21126
|
-
}
|
|
21374
|
+
return deadline;
|
|
21375
|
+
};
|
|
21376
|
+
var formatLocal = (ms, tz) => new Intl.DateTimeFormat("en-US", {
|
|
21377
|
+
month: "short",
|
|
21378
|
+
day: "numeric",
|
|
21379
|
+
hour: "numeric",
|
|
21380
|
+
minute: "2-digit",
|
|
21381
|
+
timeZoneName: "short",
|
|
21382
|
+
...tz ? { timeZone: tz } : {}
|
|
21383
|
+
}).format(new Date(ms));
|
|
21384
|
+
var formatDuration = (ms) => {
|
|
21385
|
+
const total = Math.max(0, Math.round(ms / 60000));
|
|
21386
|
+
const h = Math.floor(total / 60);
|
|
21387
|
+
const m = total % 60;
|
|
21388
|
+
if (h === 0)
|
|
21389
|
+
return `${m}m`;
|
|
21390
|
+
return m === 0 ? `${h}h` : `${h}h ${m}m`;
|
|
21391
|
+
};
|
|
21127
21392
|
|
|
21128
21393
|
// src/commands/verify.ts
|
|
21129
21394
|
var VERDICT_USAGE = [
|
|
@@ -21204,17 +21469,17 @@ async function verdictCmd(o) {
|
|
|
21204
21469
|
let screenshot;
|
|
21205
21470
|
if (a.file) {
|
|
21206
21471
|
try {
|
|
21207
|
-
if (!o.readFile &&
|
|
21472
|
+
if (!o.readFile && statSync8(a.file).size > SHOT_MAX_BYTES) {
|
|
21208
21473
|
error(`${a.file}: a screenshot is at most 4 MB`);
|
|
21209
21474
|
return 1;
|
|
21210
21475
|
}
|
|
21211
|
-
const bytes = (o.readFile ??
|
|
21476
|
+
const bytes = (o.readFile ?? readFileSync17)(a.file);
|
|
21212
21477
|
if (bytes.byteLength > SHOT_MAX_BYTES) {
|
|
21213
21478
|
error(`${a.file}: a screenshot is at most 4 MB`);
|
|
21214
21479
|
return 1;
|
|
21215
21480
|
}
|
|
21216
21481
|
screenshot = {
|
|
21217
|
-
name:
|
|
21482
|
+
name: basename8(a.file),
|
|
21218
21483
|
mime: shotMime(a.file),
|
|
21219
21484
|
content: bytes.toString("base64")
|
|
21220
21485
|
};
|
|
@@ -21473,7 +21738,7 @@ import {
|
|
|
21473
21738
|
existsSync as existsSync21,
|
|
21474
21739
|
lstatSync as lstatSync2,
|
|
21475
21740
|
mkdtempSync,
|
|
21476
|
-
readFileSync as
|
|
21741
|
+
readFileSync as readFileSync22,
|
|
21477
21742
|
readlinkSync as readlinkSync4,
|
|
21478
21743
|
rmSync as rmSync13,
|
|
21479
21744
|
writeFileSync as writeFileSync19
|
|
@@ -21483,7 +21748,7 @@ import { delimiter as delimiter3, dirname as dirname18, join as join27, resolve
|
|
|
21483
21748
|
|
|
21484
21749
|
// src/agentMcp.ts
|
|
21485
21750
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
21486
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync18, readFileSync as
|
|
21751
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync18, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "node:fs";
|
|
21487
21752
|
import { dirname as dirname16, join as join25, resolve as resolve9 } from "node:path";
|
|
21488
21753
|
init_settings();
|
|
21489
21754
|
var MCP_SERVER2 = "sleds";
|
|
@@ -21491,7 +21756,7 @@ var AGENT_NAME2 = { "claude-code": "Claude Code", codex: "Codex" };
|
|
|
21491
21756
|
var claudeUserConfigPath2 = (home, env = process.env) => env.CLAUDE_CONFIG_DIR?.trim() ? join25(claudeDir(home, env), ".claude.json") : join25(home, ".claude.json");
|
|
21492
21757
|
function hasClaudeMcp2(home, env = process.env) {
|
|
21493
21758
|
try {
|
|
21494
|
-
const raw = JSON.parse(
|
|
21759
|
+
const raw = JSON.parse(readFileSync18(claudeUserConfigPath2(home, env), "utf8"));
|
|
21495
21760
|
return Boolean(raw.mcpServers?.[MCP_SERVER2]);
|
|
21496
21761
|
} catch {
|
|
21497
21762
|
return false;
|
|
@@ -21501,7 +21766,7 @@ function hasCodexMcp2(home) {
|
|
|
21501
21766
|
const path = codexConfigPath(home);
|
|
21502
21767
|
if (!existsSync18(path))
|
|
21503
21768
|
return false;
|
|
21504
|
-
return new RegExp(`^\\s*\\[mcp_servers\\.${MCP_SERVER2}\\]\\s*$`, "m").test(
|
|
21769
|
+
return new RegExp(`^\\s*\\[mcp_servers\\.${MCP_SERVER2}\\]\\s*$`, "m").test(readFileSync18(path, "utf8"));
|
|
21505
21770
|
}
|
|
21506
21771
|
var hasAgentMcp2 = (agent, home, env = process.env) => agent === "codex" ? hasCodexMcp2(home) : hasClaudeMcp2(home, env);
|
|
21507
21772
|
var seatHome2 = (home, env) => {
|
|
@@ -21581,7 +21846,7 @@ async function offerMcpResult2(o) {
|
|
|
21581
21846
|
return no;
|
|
21582
21847
|
if (o.agent === "codex") {
|
|
21583
21848
|
const path = codexConfigPath(o.home);
|
|
21584
|
-
const prior = existsSync18(path) ?
|
|
21849
|
+
const prior = existsSync18(path) ? readFileSync18(path, "utf8") : "";
|
|
21585
21850
|
mkdirSync18(dirname16(path), { recursive: true });
|
|
21586
21851
|
writeFileSync16(path, applyCodexMcp2(prior, o.home, env), { mode: 384 });
|
|
21587
21852
|
return {
|
|
@@ -21881,14 +22146,14 @@ init_config();
|
|
|
21881
22146
|
import {
|
|
21882
22147
|
existsSync as existsSync19,
|
|
21883
22148
|
mkdirSync as mkdirSync19,
|
|
21884
|
-
readFileSync as
|
|
22149
|
+
readFileSync as readFileSync19,
|
|
21885
22150
|
readdirSync as readdirSync4,
|
|
21886
22151
|
realpathSync,
|
|
21887
22152
|
rmSync as rmSync11,
|
|
21888
22153
|
writeFileSync as writeFileSync17
|
|
21889
22154
|
} from "node:fs";
|
|
21890
22155
|
import { hostname as hostname3 } from "node:os";
|
|
21891
|
-
import { basename as
|
|
22156
|
+
import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute4, join as join26 } from "node:path";
|
|
21892
22157
|
init_state();
|
|
21893
22158
|
var ENGINE_LABEL = "ai.sleds.engine";
|
|
21894
22159
|
var ENGINE_INSTALL_USAGE = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
|
|
@@ -22015,7 +22280,7 @@ function readEngines(dir, suffix, manager, parse) {
|
|
|
22015
22280
|
const path = join26(dir, name);
|
|
22016
22281
|
let parsed;
|
|
22017
22282
|
try {
|
|
22018
|
-
parsed = parse(
|
|
22283
|
+
parsed = parse(readFileSync19(path, "utf8"), name);
|
|
22019
22284
|
} catch {
|
|
22020
22285
|
parsed = null;
|
|
22021
22286
|
}
|
|
@@ -22035,7 +22300,7 @@ function installedEngines(home) {
|
|
|
22035
22300
|
...readEngines(join26(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
|
|
22036
22301
|
...readEngines(engineUnitDir(home), ".service", "systemd", (text, file) => {
|
|
22037
22302
|
const parsed = parseEngineUnit(text);
|
|
22038
|
-
return parsed && { label:
|
|
22303
|
+
return parsed && { label: basename9(file, ".service"), ...parsed };
|
|
22039
22304
|
})
|
|
22040
22305
|
];
|
|
22041
22306
|
}
|
|
@@ -22122,7 +22387,7 @@ function installUnit(a) {
|
|
|
22122
22387
|
const log = o.log ?? console.log;
|
|
22123
22388
|
const error = o.error ?? console.error;
|
|
22124
22389
|
const unit = engineUnitPath(o.home, label);
|
|
22125
|
-
const unitName =
|
|
22390
|
+
const unitName = basename9(unit);
|
|
22126
22391
|
const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
|
|
22127
22392
|
mkdirSync19(dirname17(unit), { recursive: true });
|
|
22128
22393
|
if (existsSync19(unit))
|
|
@@ -22132,7 +22397,7 @@ function installUnit(a) {
|
|
|
22132
22397
|
continue;
|
|
22133
22398
|
if (engineArg(other.programArgs, "name") !== parsed.name)
|
|
22134
22399
|
continue;
|
|
22135
|
-
systemctl("disable", "--now",
|
|
22400
|
+
systemctl("disable", "--now", basename9(other.plist));
|
|
22136
22401
|
rmSync11(other.plist, { force: true });
|
|
22137
22402
|
log(`replaced ${other.label}, this engine as installed before`);
|
|
22138
22403
|
}
|
|
@@ -22191,18 +22456,18 @@ function engineUninstall(o) {
|
|
|
22191
22456
|
const unit = file.endsWith(".service");
|
|
22192
22457
|
const exec = o.exec ?? defaultExec2;
|
|
22193
22458
|
if (unit)
|
|
22194
|
-
exec("systemctl", ["--user", "disable", "--now",
|
|
22459
|
+
exec("systemctl", ["--user", "disable", "--now", basename9(file)]);
|
|
22195
22460
|
else
|
|
22196
22461
|
exec("launchctl", ["unload", file]);
|
|
22197
22462
|
rmSync11(file, { force: true });
|
|
22198
22463
|
if (unit)
|
|
22199
22464
|
exec("systemctl", ["--user", "daemon-reload"]);
|
|
22200
|
-
log(`engine:${name} removed: ${
|
|
22465
|
+
log(`engine:${name} removed: ${basename9(file, unit ? ".service" : ".plist")} — its sessions keep running`);
|
|
22201
22466
|
return 0;
|
|
22202
22467
|
}
|
|
22203
22468
|
|
|
22204
22469
|
// src/commands/musher.ts
|
|
22205
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync20, readFileSync as
|
|
22470
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync20, readFileSync as readFileSync20, rmSync as rmSync12, writeFileSync as writeFileSync18 } from "node:fs";
|
|
22206
22471
|
init_config();
|
|
22207
22472
|
init_meter();
|
|
22208
22473
|
var defaultWhich = (cmd) => {
|
|
@@ -22237,7 +22502,7 @@ var musherAgentState = (home, env = process.env) => {
|
|
|
22237
22502
|
if (!existsSync20(plist))
|
|
22238
22503
|
return { installed: false, thisSeat: false };
|
|
22239
22504
|
try {
|
|
22240
|
-
const text =
|
|
22505
|
+
const text = readFileSync20(plist, "utf8");
|
|
22241
22506
|
const want = env.SLEDS_HOME?.trim();
|
|
22242
22507
|
const has = /<key>SLEDS_HOME<\/key>\s*<string>([^<]*)<\/string>/.exec(text)?.[1];
|
|
22243
22508
|
return { installed: true, thisSeat: (want ?? undefined) === (has ?? undefined) };
|
|
@@ -22247,7 +22512,7 @@ var musherAgentState = (home, env = process.env) => {
|
|
|
22247
22512
|
};
|
|
22248
22513
|
|
|
22249
22514
|
// src/claudeAccount.ts
|
|
22250
|
-
import { readFileSync as
|
|
22515
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
22251
22516
|
var PLANS = {
|
|
22252
22517
|
claude_max: "Max",
|
|
22253
22518
|
claude_pro: "Pro",
|
|
@@ -22276,7 +22541,7 @@ var parseClaudeAccount = (raw) => {
|
|
|
22276
22541
|
};
|
|
22277
22542
|
var readClaudeAccount = (home, env = process.env) => {
|
|
22278
22543
|
try {
|
|
22279
|
-
return parseClaudeAccount(JSON.parse(
|
|
22544
|
+
return parseClaudeAccount(JSON.parse(readFileSync21(claudeUserConfigPath2(home, env), "utf8")));
|
|
22280
22545
|
} catch {
|
|
22281
22546
|
return null;
|
|
22282
22547
|
}
|
|
@@ -22879,7 +23144,7 @@ function boxChecks(o, env, which, need) {
|
|
|
22879
23144
|
const file = boxEnvPath(o.home);
|
|
22880
23145
|
let boxEnvText = null;
|
|
22881
23146
|
try {
|
|
22882
|
-
boxEnvText =
|
|
23147
|
+
boxEnvText = readFileSync22(file, "utf8");
|
|
22883
23148
|
} catch {
|
|
22884
23149
|
boxEnvText = null;
|
|
22885
23150
|
}
|
|
@@ -22997,10 +23262,10 @@ import {
|
|
|
22997
23262
|
appendFileSync as appendFileSync3,
|
|
22998
23263
|
chmodSync as chmodSync6,
|
|
22999
23264
|
mkdirSync as mkdirSync21,
|
|
23000
|
-
readFileSync as
|
|
23265
|
+
readFileSync as readFileSync23,
|
|
23001
23266
|
existsSync as realExists2,
|
|
23002
23267
|
rmSync as rmSync14,
|
|
23003
|
-
statSync as
|
|
23268
|
+
statSync as statSync9,
|
|
23004
23269
|
writeFileSync as writeFileSync20
|
|
23005
23270
|
} from "node:fs";
|
|
23006
23271
|
import { hostname as hostname4, tmpdir as tmpdir3, userInfo as userInfo3 } from "node:os";
|
|
@@ -23411,7 +23676,7 @@ function engineClient2(o, org, breaker) {
|
|
|
23411
23676
|
...src,
|
|
23412
23677
|
...breaker ? { fetchFn: breaker.fetch } : {},
|
|
23413
23678
|
timeoutMs: ENGINE_TIMEOUT_MS2,
|
|
23414
|
-
version: "0.1.
|
|
23679
|
+
version: "0.1.73"
|
|
23415
23680
|
});
|
|
23416
23681
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
23417
23682
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -23453,7 +23718,7 @@ function realPidAlive3(pid) {
|
|
|
23453
23718
|
function memberMcpConfigs2(o, cwd) {
|
|
23454
23719
|
const read = o.readJson ?? ((p) => {
|
|
23455
23720
|
try {
|
|
23456
|
-
return JSON.parse(
|
|
23721
|
+
return JSON.parse(readFileSync23(p, "utf8"));
|
|
23457
23722
|
} catch {
|
|
23458
23723
|
return null;
|
|
23459
23724
|
}
|
|
@@ -23488,7 +23753,7 @@ function engineCredential(o) {
|
|
|
23488
23753
|
const file = boxEnvPath(o.home);
|
|
23489
23754
|
let boxEnvText = null;
|
|
23490
23755
|
try {
|
|
23491
|
-
boxEnvText =
|
|
23756
|
+
boxEnvText = readFileSync23(file, "utf8");
|
|
23492
23757
|
} catch {}
|
|
23493
23758
|
return detectCredential(o.env ?? process.env, {
|
|
23494
23759
|
home: o.home,
|
|
@@ -23620,11 +23885,20 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
23620
23885
|
},
|
|
23621
23886
|
readMock: (p) => {
|
|
23622
23887
|
try {
|
|
23623
|
-
return
|
|
23888
|
+
return readFileSync23(p, "utf8");
|
|
23889
|
+
} catch {
|
|
23890
|
+
return null;
|
|
23891
|
+
}
|
|
23892
|
+
},
|
|
23893
|
+
fetchMock: async (url) => {
|
|
23894
|
+
try {
|
|
23895
|
+
const r = await fetch(url, { signal: AbortSignal.timeout(15000) });
|
|
23896
|
+
return r.ok ? await r.text() : null;
|
|
23624
23897
|
} catch {
|
|
23625
23898
|
return null;
|
|
23626
23899
|
}
|
|
23627
23900
|
},
|
|
23901
|
+
writeMock: (p, html) => writeFileSync20(p, html, { mode: 384 }),
|
|
23628
23902
|
ensureWorktree: (e, repoPath, branch, path, base, install) => ensureWorktree(e, repoPath, branch, path, base, o.worktreeFs ?? { ...realWorktreeFs, exists }, { ...install ? { command: install } : {}, log: o.log ?? console.log }),
|
|
23629
23903
|
ensureDraftWorktree: (e, repoPath, path, base) => ensureDetachedWorktree(e, repoPath, path, base, o.worktreeFs ?? { ...realWorktreeFs, exists }),
|
|
23630
23904
|
defaultBranch,
|
|
@@ -23759,7 +24033,7 @@ function lentHomeProblems2(accountHome, lentBy, modeOf) {
|
|
|
23759
24033
|
}
|
|
23760
24034
|
var homeMode2 = (path) => {
|
|
23761
24035
|
try {
|
|
23762
|
-
return
|
|
24036
|
+
return statSync9(path).mode & 4095;
|
|
23763
24037
|
} catch {
|
|
23764
24038
|
return null;
|
|
23765
24039
|
}
|
|
@@ -23804,7 +24078,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
23804
24078
|
runner: deps.runner.name,
|
|
23805
24079
|
atOnce: flags.atOnce,
|
|
23806
24080
|
interval: flags.interval,
|
|
23807
|
-
cliVersion: "0.1.
|
|
24081
|
+
cliVersion: "0.1.73"
|
|
23808
24082
|
};
|
|
23809
24083
|
const beat = (checkedAt) => {
|
|
23810
24084
|
const m = deps.machine;
|
|
@@ -24434,14 +24708,14 @@ init_config();
|
|
|
24434
24708
|
import {
|
|
24435
24709
|
existsSync as existsSync22,
|
|
24436
24710
|
mkdirSync as mkdirSync22,
|
|
24437
|
-
readFileSync as
|
|
24711
|
+
readFileSync as readFileSync24,
|
|
24438
24712
|
readdirSync as readdirSync6,
|
|
24439
24713
|
realpathSync as realpathSync2,
|
|
24440
24714
|
rmSync as rmSync15,
|
|
24441
24715
|
writeFileSync as writeFileSync21
|
|
24442
24716
|
} from "node:fs";
|
|
24443
24717
|
import { hostname as hostname5 } from "node:os";
|
|
24444
|
-
import { basename as
|
|
24718
|
+
import { basename as basename10, dirname as dirname20, isAbsolute as isAbsolute6, join as join29 } from "node:path";
|
|
24445
24719
|
init_state();
|
|
24446
24720
|
var ENGINE_LABEL2 = "ai.sleds.engine";
|
|
24447
24721
|
var ENGINE_INSTALL_USAGE2 = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
|
|
@@ -24568,7 +24842,7 @@ function readEngines2(dir, suffix, manager, parse) {
|
|
|
24568
24842
|
const path = join29(dir, name);
|
|
24569
24843
|
let parsed;
|
|
24570
24844
|
try {
|
|
24571
|
-
parsed = parse(
|
|
24845
|
+
parsed = parse(readFileSync24(path, "utf8"), name);
|
|
24572
24846
|
} catch {
|
|
24573
24847
|
parsed = null;
|
|
24574
24848
|
}
|
|
@@ -24588,7 +24862,7 @@ function installedEngines2(home) {
|
|
|
24588
24862
|
...readEngines2(join29(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
|
|
24589
24863
|
...readEngines2(engineUnitDir(home), ".service", "systemd", (text, file) => {
|
|
24590
24864
|
const parsed = parseEngineUnit(text);
|
|
24591
|
-
return parsed && { label:
|
|
24865
|
+
return parsed && { label: basename10(file, ".service"), ...parsed };
|
|
24592
24866
|
})
|
|
24593
24867
|
];
|
|
24594
24868
|
}
|
|
@@ -24719,7 +24993,7 @@ function installUnit2(a) {
|
|
|
24719
24993
|
const log = o.log ?? console.log;
|
|
24720
24994
|
const error = o.error ?? console.error;
|
|
24721
24995
|
const unit = engineUnitPath(o.home, label);
|
|
24722
|
-
const unitName =
|
|
24996
|
+
const unitName = basename10(unit);
|
|
24723
24997
|
const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
|
|
24724
24998
|
mkdirSync22(dirname20(unit), { recursive: true });
|
|
24725
24999
|
if (existsSync22(unit))
|
|
@@ -24729,7 +25003,7 @@ function installUnit2(a) {
|
|
|
24729
25003
|
continue;
|
|
24730
25004
|
if (engineArg2(other.programArgs, "name") !== parsed.name)
|
|
24731
25005
|
continue;
|
|
24732
|
-
systemctl("disable", "--now",
|
|
25006
|
+
systemctl("disable", "--now", basename10(other.plist));
|
|
24733
25007
|
rmSync15(other.plist, { force: true });
|
|
24734
25008
|
log(`replaced ${other.label}, this engine as installed before`);
|
|
24735
25009
|
}
|
|
@@ -24788,13 +25062,13 @@ function engineUninstall2(o) {
|
|
|
24788
25062
|
const unit = file.endsWith(".service");
|
|
24789
25063
|
const exec = o.exec ?? defaultExec2;
|
|
24790
25064
|
if (unit)
|
|
24791
|
-
exec("systemctl", ["--user", "disable", "--now",
|
|
25065
|
+
exec("systemctl", ["--user", "disable", "--now", basename10(file)]);
|
|
24792
25066
|
else
|
|
24793
25067
|
exec("launchctl", ["unload", file]);
|
|
24794
25068
|
rmSync15(file, { force: true });
|
|
24795
25069
|
if (unit)
|
|
24796
25070
|
exec("systemctl", ["--user", "daemon-reload"]);
|
|
24797
|
-
log(`engine:${name} removed: ${
|
|
25071
|
+
log(`engine:${name} removed: ${basename10(file, unit ? ".service" : ".plist")} — its sessions keep running`);
|
|
24798
25072
|
return 0;
|
|
24799
25073
|
}
|
|
24800
25074
|
|
|
@@ -24922,7 +25196,7 @@ import { closeSync as closeSync5, fstatSync as fstatSync2, openSync as openSync5
|
|
|
24922
25196
|
import { hostname as hostname6 } from "node:os";
|
|
24923
25197
|
|
|
24924
25198
|
// src/commands/engineStatus.ts
|
|
24925
|
-
import { existsSync as existsSync23, readFileSync as
|
|
25199
|
+
import { existsSync as existsSync23, readFileSync as readFileSync25 } from "node:fs";
|
|
24926
25200
|
init_state();
|
|
24927
25201
|
|
|
24928
25202
|
// src/engine/status.ts
|
|
@@ -25222,7 +25496,7 @@ var engineLogCmd = (o) => {
|
|
|
25222
25496
|
|
|
25223
25497
|
// src/commands/engineProfile.ts
|
|
25224
25498
|
init_src();
|
|
25225
|
-
import { existsSync as existsSync24, readFileSync as
|
|
25499
|
+
import { existsSync as existsSync24, readFileSync as readFileSync26 } from "node:fs";
|
|
25226
25500
|
import { hostname as hostname7 } from "node:os";
|
|
25227
25501
|
var PROFILE_USAGE = "usage: sleds engine profile [--json] | sleds engine profile set <field>=<value>… [--workspace] [--json] | sleds engine profile set --stdin [--workspace] [--json] | sleds engine profile --strict-mcp [--mcp-allow <a,b>] | --no-strict-mcp [--workspace] [--json] | sleds engine profile --sandbox [--sandbox-allow <a,b>] | --no-sandbox [--workspace] [--json] | sleds engine profile set --hold on|off [--workspace] [--json] | sleds engine profile set cmuxPassword=<pw> | --cmux-password <pw> [--json]";
|
|
25228
25502
|
var PROFILE_FIELDS = [
|
|
@@ -25493,7 +25767,7 @@ async function engineProfileCmd(o) {
|
|
|
25493
25767
|
const rest = words.slice(1);
|
|
25494
25768
|
let stdin = null;
|
|
25495
25769
|
if (fromStdin) {
|
|
25496
|
-
const taken = cmuxPasswordFromJson((o.stdin ?? (() =>
|
|
25770
|
+
const taken = cmuxPasswordFromJson((o.stdin ?? (() => readFileSync26(0, "utf8")))());
|
|
25497
25771
|
if ("error" in taken || taken.password !== undefined && password !== undefined) {
|
|
25498
25772
|
error("error" in taken ? taken.error : "the cmux password is given once");
|
|
25499
25773
|
error(PROFILE_USAGE);
|
|
@@ -25578,7 +25852,7 @@ var keychainLine = (k) => k === "set" ? "cmuxPassword: set (Keychain)" : k === "
|
|
|
25578
25852
|
|
|
25579
25853
|
// src/commands/engineStatus.ts
|
|
25580
25854
|
init_state();
|
|
25581
|
-
import { existsSync as existsSync25, readFileSync as
|
|
25855
|
+
import { existsSync as existsSync25, readFileSync as readFileSync27 } from "node:fs";
|
|
25582
25856
|
import { hostname as hostname8 } from "node:os";
|
|
25583
25857
|
var ENGINE_STATUS_USAGE = "usage: sleds engine status [--name <n>] [--org <slug>] [--json]";
|
|
25584
25858
|
function parseStatusArgs(argv, host) {
|
|
@@ -25634,7 +25908,7 @@ function readEngineStatus(stateDir, engine, host, pidAlive, seat) {
|
|
|
25634
25908
|
}
|
|
25635
25909
|
function safeRead(path) {
|
|
25636
25910
|
try {
|
|
25637
|
-
return
|
|
25911
|
+
return readFileSync27(path, "utf8");
|
|
25638
25912
|
} catch {
|
|
25639
25913
|
return "";
|
|
25640
25914
|
}
|
|
@@ -25755,7 +26029,7 @@ init_meter();
|
|
|
25755
26029
|
|
|
25756
26030
|
// src/owed.ts
|
|
25757
26031
|
init_config();
|
|
25758
|
-
import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as
|
|
26032
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as readFileSync28, renameSync as renameSync11, writeFileSync as writeFileSync22 } from "node:fs";
|
|
25759
26033
|
import { dirname as dirname21, join as join30 } from "node:path";
|
|
25760
26034
|
var owedPath = (home) => join30(configDir(home), "owed.json");
|
|
25761
26035
|
var sessionPath = (home) => join30(configDir(home), "session.json");
|
|
@@ -25776,7 +26050,7 @@ var readJson = (p) => {
|
|
|
25776
26050
|
if (!existsSync26(p))
|
|
25777
26051
|
return null;
|
|
25778
26052
|
try {
|
|
25779
|
-
return JSON.parse(
|
|
26053
|
+
return JSON.parse(readFileSync28(p, "utf8"));
|
|
25780
26054
|
} catch {
|
|
25781
26055
|
return null;
|
|
25782
26056
|
}
|
|
@@ -25916,7 +26190,7 @@ function contextFor(deps) {
|
|
|
25916
26190
|
...src,
|
|
25917
26191
|
fetchFn: deps.fetchFn,
|
|
25918
26192
|
timeoutMs: deps.timeoutMs,
|
|
25919
|
-
version: "0.1.
|
|
26193
|
+
version: "0.1.73"
|
|
25920
26194
|
}), deps.home, now) : null;
|
|
25921
26195
|
return {
|
|
25922
26196
|
channel: "code",
|
|
@@ -26990,9 +27264,9 @@ var login = async (o) => {
|
|
|
26990
27264
|
// src/commands/logout.ts
|
|
26991
27265
|
init_config();
|
|
26992
27266
|
init_state();
|
|
26993
|
-
import { existsSync as existsSync28, readFileSync as
|
|
27267
|
+
import { existsSync as existsSync28, readFileSync as readFileSync29, rmSync as rmSync16 } from "node:fs";
|
|
26994
27268
|
import { hostname as hostname10 } from "node:os";
|
|
26995
|
-
import { basename as
|
|
27269
|
+
import { basename as basename11 } from "node:path";
|
|
26996
27270
|
init_settings();
|
|
26997
27271
|
var LOGOUT_USAGE = "usage: sleds logout [--org <slug>] [--json]";
|
|
26998
27272
|
function parseLogoutArgs(argv) {
|
|
@@ -27116,7 +27390,7 @@ async function logout(o) {
|
|
|
27116
27390
|
if (!e.org) {
|
|
27117
27391
|
const exec = o.exec ?? defaultExec2;
|
|
27118
27392
|
if (e.manager === "systemd") {
|
|
27119
|
-
exec("systemctl", ["--user", "disable", "--now",
|
|
27393
|
+
exec("systemctl", ["--user", "disable", "--now", basename11(e.plist)]);
|
|
27120
27394
|
rmSync16(e.plist, { force: true });
|
|
27121
27395
|
exec("systemctl", ["--user", "daemon-reload"]);
|
|
27122
27396
|
} else {
|
|
@@ -27155,7 +27429,7 @@ async function logout(o) {
|
|
|
27155
27429
|
};
|
|
27156
27430
|
writeConfig(o.home, next);
|
|
27157
27431
|
const tp = tokenPath(o.home, env);
|
|
27158
|
-
if (existsSync28(tp) &&
|
|
27432
|
+
if (existsSync28(tp) && readFileSync29(tp, "utf8").trim() === seat.token)
|
|
27159
27433
|
rmSync16(tp, { force: true });
|
|
27160
27434
|
const active = next.activeOrg ?? next.org?.slug ?? null;
|
|
27161
27435
|
const result = { ok: true, email, org: slug, paused, active };
|
|
@@ -27233,7 +27507,7 @@ var meter = async (o) => {
|
|
|
27233
27507
|
init_config();
|
|
27234
27508
|
init_meter();
|
|
27235
27509
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
27236
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync25, readFileSync as
|
|
27510
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync25, readFileSync as readFileSync30, rmSync as rmSync17, writeFileSync as writeFileSync24 } from "node:fs";
|
|
27237
27511
|
import { hostname as hostname11 } from "node:os";
|
|
27238
27512
|
import { dirname as dirname22 } from "node:path";
|
|
27239
27513
|
var defaultWhich3 = (cmd) => {
|
|
@@ -27753,7 +28027,7 @@ var packCmd = async (o) => {
|
|
|
27753
28027
|
};
|
|
27754
28028
|
|
|
27755
28029
|
// src/commands/permissionEvent.ts
|
|
27756
|
-
import { chmodSync as chmodSync7, mkdirSync as mkdirSync26, readFileSync as
|
|
28030
|
+
import { chmodSync as chmodSync7, mkdirSync as mkdirSync26, readFileSync as readFileSync31, renameSync as renameSync12, rmSync as rmSync19, writeFileSync as writeFileSync26 } from "node:fs";
|
|
27757
28031
|
import { dirname as dirname23 } from "node:path";
|
|
27758
28032
|
var isObject13 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
27759
28033
|
var messageOf = (text) => {
|
|
@@ -27950,7 +28224,7 @@ async function reopenCmd(o) {
|
|
|
27950
28224
|
|
|
27951
28225
|
// src/commands/route.ts
|
|
27952
28226
|
init_src();
|
|
27953
|
-
import { readFileSync as
|
|
28227
|
+
import { readFileSync as readFileSync32 } from "node:fs";
|
|
27954
28228
|
import { hostname as hostname12 } from "node:os";
|
|
27955
28229
|
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>]";
|
|
27956
28230
|
var USAGE2 = "usage: sleds route <key> [--long | --dot | --json] | sleds route arm <key> [--off] [--json] | sleds route answer <key>/<node> --stdin | sleds route instruct <key>/<node> --stdin [--voice] | sleds route propose <key> --file <nodes.json> | sleds route approve <key> [--voice --stdin] | sleds route redraft <key> | sleds route single <key> | sleds route elsewhere <key> [--note <text>] | 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]";
|
|
@@ -28133,7 +28407,7 @@ async function answerCmd(o, argv) {
|
|
|
28133
28407
|
const words = argv.filter((a) => a !== "--json" && a !== "--stdin");
|
|
28134
28408
|
const ref = words[0] ?? "";
|
|
28135
28409
|
const slash = ref.lastIndexOf("/");
|
|
28136
|
-
const answer = (fromStdin ? (o.stdin ?? (() =>
|
|
28410
|
+
const answer = (fromStdin ? (o.stdin ?? (() => readFileSync32(0, "utf8")))() : words.slice(1).join(" ")).trim();
|
|
28137
28411
|
if (slash <= 0 || slash === ref.length - 1 || fromStdin && words.length > 1) {
|
|
28138
28412
|
error(ANSWER_USAGE);
|
|
28139
28413
|
return 2;
|
|
@@ -28178,7 +28452,7 @@ async function instructCmd(o, argv) {
|
|
|
28178
28452
|
error(INSTRUCT_USAGE);
|
|
28179
28453
|
return 2;
|
|
28180
28454
|
}
|
|
28181
|
-
const text = fromStdin ? (o.stdin ?? (() =>
|
|
28455
|
+
const text = fromStdin ? (o.stdin ?? (() => readFileSync32(0, "utf8")))() : words.slice(1).join(" ");
|
|
28182
28456
|
const { md, heard } = voice ? splitVoiceStdin(text) : { md: text.trim(), heard: undefined };
|
|
28183
28457
|
if (!md) {
|
|
28184
28458
|
error("an instruction needs some text");
|
|
@@ -28271,7 +28545,7 @@ async function approveCmd(o, argv) {
|
|
|
28271
28545
|
error(APPROVE_USAGE);
|
|
28272
28546
|
return 2;
|
|
28273
28547
|
}
|
|
28274
|
-
const heard = a.voice ? (o.stdin ?? (() =>
|
|
28548
|
+
const heard = a.voice ? (o.stdin ?? (() => readFileSync32(0, "utf8")))().trim() : undefined;
|
|
28275
28549
|
let nodes;
|
|
28276
28550
|
let approach;
|
|
28277
28551
|
if (a.file) {
|
|
@@ -28394,7 +28668,7 @@ async function decisionCmd(o, argv) {
|
|
|
28394
28668
|
error(DECISION_USAGE);
|
|
28395
28669
|
return 2;
|
|
28396
28670
|
}
|
|
28397
|
-
const md = seen || routeAlone ? "" : (fromStdin ? (o.stdin ?? (() =>
|
|
28671
|
+
const md = seen || routeAlone ? "" : (fromStdin ? (o.stdin ?? (() => readFileSync32(0, "utf8")))() : rest.join(" ")).trim();
|
|
28398
28672
|
if (!seen && !routeAlone && (!md || fromStdin && rest.length > 0)) {
|
|
28399
28673
|
error(md ? DECISION_USAGE : `${answer ? "an answer" : "an overrule"} needs some text`);
|
|
28400
28674
|
return 2;
|
|
@@ -28573,7 +28847,7 @@ function approvedLine(key, j) {
|
|
|
28573
28847
|
function readNodes(o, a) {
|
|
28574
28848
|
let text;
|
|
28575
28849
|
try {
|
|
28576
|
-
text = a.file ? (o.readFile ?? ((p) =>
|
|
28850
|
+
text = a.file ? (o.readFile ?? ((p) => readFileSync32(p, "utf8")))(a.file) : (o.stdin ?? (() => readFileSync32(0, "utf8")))();
|
|
28577
28851
|
} catch (e) {
|
|
28578
28852
|
return { error: e instanceof Error ? e.message : String(e) };
|
|
28579
28853
|
}
|
|
@@ -29010,7 +29284,7 @@ async function seatRevokeCmd(o) {
|
|
|
29010
29284
|
|
|
29011
29285
|
// src/commands/seatSync.ts
|
|
29012
29286
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
29013
|
-
import { existsSync as existsSync31, mkdirSync as mkdirSync27, readFileSync as
|
|
29287
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync27, readFileSync as readFileSync33, readdirSync as readdirSync7, rmSync as rmSync21, writeFileSync as writeFileSync27 } from "node:fs";
|
|
29014
29288
|
import { platform as platform2 } from "node:os";
|
|
29015
29289
|
import { dirname as dirname24, join as join33 } from "node:path";
|
|
29016
29290
|
|
|
@@ -29360,7 +29634,7 @@ function findCookieDb(home, source) {
|
|
|
29360
29634
|
return db;
|
|
29361
29635
|
}
|
|
29362
29636
|
const localStatePath = join33(root, "Local State");
|
|
29363
|
-
const localState = existsSync31(localStatePath) ?
|
|
29637
|
+
const localState = existsSync31(localStatePath) ? readFileSync33(localStatePath, "utf8") : null;
|
|
29364
29638
|
const wanted = source.profile ?? "Default";
|
|
29365
29639
|
const { dir, ambiguous } = resolveProfileDir(localState, wanted);
|
|
29366
29640
|
if (ambiguous)
|
|
@@ -29542,7 +29816,7 @@ var seatSync = async (o) => {
|
|
|
29542
29816
|
};
|
|
29543
29817
|
function readSeatToken(home, source) {
|
|
29544
29818
|
try {
|
|
29545
|
-
return
|
|
29819
|
+
return readFileSync33(seatTokenPath(home, source), "utf8").trim() || undefined;
|
|
29546
29820
|
} catch {
|
|
29547
29821
|
return;
|
|
29548
29822
|
}
|
|
@@ -29628,7 +29902,7 @@ import { homedir as homedir8 } from "node:os";
|
|
|
29628
29902
|
import { join as join37, resolve as resolve12 } from "node:path";
|
|
29629
29903
|
|
|
29630
29904
|
// src/sleuth/export.ts
|
|
29631
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync28, readFileSync as
|
|
29905
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync28, readFileSync as readFileSync34, renameSync as renameSync13, writeFileSync as writeFileSync28 } from "node:fs";
|
|
29632
29906
|
import { dirname as dirname25, join as join34 } from "node:path";
|
|
29633
29907
|
|
|
29634
29908
|
// src/sleuth/graphql.ts
|
|
@@ -30183,7 +30457,7 @@ var writeAtomic = (path, body) => {
|
|
|
30183
30457
|
var jsonl = (items) => items.length ? `${items.map((i) => JSON.stringify(i)).join(`
|
|
30184
30458
|
`)}
|
|
30185
30459
|
` : "";
|
|
30186
|
-
var readJsonl = (path) =>
|
|
30460
|
+
var readJsonl = (path) => readFileSync34(path, "utf8").split(`
|
|
30187
30461
|
`).filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
30188
30462
|
var CANNOT_QUERY = /Cannot query field "(\w+)" on type "(\w+)"/;
|
|
30189
30463
|
var TOO_DEEP = /\bmax(imum)?\b.{0,24}\bdepth\b|\btoo deep\b/i;
|
|
@@ -30640,9 +30914,9 @@ var exportSleuth = async (o) => {
|
|
|
30640
30914
|
// src/sleuth/import.ts
|
|
30641
30915
|
init_src();
|
|
30642
30916
|
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
30643
|
-
import { mkdtempSync as mkdtempSync2, readFileSync as
|
|
30917
|
+
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync35, readdirSync as readdirSync8, rmSync as rmSync22, statSync as statSync10 } from "node:fs";
|
|
30644
30918
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
30645
|
-
import { basename as
|
|
30919
|
+
import { basename as basename12, join as join35 } from "node:path";
|
|
30646
30920
|
var httpFetch = (url, init) => fetch(url, { ...init, body: init.body === "" ? undefined : init.body });
|
|
30647
30921
|
|
|
30648
30922
|
class SleuthImportError extends Error {
|
|
@@ -30654,7 +30928,7 @@ class SleuthImportError extends Error {
|
|
|
30654
30928
|
}
|
|
30655
30929
|
var isDir2 = (p) => {
|
|
30656
30930
|
try {
|
|
30657
|
-
return
|
|
30931
|
+
return statSync10(p).isDirectory();
|
|
30658
30932
|
} catch {
|
|
30659
30933
|
return false;
|
|
30660
30934
|
}
|
|
@@ -30668,7 +30942,7 @@ var entries = (p) => {
|
|
|
30668
30942
|
};
|
|
30669
30943
|
function changesRoot(dir) {
|
|
30670
30944
|
const here = [join35(dir, "data", "changes"), join35(dir, "changes")];
|
|
30671
|
-
if (
|
|
30945
|
+
if (basename12(dir) === "changes")
|
|
30672
30946
|
here.unshift(dir);
|
|
30673
30947
|
const below = entries(dir).map((e) => join35(dir, e)).filter(isDir2).flatMap((d) => [join35(d, "data", "changes"), join35(d, "changes")]);
|
|
30674
30948
|
return [...here, ...below].find(isDir2);
|
|
@@ -30683,7 +30957,7 @@ function* readChanges(dir) {
|
|
|
30683
30957
|
continue;
|
|
30684
30958
|
for (const name of entries(pdir).filter((f) => f.endsWith(".jsonl"))) {
|
|
30685
30959
|
const file = join35(pdir, name);
|
|
30686
|
-
const lines =
|
|
30960
|
+
const lines = readFileSync35(file, "utf8").split(`
|
|
30687
30961
|
`);
|
|
30688
30962
|
for (let i = 0;i < lines.length; i++) {
|
|
30689
30963
|
const text = lines[i].trim();
|
|
@@ -30704,7 +30978,7 @@ var systemUnzip = (zip, dest) => {
|
|
|
30704
30978
|
function openExport(path, unzip = systemUnzip) {
|
|
30705
30979
|
let file = false;
|
|
30706
30980
|
try {
|
|
30707
|
-
const s =
|
|
30981
|
+
const s = statSync10(path);
|
|
30708
30982
|
if (s.isDirectory())
|
|
30709
30983
|
return { dir: path, done: () => {} };
|
|
30710
30984
|
file = s.isFile();
|
|
@@ -31094,11 +31368,12 @@ var repoOk = (v) => REPO_RE.test(v);
|
|
|
31094
31368
|
|
|
31095
31369
|
// src/sleuth/reconcile.ts
|
|
31096
31370
|
init_src();
|
|
31097
|
-
import { readFileSync as
|
|
31371
|
+
import { readFileSync as readFileSync36, readdirSync as readdirSync9 } from "node:fs";
|
|
31098
31372
|
import { dirname as dirname26, join as join36 } from "node:path";
|
|
31099
31373
|
var OFF = 0.1;
|
|
31100
31374
|
var isObj8 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
31101
31375
|
var nums = (v) => Array.isArray(v) ? v.map((x) => typeof x === "number" && Number.isFinite(x) ? x : 0) : [];
|
|
31376
|
+
var sum = (xs) => xs.reduce((a, b) => a + b, 0);
|
|
31102
31377
|
var MONTH_FILE = /^(\d{4}-(0[1-9]|1[0-2]))\.json$/;
|
|
31103
31378
|
function sleuthMonth(json, project, month) {
|
|
31104
31379
|
if (!isObj8(json))
|
|
@@ -31108,17 +31383,22 @@ function sleuthMonth(json, project, month) {
|
|
|
31108
31383
|
return "no metricFrequency";
|
|
31109
31384
|
const perDay = nums(freq.datapoints);
|
|
31110
31385
|
const leadPerDay = isObj8(json.metricLeadTime) ? nums(json.metricLeadTime.datapoints) : [];
|
|
31111
|
-
const deploys = Math.round(perDay
|
|
31386
|
+
const deploys = Math.round(sum(perDay));
|
|
31112
31387
|
let weighted = 0;
|
|
31113
31388
|
for (let i = 0;i < perDay.length; i++)
|
|
31114
31389
|
weighted += perDay[i] * (leadPerDay[i] ?? 0);
|
|
31390
|
+
const failed = isObj8(json.metricFailureRate) ? Math.round(sum(nums(json.metricFailureRate.datapoints))) : null;
|
|
31391
|
+
const failedFor = isObj8(json.metricMttr) ? sum(nums(json.metricMttr.datapoints)) : null;
|
|
31115
31392
|
return {
|
|
31116
31393
|
project,
|
|
31117
31394
|
month,
|
|
31118
31395
|
environment: typeof json.environment === "string" ? json.environment.toLowerCase() : "",
|
|
31119
31396
|
deploys,
|
|
31120
|
-
flags: nums(freq.ffDeploys)
|
|
31121
|
-
lead: deploys ? Math.round(weighted / deploys) : null
|
|
31397
|
+
flags: sum(nums(freq.ffDeploys)),
|
|
31398
|
+
lead: deploys ? Math.round(weighted / deploys) : null,
|
|
31399
|
+
failed,
|
|
31400
|
+
failureRate: failed !== null && deploys ? failed / deploys : null,
|
|
31401
|
+
mttr: failed && failedFor !== null ? Math.round(failedFor / failed) : null
|
|
31122
31402
|
};
|
|
31123
31403
|
}
|
|
31124
31404
|
function metricsRoot(dir) {
|
|
@@ -31146,7 +31426,7 @@ function readMetrics(dir) {
|
|
|
31146
31426
|
continue;
|
|
31147
31427
|
let json;
|
|
31148
31428
|
try {
|
|
31149
|
-
json = JSON.parse(
|
|
31429
|
+
json = JSON.parse(readFileSync36(join36(root, project, name), "utf8"));
|
|
31150
31430
|
} catch {
|
|
31151
31431
|
errors.push(`${project}/${name}: not JSON`);
|
|
31152
31432
|
continue;
|
|
@@ -31208,24 +31488,43 @@ ${env.env.slug}
|
|
|
31208
31488
|
${s.month}`);
|
|
31209
31489
|
if (!s.deploys && !o?.deploys)
|
|
31210
31490
|
continue;
|
|
31491
|
+
const sledsDeploys = o?.deploys ?? 0;
|
|
31211
31492
|
const sledsLead = o?.lead?.workingByDeploy ?? null;
|
|
31212
|
-
const dDeploys = delta(s.deploys,
|
|
31493
|
+
const dDeploys = delta(s.deploys, sledsDeploys);
|
|
31213
31494
|
const dLead = s.lead !== null && sledsLead !== null ? delta(s.lead, sledsLead) : null;
|
|
31495
|
+
const sledsFailed = o ? o.failed ?? null : 0;
|
|
31496
|
+
const sledsRate = sledsFailed !== null && sledsDeploys ? sledsFailed / sledsDeploys : null;
|
|
31497
|
+
const sledsRecover = o?.recover ?? null;
|
|
31498
|
+
const compared = s.failed !== null && sledsFailed !== null;
|
|
31499
|
+
const dRate = compared && s.failureRate !== null && sledsRate !== null ? delta(s.failureRate, sledsRate) : null;
|
|
31500
|
+
const dRecover = s.mttr !== null && sledsRecover !== null ? delta(s.mttr, sledsRecover.mean) : null;
|
|
31501
|
+
const over = (d) => d !== null && Math.abs(d) > OFF;
|
|
31214
31502
|
rows.push({
|
|
31215
31503
|
project: s.project,
|
|
31216
31504
|
repo,
|
|
31217
31505
|
environment: env.env.slug,
|
|
31218
31506
|
month: s.month,
|
|
31219
|
-
sleuth: {
|
|
31507
|
+
sleuth: {
|
|
31508
|
+
deploys: s.deploys,
|
|
31509
|
+
lead: s.lead,
|
|
31510
|
+
failed: s.failed,
|
|
31511
|
+
failureRate: s.failureRate,
|
|
31512
|
+
mttr: s.mttr
|
|
31513
|
+
},
|
|
31220
31514
|
sleds: {
|
|
31221
|
-
deploys:
|
|
31515
|
+
deploys: sledsDeploys,
|
|
31222
31516
|
prs: o?.prs ?? 0,
|
|
31223
31517
|
missing: o?.missing ?? 0,
|
|
31224
|
-
lead: o?.lead ?? null
|
|
31518
|
+
lead: o?.lead ?? null,
|
|
31519
|
+
failed: sledsFailed,
|
|
31520
|
+
failureRate: sledsRate,
|
|
31521
|
+
recover: sledsRecover
|
|
31225
31522
|
},
|
|
31226
31523
|
deltaDeploys: dDeploys,
|
|
31227
31524
|
deltaLead: dLead,
|
|
31228
|
-
|
|
31525
|
+
deltaFailureRate: dRate,
|
|
31526
|
+
deltaRecover: dRecover,
|
|
31527
|
+
off: dDeploys === null || over(dDeploys) || over(dLead) || over(dRate) || over(dRecover) || compared && !s.failed !== !sledsFailed
|
|
31229
31528
|
});
|
|
31230
31529
|
}
|
|
31231
31530
|
const flagOnly = new Map;
|
|
@@ -31295,6 +31594,65 @@ async function reconcileSleuth(o) {
|
|
|
31295
31594
|
}
|
|
31296
31595
|
var hours = (s) => s === null || s === undefined ? "—" : `${(s / 3600).toFixed(1)}h`;
|
|
31297
31596
|
var pct = (d, sledsHas) => d === null ? sledsHas ? "new" : "—" : `${d >= 0 ? "+" : ""}${Math.round(d * 100)}%`;
|
|
31597
|
+
var rate = (x) => x === null ? "—" : `${(x * 100).toFixed(1)}%`;
|
|
31598
|
+
function columns(head, body) {
|
|
31599
|
+
const widths = head.map((h, i) => Math.max(h.length, ...body.map((row) => row[i].length)));
|
|
31600
|
+
const fmt = (row) => ` ${row.map((c, i) => i < 2 ? c.padEnd(widths[i]) : c.padStart(widths[i])).join(" ")}`.trimEnd();
|
|
31601
|
+
return [fmt(head), ...body.map(fmt)];
|
|
31602
|
+
}
|
|
31603
|
+
function stabilityTable(r) {
|
|
31604
|
+
if (!r.rows.length)
|
|
31605
|
+
return [];
|
|
31606
|
+
if (r.rows.every((x) => x.sleuth.failed === null))
|
|
31607
|
+
return [
|
|
31608
|
+
"",
|
|
31609
|
+
" Change failure rate and time to recover not compared: Sleuth's series has no metricFailureRate or metricMttr — export them again with export_metrics.sh."
|
|
31610
|
+
];
|
|
31611
|
+
if (r.rows.every((x) => x.sleds.failed === null))
|
|
31612
|
+
return [
|
|
31613
|
+
"",
|
|
31614
|
+
" Change failure rate and time to recover not compared: SLEDS did not answer with them — its deploy is older than SL-2202."
|
|
31615
|
+
];
|
|
31616
|
+
const failing = r.rows.filter((x) => (x.sleuth.failed ?? 0) > 0 || (x.sleds.failed ?? 0) > 0);
|
|
31617
|
+
const out = [
|
|
31618
|
+
"",
|
|
31619
|
+
"Change failure rate (failed ÷ deploys) and time to recover in wall-clock hours, the months with a failure on either side. Sleuth's time to recover is how long a failed change stayed failed; SLEDS's runs from a failed deploy to the next deploy to its target that held — mean beside mean, SLEDS's median after",
|
|
31620
|
+
""
|
|
31621
|
+
];
|
|
31622
|
+
if (!failing.length)
|
|
31623
|
+
return [...out, " (no failure on either side)"];
|
|
31624
|
+
const n = (x) => x === null ? "—" : String(x);
|
|
31625
|
+
return [
|
|
31626
|
+
...out,
|
|
31627
|
+
...columns([
|
|
31628
|
+
"project",
|
|
31629
|
+
"month",
|
|
31630
|
+
"Sleuth failed",
|
|
31631
|
+
"SLEDS failed",
|
|
31632
|
+
"Sleuth rate",
|
|
31633
|
+
"SLEDS rate",
|
|
31634
|
+
"Δ",
|
|
31635
|
+
"Sleuth recover",
|
|
31636
|
+
"SLEDS recover",
|
|
31637
|
+
"Δ",
|
|
31638
|
+
"median",
|
|
31639
|
+
""
|
|
31640
|
+
], failing.map((x) => [
|
|
31641
|
+
x.project,
|
|
31642
|
+
x.month,
|
|
31643
|
+
n(x.sleuth.failed),
|
|
31644
|
+
n(x.sleds.failed),
|
|
31645
|
+
rate(x.sleuth.failureRate),
|
|
31646
|
+
rate(x.sleds.failureRate),
|
|
31647
|
+
pct(x.deltaFailureRate, (x.sleds.failed ?? 0) > 0),
|
|
31648
|
+
hours(x.sleuth.mttr),
|
|
31649
|
+
hours(x.sleds.recover?.mean),
|
|
31650
|
+
pct(x.deltaRecover, false),
|
|
31651
|
+
hours(x.sleds.recover?.median),
|
|
31652
|
+
x.off ? "!" : ""
|
|
31653
|
+
]))
|
|
31654
|
+
];
|
|
31655
|
+
}
|
|
31298
31656
|
function reconcileTable(r) {
|
|
31299
31657
|
const head = [
|
|
31300
31658
|
"project",
|
|
@@ -31324,16 +31682,14 @@ function reconcileTable(r) {
|
|
|
31324
31682
|
x.sleds.missing ? `${x.sleds.missing} of ${x.sleds.prs}` : "",
|
|
31325
31683
|
x.off ? "!" : ""
|
|
31326
31684
|
]);
|
|
31327
|
-
const widths = head.map((h, i) => Math.max(h.length, ...body.map((row) => row[i].length)));
|
|
31328
|
-
const fmt = (row) => ` ${row.map((c, i) => i < 2 ? c.padEnd(widths[i]) : c.padStart(widths[i])).join(" ")}`.trimEnd();
|
|
31329
31685
|
const out = [
|
|
31330
31686
|
`Sleuth beside SLEDS for ${r.org}, ${r.since} to ${r.until} — deploys a month; lead time in working hours (Mon–Fri 14:00–23:00 UTC), a mean over deploys as Sleuth counts it`,
|
|
31331
31687
|
"",
|
|
31332
|
-
|
|
31333
|
-
...body.map(fmt)
|
|
31688
|
+
...columns(head, body)
|
|
31334
31689
|
];
|
|
31335
31690
|
if (!r.rows.length)
|
|
31336
31691
|
out.push(" (no month with deploys on either side)");
|
|
31692
|
+
out.push(...stabilityTable(r));
|
|
31337
31693
|
if (r.skipped.length) {
|
|
31338
31694
|
out.push("", " not compared:");
|
|
31339
31695
|
for (const s of r.skipped)
|
|
@@ -31729,8 +32085,8 @@ var reconcileCmd = async (o, { words, flags, all }) => {
|
|
|
31729
32085
|
|
|
31730
32086
|
// src/commands/specEvent.ts
|
|
31731
32087
|
init_meter();
|
|
31732
|
-
import { readFileSync as
|
|
31733
|
-
import { basename as
|
|
32088
|
+
import { readFileSync as readFileSync37, statSync as statSync11 } from "node:fs";
|
|
32089
|
+
import { basename as basename13, isAbsolute as isAbsolute7, relative as relative2 } from "node:path";
|
|
31734
32090
|
var HOOK_STDIN_TIMEOUT_MS3 = 1000;
|
|
31735
32091
|
var ESTIMATE_TIMEOUT_MS = 4000;
|
|
31736
32092
|
var MIN_SPEC_CHARS = 200;
|
|
@@ -31743,12 +32099,12 @@ function isSpecPath(path) {
|
|
|
31743
32099
|
return false;
|
|
31744
32100
|
if (NOT_SPEC.test(path))
|
|
31745
32101
|
return false;
|
|
31746
|
-
return SPEC_DIRS.test(path) || SPEC_NAMES.test(
|
|
32102
|
+
return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename13(path));
|
|
31747
32103
|
}
|
|
31748
32104
|
function specTitle(body, path) {
|
|
31749
32105
|
const m = /^#\s+(.+?)\s*$/m.exec(body);
|
|
31750
32106
|
const t = m?.[1]?.trim();
|
|
31751
|
-
return (t && t.length > 0 ? t :
|
|
32107
|
+
return (t && t.length > 0 ? t : basename13(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
|
|
31752
32108
|
}
|
|
31753
32109
|
function looksLikeSpec(body) {
|
|
31754
32110
|
if (body.trim().length < MIN_SPEC_CHARS)
|
|
@@ -31783,9 +32139,9 @@ function projectKey(filePath, cwd) {
|
|
|
31783
32139
|
}
|
|
31784
32140
|
function readFileOrNull(path) {
|
|
31785
32141
|
try {
|
|
31786
|
-
if (
|
|
32142
|
+
if (statSync11(path).size > 2000000)
|
|
31787
32143
|
return null;
|
|
31788
|
-
return
|
|
32144
|
+
return readFileSync37(path, "utf8");
|
|
31789
32145
|
} catch {
|
|
31790
32146
|
return null;
|
|
31791
32147
|
}
|
|
@@ -31811,7 +32167,7 @@ var specEvent = async (o) => {
|
|
|
31811
32167
|
const spec = {
|
|
31812
32168
|
title: specTitle(body, input.filePath),
|
|
31813
32169
|
body: body.slice(0, MAX_SPEC_CHARS),
|
|
31814
|
-
repoHint: input.cwd ?
|
|
32170
|
+
repoHint: input.cwd ? basename13(input.cwd) : undefined
|
|
31815
32171
|
};
|
|
31816
32172
|
try {
|
|
31817
32173
|
const res = await (o.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
|
|
@@ -32130,7 +32486,7 @@ var announce = (o, events) => {
|
|
|
32130
32486
|
|
|
32131
32487
|
// src/commands/stopEvent.ts
|
|
32132
32488
|
init_meter();
|
|
32133
|
-
import { existsSync as existsSync34, readFileSync as
|
|
32489
|
+
import { existsSync as existsSync34, readFileSync as readFileSync38 } from "node:fs";
|
|
32134
32490
|
|
|
32135
32491
|
// src/transcript.ts
|
|
32136
32492
|
var isObject16 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -32231,7 +32587,7 @@ async function postTranscript(o, payload, now) {
|
|
|
32231
32587
|
}
|
|
32232
32588
|
if (!src)
|
|
32233
32589
|
return false;
|
|
32234
|
-
const read = o.readFile ?? ((p) => existsSync34(p) ?
|
|
32590
|
+
const read = o.readFile ?? ((p) => existsSync34(p) ? readFileSync38(p, "utf8") : null);
|
|
32235
32591
|
let text;
|
|
32236
32592
|
try {
|
|
32237
32593
|
text = read(path);
|
|
@@ -32309,7 +32665,7 @@ var stopEvent = async (o) => {
|
|
|
32309
32665
|
|
|
32310
32666
|
// src/commands/uninstall.ts
|
|
32311
32667
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
32312
|
-
import { existsSync as existsSync35, readFileSync as
|
|
32668
|
+
import { existsSync as existsSync35, readFileSync as readFileSync39, rmSync as rmSync23 } from "node:fs";
|
|
32313
32669
|
init_config();
|
|
32314
32670
|
init_meter();
|
|
32315
32671
|
init_settings();
|
|
@@ -32326,7 +32682,7 @@ var planUninstall = (o) => {
|
|
|
32326
32682
|
const changes = [];
|
|
32327
32683
|
const remove = [];
|
|
32328
32684
|
const codexPath = codexConfigPath(o.home);
|
|
32329
|
-
const codex = user && existsSync35(codexPath) && removeCodexProvider(
|
|
32685
|
+
const codex = user && existsSync35(codexPath) && removeCodexProvider(readFileSync39(codexPath, "utf8")) !== readFileSync39(codexPath, "utf8");
|
|
32330
32686
|
if (codex)
|
|
32331
32687
|
changes.push({ path: codexPath, what: 'removes the "sleds" provider' });
|
|
32332
32688
|
const priorStatusLine = user ? cfg.priorStatusLine : rec?.priorStatusLine;
|
|
@@ -32463,7 +32819,7 @@ var uninstall2 = async (o) => {
|
|
|
32463
32819
|
init_server();
|
|
32464
32820
|
import { existsSync as existsSync36 } from "node:fs";
|
|
32465
32821
|
import { homedir as homedir9, userInfo as userInfo4 } from "node:os";
|
|
32466
|
-
import { basename as
|
|
32822
|
+
import { basename as basename14 } from "node:path";
|
|
32467
32823
|
init_config();
|
|
32468
32824
|
init_state();
|
|
32469
32825
|
init_meter();
|
|
@@ -32528,7 +32884,7 @@ var realPidAlive4 = (pid) => {
|
|
|
32528
32884
|
};
|
|
32529
32885
|
function machineClient(home, env) {
|
|
32530
32886
|
const src = meterSource(home, undefined, { env });
|
|
32531
|
-
return src ? fetchClient({ ...src, version: "0.1.
|
|
32887
|
+
return src ? fetchClient({ ...src, version: "0.1.73" }) : null;
|
|
32532
32888
|
}
|
|
32533
32889
|
async function noteAnswer2(home, a, now) {
|
|
32534
32890
|
try {
|
|
@@ -32540,7 +32896,7 @@ async function noteAnswer2(home, a, now) {
|
|
|
32540
32896
|
}
|
|
32541
32897
|
function busyEngines(files) {
|
|
32542
32898
|
return files.map((f) => ({
|
|
32543
|
-
name:
|
|
32899
|
+
name: basename14(f, ".json"),
|
|
32544
32900
|
running: readState(f).runs.filter(isRunning).length
|
|
32545
32901
|
})).filter((e) => e.running > 0);
|
|
32546
32902
|
}
|
|
@@ -32722,8 +33078,8 @@ async function maybeNotice(cmd, argv, o) {
|
|
|
32722
33078
|
|
|
32723
33079
|
// src/commands/verify.ts
|
|
32724
33080
|
init_meter();
|
|
32725
|
-
import { readFileSync as
|
|
32726
|
-
import { basename as
|
|
33081
|
+
import { readFileSync as readFileSync40, statSync as statSync12 } from "node:fs";
|
|
33082
|
+
import { basename as basename15, extname as extname2 } from "node:path";
|
|
32727
33083
|
var jobIdFromTarget = (target) => {
|
|
32728
33084
|
const t = target.trim();
|
|
32729
33085
|
const m = /SLEDS-Attest:.*\bjob=([^\s]+)/.exec(t);
|
|
@@ -32848,17 +33204,17 @@ async function verdictCmd2(o) {
|
|
|
32848
33204
|
let screenshot;
|
|
32849
33205
|
if (a.file) {
|
|
32850
33206
|
try {
|
|
32851
|
-
if (!o.readFile &&
|
|
33207
|
+
if (!o.readFile && statSync12(a.file).size > SHOT_MAX_BYTES2) {
|
|
32852
33208
|
error(`${a.file}: a screenshot is at most 4 MB`);
|
|
32853
33209
|
return 1;
|
|
32854
33210
|
}
|
|
32855
|
-
const bytes = (o.readFile ??
|
|
33211
|
+
const bytes = (o.readFile ?? readFileSync40)(a.file);
|
|
32856
33212
|
if (bytes.byteLength > SHOT_MAX_BYTES2) {
|
|
32857
33213
|
error(`${a.file}: a screenshot is at most 4 MB`);
|
|
32858
33214
|
return 1;
|
|
32859
33215
|
}
|
|
32860
33216
|
screenshot = {
|
|
32861
|
-
name:
|
|
33217
|
+
name: basename15(a.file),
|
|
32862
33218
|
mime: shotMime2(a.file),
|
|
32863
33219
|
content: bytes.toString("base64")
|
|
32864
33220
|
};
|
|
@@ -32982,7 +33338,7 @@ var webhooksCmd = async (o) => {
|
|
|
32982
33338
|
|
|
32983
33339
|
// src/config.ts
|
|
32984
33340
|
init_settings();
|
|
32985
|
-
import { chmodSync as chmodSync8, existsSync as existsSync37, mkdirSync as mkdirSync29, readFileSync as
|
|
33341
|
+
import { chmodSync as chmodSync8, existsSync as existsSync37, mkdirSync as mkdirSync29, readFileSync as readFileSync41, renameSync as renameSync14, writeFileSync as writeFileSync29 } from "node:fs";
|
|
32986
33342
|
import { join as join38, resolve as resolve13 } from "node:path";
|
|
32987
33343
|
var configDir2 = (home, env = process.env) => {
|
|
32988
33344
|
const o = env.SLEDS_HOME?.trim();
|
|
@@ -33153,17 +33509,17 @@ var readConfig2 = (home, env = process.env) => {
|
|
|
33153
33509
|
const p = configPath2(home, env);
|
|
33154
33510
|
if (!existsSync37(p))
|
|
33155
33511
|
return {};
|
|
33156
|
-
return parseConfig2(JSON.parse(
|
|
33512
|
+
return parseConfig2(JSON.parse(readFileSync41(p, "utf8")));
|
|
33157
33513
|
};
|
|
33158
33514
|
|
|
33159
33515
|
// src/musher.ts
|
|
33160
|
-
import { basename as
|
|
33516
|
+
import { basename as basename16, dirname as dirname27, join as join39 } from "node:path";
|
|
33161
33517
|
var MUSHER_LABEL2 = "ai.sleds.musher";
|
|
33162
33518
|
var musherLabel2 = (env = process.env) => {
|
|
33163
33519
|
const sh = env.SLEDS_HOME?.trim();
|
|
33164
33520
|
if (!sh)
|
|
33165
33521
|
return MUSHER_LABEL2;
|
|
33166
|
-
const tag =
|
|
33522
|
+
const tag = basename16(sh).replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]+/g, "-") || "seat";
|
|
33167
33523
|
return `${MUSHER_LABEL2}.${tag}`;
|
|
33168
33524
|
};
|
|
33169
33525
|
var musherPlistPath2 = (home, env = process.env) => join39(home, "Library", "LaunchAgents", `${musherLabel2(env)}.plist`);
|
|
@@ -33249,7 +33605,7 @@ var defaultExec5 = (cmd, args) => {
|
|
|
33249
33605
|
};
|
|
33250
33606
|
|
|
33251
33607
|
// src/settings.ts
|
|
33252
|
-
import { basename as
|
|
33608
|
+
import { basename as basename17, dirname as dirname28, join as join41, resolve as resolve14 } from "node:path";
|
|
33253
33609
|
var withSeatEnv2 = (command, home, env = process.env, org) => {
|
|
33254
33610
|
const parts = [];
|
|
33255
33611
|
const sh = env.SLEDS_HOME?.trim();
|
|
@@ -33465,6 +33821,12 @@ commands:
|
|
|
33465
33821
|
--json SLEDS's answer as it came
|
|
33466
33822
|
defect <key> "<what is wrong>" The same as verify fail <key> "\u2026" --defect
|
|
33467
33823
|
(--same-engineer, --file, --json).
|
|
33824
|
+
attach <key> --file <path> Put a file from disk on the item (4 MB at most) and print its link \u2014
|
|
33825
|
+
a preview screenshot for the PR's look, a spec, a prototype.
|
|
33826
|
+
--kind <k> screenshot \xB7 prototype \xB7 spec \xB7 doc \xB7 other (read from the
|
|
33827
|
+
name when absent)
|
|
33828
|
+
--mock mark it as the item's mock
|
|
33829
|
+
--json SLEDS's answer as it came
|
|
33468
33830
|
off Switch Claude Code back to your seat. Restores whatever \`on\` replaced.
|
|
33469
33831
|
uninstall The same as \`sleds init --undo\`: lists what SLEDS put in your user settings and
|
|
33470
33832
|
asks first (--yes skips), then takes it out. Keeps ~/.sleds-token.
|
|
@@ -33621,7 +33983,7 @@ var main = async (argv) => {
|
|
|
33621
33983
|
now: Date.now(),
|
|
33622
33984
|
stderr: (line) => console.error(line),
|
|
33623
33985
|
isTTY: !!process.stderr.isTTY,
|
|
33624
|
-
version: "0.1.
|
|
33986
|
+
version: "0.1.73"
|
|
33625
33987
|
});
|
|
33626
33988
|
switch (cmd) {
|
|
33627
33989
|
case "update":
|
|
@@ -33852,6 +34214,8 @@ var main = async (argv) => {
|
|
|
33852
34214
|
return verify2({ home, target: process.argv.slice(3).join(" ") || undefined });
|
|
33853
34215
|
case "defect":
|
|
33854
34216
|
return defectCmd({ home, argv: argv.slice(1) });
|
|
34217
|
+
case "attach":
|
|
34218
|
+
return attachCmd({ home, argv: argv.slice(1) });
|
|
33855
34219
|
case "uninstall":
|
|
33856
34220
|
return uninstall2({
|
|
33857
34221
|
home,
|
|
@@ -33889,7 +34253,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
33889
34253
|
case "version":
|
|
33890
34254
|
case "--version":
|
|
33891
34255
|
case "-v":
|
|
33892
|
-
console.log("sleds 0.1.
|
|
34256
|
+
console.log("sleds 0.1.73");
|
|
33893
34257
|
return 0;
|
|
33894
34258
|
default:
|
|
33895
34259
|
console.error(`unknown command: ${cmd}
|