@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.
Files changed (2) hide show
  1. package/dist/sleds.mjs +1312 -948
  2. 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 ? "- This node has a visual surface: the look happens on the PR, not in chat. Open it as a draft (`gh pr create --draft`) and put the mock in its body — a screenshot built from the real design tokens and data, or the artifact link. A person looks there and marks it ready." : "- If the change turns out to have a visual surface, 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."
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 isObject9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), str7 = (v) => typeof v === "string" ? v : undefined, num5 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
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 (!isObject9(v))
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 (!isObject9(v) || v.reason !== "machine busy")
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 existsSync7,
9168
+ existsSync as existsSync6,
9161
9169
  linkSync,
9162
- mkdirSync as mkdirSync7,
9163
- readFileSync as readFileSync7,
9164
- renameSync as renameSync4,
9170
+ mkdirSync as mkdirSync6,
9171
+ readFileSync as readFileSync6,
9172
+ renameSync as renameSync3,
9165
9173
  rmSync,
9166
- writeFileSync as writeFileSync7
9174
+ writeFileSync as writeFileSync6
9167
9175
  } from "node:fs";
9168
- import { dirname as dirname6, join as join9 } from "node:path";
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 ? join9(stateDir, "orgs", slugify(org, 80) || "org") : stateDir;
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 (!existsSync7(from) || existsSync7(to))
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
- mkdirSync7(dirname6(to), { recursive: true, mode: 448 });
9184
- renameSync4(from, to);
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 ? join9(orgDir, "seats", slug) : orgDir;
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 (!existsSync7(from) || existsSync7(to))
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
- mkdirSync7(dirname6(to), { recursive: true, mode: 448 });
9203
- renameSync4(from, to);
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 join9(stateDir, `${engineSlug(engine)}.json`);
9215
+ return join7(stateDir, `${engineSlug(engine)}.json`);
9208
9216
  }
9209
9217
  function lockPath(stateDir, engine) {
9210
- return join9(stateDir, `${engineSlug(engine)}.lock`);
9218
+ return join7(stateDir, `${engineSlug(engine)}.lock`);
9211
9219
  }
9212
9220
  function parseHandle(handle) {
9213
- if (!isObject9(handle))
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
- ...isObject9(handle.own) && typeof handle.own.branch === "string" && typeof handle.own.head === "string" ? { own: { branch: handle.own.branch, head: handle.own.head } } : {}
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 (!isObject9(v) || typeof v.node !== "string" || typeof v.pr !== "string")
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(isObject9).flatMap((n) => typeof n.key === "string" ? [
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 (!isObject9(v))
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 (!isObject9(v))
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 = isObject9(v.answerer) ? v.answerer : null;
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 (!isObject9(v) || typeof v.base !== "string" || typeof v.since !== "number")
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 (!isObject9(v))
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 (!isObject9(v) || typeof v.question !== "string" || typeof v.at !== "number")
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 (isObject9(a) && (a.ended === "answered" || a.ended === "escalated" || a.ended === "none")) {
9374
+ if (isObject7(a) && (a.ended === "answered" || a.ended === "escalated" || a.ended === "none")) {
9367
9375
  answerer = { ended: a.ended };
9368
- } else if (isObject9(a) && typeof a.decisionId === "string" && typeof a.runId === "string" && typeof a.until === "number") {
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 (!isObject9(v))
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 = isObject9(v.pr) ? parseConflicted(v.pr.conflicted) : undefined;
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
- ...isObject9(v.mock) && typeof v.mock.out === "string" && typeof v.mock.base === "string" ? {
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
- ...isObject9(v.group) && typeof v.group.key === "string" && typeof v.group.title === "string" ? { group: { key: v.group.key, title: v.group.title } } : {},
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
- ...isObject9(v.permission) && typeof v.permission.decisionId === "string" && typeof v.permission.at === "number" ? {
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
- ...isObject9(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 } } : {},
9445
- ...isObject9(v.atPrompt) && typeof v.atPrompt.since === "number" && typeof v.atPrompt.text === "string" ? { atPrompt: { since: v.atPrompt.since, text: v.atPrompt.text } } : {},
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
- ...isObject9(v.pr) && typeof v.pr.url === "string" ? {
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
- ...isObject9(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" ? {
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
- ...isObject9(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 } } : {},
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
- ...isObject9(v.pr.instructed) && Array.isArray(v.pr.instructed.ids) && (v.pr.instructed.how === "told" || v.pr.instructed.how === "restarted") ? {
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 (!isObject9(raw) || !Array.isArray(raw.runs))
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 = isObject9(raw.slowStarts) ? Object.fromEntries(Object.entries(raw.slowStarts).filter((e) => typeof e[1] === "number" && e[1] > 0)) : {};
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 isObject9(raw) && typeof raw.v === "number" ? raw.v : 1;
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(readFileSync7(path, "utf8"));
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 = readFileSync7(path, "utf8");
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
- mkdirSync7(dirname6(path), { recursive: true, mode: 448 });
9545
+ mkdirSync6(dirname5(path), { recursive: true, mode: 448 });
9537
9546
  const tmp = `${path}.${process.pid}.tmp`;
9538
- writeFileSync7(tmp, `${JSON.stringify({ v: STATE_VERSION, ...state }, null, 2)}
9547
+ writeFileSync6(tmp, `${JSON.stringify({ v: STATE_VERSION, ...state }, null, 2)}
9539
9548
  `, {
9540
9549
  mode: 384
9541
9550
  });
9542
- renameSync4(tmp, path);
9551
+ renameSync3(tmp, path);
9543
9552
  }
9544
9553
  function parseLock(text) {
9545
9554
  try {
9546
9555
  const v = JSON.parse(text);
9547
- if (!isObject9(v))
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 = isObject9(rh) && typeof rh.why === "string" && rh.why && typeof rh.since === "number" ? { why: rh.why, since: rh.since } : undefined;
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(readFileSync7(path, "utf8"));
9591
+ return parseLock(readFileSync6(path, "utf8"));
9583
9592
  } catch {
9584
9593
  return null;
9585
9594
  }
9586
9595
  }
9587
9596
  function writeLock(path, lock) {
9588
- mkdirSync7(dirname6(path), { recursive: true, mode: 448 });
9597
+ mkdirSync6(dirname5(path), { recursive: true, mode: 448 });
9589
9598
  const tmp = `${path}.${process.pid}.tmp`;
9590
- writeFileSync7(tmp, `${JSON.stringify(lock, null, 2)}
9599
+ writeFileSync6(tmp, `${JSON.stringify(lock, null, 2)}
9591
9600
  `, { mode: 384 });
9592
- renameSync4(tmp, path);
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
- mkdirSync7(dirname6(path), { recursive: true, mode: 448 });
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
- writeFileSync7(tmp, `${JSON.stringify(lock, null, 2)}
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
- renameSync4(path, aside);
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 join9(seatDir, "removed-engines.json");
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 = isObject9(raw) && Array.isArray(raw.engines) ? raw.engines : [];
9657
+ const list = isObject7(raw) && Array.isArray(raw.engines) ? raw.engines : [];
9649
9658
  const out = [];
9650
9659
  for (const e of list) {
9651
- if (!isObject9(e) || typeof e.name !== "string" || !e.name)
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(readFileSync7(removedEnginesPath(seatDir), "utf8"));
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
- mkdirSync7(seatDir, { recursive: true, mode: 448 });
9678
- writeFileSync7(path, `${JSON.stringify({ v: 1, engines }, null, 2)}
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/verify.ts
10070
- init_meter();
10160
+ // src/commands/attach.ts
10161
+ init_server();
10071
10162
  import { readFileSync as readFileSync16, statSync as statSync7 } from "node:fs";
10072
- import { basename as basename7, extname } from "node:path";
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
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 dirname15, isAbsolute as isAbsolute3, join as join24, resolve as resolve8 } from "node:path";
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.71" ?? "dev",
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 join8 } from "node:path";
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 join8(env.CLAUDE_CONFIG_DIR?.trim() || join8(home, ".claude"), ".credentials.json");
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 (isObject9(v))
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(isObject9);
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 = isObject9(r.states) ? r.states : {};
10574
- const runs = (Array.isArray(r.runs) ? r.runs : []).filter(isObject9);
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(isObject9).filter((b) => b.landed !== true).map((b) => String(b.key));
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 (!isObject9(fields) || !isObject9(fields.status))
10909
+ if (!isObject7(fields) || !isObject7(fields.status))
11146
10910
  return "new";
11147
10911
  const cat = fields.status.statusCategory;
11148
- return isObject9(cat) && str7(cat.key) || "new";
10912
+ return isObject7(cat) && str7(cat.key) || "new";
11149
10913
  };
11150
10914
  function jiraNode(issue) {
11151
- const fields = isObject9(issue.fields) ? issue.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(isObject9) : [];
11155
- const blockers = links.filter((l) => isObject9(l.type) && l.type.name === "Blocks" && isObject9(l.inwardIssue)).map((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 (!isObject9(n))
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: isObject9(json) ? json : null };
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(isObject9));
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(isObject9) : [];
11322
- const hit = list.find((x) => isObject9(x.to) && categoryOf({ status: x.to }) === category && x.id !== undefined);
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 dirname7, join as join10 } from "node:path";
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 isObject10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
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 (!isObject10(v))
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 (!isObject10(raw))
11240
+ if (!isObject9(raw))
11477
11241
  return null;
11478
- const limits = isObject10(raw.rate_limits) ? raw.rate_limits : raw;
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 (isObject10(limits.models))
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) => join10(configDir(home), SEAT_FILE);
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 join10(seatStateDir(orgStateDir(configDir(home), key.org?.trim()), key.email), SEAT_FILE);
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) => join10(d, e.name));
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(join10(root, "orgs")).flatMap((org) => [
11563
- join10(org, SEAT_FILE),
11564
- ...dirs(join10(org, "seats")).map((seat) => join10(seat, SEAT_FILE))
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(join10(root, "seats")).map((seat) => join10(seat, SEAT_FILE));
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(dirname7(target), { recursive: true, mode: 448 });
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 (!isObject10(v))
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 (!isObject10(raw))
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 (isObject10(raw.lastPosted)) {
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 (isObject10(raw.warned)) {
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 (!isObject10(w))
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 (isObject10(raw.told)) {
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 (!isObject10(w))
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 (isObject10(raw.transcriptScan) && typeof raw.transcriptScan.path === "string") {
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 (isObject10(raw.cockpit) && raw.cockpit.kind === "cmux") {
11422
+ if (isObject9(raw.cockpit) && raw.cockpit.kind === "cmux") {
11659
11423
  const c = { kind: "cmux" };
11660
- if (isObject10(raw.cockpit.lines)) {
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 (isObject10(f) && num6(f.at) !== undefined) {
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 = isObject10(f.jobs) ? f.jobs : {};
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 (isObject10(raw.estimate)) {
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 (!isObject10(v) || typeof v.id !== "string" || !v.id)
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 (!isObject10(raw) || typeof raw.session_id !== "string" || !raw.session_id)
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 = isObject10(raw.model) ? raw.model.id : raw.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(dirname7(target), { recursive: true, mode: 448 });
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) => isObject10(b) && b.type === "text" && typeof b.text === "string" ? b.text : "").join(`
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 (!isObject10(raw))
11607
+ if (!isObject9(raw))
11844
11608
  return false;
11845
- const message = isObject10(raw.message) ? raw.message : undefined;
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 isObject10(raw) && typeof raw.transcript_path === "string" && raw.transcript_path ? raw.transcript_path : null;
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 isObject11 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
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 (!isObject11(raw))
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 isObject12 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
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 (!isObject12(raw) || typeof raw.at !== "number")
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 spawnSync3 } from "node:child_process";
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 basename3, dirname as dirname8, join as join11 } from "node:path";
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 = spawnSync3(cmd, [...args], {
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 = basename3(promptFile).replace(/\.md$/i, "");
12160
- return join11(dir ?? dirname8(promptFile), `${base}.${ext}`);
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 (!isObject9(d) || d.state !== "answered" || !isObject9(d.answer))
11975
+ if (!isObject7(d) || d.state !== "answered" || !isObject7(d.answer))
12212
11976
  return null;
12213
- const q = isObject9(d.question) ? str7(d.question.md) : undefined;
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 = isObject9(row.mockRun) ? row.mockRun : {};
12348
- return { asked: isObject9(m.asked), running: isObject9(m.running) };
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(isObject9) : [];
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 = num5(b.lowMin);
12359
- const hi = num5(b.highMin);
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(isObject9).flatMap((w) => {
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 = isObject9(w.finding) ? w.finding : null;
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 (!isObject9(armed))
12166
+ if (!isObject7(armed))
12395
12167
  return { seatIds: [] };
12396
- const atOnce = num5(armed.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) => num5(x) ?? 1) : undefined;
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(isObject9) : [];
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 = isObject9(r.states) ? r.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(isObject9) : [];
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 = num5(x.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 = isObject9(j.parent) ? j.parent : null;
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(isObject9).flatMap((x) => {
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 (!isObject9(armed))
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(isObject9) : [];
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 (!isObject9(route))
12288
+ if (!isObject7(route))
12517
12289
  continue;
12518
12290
  if (armedOnly && !armedFor(route.armed, engine))
12519
12291
  continue;
12520
- const states = isObject9(route.states) ? route.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 || !isObject9(r.profile))
12326
+ if (!r || r.ok === false || !isObject7(r.profile))
12555
12327
  return null;
12556
12328
  const p = r.profile;
12557
- const member = isObject9(r.member) ? r.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 = num5(p.atOnce);
12352
+ const atOnce = num4(p.atOnce);
12581
12353
  if (atOnce !== undefined && atOnce >= 1)
12582
12354
  out.atOnce = Math.round(atOnce);
12583
- const seatAtOnce = num5(r.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 = num5(p.holdCpu);
12360
+ const holdCpu = num4(p.holdCpu);
12589
12361
  if (holdCpu !== undefined && holdCpu > 0 && holdCpu <= 100)
12590
12362
  out.holdCpu = holdCpu;
12591
- const holdLoad = num5(p.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 = num5(p.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(isObject9) : [];
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 (!isObject9(route) || !armedFor(route.armed, o.engine))
12400
+ if (!isObject7(route) || !armedFor(route.armed, o.engine))
12629
12401
  continue;
12630
- const states = isObject9(route.states) ? route.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 (!isObject9(route) || isObject9(route.armed) || route.draftParked)
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 (isObject9(route.elsewhere))
12418
+ if (isObject7(route.elsewhere))
12647
12419
  continue;
12648
- const states = isObject9(route.states) ? route.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(isObject9) : [];
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 (isObject9(route) && route.drafting === true)
12433
+ if (isObject7(route) && route.drafting === true)
12662
12434
  running++;
12663
12435
  if (mockRunOf(row).running)
12664
12436
  running++;
12665
- if (!isObject9(route) || !isObject9(route.armed))
12437
+ if (!isObject7(route) || !isObject7(route.armed))
12666
12438
  continue;
12667
- running += keysIn(isObject9(route.states) ? route.states : {}, "running").length;
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(isObject9) : [];
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 (!isObject9(route) || !armedFor(route.armed, engine) || route.implicit !== true)
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 (isObject9(route.elsewhere))
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 = isObject9(route.states) ? route.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 isObject9(route) && isObject9(route.redraft) && route.drafting !== true && route.proposed !== true;
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(isObject9) : [];
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(isObject9(states) ? states : {}).map(([k, v]) => `${k} — ${String(v)}`).join(`
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 = isObject9(row.route) ? strings(row.route.needsRoute) : [];
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 ${isObject9(armed) ? str7(armed.engine) : "another engine"}`);
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 = isObject9(row.route) ? row.route : {};
12725
- const states = isObject9(route.states) ? route.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 = isObject9(row.route) && isObject9(row.route.redraft) ? row.route.redraft : null;
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 = (isObject9(brief?.draft) ? str7(brief.draft.pack) : undefined) ?? "";
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 = isObject9(brief?.redraft) ? brief.redraft : {};
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, isObject9(row.route) ? row.route.states : null)
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 = num5(j.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 = isObject9(j.band) ? mockBandText(j.band) : undefined;
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 = num5(j.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(isObject9) : [];
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 (!isObject9(route) || !armedFor(route.armed, o.engine) || !redraftDue(route))
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 = isObject9(row.route) ? row.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(isObject9) : [];
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(isObject9) : [];
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(isObject9) : [];
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 = num5(hit.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 (!isObject9(route))
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 || isObject9(route.proposed) || isObject9(route.elsewhere))
12801
+ if (filed || isObject7(route.proposed) || isObject7(route.elsewhere))
13028
12802
  return "done";
13029
- if (isObject9(route.draftParked))
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(isObject9) : [];
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(isObject9) : [];
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(isObject9) : [];
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" && isObject9(d.answerer) && d.answerer.verdict === "answered")
12892
+ if (d?.state === "answered" && isObject7(d.answerer) && d.answerer.verdict === "answered")
13119
12893
  return "answered";
13120
- if (d?.state === "answered" && isObject9(d.answerer) && d.answerer.verdict === "released")
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(isObject9) : [];
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 = isObject9(d.answer) ? str7(d.answer.md) : undefined;
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(isObject9) : [];
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 dirname9, isAbsolute, join as join12 } from "node:path";
13276
+ import { dirname as dirname8, isAbsolute, join as join11 } from "node:path";
13503
13277
  function worktreePath(repoPath, name) {
13504
- return join12(repoPath, ".worktrees", name);
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(dirname9(p), { recursive: true });
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 = join12(isAbsolute(dir) ? dir : join12(repoPath, dir), "info", "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(join12(path, ".git"))) {
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(join12(path, "pnpm-lock.yaml")))
13420
+ if (exists(join11(path, "pnpm-lock.yaml")))
13647
13421
  return ["pnpm", "install", "--frozen-lockfile"];
13648
- if (exists(join12(path, "bun.lock")) || exists(join12(path, "bun.lockb")))
13422
+ if (exists(join11(path, "bun.lock")) || exists(join11(path, "bun.lockb")))
13649
13423
  return ["bun", "install", "--frozen-lockfile"];
13650
- if (exists(join12(path, "yarn.lock")))
13424
+ if (exists(join11(path, "yarn.lock")))
13651
13425
  return ["yarn", "install", "--frozen-lockfile"];
13652
- if (exists(join12(path, "package-lock.json")))
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(join12(path, "package.json")) || fs.exists(join12(path, "node_modules")))
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(join12(path, ".git")))
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
- return `A draft PR waits for your look: ${url}.${mock ? ` The mock: ${mock}.` : " Its body names no mock; the PR is the place to look."} Looks good marks it ready for review.`;
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 basename4, dirname as dirname10, join as join13 } from "node:path";
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) => basename4(r.trim())).filter(Boolean);
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 = join13(dir, name);
16895
- if (o.exists(join13(p, ".git")))
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) => join13(d, n))).join(" or ");
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) => dirname10(p) === p;
16725
+ var isRoot = (p) => dirname9(p) === p;
16906
16726
  function insideCheckout(dir, exists) {
16907
- for (let d = dir;!isRoot(d); d = dirname10(d)) {
16908
- if (exists(join13(d, ".git")))
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 basename5, dirname as dirname11, join as join14, resolve as resolve6 } from "node:path";
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 (basename5(dirname11(wt)) !== ".worktrees")
16806
+ if (basename4(dirname10(wt)) !== ".worktrees")
16987
16807
  return null;
16988
- const common = join14(dirname11(dirname11(wt)), ".git");
16989
- if (!stat.isFile(join14(wt, ".git")) || !stat.isDir(common))
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: join14(common, "worktrees", basename5(wt)),
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(basename5(cmd)) ? exec(cmd, args, {
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 join15 } from "node:path";
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(join15(dir, "cmux")))
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 join16, resolve as resolve7 } from "node:path";
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 = join16(dir, "orca");
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 join17, win32 } from "node:path";
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") : join17(home, ".sleds", "bin", "sleds");
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 join23 } from "node:path";
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 as createPublicKey2, sign, verify } from "node:crypto";
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 = createPublicKey2({
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 dirname12, join as join18, win32 as win322 } from "node:path";
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") : join18(home, ".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: join18 };
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(dirname12(path), { recursive: true, mode: 448 });
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(dirname12(path), { recursive: true, mode: 448 });
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.71";
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 basename6, delimiter as delimiter2, dirname as dirname13, isAbsolute as isAbsolute2, join as join21, relative } from "node:path";
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 join19 } from "node:path";
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 join19(home, ".config", "sleds", "box.env");
18736
+ return join18(home, ".config", "sleds", "box.env");
18917
18737
  }
18918
18738
  function engineUnitDir(home) {
18919
- return join19(home, ".config", "systemd", "user");
18739
+ return join18(home, ".config", "systemd", "user");
18920
18740
  }
18921
18741
  function engineUnitPath(home, label) {
18922
- return join19(engineUnitDir(home), `${label}.service`);
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 spawnSync4 } from "node:child_process";
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 join20 } from "node:path";
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 = spawnSync4(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
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) => join20(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
18973
- var xmlEscape2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
18792
+ var plistPath = (home) => join19(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
18793
+ var xmlEscape = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
18974
18794
  var buildLaunchdPlist = (sledsArgv, deadline) => {
18975
- const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape2(a)}</string>`).join(`
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(join20(d.home, "Library", "LaunchAgents"), { recursive: true });
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) => join21(sledsRoot(home), "migrate.bak");
19064
- var manifestPath = (home) => join21(migrateBakDir(home), "manifest.json");
19065
- var xmlEscape3 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19066
18886
  var xmlUnescape = (s) => s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/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>${xmlEscape3(link)}</string>${text.slice(to)}`;
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) => join21(dir, 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(join21(home, "Library", "LaunchAgents"), (n) => n.startsWith("ai.sleds.") && n.endsWith(".plist")).map((path) => ({
18990
+ const agents = listDir(join20(home, "Library", "LaunchAgents"), (n) => n.startsWith("ai.sleds.") && n.endsWith(".plist")).map((path) => ({
19171
18991
  path,
19172
- ...basename6(path).startsWith("ai.sleds.revert") ? {} : { reload: "launchd" }
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 = [join21(home, ".claude"), claudeDir(home, env)];
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 = join21(dir, "settings.json");
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) ? join21(migrateBakDir(home), "abs", path) : join21(migrateBakDir(home), 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(dirname13(link), { recursive: true, mode: 448 });
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(basename6(u.path))).join(" ")}`);
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(dirname13(backup), { recursive: true, mode: 448 });
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 = dirname13(link);
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 dirname14, join as join22 } from "node:path";
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), join22(home, ".config", "sleds")])];
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(join22(dir, n));
19245
+ out.push(join21(dir, n));
19426
19246
  for (const sub of ["orgs", "seats"]) {
19427
19247
  let kids;
19428
19248
  try {
19429
- kids = readdirSync3(join22(dir, sub));
19249
+ kids = readdirSync3(join21(dir, sub));
19430
19250
  } catch {
19431
19251
  continue;
19432
19252
  }
19433
19253
  for (const k of kids.sort())
19434
- walk(join22(dir, sub, k));
19254
+ walk(join21(dir, sub, k));
19435
19255
  }
19436
19256
  };
19437
19257
  for (const r of roots)
19438
- walk(join22(r, "engine"));
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(dirname14(bin), { recursive: true, mode: 448 });
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 = dirname14(f);
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(join22(dir, n), { force: true });
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 = dirname14(versionDir(home, s.current, platform));
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 = join23(dir, "fetch.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.71";
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) ? join24(home, d.slice(1)) : d).join(":");
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.71"
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 ? join24(claudeDir, ".claude.json") : join24(o.home, ".claude.json")),
20468
- ...cwd ? [read(join24(cwd, ".mcp.json"))] : []
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 ?? join24(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
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 = join24(stateDir, "hooks");
20322
+ const hooksDir = join23(stateDir, "hooks");
20503
20323
  const pnpmStores = new Map;
20504
- const permissionMark = (name) => join24(hooksDir, `${name}.permission.json`);
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 = join24(stateDir, "sandbox");
20349
+ const dir = join23(stateDir, "sandbox");
20530
20350
  mkdirSync17(dir, { recursive: true, mode: 448 });
20531
- const p = join24(dir, `${name}.json`);
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 = join24(hooksDir, `${name}.json`);
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 = join24(stateDir, "mcp");
20401
+ const dir = join23(stateDir, "mcp");
20582
20402
  mkdirSync17(dir, { recursive: true, mode: 448 });
20583
- const p = join24(dir, `${name}.json`);
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 = join24(stateDir, "prompts");
20419
+ const dir = join23(stateDir, "prompts");
20600
20420
  mkdirSync17(dir, { recursive: true, mode: 448 });
20601
- const p = join24(dir, `${name}.md`);
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 = join24(tmpdir(), "sleds-mocks");
20426
+ const dir = join23(tmpdir(), "sleds-mocks");
20607
20427
  mkdirSync17(dir, { recursive: true, mode: 448 });
20608
- const p = join24(dir, `${name}.html`);
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), join24(home, ".config", "sleds")])],
20472
+ dirs: [...new Set([configDir(home, env), join23(home, ".config", "sleds")])],
20644
20473
  files: [
20645
20474
  ...new Set([
20646
20475
  tokenPath(home, env),
20647
- join24(home, ".sleds-token"),
20476
+ join23(home, ".sleds-token"),
20648
20477
  settingsPath(home, env),
20649
20478
  backupPath(home, env),
20650
- join24(claudeDir(home, env), "settings.local.json")
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(join24(cwd, "pnpm-lock.yaml")))
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) : join24(dirname15(accountHome), 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.71"
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
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
- var PAUSE_WAIT_MS = 90000;
21044
- async function enginePauseCmd(o) {
21045
- const log = o.log ?? console.log;
21046
- const error = o.error ?? console.error;
21047
- const host = o.host ?? hostname();
21048
- const parsed = parsePauseArgs(o.argv, host);
21049
- if ("error" in parsed) {
21050
- error(parsed.error);
21051
- error(ENGINE_PAUSE_USAGE);
21052
- return 2;
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
- const engine = `engine:${parsed.name}`;
21055
- const which = engineOrg(o, parsed.org);
21056
- const org = which.slug && (which.seated || parsed.org) ? which.slug : null;
21057
- const seat = engineSeat(o, org ?? undefined) ?? null;
21058
- const seatDir = engineStateDir(o, org, seat);
21059
- const orgDir = engineStateDir(o, org);
21060
- const has = (d) => realExists(statePath(d, engine)) || realExists(lockPath(d, engine));
21061
- const dir = !has(seatDir) && has(orgDir) ? orgDir : seatDir;
21062
- const alive = o.pidAlive ?? realPidAlive2;
21063
- const sleep = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
21064
- const kill = o.kill ?? ((pid, sig) => void process.kill(pid, sig));
21065
- const lock = readLock(lockPath(dir, engine));
21066
- let stopped = false;
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
- stopped = true;
21078
- }
21079
- const file = statePath(dir, engine);
21080
- const state = readState(file);
21081
- const result = {
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 (parsed.json)
21116
- log(JSON.stringify(result, null, 2));
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 result.errors.length ? 1 : 0;
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 && statSync7(a.file).size > SHOT_MAX_BYTES) {
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 ?? readFileSync16)(a.file);
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: basename7(a.file),
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 readFileSync21,
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 readFileSync17, writeFileSync as writeFileSync16 } from "node:fs";
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(readFileSync17(claudeUserConfigPath2(home, env), "utf8"));
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(readFileSync17(path, "utf8"));
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) ? readFileSync17(path, "utf8") : "";
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 readFileSync18,
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 basename8, dirname as dirname17, isAbsolute as isAbsolute4, join as join26 } from "node:path";
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(readFileSync18(path, "utf8"), name);
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: basename8(file, ".service"), ...parsed };
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 = basename8(unit);
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", basename8(other.plist));
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", basename8(file)]);
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: ${basename8(file, unit ? ".service" : ".plist")} — its sessions keep running`);
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 readFileSync19, rmSync as rmSync12, writeFileSync as writeFileSync18 } from "node:fs";
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 = readFileSync19(plist, "utf8");
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 readFileSync20 } from "node:fs";
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(readFileSync20(claudeUserConfigPath2(home, env), "utf8")));
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 = readFileSync21(file, "utf8");
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 readFileSync22,
23265
+ readFileSync as readFileSync23,
23001
23266
  existsSync as realExists2,
23002
23267
  rmSync as rmSync14,
23003
- statSync as statSync8,
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.71"
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(readFileSync22(p, "utf8"));
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 = readFileSync22(file, "utf8");
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 readFileSync22(p, "utf8");
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 statSync8(path).mode & 4095;
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.71"
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 readFileSync23,
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 basename9, dirname as dirname20, isAbsolute as isAbsolute6, join as join29 } from "node:path";
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(readFileSync23(path, "utf8"), name);
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: basename9(file, ".service"), ...parsed };
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 = basename9(unit);
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", basename9(other.plist));
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", basename9(file)]);
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: ${basename9(file, unit ? ".service" : ".plist")} — its sessions keep running`);
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 readFileSync24 } from "node:fs";
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 readFileSync25 } from "node:fs";
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 ?? (() => readFileSync25(0, "utf8")))());
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 readFileSync26 } from "node:fs";
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 readFileSync26(path, "utf8");
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 readFileSync27, renameSync as renameSync11, writeFileSync as writeFileSync22 } from "node:fs";
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(readFileSync27(p, "utf8"));
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.71"
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 readFileSync28, rmSync as rmSync16 } from "node:fs";
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 basename10 } from "node:path";
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", basename10(e.plist)]);
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) && readFileSync28(tp, "utf8").trim() === seat.token)
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 readFileSync29, rmSync as rmSync17, writeFileSync as writeFileSync24 } from "node:fs";
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 readFileSync30, renameSync as renameSync12, rmSync as rmSync19, writeFileSync as writeFileSync26 } from "node:fs";
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 readFileSync31 } from "node:fs";
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 ?? (() => readFileSync31(0, "utf8")))() : words.slice(1).join(" ")).trim();
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 ?? (() => readFileSync31(0, "utf8")))() : words.slice(1).join(" ");
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 ?? (() => readFileSync31(0, "utf8")))().trim() : undefined;
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 ?? (() => readFileSync31(0, "utf8")))() : rest.join(" ")).trim();
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) => readFileSync31(p, "utf8")))(a.file) : (o.stdin ?? (() => readFileSync31(0, "utf8")))();
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 readFileSync32, readdirSync as readdirSync7, rmSync as rmSync21, writeFileSync as writeFileSync27 } from "node:fs";
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) ? readFileSync32(localStatePath, "utf8") : null;
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 readFileSync32(seatTokenPath(home, source), "utf8").trim() || undefined;
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 readFileSync33, renameSync as renameSync13, writeFileSync as writeFileSync28 } from "node:fs";
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) => readFileSync33(path, "utf8").split(`
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 readFileSync34, readdirSync as readdirSync8, rmSync as rmSync22, statSync as statSync9 } from "node:fs";
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 basename11, join as join35 } from "node:path";
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 statSync9(p).isDirectory();
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 (basename11(dir) === "changes")
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 = readFileSync34(file, "utf8").split(`
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 = statSync9(path);
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 readFileSync35, readdirSync as readdirSync9 } from "node:fs";
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.reduce((a, b) => a + b, 0));
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).reduce((a, b) => a + b, 0),
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(readFileSync35(join36(root, project, name), "utf8"));
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, o?.deploys ?? 0);
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: { deploys: s.deploys, lead: s.lead },
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: o?.deploys ?? 0,
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
- off: dDeploys === null || Math.abs(dDeploys) > OFF || dLead !== null && Math.abs(dLead) > OFF
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
- fmt(head),
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 readFileSync36, statSync as statSync10 } from "node:fs";
31733
- import { basename as basename12, isAbsolute as isAbsolute7, relative as relative2 } from "node:path";
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(basename12(path));
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 : basename12(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
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 (statSync10(path).size > 2000000)
32142
+ if (statSync11(path).size > 2000000)
31787
32143
  return null;
31788
- return readFileSync36(path, "utf8");
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 ? basename12(input.cwd) : undefined
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 readFileSync37 } from "node:fs";
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) ? readFileSync37(p, "utf8") : null);
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 readFileSync38, rmSync as rmSync23 } from "node:fs";
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(readFileSync38(codexPath, "utf8")) !== readFileSync38(codexPath, "utf8");
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 basename13 } from "node:path";
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.71" }) : null;
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: basename13(f, ".json"),
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 readFileSync39, statSync as statSync11 } from "node:fs";
32726
- import { basename as basename14, extname as extname2 } from "node:path";
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 && statSync11(a.file).size > SHOT_MAX_BYTES2) {
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 ?? readFileSync39)(a.file);
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: basename14(a.file),
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 readFileSync40, renameSync as renameSync14, writeFileSync as writeFileSync29 } from "node:fs";
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(readFileSync40(p, "utf8")));
33512
+ return parseConfig2(JSON.parse(readFileSync41(p, "utf8")));
33157
33513
  };
33158
33514
 
33159
33515
  // src/musher.ts
33160
- import { basename as basename15, dirname as dirname27, join as join39 } from "node:path";
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 = basename15(sh).replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]+/g, "-") || "seat";
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 basename16, dirname as dirname28, join as join41, resolve as resolve14 } from "node:path";
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.71"
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.71");
34256
+ console.log("sleds 0.1.73");
33893
34257
  return 0;
33894
34258
  default:
33895
34259
  console.error(`unknown command: ${cmd}