@sleds/cli 0.1.46 → 0.1.47

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 (3) hide show
  1. package/README.md +4 -2
  2. package/dist/sleds.mjs +450 -229
  3. package/package.json +2 -1
package/dist/sleds.mjs CHANGED
@@ -295,7 +295,6 @@ var init_sledSort = __esm(() => {
295
295
  function slugify(text, max = 63) {
296
296
  return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, max);
297
297
  }
298
-
299
298
  // ../../packages/shared/src/seat/agents.ts
300
299
  var init_agents = () => {};
301
300
  // ../../packages/shared/src/seat/burn.ts
@@ -2086,7 +2085,7 @@ ${state}`)}, fillcolor="${fill}", color="${border}"${style}];`);
2086
2085
  `)}
2087
2086
  `;
2088
2087
  }
2089
- var ROUTE_APPROACH_MAX = 2000, PLAN_APPROACH_MAX = 1200, PLAN_LIST_MAX = 8, PLAN_LINE_MAX = 240, CONTROL, MAX_NODES = 24, DEPTH_WARN = 4, norm2 = (s) => s.trim().toUpperCase(), AREA_ROOTS, NOT_AREAS, sameRepo = (a, b) => a.length === 0 || b.length === 0 || a.some((r) => b.includes(r)), DOT_COLORS, ROUTE_DRAFT_RULE = "Draft the route: PR-sized nodes, file-disjoint where they run in parallel, each with a title, the files or areas it touches, the repo, and the nodes it waits on (by key: A, B, C…). Prefer wide waves over chains deeper than four. Make the tough calls once, so each node's session follows them: an `approach` paragraph for the whole route, and on each node a `plan` — its approach, what it `provides` that later nodes rely on (names, shapes, files), what it `expects` from the nodes it waits on, and the `doneChecks` that say it landed. Show the graph and the plans as text and ask for a yes; file nothing before it. An item with children takes no nodes: its children are the work, and their order lives in their blockedBy. Then `route {q, approach, nodes: [{key, title, touches, repos, blockedBy, plan: {approach, provides, expects, doneChecks}}], confirm: true}`.";
2088
+ var ROUTE_APPROACH_MAX = 2000, PLAN_APPROACH_MAX = 1200, PLAN_LIST_MAX = 8, PLAN_LINE_MAX = 240, CONTROL, MAX_NODES = 24, DEPTH_WARN = 4, norm2 = (s) => s.trim().toUpperCase(), AREA_ROOTS, NOT_AREAS, sameRepo = (a, b) => a.length === 0 || b.length === 0 || a.some((r) => b.includes(r)), DOT_COLORS, ROUTE_DRAFT_RULE = "Plan the route: PR-sized nodes, file-disjoint where they run in parallel, each with a title, the files or areas it touches, the repo, and the nodes it waits on (by key: A, B, C…). Prefer wide waves over chains deeper than four. Make the tough calls once, so each node's session follows them: an `approach` paragraph for the whole route, and on each node a `plan` — its approach, what it `provides` that later nodes rely on (names, shapes, files), what it `expects` from the nodes it waits on, and the `doneChecks` that say it landed. Show the graph and the plans as text and ask for a yes; file nothing before it. An item with children takes no nodes: its children are the work, and their order lives in their blockedBy. Then `route {q, approach, nodes: [{key, title, touches, repos, blockedBy, plan: {approach, provides, expects, doneChecks}}], confirm: true}`.";
2090
2089
  var init_route = __esm(() => {
2091
2090
  CONTROL = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g;
2092
2091
  AREA_ROOTS = new Set(["apps", "packages", "services", "libs", "crates", "modules"]);
@@ -2598,7 +2597,11 @@ function failureText(e, timeoutMs) {
2598
2597
  function fetchClient(o) {
2599
2598
  const fetchFn = o.fetchFn ?? fetch;
2600
2599
  const base = o.proxyUrl.replace(/\/+$/, "");
2601
- const headers = { "content-type": "application/json", authorization: `Bearer ${o.token}` };
2600
+ const headers = {
2601
+ "content-type": "application/json",
2602
+ authorization: `Bearer ${o.token}`,
2603
+ ...o.version ? { "x-sleds-version": o.version } : {}
2604
+ };
2602
2605
  const timeout = () => AbortSignal.timeout(o.timeoutMs ?? MCP_TIMEOUT_MS);
2603
2606
  return {
2604
2607
  async post(path, body) {
@@ -3411,7 +3414,7 @@ An engine (or you) takes a ready node with \`sled {take: "${key}/<key>"}\`; Run
3411
3414
  }
3412
3415
  if (nodes.length > 0)
3413
3416
  return {
3414
- text: "Show the person the graph as text and ask for a yes; then call route again with the same nodes and confirm: true. With nobody to ask (a drafting session), call again with propose: true instead.",
3417
+ text: "Show the person the graph as text and ask for a yes; then call route again with the same nodes and confirm: true. With nobody to ask (a planning session), call again with propose: true instead.",
3415
3418
  isError: true
3416
3419
  };
3417
3420
  const r = await ctx.client.get(`/proxy/route?q=${encodeURIComponent(q)}`);
@@ -3425,7 +3428,7 @@ An engine (or you) takes a ready node with \`sled {take: "${key}/<key>"}\`; Run
3425
3428
  const key = str5(r.key) ?? q;
3426
3429
  const n = Array.isArray(proposed.nodes) ? proposed.nodes.length : 0;
3427
3430
  return {
3428
- text: `${proposalText(str5(r.text)) || `${key} · route drafted, not filed — ${n} nodes`}
3431
+ text: `${proposalText(str5(r.text)) || `${key} · route planned, not filed — ${n} nodes`}
3429
3432
 
3430
3433
  ${PROPOSED_NEXT(key)}`,
3431
3434
  structured: { key, nodes: 0, proposed: n }
@@ -4434,7 +4437,7 @@ async function handleLine(line, ctx) {
4434
4437
  return isNotification ? null : errorResponse(id, -32601, `method not found: ${method}`);
4435
4438
  }
4436
4439
  }
4437
- var PROTOCOL_VERSION = "2025-06-18", SERVER_INFO, SERVER_INSTRUCTIONS, MCP_TIMEOUT_MS = 5000, sourceSchema, specSchema, TOOLS, VIEW_TOOLS, NOT_SET_UP, UNREACHABLE, isObject4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, str5 = (v) => typeof v === "string" ? v : undefined, errorMessage = (j) => isObject4(j?.error) ? str5(j.error.message) : str5(j?.error), proposalText = (t) => (t ?? "").replace(/\n*Nothing runs until a person says yes:[^\n]*$/, ""), PROPOSED_NEXT = (key) => `Nothing runs until a person approves it: Approve in the SLEDS app or on the item page, or \`sleds route approve ${key}\`. If you are a drafting session, stop here.`, strList = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : undefined, RELATION_HOWS, UI_RESOURCES, response = (id, result) => JSON.stringify({ jsonrpc: "2.0", id, result }), errorResponse = (id, code, message) => JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
4440
+ var PROTOCOL_VERSION = "2025-06-18", SERVER_INFO, SERVER_INSTRUCTIONS, MCP_TIMEOUT_MS = 5000, sourceSchema, specSchema, TOOLS, VIEW_TOOLS, NOT_SET_UP, UNREACHABLE, isObject4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, str5 = (v) => typeof v === "string" ? v : undefined, errorMessage = (j) => isObject4(j?.error) ? str5(j.error.message) : str5(j?.error), proposalText = (t) => (t ?? "").replace(/\n*Nothing runs until a person says yes:[^\n]*$/, ""), PROPOSED_NEXT = (key) => `Nothing runs until a person approves it: Approve in the SLEDS app or on the item page, or \`sleds route approve ${key}\`. If you are a planning session, stop here.`, strList = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : undefined, RELATION_HOWS, UI_RESOURCES, response = (id, result) => JSON.stringify({ jsonrpc: "2.0", id, result }), errorResponse = (id, code, message) => JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
4438
4441
  var init_server = __esm(() => {
4439
4442
  init_worth();
4440
4443
  init_intake();
@@ -4722,7 +4725,7 @@ var init_server = __esm(() => {
4722
4725
  },
4723
4726
  {
4724
4727
  name: "route",
4725
- description: "The route — an item's internal order as PR-sized nodes with blockers (spec 26). With only `q`: the route as filed (each node's state, what it waits on, the ready set, where each run can be watched), or, when none is filed, the pack and the drafting rule so you draft one. Drafting: PR-sized nodes, file-disjoint where they run in parallel, each with a title, the files or areas it touches, the repo, and the nodes it waits on by key (A, B, C…); prefer wide waves over chains deeper than four. Make the tough calls once: an `approach` for the route and a `plan` on each node (its approach, what it provides to later nodes, what it expects from the nodes it waits on, its done-checks), so each node's session follows them instead of re-planning. Show the graph and the plans as text and ask for a yes; file nothing before it. Then call again with `nodes` and `confirm: true`. An item with children is refused nodes — its children are the work: set their order with blockedBy on them. The item lands only when every child has landed. Re-drafting shows what changed; a node with a run or a PR is never removed. Ready is computed from landed blockers, never set. With nobody to ask (a drafting session an engine started, spec 26 §5.1): call with `nodes` and `propose: true` instead — the route is held on the item for a person's yes and nothing is filed; then stop. A read of an item with a proposal shows it as drafted, not filed.",
4728
+ description: "The route — an item's internal order as PR-sized nodes with blockers (spec 26). With only `q`: the route as filed (each node's state, what it waits on, the ready set, where each run can be watched), or, when none is filed, the pack and the planning rule so you plan one (Plan route — the AI step; a person's hand editor on the item page is Edit route). Planning: PR-sized nodes, file-disjoint where they run in parallel, each with a title, the files or areas it touches, the repo, and the nodes it waits on by key (A, B, C…); prefer wide waves over chains deeper than four. Make the tough calls once: an `approach` for the route and a `plan` on each node (its approach, what it provides to later nodes, what it expects from the nodes it waits on, its done-checks), so each node's session follows them instead of re-planning. Show the graph and the plans as text and ask for a yes; file nothing before it. Then call again with `nodes` and `confirm: true`. An item with children is refused nodes — its children are the work: set their order with blockedBy on them. The item lands only when every child has landed. Planning it again shows what changed; a node with a run or a PR is never removed. Ready is computed from landed blockers, never set. With nobody to ask (a planning session an engine started, spec 26 §5.1): call with `nodes` and `propose: true` instead — the route is held on the item for a person's yes and nothing is filed; then stop. A read of an item with a proposal shows it as planned, not filed.",
4726
4729
  inputSchema: {
4727
4730
  type: "object",
4728
4731
  properties: {
@@ -4733,7 +4736,7 @@ var init_server = __esm(() => {
4733
4736
  },
4734
4737
  nodes: {
4735
4738
  type: "array",
4736
- description: "The drafted nodes, in route order. Keys are minted (A, B, C…) when absent.",
4739
+ description: "The planned nodes, in route order. Keys are minted (A, B, C…) when absent.",
4737
4740
  items: {
4738
4741
  type: "object",
4739
4742
  properties: {
@@ -4789,7 +4792,7 @@ var init_server = __esm(() => {
4789
4792
  },
4790
4793
  propose: {
4791
4794
  type: "boolean",
4792
- description: "true holds the nodes on the item as a drafted route, waiting for a person's yes; nothing is filed. For a drafting session with nobody at the keyboard — with a person here, ask and confirm instead."
4795
+ description: "true holds the nodes on the item as a planned route, waiting for a person's yes; nothing is filed. For a planning session with nobody at the keyboard — with a person here, ask and confirm instead."
4793
4796
  },
4794
4797
  disjoint: {
4795
4798
  type: "boolean",
@@ -6455,11 +6458,15 @@ var init_flags = () => {};
6455
6458
  // ../../packages/shared/src/sentry/sentry.ts
6456
6459
  var init_sentry = () => {};
6457
6460
 
6461
+ // ../../packages/shared/src/pack/outside.ts
6462
+ var init_outside = () => {};
6463
+
6458
6464
  // ../../packages/shared/src/pack/pack.ts
6459
6465
  var init_pack = __esm(() => {
6460
6466
  init_flags();
6461
6467
  init_profile();
6462
6468
  init_sentry();
6469
+ init_outside();
6463
6470
  init_setup();
6464
6471
  });
6465
6472
  // ../../packages/shared/src/pack/prHeader.ts
@@ -6471,6 +6478,7 @@ var init_pack2 = __esm(() => {
6471
6478
  init_setup();
6472
6479
  init_pack();
6473
6480
  init_prHeader();
6481
+ init_outside();
6474
6482
  });
6475
6483
 
6476
6484
  // ../../packages/shared/src/deploys/deploys.ts
@@ -8588,8 +8596,8 @@ var init_seat = __esm(() => {
8588
8596
  });
8589
8597
 
8590
8598
  // src/index.ts
8591
- import { realpathSync as realpathSync3 } from "fs";
8592
- import { homedir, platform as platform3 } from "os";
8599
+ import { existsSync as existsSync31, realpathSync as realpathSync3 } from "fs";
8600
+ import { homedir as homedir3, platform as platform3 } from "os";
8593
8601
  import { fileURLToPath } from "url";
8594
8602
 
8595
8603
  // ../../packages/shared/src/index.ts
@@ -9930,7 +9938,7 @@ import {
9930
9938
  writeFileSync as writeFileSync17
9931
9939
  } from "node:fs";
9932
9940
  import { tmpdir } from "node:os";
9933
- import { join as join20, resolve as resolve9 } from "node:path";
9941
+ import { join as join21, resolve as resolve9 } from "node:path";
9934
9942
 
9935
9943
  // src/agentMcp.ts
9936
9944
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -10387,20 +10395,37 @@ import { basename as basename3, dirname as dirname10, join as join12 } from "nod
10387
10395
 
10388
10396
  // src/runners/sandbox.ts
10389
10397
  var absRule = (dir) => `/${dir.replace(/\/+$/, "")}/**`;
10398
+ var gitDenyWrite = (gitCommonDir) => {
10399
+ const g = gitCommonDir.replace(/\/+$/, "");
10400
+ return {
10401
+ files: [`${g}/config`, `${g}/config.worktree`, `${g}/worktrees/*/config.worktree`],
10402
+ dirs: [`${g}/hooks`]
10403
+ };
10404
+ };
10390
10405
  var sandboxSettings = (o) => {
10391
10406
  const domains = [...new Set(o.allow ?? [])];
10407
+ const git = gitDenyWrite(o.gitCommonDir);
10392
10408
  return {
10393
10409
  sandbox: {
10394
10410
  enabled: true,
10395
10411
  allowUnsandboxedCommands: false,
10396
10412
  failIfUnavailable: true,
10397
- filesystem: { denyRead: [...o.denyRead], allowWrite: [o.gitCommonDir] },
10413
+ filesystem: {
10414
+ denyRead: [...o.denyRead],
10415
+ allowWrite: [o.gitCommonDir],
10416
+ denyWrite: [...git.files, ...git.dirs]
10417
+ },
10398
10418
  network: { allowedDomains: domains, strictAllowlist: true }
10399
10419
  },
10400
10420
  permissions: {
10401
- deny: o.denyRead.flatMap((d) => [`Read(${absRule(d)})`, `Edit(${absRule(d)})`]),
10421
+ deny: [
10422
+ ...o.denyRead.flatMap((d) => [`Read(${absRule(d)})`, `Edit(${absRule(d)})`]),
10423
+ ...git.files.map((f) => `Edit(/${f})`),
10424
+ ...git.dirs.map((d) => `Edit(${absRule(d)})`)
10425
+ ],
10402
10426
  allow: [`Edit(${absRule(o.gitCommonDir)})`, ...domains.map((d) => `WebFetch(domain:${d})`)]
10403
- }
10427
+ },
10428
+ env: { CLAUDE_CODE_SUBPROCESS_ENV_SCRUB: "1" }
10404
10429
  };
10405
10430
  };
10406
10431
  var sandboxAgentKind = (agent) => {
@@ -11131,7 +11156,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
11131
11156
  name: flags.name,
11132
11157
  os: host.os ?? process.platform,
11133
11158
  runner: flags.runner,
11134
- version: host.version ?? "0.1.46" ?? "dev",
11159
+ version: host.version ?? "0.1.47" ?? "dev",
11135
11160
  running: live.length,
11136
11161
  items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
11137
11162
  ...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
@@ -11148,13 +11173,28 @@ function beatBody(state, flags, host = {}, cap = {}) {
11148
11173
  } : {}
11149
11174
  };
11150
11175
  }
11176
+ var versionOrNull = (v) => v === null || typeof v === "string";
11177
+ function updateOf(v) {
11178
+ if (typeof v !== "object" || v === null)
11179
+ return;
11180
+ const { target, minimum, manifestUrl } = v;
11181
+ return versionOrNull(target) && versionOrNull(minimum) && versionOrNull(manifestUrl) ? { target, minimum, manifestUrl } : undefined;
11182
+ }
11151
11183
  async function postBeat(client, body) {
11152
11184
  try {
11153
11185
  const r = await client.postFull("/proxy/engine/beat", { ...body });
11154
- if (r?.status === 200 && r.json?.ok === true)
11155
- return { ok: true };
11186
+ if (r?.status === 200 && r.json?.ok === true) {
11187
+ const update = updateOf(r.json.update);
11188
+ return update ? { ok: true, update } : { ok: true };
11189
+ }
11156
11190
  const error = r?.json?.error;
11157
- return r?.status === 409 && typeof error === "string" ? { ok: false, refused: error } : { ok: false };
11191
+ if (typeof error !== "string")
11192
+ return { ok: false };
11193
+ if (r?.status === 409)
11194
+ return { ok: false, refused: error };
11195
+ if (r?.status === 426)
11196
+ return { ok: false, refused: error, below: true };
11197
+ return { ok: false };
11158
11198
  } catch {
11159
11199
  return { ok: false };
11160
11200
  }
@@ -12207,6 +12247,18 @@ function groupOf(j, item) {
12207
12247
  const title = str6(j.title);
12208
12248
  return title ? { key, title } : null;
12209
12249
  }
12250
+ function runOf(v) {
12251
+ if (!Array.isArray(v))
12252
+ return;
12253
+ return v.filter(isObject8).flatMap((x) => {
12254
+ const repo = str6(x.repo)?.trim();
12255
+ if (!repo)
12256
+ return [];
12257
+ const install = str6(x.install)?.trim();
12258
+ const gate = str6(x.gate)?.trim();
12259
+ return [{ repo, ...install ? { install } : {}, ...gate ? { gate } : {} }];
12260
+ });
12261
+ }
12210
12262
  function sameEngine(a, b) {
12211
12263
  const bare = (s) => s.trim().replace(/^engine:/, "").toLowerCase();
12212
12264
  return bare(a) === bare(b);
@@ -12258,14 +12310,14 @@ var PROFILE_TEXT = [
12258
12310
  "reposDir",
12259
12311
  "engine"
12260
12312
  ];
12261
- var SHELL_TEXT = ["agent", "launcher"];
12313
+ var SHELL_TEXT = ["agent", "launcher", "mode"];
12262
12314
  function profileOf(r) {
12263
12315
  if (!r || r.ok === false || !isObject8(r.profile))
12264
12316
  return null;
12265
12317
  const p = r.profile;
12266
12318
  const member = isObject8(r.member) ? r.member : {};
12267
12319
  const out = {
12268
- pickup: p.pickup === "auto" ? "auto" : "approve",
12320
+ pickup: p.pickup === "auto" && member.pickup === "auto" ? "auto" : "approve",
12269
12321
  ...HOLD_DEFAULTS2,
12270
12322
  holdOff: p.holdOff === true
12271
12323
  };
@@ -12284,8 +12336,8 @@ function profileOf(r) {
12284
12336
  else if (str6(p[k])?.trim())
12285
12337
  notYours.push(k);
12286
12338
  }
12287
- if (notYours.length)
12288
- out.notYours = notYours;
12339
+ if (p.pickup === "auto" && out.pickup !== "auto")
12340
+ notYours.push("pickup");
12289
12341
  const atOnce = num5(p.atOnce);
12290
12342
  if (atOnce !== undefined && atOnce >= 1)
12291
12343
  out.atOnce = Math.round(atOnce);
@@ -12304,13 +12356,17 @@ function profileOf(r) {
12304
12356
  if (names.length)
12305
12357
  out.mcpAllow = names;
12306
12358
  }
12307
- if (typeof p.sandbox === "boolean")
12359
+ if (p.sandbox === true || p.sandbox === false && member.sandbox === false)
12308
12360
  out.sandbox = p.sandbox;
12361
+ else if (p.sandbox === false)
12362
+ notYours.push("sandbox");
12309
12363
  if (Array.isArray(p.sandboxAllow)) {
12310
12364
  const hosts = p.sandboxAllow.filter((x) => typeof x === "string" && x.trim() !== "");
12311
12365
  if (hosts.length)
12312
12366
  out.sandboxAllow = hosts;
12313
12367
  }
12368
+ if (notYours.length)
12369
+ out.notYours = notYours;
12314
12370
  return out;
12315
12371
  }
12316
12372
  async function readProfile(client) {
@@ -12436,7 +12492,7 @@ function sledsSource(client, o) {
12436
12492
  ...o.leaseMin !== undefined ? { leaseMin: o.leaseMin } : {}
12437
12493
  });
12438
12494
  if (!r || r.status >= 300 || !r.json || r.json.ok === false) {
12439
- o.log?.(`${pending ? `${item}: could not claim the re-draft` : started ? `${item}: Start could not claim it for drafting` : `Pickup: Auto could not claim ${item} for drafting`} — ${r ? serverMessage(r) : UNREACHABLE2}`);
12495
+ o.log?.(`${pending ? `${item}: could not claim it to plan its route again` : started ? `${item}: Start could not claim it for planning` : `Pickup: Auto could not claim ${item} for planning`} — ${r ? serverMessage(r) : UNREACHABLE2}`);
12440
12496
  return null;
12441
12497
  }
12442
12498
  const j = r.json;
@@ -12458,7 +12514,7 @@ function sledsSource(client, o) {
12458
12514
  route: routeText(brief, isObject8(row.route) ? row.route.states : null)
12459
12515
  };
12460
12516
  }
12461
- o.log?.(redraft ? `${item}: re-drafting the route from ${redraft.by}'s answer — it waits for a yes` : `${started ? `${item}: Start` : "Pickup: Auto"} is drafting ${started ? "its" : `${item}'s`} route first (${why.join(", ")}) — it waits for a yes`);
12517
+ 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`);
12462
12518
  const leaseUntil = num5(j.leaseUntil);
12463
12519
  const claim = {
12464
12520
  item,
@@ -12560,6 +12616,7 @@ function sledsSource(client, o) {
12560
12616
  }
12561
12617
  const leaseUntil = num5(hit.leaseUntil);
12562
12618
  const runToken = str6(hit.runToken) ?? (taken.length === 1 ? str6(r.json?.runToken) : undefined);
12619
+ const run = runOf(hit.run);
12563
12620
  const claim = {
12564
12621
  item,
12565
12622
  node: str6(hit.node) ?? node,
@@ -12571,7 +12628,8 @@ function sledsSource(client, o) {
12571
12628
  ...t.seatId ? { seatId: t.seatId } : {},
12572
12629
  ...str6(hit.answer) ? { answer: str6(hit.answer) } : {},
12573
12630
  ...runToken ? { runToken } : {},
12574
- ...group ? { group } : {}
12631
+ ...group ? { group } : {},
12632
+ ...run ? { run } : {}
12575
12633
  };
12576
12634
  return { ok: true, claim };
12577
12635
  },
@@ -13091,17 +13149,20 @@ var MANAGERS = new Set(["pnpm", "npm", "yarn", "bun"]);
13091
13149
  var INSTALL_VERBS = new Set(["install", "i", "ci"]);
13092
13150
  function installArgv(command) {
13093
13151
  const line = command?.trim().replace(/^`|`$/g, "") ?? "";
13094
- if (!line || /[;&|<>$`()]/.test(line))
13152
+ if (!line || /[;&|<>$`()\n]/.test(line))
13095
13153
  return null;
13096
13154
  const argv = shellWords(line);
13097
13155
  const [tool, verb] = argv;
13098
13156
  if (!tool || !MANAGERS.has(tool))
13099
13157
  return null;
13100
- if (tool !== "yarn" && (!verb || !INSTALL_VERBS.has(verb)))
13101
- return null;
13102
- if (tool === "yarn" && verb !== undefined && verb !== "install" && !verb.startsWith("-"))
13158
+ let rest;
13159
+ if (tool === "yarn")
13160
+ rest = argv.slice(verb === "install" ? 2 : 1);
13161
+ else if (verb && INSTALL_VERBS.has(verb))
13162
+ rest = argv.slice(2);
13163
+ else
13103
13164
  return null;
13104
- return argv;
13165
+ return rest.every((a) => a.startsWith("-")) ? argv : null;
13105
13166
  }
13106
13167
  function lockfileInstall(path, exists) {
13107
13168
  if (exists(join15(path, "pnpm-lock.yaml")))
@@ -13114,57 +13175,59 @@ function lockfileInstall(path, exists) {
13114
13175
  return ["npm", "ci"];
13115
13176
  return null;
13116
13177
  }
13117
- function packInstallOf(pack, repo) {
13118
- let section = null;
13119
- let first;
13120
- const want = repo?.trim().toLowerCase();
13121
- for (const line of pack.split(`
13122
- `)) {
13123
- const h = line.match(/^###\s+(.+?)\s*$/);
13124
- if (h) {
13125
- section = h[1].toLowerCase();
13126
- continue;
13127
- }
13128
- const m = line.match(/^\s*-\s*Install:\s*(.+?)\s*$/i);
13129
- if (!m?.[1])
13130
- continue;
13131
- if (want && section === want)
13132
- return m[1];
13133
- first ??= m[1];
13134
- }
13135
- return first;
13136
- }
13137
- function packGateOf(pack, repo) {
13138
- let inDone = false;
13139
- let first;
13140
- const want = repo?.trim().toLowerCase();
13141
- for (const line of pack.split(`
13142
- `)) {
13143
- if (/^##\s/.test(line)) {
13144
- inDone = /^##\s+4\./.test(line);
13145
- continue;
13146
- }
13147
- if (!inDone)
13148
- continue;
13149
- const m = line.match(/^\s*-\s*([^:`]+?):\s*`(.+)`\s*$/);
13150
- if (!m?.[1] || !m[2])
13151
- continue;
13152
- const name = m[1].trim().toLowerCase();
13153
- if (name === "done means" || name.startsWith("try it"))
13154
- continue;
13155
- if (want && name === want)
13156
- return m[2];
13157
- first ??= m[2];
13158
- }
13159
- return first;
13178
+ var INTERPRETERS = new Set([
13179
+ "node",
13180
+ "bun",
13181
+ "deno",
13182
+ "python",
13183
+ "python3",
13184
+ "sh",
13185
+ "bash",
13186
+ "zsh",
13187
+ "fish",
13188
+ "npx",
13189
+ "pnpx",
13190
+ "bunx",
13191
+ "dlx",
13192
+ "env",
13193
+ "eval",
13194
+ "exec",
13195
+ "ruby",
13196
+ "perl",
13197
+ "sudo"
13198
+ ]);
13199
+ function runsInterpreter(part) {
13200
+ const [first = "", second, third] = part.split(/\s+/);
13201
+ const tool = first.split("/").pop() ?? first;
13202
+ if (tool.includes("=") || INTERPRETERS.has(tool))
13203
+ return true;
13204
+ if (!MANAGERS.has(tool))
13205
+ return false;
13206
+ if (second === "dlx" || second === "x")
13207
+ return true;
13208
+ return second === "exec" && third !== undefined && INTERPRETERS.has(third.split("/").pop() ?? "");
13160
13209
  }
13161
13210
  function gateAllowRules(gate) {
13162
13211
  const whole = gate?.trim();
13163
13212
  if (!whole)
13164
13213
  return [];
13214
+ if (/[$`()<>|&\n]/.test(whole.replace(/&&|\|\|/g, " ")))
13215
+ return [];
13165
13216
  const parts = whole.split(/&&|\|\||;/).map((p) => p.trim()).filter(Boolean);
13217
+ if (parts.some(runsInterpreter))
13218
+ return [];
13166
13219
  return [...new Set([whole, ...parts])].map((c) => `Bash(${c})`);
13167
13220
  }
13221
+ function claimRunOf(run, repo) {
13222
+ if (!run?.length)
13223
+ return {};
13224
+ const want = repo?.trim().toLowerCase();
13225
+ const hit = want && run.find((r) => r.repo.trim().toLowerCase() === want) || run[0];
13226
+ return {
13227
+ ...hit?.install ? { install: hit.install } : {},
13228
+ ...hit?.gate ? { gate: hit.gate } : {}
13229
+ };
13230
+ }
13168
13231
  function ensureInstalled(exec, path, fs, o = {}) {
13169
13232
  if (!fs.exists(join15(path, "package.json")) || fs.exists(join15(path, "node_modules")))
13170
13233
  return null;
@@ -13722,10 +13785,10 @@ async function tickOnce(d) {
13722
13785
  let mcpConfig;
13723
13786
  try {
13724
13787
  const base = d.defaultBranch(d.exec, repoPath);
13725
- const worktree = d.runner.makesWorktree ? repoPath : d.ensureWorktree(d.exec, repoPath, branch, worktreePath(repoPath, name), base, packInstallOf(claim.pack, claim.repos[0])) ?? worktreePath(repoPath, name);
13788
+ const { install, gate } = claimRunOf(claim.run, claim.repos[0]);
13789
+ const worktree = d.runner.makesWorktree ? repoPath : d.ensureWorktree(d.exec, repoPath, branch, worktreePath(repoPath, name), base, install) ?? worktreePath(repoPath, name);
13726
13790
  const prTitle = d.prTitleOf?.(claim);
13727
13791
  mcpConfig = engineMcpConfigFor(d, name, claim.runToken, at, worktree);
13728
- const gate = packGateOf(claim.pack, claim.repos[0]);
13729
13792
  const allow = gateAllowRules(gate);
13730
13793
  const prompt = nodePrompt({
13731
13794
  claim,
@@ -14699,7 +14762,7 @@ async function startDraft(d, claim, why, state, started, finished) {
14699
14762
  };
14700
14763
  state.runs.push(run);
14701
14764
  d.writeState(state);
14702
- d.log(claim.redraft ? `${at}: re-drafting the route from ${claim.redraft.by}'s answer — it waits for a yes` : `${at}: drafting a route${why.length ? ` (${why.join(", ")})` : ""} — it waits for a yes, unless it is one node inside the brief's touches`);
14765
+ d.log(claim.redraft ? `${at}: planning the route again from ${claim.redraft.by}'s answer — it waits for a yes` : `${at}: planning the route${why.length ? ` (${why.join(", ")})` : ""} — it waits for a yes, unless it is one node inside the brief's touches`);
14703
14766
  try {
14704
14767
  await d.source.heartbeat(claim, watch);
14705
14768
  } catch (e) {
@@ -14716,7 +14779,7 @@ async function settleDraft(d, run, claim, runner, finished) {
14716
14779
  return true;
14717
14780
  }
14718
14781
  if (beat === "done") {
14719
- d.log(`${ref(run)}: route drafted — it waits for a person's yes`);
14782
+ d.log(`${ref(run)}: route planned — it waits for a person's yes`);
14720
14783
  endDraft(d, run, runner);
14721
14784
  return false;
14722
14785
  }
@@ -14730,7 +14793,7 @@ async function settleDraft(d, run, claim, runner, finished) {
14730
14793
  return false;
14731
14794
  }
14732
14795
  if (beat === "lost") {
14733
- d.log(`${ref(run)}: the drafting claim was lost — stopping the session`);
14796
+ d.log(`${ref(run)}: the planning claim was lost — stopping the session`);
14734
14797
  endDraft(d, run, runner);
14735
14798
  return false;
14736
14799
  }
@@ -14746,7 +14809,7 @@ async function settleDraft(d, run, claim, runner, finished) {
14746
14809
  let log = "";
14747
14810
  if (status === "exited") {
14748
14811
  try {
14749
- log = runner.read(run.handle) || "The drafting session exited with no route proposed.";
14812
+ log = runner.read(run.handle) || "The planning session exited with no route proposed.";
14750
14813
  } catch (e) {
14751
14814
  log = `(the session's output could not be read: ${message(e)})`;
14752
14815
  }
@@ -15689,6 +15752,18 @@ init_machine();
15689
15752
  init_state();
15690
15753
  init_meter();
15691
15754
 
15755
+ // src/runners/gitGuard.ts
15756
+ import { basename as basename4 } from "node:path";
15757
+ var GIT_GUARD_ENV = {
15758
+ GIT_CONFIG_COUNT: "2",
15759
+ GIT_CONFIG_KEY_0: "core.fsmonitor",
15760
+ GIT_CONFIG_VALUE_0: "false",
15761
+ GIT_CONFIG_KEY_1: "core.hooksPath",
15762
+ GIT_CONFIG_VALUE_1: "/dev/null"
15763
+ };
15764
+ var GUARDED = new Set(["git", "gh"]);
15765
+ var guardGit = (exec) => (cmd, args, o) => GUARDED.has(basename4(cmd)) ? exec(cmd, args, { ...o, env: { ...o?.env, ...GIT_GUARD_ENV } }) : exec(cmd, args, o);
15766
+
15692
15767
  // src/runners/command.ts
15693
15768
  var expandCommandTemplate = (template, o) => {
15694
15769
  const values = {
@@ -16630,7 +16705,7 @@ function flagsFromProfile(flags, given, profile, home) {
16630
16705
  const used = [];
16631
16706
  const skipped = [];
16632
16707
  for (const k of profile.notYours ?? [])
16633
- skipped.push(`${k} (the workspace default — the engine runs only one you set yourself)`);
16708
+ skipped.push(`${k} (the workspace default — the engine takes it only from your own profile)`);
16634
16709
  if (profile.atOnce !== undefined && !has("at-once")) {
16635
16710
  out.atOnce = profile.atOnce;
16636
16711
  used.push(`at-once ${profile.atOnce}`);
@@ -16794,7 +16869,11 @@ function engineClient(o, org) {
16794
16869
  const env = o.env ?? process.env;
16795
16870
  const src = meterSource(o.home, undefined, { ...org ? { flag: org } : {}, env });
16796
16871
  if (src)
16797
- return fetchClient({ ...src, timeoutMs: ENGINE_TIMEOUT_MS });
16872
+ return fetchClient({
16873
+ ...src,
16874
+ timeoutMs: ENGINE_TIMEOUT_MS,
16875
+ version: "0.1.47"
16876
+ });
16798
16877
  const asked = org?.trim() || env.SLEDS_ORG?.trim();
16799
16878
  if (asked && !selectOrg(readConfig(o.home), org, env).seat)
16800
16879
  return {
@@ -16858,7 +16937,7 @@ function engineToken(o, org) {
16858
16937
  }
16859
16938
  var withToken = (token, now) => token ? { token, tokenNow: now } : {};
16860
16939
  function engineDeps(o, flags, source, runner, stateName) {
16861
- const exec = o.exec ?? defaultExec;
16940
+ const exec = guardGit(o.exec ?? defaultExec);
16862
16941
  const cwd = o.cwd ?? process.cwd();
16863
16942
  const exists = o.exists ?? realExists;
16864
16943
  const log = o.log ?? console.log;
@@ -16989,7 +17068,15 @@ function engineDeps(o, flags, source, runner, stateName) {
16989
17068
  function sandboxDenyRead(home, env) {
16990
17069
  return {
16991
17070
  dirs: [...new Set([configDir(home, env), join16(home, ".config", "sleds")])],
16992
- files: [...new Set([tokenPath(home, env), join16(home, ".sleds-token")])]
17071
+ files: [
17072
+ ...new Set([
17073
+ tokenPath(home, env),
17074
+ join16(home, ".sleds-token"),
17075
+ settingsPath(home, env),
17076
+ backupPath(home, env),
17077
+ join16(claudeDir(home, env), "settings.local.json")
17078
+ ])
17079
+ ]
16993
17080
  };
16994
17081
  }
16995
17082
  function engineSandboxSettings(home, env, gitCommonDir, allow) {
@@ -17046,7 +17133,7 @@ async function driveEngine(o, flags, deps, until = {}) {
17046
17133
  runner: deps.runner.name,
17047
17134
  atOnce: flags.atOnce,
17048
17135
  interval: flags.interval,
17049
- cliVersion: "0.1.46"
17136
+ cliVersion: "0.1.47"
17050
17137
  };
17051
17138
  const beat = (checkedAt) => {
17052
17139
  const m = deps.machine;
@@ -17232,7 +17319,7 @@ async function drive(o, flags, deps, until, beat) {
17232
17319
  var SEAT_CHANGED_EXIT = 3;
17233
17320
  function engineRunner(o, flags) {
17234
17321
  const runnerFor = o.runnerFor ?? runnerFor2;
17235
- return runnerFor(flags.runner, o.exec ?? defaultExec, {
17322
+ return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
17236
17323
  ...flags.runnerCmd ? { command: flags.runnerCmd } : {}
17237
17324
  });
17238
17325
  }
@@ -17319,7 +17406,7 @@ async function enginePauseCmd(o) {
17319
17406
  source = sledsSource(c, { engine, log });
17320
17407
  }
17321
17408
  const why = parsed.why ?? `paused on ${defaultEngineName(host)} (sleds engine pause)`;
17322
- const exec = o.exec ?? defaultExec;
17409
+ const exec = guardGit(o.exec ?? defaultExec);
17323
17410
  const gone = new Set;
17324
17411
  for (const run of running) {
17325
17412
  const at = `${run.item}/${run.node}`;
@@ -17368,13 +17455,18 @@ import {
17368
17455
  writeFileSync as writeFileSync15
17369
17456
  } from "node:fs";
17370
17457
  import { hostname as hostname3 } from "node:os";
17371
- import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute2, join as join19 } from "node:path";
17458
+ import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute2, join as join20 } from "node:path";
17372
17459
  init_state();
17373
17460
 
17461
+ // src/runtime.ts
17462
+ import { homedir } from "node:os";
17463
+ import { join as join17, win32 } from "node:path";
17464
+ var sledsLink = (home = homedir(), platform = process.platform) => platform === "win32" ? win32.join(process.env.LOCALAPPDATA ?? win32.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join17(home, ".sleds", "bin", "sleds");
17465
+
17374
17466
  // src/schedule.ts
17375
17467
  import { spawnSync as spawnSync4 } from "node:child_process";
17376
17468
  import { existsSync as existsSync14, mkdirSync as mkdirSync13, rmSync as rmSync5, writeFileSync as writeFileSync14 } from "node:fs";
17377
- import { join as join17 } from "node:path";
17469
+ import { join as join18 } from "node:path";
17378
17470
  var REVERT_LABEL = "ai.sleds.revert";
17379
17471
  var defaultExec2 = (cmd, args) => {
17380
17472
  const r = spawnSync4(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
@@ -17382,7 +17474,7 @@ var defaultExec2 = (cmd, args) => {
17382
17474
  return { ok: false, stderr: r.error.message };
17383
17475
  return { ok: r.status === 0, stderr: r.stderr ?? "" };
17384
17476
  };
17385
- var plistPath = (home) => join17(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
17477
+ var plistPath = (home) => join18(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
17386
17478
  var xmlEscape2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
17387
17479
  var buildLaunchdPlist = (sledsArgv, deadline) => {
17388
17480
  const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape2(a)}</string>`).join(`
@@ -17421,7 +17513,7 @@ var scheduleRevert = (d, deadlineMs) => {
17421
17513
  if (d.platform === "darwin") {
17422
17514
  const p = plistPath(d.home);
17423
17515
  try {
17424
- mkdirSync13(join17(d.home, "Library", "LaunchAgents"), { recursive: true });
17516
+ mkdirSync13(join18(d.home, "Library", "LaunchAgents"), { recursive: true });
17425
17517
  d.exec("launchctl", ["unload", p]);
17426
17518
  writeFileSync14(p, buildLaunchdPlist(d.sledsArgv, deadline));
17427
17519
  const r = d.exec("launchctl", ["load", p]);
@@ -17461,16 +17553,16 @@ var cancelRevert = (d, kind) => {
17461
17553
  };
17462
17554
 
17463
17555
  // src/commands/engineSystemd.ts
17464
- import { join as join18 } from "node:path";
17556
+ import { join as join19 } from "node:path";
17465
17557
  var BOX_ENV_UNIT_PATH = "%h/.config/sleds/box.env";
17466
17558
  function boxEnvPath(home) {
17467
- return join18(home, ".config", "sleds", "box.env");
17559
+ return join19(home, ".config", "sleds", "box.env");
17468
17560
  }
17469
17561
  function engineUnitDir(home) {
17470
- return join18(home, ".config", "systemd", "user");
17562
+ return join19(home, ".config", "systemd", "user");
17471
17563
  }
17472
17564
  function engineUnitPath(home, label) {
17473
- return join18(engineUnitDir(home), `${label}.service`);
17565
+ return join19(engineUnitDir(home), `${label}.service`);
17474
17566
  }
17475
17567
  function systemdQuote(s) {
17476
17568
  const body = s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/%/g, "%%").replace(/\$/g, "$$$$");
@@ -17513,9 +17605,10 @@ function parseEngineUnit(text) {
17513
17605
  var ENGINE_LABEL = "ai.sleds.engine";
17514
17606
  var ENGINE_INSTALL_USAGE = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
17515
17607
  ${ENGINE_USAGE}`;
17516
- function stableArgv(argv, realpath = realpathSync) {
17608
+ function stableArgv(argv, realpath = realpathSync, home) {
17609
+ const link = sledsLink(home);
17517
17610
  return argv.map((a) => {
17518
- if (!isAbsolute2(a))
17611
+ if (!isAbsolute2(a) || a === link)
17519
17612
  return a;
17520
17613
  try {
17521
17614
  return realpath(a);
@@ -17528,13 +17621,13 @@ function engineLabel(name, org, seat) {
17528
17621
  return [ENGINE_LABEL, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
17529
17622
  }
17530
17623
  function enginePlistPath(home, name, org, seat) {
17531
- return join19(home, "Library", "LaunchAgents", `${engineLabel(name, org, seat)}.plist`);
17624
+ return join20(home, "Library", "LaunchAgents", `${engineLabel(name, org, seat)}.plist`);
17532
17625
  }
17533
17626
  function engineLogPath(stateDir, name) {
17534
- return join19(stateDir, `${engineSlug(name)}.log`);
17627
+ return join20(stateDir, `${engineSlug(name)}.log`);
17535
17628
  }
17536
17629
  function engineEventsPath(stateDir, name) {
17537
- return join19(stateDir, `${engineSlug(name)}.events.jsonl`);
17630
+ return join20(stateDir, `${engineSlug(name)}.events.jsonl`);
17538
17631
  }
17539
17632
  var xmlEscape3 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
17540
17633
  function buildEnginePlist(o) {
@@ -17631,7 +17724,7 @@ function readEngines(dir, suffix, manager, parse) {
17631
17724
  }
17632
17725
  const out = [];
17633
17726
  for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL}.`) && n.endsWith(suffix))) {
17634
- const path = join19(dir, name);
17727
+ const path = join20(dir, name);
17635
17728
  let parsed;
17636
17729
  try {
17637
17730
  parsed = parse(readFileSync14(path, "utf8"), name);
@@ -17651,10 +17744,10 @@ function readEngines(dir, suffix, manager, parse) {
17651
17744
  }
17652
17745
  function installedEngines(home) {
17653
17746
  return [
17654
- ...readEngines(join19(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
17747
+ ...readEngines(join20(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
17655
17748
  ...readEngines(engineUnitDir(home), ".service", "systemd", (text, file) => {
17656
17749
  const parsed = parseEngineUnit(text);
17657
- return parsed && { label: basename4(file, ".service"), ...parsed };
17750
+ return parsed && { label: basename5(file, ".service"), ...parsed };
17658
17751
  })
17659
17752
  ];
17660
17753
  }
@@ -17689,7 +17782,7 @@ function engineInstall(o) {
17689
17782
  const label = engineLabel(parsed.name, parsed.org, seat);
17690
17783
  const logPath = engineLogPath(stateDir, parsed.name);
17691
17784
  mkdirSync14(stateDir, { recursive: true, mode: 448 });
17692
- const sledsArgv = stableArgv(o.sledsArgv, o.realpath);
17785
+ const sledsArgv = stableArgv(o.sledsArgv, o.realpath, o.home);
17693
17786
  const execPath = sledsArgv[0] ?? process.execPath;
17694
17787
  const agentEnv = {
17695
17788
  PATH: musherPath(o.home, execPath, env.PATH ?? ""),
@@ -17741,7 +17834,7 @@ function installUnit(a) {
17741
17834
  const log = o.log ?? console.log;
17742
17835
  const error = o.error ?? console.error;
17743
17836
  const unit = engineUnitPath(o.home, label);
17744
- const unitName = basename4(unit);
17837
+ const unitName = basename5(unit);
17745
17838
  const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
17746
17839
  mkdirSync14(dirname12(unit), { recursive: true });
17747
17840
  if (existsSync15(unit))
@@ -17751,7 +17844,7 @@ function installUnit(a) {
17751
17844
  continue;
17752
17845
  if (engineArg(other.programArgs, "name") !== parsed.name)
17753
17846
  continue;
17754
- systemctl("disable", "--now", basename4(other.plist));
17847
+ systemctl("disable", "--now", basename5(other.plist));
17755
17848
  rmSync6(other.plist, { force: true });
17756
17849
  log(`replaced ${other.label}, this engine as installed before`);
17757
17850
  }
@@ -17810,13 +17903,13 @@ function engineUninstall(o) {
17810
17903
  const unit = file.endsWith(".service");
17811
17904
  const exec = o.exec ?? defaultExec2;
17812
17905
  if (unit)
17813
- exec("systemctl", ["--user", "disable", "--now", basename4(file)]);
17906
+ exec("systemctl", ["--user", "disable", "--now", basename5(file)]);
17814
17907
  else
17815
17908
  exec("launchctl", ["unload", file]);
17816
17909
  rmSync6(file, { force: true });
17817
17910
  if (unit)
17818
17911
  exec("systemctl", ["--user", "daemon-reload"]);
17819
- log(`engine:${name} removed: ${basename4(file, unit ? ".service" : ".plist")} — its sessions keep running`);
17912
+ log(`engine:${name} removed: ${basename5(file, unit ? ".service" : ".plist")} — its sessions keep running`);
17820
17913
  return 0;
17821
17914
  }
17822
17915
 
@@ -17933,7 +18026,7 @@ function nodeOk(version, min = NODE_MIN) {
17933
18026
  }
17934
18027
  var MARK = { ok: "ok ", warn: "warn", fail: "FAIL" };
17935
18028
  function formatDoctor(checks) {
17936
- const lines = checks.map((c) => `${MARK[c.level]} ${c.name.padEnd(16)}${c.detail}`);
18029
+ const lines = checks.map((c) => `${MARK[c.level]} ${c.name.padEnd(15)} ${c.detail}`);
17937
18030
  const fixes = checks.filter((c) => c.level !== "ok" && c.fix);
17938
18031
  if (fixes.length > 0) {
17939
18032
  lines.push("");
@@ -17973,7 +18066,7 @@ async function runDoctor(o) {
17973
18066
  level: "fail",
17974
18067
  name: "config",
17975
18068
  detail: `${configPath(home)} does not exist${overrides.length ? ` (this shell has ${overrides.join(" ")})` : ""}`,
17976
- fix: overrides.length ? "unset SLEDS_HOME CLAUDE_CONFIG_DIR — or run `sleds init` for this seat" : "sleds init --token <sled_…>"
18069
+ fix: overrides.length ? "unset SLEDS_HOME CLAUDE_CONFIG_DIR — or run `sleds init` for this seat" : "sleds init"
17977
18070
  });
17978
18071
  } else {
17979
18072
  checks.push({
@@ -18003,7 +18096,7 @@ async function runDoctor(o) {
18003
18096
  level: "warn",
18004
18097
  name: "claude",
18005
18098
  detail: `${sPath} carries a different token (${maskToken(pointed.token)}) than ${configPath(home)} (${maskToken(cfg.token)})`,
18006
- fix: "sleds init --token <the one you mean>"
18099
+ fix: "sleds init (or `sleds login` as the seat you mean)"
18007
18100
  });
18008
18101
  } else {
18009
18102
  checks.push({ level: "ok", name: "claude", detail: `${sPath} → ${pointed.url}` });
@@ -18169,13 +18262,16 @@ async function runDoctor(o) {
18169
18262
  }
18170
18263
  var SANDBOX_PROBE = "sandbox-probe";
18171
18264
  var PROBE_ENV = "SLEDS_DOCTOR_PROBE";
18265
+ var SETTINGS_ENV = "SLEDS_DOCTOR_SETTINGS";
18172
18266
  var SANDBOX_PROBE_COMMAND = [
18173
18267
  `cat "$${PROBE_ENV}"; echo "SLEDS_CAT_EXIT=$?"`,
18268
+ `[ -n "$ANTHROPIC_AUTH_TOKEN$ANTHROPIC_API_KEY" ]; echo "SLEDS_ENV_EMPTY=$?"`,
18269
+ `cat "$${SETTINGS_ENV}" >/dev/null; echo "SLEDS_SETTINGS_EXIT=$?"`,
18174
18270
  `curl -sS -m 10 -o /dev/null -w "SLEDS_CURL_CODE=%{http_code}\\n" https://example.com; echo "SLEDS_CURL_EXIT=$?"`,
18175
18271
  `gh api user -q .login; echo "SLEDS_GH_EXIT=$?"`
18176
18272
  ].join("; ");
18177
18273
  var marker = (out, name) => new RegExp(`${name}=(\\d+)`).exec(out)?.[1] ?? null;
18178
- function readSandboxProbe(run, nonce) {
18274
+ function readSandboxProbe(run, nonce, o = {}) {
18179
18275
  const out = `${run.stdout}
18180
18276
  ${run.stderr}`;
18181
18277
  const failed = run.status !== 0;
@@ -18197,6 +18293,34 @@ ${run.stderr}`;
18197
18293
  detail: catExit === "0" ? "cat succeeded but printed no nonce — inconclusive" : `${why} — inconclusive`,
18198
18294
  fix
18199
18295
  };
18296
+ const leaked = Boolean(o.token) && out.includes(o.token);
18297
+ const envEmpty = marker(out, "SLEDS_ENV_EMPTY");
18298
+ const envRow = envEmpty === "0" ? {
18299
+ level: "fail",
18300
+ name: "sandbox env",
18301
+ detail: "a sandboxed session's shell has ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY — the seat token is readable",
18302
+ fix: "update Claude Code: the sandbox settings' env sets CLAUDE_CODE_SUBPROCESS_ENV_SCRUB, which 2.1.310 honors"
18303
+ } : envEmpty !== null ? {
18304
+ level: "ok",
18305
+ name: "sandbox env",
18306
+ detail: "the session's shell has no Anthropic credential in its env"
18307
+ } : { level: "warn", name: "sandbox env", detail: `${why} — inconclusive`, fix };
18308
+ const settingsExit = marker(out, "SLEDS_SETTINGS_EXIT");
18309
+ const settingsRow = leaked || settingsExit === "0" && o.settingsExists !== false ? {
18310
+ level: "fail",
18311
+ name: "sandbox settings read",
18312
+ detail: leaked ? "the seat token appeared in a sandboxed session's output" : "a sandboxed session read Claude Code's settings.json — a proxied seat's token is readable",
18313
+ fix: "check that the sandbox settings deny the Claude settings files (sandbox.filesystem.denyRead)"
18314
+ } : o.settingsExists === false ? {
18315
+ level: "warn",
18316
+ name: "sandbox settings read",
18317
+ detail: "Claude Code has no settings.json for this seat — nothing to guard yet",
18318
+ fix: "sleds init"
18319
+ } : settingsExit !== null ? {
18320
+ level: "ok",
18321
+ name: "sandbox settings read",
18322
+ detail: "Claude Code's settings.json is unreadable from a sandboxed session"
18323
+ } : { level: "warn", name: "sandbox settings read", detail: `${why} — inconclusive`, fix };
18200
18324
  const code = marker(out, "SLEDS_CURL_CODE");
18201
18325
  const curlExit = marker(out, "SLEDS_CURL_EXIT");
18202
18326
  const egress = code !== null && code !== "000" ? {
@@ -18221,8 +18345,15 @@ ${run.stderr}`;
18221
18345
  detail: ghExit === null ? `${why} — inconclusive` : `gh fails inside the sandbox (exit ${ghExit}) — a sandboxed node cannot push or open its PR`,
18222
18346
  fix: ghExit === null ? fix : "gh auth status; api.github.com on the allowlist; on macOS gh (Go) needs sandbox.enableWeakerNetworkIsolation for TLS"
18223
18347
  };
18224
- return [read, egress, github];
18348
+ return [read, envRow, settingsRow, egress, github];
18225
18349
  }
18350
+ var proxyToken = (home, env) => {
18351
+ try {
18352
+ return readProxy(readSettings(home, env))?.token;
18353
+ } catch {
18354
+ return;
18355
+ }
18356
+ };
18226
18357
  function sandboxChecks(o, env) {
18227
18358
  const which = (c) => (o.which ?? defaultWhich2)(c)[0] ?? null;
18228
18359
  const exec = o.exec ?? sessionExec;
@@ -18247,17 +18378,14 @@ function sandboxChecks(o, env) {
18247
18378
  }
18248
18379
  ];
18249
18380
  const nonce = o.nonce ?? `sleds-probe-${randomBytes(16).toString("hex")}`;
18250
- const probe = join20(dir, SANDBOX_PROBE);
18251
- const work = mkdtempSync(join20(tmpdir(), "sleds-sandbox-"));
18381
+ const probe = join21(dir, SANDBOX_PROBE);
18382
+ const work = mkdtempSync(join21(tmpdir(), "sleds-sandbox-"));
18252
18383
  try {
18253
18384
  writeFileSync17(probe, `${nonce}
18254
18385
  `, { mode: 384 });
18255
- const settingsFile = join20(work, "settings.json");
18256
- const settings = sandboxSettings({
18257
- denyRead: [dir],
18258
- gitCommonDir: work,
18259
- allow: SANDBOX_DEFAULT_ALLOW
18260
- });
18386
+ const settingsFile = join21(work, "settings.json");
18387
+ const settings = engineSandboxSettings(o.home, env, work, SANDBOX_DEFAULT_ALLOW);
18388
+ const claudeSettings = settingsPath(o.home, env);
18261
18389
  writeFileSync17(settingsFile, JSON.stringify(settings, null, 2), { mode: 384 });
18262
18390
  const prompt = `Run exactly this one Bash command, once, then reply with its complete output verbatim and nothing else:
18263
18391
 
@@ -18266,6 +18394,7 @@ ${SANDBOX_PROBE_COMMAND}`;
18266
18394
  "-u",
18267
18395
  "SLEDS_TOKEN",
18268
18396
  `${PROBE_ENV}=${probe}`,
18397
+ `${SETTINGS_ENV}=${claudeSettings}`,
18269
18398
  claude,
18270
18399
  "-p",
18271
18400
  "--model",
@@ -18278,7 +18407,9 @@ ${SANDBOX_PROBE_COMMAND}`;
18278
18407
  "3",
18279
18408
  prompt
18280
18409
  ], { cwd: work });
18281
- return readSandboxProbe(run, nonce);
18410
+ const settingsExists = existsSync17(claudeSettings);
18411
+ const token = settingsExists ? proxyToken(o.home, env) : undefined;
18412
+ return readSandboxProbe(run, nonce, { ...token ? { token } : {}, settingsExists });
18282
18413
  } finally {
18283
18414
  rmSync8(probe, { force: true });
18284
18415
  rmSync8(work, { recursive: true, force: true });
@@ -18515,7 +18646,7 @@ import {
18515
18646
  writeFileSync as writeFileSync18
18516
18647
  } from "node:fs";
18517
18648
  import { hostname as hostname4 } from "node:os";
18518
- import { join as join21, resolve as resolve10 } from "node:path";
18649
+ import { join as join22, resolve as resolve10 } from "node:path";
18519
18650
  init_machine();
18520
18651
  init_state();
18521
18652
  init_meter();
@@ -18697,7 +18828,7 @@ function flagsFromProfile2(flags, given, profile, home) {
18697
18828
  const used = [];
18698
18829
  const skipped = [];
18699
18830
  for (const k of profile.notYours ?? [])
18700
- skipped.push(`${k} (the workspace default — the engine runs only one you set yourself)`);
18831
+ skipped.push(`${k} (the workspace default — the engine takes it only from your own profile)`);
18701
18832
  if (profile.atOnce !== undefined && !has("at-once")) {
18702
18833
  out.atOnce = profile.atOnce;
18703
18834
  used.push(`at-once ${profile.atOnce}`);
@@ -18770,7 +18901,7 @@ function flagsFromProfile2(flags, given, profile, home) {
18770
18901
  }
18771
18902
  }
18772
18903
  if (profile.reposDir && !has("repos-dir") && !has("repo")) {
18773
- out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join21(home, d.slice(1)) : d).join(":");
18904
+ out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join22(home, d.slice(1)) : d).join(":");
18774
18905
  used.push(`repos ${profile.reposDir}`);
18775
18906
  }
18776
18907
  if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
@@ -18913,7 +19044,11 @@ function engineClient2(o, org) {
18913
19044
  const env = o.env ?? process.env;
18914
19045
  const src = meterSource(o.home, undefined, { ...org ? { flag: org } : {}, env });
18915
19046
  if (src)
18916
- return fetchClient({ ...src, timeoutMs: ENGINE_TIMEOUT_MS2 });
19047
+ return fetchClient({
19048
+ ...src,
19049
+ timeoutMs: ENGINE_TIMEOUT_MS2,
19050
+ version: "0.1.47"
19051
+ });
18917
19052
  const asked = org?.trim() || env.SLEDS_ORG?.trim();
18918
19053
  if (asked && !selectOrg(readConfig(o.home), org, env).seat)
18919
19054
  return {
@@ -18961,12 +19096,12 @@ function memberMcpConfigs2(o, cwd) {
18961
19096
  });
18962
19097
  const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
18963
19098
  return [
18964
- read(claudeDir ? join21(claudeDir, ".claude.json") : join21(o.home, ".claude.json")),
18965
- ...cwd ? [read(join21(cwd, ".mcp.json"))] : []
19099
+ read(claudeDir ? join22(claudeDir, ".claude.json") : join22(o.home, ".claude.json")),
19100
+ ...cwd ? [read(join22(cwd, ".mcp.json"))] : []
18966
19101
  ];
18967
19102
  }
18968
19103
  function engineStateDir2(o, org, seat) {
18969
- return seatStateDir(orgStateDir(o.stateDir ?? join21(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
19104
+ return seatStateDir(orgStateDir(o.stateDir ?? join22(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
18970
19105
  }
18971
19106
  function engineSeat2(o, org) {
18972
19107
  try {
@@ -18986,7 +19121,7 @@ function engineToken2(o, org) {
18986
19121
  }
18987
19122
  var withToken2 = (token, now) => token ? { token, tokenNow: now } : {};
18988
19123
  function engineDeps2(o, flags, source, runner, stateName) {
18989
- const exec = o.exec ?? defaultExec;
19124
+ const exec = guardGit(o.exec ?? defaultExec);
18990
19125
  const cwd = o.cwd ?? process.cwd();
18991
19126
  const exists = o.exists ?? realExists2;
18992
19127
  const log = o.log ?? console.log;
@@ -18996,8 +19131,8 @@ function engineDeps2(o, flags, source, runner, stateName) {
18996
19131
  const repo = flags.repo ? resolve10(cwd, flags.repo) : undefined;
18997
19132
  const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve10(cwd, d));
18998
19133
  const { branch, prTitle } = flags;
18999
- const hooksDir = join21(stateDir, "hooks");
19000
- const permissionMark = (name) => join21(hooksDir, `${name}.permission.json`);
19134
+ const hooksDir = join22(stateDir, "hooks");
19135
+ const permissionMark = (name) => join22(hooksDir, `${name}.permission.json`);
19001
19136
  const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
19002
19137
  return {
19003
19138
  source,
@@ -19022,9 +19157,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
19022
19157
  sandbox: true,
19023
19158
  writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
19024
19159
  const gitCommonDir = gitCommonDirOf2(exec, cwd);
19025
- const dir = join21(stateDir, "sandbox");
19160
+ const dir = join22(stateDir, "sandbox");
19026
19161
  mkdirSync16(dir, { recursive: true, mode: 448 });
19027
- const p = join21(dir, `${name}.json`);
19162
+ const p = join22(dir, `${name}.json`);
19028
19163
  const walls = engineSandboxSettings2(o.home, o.env ?? process.env, gitCommonDir, [
19029
19164
  ...SANDBOX_DEFAULT_ALLOW,
19030
19165
  ...flags.sandboxAllow ?? []
@@ -19041,7 +19176,7 @@ function engineDeps2(o, flags, source, runner, stateName) {
19041
19176
  } : {},
19042
19177
  writeHookSettings: (name, allow) => {
19043
19178
  mkdirSync16(hooksDir, { recursive: true, mode: 448 });
19044
- const p = join21(hooksDir, `${name}.json`);
19179
+ const p = join22(hooksDir, `${name}.json`);
19045
19180
  const base = allow?.length ? { permissions: { allow: [...allow] } } : {};
19046
19181
  writeFileSync18(p, `${JSON.stringify(withHook(name, base), null, 2)}
19047
19182
  `, { mode: 384 });
@@ -19069,9 +19204,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
19069
19204
  exists
19070
19205
  }),
19071
19206
  writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
19072
- const dir = join21(stateDir, "mcp");
19207
+ const dir = join22(stateDir, "mcp");
19073
19208
  mkdirSync16(dir, { recursive: true, mode: 448 });
19074
- const p = join21(dir, `${name}.json`);
19209
+ const p = join22(dir, `${name}.json`);
19075
19210
  let others = {};
19076
19211
  if (flags.strictMcp && flags.mcpAllow?.length) {
19077
19212
  const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs2(o, worktree));
@@ -19087,9 +19222,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
19087
19222
  }),
19088
19223
  removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync9(p, { force: true })),
19089
19224
  writePrompt: o.writePrompt ?? ((name, text) => {
19090
- const dir = join21(stateDir, "prompts");
19225
+ const dir = join22(stateDir, "prompts");
19091
19226
  mkdirSync16(dir, { recursive: true, mode: 448 });
19092
- const p = join21(dir, `${name}.md`);
19227
+ const p = join22(dir, `${name}.md`);
19093
19228
  writeFileSync18(p, text, { mode: 384 });
19094
19229
  return p;
19095
19230
  }),
@@ -19116,8 +19251,16 @@ function engineDeps2(o, flags, source, runner, stateName) {
19116
19251
  }
19117
19252
  function sandboxDenyRead2(home, env) {
19118
19253
  return {
19119
- dirs: [...new Set([configDir(home, env), join21(home, ".config", "sleds")])],
19120
- files: [...new Set([tokenPath(home, env), join21(home, ".sleds-token")])]
19254
+ dirs: [...new Set([configDir(home, env), join22(home, ".config", "sleds")])],
19255
+ files: [
19256
+ ...new Set([
19257
+ tokenPath(home, env),
19258
+ join22(home, ".sleds-token"),
19259
+ settingsPath(home, env),
19260
+ backupPath(home, env),
19261
+ join22(claudeDir(home, env), "settings.local.json")
19262
+ ])
19263
+ ]
19121
19264
  };
19122
19265
  }
19123
19266
  function engineSandboxSettings2(home, env, gitCommonDir, allow) {
@@ -19141,6 +19284,8 @@ function sandboxRefusal(flags) {
19141
19284
  return "sandboxed sessions: the conductor runner starts them in Conductor's cloud, where the engine cannot put the sandbox on — use another runner, or --no-sandbox";
19142
19285
  if (flags.agent && sandboxAgentKind(flags.agent) === null)
19143
19286
  return `sandboxed sessions: --agent '${flags.agent}' is neither Claude Code nor Codex, so the engine cannot sandbox it — use one of those, or --no-sandbox`;
19287
+ if (flags.agent && sandboxAgentKind(flags.agent) === "codex")
19288
+ return "sandboxed sessions: Codex's sandbox walls writes, not reads — the seat token stays readable; use Claude Code, or --no-sandbox";
19144
19289
  return null;
19145
19290
  }
19146
19291
  function pinOrg3(configJson, org) {
@@ -19183,7 +19328,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
19183
19328
  runner: deps.runner.name,
19184
19329
  atOnce: flags.atOnce,
19185
19330
  interval: flags.interval,
19186
- cliVersion: "0.1.46"
19331
+ cliVersion: "0.1.47"
19187
19332
  };
19188
19333
  const beat = (checkedAt) => {
19189
19334
  const m = deps.machine;
@@ -19369,7 +19514,7 @@ async function drive2(o, flags, deps, until, beat) {
19369
19514
  var SEAT_CHANGED_EXIT2 = 3;
19370
19515
  function engineRunner2(o, flags) {
19371
19516
  const runnerFor = o.runnerFor ?? runnerFor2;
19372
- return runnerFor(flags.runner, o.exec ?? defaultExec, {
19517
+ return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
19373
19518
  ...flags.runnerCmd ? { command: flags.runnerCmd } : {}
19374
19519
  });
19375
19520
  }
@@ -19510,7 +19655,7 @@ var engineCmd = async (o) => {
19510
19655
  if (!r || r.ok || !r.refused || r.refused === refused)
19511
19656
  return;
19512
19657
  refused = r.refused;
19513
- error(`${r.refused}. This engine is not shown as up until it beats under a name of its own.`);
19658
+ error(r.below ? `${r.refused}. This engine is not shown as up until it beats on a version SLEDS serves.` : `${r.refused}. This engine is not shown as up until it beats under a name of its own.`);
19514
19659
  };
19515
19660
  afterTick = () => {
19516
19661
  try {
@@ -19608,7 +19753,7 @@ async function enginePauseCmd2(o) {
19608
19753
  source = sledsSource(c, { engine, log });
19609
19754
  }
19610
19755
  const why = parsed.why ?? `paused on ${defaultEngineName2(host)} (sleds engine pause)`;
19611
- const exec = o.exec ?? defaultExec;
19756
+ const exec = guardGit(o.exec ?? defaultExec);
19612
19757
  const gone = new Set;
19613
19758
  for (const run of running) {
19614
19759
  const at = `${run.item}/${run.node}`;
@@ -19657,14 +19802,15 @@ import {
19657
19802
  writeFileSync as writeFileSync19
19658
19803
  } from "node:fs";
19659
19804
  import { hostname as hostname5 } from "node:os";
19660
- import { basename as basename5, dirname as dirname13, isAbsolute as isAbsolute3, join as join22 } from "node:path";
19805
+ import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute3, join as join23 } from "node:path";
19661
19806
  init_state();
19662
19807
  var ENGINE_LABEL2 = "ai.sleds.engine";
19663
19808
  var ENGINE_INSTALL_USAGE2 = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
19664
19809
  ${ENGINE_USAGE}`;
19665
- function stableArgv2(argv, realpath = realpathSync2) {
19810
+ function stableArgv2(argv, realpath = realpathSync2, home) {
19811
+ const link = sledsLink(home);
19666
19812
  return argv.map((a) => {
19667
- if (!isAbsolute3(a))
19813
+ if (!isAbsolute3(a) || a === link)
19668
19814
  return a;
19669
19815
  try {
19670
19816
  return realpath(a);
@@ -19677,13 +19823,13 @@ function engineLabel2(name, org, seat) {
19677
19823
  return [ENGINE_LABEL2, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
19678
19824
  }
19679
19825
  function enginePlistPath2(home, name, org, seat) {
19680
- return join22(home, "Library", "LaunchAgents", `${engineLabel2(name, org, seat)}.plist`);
19826
+ return join23(home, "Library", "LaunchAgents", `${engineLabel2(name, org, seat)}.plist`);
19681
19827
  }
19682
19828
  function engineLogPath2(stateDir, name) {
19683
- return join22(stateDir, `${engineSlug(name)}.log`);
19829
+ return join23(stateDir, `${engineSlug(name)}.log`);
19684
19830
  }
19685
19831
  function engineEventsPath2(stateDir, name) {
19686
- return join22(stateDir, `${engineSlug(name)}.events.jsonl`);
19832
+ return join23(stateDir, `${engineSlug(name)}.events.jsonl`);
19687
19833
  }
19688
19834
  var xmlEscape4 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19689
19835
  function buildEnginePlist2(o) {
@@ -19780,7 +19926,7 @@ function readEngines2(dir, suffix, manager, parse) {
19780
19926
  }
19781
19927
  const out = [];
19782
19928
  for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL2}.`) && n.endsWith(suffix))) {
19783
- const path = join22(dir, name);
19929
+ const path = join23(dir, name);
19784
19930
  let parsed;
19785
19931
  try {
19786
19932
  parsed = parse(readFileSync19(path, "utf8"), name);
@@ -19800,10 +19946,10 @@ function readEngines2(dir, suffix, manager, parse) {
19800
19946
  }
19801
19947
  function installedEngines2(home) {
19802
19948
  return [
19803
- ...readEngines2(join22(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
19949
+ ...readEngines2(join23(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
19804
19950
  ...readEngines2(engineUnitDir(home), ".service", "systemd", (text, file) => {
19805
19951
  const parsed = parseEngineUnit(text);
19806
- return parsed && { label: basename5(file, ".service"), ...parsed };
19952
+ return parsed && { label: basename6(file, ".service"), ...parsed };
19807
19953
  })
19808
19954
  ];
19809
19955
  }
@@ -19838,7 +19984,7 @@ async function ensureReposDir(o) {
19838
19984
  return false;
19839
19985
  }
19840
19986
  const exists = o.exists ?? existsSync18;
19841
- const missing = dirs.filter((d) => !exists(/^~(\/|$)/.test(d) ? join22(o.home, d.slice(1)) : d));
19987
+ const missing = dirs.filter((d) => !exists(/^~(\/|$)/.test(d) ? join23(o.home, d.slice(1)) : d));
19842
19988
  if (missing.length) {
19843
19989
  error(`Not a folder on this machine: ${missing.join(", ")}. ${REPOS_DIR_NEEDED}`);
19844
19990
  return false;
@@ -19882,7 +20028,7 @@ function engineInstall2(o) {
19882
20028
  const label = engineLabel2(parsed.name, parsed.org, seat);
19883
20029
  const logPath = engineLogPath2(stateDir, parsed.name);
19884
20030
  mkdirSync17(stateDir, { recursive: true, mode: 448 });
19885
- const sledsArgv = stableArgv2(o.sledsArgv, o.realpath);
20031
+ const sledsArgv = stableArgv2(o.sledsArgv, o.realpath, o.home);
19886
20032
  const execPath = sledsArgv[0] ?? process.execPath;
19887
20033
  const agentEnv = {
19888
20034
  PATH: musherPath(o.home, execPath, env.PATH ?? ""),
@@ -19934,7 +20080,7 @@ function installUnit2(a) {
19934
20080
  const log = o.log ?? console.log;
19935
20081
  const error = o.error ?? console.error;
19936
20082
  const unit = engineUnitPath(o.home, label);
19937
- const unitName = basename5(unit);
20083
+ const unitName = basename6(unit);
19938
20084
  const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
19939
20085
  mkdirSync17(dirname13(unit), { recursive: true });
19940
20086
  if (existsSync18(unit))
@@ -19944,7 +20090,7 @@ function installUnit2(a) {
19944
20090
  continue;
19945
20091
  if (engineArg2(other.programArgs, "name") !== parsed.name)
19946
20092
  continue;
19947
- systemctl("disable", "--now", basename5(other.plist));
20093
+ systemctl("disable", "--now", basename6(other.plist));
19948
20094
  rmSync10(other.plist, { force: true });
19949
20095
  log(`replaced ${other.label}, this engine as installed before`);
19950
20096
  }
@@ -20003,13 +20149,13 @@ function engineUninstall2(o) {
20003
20149
  const unit = file.endsWith(".service");
20004
20150
  const exec = o.exec ?? defaultExec2;
20005
20151
  if (unit)
20006
- exec("systemctl", ["--user", "disable", "--now", basename5(file)]);
20152
+ exec("systemctl", ["--user", "disable", "--now", basename6(file)]);
20007
20153
  else
20008
20154
  exec("launchctl", ["unload", file]);
20009
20155
  rmSync10(file, { force: true });
20010
20156
  if (unit)
20011
20157
  exec("systemctl", ["--user", "daemon-reload"]);
20012
- log(`engine:${name} removed: ${basename5(file, unit ? ".service" : ".plist")} — its sessions keep running`);
20158
+ log(`engine:${name} removed: ${basename6(file, unit ? ".service" : ".plist")} — its sessions keep running`);
20013
20159
  return 0;
20014
20160
  }
20015
20161
 
@@ -20955,9 +21101,9 @@ init_meter();
20955
21101
  // src/owed.ts
20956
21102
  init_config();
20957
21103
  import { existsSync as existsSync22, mkdirSync as mkdirSync18, readFileSync as readFileSync23, renameSync as renameSync7, writeFileSync as writeFileSync20 } from "node:fs";
20958
- import { dirname as dirname14, join as join23 } from "node:path";
20959
- var owedPath = (home) => join23(configDir(home), "owed.json");
20960
- var sessionPath = (home) => join23(configDir(home), "session.json");
21104
+ import { dirname as dirname14, join as join24 } from "node:path";
21105
+ var owedPath = (home) => join24(configDir(home), "owed.json");
21106
+ var sessionPath = (home) => join24(configDir(home), "session.json");
20961
21107
  var OWED_TTL_MS = 3 * 24 * 60 * 60000;
20962
21108
  var str13 = (v) => typeof v === "string" ? v : undefined;
20963
21109
  function sourceKey(s) {
@@ -21111,7 +21257,12 @@ function trackingClient(client, home, now) {
21111
21257
  function contextFor(deps) {
21112
21258
  const src = meterSource(deps.home, runTokenOf(deps.env));
21113
21259
  const now = deps.now ?? Date.now;
21114
- const client = src ? trackingClient(fetchClient({ ...src, fetchFn: deps.fetchFn, timeoutMs: deps.timeoutMs }), deps.home, now) : null;
21260
+ const client = src ? trackingClient(fetchClient({
21261
+ ...src,
21262
+ fetchFn: deps.fetchFn,
21263
+ timeoutMs: deps.timeoutMs,
21264
+ version: "0.1.47"
21265
+ }), deps.home, now) : null;
21115
21266
  return {
21116
21267
  channel: "code",
21117
21268
  client,
@@ -21380,7 +21531,7 @@ var DEVICE_REASONS = {
21380
21531
  bad_answer: "the proxy gave an answer this CLI does not understand — update it: curl -fsSL sleds.ai/install | sh"
21381
21532
  };
21382
21533
  function deviceFailureText(reason) {
21383
- return `Sign-in did not complete: ${DEVICE_REASONS[reason]} Or mint a seat on the dashboard (Settings › Your seat & tools) and run \`sleds init --token …\`.`;
21534
+ return `Sign-in did not complete: ${DEVICE_REASONS[reason]} Or mint a seat on the dashboard (Settings › Your seat & tools), set it as SLEDS_TOKEN and run \`sleds init\`.`;
21384
21535
  }
21385
21536
  function parseStart(body) {
21386
21537
  if (typeof body !== "object" || body === null)
@@ -21642,7 +21793,7 @@ var SIGNUP_REASONS = {
21642
21793
  not_configured: "the proxy is not set up for self-serve signup yet.",
21643
21794
  team: "the team needs a name (2–80 characters).",
21644
21795
  personal_email: "a team needs a work email — that domain is a personal mailbox. Sign up as an individual instead, or use your company address.",
21645
- org_exists: "someone at your company already set up SLEDS. Ask them for a seat (Members → invite, Admin → Mint a seat) and run `sleds init --token …`.",
21796
+ org_exists: "someone at your company already set up SLEDS. Ask them to invite you (Members → invite), then run `sleds init` and sign in through the browser.",
21646
21797
  unavailable: "the proxy could not reach its control plane. Try again in a moment.",
21647
21798
  unreachable: "could not reach the proxy.",
21648
21799
  code: "that code is six digits.",
@@ -21769,7 +21920,7 @@ var resolveToken = async (o) => {
21769
21920
  return null;
21770
21921
  }
21771
21922
  log(`Created ${team} with you as owner (${email}).${credential ? " Your platform key is stored encrypted as the org's upstream key." : " No platform key yet — add one on the dashboard (Admin → Keys) to unlock continue / overnight / switch at a wall."}`);
21772
- log("Invite your team on the dashboard (Members → invite by email, Admin → Mint a seat); each person runs `sleds init --token …`.");
21923
+ log("Invite your team on the dashboard (Members → invite by email, Admin → Mint a seat); each person runs `sleds init` and signs in through the browser.");
21773
21924
  return { token: r.token, source: "signup" };
21774
21925
  }
21775
21926
  const credential = (await o.prompt("Your Anthropic API key (sk-ant-…, stored encrypted, spends only your account): ")).trim();
@@ -21793,7 +21944,7 @@ var init = async (o) => {
21793
21944
  }
21794
21945
  const resolved = await resolveToken(o);
21795
21946
  if (!resolved) {
21796
- error(o.signup ? "Signup did not complete. Nothing was changed." : "No seat token. Run `sleds init` without --non-interactive to sign in through the browser, or pass --token / set SLEDS_TOKEN.");
21947
+ error(o.signup ? "Signup did not complete. Nothing was changed." : "No seat token. Run `sleds init` without --non-interactive to sign in through the browser, or set SLEDS_TOKEN (never the token on the command line).");
21797
21948
  return 2;
21798
21949
  }
21799
21950
  if (!isSeatToken(resolved.token)) {
@@ -22509,7 +22660,7 @@ var on = (o) => {
22509
22660
  return 2;
22510
22661
  }
22511
22662
  if (!isSeatToken(token)) {
22512
- error("Saved token is not a sled_ token. Run `sleds init --token <sled_…>`.");
22663
+ error("Saved token is not a sled_ token. Run `sleds login` to sign in again.");
22513
22664
  return 2;
22514
22665
  }
22515
22666
  if (cfg.org && !cfg.org.capabilities.upstreamKey) {
@@ -22677,7 +22828,7 @@ var orgCmd = (o) => {
22677
22828
  init_src();
22678
22829
  import { spawnSync as spawnSync8 } from "node:child_process";
22679
22830
  import { writeFileSync as writeFileSync23 } from "node:fs";
22680
- import { join as join24 } from "node:path";
22831
+ import { join as join25 } from "node:path";
22681
22832
  function packFileName(key) {
22682
22833
  return `pack-${slugify(key, 80) || "item"}.md`;
22683
22834
  }
@@ -22705,7 +22856,7 @@ var packCmd = async (o) => {
22705
22856
  log(r.text);
22706
22857
  return 0;
22707
22858
  }
22708
- const path = join24(o.cwd ?? process.cwd(), packFileName(key));
22859
+ const path = join25(o.cwd ?? process.cwd(), packFileName(key));
22709
22860
  (o.write ?? ((p, t) => writeFileSync23(p, t.endsWith(`
22710
22861
  `) ? t : `${t}
22711
22862
  `)))(path, r.text);
@@ -22964,7 +23115,9 @@ function parseVerbArgs(argv, allowed) {
22964
23115
  if (flag === "name")
22965
23116
  out.name = value;
22966
23117
  i++;
22967
- } else if (out.key === undefined)
23118
+ } else if (a.startsWith("-"))
23119
+ return { error: `unknown flag ${a}` };
23120
+ else if (out.key === undefined)
22968
23121
  out.key = a;
22969
23122
  else
22970
23123
  return { error: `one item at a time — "${a}" is extra` };
@@ -23146,7 +23299,7 @@ async function proposeCmd(o, argv) {
23146
23299
  log(`- ${w}`);
23147
23300
  const shown = typeof r.json?.key === "string" ? r.json.key : a.key;
23148
23301
  const text = typeof r.json?.text === "string" ? r.json.text : "";
23149
- log(text.replace(/\n*Nothing runs until a person says yes:[^\n]*$/, "") || `${shown} · route drafted, not filed`);
23302
+ log(text.replace(/\n*Nothing runs until a person says yes:[^\n]*$/, "") || `${shown} · route planned, not filed`);
23150
23303
  log("");
23151
23304
  log(`Nothing runs until a person approves it: \`sleds route approve ${shown}\`, or Approve in the app.`);
23152
23305
  });
@@ -23188,7 +23341,7 @@ async function approveCmd(o, argv) {
23188
23341
  return said(o, a.key, a.json, r, () => log(approvedLine(a.key, r.json ?? {})));
23189
23342
  }
23190
23343
  async function redraftCmd(o, argv) {
23191
- return oneVerb(o, argv, REDRAFT_USAGE, { draft: "retry" }, "nothing re-drafted", (key) => redraftLine(key));
23344
+ return oneVerb(o, argv, REDRAFT_USAGE, { draft: "retry" }, "nothing planned again", (key) => redraftLine(key));
23192
23345
  }
23193
23346
  async function singleCmd(o, argv) {
23194
23347
  return oneVerb(o, argv, SINGLE_USAGE, { single: true }, "nothing changed", (key) => singleLine(key));
@@ -23216,17 +23369,17 @@ async function oneVerb(o, argv, usage, body, unreachable, line) {
23216
23369
  return said(o, a.key, a.json, r, () => log(line(shown)));
23217
23370
  }
23218
23371
  function redraftLine(key) {
23219
- return `${key} re-draft asked — the engine drafts its route on its next check`;
23372
+ return `${key} plan again asked — the engine plans its route on its next check`;
23220
23373
  }
23221
23374
  function singleLine(key) {
23222
- return `${key} runs as one node — it is not drafted again`;
23375
+ return `${key} runs as one node — it is not planned again`;
23223
23376
  }
23224
23377
  function answeredLine(key, route, held) {
23225
23378
  const nodes = Array.isArray(held) && held.length ? ` (${held.join(", ")})` : "";
23226
23379
  if (route === "accept")
23227
23380
  return `${key}: change accepted — what it held${nodes} waits until the route is re-filed`;
23228
23381
  if (route === "redraft")
23229
- return `${key}: re-draft asked — what it held${nodes} waits until the route is re-filed`;
23382
+ return `${key}: plan again asked — what it held${nodes} waits until the route is re-filed`;
23230
23383
  if (route === "keep")
23231
23384
  return `${key}: route kept as filed — what it held is released`;
23232
23385
  return `${key}: answered — what it held is released`;
@@ -23303,12 +23456,24 @@ function lookToReady(route, id) {
23303
23456
  return { error: `no decision ${id} on this item` };
23304
23457
  if (d.kind !== "look")
23305
23458
  return { error: `decision ${id} is not a look — --ready marks a look` };
23459
+ if (d.state === "superseded" || d.state === "answered")
23460
+ return { settled: `decision ${id} is ${d.state}` };
23306
23461
  if (d.state !== "escalated")
23307
23462
  return { error: `decision ${id} is ${String(d.state)} — not a look you owe` };
23308
23463
  const about = d.about && typeof d.about === "object" ? d.about : {};
23309
23464
  const pr = Array.isArray(about.prs) ? about.prs.find((p) => typeof p === "string" && p) : undefined;
23310
23465
  return typeof pr === "string" ? { pr } : { error: `decision ${id} names no PR` };
23311
23466
  }
23467
+ function prLookState(stdout) {
23468
+ try {
23469
+ const j = JSON.parse(stdout);
23470
+ if (!j || typeof j.isDraft !== "boolean" || typeof j.state !== "string")
23471
+ return null;
23472
+ return { isDraft: j.isDraft, state: j.state };
23473
+ } catch {
23474
+ return null;
23475
+ }
23476
+ }
23312
23477
  async function readyCmd(o, argv) {
23313
23478
  const log = o.log ?? console.log;
23314
23479
  const error = o.error ?? console.error;
@@ -23329,6 +23494,13 @@ async function readyCmd(o, argv) {
23329
23494
  error(reader.error);
23330
23495
  return 1;
23331
23496
  }
23497
+ const settled = (why) => {
23498
+ if (json)
23499
+ log(JSON.stringify({ ok: true, settled: why }));
23500
+ else
23501
+ log(`${key}: the look is already settled — nothing to do`);
23502
+ return 0;
23503
+ };
23332
23504
  const route = await reader.read(key).catch((e) => {
23333
23505
  error(e instanceof Error ? e.message : String(e));
23334
23506
  return;
@@ -23340,12 +23512,25 @@ async function readyCmd(o, argv) {
23340
23512
  error(`${key}: ${look.error}`);
23341
23513
  return 1;
23342
23514
  }
23343
- const gh = (o.exec ?? defaultExec)("gh", ["pr", "ready", look.pr]);
23344
- if (gh.status !== 0) {
23345
- error(gh.stderr.trim() || `gh pr ready ${look.pr} exited ${gh.status}`);
23515
+ if ("settled" in look)
23516
+ return settled(look.settled);
23517
+ const exec = o.exec ?? defaultExec;
23518
+ const view = exec("gh", ["pr", "view", look.pr, "--json", "isDraft,state"]);
23519
+ const pr = view.status === 0 ? prLookState(view.stdout) : null;
23520
+ if (!pr) {
23521
+ error(view.stderr.trim() || (view.status === 0 ? `gh pr view ${look.pr} said nothing readable` : `gh pr view ${look.pr} exited ${view.status}`));
23346
23522
  error(`${key}: the look is not answered`);
23347
23523
  return 1;
23348
23524
  }
23525
+ const draft = pr.state === "OPEN" && pr.isDraft;
23526
+ if (draft) {
23527
+ const gh = exec("gh", ["pr", "ready", look.pr]);
23528
+ if (gh.status !== 0) {
23529
+ error(gh.stderr.trim() || `gh pr ready ${look.pr} exited ${gh.status}`);
23530
+ error(`${key}: the look is not answered`);
23531
+ return 1;
23532
+ }
23533
+ }
23349
23534
  const r = await client.postFull("/proxy/route/decision", {
23350
23535
  project: key,
23351
23536
  id,
@@ -23355,7 +23540,13 @@ async function readyCmd(o, argv) {
23355
23540
  error(`${key}: ${look.pr} is ready for review, but SLEDS is unreachable — the look is not answered`);
23356
23541
  return 1;
23357
23542
  }
23358
- return said(o, key, json, r, () => log(`${key}: ${look.pr} marked ready for review — the look is answered`));
23543
+ if (r.status >= 300 || r.json?.ok === false) {
23544
+ const again = await reader.read(key).catch(() => null);
23545
+ const now = lookToReady(again ?? null, id);
23546
+ if ("settled" in now)
23547
+ return settled(now.settled);
23548
+ }
23549
+ return said(o, key, json, r, () => log(draft ? `${key}: ${look.pr} marked ready for review — the look is answered` : `${key}: ${look.pr} is ${pr.state === "OPEN" ? "already ready for review" : pr.state.toLowerCase()} — the look is answered`));
23359
23550
  }
23360
23551
  var DECISIONS_USAGE = "usage: sleds route decisions [<key>] [--flagged] [--json]";
23361
23552
  function decisionsLines(raw) {
@@ -23368,7 +23559,7 @@ function decisionsLines(raw) {
23368
23559
  const first = q.replace(/\s+/g, " ").trim().slice(0, 100);
23369
23560
  const where = [d.project && !j.project ? d.project : null, d.node].filter(Boolean).join("/");
23370
23561
  const flag = d.flagged ? " · decided for you" : "";
23371
- const pending = d.redraftPending ? " · re-draft pending" : "";
23562
+ const pending = d.redraftPending ? " · plan again pending" : "";
23372
23563
  return `${String(d.state)}${flag}${pending} ${where || "—"} ${first} [${String(d.id)}]`;
23373
23564
  });
23374
23565
  }
@@ -23584,12 +23775,14 @@ function routeReader(o, org) {
23584
23775
  read: (k) => readOrSay(client, `/proxy/route?q=${encodeURIComponent(k)}`, k)
23585
23776
  };
23586
23777
  }
23587
- var SLED_USAGE = "usage: sleds sled --json | sleds sled top <KEY>";
23778
+ var SLED_USAGE = "usage: sleds sled --json | sleds sled top <KEY> | sleds sled order <KEY>…";
23588
23779
  async function sledCmd(o) {
23589
23780
  const log = o.log ?? console.log;
23590
23781
  const error = o.error ?? console.error;
23591
23782
  const top = o.argv[0] === "top" && o.argv.length === 2 && !o.argv[1]?.startsWith("-");
23592
- if (!top && (o.argv.length !== 1 || o.argv[0] !== "--json")) {
23783
+ const keys = o.argv.slice(1);
23784
+ const order = o.argv[0] === "order" && keys.length > 0 && keys.every((k) => k.trim() && !k.startsWith("-"));
23785
+ if (!top && !order && (o.argv.length !== 1 || o.argv[0] !== "--json")) {
23593
23786
  error(SLED_USAGE);
23594
23787
  return 2;
23595
23788
  }
@@ -23600,6 +23793,8 @@ async function sledCmd(o) {
23600
23793
  }
23601
23794
  if (top)
23602
23795
  return sledTop(client, o.argv[1], log, error);
23796
+ if (order)
23797
+ return sledOrder(client, keys, log, error);
23603
23798
  try {
23604
23799
  log(JSON.stringify(await readOrSay(client, "/proxy/sled", "the sled")));
23605
23800
  return 0;
@@ -23621,6 +23816,19 @@ async function sledTop(client, key, log, error) {
23621
23816
  log(`${typeof r.json?.key === "string" ? r.json.key : key} is first on your sled`);
23622
23817
  return 0;
23623
23818
  }
23819
+ async function sledOrder(client, keys, log, error) {
23820
+ const r = await client.postFull("/proxy/sled/order", { order: keys });
23821
+ if (!r) {
23822
+ error("SLEDS unreachable — the sled is unchanged");
23823
+ return 1;
23824
+ }
23825
+ if (r.status >= 300 || r.json?.ok === false) {
23826
+ error(typeof r.json?.error === "string" ? r.json.error : `sled order: HTTP ${r.status}`);
23827
+ return 1;
23828
+ }
23829
+ log(`${typeof r.json?.ordered === "number" ? r.json.ordered : keys.length} ordered on your sled`);
23830
+ return 0;
23831
+ }
23624
23832
 
23625
23833
  // src/commands/run.ts
23626
23834
  init_config();
@@ -23726,12 +23934,12 @@ var seatEvent = async (o) => {
23726
23934
  import { execFileSync as execFileSync5 } from "node:child_process";
23727
23935
  import { existsSync as existsSync26, mkdirSync as mkdirSync22, readFileSync as readFileSync28, readdirSync as readdirSync5, rmSync as rmSync16, writeFileSync as writeFileSync25 } from "node:fs";
23728
23936
  import { platform as platform2 } from "node:os";
23729
- import { dirname as dirname17, join as join26 } from "node:path";
23937
+ import { dirname as dirname17, join as join27 } from "node:path";
23730
23938
 
23731
23939
  // src/cookieDb.ts
23732
23940
  import { copyFileSync, rmSync as rmSync15 } from "node:fs";
23733
23941
  import { tmpdir as tmpdir2 } from "node:os";
23734
- import { join as join25 } from "node:path";
23942
+ import { join as join26 } from "node:path";
23735
23943
  var QUERY = "SELECT name, hex(encrypted_value) AS ev FROM cookies WHERE host_key LIKE '%claude.ai%'";
23736
23944
  var isBun = () => typeof globalThis.Bun !== "undefined";
23737
23945
  async function queryRows(dbPath) {
@@ -23760,7 +23968,7 @@ function nodeSqlite() {
23760
23968
  return mod;
23761
23969
  }
23762
23970
  async function readCookieRows(dbPath) {
23763
- const copy = join25(tmpdir2(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
23971
+ const copy = join26(tmpdir2(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
23764
23972
  copyFileSync(dbPath, copy);
23765
23973
  try {
23766
23974
  const rows = await queryRows(copy);
@@ -24053,7 +24261,7 @@ function findFile(root, name) {
24053
24261
  continue;
24054
24262
  }
24055
24263
  for (const e of entries) {
24056
- const p = join26(dir, e.name);
24264
+ const p = join27(dir, e.name);
24057
24265
  if (e.isDirectory())
24058
24266
  stack.push(p);
24059
24267
  else if (e.name === name)
@@ -24064,7 +24272,7 @@ function findFile(root, name) {
24064
24272
  }
24065
24273
  function findCookieDb(home, source) {
24066
24274
  const b = BROWSERS[source.browser];
24067
- const root = join26(home, APP_SUPPORT, b.appDir);
24275
+ const root = join27(home, APP_SUPPORT, b.appDir);
24068
24276
  if (!existsSync26(root))
24069
24277
  throw new Error(`no ${source.browser} data at ${root} (is it installed?)`);
24070
24278
  if (!b.profiled) {
@@ -24073,7 +24281,7 @@ function findCookieDb(home, source) {
24073
24281
  throw new Error(`no cookie store under ${root}`);
24074
24282
  return db;
24075
24283
  }
24076
- const localStatePath = join26(root, "Local State");
24284
+ const localStatePath = join27(root, "Local State");
24077
24285
  const localState = existsSync26(localStatePath) ? readFileSync28(localStatePath, "utf8") : null;
24078
24286
  const wanted = source.profile ?? "Default";
24079
24287
  const { dir, ambiguous } = resolveProfileDir(localState, wanted);
@@ -24081,7 +24289,7 @@ function findCookieDb(home, source) {
24081
24289
  throw new Error(`"${wanted}" names ${ambiguous.length} ${source.browser} profiles (${ambiguous.join(", ")}) — pass the directory or the account email instead`);
24082
24290
  if (!dir)
24083
24291
  throw new Error(`no ${source.browser} profile named "${wanted}" (check chrome://version)`);
24084
- const db = cookieDbCandidates(join26(root, dir)).find((p) => existsSync26(p));
24292
+ const db = cookieDbCandidates(join27(root, dir)).find((p) => existsSync26(p));
24085
24293
  if (!db)
24086
24294
  throw new Error(`profile "${dir}" has no cookie store yet (open claude.ai in it once)`);
24087
24295
  return db;
@@ -24123,11 +24331,11 @@ function fetchSeatUsage(jar, org, now, run) {
24123
24331
  return { usage: null, status };
24124
24332
  }
24125
24333
  }
24126
- function launchAgentPlist(bun, script, home, source) {
24334
+ function launchAgentPlist(argv, home, source) {
24127
24335
  const label = launchLabel(source);
24128
- const log = join26(home, ".config", "sleds", `${label.slice("ai.sleds.".length)}.log`);
24336
+ const log = join27(home, ".config", "sleds", `${label.slice("ai.sleds.".length)}.log`);
24129
24337
  const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
24130
- const args = [bun, script, "seat-sync", ...sourceArgs(source)].map((a) => ` <string>${esc(a)}</string>`).join(`
24338
+ const args = [...argv, "seat-sync", ...sourceArgs(source)].map((a) => ` <string>${esc(a)}</string>`).join(`
24131
24339
  `);
24132
24340
  return `<?xml version="1.0" encoding="UTF-8"?>
24133
24341
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -24147,16 +24355,14 @@ ${args}
24147
24355
  `;
24148
24356
  }
24149
24357
  function plistPath2(home, source) {
24150
- return join26(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
24358
+ return join27(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
24151
24359
  }
24152
- function install(home, argv, source, log) {
24153
- const bun = argv[0] ?? process.execPath;
24154
- const script = argv[1] ?? "";
24155
- if (!script) {
24156
- log("cannot resolve the sleds script path to install the timer");
24360
+ function install(home, argv, source, log, launchctl) {
24361
+ if (!argv[0]) {
24362
+ log("cannot resolve the sleds command to install the timer");
24157
24363
  return 1;
24158
24364
  }
24159
- const dir = join26(home, "Library", "LaunchAgents");
24365
+ const dir = join27(home, "Library", "LaunchAgents");
24160
24366
  mkdirSync22(dir, { recursive: true });
24161
24367
  const path = plistPath2(home, source);
24162
24368
  const tokenPath = seatTokenPath(home, source);
@@ -24166,11 +24372,11 @@ function install(home, argv, source, log) {
24166
24372
  writeFileSync25(tokenPath, `${source.token}
24167
24373
  `, { mode: 384 });
24168
24374
  }
24169
- writeFileSync25(path, launchAgentPlist(bun, script, home, source), { mode: 384 });
24375
+ writeFileSync25(path, launchAgentPlist(argv, home, source), { mode: 384 });
24170
24376
  try {
24171
- execFileSync5("launchctl", ["unload", path], { stdio: "ignore" });
24377
+ launchctl(["unload", path]);
24172
24378
  } catch {}
24173
- execFileSync5("launchctl", ["load", "-w", path]);
24379
+ launchctl(["load", "-w", path]);
24174
24380
  log(`seat-sync timer installed (every ${SYNC_INTERVAL_S / 60} min) → ${path}`);
24175
24381
  return 0;
24176
24382
  }
@@ -24195,7 +24401,9 @@ var seatSync = async (o) => {
24195
24401
  if (source.uninstall)
24196
24402
  return uninstall(o.home, source, log);
24197
24403
  if (source.install)
24198
- return install(o.home, [process.execPath, process.argv[1] ?? ""], source, log);
24404
+ return install(o.home, o.sledsArgv ?? [process.execPath, process.argv[1] ?? ""], source, log, o.launchctl ?? ((args) => {
24405
+ execFileSync5("launchctl", args, args[0] === "unload" ? { stdio: "ignore" } : {});
24406
+ }));
24199
24407
  if (platform2() !== "darwin" && !o.readCookieRows) {
24200
24408
  log("seat-sync is macOS-only for now.");
24201
24409
  return 2;
@@ -24338,7 +24546,7 @@ var sessionEvent = async (o) => {
24338
24546
  // src/commands/specEvent.ts
24339
24547
  init_meter();
24340
24548
  import { readFileSync as readFileSync29, statSync as statSync2 } from "node:fs";
24341
- import { basename as basename6, isAbsolute as isAbsolute4, relative } from "node:path";
24549
+ import { basename as basename7, isAbsolute as isAbsolute4, relative } from "node:path";
24342
24550
  var HOOK_STDIN_TIMEOUT_MS3 = 1000;
24343
24551
  var ESTIMATE_TIMEOUT_MS = 4000;
24344
24552
  var MIN_SPEC_CHARS = 200;
@@ -24351,12 +24559,12 @@ function isSpecPath(path) {
24351
24559
  return false;
24352
24560
  if (NOT_SPEC.test(path))
24353
24561
  return false;
24354
- return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename6(path));
24562
+ return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename7(path));
24355
24563
  }
24356
24564
  function specTitle(body, path) {
24357
24565
  const m = /^#\s+(.+?)\s*$/m.exec(body);
24358
24566
  const t = m?.[1]?.trim();
24359
- return (t && t.length > 0 ? t : basename6(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
24567
+ return (t && t.length > 0 ? t : basename7(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
24360
24568
  }
24361
24569
  function looksLikeSpec(body) {
24362
24570
  if (body.trim().length < MIN_SPEC_CHARS)
@@ -24414,7 +24622,7 @@ var specEvent = async (o) => {
24414
24622
  const spec = {
24415
24623
  title: specTitle(body, input.filePath),
24416
24624
  body: body.slice(0, MAX_SPEC_CHARS),
24417
- repoHint: input.cwd ? basename6(input.cwd) : undefined
24625
+ repoHint: input.cwd ? basename7(input.cwd) : undefined
24418
24626
  };
24419
24627
  try {
24420
24628
  const res = await (o.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
@@ -25134,12 +25342,12 @@ var webhooksCmd = async (o) => {
25134
25342
  // src/config.ts
25135
25343
  init_settings();
25136
25344
  import { chmodSync as chmodSync7, existsSync as existsSync30, mkdirSync as mkdirSync23, readFileSync as readFileSync31, renameSync as renameSync9, writeFileSync as writeFileSync26 } from "node:fs";
25137
- import { join as join27, resolve as resolve11 } from "node:path";
25345
+ import { join as join28, resolve as resolve11 } from "node:path";
25138
25346
  var configDir2 = (home, env = process.env) => {
25139
25347
  const o = env.SLEDS_HOME?.trim();
25140
- return o ? resolve11(home, o) : join27(home, ".config", "sleds");
25348
+ return o ? resolve11(home, o) : join28(home, ".config", "sleds");
25141
25349
  };
25142
- var configPath2 = (home) => join27(configDir2(home), "config.json");
25350
+ var configPath2 = (home) => join28(configDir2(home), "config.json");
25143
25351
  var isObject17 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
25144
25352
  var optString2 = (v) => typeof v === "string" ? v : undefined;
25145
25353
  var parsePriorEnv2 = (v) => {
@@ -25315,6 +25523,12 @@ function runnerFor3(name, exec = defaultExec, o = {}) {
25315
25523
  }
25316
25524
  }
25317
25525
 
25526
+ // src/runtime.ts
25527
+ import { homedir as homedir2 } from "node:os";
25528
+ import { join as join29, win32 as win322 } from "node:path";
25529
+ var isCompiled = (argv1 = process.argv[1]) => Boolean(argv1 && (argv1.startsWith("/$bunfs/") || argv1.startsWith("B:\\~BUN\\")));
25530
+ var sledsLink2 = (home = homedir2(), platform = process.platform) => platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join29(home, ".sleds", "bin", "sleds");
25531
+
25318
25532
  // src/schedule.ts
25319
25533
  import { spawnSync as spawnSync11 } from "node:child_process";
25320
25534
  var defaultExec5 = (cmd, args) => {
@@ -25325,7 +25539,7 @@ var defaultExec5 = (cmd, args) => {
25325
25539
  };
25326
25540
 
25327
25541
  // src/settings.ts
25328
- import { dirname as dirname18, join as join28, resolve as resolve12 } from "node:path";
25542
+ import { dirname as dirname18, join as join30, resolve as resolve12 } from "node:path";
25329
25543
  var withSeatEnv2 = (command, home, env = process.env, org) => {
25330
25544
  const parts = [];
25331
25545
  const sh = env.SLEDS_HOME?.trim();
@@ -25421,6 +25635,7 @@ commands:
25421
25635
  Token from SLEDS_DEPLOY_TOKEN (Settings \u203A Deploys). SLEDS down never fails a release.
25422
25636
  sled --json What is on your sled (mine with each route, proposed, sent), for a front end.
25423
25637
  sleds sled top KEY put KEY first on your sled; the engine picks it next
25638
+ sleds sled order KEY\u2026 those items in this order, in the places they hold; the rest stay
25424
25639
  route <key> Print an item's route: its nodes, what each waits on, what is ready, where each
25425
25640
  run can be watched.
25426
25641
  --dot Graphviz instead: \`sleds route QW-142 --dot | dot -Tpng -o route.png\`
@@ -25430,10 +25645,10 @@ commands:
25430
25645
  disarms; --name <engine> sends it to that engine; --json)
25431
25646
  answer <key>/<node> answer a parked node: the words after it, or --stdin; it
25432
25647
  goes back to ready and the engine takes it (--json)
25433
- propose <key> hold a drafted route on the item for a person's yes, filing
25434
- nothing (a drafting session with no connector): --file
25648
+ propose <key> hold a planned route on the item for a person's yes, filing
25649
+ nothing (a planning session with no connector): --file
25435
25650
  <nodes.json> or --stdin, --name <engine> (--json)
25436
- approve <key> a person's yes to a drafted route: files it and, under
25651
+ approve <key> a person's yes to a planned route: files it and, under
25437
25652
  Pickup: Auto, arms it; --file <nodes.json> approves an
25438
25653
  edited set instead (--json)
25439
25654
  run <key> run the engine for this one item until its route lands
@@ -25469,8 +25684,8 @@ commands:
25469
25684
  high, xhigh or max. With --agent, a claude command gets it;
25470
25685
  another runs as given and the engine says so
25471
25686
  --decider-effort <e> the effort every answerer launches with; default the node's
25472
- --drafter-model <id> the model a drafting session launches with; default the node's
25473
- --drafter-effort <e> the effort a drafting session launches with; default the node's
25687
+ --drafter-model <id> the model a planning session launches with; default the node's
25688
+ --drafter-effort <e> the effort a planning session launches with; default the node's
25474
25689
  --pr-title '<template>' the PR title the session must use: {key} {ticket} {item}
25475
25690
  {node} {title}, e.g. 'feat: [{key}] {title}'
25476
25691
  Flags left out come from your engine profile in SLEDS (Settings); with Pickup:
@@ -25597,14 +25812,20 @@ var hookStdin = async () => {
25597
25812
  const text = await readStdin2(300);
25598
25813
  return text.trim() ? text : undefined;
25599
25814
  };
25600
- var sledsArgv = (execPath = process.execPath, script = process.argv[1], realpath) => stableArgv2(script ? [execPath, script] : [execPath], realpath);
25815
+ var sledsArgv = (execPath = process.execPath, script = process.argv[1], realpath, o = {}) => {
25816
+ if (isCompiled(script)) {
25817
+ const link = sledsLink2(o.home);
25818
+ return stableArgv2([(o.exists ?? existsSync31)(link) ? link : execPath], realpath, o.home);
25819
+ }
25820
+ return stableArgv2(script ? [execPath, script] : [execPath], realpath, o.home);
25821
+ };
25601
25822
  var shellQuote = (s) => /^[\w./-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
25602
- var statusLineCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "statusline"].map(shellQuote).join(" "), home);
25603
- var seatEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "seat-event"].map(shellQuote).join(" "), home);
25604
- var promptEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "prompt-event"].map(shellQuote).join(" "), home);
25605
- var sessionEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "session-event"].map(shellQuote).join(" "), home);
25606
- var stopEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "stop-event"].map(shellQuote).join(" "), home);
25607
- var specEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "spec-event"].map(shellQuote).join(" "), home);
25823
+ var statusLineCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "statusline"].map(shellQuote).join(" "), home);
25824
+ var seatEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "seat-event"].map(shellQuote).join(" "), home);
25825
+ var promptEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "prompt-event"].map(shellQuote).join(" "), home);
25826
+ var sessionEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "session-event"].map(shellQuote).join(" "), home);
25827
+ var stopEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "stop-event"].map(shellQuote).join(" "), home);
25828
+ var specEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "spec-event"].map(shellQuote).join(" "), home);
25608
25829
  var mcpFlag = (flags) => flags["no-mcp"] === true ? false : flags.mcp === true ? true : undefined;
25609
25830
  var main = async (argv) => {
25610
25831
  const { cmd, flags } = parseArgs(argv);
@@ -25612,7 +25833,7 @@ var main = async (argv) => {
25612
25833
  console.log(commandUsage(cmd));
25613
25834
  return 0;
25614
25835
  }
25615
- const home = homedir();
25836
+ const home = homedir3();
25616
25837
  const scheduler = {
25617
25838
  platform: platform3(),
25618
25839
  home,
@@ -25822,7 +26043,7 @@ var main = async (argv) => {
25822
26043
  case "mcp":
25823
26044
  return mcp({ home });
25824
26045
  case "seat-sync":
25825
- return seatSync({ home, argv: process.argv.slice(3) });
26046
+ return seatSync({ home, argv: process.argv.slice(3), sledsArgv: sledsArgv() });
25826
26047
  case "statusline":
25827
26048
  return statusline({ home });
25828
26049
  case "help":
@@ -25835,7 +26056,7 @@ ${renderHelpText(argv[1])}`);
25835
26056
  case "version":
25836
26057
  case "--version":
25837
26058
  case "-v":
25838
- console.log("sleds 0.1.46");
26059
+ console.log("sleds 0.1.47");
25839
26060
  return 0;
25840
26061
  default:
25841
26062
  console.error(`unknown command: ${cmd}