@sleds/cli 0.1.71 → 0.1.72

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 +1254 -945
  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.72" ?? "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,30 @@ 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
  }
12362
12126
  function instructionsFrom(waiting) {
12363
12127
  if (!Array.isArray(waiting))
12364
12128
  return [];
12365
- return waiting.filter(isObject9).flatMap((w) => {
12129
+ return waiting.filter(isObject7).flatMap((w) => {
12366
12130
  const id = str7(w.id);
12367
12131
  const md = str7(w.md);
12368
12132
  if (!id || !md)
12369
12133
  return [];
12370
- const f = isObject9(w.finding) ? w.finding : null;
12134
+ const f = isObject7(w.finding) ? w.finding : null;
12371
12135
  const kind = f?.kind === "review" || f?.kind === "bot" ? f.kind : null;
12372
12136
  const url = f ? str7(f.url) : undefined;
12373
12137
  const by = f ? str7(f.by) : undefined;
@@ -12391,11 +12155,11 @@ function statesLanded(states) {
12391
12155
  return all.length > 0 && all.every((s) => s === "landed" || s === "skipped") && all.some((s) => s === "landed");
12392
12156
  }
12393
12157
  function armedTerms(armed) {
12394
- if (!isObject9(armed))
12158
+ if (!isObject7(armed))
12395
12159
  return { seatIds: [] };
12396
- const atOnce = num5(armed.atOnce);
12160
+ const atOnce = num4(armed.atOnce);
12397
12161
  const runner = str7(armed.runner);
12398
- const seatAtOnce = Array.isArray(armed.seatAtOnce) ? armed.seatAtOnce.map((x) => num5(x) ?? 1) : undefined;
12162
+ const seatAtOnce = Array.isArray(armed.seatAtOnce) ? armed.seatAtOnce.map((x) => num4(x) ?? 1) : undefined;
12399
12163
  return {
12400
12164
  ...atOnce !== undefined ? { atOnce } : {},
12401
12165
  seatIds: strings(armed.seatIds),
@@ -12447,10 +12211,10 @@ async function readOrSay(client, path, what) {
12447
12211
  function routeItem(q, r) {
12448
12212
  if (!r || r.ok === false)
12449
12213
  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) : [];
12214
+ const nodes = Array.isArray(r.nodes) ? r.nodes.filter(isObject7) : [];
12451
12215
  if (nodes.length === 0)
12452
12216
  throw new Error(`${q} has no route — draft one with the \`route\` tool first`);
12453
- const states = isObject9(r.states) ? r.states : {};
12217
+ const states = isObject7(r.states) ? r.states : {};
12454
12218
  const found = nodes.filter((n) => n.state === "running").map((n) => String(n.key));
12455
12219
  const running = found.length > 0 ? found : keysIn(states, "running");
12456
12220
  const held = heldOf(r, running);
@@ -12464,12 +12228,12 @@ function routeItem(q, r) {
12464
12228
  };
12465
12229
  }
12466
12230
  function heldOf(r, running) {
12467
- const runs = Array.isArray(r?.runs) ? r.runs.filter(isObject9) : [];
12231
+ const runs = Array.isArray(r?.runs) ? r.runs.filter(isObject7) : [];
12468
12232
  return runs.flatMap((x) => {
12469
12233
  const node = str7(x.node);
12470
12234
  const runId = str7(x.runId);
12471
12235
  const engine = str7(x.engine);
12472
- const startedAt = num5(x.startedAt);
12236
+ const startedAt = num4(x.startedAt);
12473
12237
  if (!node || !running.includes(node) || !runId || !engine || startedAt === undefined)
12474
12238
  return [];
12475
12239
  return [{ node, runId, engine, startedAt }];
@@ -12478,7 +12242,7 @@ function heldOf(r, running) {
12478
12242
  function groupOf(j, item) {
12479
12243
  if (!j || j.ok === false)
12480
12244
  return null;
12481
- const parent = isObject9(j.parent) ? j.parent : null;
12245
+ const parent = isObject7(j.parent) ? j.parent : null;
12482
12246
  const parentKey = str7(parent?.key)?.trim();
12483
12247
  if (parent && parentKey)
12484
12248
  return { key: parentKey, title: str7(parent.title) ?? parentKey };
@@ -12489,7 +12253,7 @@ function groupOf(j, item) {
12489
12253
  function runOf(v) {
12490
12254
  if (!Array.isArray(v))
12491
12255
  return;
12492
- return v.filter(isObject9).flatMap((x) => {
12256
+ return v.filter(isObject7).flatMap((x) => {
12493
12257
  const repo = str7(x.repo)?.trim();
12494
12258
  if (!repo)
12495
12259
  return [];
@@ -12503,21 +12267,21 @@ function sameEngine(a, b) {
12503
12267
  return bare(a) === bare(b);
12504
12268
  }
12505
12269
  function armedFor(armed, engine) {
12506
- if (!isObject9(armed))
12270
+ if (!isObject7(armed))
12507
12271
  return false;
12508
12272
  const where = str7(armed.engine);
12509
12273
  return !engine || !where?.trim() || sameEngine(where, engine);
12510
12274
  }
12511
12275
  function sledItems(r, armedOnly, engine) {
12512
- const mine = Array.isArray(r.mine) ? r.mine.filter(isObject9) : [];
12276
+ const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
12513
12277
  const out = [];
12514
12278
  for (const row of mine) {
12515
12279
  const route = row.route;
12516
- if (!isObject9(route))
12280
+ if (!isObject7(route))
12517
12281
  continue;
12518
12282
  if (armedOnly && !armedFor(route.armed, engine))
12519
12283
  continue;
12520
- const states = isObject9(route.states) ? route.states : {};
12284
+ const states = isObject7(route.states) ? route.states : {};
12521
12285
  out.push({
12522
12286
  item: str7(row.key) ?? String(row.project),
12523
12287
  ready: strings(route.ready),
@@ -12551,10 +12315,10 @@ var PROFILE_TEXT = [
12551
12315
  ];
12552
12316
  var SHELL_TEXT = ["agent", "launcher", "mode"];
12553
12317
  function profileOf(r) {
12554
- if (!r || r.ok === false || !isObject9(r.profile))
12318
+ if (!r || r.ok === false || !isObject7(r.profile))
12555
12319
  return null;
12556
12320
  const p = r.profile;
12557
- const member = isObject9(r.member) ? r.member : {};
12321
+ const member = isObject7(r.member) ? r.member : {};
12558
12322
  const out = {
12559
12323
  pickup: p.pickup === "auto" && member.pickup === "auto" ? "auto" : "approve",
12560
12324
  ...HOLD_DEFAULTS2,
@@ -12577,23 +12341,23 @@ function profileOf(r) {
12577
12341
  }
12578
12342
  if (p.pickup === "auto" && out.pickup !== "auto")
12579
12343
  notYours.push("pickup");
12580
- const atOnce = num5(p.atOnce);
12344
+ const atOnce = num4(p.atOnce);
12581
12345
  if (atOnce !== undefined && atOnce >= 1)
12582
12346
  out.atOnce = Math.round(atOnce);
12583
- const seatAtOnce = num5(r.seatAtOnce);
12347
+ const seatAtOnce = num4(r.seatAtOnce);
12584
12348
  if (seatAtOnce !== undefined && Number.isInteger(seatAtOnce) && seatAtOnce >= 1)
12585
12349
  out.seatAtOnce = seatAtOnce;
12586
12350
  if (typeof p.mcpStrict === "boolean")
12587
12351
  out.mcpStrict = p.mcpStrict;
12588
- const holdCpu = num5(p.holdCpu);
12352
+ const holdCpu = num4(p.holdCpu);
12589
12353
  if (holdCpu !== undefined && holdCpu > 0 && holdCpu <= 100)
12590
12354
  out.holdCpu = holdCpu;
12591
- const holdLoad = num5(p.holdLoad);
12355
+ const holdLoad = num4(p.holdLoad);
12592
12356
  if (holdLoad !== undefined && holdLoad > 0)
12593
12357
  out.holdLoad = holdLoad;
12594
12358
  if (p.holdPressure === "warn" || p.holdPressure === "critical")
12595
12359
  out.holdPressure = p.holdPressure;
12596
- const drainMaxMin = num5(p.drainMaxMin);
12360
+ const drainMaxMin = num4(p.drainMaxMin);
12597
12361
  if (drainMaxMin !== undefined && Number.isInteger(drainMaxMin) && drainMaxMin >= 0)
12598
12362
  out.drainMaxMin = drainMaxMin;
12599
12363
  if (Array.isArray(p.mcpAllow)) {
@@ -12622,12 +12386,12 @@ async function readProfile(client) {
12622
12386
  }
12623
12387
  }
12624
12388
  function nextPickup(r, o) {
12625
- const mine = Array.isArray(r.mine) ? r.mine.filter(isObject9) : [];
12389
+ const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
12626
12390
  for (const row of mine) {
12627
12391
  const route = row.route;
12628
- if (!isObject9(route) || !armedFor(route.armed, o.engine))
12392
+ if (!isObject7(route) || !armedFor(route.armed, o.engine))
12629
12393
  continue;
12630
- const states = isObject9(route.states) ? route.states : {};
12394
+ const states = isObject7(route.states) ? route.states : {};
12631
12395
  if (statesLanded(states))
12632
12396
  continue;
12633
12397
  if (strings(route.ready).length > 0)
@@ -12637,15 +12401,15 @@ function nextPickup(r, o) {
12637
12401
  return null;
12638
12402
  for (const row of mine) {
12639
12403
  const route = row.route;
12640
- if (!isObject9(route) || isObject9(route.armed) || route.draftParked)
12404
+ if (!isObject7(route) || isObject7(route.armed) || route.draftParked)
12641
12405
  continue;
12642
12406
  if (isPrMirror(row.source))
12643
12407
  continue;
12644
12408
  if (route.packable === false)
12645
12409
  continue;
12646
- if (isObject9(route.elsewhere))
12410
+ if (isObject7(route.elsewhere))
12647
12411
  continue;
12648
- const states = isObject9(route.states) ? route.states : {};
12412
+ const states = isObject7(route.states) ? route.states : {};
12649
12413
  if (statesLanded(states) || keysIn(states, "running").length > 0)
12650
12414
  continue;
12651
12415
  if (strings(route.ready).length > 0 || redraftDue(route))
@@ -12654,45 +12418,45 @@ function nextPickup(r, o) {
12654
12418
  return null;
12655
12419
  }
12656
12420
  function sledRunning(r) {
12657
- const mine = Array.isArray(r) ? r : Array.isArray(r.mine) ? r.mine.filter(isObject9) : [];
12421
+ const mine = Array.isArray(r) ? r : Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
12658
12422
  let running = 0;
12659
12423
  for (const row of mine) {
12660
12424
  const route = row.route;
12661
- if (isObject9(route) && route.drafting === true)
12425
+ if (isObject7(route) && route.drafting === true)
12662
12426
  running++;
12663
12427
  if (mockRunOf(row).running)
12664
12428
  running++;
12665
- if (!isObject9(route) || !isObject9(route.armed))
12429
+ if (!isObject7(route) || !isObject7(route.armed))
12666
12430
  continue;
12667
- running += keysIn(isObject9(route.states) ? route.states : {}, "running").length;
12431
+ running += keysIn(isObject7(route.states) ? route.states : {}, "running").length;
12668
12432
  }
12669
12433
  return running;
12670
12434
  }
12671
12435
  function armedDrafts(r, engine) {
12672
- const mine = Array.isArray(r.mine) ? r.mine.filter(isObject9) : [];
12436
+ const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
12673
12437
  return mine.filter((row) => {
12674
12438
  const route = row.route;
12675
- if (!isObject9(route) || !armedFor(route.armed, engine) || route.implicit !== true)
12439
+ if (!isObject7(route) || !armedFor(route.armed, engine) || route.implicit !== true)
12676
12440
  return false;
12677
12441
  if (route.drafting === true || route.proposed === true || route.draftParked)
12678
12442
  return false;
12679
- if (isObject9(route.elsewhere))
12443
+ if (isObject7(route.elsewhere))
12680
12444
  return false;
12681
12445
  if (strings(route.needsRoute).length === 0 || isPrMirror(row.source))
12682
12446
  return false;
12683
- const states = isObject9(route.states) ? route.states : {};
12447
+ const states = isObject7(route.states) ? route.states : {};
12684
12448
  return !statesLanded(states) && keysIn(states, "running").length === 0;
12685
12449
  });
12686
12450
  }
12687
12451
  function redraftDue(route) {
12688
- return isObject9(route) && isObject9(route.redraft) && route.drafting !== true && route.proposed !== true;
12452
+ return isObject7(route) && isObject7(route.redraft) && route.drafting !== true && route.proposed !== true;
12689
12453
  }
12690
12454
  function routeText(route, states) {
12691
- const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject9) : [];
12455
+ const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject7) : [];
12692
12456
  if (nodes.length > 0)
12693
12457
  return nodes.map((n) => `${String(n.key)} · ${str7(n.title) ?? String(n.key)} — ${str7(n.state) ?? "ready"}`).join(`
12694
12458
  `);
12695
- return Object.entries(isObject9(states) ? states : {}).map(([k, v]) => `${k} — ${String(v)}`).join(`
12459
+ return Object.entries(isObject7(states) ? states : {}).map(([k, v]) => `${k} — ${String(v)}`).join(`
12696
12460
  `);
12697
12461
  }
12698
12462
  function sledsSource(client, o) {
@@ -12707,7 +12471,7 @@ function sledsSource(client, o) {
12707
12471
  if (!row)
12708
12472
  return null;
12709
12473
  const item = str7(row.key) ?? String(row.project);
12710
- const why = isObject9(row.route) ? strings(row.route.needsRoute) : [];
12474
+ const why = isObject7(row.route) ? strings(row.route.needsRoute) : [];
12711
12475
  if (why.length > 0 || redraftDue(row.route))
12712
12476
  return draft(row, item, why);
12713
12477
  const a = await client.postFull("/proxy/route/arm", { project: str7(row.project) ?? item });
@@ -12717,12 +12481,12 @@ function sledsSource(client, o) {
12717
12481
  }
12718
12482
  const armed = a.json?.armed;
12719
12483
  if (!armedFor(armed, engine)) {
12720
- o.log?.(`Pickup: Auto armed ${item} for ${isObject9(armed) ? str7(armed.engine) : "another engine"}`);
12484
+ o.log?.(`Pickup: Auto armed ${item} for ${isObject7(armed) ? str7(armed.engine) : "another engine"}`);
12721
12485
  return null;
12722
12486
  }
12723
12487
  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 : {};
12488
+ const route = isObject7(row.route) ? row.route : {};
12489
+ const states = isObject7(route.states) ? route.states : {};
12726
12490
  return {
12727
12491
  item,
12728
12492
  ready: strings(route.ready),
@@ -12733,7 +12497,7 @@ function sledsSource(client, o) {
12733
12497
  }
12734
12498
  async function draft(row, item, why, started = false) {
12735
12499
  const project = str7(row.project) ?? item;
12736
- const pending = isObject9(row.route) && isObject9(row.route.redraft) ? row.route.redraft : null;
12500
+ const pending = isObject7(row.route) && isObject7(row.route.redraft) ? row.route.redraft : null;
12737
12501
  const runner = typeof o.runner === "function" ? o.runner() : o.runner;
12738
12502
  const r = await client.postFull("/proxy/route", {
12739
12503
  project,
@@ -12751,22 +12515,22 @@ function sledsSource(client, o) {
12751
12515
  let brief = null;
12752
12516
  try {
12753
12517
  brief = await client.get(`/proxy/route?q=${encodeURIComponent(project)}&draft=1`);
12754
- pack = (isObject9(brief?.draft) ? str7(brief.draft.pack) : undefined) ?? "";
12518
+ pack = (isObject7(brief?.draft) ? str7(brief.draft.pack) : undefined) ?? "";
12755
12519
  } catch {
12756
12520
  pack = "";
12757
12521
  }
12758
12522
  let redraft;
12759
12523
  if (pending) {
12760
- const full = isObject9(brief?.redraft) ? brief.redraft : {};
12524
+ const full = isObject7(brief?.redraft) ? brief.redraft : {};
12761
12525
  redraft = {
12762
12526
  md: str7(full.md) ?? str7(pending.md) ?? "",
12763
12527
  by: str7(full.by) ?? "a person",
12764
12528
  decision: str7(full.decisionId) ?? str7(pending.decisionId) ?? "",
12765
- route: routeText(brief, isObject9(row.route) ? row.route.states : null)
12529
+ route: routeText(brief, isObject7(row.route) ? row.route.states : null)
12766
12530
  };
12767
12531
  }
12768
12532
  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);
12533
+ const leaseUntil = num4(j.leaseUntil);
12770
12534
  const claim = {
12771
12535
  item,
12772
12536
  node: DRAFT_NODE,
@@ -12827,9 +12591,9 @@ function sledsSource(client, o) {
12827
12591
  mockRefused.delete(item);
12828
12592
  const j = r.json;
12829
12593
  const key = str7(j.key) ?? item;
12830
- const band = isObject9(j.band) ? mockBandText(j.band) : undefined;
12594
+ const band = isObject7(j.band) ? mockBandText(j.band) : undefined;
12831
12595
  o.log?.(`Pickup: Auto is drawing ${key}'s mock — a no-code session${band ? `, sized ${band}` : ""}`);
12832
- const leaseUntil = num5(j.leaseUntil);
12596
+ const leaseUntil = num4(j.leaseUntil);
12833
12597
  return {
12834
12598
  item: key,
12835
12599
  node: MOCK_NODE,
@@ -12895,10 +12659,10 @@ function sledsSource(client, o) {
12895
12659
  profileRead ??= readProfile(client);
12896
12660
  return profileRead;
12897
12661
  };
12898
- const mine = Array.isArray(r.mine) ? r.mine.filter(isObject9) : [];
12662
+ const mine = Array.isArray(r.mine) ? r.mine.filter(isObject7) : [];
12899
12663
  for (const row of mine) {
12900
12664
  const route = row.route;
12901
- if (!isObject9(route) || !armedFor(route.armed, o.engine) || !redraftDue(route))
12665
+ if (!isObject7(route) || !armedFor(route.armed, o.engine) || !redraftDue(route))
12902
12666
  continue;
12903
12667
  const item = str7(row.key) ?? String(row.project);
12904
12668
  const claimed = await draft(row, item, strings(route.needsRoute));
@@ -12918,7 +12682,7 @@ function sledsSource(client, o) {
12918
12682
  it.ready = [];
12919
12683
  if (room <= 0)
12920
12684
  continue;
12921
- const route = isObject9(row.route) ? row.route : {};
12685
+ const route = isObject7(row.route) ? row.route : {};
12922
12686
  const claimed = await draft(row, item, strings(route.needsRoute), true);
12923
12687
  if (claimed?.draft && it) {
12924
12688
  it.draft = claimed.draft;
@@ -12959,17 +12723,17 @@ function sledsSource(client, o) {
12959
12723
  });
12960
12724
  if (!r)
12961
12725
  return { ok: false, error: UNREACHABLE3 };
12962
- const taken = Array.isArray(r.json?.taken) ? r.json.taken.filter(isObject9) : [];
12726
+ const taken = Array.isArray(r.json?.taken) ? r.json.taken.filter(isObject7) : [];
12963
12727
  const hit = taken.find((x) => x.node === node) ?? taken[0];
12964
12728
  if (r.status >= 400 || !hit) {
12965
- const failed = Array.isArray(r.json?.failed) ? r.json.failed.filter(isObject9) : [];
12729
+ const failed = Array.isArray(r.json?.failed) ? r.json.failed.filter(isObject7) : [];
12966
12730
  return { ok: false, error: str7(failed[0]?.error) ?? serverMessage(r) };
12967
12731
  }
12968
12732
  let repos = strings(hit.repos);
12969
12733
  if (!Array.isArray(hit.repos)) {
12970
12734
  try {
12971
12735
  const route = await routeOf(item);
12972
- const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject9) : [];
12736
+ const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject7) : [];
12973
12737
  repos = strings(nodes.find((n) => n.key === (str7(hit.node) ?? node))?.repos);
12974
12738
  } catch {
12975
12739
  repos = [];
@@ -12981,7 +12745,7 @@ function sledsSource(client, o) {
12981
12745
  } catch {
12982
12746
  group = null;
12983
12747
  }
12984
- const leaseUntil = num5(hit.leaseUntil);
12748
+ const leaseUntil = num4(hit.leaseUntil);
12985
12749
  const runToken = str7(hit.runToken) ?? (taken.length === 1 ? str7(r.json?.runToken) : undefined);
12986
12750
  const run = runOf(hit.run);
12987
12751
  const claim = {
@@ -13020,17 +12784,17 @@ function sledsSource(client, o) {
13020
12784
  } catch {
13021
12785
  route = null;
13022
12786
  }
13023
- if (!isObject9(route))
12787
+ if (!isObject7(route))
13024
12788
  return "running";
13025
12789
  if (claim.kind === "draft") {
13026
12790
  const filed = Array.isArray(route.nodes) && route.nodes.length > 0;
13027
- if (filed || isObject9(route.proposed) || isObject9(route.elsewhere))
12791
+ if (filed || isObject7(route.proposed) || isObject7(route.elsewhere))
13028
12792
  return "done";
13029
- if (isObject9(route.draftParked))
12793
+ if (isObject7(route.draftParked))
13030
12794
  return "parked";
13031
12795
  return "lost";
13032
12796
  }
13033
- const nodes = Array.isArray(route.nodes) ? route.nodes.filter(isObject9) : [];
12797
+ const nodes = Array.isArray(route.nodes) ? route.nodes.filter(isObject7) : [];
13034
12798
  const state = nodes.find((n) => n.key === claim.node)?.state;
13035
12799
  if (state === "parked")
13036
12800
  return "parked";
@@ -13078,7 +12842,7 @@ function sledsSource(client, o) {
13078
12842
  },
13079
12843
  async openDecision(item, node) {
13080
12844
  const route = await routeOf(item);
13081
- const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject9) : [];
12845
+ const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject7) : [];
13082
12846
  const open = decisions.find((x) => x.state === "open" && x.node === node);
13083
12847
  return open ? str7(open.id) ?? null : null;
13084
12848
  },
@@ -13113,11 +12877,11 @@ function sledsSource(client, o) {
13113
12877
  return "running";
13114
12878
  try {
13115
12879
  const route = await routeOf(a.item);
13116
- const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject9) : [];
12880
+ const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject7) : [];
13117
12881
  const d = decisions.find((x) => x.id === a.decisionId);
13118
- if (d?.state === "answered" && isObject9(d.answerer) && d.answerer.verdict === "answered")
12882
+ if (d?.state === "answered" && isObject7(d.answerer) && d.answerer.verdict === "answered")
13119
12883
  return "answered";
13120
- if (d?.state === "answered" && isObject9(d.answerer) && d.answerer.verdict === "released")
12884
+ if (d?.state === "answered" && isObject7(d.answerer) && d.answerer.verdict === "released")
13121
12885
  return "released";
13122
12886
  if (d?.state === "escalated")
13123
12887
  return "escalated";
@@ -13200,16 +12964,16 @@ function sledsSource(client, o) {
13200
12964
  },
13201
12965
  async decisionOf(item, decisionId) {
13202
12966
  const route = await routeOf(item);
13203
- const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject9) : [];
12967
+ const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject7) : [];
13204
12968
  const d = decisions.find((x) => x.id === decisionId);
13205
12969
  if (!d)
13206
12970
  return null;
13207
- const answer = isObject9(d.answer) ? str7(d.answer.md) : undefined;
12971
+ const answer = isObject7(d.answer) ? str7(d.answer.md) : undefined;
13208
12972
  return { state: str7(d.state) ?? "", ...answer ? { answer } : {} };
13209
12973
  },
13210
12974
  async routeBriefs(item) {
13211
12975
  const route = await routeOf(item);
13212
- const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject9) : [];
12976
+ const nodes = Array.isArray(route?.nodes) ? route.nodes.filter(isObject7) : [];
13213
12977
  return nodes.flatMap((n) => {
13214
12978
  const key = str7(n.key);
13215
12979
  const { plan } = nodePlanOf(n.plan);
@@ -13499,9 +13263,9 @@ function providerFailure(screen) {
13499
13263
  // src/engine/worktree.ts
13500
13264
  init_src();
13501
13265
  import { appendFileSync, existsSync as existsSync9, mkdirSync as mkdirSync10 } from "node:fs";
13502
- import { dirname as dirname9, isAbsolute, join as join12 } from "node:path";
13266
+ import { dirname as dirname8, isAbsolute, join as join11 } from "node:path";
13503
13267
  function worktreePath(repoPath, name) {
13504
- return join12(repoPath, ".worktrees", name);
13268
+ return join11(repoPath, ".worktrees", name);
13505
13269
  }
13506
13270
  var fail2 = (what, r) => new Error(`${what} failed: ${(r.stderr || r.stdout).trim() || `exit ${r.status}`}`);
13507
13271
  function defaultBranch(exec, repoPath) {
@@ -13524,7 +13288,7 @@ function defaultBranch(exec, repoPath) {
13524
13288
  var realWorktreeFs = {
13525
13289
  exists: existsSync9,
13526
13290
  append: (p, text) => {
13527
- mkdirSync10(dirname9(p), { recursive: true });
13291
+ mkdirSync10(dirname8(p), { recursive: true });
13528
13292
  appendFileSync(p, text);
13529
13293
  }
13530
13294
  };
@@ -13536,7 +13300,7 @@ function ensureIgnored(exec, repoPath, fs = realWorktreeFs) {
13536
13300
  if (common.status !== 0)
13537
13301
  return;
13538
13302
  const dir = common.stdout.trim();
13539
- const exclude = join12(isAbsolute(dir) ? dir : join12(repoPath, dir), "info", "exclude");
13303
+ const exclude = join11(isAbsolute(dir) ? dir : join11(repoPath, dir), "info", "exclude");
13540
13304
  fs.append(exclude, `
13541
13305
  # sleds engine: one worktree per route node
13542
13306
  .worktrees/
@@ -13548,7 +13312,7 @@ function ensureWorktree(exec, repoPath, branch, path, base = "main", fs = realWo
13548
13312
  return path;
13549
13313
  }
13550
13314
  function makeWorktree(exec, repoPath, branch, path, base, fs, log) {
13551
- if (fs.exists(join12(path, ".git"))) {
13315
+ if (fs.exists(join11(path, ".git"))) {
13552
13316
  fastForwardUntouched(exec, path, base, log);
13553
13317
  return path;
13554
13318
  }
@@ -13643,13 +13407,13 @@ function installArgv(command) {
13643
13407
  return rest.every((a) => INSTALL_FLAGS.has(a)) ? argv : null;
13644
13408
  }
13645
13409
  function lockfileInstall(path, exists) {
13646
- if (exists(join12(path, "pnpm-lock.yaml")))
13410
+ if (exists(join11(path, "pnpm-lock.yaml")))
13647
13411
  return ["pnpm", "install", "--frozen-lockfile"];
13648
- if (exists(join12(path, "bun.lock")) || exists(join12(path, "bun.lockb")))
13412
+ if (exists(join11(path, "bun.lock")) || exists(join11(path, "bun.lockb")))
13649
13413
  return ["bun", "install", "--frozen-lockfile"];
13650
- if (exists(join12(path, "yarn.lock")))
13414
+ if (exists(join11(path, "yarn.lock")))
13651
13415
  return ["yarn", "install", "--frozen-lockfile"];
13652
- if (exists(join12(path, "package-lock.json")))
13416
+ if (exists(join11(path, "package-lock.json")))
13653
13417
  return ["npm", "ci"];
13654
13418
  return null;
13655
13419
  }
@@ -13707,7 +13471,7 @@ function claimRunOf(run, repo) {
13707
13471
  };
13708
13472
  }
13709
13473
  function ensureInstalled(exec, path, fs, o = {}) {
13710
- if (!fs.exists(join12(path, "package.json")) || fs.exists(join12(path, "node_modules")))
13474
+ if (!fs.exists(join11(path, "package.json")) || fs.exists(join11(path, "node_modules")))
13711
13475
  return null;
13712
13476
  const argv = installArgv(o.command) ?? lockfileInstall(path, fs.exists);
13713
13477
  if (!argv)
@@ -13722,7 +13486,7 @@ function ensureInstalled(exec, path, fs, o = {}) {
13722
13486
  return { argv, ok };
13723
13487
  }
13724
13488
  function ensureDetachedWorktree(exec, repoPath, path, base = "main", fs = realWorktreeFs) {
13725
- if (fs.exists(join12(path, ".git")))
13489
+ if (fs.exists(join11(path, ".git")))
13726
13490
  return path;
13727
13491
  ensureIgnored(exec, repoPath, fs);
13728
13492
  const f = exec("git", ["-C", repoPath, "fetch", "origin", base]);
@@ -15890,9 +15654,16 @@ ${instructionNudge(url, items)}`;
15890
15654
  function reviewNudge(url, count) {
15891
15655
  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
15656
  }
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.`;
15657
+ function lookQuestion(url, mock, comparison) {
15658
+ 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."}`;
15659
+ 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.";
15660
+ return `${head}
15661
+
15662
+ ${compared}
15663
+
15664
+ Looks good marks it ready for review.`;
15895
15665
  }
15666
+ var LOOK_WAIT_MS = 30 * 60000;
15896
15667
  async function judgeLook(d, run, view) {
15897
15668
  const looks = looksOf(d.source);
15898
15669
  const pr = run.pr;
@@ -15900,15 +15671,25 @@ async function judgeLook(d, run, view) {
15900
15671
  return;
15901
15672
  const draft = view.state === "OPEN" && view.draft;
15902
15673
  if (draft && !pr.look) {
15674
+ if (!view.comparison) {
15675
+ if (pr.lookWait === undefined) {
15676
+ pr.lookWait = d.now();
15677
+ d.log(`${ref(run)}: ${pr.url} is a draft — the look waits for the preview's comparison`);
15678
+ return;
15679
+ }
15680
+ if (d.now() - pr.lookWait < LOOK_WAIT_MS)
15681
+ return;
15682
+ }
15903
15683
  try {
15904
15684
  const r = await looks.openLook(run.runId, {
15905
- md: lookQuestion(pr.url, view.mock),
15685
+ md: lookQuestion(pr.url, view.mock, view.comparison),
15906
15686
  pr: pr.url,
15907
15687
  ...view.mock ? { mock: view.mock } : {}
15908
15688
  }, d.engine);
15909
15689
  if (!r.decisionId)
15910
15690
  return;
15911
15691
  pr.look = r.decisionId;
15692
+ pr.lookWait = undefined;
15912
15693
  if (r.opened)
15913
15694
  d.log(`${ref(run)}: ${pr.url} is a draft — a look waits for a person`);
15914
15695
  } catch (e) {
@@ -15924,6 +15705,8 @@ async function judgeLook(d, run, view) {
15924
15705
  d.log(`${ref(run)}: could not clear the look on ${pr.url}: ${message(e)}`);
15925
15706
  }
15926
15707
  }
15708
+ if (!draft)
15709
+ pr.lookWait = undefined;
15927
15710
  }
15928
15711
  async function follow(d, state, run, claim, runner, finished, attention, changes, decided) {
15929
15712
  const pr = run.pr;
@@ -16864,7 +16647,7 @@ async function settleEvent(d, events, state, dec, attention, decided) {
16864
16647
  init_machine();
16865
16648
 
16866
16649
  // src/engine/repos.ts
16867
- import { basename as basename4, dirname as dirname10, join as join13 } from "node:path";
16650
+ import { basename as basename3, dirname as dirname9, join as join12 } from "node:path";
16868
16651
  function splitReposDirs(raw) {
16869
16652
  return (raw ?? "").split(/[:\n]/).map((d) => d.trim()).filter(Boolean);
16870
16653
  }
@@ -16876,7 +16659,7 @@ function resolveRepoPath(o) {
16876
16659
  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
16660
  };
16878
16661
  }
16879
- const names = o.repos.map((r) => basename4(r.trim())).filter(Boolean);
16662
+ const names = o.repos.map((r) => basename3(r.trim())).filter(Boolean);
16880
16663
  const dirs = o.reposDirs ?? [];
16881
16664
  if (dirs.length === 0 || names.length === 0) {
16882
16665
  if (insideCheckout(o.cwd, o.exists))
@@ -16891,21 +16674,21 @@ function resolveRepoPath(o) {
16891
16674
  if (name.startsWith("."))
16892
16675
  continue;
16893
16676
  for (const dir of dirs) {
16894
- const p = join13(dir, name);
16895
- if (o.exists(join13(p, ".git")))
16677
+ const p = join12(dir, name);
16678
+ if (o.exists(join12(p, ".git")))
16896
16679
  return p;
16897
16680
  }
16898
16681
  }
16899
16682
  const want = o.repos.join(", ");
16900
- const where = names.flatMap((n) => dirs.map((d) => join13(d, n))).join(" or ");
16683
+ const where = names.flatMap((n) => dirs.map((d) => join12(d, n))).join(" or ");
16901
16684
  return {
16902
16685
  error: `No checkout of ${want} on this engine's machine: expected ${where}. Clone it there (or pass --repo).`
16903
16686
  };
16904
16687
  }
16905
- var isRoot = (p) => dirname10(p) === p;
16688
+ var isRoot = (p) => dirname9(p) === p;
16906
16689
  function insideCheckout(dir, exists) {
16907
- for (let d = dir;!isRoot(d); d = dirname10(d)) {
16908
- if (exists(join13(d, ".git")))
16690
+ for (let d = dir;!isRoot(d); d = dirname9(d)) {
16691
+ if (exists(join12(d, ".git")))
16909
16692
  return true;
16910
16693
  }
16911
16694
  return false;
@@ -16950,7 +16733,7 @@ init_meter();
16950
16733
 
16951
16734
  // src/runners/gitGuard.ts
16952
16735
  import { statSync as statSync2 } from "node:fs";
16953
- import { basename as basename5, dirname as dirname11, join as join14, resolve as resolve6 } from "node:path";
16736
+ import { basename as basename4, dirname as dirname10, join as join13, resolve as resolve6 } from "node:path";
16954
16737
  var GIT_GUARD_ENV = {
16955
16738
  GIT_CONFIG_COUNT: "4",
16956
16739
  GIT_CONFIG_KEY_0: "core.fsmonitor",
@@ -16983,13 +16766,13 @@ var isFile = (p) => statSync2(p, { throwIfNoEntry: false })?.isFile() ?? false;
16983
16766
  var isDir = (p) => statSync2(p, { throwIfNoEntry: false })?.isDirectory() ?? false;
16984
16767
  function ownGitDirs(dir, stat = { isFile, isDir }) {
16985
16768
  const wt = resolve6(dir);
16986
- if (basename5(dirname11(wt)) !== ".worktrees")
16769
+ if (basename4(dirname10(wt)) !== ".worktrees")
16987
16770
  return null;
16988
- const common = join14(dirname11(dirname11(wt)), ".git");
16989
- if (!stat.isFile(join14(wt, ".git")) || !stat.isDir(common))
16771
+ const common = join13(dirname10(dirname10(wt)), ".git");
16772
+ if (!stat.isFile(join13(wt, ".git")) || !stat.isDir(common))
16990
16773
  return null;
16991
16774
  return {
16992
- GIT_DIR: join14(common, "worktrees", basename5(wt)),
16775
+ GIT_DIR: join13(common, "worktrees", basename4(wt)),
16993
16776
  GIT_COMMON_DIR: common,
16994
16777
  GIT_WORK_TREE: wt
16995
16778
  };
@@ -16999,14 +16782,14 @@ var callDir = (args, cwd) => {
16999
16782
  return args[0] === "-C" && args[1] ? resolve6(base, args[1]) : base;
17000
16783
  };
17001
16784
  var GUARDED = new Set(["git", "gh"]);
17002
- var guardGit = (exec, guard = gitGuardEnv) => (cmd, args, o) => GUARDED.has(basename5(cmd)) ? exec(cmd, args, {
16785
+ var guardGit = (exec, guard = gitGuardEnv) => (cmd, args, o) => GUARDED.has(basename4(cmd)) ? exec(cmd, args, {
17003
16786
  ...o,
17004
16787
  env: { ...o?.env, ...guard(), ...ownGitDirs(callDir(args, o?.cwd)) }
17005
16788
  }) : exec(cmd, args, o);
17006
16789
 
17007
16790
  // src/runners/cmux.ts
17008
16791
  import { existsSync as existsSync10, rmSync as rmSync3, writeFileSync as writeFileSync10 } from "node:fs";
17009
- import { delimiter, join as join15 } from "node:path";
16792
+ import { delimiter, join as join14 } from "node:path";
17010
16793
 
17011
16794
  // src/keychain.ts
17012
16795
  var CMUX_KEYCHAIN_SERVICE = "ai.sleds.cmux";
@@ -17037,7 +16820,7 @@ var clearCmuxPassword = (exec) => exec("security", ["delete-generic-password", .
17037
16820
  var CMUX_APP_BIN = "/Applications/cmux.app/Contents/Resources/bin/cmux";
17038
16821
  var resolveCmuxBin = (exists = existsSync10, path = process.env.PATH ?? "") => {
17039
16822
  for (const dir of path.split(delimiter)) {
17040
- if (dir && exists(join15(dir, "cmux")))
16823
+ if (dir && exists(join14(dir, "cmux")))
17041
16824
  return "cmux";
17042
16825
  }
17043
16826
  return exists(CMUX_APP_BIN) ? CMUX_APP_BIN : "cmux";
@@ -18052,7 +17835,7 @@ ${renderTranscript(eventMessages(all))}`;
18052
17835
 
18053
17836
  // src/runners/orca.ts
18054
17837
  import { existsSync as existsSync11, lstatSync, readlinkSync, writeFileSync as writeFileSync11 } from "node:fs";
18055
- import { join as join16, resolve as resolve7 } from "node:path";
17838
+ import { join as join15, resolve as resolve7 } from "node:path";
18056
17839
  var obj3 = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
18057
17840
  var str11 = (v) => typeof v === "string" && v.length > 0 ? v : null;
18058
17841
  var parseOrcaJson = (stdout) => {
@@ -18115,7 +17898,7 @@ var realFs = { lstat: lstatSync, readlink: readlinkSync, exists: existsSync11 };
18115
17898
  var ORCA_LINK_FIX = "reinstall Orca's shell command from Orca (it links `orca` onto your PATH)";
18116
17899
  function danglingOrca(path, fs) {
18117
17900
  for (const dir of path.split(":").filter(Boolean)) {
18118
- const link = join16(dir, "orca");
17901
+ const link = join15(dir, "orca");
18119
17902
  try {
18120
17903
  if (!fs.lstat(link).isSymbolicLink())
18121
17904
  return null;
@@ -18413,9 +18196,9 @@ function restoreRunner(name, exec = defaultExec) {
18413
18196
 
18414
18197
  // src/runtime.ts
18415
18198
  import { homedir as homedir2 } from "node:os";
18416
- import { join as join17, win32 } from "node:path";
18199
+ import { join as join16, win32 } from "node:path";
18417
18200
  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");
18201
+ 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
18202
 
18420
18203
  // src/commands/engine.ts
18421
18204
  init_settings();
@@ -18434,7 +18217,7 @@ import {
18434
18217
  writeSync as writeSync2
18435
18218
  } from "node:fs";
18436
18219
  import { homedir as homedir7 } from "node:os";
18437
- import { join as join23 } from "node:path";
18220
+ import { join as join22 } from "node:path";
18438
18221
 
18439
18222
  // ../../packages/shared/src/updates/manifest.ts
18440
18223
  var CLI_PLATFORMS = [
@@ -18546,14 +18329,14 @@ import {
18546
18329
  var RELEASE_PUBLIC_KEY = "MCowBQYDK2VwAyEADIZiQghghQlN6WoLDF9xLmqMeFSQL4crcCBT4wINNCc=";
18547
18330
 
18548
18331
  // ../../packages/shared/src/updates/verify.ts
18549
- import { createPrivateKey, createPublicKey as createPublicKey2, sign, verify } from "node:crypto";
18332
+ import { createPrivateKey, createPublicKey, sign, verify } from "node:crypto";
18550
18333
  var B64_RE = /^[A-Za-z0-9+/]+={0,2}$/;
18551
18334
  function verifyManifest(text, signatureB64, publicKeySpkiB64) {
18552
18335
  try {
18553
18336
  const sig = signatureB64.trim();
18554
18337
  if (!B64_RE.test(sig))
18555
18338
  return false;
18556
- const key = createPublicKey2({
18339
+ const key = createPublicKey({
18557
18340
  key: Buffer.from(publicKeySpkiB64, "base64"),
18558
18341
  format: "der",
18559
18342
  type: "spki"
@@ -18577,12 +18360,12 @@ import {
18577
18360
  writeFileSync as writeFileSync12
18578
18361
  } from "node:fs";
18579
18362
  import { homedir as homedir3 } from "node:os";
18580
- import { dirname as dirname12, join as join18, win32 as win322 } from "node:path";
18363
+ import { dirname as dirname11, join as join17, win32 as win322 } from "node:path";
18581
18364
  var UPDATE_LOCK_STALE_MS = 10 * 60000;
18582
18365
  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");
18366
+ return platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds") : join17(home, ".sleds");
18584
18367
  }
18585
- var pathFor = (platform) => platform === "win32" ? win322 : { join: join18 };
18368
+ var pathFor = (platform) => platform === "win32" ? win322 : { join: join17 };
18586
18369
  function versionDir(home, v, platform = process.platform) {
18587
18370
  return pathFor(platform).join(sledsRoot(home, platform), "versions", v);
18588
18371
  }
@@ -18655,7 +18438,7 @@ function readUpdateState(home) {
18655
18438
  }
18656
18439
  function writeUpdateState(home, s) {
18657
18440
  const path = updateStatePath(home);
18658
- mkdirSync11(dirname12(path), { recursive: true, mode: 448 });
18441
+ mkdirSync11(dirname11(path), { recursive: true, mode: 448 });
18659
18442
  const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;
18660
18443
  writeFileSync12(tmp, `${JSON.stringify(s, null, 2)}
18661
18444
  `, { mode: 384 });
@@ -18733,7 +18516,7 @@ function breakStale(path, seen, token) {
18733
18516
  async function withUpdateLock(home, fn, o = {}) {
18734
18517
  const waitMs = o.waitMs ?? 30000;
18735
18518
  const path = updateLockPath(home);
18736
- mkdirSync11(dirname12(path), { recursive: true, mode: 448 });
18519
+ mkdirSync11(dirname11(path), { recursive: true, mode: 448 });
18737
18520
  const token = randomUUID();
18738
18521
  const tmp = `${path}.${token}.tmp`;
18739
18522
  writeFileSync12(tmp, `${JSON.stringify({ pid: process.pid, at: Date.now(), token })}
@@ -18812,7 +18595,7 @@ async function fetchVersion(o) {
18812
18595
  const platform = o.platform ?? process.platform;
18813
18596
  const arch = o.arch ?? process.arch;
18814
18597
  const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
18815
- const running = o.running ?? "0.1.71";
18598
+ const running = o.running ?? "0.1.72";
18816
18599
  if (!publicKey)
18817
18600
  return { ok: false, why: "no release key yet" };
18818
18601
  if (!VERSION_RE2.test(o.version))
@@ -18907,19 +18690,19 @@ import {
18907
18690
  writeFileSync as writeFileSync14
18908
18691
  } from "node:fs";
18909
18692
  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";
18693
+ import { basename as basename5, delimiter as delimiter2, dirname as dirname12, isAbsolute as isAbsolute2, join as join20, relative } from "node:path";
18911
18694
 
18912
18695
  // src/commands/engineSystemd.ts
18913
- import { join as join19 } from "node:path";
18696
+ import { join as join18 } from "node:path";
18914
18697
  var BOX_ENV_UNIT_PATH = "%h/.config/sleds/box.env";
18915
18698
  function boxEnvPath(home) {
18916
- return join19(home, ".config", "sleds", "box.env");
18699
+ return join18(home, ".config", "sleds", "box.env");
18917
18700
  }
18918
18701
  function engineUnitDir(home) {
18919
- return join19(home, ".config", "systemd", "user");
18702
+ return join18(home, ".config", "systemd", "user");
18920
18703
  }
18921
18704
  function engineUnitPath(home, label) {
18922
- return join19(engineUnitDir(home), `${label}.service`);
18705
+ return join18(engineUnitDir(home), `${label}.service`);
18923
18706
  }
18924
18707
  function systemdQuote(s) {
18925
18708
  const body = s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/%/g, "%%").replace(/\$/g, "$$$$");
@@ -18959,20 +18742,20 @@ function parseEngineUnit(text) {
18959
18742
  }
18960
18743
 
18961
18744
  // src/schedule.ts
18962
- import { spawnSync as spawnSync4 } from "node:child_process";
18745
+ import { spawnSync as spawnSync3 } from "node:child_process";
18963
18746
  import { existsSync as existsSync13, mkdirSync as mkdirSync13, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "node:fs";
18964
- import { join as join20 } from "node:path";
18747
+ import { join as join19 } from "node:path";
18965
18748
  var REVERT_LABEL = "ai.sleds.revert";
18966
18749
  var defaultExec2 = (cmd, args) => {
18967
- const r = spawnSync4(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
18750
+ const r = spawnSync3(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
18968
18751
  if (r.error)
18969
18752
  return { ok: false, stderr: r.error.message };
18970
18753
  return { ok: r.status === 0, stderr: r.stderr ?? "" };
18971
18754
  };
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;");
18755
+ var plistPath = (home) => join19(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
18756
+ var xmlEscape = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
18974
18757
  var buildLaunchdPlist = (sledsArgv, deadline) => {
18975
- const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape2(a)}</string>`).join(`
18758
+ const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape(a)}</string>`).join(`
18976
18759
  `);
18977
18760
  return `<?xml version="1.0" encoding="UTF-8"?>
18978
18761
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -19008,7 +18791,7 @@ var scheduleRevert = (d, deadlineMs) => {
19008
18791
  if (d.platform === "darwin") {
19009
18792
  const p = plistPath(d.home);
19010
18793
  try {
19011
- mkdirSync13(join20(d.home, "Library", "LaunchAgents"), { recursive: true });
18794
+ mkdirSync13(join19(d.home, "Library", "LaunchAgents"), { recursive: true });
19012
18795
  d.exec("launchctl", ["unload", p]);
19013
18796
  writeFileSync13(p, buildLaunchdPlist(d.sledsArgv, deadline));
19014
18797
  const r = d.exec("launchctl", ["load", p]);
@@ -19060,9 +18843,9 @@ var HOOK_SUBS = [
19060
18843
  "stop-event",
19061
18844
  "permission-event"
19062
18845
  ];
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;");
18846
+ var migrateBakDir = (home) => join20(sledsRoot(home), "migrate.bak");
18847
+ var manifestPath = (home) => join20(migrateBakDir(home), "manifest.json");
18848
+ var xmlEscape2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19066
18849
  var xmlUnescape = (s) => s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
19067
18850
  var shQuote = (s) => /^[\w./~-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
19068
18851
  function rewritePlist(text, link) {
@@ -19083,7 +18866,7 @@ function rewritePlist(text, link) {
19083
18866
  return null;
19084
18867
  const from = bodyAt + first.index;
19085
18868
  const to = bodyAt + last.index + last[0].length;
19086
- return `${text.slice(0, from)}<string>${xmlEscape3(link)}</string>${text.slice(to)}`;
18869
+ return `${text.slice(0, from)}<string>${xmlEscape2(link)}</string>${text.slice(to)}`;
19087
18870
  }
19088
18871
  function rewriteUnit(text, link) {
19089
18872
  const line = /^ExecStart=(.*)$/m.exec(text);
@@ -19161,15 +18944,15 @@ function rewriteSettings(text, link) {
19161
18944
  }
19162
18945
  var listDir = (dir, keep) => {
19163
18946
  try {
19164
- return readdirSync2(dir).filter(keep).sort().map((n) => join21(dir, n));
18947
+ return readdirSync2(dir).filter(keep).sort().map((n) => join20(dir, n));
19165
18948
  } catch {
19166
18949
  return [];
19167
18950
  }
19168
18951
  };
19169
18952
  function unitFiles(home) {
19170
- const agents = listDir(join21(home, "Library", "LaunchAgents"), (n) => n.startsWith("ai.sleds.") && n.endsWith(".plist")).map((path) => ({
18953
+ const agents = listDir(join20(home, "Library", "LaunchAgents"), (n) => n.startsWith("ai.sleds.") && n.endsWith(".plist")).map((path) => ({
19171
18954
  path,
19172
- ...basename6(path).startsWith("ai.sleds.revert") ? {} : { reload: "launchd" }
18955
+ ...basename5(path).startsWith("ai.sleds.revert") ? {} : { reload: "launchd" }
19173
18956
  }));
19174
18957
  const units = listDir(engineUnitDir(home), (n) => n.startsWith("ai.sleds.") && n.endsWith(".service")).map((path) => ({ path, reload: "systemd" }));
19175
18958
  return [...agents, ...units];
@@ -19179,7 +18962,7 @@ function unitClaudeDir(text) {
19179
18962
  return plist ? xmlUnescape(plist) : undefined;
19180
18963
  }
19181
18964
  function claudeDirs(home, env) {
19182
- const dirs = [join21(home, ".claude"), claudeDir(home, env)];
18965
+ const dirs = [join20(home, ".claude"), claudeDir(home, env)];
19183
18966
  for (const u of unitFiles(home)) {
19184
18967
  try {
19185
18968
  const d = unitClaudeDir(readFileSync13(u.path, "utf8"));
@@ -19203,7 +18986,7 @@ function migrationPlan(home, link, env = process.env) {
19203
18986
  out.push({ ...u, text: next });
19204
18987
  }
19205
18988
  for (const dir of claudeDirs(home, env)) {
19206
- const path = join21(dir, "settings.json");
18989
+ const path = join20(dir, "settings.json");
19207
18990
  let text;
19208
18991
  try {
19209
18992
  text = readFileSync13(path, "utf8");
@@ -19218,7 +19001,7 @@ function migrationPlan(home, link, env = process.env) {
19218
19001
  }
19219
19002
  var backupFor = (home, path) => {
19220
19003
  const rel = relative(home, path);
19221
- return rel.startsWith("..") || isAbsolute2(rel) ? join21(migrateBakDir(home), "abs", path) : join21(migrateBakDir(home), rel);
19004
+ return rel.startsWith("..") || isAbsolute2(rel) ? join20(migrateBakDir(home), "abs", path) : join20(migrateBakDir(home), rel);
19222
19005
  };
19223
19006
  function writeKeepingMode(path, text) {
19224
19007
  let mode = 420;
@@ -19235,7 +19018,7 @@ function copyInto(from, to) {
19235
19018
  renameSync9(tmp, to);
19236
19019
  }
19237
19020
  function pointLink(link, bin) {
19238
- mkdirSync14(dirname13(link), { recursive: true, mode: 448 });
19021
+ mkdirSync14(dirname12(link), { recursive: true, mode: 448 });
19239
19022
  const tmp = `${link}.tmp`;
19240
19023
  rmSync7(tmp, { force: true });
19241
19024
  symlinkSync(bin, tmp);
@@ -19260,7 +19043,7 @@ function reloadScript(lock, files) {
19260
19043
  for (const a of agents)
19261
19044
  lines.push(`launchctl unload ${shQuote(a.path)} 2>/dev/null; launchctl load ${shQuote(a.path)}`);
19262
19045
  if (units.length)
19263
- lines.push("systemctl --user daemon-reload", `systemctl --user --no-block restart ${units.map((u) => shQuote(basename6(u.path))).join(" ")}`);
19046
+ lines.push("systemctl --user daemon-reload", `systemctl --user --no-block restart ${units.map((u) => shQuote(basename5(u.path))).join(" ")}`);
19264
19047
  if (!lines.length)
19265
19048
  return null;
19266
19049
  return [
@@ -19354,7 +19137,7 @@ async function migrateToBinary(o) {
19354
19137
  rmSync7(migrateBakDir(home), { recursive: true, force: true });
19355
19138
  for (const p of plan) {
19356
19139
  const backup = backupFor(home, p.path);
19357
- mkdirSync14(dirname13(backup), { recursive: true, mode: 448 });
19140
+ mkdirSync14(dirname12(backup), { recursive: true, mode: 448 });
19358
19141
  copyFileSync(p.path, backup);
19359
19142
  manifest.files.push({ path: p.path, backup, ...p.reload ? { reload: p.reload } : {} });
19360
19143
  }
@@ -19388,7 +19171,7 @@ async function migrateToBinary(o) {
19388
19171
  log(`sleds stays on the npm install: ${result.why}`);
19389
19172
  return { ok: false, why: result.why };
19390
19173
  }
19391
- const binDir = dirname13(link);
19174
+ const binDir = dirname12(link);
19392
19175
  if (!(env.PATH ?? "").split(delimiter2).includes(binDir))
19393
19176
  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
19177
  reload(home, result.files, detach);
@@ -19408,10 +19191,10 @@ import {
19408
19191
  symlinkSync as symlinkSync2
19409
19192
  } from "node:fs";
19410
19193
  import { homedir as homedir5 } from "node:os";
19411
- import { dirname as dirname14, join as join22 } from "node:path";
19194
+ import { dirname as dirname13, join as join21 } from "node:path";
19412
19195
  var NO_PREVIOUS = "no previous version on this machine";
19413
19196
  function allStateFiles(home = homedir5(), env = process.env) {
19414
- const roots = [...new Set([configDir(home, env), join22(home, ".config", "sleds")])];
19197
+ const roots = [...new Set([configDir(home, env), join21(home, ".config", "sleds")])];
19415
19198
  const out = [];
19416
19199
  const walk = (dir) => {
19417
19200
  let names;
@@ -19422,20 +19205,20 @@ function allStateFiles(home = homedir5(), env = process.env) {
19422
19205
  }
19423
19206
  for (const n of names.sort())
19424
19207
  if (n.endsWith(".json") && n !== "removed-engines.json")
19425
- out.push(join22(dir, n));
19208
+ out.push(join21(dir, n));
19426
19209
  for (const sub of ["orgs", "seats"]) {
19427
19210
  let kids;
19428
19211
  try {
19429
- kids = readdirSync3(join22(dir, sub));
19212
+ kids = readdirSync3(join21(dir, sub));
19430
19213
  } catch {
19431
19214
  continue;
19432
19215
  }
19433
19216
  for (const k of kids.sort())
19434
- walk(join22(dir, sub, k));
19217
+ walk(join21(dir, sub, k));
19435
19218
  }
19436
19219
  };
19437
19220
  for (const r of roots)
19438
- walk(join22(r, "engine"));
19221
+ walk(join21(r, "engine"));
19439
19222
  return out;
19440
19223
  }
19441
19224
  var backupPath2 = (file, v) => `${file}.${v}.bak`;
@@ -19449,7 +19232,7 @@ function pointBinAt(home, v, platform) {
19449
19232
  const target = versionBin(home, v, platform);
19450
19233
  if (!existsSync14(target))
19451
19234
  throw new Error(`${target} is missing — sleds ${v} is not downloaded`);
19452
- mkdirSync15(dirname14(bin), { recursive: true, mode: 448 });
19235
+ mkdirSync15(dirname13(bin), { recursive: true, mode: 448 });
19453
19236
  if (platform === "win32") {
19454
19237
  replaceAside(bin, target);
19455
19238
  return;
@@ -19521,7 +19304,7 @@ function applyConfirm(s, home, o = {}) {
19521
19304
  if (!s.current)
19522
19305
  return;
19523
19306
  for (const f of o.stateFiles ?? allStateFiles(home)) {
19524
- const dir = dirname14(f);
19307
+ const dir = dirname13(f);
19525
19308
  const prefix = `${f.slice(dir.length + 1)}.`;
19526
19309
  let names;
19527
19310
  try {
@@ -19531,10 +19314,10 @@ function applyConfirm(s, home, o = {}) {
19531
19314
  }
19532
19315
  for (const n of names)
19533
19316
  if (n.startsWith(prefix) && n.endsWith(".bak"))
19534
- rmSync8(join22(dir, n), { force: true });
19317
+ rmSync8(join21(dir, n), { force: true });
19535
19318
  }
19536
19319
  const keep = new Set([s.current, s.previous, s.drain?.to].filter(Boolean));
19537
- const versions = dirname14(versionDir(home, s.current, platform));
19320
+ const versions = dirname13(versionDir(home, s.current, platform));
19538
19321
  let names = [];
19539
19322
  try {
19540
19323
  names = readdirSync3(versions);
@@ -19803,7 +19586,7 @@ async function machineAnswer(client, tokens) {
19803
19586
  var FETCH_LOCK_TOUCH_MS = 30000;
19804
19587
  async function fetchOnce(o) {
19805
19588
  const dir = versionDir(o.home, o.version, o.platform);
19806
- const lock = join23(dir, "fetch.lock");
19589
+ const lock = join22(dir, "fetch.lock");
19807
19590
  mkdirSync16(dir, { recursive: true, mode: 493 });
19808
19591
  let fd;
19809
19592
  try {
@@ -20038,7 +19821,7 @@ function engineUpdater(o) {
20038
19821
 
20039
19822
  // src/version.ts
20040
19823
  function cliVersion(env) {
20041
- return "0.1.71";
19824
+ return "0.1.72";
20042
19825
  }
20043
19826
 
20044
19827
  // src/commands/update.ts
@@ -20329,7 +20112,7 @@ function flagsFromProfile(flags, given, profile, home) {
20329
20112
  }
20330
20113
  }
20331
20114
  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(":");
20115
+ out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join23(home, d.slice(1)) : d).join(":");
20333
20116
  used.push(`repos ${profile.reposDir}`);
20334
20117
  }
20335
20118
  if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
@@ -20424,7 +20207,7 @@ function engineClient(o, org, breaker) {
20424
20207
  ...src,
20425
20208
  ...breaker ? { fetchFn: breaker.fetch } : {},
20426
20209
  timeoutMs: ENGINE_TIMEOUT_MS,
20427
- version: "0.1.71"
20210
+ version: "0.1.72"
20428
20211
  });
20429
20212
  const asked = org?.trim() || env.SLEDS_ORG?.trim();
20430
20213
  if (asked && !selectOrg(readConfig(o.home), org, env).seat)
@@ -20464,12 +20247,12 @@ function memberMcpConfigs(o, cwd) {
20464
20247
  });
20465
20248
  const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
20466
20249
  return [
20467
- read(claudeDir ? join24(claudeDir, ".claude.json") : join24(o.home, ".claude.json")),
20468
- ...cwd ? [read(join24(cwd, ".mcp.json"))] : []
20250
+ read(claudeDir ? join23(claudeDir, ".claude.json") : join23(o.home, ".claude.json")),
20251
+ ...cwd ? [read(join23(cwd, ".mcp.json"))] : []
20469
20252
  ];
20470
20253
  }
20471
20254
  function engineStateDir(o, org, seat) {
20472
- return seatStateDir(orgStateDir(o.stateDir ?? join24(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
20255
+ return seatStateDir(orgStateDir(o.stateDir ?? join23(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
20473
20256
  }
20474
20257
  function engineSeat(o, org) {
20475
20258
  try {
@@ -20499,9 +20282,9 @@ function engineDeps(o, flags, source, runner, stateName) {
20499
20282
  const repo = flags.repo ? resolve8(cwd, flags.repo) : undefined;
20500
20283
  const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve8(cwd, d));
20501
20284
  const { branch, prTitle } = flags;
20502
- const hooksDir = join24(stateDir, "hooks");
20285
+ const hooksDir = join23(stateDir, "hooks");
20503
20286
  const pnpmStores = new Map;
20504
- const permissionMark = (name) => join24(hooksDir, `${name}.permission.json`);
20287
+ const permissionMark = (name) => join23(hooksDir, `${name}.permission.json`);
20505
20288
  const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
20506
20289
  return {
20507
20290
  source,
@@ -20526,9 +20309,9 @@ function engineDeps(o, flags, source, runner, stateName) {
20526
20309
  sandbox: true,
20527
20310
  writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow, readOnly) => {
20528
20311
  const gitCommonDir = gitCommonDirOf(exec, cwd);
20529
- const dir = join24(stateDir, "sandbox");
20312
+ const dir = join23(stateDir, "sandbox");
20530
20313
  mkdirSync17(dir, { recursive: true, mode: 448 });
20531
- const p = join24(dir, `${name}.json`);
20314
+ const p = join23(dir, `${name}.json`);
20532
20315
  const walls = engineSandboxSettings(o.home, o.env ?? process.env, gitCommonDir, [
20533
20316
  ...SANDBOX_DEFAULT_ALLOW,
20534
20317
  ...flags.sandboxAllow ?? []
@@ -20551,7 +20334,7 @@ function engineDeps(o, flags, source, runner, stateName) {
20551
20334
  } : {},
20552
20335
  writeHookSettings: (name, allow, readOnly) => {
20553
20336
  mkdirSync17(hooksDir, { recursive: true, mode: 448 });
20554
- const p = join24(hooksDir, `${name}.json`);
20337
+ const p = join23(hooksDir, `${name}.json`);
20555
20338
  const deny = readOnlyDenyRules(readOnly ?? []);
20556
20339
  const permissions = {
20557
20340
  ...allow?.length ? { allow: [...allow] } : {},
@@ -20578,9 +20361,9 @@ function engineDeps(o, flags, source, runner, stateName) {
20578
20361
  exists
20579
20362
  }),
20580
20363
  writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
20581
- const dir = join24(stateDir, "mcp");
20364
+ const dir = join23(stateDir, "mcp");
20582
20365
  mkdirSync17(dir, { recursive: true, mode: 448 });
20583
- const p = join24(dir, `${name}.json`);
20366
+ const p = join23(dir, `${name}.json`);
20584
20367
  let others = {};
20585
20368
  if (flags.strictMcp && flags.mcpAllow?.length) {
20586
20369
  const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs(o, worktree));
@@ -20596,16 +20379,16 @@ function engineDeps(o, flags, source, runner, stateName) {
20596
20379
  }),
20597
20380
  removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync10(p, { force: true })),
20598
20381
  writePrompt: o.writePrompt ?? ((name, text) => {
20599
- const dir = join24(stateDir, "prompts");
20382
+ const dir = join23(stateDir, "prompts");
20600
20383
  mkdirSync17(dir, { recursive: true, mode: 448 });
20601
- const p = join24(dir, `${name}.md`);
20384
+ const p = join23(dir, `${name}.md`);
20602
20385
  writeFileSync15(p, text, { mode: 384 });
20603
20386
  return p;
20604
20387
  }),
20605
20388
  mockOut: (name) => {
20606
- const dir = join24(tmpdir(), "sleds-mocks");
20389
+ const dir = join23(tmpdir(), "sleds-mocks");
20607
20390
  mkdirSync17(dir, { recursive: true, mode: 448 });
20608
- const p = join24(dir, `${name}.html`);
20391
+ const p = join23(dir, `${name}.html`);
20609
20392
  rmSync10(p, { force: true });
20610
20393
  return p;
20611
20394
  },
@@ -20640,14 +20423,14 @@ function engineDeps(o, flags, source, runner, stateName) {
20640
20423
  }
20641
20424
  function sandboxDenyRead(home, env) {
20642
20425
  return {
20643
- dirs: [...new Set([configDir(home, env), join24(home, ".config", "sleds")])],
20426
+ dirs: [...new Set([configDir(home, env), join23(home, ".config", "sleds")])],
20644
20427
  files: [
20645
20428
  ...new Set([
20646
20429
  tokenPath(home, env),
20647
- join24(home, ".sleds-token"),
20430
+ join23(home, ".sleds-token"),
20648
20431
  settingsPath(home, env),
20649
20432
  backupPath(home, env),
20650
- join24(claudeDir(home, env), "settings.local.json")
20433
+ join23(claudeDir(home, env), "settings.local.json")
20651
20434
  ])
20652
20435
  ]
20653
20436
  };
@@ -20689,7 +20472,7 @@ function engineReadDirs(exec, cwd, exists, stores) {
20689
20472
  })();
20690
20473
  const pnpmStore = (() => {
20691
20474
  try {
20692
- if (!exists(join24(cwd, "pnpm-lock.yaml")))
20475
+ if (!exists(join23(cwd, "pnpm-lock.yaml")))
20693
20476
  return null;
20694
20477
  const key = common ?? cwd;
20695
20478
  const known = stores.get(key);
@@ -20714,7 +20497,7 @@ function engineReadDirs(exec, cwd, exists, stores) {
20714
20497
  }
20715
20498
  var LENT_NEEDS_SANDBOX = "a lent engine runs every session sandboxed (spec 48 rule 10) — add --sandbox to --lent-by";
20716
20499
  function lenderHome(accountHome, lentBy) {
20717
- return isAbsolute3(lentBy) ? resolve8(lentBy) : join24(dirname15(accountHome), lentBy);
20500
+ return isAbsolute3(lentBy) ? resolve8(lentBy) : join23(dirname14(accountHome), lentBy);
20718
20501
  }
20719
20502
  function lentHomeProblems(accountHome, lentBy, modeOf) {
20720
20503
  const lender = lenderHome(accountHome, lentBy);
@@ -20782,7 +20565,7 @@ async function driveEngine(o, flags, deps, until = {}) {
20782
20565
  runner: deps.runner.name,
20783
20566
  atOnce: flags.atOnce,
20784
20567
  interval: flags.interval,
20785
- cliVersion: "0.1.71"
20568
+ cliVersion: "0.1.72"
20786
20569
  };
20787
20570
  const beat = (checkedAt) => {
20788
20571
  const m = deps.machine;
@@ -21004,126 +20787,562 @@ function parsePauseArgs(argv, host) {
21004
20787
  } else
21005
20788
  return { error: `unknown argument ${a}` };
21006
20789
  }
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 });
20790
+ return {
20791
+ name: got.name ?? defaultEngineName(host),
20792
+ json,
20793
+ ...got.org ? { org: got.org } : {},
20794
+ ...got.why ? { why: got.why } : {}
20795
+ };
20796
+ }
20797
+ var isRunning = (r) => !r.pr && !r.parked;
20798
+ async function releaseRunning(o) {
20799
+ const state = o.read();
20800
+ const out = { released: 0, kept: [], errors: [] };
20801
+ const gone = new Set;
20802
+ for (const run of state.runs.filter(isRunning)) {
20803
+ const at = `${run.item}/${run.node}`;
20804
+ const runner = o.runnerFor ? o.runnerFor(run.handle.runner, o.exec) : restoreRunner(run.handle.runner, o.exec);
20805
+ try {
20806
+ runner?.stop(run.handle);
20807
+ } catch (e) {
20808
+ o.log(`${at}: could not stop the session: ${e instanceof Error ? e.message : String(e)}`);
20809
+ }
20810
+ try {
20811
+ await o.source.report(claimOf(run), { kind: "release", why: o.why }, o.engine);
20812
+ } catch (e) {
20813
+ out.errors.push(`${at}: ${e instanceof Error ? e.message : String(e)}`);
20814
+ continue;
20815
+ }
20816
+ gone.add(run);
20817
+ out.released++;
20818
+ out.kept.push(run.handle.cwd);
20819
+ if (run.mcpConfig)
20820
+ rmSync10(run.mcpConfig, { force: true });
20821
+ }
20822
+ if (gone.size)
20823
+ o.write({ ...state, runs: state.runs.filter((r) => !gone.has(r)) });
20824
+ return out;
20825
+ }
20826
+ var PAUSE_WAIT_MS = 90000;
20827
+ async function enginePauseCmd(o) {
20828
+ const log = o.log ?? console.log;
20829
+ const error = o.error ?? console.error;
20830
+ const host = o.host ?? hostname();
20831
+ const parsed = parsePauseArgs(o.argv, host);
20832
+ if ("error" in parsed) {
20833
+ error(parsed.error);
20834
+ error(ENGINE_PAUSE_USAGE);
20835
+ return 2;
20836
+ }
20837
+ const engine = `engine:${parsed.name}`;
20838
+ const which = engineOrg(o, parsed.org);
20839
+ const org = which.slug && (which.seated || parsed.org) ? which.slug : null;
20840
+ const seat = engineSeat(o, org ?? undefined) ?? null;
20841
+ const seatDir = engineStateDir(o, org, seat);
20842
+ const orgDir = engineStateDir(o, org);
20843
+ const has = (d) => realExists(statePath(d, engine)) || realExists(lockPath(d, engine));
20844
+ const dir = !has(seatDir) && has(orgDir) ? orgDir : seatDir;
20845
+ const alive = o.pidAlive ?? realPidAlive2;
20846
+ const sleep = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
20847
+ const kill = o.kill ?? ((pid, sig) => void process.kill(pid, sig));
20848
+ const lock = readLock(lockPath(dir, engine));
20849
+ let stopped = false;
20850
+ if (lock && lock.host === host && lock.pid !== process.pid && alive(lock.pid)) {
20851
+ try {
20852
+ kill(lock.pid, "SIGTERM");
20853
+ } catch {}
20854
+ for (let waited = 0;alive(lock.pid) && waited < PAUSE_WAIT_MS; waited += 250)
20855
+ await sleep(250);
20856
+ if (alive(lock.pid)) {
20857
+ error(`${engine} (pid ${lock.pid}) did not stop within ${PAUSE_WAIT_MS / 1000} s — nothing was paused. Try again, or stop it by hand.`);
20858
+ return 1;
20859
+ }
20860
+ stopped = true;
20861
+ }
20862
+ const file = statePath(dir, engine);
20863
+ const state = readState(file);
20864
+ const result = {
20865
+ released: 0,
20866
+ kept: [],
20867
+ following: 0,
20868
+ parked: 0,
20869
+ stopped,
20870
+ errors: []
20871
+ };
20872
+ result.following = state.runs.filter((r) => r.pr).length;
20873
+ result.parked = state.runs.filter((r) => r.parked).length;
20874
+ let source = o.source;
20875
+ if (state.runs.some(isRunning) && !source) {
20876
+ const c = orgClient(o, parsed.org);
20877
+ if ("error" in c) {
20878
+ error(c.error);
20879
+ return 1;
20880
+ }
20881
+ source = sledsSource(c, { engine, log });
20882
+ }
20883
+ if (source) {
20884
+ const r = await releaseRunning({
20885
+ read: () => state,
20886
+ write: (next) => writeState(file, next),
20887
+ source,
20888
+ engine,
20889
+ why: parsed.why ?? `paused on ${defaultEngineName(host)} (sleds engine pause)`,
20890
+ exec: guardGit(o.exec ?? defaultExec),
20891
+ ...o.runnerFor ? { runnerFor: o.runnerFor } : {},
20892
+ log
20893
+ });
20894
+ result.released = r.released;
20895
+ result.kept = r.kept;
20896
+ result.errors = r.errors;
20897
+ }
20898
+ if (parsed.json)
20899
+ log(JSON.stringify(result, null, 2));
20900
+ else {
20901
+ const n = (k, one) => `${k} ${one}${k === 1 ? "" : "s"}`;
20902
+ 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`);
20903
+ for (const w of result.kept)
20904
+ log(` kept ${w}`);
20905
+ for (const e of result.errors)
20906
+ error(` not released, retry with \`sleds engine pause\`: ${e}`);
20907
+ }
20908
+ return result.errors.length ? 1 : 0;
20909
+ }
20910
+
20911
+ // src/commands/attach.ts
20912
+ var ATTACH_USAGE = "usage: sleds attach <key> --file <path> [--kind screenshot|prototype|spec|doc|other] [--mock] [--json]";
20913
+ var ATTACH_MAX_BYTES = 4 * 1024 * 1024;
20914
+ var KINDS2 = new Set(["spec", "prototype", "screenshot", "doc", "other"]);
20915
+ function parseAttachArgs(argv) {
20916
+ let key;
20917
+ let file;
20918
+ let kind;
20919
+ let mock = false;
20920
+ let json = false;
20921
+ for (let i = 0;i < argv.length; i++) {
20922
+ const a = argv[i];
20923
+ if (a === "--json")
20924
+ json = true;
20925
+ else if (a === "--mock")
20926
+ mock = true;
20927
+ else if (a === "--file" || a === "--kind") {
20928
+ const value = argv[i + 1];
20929
+ if (value === undefined || value.startsWith("--"))
20930
+ return { error: `${a} needs a value` };
20931
+ if (a === "--file")
20932
+ file = value;
20933
+ else if (KINDS2.has(value))
20934
+ kind = value;
20935
+ else
20936
+ return { error: `--kind is one of ${[...KINDS2].join(", ")}` };
20937
+ i++;
20938
+ } else if (a.startsWith("--"))
20939
+ return { error: `unknown flag ${a}` };
20940
+ else if (key === undefined)
20941
+ key = a;
20942
+ else
20943
+ return { error: `one item and one --file at a time (${a}?)` };
20944
+ }
20945
+ if (!key)
20946
+ return { error: "which item?" };
20947
+ if (!file)
20948
+ return { error: "--file names the file to put on the item" };
20949
+ return { key, file, ...kind ? { kind } : {}, mock, json };
20950
+ }
20951
+ function attachEncoding(mime) {
20952
+ return /^text\/|^application\/json$|^image\/svg\+xml$/.test(mime) ? "text" : "base64";
20953
+ }
20954
+ async function attachCmd(o) {
20955
+ const log = o.log ?? console.log;
20956
+ const error = o.error ?? console.error;
20957
+ const a = parseAttachArgs(o.argv);
20958
+ if ("error" in a) {
20959
+ error(a.error);
20960
+ error(ATTACH_USAGE);
20961
+ return 2;
20962
+ }
20963
+ let bytes;
20964
+ try {
20965
+ if (!o.readFile && statSync7(a.file).size > ATTACH_MAX_BYTES) {
20966
+ error(`${a.file}: a file on an item is at most 4 MB`);
20967
+ return 1;
20968
+ }
20969
+ bytes = (o.readFile ?? readFileSync16)(a.file);
20970
+ } catch {
20971
+ error(`${a.file}: cannot read it`);
20972
+ return 1;
20973
+ }
20974
+ if (bytes.byteLength > ATTACH_MAX_BYTES) {
20975
+ error(`${a.file}: a file on an item is at most 4 MB`);
20976
+ return 1;
20977
+ }
20978
+ const name = basename6(a.file);
20979
+ const mime = mimeFromName(name);
20980
+ const encoding = attachEncoding(mime);
20981
+ const client = engineClient({ home: o.home, ...o.client ? { client: o.client } : {} });
20982
+ if ("error" in client) {
20983
+ error(client.error);
20984
+ return 1;
20985
+ }
20986
+ const r = await client.postFull("/proxy/asset", {
20987
+ project: a.key,
20988
+ name,
20989
+ mime,
20990
+ content: encoding === "base64" ? bytes.toString("base64") : bytes.toString("utf8"),
20991
+ ...encoding === "base64" ? { encoding } : {},
20992
+ ...a.kind ? { kind: a.kind } : {},
20993
+ ...a.mock ? { mock: true } : {}
20994
+ });
20995
+ if (!r) {
20996
+ error(`${a.key}: SLEDS unreachable — nothing stored`);
20997
+ return 1;
20998
+ }
20999
+ if (a.json)
21000
+ log(JSON.stringify(r.json ?? { ok: false, error: `HTTP ${r.status}` }));
21001
+ if (r.status >= 300) {
21002
+ const why = typeof r.json?.error === "string" ? r.json.error : `HTTP ${r.status}`;
21003
+ if (!a.json)
21004
+ error(r.status === 404 && !r.json ? `${a.key}: SLEDS does not know this seat — run \`sleds init\`` : `${a.key}: ${why}`);
21005
+ return 1;
21006
+ }
21007
+ const url = typeof r.json?.url === "string" ? r.json.url : "";
21008
+ if (!a.json)
21009
+ log(url || `${name} is on ${a.key}`);
21010
+ return 0;
21011
+ }
21012
+
21013
+ // src/commands/verify.ts
21014
+ init_meter();
21015
+ import { readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
21016
+ import { basename as basename8, extname } from "node:path";
21017
+
21018
+ // src/musher.ts
21019
+ import { spawnSync as spawnSync4 } from "node:child_process";
21020
+ import { createPublicKey as createPublicKey2, verify as cryptoVerify } from "node:crypto";
21021
+ import { basename as basename7, dirname as dirname15, join as join24 } from "node:path";
21022
+ var MUSHER_LABEL = "ai.sleds.musher";
21023
+ var MUSHER_INTERVAL_S = 300;
21024
+ var DEFAULT_PERMISSION_MODE = "acceptEdits";
21025
+ var PERMISSION_MODES = [
21026
+ "acceptEdits",
21027
+ "auto",
21028
+ "bypassPermissions",
21029
+ "default",
21030
+ "dontAsk",
21031
+ "plan"
21032
+ ];
21033
+ var DEFAULT_TIMEOUT_MINUTES = 90;
21034
+ var SUMMARY_MAX = 2000;
21035
+ var musherLabel = (env = process.env) => {
21036
+ const sh = env.SLEDS_HOME?.trim();
21037
+ if (!sh)
21038
+ return MUSHER_LABEL;
21039
+ const tag = basename7(sh).replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]+/g, "-") || "seat";
21040
+ return `${MUSHER_LABEL}.${tag}`;
21041
+ };
21042
+ var musherPlistPath = (home, env = process.env) => join24(home, "Library", "LaunchAgents", `${musherLabel(env)}.plist`);
21043
+ var musherLogPath = (configDir) => join24(configDir, "musher.log");
21044
+ var xmlEscape3 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
21045
+ var musherPath = (home, execPath, currentPath = "") => {
21046
+ const parts = [
21047
+ dirname15(execPath),
21048
+ join24(home, ".sleds", "bin"),
21049
+ join24(home, ".local", "bin"),
21050
+ join24(home, ".bun", "bin"),
21051
+ "/opt/homebrew/bin",
21052
+ "/usr/local/bin",
21053
+ "/usr/bin",
21054
+ "/bin",
21055
+ ...currentPath.split(":").filter(Boolean)
21056
+ ];
21057
+ return [...new Set(parts)].join(":");
21058
+ };
21059
+ var buildMusherPlist = (o) => {
21060
+ const label = o.label ?? MUSHER_LABEL;
21061
+ const args = [...o.sledsArgv, "musher", "tick"].map((a) => ` <string>${xmlEscape3(a)}</string>`).join(`
21062
+ `);
21063
+ const env = Object.entries(o.env).filter(([, v]) => v !== "").map(([k, v]) => ` <key>${xmlEscape3(k)}</key>
21064
+ <string>${xmlEscape3(v)}</string>`).join(`
21065
+ `);
21066
+ return `<?xml version="1.0" encoding="UTF-8"?>
21067
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
21068
+ <plist version="1.0">
21069
+ <dict>
21070
+ <key>Label</key>
21071
+ <string>${label}</string>
21072
+ <key>ProgramArguments</key>
21073
+ <array>
21074
+ ${args}
21075
+ </array>
21076
+ <key>EnvironmentVariables</key>
21077
+ <dict>
21078
+ ${env}
21079
+ </dict>
21080
+ <key>StartInterval</key>
21081
+ <integer>${MUSHER_INTERVAL_S}</integer>
21082
+ <key>RunAtLoad</key>
21083
+ <true/>
21084
+ <key>StandardOutPath</key>
21085
+ <string>${xmlEscape3(o.logPath)}</string>
21086
+ <key>StandardErrorPath</key>
21087
+ <string>${xmlEscape3(o.logPath)}</string>
21088
+ </dict>
21089
+ </plist>
21090
+ `;
21091
+ };
21092
+ var RESUME_PROMPT = [
21093
+ "SLEDS musher: the usage limit that stopped this session has reset, and the seat's owner",
21094
+ "scheduled this unattended run to continue it. Pick up exactly where the session left off:",
21095
+ "finish the task that was in flight, run the checks you would normally run, follow the repo's",
21096
+ "own conventions for branches and commits, and do not start unrelated work. If you are blocked",
21097
+ "on a decision only the owner can make, stop there and say so. Finish with a summary under",
21098
+ "200 words: what was done, what remains, anything the owner must decide."
21099
+ ].join(" ");
21100
+ var NO_SESSION_PROMPT = [
21101
+ "SLEDS musher: a deferred job started on this seat, but no Claude Code session was recorded",
21102
+ "to resume. Do not guess at work. Reply with one line saying so, and stop."
21103
+ ].join(" ");
21104
+ var claudeArgs = (o) => [
21105
+ "-p",
21106
+ o.sessionId ? RESUME_PROMPT : NO_SESSION_PROMPT,
21107
+ ...o.sessionId ? ["--resume", o.sessionId] : [],
21108
+ ...o.model ? ["--model", o.model] : [],
21109
+ "--output-format",
21110
+ "json",
21111
+ "--permission-mode",
21112
+ o.permissionMode
21113
+ ];
21114
+ var parseClaudeOutput = (stdout, exitCode) => {
21115
+ const lines = stdout.split(`
21116
+ `).map((l) => l.trim()).filter(Boolean);
21117
+ for (let i = lines.length - 1;i >= 0; i--) {
21118
+ const line = lines[i] ?? "";
21119
+ if (!line.startsWith("{"))
21120
+ continue;
21121
+ try {
21122
+ const j = JSON.parse(line);
21123
+ if (j.type !== "result" && typeof j.result !== "string")
21124
+ continue;
21125
+ const isError = j.is_error === true || typeof j.subtype === "string" && j.subtype !== "success";
21126
+ const text = typeof j.result === "string" ? j.result : "";
21127
+ const models = j.modelUsage;
21128
+ const model = typeof j.model === "string" ? j.model : models && typeof models === "object" ? Object.keys(models)[0] : undefined;
21129
+ return {
21130
+ ok: !isError && exitCode === 0,
21131
+ summary: (text || (isError ? "Claude Code reported an error" : "")).slice(0, SUMMARY_MAX),
21132
+ ...typeof j.session_id === "string" ? { sessionId: j.session_id } : {},
21133
+ ...model ? { model } : {},
21134
+ ...typeof j.duration_ms === "number" ? { durationMs: j.duration_ms } : {},
21135
+ ...typeof j.total_cost_usd === "number" ? { costUsd: j.total_cost_usd } : {}
21136
+ };
21137
+ } catch {}
21138
+ }
21139
+ const tail = lines.slice(-5).join(" ").slice(0, SUMMARY_MAX);
21140
+ return { ok: false, summary: tail || `claude exited ${exitCode ?? "without a code"}` };
21141
+ };
21142
+ var defaultExecCapture = (cmd, args, o) => {
21143
+ const r = spawnSync4(cmd, [...args], {
21144
+ cwd: o.cwd,
21145
+ encoding: "utf8",
21146
+ timeout: o.timeoutMs,
21147
+ maxBuffer: 64 * 1024 * 1024,
21148
+ stdio: ["ignore", "pipe", "pipe"],
21149
+ env: { ...process.env, SLEDS_MUSHER: "1" }
21150
+ });
21151
+ const timedOut = r.error?.code === "ETIMEDOUT";
21152
+ return {
21153
+ stdout: r.stdout ?? "",
21154
+ stderr: r.stderr ?? "",
21155
+ status: r.status,
21156
+ ...timedOut ? { timedOut } : r.error ? { error: r.error.message } : {}
21157
+ };
21158
+ };
21159
+ var musherClient = (o) => {
21160
+ const fetchFn = o.fetchFn ?? fetch;
21161
+ const headers = { authorization: `Bearer ${o.token}`, "content-type": "application/json" };
21162
+ const call = async (path, body) => {
21163
+ try {
21164
+ const res = await fetchFn(`${o.proxyUrl}${path}`, {
21165
+ method: body === undefined ? "GET" : "POST",
21166
+ headers,
21167
+ ...body === undefined ? {} : { body: JSON.stringify(body) },
21168
+ signal: AbortSignal.timeout(o.timeoutMs ?? 1e4)
21169
+ });
21170
+ if (!res.ok)
21171
+ return null;
21172
+ return await res.json();
21173
+ } catch {
21174
+ return null;
21175
+ }
21176
+ };
21177
+ return {
21178
+ list: () => call("/proxy/musher"),
21179
+ start: (jobId, local) => call("/proxy/musher/start", { jobId, ...local }),
21180
+ finish: async (input) => await call("/proxy/musher/finish", input) !== null,
21181
+ defer: (input) => call("/proxy/defer", input),
21182
+ attestation: (jobId) => call(`/proxy/attest/${encodeURIComponent(jobId)}`)
21183
+ };
21184
+ };
21185
+ var gitHead = (cwd, exec) => {
21186
+ if (!cwd)
21187
+ return null;
21188
+ const r = exec("git", ["rev-parse", "HEAD"], { cwd, timeoutMs: 5000 });
21189
+ const sha = r.stdout.trim();
21190
+ return r.status === 0 && /^[0-9a-f]{40}$/.test(sha) ? sha : null;
21191
+ };
21192
+ var gitNewCommits = (cwd, before, after, exec) => {
21193
+ if (!cwd || !after || after === before)
21194
+ return [];
21195
+ if (!before)
21196
+ return [after];
21197
+ const r = exec("git", ["rev-list", `${before}..${after}`], { cwd, timeoutMs: 5000 });
21198
+ if (r.status !== 0)
21199
+ return [after];
21200
+ return r.stdout.split(`
21201
+ `).map((l) => l.trim()).filter((l) => /^[0-9a-f]{40}$/.test(l)).slice(0, 40);
21202
+ };
21203
+ var collectOutputs = (commits, summary) => {
21204
+ const out = commits.map((c) => `git:${c}`);
21205
+ for (const m of summary.matchAll(/https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+/g))
21206
+ if (!out.includes(`pr:${m[0]}`))
21207
+ out.push(`pr:${m[0]}`);
21208
+ return out.slice(0, 50);
21209
+ };
21210
+ var runJob = async (o) => {
21211
+ const log = o.log ?? (() => {});
21212
+ const sessionId = o.job.claudeSessionId ?? o.fallbackSession?.id ?? null;
21213
+ const cwd = o.job.cwd ?? o.fallbackSession?.cwd ?? undefined;
21214
+ const started = await o.client.start(o.job.jobId, {
21215
+ ...sessionId ? { claudeSessionId: sessionId } : {},
21216
+ ...cwd ? { cwd } : {},
21217
+ host: o.host
21218
+ });
21219
+ if (!started)
21220
+ return { kind: "skipped", reason: "control plane unreachable" };
21221
+ if (!started.ok)
21222
+ return { kind: "skipped", reason: started.reason };
21223
+ const model = o.job.model ?? started.model ?? o.fallbackSession?.model ?? null;
21224
+ const args = claudeArgs({ sessionId, model, permissionMode: o.permissionMode });
21225
+ log(`musher: running job ${o.job.jobId} (${sessionId ? `resume ${sessionId}` : "no session"}${model ? ` · ${model}` : ""}${cwd ? ` · ${cwd}` : ""})`);
21226
+ const exec = o.exec ?? defaultExecCapture;
21227
+ const headBefore = gitHead(cwd, exec);
21228
+ const t0 = Date.now();
21229
+ const r = exec(o.claudePath, args, { cwd, timeoutMs: o.timeoutMs });
21230
+ const durationMs = Date.now() - t0;
21231
+ const result = r.error ? { ok: false, summary: `could not run ${o.claudePath}: ${r.error}` } : parseClaudeOutput(r.stdout, r.status);
21232
+ if (!r.error && (r.timedOut || r.status === null)) {
21233
+ result.ok = false;
21234
+ result.summary = `timed out after ${Math.round(o.timeoutMs / 60000)} min. ${result.summary}`.trim();
21235
+ }
21236
+ const outputs = collectOutputs(gitNewCommits(cwd, headBefore, gitHead(cwd, exec), exec), result.summary);
21237
+ await o.client.finish({
21238
+ jobId: o.job.jobId,
21239
+ runId: started.runId,
21240
+ ok: result.ok,
21241
+ summary: result.summary,
21242
+ ...outputs.length ? { outputs } : {},
21243
+ ...result.model ?? model ? { model: result.model ?? model } : {},
21244
+ durationMs: result.durationMs ?? durationMs,
21245
+ ...result.sessionId ?? sessionId ? { claudeSessionId: result.sessionId ?? sessionId } : {}
21246
+ });
21247
+ log(`musher: job ${o.job.jobId} ${result.ok ? "delivered" : "failed"} in ${Math.round(durationMs / 1000)}s`);
21248
+ return { kind: "ran", ok: result.ok, summary: result.summary, durationMs, outputs };
21249
+ };
21250
+ var verifyAttestation = (payload, sig, publicKeyB64) => {
21251
+ try {
21252
+ const pub = createPublicKey2({
21253
+ key: Buffer.from(publicKeyB64, "base64"),
21254
+ format: "der",
21255
+ type: "spki"
21256
+ });
21257
+ const raw = Buffer.from(sig.replace(/-/g, "+").replace(/_/g, "/"), "base64");
21258
+ return cryptoVerify(null, Buffer.from(payload, "utf8"), pub, raw);
21259
+ } catch {
21260
+ return false;
21261
+ }
21262
+ };
21263
+ var parsePayload = (payload) => {
21264
+ const out = {};
21265
+ for (const line of payload.split(`
21266
+ `).slice(1)) {
21267
+ const eq = line.indexOf("=");
21268
+ if (eq > 0)
21269
+ out[line.slice(0, eq)] = line.slice(eq + 1);
21038
21270
  }
21039
- if (gone.size)
21040
- o.write({ ...state, runs: state.runs.filter((r) => !gone.has(r)) });
21041
21271
  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;
21272
+ };
21273
+
21274
+ // src/switch.ts
21275
+ init_settings();
21276
+ var isObject12 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
21277
+ var envOf2 = (settings) => isObject12(settings.env) ? settings.env : {};
21278
+ var capturePriorEnv = (settings) => {
21279
+ const env = envOf2(settings);
21280
+ const prior = { hadEnv: isObject12(settings.env) };
21281
+ const url = env[BASE_URL_KEY];
21282
+ const token = env[AUTH_TOKEN_KEY];
21283
+ if (typeof url === "string")
21284
+ prior[BASE_URL_KEY] = url;
21285
+ if (typeof token === "string")
21286
+ prior[AUTH_TOKEN_KEY] = token;
21287
+ return prior;
21288
+ };
21289
+ var switchOn = (settings, cfg) => applyProxy(settings, cfg);
21290
+ var switchOff = (settings, prior) => {
21291
+ const hadEnv = prior.hadEnv === true;
21292
+ const stripped = removeProxy(settings);
21293
+ const env = { ...envOf2(stripped) };
21294
+ const url = prior[BASE_URL_KEY];
21295
+ const token = prior[AUTH_TOKEN_KEY];
21296
+ if (url !== undefined)
21297
+ env[BASE_URL_KEY] = url;
21298
+ if (token !== undefined)
21299
+ env[AUTH_TOKEN_KEY] = token;
21300
+ if (Object.keys(env).length === 0 && !hadEnv) {
21301
+ const { env: _env, ...rest } = stripped;
21302
+ return rest;
21053
21303
  }
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;
21304
+ return { ...stripped, env };
21305
+ };
21306
+ var envToRestore = (priors, proxyUrls) => priors.find((p) => p !== undefined && !isSledsProxyEnv({ env: p }, proxyUrls)) ?? {};
21307
+ var RELATIVE = /^\+(?:(\d+)h)?(?:(\d+)m)?$/;
21308
+ var parseUntilReset = (input, nowMs) => {
21309
+ const trimmed = input.trim();
21310
+ const rel = RELATIVE.exec(trimmed);
21311
+ let deadline;
21312
+ if (rel) {
21313
+ const hours = Number(rel[1] ?? 0);
21314
+ const minutes = Number(rel[2] ?? 0);
21315
+ if (hours === 0 && minutes === 0) {
21316
+ throw new Error(`--until-reset: "${input}" is zero; use something like +5h or +90m`);
21076
21317
  }
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;
21318
+ deadline = nowMs + (hours * 60 + minutes) * 60000;
21319
+ } else {
21320
+ deadline = Date.parse(trimmed);
21321
+ if (Number.isNaN(deadline)) {
21322
+ throw new Error(`--until-reset: "${input}" is not +<n>h[<n>m] or an ISO timestamp`);
21097
21323
  }
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
21324
  }
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}`);
21325
+ if (deadline <= nowMs) {
21326
+ throw new Error(`--until-reset: ${trimmed} is in the past`);
21124
21327
  }
21125
- return result.errors.length ? 1 : 0;
21126
- }
21328
+ return deadline;
21329
+ };
21330
+ var formatLocal = (ms, tz) => new Intl.DateTimeFormat("en-US", {
21331
+ month: "short",
21332
+ day: "numeric",
21333
+ hour: "numeric",
21334
+ minute: "2-digit",
21335
+ timeZoneName: "short",
21336
+ ...tz ? { timeZone: tz } : {}
21337
+ }).format(new Date(ms));
21338
+ var formatDuration = (ms) => {
21339
+ const total = Math.max(0, Math.round(ms / 60000));
21340
+ const h = Math.floor(total / 60);
21341
+ const m = total % 60;
21342
+ if (h === 0)
21343
+ return `${m}m`;
21344
+ return m === 0 ? `${h}h` : `${h}h ${m}m`;
21345
+ };
21127
21346
 
21128
21347
  // src/commands/verify.ts
21129
21348
  var VERDICT_USAGE = [
@@ -21204,17 +21423,17 @@ async function verdictCmd(o) {
21204
21423
  let screenshot;
21205
21424
  if (a.file) {
21206
21425
  try {
21207
- if (!o.readFile && statSync7(a.file).size > SHOT_MAX_BYTES) {
21426
+ if (!o.readFile && statSync8(a.file).size > SHOT_MAX_BYTES) {
21208
21427
  error(`${a.file}: a screenshot is at most 4 MB`);
21209
21428
  return 1;
21210
21429
  }
21211
- const bytes = (o.readFile ?? readFileSync16)(a.file);
21430
+ const bytes = (o.readFile ?? readFileSync17)(a.file);
21212
21431
  if (bytes.byteLength > SHOT_MAX_BYTES) {
21213
21432
  error(`${a.file}: a screenshot is at most 4 MB`);
21214
21433
  return 1;
21215
21434
  }
21216
21435
  screenshot = {
21217
- name: basename7(a.file),
21436
+ name: basename8(a.file),
21218
21437
  mime: shotMime(a.file),
21219
21438
  content: bytes.toString("base64")
21220
21439
  };
@@ -21473,7 +21692,7 @@ import {
21473
21692
  existsSync as existsSync21,
21474
21693
  lstatSync as lstatSync2,
21475
21694
  mkdtempSync,
21476
- readFileSync as readFileSync21,
21695
+ readFileSync as readFileSync22,
21477
21696
  readlinkSync as readlinkSync4,
21478
21697
  rmSync as rmSync13,
21479
21698
  writeFileSync as writeFileSync19
@@ -21483,7 +21702,7 @@ import { delimiter as delimiter3, dirname as dirname18, join as join27, resolve
21483
21702
 
21484
21703
  // src/agentMcp.ts
21485
21704
  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";
21705
+ import { existsSync as existsSync18, mkdirSync as mkdirSync18, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "node:fs";
21487
21706
  import { dirname as dirname16, join as join25, resolve as resolve9 } from "node:path";
21488
21707
  init_settings();
21489
21708
  var MCP_SERVER2 = "sleds";
@@ -21491,7 +21710,7 @@ var AGENT_NAME2 = { "claude-code": "Claude Code", codex: "Codex" };
21491
21710
  var claudeUserConfigPath2 = (home, env = process.env) => env.CLAUDE_CONFIG_DIR?.trim() ? join25(claudeDir(home, env), ".claude.json") : join25(home, ".claude.json");
21492
21711
  function hasClaudeMcp2(home, env = process.env) {
21493
21712
  try {
21494
- const raw = JSON.parse(readFileSync17(claudeUserConfigPath2(home, env), "utf8"));
21713
+ const raw = JSON.parse(readFileSync18(claudeUserConfigPath2(home, env), "utf8"));
21495
21714
  return Boolean(raw.mcpServers?.[MCP_SERVER2]);
21496
21715
  } catch {
21497
21716
  return false;
@@ -21501,7 +21720,7 @@ function hasCodexMcp2(home) {
21501
21720
  const path = codexConfigPath(home);
21502
21721
  if (!existsSync18(path))
21503
21722
  return false;
21504
- return new RegExp(`^\\s*\\[mcp_servers\\.${MCP_SERVER2}\\]\\s*$`, "m").test(readFileSync17(path, "utf8"));
21723
+ return new RegExp(`^\\s*\\[mcp_servers\\.${MCP_SERVER2}\\]\\s*$`, "m").test(readFileSync18(path, "utf8"));
21505
21724
  }
21506
21725
  var hasAgentMcp2 = (agent, home, env = process.env) => agent === "codex" ? hasCodexMcp2(home) : hasClaudeMcp2(home, env);
21507
21726
  var seatHome2 = (home, env) => {
@@ -21581,7 +21800,7 @@ async function offerMcpResult2(o) {
21581
21800
  return no;
21582
21801
  if (o.agent === "codex") {
21583
21802
  const path = codexConfigPath(o.home);
21584
- const prior = existsSync18(path) ? readFileSync17(path, "utf8") : "";
21803
+ const prior = existsSync18(path) ? readFileSync18(path, "utf8") : "";
21585
21804
  mkdirSync18(dirname16(path), { recursive: true });
21586
21805
  writeFileSync16(path, applyCodexMcp2(prior, o.home, env), { mode: 384 });
21587
21806
  return {
@@ -21881,14 +22100,14 @@ init_config();
21881
22100
  import {
21882
22101
  existsSync as existsSync19,
21883
22102
  mkdirSync as mkdirSync19,
21884
- readFileSync as readFileSync18,
22103
+ readFileSync as readFileSync19,
21885
22104
  readdirSync as readdirSync4,
21886
22105
  realpathSync,
21887
22106
  rmSync as rmSync11,
21888
22107
  writeFileSync as writeFileSync17
21889
22108
  } from "node:fs";
21890
22109
  import { hostname as hostname3 } from "node:os";
21891
- import { basename as basename8, dirname as dirname17, isAbsolute as isAbsolute4, join as join26 } from "node:path";
22110
+ import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute4, join as join26 } from "node:path";
21892
22111
  init_state();
21893
22112
  var ENGINE_LABEL = "ai.sleds.engine";
21894
22113
  var ENGINE_INSTALL_USAGE = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
@@ -22015,7 +22234,7 @@ function readEngines(dir, suffix, manager, parse) {
22015
22234
  const path = join26(dir, name);
22016
22235
  let parsed;
22017
22236
  try {
22018
- parsed = parse(readFileSync18(path, "utf8"), name);
22237
+ parsed = parse(readFileSync19(path, "utf8"), name);
22019
22238
  } catch {
22020
22239
  parsed = null;
22021
22240
  }
@@ -22035,7 +22254,7 @@ function installedEngines(home) {
22035
22254
  ...readEngines(join26(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
22036
22255
  ...readEngines(engineUnitDir(home), ".service", "systemd", (text, file) => {
22037
22256
  const parsed = parseEngineUnit(text);
22038
- return parsed && { label: basename8(file, ".service"), ...parsed };
22257
+ return parsed && { label: basename9(file, ".service"), ...parsed };
22039
22258
  })
22040
22259
  ];
22041
22260
  }
@@ -22122,7 +22341,7 @@ function installUnit(a) {
22122
22341
  const log = o.log ?? console.log;
22123
22342
  const error = o.error ?? console.error;
22124
22343
  const unit = engineUnitPath(o.home, label);
22125
- const unitName = basename8(unit);
22344
+ const unitName = basename9(unit);
22126
22345
  const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
22127
22346
  mkdirSync19(dirname17(unit), { recursive: true });
22128
22347
  if (existsSync19(unit))
@@ -22132,7 +22351,7 @@ function installUnit(a) {
22132
22351
  continue;
22133
22352
  if (engineArg(other.programArgs, "name") !== parsed.name)
22134
22353
  continue;
22135
- systemctl("disable", "--now", basename8(other.plist));
22354
+ systemctl("disable", "--now", basename9(other.plist));
22136
22355
  rmSync11(other.plist, { force: true });
22137
22356
  log(`replaced ${other.label}, this engine as installed before`);
22138
22357
  }
@@ -22191,18 +22410,18 @@ function engineUninstall(o) {
22191
22410
  const unit = file.endsWith(".service");
22192
22411
  const exec = o.exec ?? defaultExec2;
22193
22412
  if (unit)
22194
- exec("systemctl", ["--user", "disable", "--now", basename8(file)]);
22413
+ exec("systemctl", ["--user", "disable", "--now", basename9(file)]);
22195
22414
  else
22196
22415
  exec("launchctl", ["unload", file]);
22197
22416
  rmSync11(file, { force: true });
22198
22417
  if (unit)
22199
22418
  exec("systemctl", ["--user", "daemon-reload"]);
22200
- log(`engine:${name} removed: ${basename8(file, unit ? ".service" : ".plist")} — its sessions keep running`);
22419
+ log(`engine:${name} removed: ${basename9(file, unit ? ".service" : ".plist")} — its sessions keep running`);
22201
22420
  return 0;
22202
22421
  }
22203
22422
 
22204
22423
  // src/commands/musher.ts
22205
- import { existsSync as existsSync20, mkdirSync as mkdirSync20, readFileSync as readFileSync19, rmSync as rmSync12, writeFileSync as writeFileSync18 } from "node:fs";
22424
+ import { existsSync as existsSync20, mkdirSync as mkdirSync20, readFileSync as readFileSync20, rmSync as rmSync12, writeFileSync as writeFileSync18 } from "node:fs";
22206
22425
  init_config();
22207
22426
  init_meter();
22208
22427
  var defaultWhich = (cmd) => {
@@ -22237,7 +22456,7 @@ var musherAgentState = (home, env = process.env) => {
22237
22456
  if (!existsSync20(plist))
22238
22457
  return { installed: false, thisSeat: false };
22239
22458
  try {
22240
- const text = readFileSync19(plist, "utf8");
22459
+ const text = readFileSync20(plist, "utf8");
22241
22460
  const want = env.SLEDS_HOME?.trim();
22242
22461
  const has = /<key>SLEDS_HOME<\/key>\s*<string>([^<]*)<\/string>/.exec(text)?.[1];
22243
22462
  return { installed: true, thisSeat: (want ?? undefined) === (has ?? undefined) };
@@ -22247,7 +22466,7 @@ var musherAgentState = (home, env = process.env) => {
22247
22466
  };
22248
22467
 
22249
22468
  // src/claudeAccount.ts
22250
- import { readFileSync as readFileSync20 } from "node:fs";
22469
+ import { readFileSync as readFileSync21 } from "node:fs";
22251
22470
  var PLANS = {
22252
22471
  claude_max: "Max",
22253
22472
  claude_pro: "Pro",
@@ -22276,7 +22495,7 @@ var parseClaudeAccount = (raw) => {
22276
22495
  };
22277
22496
  var readClaudeAccount = (home, env = process.env) => {
22278
22497
  try {
22279
- return parseClaudeAccount(JSON.parse(readFileSync20(claudeUserConfigPath2(home, env), "utf8")));
22498
+ return parseClaudeAccount(JSON.parse(readFileSync21(claudeUserConfigPath2(home, env), "utf8")));
22280
22499
  } catch {
22281
22500
  return null;
22282
22501
  }
@@ -22879,7 +23098,7 @@ function boxChecks(o, env, which, need) {
22879
23098
  const file = boxEnvPath(o.home);
22880
23099
  let boxEnvText = null;
22881
23100
  try {
22882
- boxEnvText = readFileSync21(file, "utf8");
23101
+ boxEnvText = readFileSync22(file, "utf8");
22883
23102
  } catch {
22884
23103
  boxEnvText = null;
22885
23104
  }
@@ -22997,10 +23216,10 @@ import {
22997
23216
  appendFileSync as appendFileSync3,
22998
23217
  chmodSync as chmodSync6,
22999
23218
  mkdirSync as mkdirSync21,
23000
- readFileSync as readFileSync22,
23219
+ readFileSync as readFileSync23,
23001
23220
  existsSync as realExists2,
23002
23221
  rmSync as rmSync14,
23003
- statSync as statSync8,
23222
+ statSync as statSync9,
23004
23223
  writeFileSync as writeFileSync20
23005
23224
  } from "node:fs";
23006
23225
  import { hostname as hostname4, tmpdir as tmpdir3, userInfo as userInfo3 } from "node:os";
@@ -23411,7 +23630,7 @@ function engineClient2(o, org, breaker) {
23411
23630
  ...src,
23412
23631
  ...breaker ? { fetchFn: breaker.fetch } : {},
23413
23632
  timeoutMs: ENGINE_TIMEOUT_MS2,
23414
- version: "0.1.71"
23633
+ version: "0.1.72"
23415
23634
  });
23416
23635
  const asked = org?.trim() || env.SLEDS_ORG?.trim();
23417
23636
  if (asked && !selectOrg(readConfig(o.home), org, env).seat)
@@ -23453,7 +23672,7 @@ function realPidAlive3(pid) {
23453
23672
  function memberMcpConfigs2(o, cwd) {
23454
23673
  const read = o.readJson ?? ((p) => {
23455
23674
  try {
23456
- return JSON.parse(readFileSync22(p, "utf8"));
23675
+ return JSON.parse(readFileSync23(p, "utf8"));
23457
23676
  } catch {
23458
23677
  return null;
23459
23678
  }
@@ -23488,7 +23707,7 @@ function engineCredential(o) {
23488
23707
  const file = boxEnvPath(o.home);
23489
23708
  let boxEnvText = null;
23490
23709
  try {
23491
- boxEnvText = readFileSync22(file, "utf8");
23710
+ boxEnvText = readFileSync23(file, "utf8");
23492
23711
  } catch {}
23493
23712
  return detectCredential(o.env ?? process.env, {
23494
23713
  home: o.home,
@@ -23620,7 +23839,7 @@ function engineDeps2(o, flags, source, runner, stateName) {
23620
23839
  },
23621
23840
  readMock: (p) => {
23622
23841
  try {
23623
- return readFileSync22(p, "utf8");
23842
+ return readFileSync23(p, "utf8");
23624
23843
  } catch {
23625
23844
  return null;
23626
23845
  }
@@ -23759,7 +23978,7 @@ function lentHomeProblems2(accountHome, lentBy, modeOf) {
23759
23978
  }
23760
23979
  var homeMode2 = (path) => {
23761
23980
  try {
23762
- return statSync8(path).mode & 4095;
23981
+ return statSync9(path).mode & 4095;
23763
23982
  } catch {
23764
23983
  return null;
23765
23984
  }
@@ -23804,7 +24023,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
23804
24023
  runner: deps.runner.name,
23805
24024
  atOnce: flags.atOnce,
23806
24025
  interval: flags.interval,
23807
- cliVersion: "0.1.71"
24026
+ cliVersion: "0.1.72"
23808
24027
  };
23809
24028
  const beat = (checkedAt) => {
23810
24029
  const m = deps.machine;
@@ -24434,14 +24653,14 @@ init_config();
24434
24653
  import {
24435
24654
  existsSync as existsSync22,
24436
24655
  mkdirSync as mkdirSync22,
24437
- readFileSync as readFileSync23,
24656
+ readFileSync as readFileSync24,
24438
24657
  readdirSync as readdirSync6,
24439
24658
  realpathSync as realpathSync2,
24440
24659
  rmSync as rmSync15,
24441
24660
  writeFileSync as writeFileSync21
24442
24661
  } from "node:fs";
24443
24662
  import { hostname as hostname5 } from "node:os";
24444
- import { basename as basename9, dirname as dirname20, isAbsolute as isAbsolute6, join as join29 } from "node:path";
24663
+ import { basename as basename10, dirname as dirname20, isAbsolute as isAbsolute6, join as join29 } from "node:path";
24445
24664
  init_state();
24446
24665
  var ENGINE_LABEL2 = "ai.sleds.engine";
24447
24666
  var ENGINE_INSTALL_USAGE2 = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
@@ -24568,7 +24787,7 @@ function readEngines2(dir, suffix, manager, parse) {
24568
24787
  const path = join29(dir, name);
24569
24788
  let parsed;
24570
24789
  try {
24571
- parsed = parse(readFileSync23(path, "utf8"), name);
24790
+ parsed = parse(readFileSync24(path, "utf8"), name);
24572
24791
  } catch {
24573
24792
  parsed = null;
24574
24793
  }
@@ -24588,7 +24807,7 @@ function installedEngines2(home) {
24588
24807
  ...readEngines2(join29(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
24589
24808
  ...readEngines2(engineUnitDir(home), ".service", "systemd", (text, file) => {
24590
24809
  const parsed = parseEngineUnit(text);
24591
- return parsed && { label: basename9(file, ".service"), ...parsed };
24810
+ return parsed && { label: basename10(file, ".service"), ...parsed };
24592
24811
  })
24593
24812
  ];
24594
24813
  }
@@ -24719,7 +24938,7 @@ function installUnit2(a) {
24719
24938
  const log = o.log ?? console.log;
24720
24939
  const error = o.error ?? console.error;
24721
24940
  const unit = engineUnitPath(o.home, label);
24722
- const unitName = basename9(unit);
24941
+ const unitName = basename10(unit);
24723
24942
  const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
24724
24943
  mkdirSync22(dirname20(unit), { recursive: true });
24725
24944
  if (existsSync22(unit))
@@ -24729,7 +24948,7 @@ function installUnit2(a) {
24729
24948
  continue;
24730
24949
  if (engineArg2(other.programArgs, "name") !== parsed.name)
24731
24950
  continue;
24732
- systemctl("disable", "--now", basename9(other.plist));
24951
+ systemctl("disable", "--now", basename10(other.plist));
24733
24952
  rmSync15(other.plist, { force: true });
24734
24953
  log(`replaced ${other.label}, this engine as installed before`);
24735
24954
  }
@@ -24788,13 +25007,13 @@ function engineUninstall2(o) {
24788
25007
  const unit = file.endsWith(".service");
24789
25008
  const exec = o.exec ?? defaultExec2;
24790
25009
  if (unit)
24791
- exec("systemctl", ["--user", "disable", "--now", basename9(file)]);
25010
+ exec("systemctl", ["--user", "disable", "--now", basename10(file)]);
24792
25011
  else
24793
25012
  exec("launchctl", ["unload", file]);
24794
25013
  rmSync15(file, { force: true });
24795
25014
  if (unit)
24796
25015
  exec("systemctl", ["--user", "daemon-reload"]);
24797
- log(`engine:${name} removed: ${basename9(file, unit ? ".service" : ".plist")} — its sessions keep running`);
25016
+ log(`engine:${name} removed: ${basename10(file, unit ? ".service" : ".plist")} — its sessions keep running`);
24798
25017
  return 0;
24799
25018
  }
24800
25019
 
@@ -24922,7 +25141,7 @@ import { closeSync as closeSync5, fstatSync as fstatSync2, openSync as openSync5
24922
25141
  import { hostname as hostname6 } from "node:os";
24923
25142
 
24924
25143
  // src/commands/engineStatus.ts
24925
- import { existsSync as existsSync23, readFileSync as readFileSync24 } from "node:fs";
25144
+ import { existsSync as existsSync23, readFileSync as readFileSync25 } from "node:fs";
24926
25145
  init_state();
24927
25146
 
24928
25147
  // src/engine/status.ts
@@ -25222,7 +25441,7 @@ var engineLogCmd = (o) => {
25222
25441
 
25223
25442
  // src/commands/engineProfile.ts
25224
25443
  init_src();
25225
- import { existsSync as existsSync24, readFileSync as readFileSync25 } from "node:fs";
25444
+ import { existsSync as existsSync24, readFileSync as readFileSync26 } from "node:fs";
25226
25445
  import { hostname as hostname7 } from "node:os";
25227
25446
  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
25447
  var PROFILE_FIELDS = [
@@ -25493,7 +25712,7 @@ async function engineProfileCmd(o) {
25493
25712
  const rest = words.slice(1);
25494
25713
  let stdin = null;
25495
25714
  if (fromStdin) {
25496
- const taken = cmuxPasswordFromJson((o.stdin ?? (() => readFileSync25(0, "utf8")))());
25715
+ const taken = cmuxPasswordFromJson((o.stdin ?? (() => readFileSync26(0, "utf8")))());
25497
25716
  if ("error" in taken || taken.password !== undefined && password !== undefined) {
25498
25717
  error("error" in taken ? taken.error : "the cmux password is given once");
25499
25718
  error(PROFILE_USAGE);
@@ -25578,7 +25797,7 @@ var keychainLine = (k) => k === "set" ? "cmuxPassword: set (Keychain)" : k === "
25578
25797
 
25579
25798
  // src/commands/engineStatus.ts
25580
25799
  init_state();
25581
- import { existsSync as existsSync25, readFileSync as readFileSync26 } from "node:fs";
25800
+ import { existsSync as existsSync25, readFileSync as readFileSync27 } from "node:fs";
25582
25801
  import { hostname as hostname8 } from "node:os";
25583
25802
  var ENGINE_STATUS_USAGE = "usage: sleds engine status [--name <n>] [--org <slug>] [--json]";
25584
25803
  function parseStatusArgs(argv, host) {
@@ -25634,7 +25853,7 @@ function readEngineStatus(stateDir, engine, host, pidAlive, seat) {
25634
25853
  }
25635
25854
  function safeRead(path) {
25636
25855
  try {
25637
- return readFileSync26(path, "utf8");
25856
+ return readFileSync27(path, "utf8");
25638
25857
  } catch {
25639
25858
  return "";
25640
25859
  }
@@ -25755,7 +25974,7 @@ init_meter();
25755
25974
 
25756
25975
  // src/owed.ts
25757
25976
  init_config();
25758
- import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as readFileSync27, renameSync as renameSync11, writeFileSync as writeFileSync22 } from "node:fs";
25977
+ import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as readFileSync28, renameSync as renameSync11, writeFileSync as writeFileSync22 } from "node:fs";
25759
25978
  import { dirname as dirname21, join as join30 } from "node:path";
25760
25979
  var owedPath = (home) => join30(configDir(home), "owed.json");
25761
25980
  var sessionPath = (home) => join30(configDir(home), "session.json");
@@ -25776,7 +25995,7 @@ var readJson = (p) => {
25776
25995
  if (!existsSync26(p))
25777
25996
  return null;
25778
25997
  try {
25779
- return JSON.parse(readFileSync27(p, "utf8"));
25998
+ return JSON.parse(readFileSync28(p, "utf8"));
25780
25999
  } catch {
25781
26000
  return null;
25782
26001
  }
@@ -25916,7 +26135,7 @@ function contextFor(deps) {
25916
26135
  ...src,
25917
26136
  fetchFn: deps.fetchFn,
25918
26137
  timeoutMs: deps.timeoutMs,
25919
- version: "0.1.71"
26138
+ version: "0.1.72"
25920
26139
  }), deps.home, now) : null;
25921
26140
  return {
25922
26141
  channel: "code",
@@ -26990,9 +27209,9 @@ var login = async (o) => {
26990
27209
  // src/commands/logout.ts
26991
27210
  init_config();
26992
27211
  init_state();
26993
- import { existsSync as existsSync28, readFileSync as readFileSync28, rmSync as rmSync16 } from "node:fs";
27212
+ import { existsSync as existsSync28, readFileSync as readFileSync29, rmSync as rmSync16 } from "node:fs";
26994
27213
  import { hostname as hostname10 } from "node:os";
26995
- import { basename as basename10 } from "node:path";
27214
+ import { basename as basename11 } from "node:path";
26996
27215
  init_settings();
26997
27216
  var LOGOUT_USAGE = "usage: sleds logout [--org <slug>] [--json]";
26998
27217
  function parseLogoutArgs(argv) {
@@ -27116,7 +27335,7 @@ async function logout(o) {
27116
27335
  if (!e.org) {
27117
27336
  const exec = o.exec ?? defaultExec2;
27118
27337
  if (e.manager === "systemd") {
27119
- exec("systemctl", ["--user", "disable", "--now", basename10(e.plist)]);
27338
+ exec("systemctl", ["--user", "disable", "--now", basename11(e.plist)]);
27120
27339
  rmSync16(e.plist, { force: true });
27121
27340
  exec("systemctl", ["--user", "daemon-reload"]);
27122
27341
  } else {
@@ -27155,7 +27374,7 @@ async function logout(o) {
27155
27374
  };
27156
27375
  writeConfig(o.home, next);
27157
27376
  const tp = tokenPath(o.home, env);
27158
- if (existsSync28(tp) && readFileSync28(tp, "utf8").trim() === seat.token)
27377
+ if (existsSync28(tp) && readFileSync29(tp, "utf8").trim() === seat.token)
27159
27378
  rmSync16(tp, { force: true });
27160
27379
  const active = next.activeOrg ?? next.org?.slug ?? null;
27161
27380
  const result = { ok: true, email, org: slug, paused, active };
@@ -27233,7 +27452,7 @@ var meter = async (o) => {
27233
27452
  init_config();
27234
27453
  init_meter();
27235
27454
  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";
27455
+ import { existsSync as existsSync29, mkdirSync as mkdirSync25, readFileSync as readFileSync30, rmSync as rmSync17, writeFileSync as writeFileSync24 } from "node:fs";
27237
27456
  import { hostname as hostname11 } from "node:os";
27238
27457
  import { dirname as dirname22 } from "node:path";
27239
27458
  var defaultWhich3 = (cmd) => {
@@ -27753,7 +27972,7 @@ var packCmd = async (o) => {
27753
27972
  };
27754
27973
 
27755
27974
  // 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";
27975
+ import { chmodSync as chmodSync7, mkdirSync as mkdirSync26, readFileSync as readFileSync31, renameSync as renameSync12, rmSync as rmSync19, writeFileSync as writeFileSync26 } from "node:fs";
27757
27976
  import { dirname as dirname23 } from "node:path";
27758
27977
  var isObject13 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
27759
27978
  var messageOf = (text) => {
@@ -27950,7 +28169,7 @@ async function reopenCmd(o) {
27950
28169
 
27951
28170
  // src/commands/route.ts
27952
28171
  init_src();
27953
- import { readFileSync as readFileSync31 } from "node:fs";
28172
+ import { readFileSync as readFileSync32 } from "node:fs";
27954
28173
  import { hostname as hostname12 } from "node:os";
27955
28174
  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
28175
  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 +28352,7 @@ async function answerCmd(o, argv) {
28133
28352
  const words = argv.filter((a) => a !== "--json" && a !== "--stdin");
28134
28353
  const ref = words[0] ?? "";
28135
28354
  const slash = ref.lastIndexOf("/");
28136
- const answer = (fromStdin ? (o.stdin ?? (() => readFileSync31(0, "utf8")))() : words.slice(1).join(" ")).trim();
28355
+ const answer = (fromStdin ? (o.stdin ?? (() => readFileSync32(0, "utf8")))() : words.slice(1).join(" ")).trim();
28137
28356
  if (slash <= 0 || slash === ref.length - 1 || fromStdin && words.length > 1) {
28138
28357
  error(ANSWER_USAGE);
28139
28358
  return 2;
@@ -28178,7 +28397,7 @@ async function instructCmd(o, argv) {
28178
28397
  error(INSTRUCT_USAGE);
28179
28398
  return 2;
28180
28399
  }
28181
- const text = fromStdin ? (o.stdin ?? (() => readFileSync31(0, "utf8")))() : words.slice(1).join(" ");
28400
+ const text = fromStdin ? (o.stdin ?? (() => readFileSync32(0, "utf8")))() : words.slice(1).join(" ");
28182
28401
  const { md, heard } = voice ? splitVoiceStdin(text) : { md: text.trim(), heard: undefined };
28183
28402
  if (!md) {
28184
28403
  error("an instruction needs some text");
@@ -28271,7 +28490,7 @@ async function approveCmd(o, argv) {
28271
28490
  error(APPROVE_USAGE);
28272
28491
  return 2;
28273
28492
  }
28274
- const heard = a.voice ? (o.stdin ?? (() => readFileSync31(0, "utf8")))().trim() : undefined;
28493
+ const heard = a.voice ? (o.stdin ?? (() => readFileSync32(0, "utf8")))().trim() : undefined;
28275
28494
  let nodes;
28276
28495
  let approach;
28277
28496
  if (a.file) {
@@ -28394,7 +28613,7 @@ async function decisionCmd(o, argv) {
28394
28613
  error(DECISION_USAGE);
28395
28614
  return 2;
28396
28615
  }
28397
- const md = seen || routeAlone ? "" : (fromStdin ? (o.stdin ?? (() => readFileSync31(0, "utf8")))() : rest.join(" ")).trim();
28616
+ const md = seen || routeAlone ? "" : (fromStdin ? (o.stdin ?? (() => readFileSync32(0, "utf8")))() : rest.join(" ")).trim();
28398
28617
  if (!seen && !routeAlone && (!md || fromStdin && rest.length > 0)) {
28399
28618
  error(md ? DECISION_USAGE : `${answer ? "an answer" : "an overrule"} needs some text`);
28400
28619
  return 2;
@@ -28573,7 +28792,7 @@ function approvedLine(key, j) {
28573
28792
  function readNodes(o, a) {
28574
28793
  let text;
28575
28794
  try {
28576
- text = a.file ? (o.readFile ?? ((p) => readFileSync31(p, "utf8")))(a.file) : (o.stdin ?? (() => readFileSync31(0, "utf8")))();
28795
+ text = a.file ? (o.readFile ?? ((p) => readFileSync32(p, "utf8")))(a.file) : (o.stdin ?? (() => readFileSync32(0, "utf8")))();
28577
28796
  } catch (e) {
28578
28797
  return { error: e instanceof Error ? e.message : String(e) };
28579
28798
  }
@@ -29010,7 +29229,7 @@ async function seatRevokeCmd(o) {
29010
29229
 
29011
29230
  // src/commands/seatSync.ts
29012
29231
  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";
29232
+ import { existsSync as existsSync31, mkdirSync as mkdirSync27, readFileSync as readFileSync33, readdirSync as readdirSync7, rmSync as rmSync21, writeFileSync as writeFileSync27 } from "node:fs";
29014
29233
  import { platform as platform2 } from "node:os";
29015
29234
  import { dirname as dirname24, join as join33 } from "node:path";
29016
29235
 
@@ -29360,7 +29579,7 @@ function findCookieDb(home, source) {
29360
29579
  return db;
29361
29580
  }
29362
29581
  const localStatePath = join33(root, "Local State");
29363
- const localState = existsSync31(localStatePath) ? readFileSync32(localStatePath, "utf8") : null;
29582
+ const localState = existsSync31(localStatePath) ? readFileSync33(localStatePath, "utf8") : null;
29364
29583
  const wanted = source.profile ?? "Default";
29365
29584
  const { dir, ambiguous } = resolveProfileDir(localState, wanted);
29366
29585
  if (ambiguous)
@@ -29542,7 +29761,7 @@ var seatSync = async (o) => {
29542
29761
  };
29543
29762
  function readSeatToken(home, source) {
29544
29763
  try {
29545
- return readFileSync32(seatTokenPath(home, source), "utf8").trim() || undefined;
29764
+ return readFileSync33(seatTokenPath(home, source), "utf8").trim() || undefined;
29546
29765
  } catch {
29547
29766
  return;
29548
29767
  }
@@ -29628,7 +29847,7 @@ import { homedir as homedir8 } from "node:os";
29628
29847
  import { join as join37, resolve as resolve12 } from "node:path";
29629
29848
 
29630
29849
  // src/sleuth/export.ts
29631
- import { existsSync as existsSync32, mkdirSync as mkdirSync28, readFileSync as readFileSync33, renameSync as renameSync13, writeFileSync as writeFileSync28 } from "node:fs";
29850
+ import { existsSync as existsSync32, mkdirSync as mkdirSync28, readFileSync as readFileSync34, renameSync as renameSync13, writeFileSync as writeFileSync28 } from "node:fs";
29632
29851
  import { dirname as dirname25, join as join34 } from "node:path";
29633
29852
 
29634
29853
  // src/sleuth/graphql.ts
@@ -30183,7 +30402,7 @@ var writeAtomic = (path, body) => {
30183
30402
  var jsonl = (items) => items.length ? `${items.map((i) => JSON.stringify(i)).join(`
30184
30403
  `)}
30185
30404
  ` : "";
30186
- var readJsonl = (path) => readFileSync33(path, "utf8").split(`
30405
+ var readJsonl = (path) => readFileSync34(path, "utf8").split(`
30187
30406
  `).filter((l) => l.trim()).map((l) => JSON.parse(l));
30188
30407
  var CANNOT_QUERY = /Cannot query field "(\w+)" on type "(\w+)"/;
30189
30408
  var TOO_DEEP = /\bmax(imum)?\b.{0,24}\bdepth\b|\btoo deep\b/i;
@@ -30640,9 +30859,9 @@ var exportSleuth = async (o) => {
30640
30859
  // src/sleuth/import.ts
30641
30860
  init_src();
30642
30861
  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";
30862
+ import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync35, readdirSync as readdirSync8, rmSync as rmSync22, statSync as statSync10 } from "node:fs";
30644
30863
  import { tmpdir as tmpdir5 } from "node:os";
30645
- import { basename as basename11, join as join35 } from "node:path";
30864
+ import { basename as basename12, join as join35 } from "node:path";
30646
30865
  var httpFetch = (url, init) => fetch(url, { ...init, body: init.body === "" ? undefined : init.body });
30647
30866
 
30648
30867
  class SleuthImportError extends Error {
@@ -30654,7 +30873,7 @@ class SleuthImportError extends Error {
30654
30873
  }
30655
30874
  var isDir2 = (p) => {
30656
30875
  try {
30657
- return statSync9(p).isDirectory();
30876
+ return statSync10(p).isDirectory();
30658
30877
  } catch {
30659
30878
  return false;
30660
30879
  }
@@ -30668,7 +30887,7 @@ var entries = (p) => {
30668
30887
  };
30669
30888
  function changesRoot(dir) {
30670
30889
  const here = [join35(dir, "data", "changes"), join35(dir, "changes")];
30671
- if (basename11(dir) === "changes")
30890
+ if (basename12(dir) === "changes")
30672
30891
  here.unshift(dir);
30673
30892
  const below = entries(dir).map((e) => join35(dir, e)).filter(isDir2).flatMap((d) => [join35(d, "data", "changes"), join35(d, "changes")]);
30674
30893
  return [...here, ...below].find(isDir2);
@@ -30683,7 +30902,7 @@ function* readChanges(dir) {
30683
30902
  continue;
30684
30903
  for (const name of entries(pdir).filter((f) => f.endsWith(".jsonl"))) {
30685
30904
  const file = join35(pdir, name);
30686
- const lines = readFileSync34(file, "utf8").split(`
30905
+ const lines = readFileSync35(file, "utf8").split(`
30687
30906
  `);
30688
30907
  for (let i = 0;i < lines.length; i++) {
30689
30908
  const text = lines[i].trim();
@@ -30704,7 +30923,7 @@ var systemUnzip = (zip, dest) => {
30704
30923
  function openExport(path, unzip = systemUnzip) {
30705
30924
  let file = false;
30706
30925
  try {
30707
- const s = statSync9(path);
30926
+ const s = statSync10(path);
30708
30927
  if (s.isDirectory())
30709
30928
  return { dir: path, done: () => {} };
30710
30929
  file = s.isFile();
@@ -31094,11 +31313,12 @@ var repoOk = (v) => REPO_RE.test(v);
31094
31313
 
31095
31314
  // src/sleuth/reconcile.ts
31096
31315
  init_src();
31097
- import { readFileSync as readFileSync35, readdirSync as readdirSync9 } from "node:fs";
31316
+ import { readFileSync as readFileSync36, readdirSync as readdirSync9 } from "node:fs";
31098
31317
  import { dirname as dirname26, join as join36 } from "node:path";
31099
31318
  var OFF = 0.1;
31100
31319
  var isObj8 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
31101
31320
  var nums = (v) => Array.isArray(v) ? v.map((x) => typeof x === "number" && Number.isFinite(x) ? x : 0) : [];
31321
+ var sum = (xs) => xs.reduce((a, b) => a + b, 0);
31102
31322
  var MONTH_FILE = /^(\d{4}-(0[1-9]|1[0-2]))\.json$/;
31103
31323
  function sleuthMonth(json, project, month) {
31104
31324
  if (!isObj8(json))
@@ -31108,17 +31328,22 @@ function sleuthMonth(json, project, month) {
31108
31328
  return "no metricFrequency";
31109
31329
  const perDay = nums(freq.datapoints);
31110
31330
  const leadPerDay = isObj8(json.metricLeadTime) ? nums(json.metricLeadTime.datapoints) : [];
31111
- const deploys = Math.round(perDay.reduce((a, b) => a + b, 0));
31331
+ const deploys = Math.round(sum(perDay));
31112
31332
  let weighted = 0;
31113
31333
  for (let i = 0;i < perDay.length; i++)
31114
31334
  weighted += perDay[i] * (leadPerDay[i] ?? 0);
31335
+ const failed = isObj8(json.metricFailureRate) ? Math.round(sum(nums(json.metricFailureRate.datapoints))) : null;
31336
+ const failedFor = isObj8(json.metricMttr) ? sum(nums(json.metricMttr.datapoints)) : null;
31115
31337
  return {
31116
31338
  project,
31117
31339
  month,
31118
31340
  environment: typeof json.environment === "string" ? json.environment.toLowerCase() : "",
31119
31341
  deploys,
31120
- flags: nums(freq.ffDeploys).reduce((a, b) => a + b, 0),
31121
- lead: deploys ? Math.round(weighted / deploys) : null
31342
+ flags: sum(nums(freq.ffDeploys)),
31343
+ lead: deploys ? Math.round(weighted / deploys) : null,
31344
+ failed,
31345
+ failureRate: failed !== null && deploys ? failed / deploys : null,
31346
+ mttr: failed && failedFor !== null ? Math.round(failedFor / failed) : null
31122
31347
  };
31123
31348
  }
31124
31349
  function metricsRoot(dir) {
@@ -31146,7 +31371,7 @@ function readMetrics(dir) {
31146
31371
  continue;
31147
31372
  let json;
31148
31373
  try {
31149
- json = JSON.parse(readFileSync35(join36(root, project, name), "utf8"));
31374
+ json = JSON.parse(readFileSync36(join36(root, project, name), "utf8"));
31150
31375
  } catch {
31151
31376
  errors.push(`${project}/${name}: not JSON`);
31152
31377
  continue;
@@ -31208,24 +31433,43 @@ ${env.env.slug}
31208
31433
  ${s.month}`);
31209
31434
  if (!s.deploys && !o?.deploys)
31210
31435
  continue;
31436
+ const sledsDeploys = o?.deploys ?? 0;
31211
31437
  const sledsLead = o?.lead?.workingByDeploy ?? null;
31212
- const dDeploys = delta(s.deploys, o?.deploys ?? 0);
31438
+ const dDeploys = delta(s.deploys, sledsDeploys);
31213
31439
  const dLead = s.lead !== null && sledsLead !== null ? delta(s.lead, sledsLead) : null;
31440
+ const sledsFailed = o ? o.failed ?? null : 0;
31441
+ const sledsRate = sledsFailed !== null && sledsDeploys ? sledsFailed / sledsDeploys : null;
31442
+ const sledsRecover = o?.recover ?? null;
31443
+ const compared = s.failed !== null && sledsFailed !== null;
31444
+ const dRate = compared && s.failureRate !== null && sledsRate !== null ? delta(s.failureRate, sledsRate) : null;
31445
+ const dRecover = s.mttr !== null && sledsRecover !== null ? delta(s.mttr, sledsRecover.mean) : null;
31446
+ const over = (d) => d !== null && Math.abs(d) > OFF;
31214
31447
  rows.push({
31215
31448
  project: s.project,
31216
31449
  repo,
31217
31450
  environment: env.env.slug,
31218
31451
  month: s.month,
31219
- sleuth: { deploys: s.deploys, lead: s.lead },
31452
+ sleuth: {
31453
+ deploys: s.deploys,
31454
+ lead: s.lead,
31455
+ failed: s.failed,
31456
+ failureRate: s.failureRate,
31457
+ mttr: s.mttr
31458
+ },
31220
31459
  sleds: {
31221
- deploys: o?.deploys ?? 0,
31460
+ deploys: sledsDeploys,
31222
31461
  prs: o?.prs ?? 0,
31223
31462
  missing: o?.missing ?? 0,
31224
- lead: o?.lead ?? null
31463
+ lead: o?.lead ?? null,
31464
+ failed: sledsFailed,
31465
+ failureRate: sledsRate,
31466
+ recover: sledsRecover
31225
31467
  },
31226
31468
  deltaDeploys: dDeploys,
31227
31469
  deltaLead: dLead,
31228
- off: dDeploys === null || Math.abs(dDeploys) > OFF || dLead !== null && Math.abs(dLead) > OFF
31470
+ deltaFailureRate: dRate,
31471
+ deltaRecover: dRecover,
31472
+ off: dDeploys === null || over(dDeploys) || over(dLead) || over(dRate) || over(dRecover) || compared && !s.failed !== !sledsFailed
31229
31473
  });
31230
31474
  }
31231
31475
  const flagOnly = new Map;
@@ -31295,6 +31539,65 @@ async function reconcileSleuth(o) {
31295
31539
  }
31296
31540
  var hours = (s) => s === null || s === undefined ? "—" : `${(s / 3600).toFixed(1)}h`;
31297
31541
  var pct = (d, sledsHas) => d === null ? sledsHas ? "new" : "—" : `${d >= 0 ? "+" : ""}${Math.round(d * 100)}%`;
31542
+ var rate = (x) => x === null ? "—" : `${(x * 100).toFixed(1)}%`;
31543
+ function columns(head, body) {
31544
+ const widths = head.map((h, i) => Math.max(h.length, ...body.map((row) => row[i].length)));
31545
+ const fmt = (row) => ` ${row.map((c, i) => i < 2 ? c.padEnd(widths[i]) : c.padStart(widths[i])).join(" ")}`.trimEnd();
31546
+ return [fmt(head), ...body.map(fmt)];
31547
+ }
31548
+ function stabilityTable(r) {
31549
+ if (!r.rows.length)
31550
+ return [];
31551
+ if (r.rows.every((x) => x.sleuth.failed === null))
31552
+ return [
31553
+ "",
31554
+ " Change failure rate and time to recover not compared: Sleuth's series has no metricFailureRate or metricMttr — export them again with export_metrics.sh."
31555
+ ];
31556
+ if (r.rows.every((x) => x.sleds.failed === null))
31557
+ return [
31558
+ "",
31559
+ " Change failure rate and time to recover not compared: SLEDS did not answer with them — its deploy is older than SL-2202."
31560
+ ];
31561
+ const failing = r.rows.filter((x) => (x.sleuth.failed ?? 0) > 0 || (x.sleds.failed ?? 0) > 0);
31562
+ const out = [
31563
+ "",
31564
+ "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",
31565
+ ""
31566
+ ];
31567
+ if (!failing.length)
31568
+ return [...out, " (no failure on either side)"];
31569
+ const n = (x) => x === null ? "—" : String(x);
31570
+ return [
31571
+ ...out,
31572
+ ...columns([
31573
+ "project",
31574
+ "month",
31575
+ "Sleuth failed",
31576
+ "SLEDS failed",
31577
+ "Sleuth rate",
31578
+ "SLEDS rate",
31579
+ "Δ",
31580
+ "Sleuth recover",
31581
+ "SLEDS recover",
31582
+ "Δ",
31583
+ "median",
31584
+ ""
31585
+ ], failing.map((x) => [
31586
+ x.project,
31587
+ x.month,
31588
+ n(x.sleuth.failed),
31589
+ n(x.sleds.failed),
31590
+ rate(x.sleuth.failureRate),
31591
+ rate(x.sleds.failureRate),
31592
+ pct(x.deltaFailureRate, (x.sleds.failed ?? 0) > 0),
31593
+ hours(x.sleuth.mttr),
31594
+ hours(x.sleds.recover?.mean),
31595
+ pct(x.deltaRecover, false),
31596
+ hours(x.sleds.recover?.median),
31597
+ x.off ? "!" : ""
31598
+ ]))
31599
+ ];
31600
+ }
31298
31601
  function reconcileTable(r) {
31299
31602
  const head = [
31300
31603
  "project",
@@ -31324,16 +31627,14 @@ function reconcileTable(r) {
31324
31627
  x.sleds.missing ? `${x.sleds.missing} of ${x.sleds.prs}` : "",
31325
31628
  x.off ? "!" : ""
31326
31629
  ]);
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
31630
  const out = [
31330
31631
  `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
31632
  "",
31332
- fmt(head),
31333
- ...body.map(fmt)
31633
+ ...columns(head, body)
31334
31634
  ];
31335
31635
  if (!r.rows.length)
31336
31636
  out.push(" (no month with deploys on either side)");
31637
+ out.push(...stabilityTable(r));
31337
31638
  if (r.skipped.length) {
31338
31639
  out.push("", " not compared:");
31339
31640
  for (const s of r.skipped)
@@ -31729,8 +32030,8 @@ var reconcileCmd = async (o, { words, flags, all }) => {
31729
32030
 
31730
32031
  // src/commands/specEvent.ts
31731
32032
  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";
32033
+ import { readFileSync as readFileSync37, statSync as statSync11 } from "node:fs";
32034
+ import { basename as basename13, isAbsolute as isAbsolute7, relative as relative2 } from "node:path";
31734
32035
  var HOOK_STDIN_TIMEOUT_MS3 = 1000;
31735
32036
  var ESTIMATE_TIMEOUT_MS = 4000;
31736
32037
  var MIN_SPEC_CHARS = 200;
@@ -31743,12 +32044,12 @@ function isSpecPath(path) {
31743
32044
  return false;
31744
32045
  if (NOT_SPEC.test(path))
31745
32046
  return false;
31746
- return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename12(path));
32047
+ return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename13(path));
31747
32048
  }
31748
32049
  function specTitle(body, path) {
31749
32050
  const m = /^#\s+(.+?)\s*$/m.exec(body);
31750
32051
  const t = m?.[1]?.trim();
31751
- return (t && t.length > 0 ? t : basename12(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
32052
+ return (t && t.length > 0 ? t : basename13(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
31752
32053
  }
31753
32054
  function looksLikeSpec(body) {
31754
32055
  if (body.trim().length < MIN_SPEC_CHARS)
@@ -31783,9 +32084,9 @@ function projectKey(filePath, cwd) {
31783
32084
  }
31784
32085
  function readFileOrNull(path) {
31785
32086
  try {
31786
- if (statSync10(path).size > 2000000)
32087
+ if (statSync11(path).size > 2000000)
31787
32088
  return null;
31788
- return readFileSync36(path, "utf8");
32089
+ return readFileSync37(path, "utf8");
31789
32090
  } catch {
31790
32091
  return null;
31791
32092
  }
@@ -31811,7 +32112,7 @@ var specEvent = async (o) => {
31811
32112
  const spec = {
31812
32113
  title: specTitle(body, input.filePath),
31813
32114
  body: body.slice(0, MAX_SPEC_CHARS),
31814
- repoHint: input.cwd ? basename12(input.cwd) : undefined
32115
+ repoHint: input.cwd ? basename13(input.cwd) : undefined
31815
32116
  };
31816
32117
  try {
31817
32118
  const res = await (o.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
@@ -32130,7 +32431,7 @@ var announce = (o, events) => {
32130
32431
 
32131
32432
  // src/commands/stopEvent.ts
32132
32433
  init_meter();
32133
- import { existsSync as existsSync34, readFileSync as readFileSync37 } from "node:fs";
32434
+ import { existsSync as existsSync34, readFileSync as readFileSync38 } from "node:fs";
32134
32435
 
32135
32436
  // src/transcript.ts
32136
32437
  var isObject16 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
@@ -32231,7 +32532,7 @@ async function postTranscript(o, payload, now) {
32231
32532
  }
32232
32533
  if (!src)
32233
32534
  return false;
32234
- const read = o.readFile ?? ((p) => existsSync34(p) ? readFileSync37(p, "utf8") : null);
32535
+ const read = o.readFile ?? ((p) => existsSync34(p) ? readFileSync38(p, "utf8") : null);
32235
32536
  let text;
32236
32537
  try {
32237
32538
  text = read(path);
@@ -32309,7 +32610,7 @@ var stopEvent = async (o) => {
32309
32610
 
32310
32611
  // src/commands/uninstall.ts
32311
32612
  import { spawnSync as spawnSync9 } from "node:child_process";
32312
- import { existsSync as existsSync35, readFileSync as readFileSync38, rmSync as rmSync23 } from "node:fs";
32613
+ import { existsSync as existsSync35, readFileSync as readFileSync39, rmSync as rmSync23 } from "node:fs";
32313
32614
  init_config();
32314
32615
  init_meter();
32315
32616
  init_settings();
@@ -32326,7 +32627,7 @@ var planUninstall = (o) => {
32326
32627
  const changes = [];
32327
32628
  const remove = [];
32328
32629
  const codexPath = codexConfigPath(o.home);
32329
- const codex = user && existsSync35(codexPath) && removeCodexProvider(readFileSync38(codexPath, "utf8")) !== readFileSync38(codexPath, "utf8");
32630
+ const codex = user && existsSync35(codexPath) && removeCodexProvider(readFileSync39(codexPath, "utf8")) !== readFileSync39(codexPath, "utf8");
32330
32631
  if (codex)
32331
32632
  changes.push({ path: codexPath, what: 'removes the "sleds" provider' });
32332
32633
  const priorStatusLine = user ? cfg.priorStatusLine : rec?.priorStatusLine;
@@ -32463,7 +32764,7 @@ var uninstall2 = async (o) => {
32463
32764
  init_server();
32464
32765
  import { existsSync as existsSync36 } from "node:fs";
32465
32766
  import { homedir as homedir9, userInfo as userInfo4 } from "node:os";
32466
- import { basename as basename13 } from "node:path";
32767
+ import { basename as basename14 } from "node:path";
32467
32768
  init_config();
32468
32769
  init_state();
32469
32770
  init_meter();
@@ -32528,7 +32829,7 @@ var realPidAlive4 = (pid) => {
32528
32829
  };
32529
32830
  function machineClient(home, env) {
32530
32831
  const src = meterSource(home, undefined, { env });
32531
- return src ? fetchClient({ ...src, version: "0.1.71" }) : null;
32832
+ return src ? fetchClient({ ...src, version: "0.1.72" }) : null;
32532
32833
  }
32533
32834
  async function noteAnswer2(home, a, now) {
32534
32835
  try {
@@ -32540,7 +32841,7 @@ async function noteAnswer2(home, a, now) {
32540
32841
  }
32541
32842
  function busyEngines(files) {
32542
32843
  return files.map((f) => ({
32543
- name: basename13(f, ".json"),
32844
+ name: basename14(f, ".json"),
32544
32845
  running: readState(f).runs.filter(isRunning).length
32545
32846
  })).filter((e) => e.running > 0);
32546
32847
  }
@@ -32722,8 +33023,8 @@ async function maybeNotice(cmd, argv, o) {
32722
33023
 
32723
33024
  // src/commands/verify.ts
32724
33025
  init_meter();
32725
- import { readFileSync as readFileSync39, statSync as statSync11 } from "node:fs";
32726
- import { basename as basename14, extname as extname2 } from "node:path";
33026
+ import { readFileSync as readFileSync40, statSync as statSync12 } from "node:fs";
33027
+ import { basename as basename15, extname as extname2 } from "node:path";
32727
33028
  var jobIdFromTarget = (target) => {
32728
33029
  const t = target.trim();
32729
33030
  const m = /SLEDS-Attest:.*\bjob=([^\s]+)/.exec(t);
@@ -32848,17 +33149,17 @@ async function verdictCmd2(o) {
32848
33149
  let screenshot;
32849
33150
  if (a.file) {
32850
33151
  try {
32851
- if (!o.readFile && statSync11(a.file).size > SHOT_MAX_BYTES2) {
33152
+ if (!o.readFile && statSync12(a.file).size > SHOT_MAX_BYTES2) {
32852
33153
  error(`${a.file}: a screenshot is at most 4 MB`);
32853
33154
  return 1;
32854
33155
  }
32855
- const bytes = (o.readFile ?? readFileSync39)(a.file);
33156
+ const bytes = (o.readFile ?? readFileSync40)(a.file);
32856
33157
  if (bytes.byteLength > SHOT_MAX_BYTES2) {
32857
33158
  error(`${a.file}: a screenshot is at most 4 MB`);
32858
33159
  return 1;
32859
33160
  }
32860
33161
  screenshot = {
32861
- name: basename14(a.file),
33162
+ name: basename15(a.file),
32862
33163
  mime: shotMime2(a.file),
32863
33164
  content: bytes.toString("base64")
32864
33165
  };
@@ -32982,7 +33283,7 @@ var webhooksCmd = async (o) => {
32982
33283
 
32983
33284
  // src/config.ts
32984
33285
  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";
33286
+ import { chmodSync as chmodSync8, existsSync as existsSync37, mkdirSync as mkdirSync29, readFileSync as readFileSync41, renameSync as renameSync14, writeFileSync as writeFileSync29 } from "node:fs";
32986
33287
  import { join as join38, resolve as resolve13 } from "node:path";
32987
33288
  var configDir2 = (home, env = process.env) => {
32988
33289
  const o = env.SLEDS_HOME?.trim();
@@ -33153,17 +33454,17 @@ var readConfig2 = (home, env = process.env) => {
33153
33454
  const p = configPath2(home, env);
33154
33455
  if (!existsSync37(p))
33155
33456
  return {};
33156
- return parseConfig2(JSON.parse(readFileSync40(p, "utf8")));
33457
+ return parseConfig2(JSON.parse(readFileSync41(p, "utf8")));
33157
33458
  };
33158
33459
 
33159
33460
  // src/musher.ts
33160
- import { basename as basename15, dirname as dirname27, join as join39 } from "node:path";
33461
+ import { basename as basename16, dirname as dirname27, join as join39 } from "node:path";
33161
33462
  var MUSHER_LABEL2 = "ai.sleds.musher";
33162
33463
  var musherLabel2 = (env = process.env) => {
33163
33464
  const sh = env.SLEDS_HOME?.trim();
33164
33465
  if (!sh)
33165
33466
  return MUSHER_LABEL2;
33166
- const tag = basename15(sh).replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]+/g, "-") || "seat";
33467
+ const tag = basename16(sh).replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]+/g, "-") || "seat";
33167
33468
  return `${MUSHER_LABEL2}.${tag}`;
33168
33469
  };
33169
33470
  var musherPlistPath2 = (home, env = process.env) => join39(home, "Library", "LaunchAgents", `${musherLabel2(env)}.plist`);
@@ -33249,7 +33550,7 @@ var defaultExec5 = (cmd, args) => {
33249
33550
  };
33250
33551
 
33251
33552
  // src/settings.ts
33252
- import { basename as basename16, dirname as dirname28, join as join41, resolve as resolve14 } from "node:path";
33553
+ import { basename as basename17, dirname as dirname28, join as join41, resolve as resolve14 } from "node:path";
33253
33554
  var withSeatEnv2 = (command, home, env = process.env, org) => {
33254
33555
  const parts = [];
33255
33556
  const sh = env.SLEDS_HOME?.trim();
@@ -33465,6 +33766,12 @@ commands:
33465
33766
  --json SLEDS's answer as it came
33466
33767
  defect <key> "<what is wrong>" The same as verify fail <key> "\u2026" --defect
33467
33768
  (--same-engineer, --file, --json).
33769
+ attach <key> --file <path> Put a file from disk on the item (4 MB at most) and print its link \u2014
33770
+ a preview screenshot for the PR's look, a spec, a prototype.
33771
+ --kind <k> screenshot \xB7 prototype \xB7 spec \xB7 doc \xB7 other (read from the
33772
+ name when absent)
33773
+ --mock mark it as the item's mock
33774
+ --json SLEDS's answer as it came
33468
33775
  off Switch Claude Code back to your seat. Restores whatever \`on\` replaced.
33469
33776
  uninstall The same as \`sleds init --undo\`: lists what SLEDS put in your user settings and
33470
33777
  asks first (--yes skips), then takes it out. Keeps ~/.sleds-token.
@@ -33621,7 +33928,7 @@ var main = async (argv) => {
33621
33928
  now: Date.now(),
33622
33929
  stderr: (line) => console.error(line),
33623
33930
  isTTY: !!process.stderr.isTTY,
33624
- version: "0.1.71"
33931
+ version: "0.1.72"
33625
33932
  });
33626
33933
  switch (cmd) {
33627
33934
  case "update":
@@ -33852,6 +34159,8 @@ var main = async (argv) => {
33852
34159
  return verify2({ home, target: process.argv.slice(3).join(" ") || undefined });
33853
34160
  case "defect":
33854
34161
  return defectCmd({ home, argv: argv.slice(1) });
34162
+ case "attach":
34163
+ return attachCmd({ home, argv: argv.slice(1) });
33855
34164
  case "uninstall":
33856
34165
  return uninstall2({
33857
34166
  home,
@@ -33889,7 +34198,7 @@ ${renderHelpText(argv[1])}`);
33889
34198
  case "version":
33890
34199
  case "--version":
33891
34200
  case "-v":
33892
- console.log("sleds 0.1.71");
34201
+ console.log("sleds 0.1.72");
33893
34202
  return 0;
33894
34203
  default:
33895
34204
  console.error(`unknown command: ${cmd}