@sleds/cli 0.1.45 → 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 +506 -240
  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.45" ?? "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) {
@@ -12322,21 +12378,17 @@ async function readProfile(client) {
12322
12378
  }
12323
12379
  function nextPickup(r, o) {
12324
12380
  const mine = Array.isArray(r.mine) ? r.mine.filter(isObject8) : [];
12325
- let running = 0;
12326
12381
  for (const row of mine) {
12327
12382
  const route = row.route;
12328
- if (isObject8(route) && route.drafting === true)
12329
- running++;
12330
- if (!isObject8(route) || !isObject8(route.armed))
12383
+ if (!isObject8(route) || !armedFor(route.armed, o.engine))
12331
12384
  continue;
12332
12385
  const states = isObject8(route.states) ? route.states : {};
12333
- running += keysIn(states, "running").length;
12334
- if (!armedFor(route.armed, o.engine) || statesLanded(states))
12386
+ if (statesLanded(states))
12335
12387
  continue;
12336
12388
  if (strings(route.ready).length > 0)
12337
12389
  return null;
12338
12390
  }
12339
- if (running >= o.atOnce)
12391
+ if (sledRunning(mine) >= o.atOnce)
12340
12392
  return null;
12341
12393
  for (const row of mine) {
12342
12394
  const route = row.route;
@@ -12352,6 +12404,33 @@ function nextPickup(r, o) {
12352
12404
  }
12353
12405
  return null;
12354
12406
  }
12407
+ function sledRunning(r) {
12408
+ const mine = Array.isArray(r) ? r : Array.isArray(r.mine) ? r.mine.filter(isObject8) : [];
12409
+ let running = 0;
12410
+ for (const row of mine) {
12411
+ const route = row.route;
12412
+ if (isObject8(route) && route.drafting === true)
12413
+ running++;
12414
+ if (!isObject8(route) || !isObject8(route.armed))
12415
+ continue;
12416
+ running += keysIn(isObject8(route.states) ? route.states : {}, "running").length;
12417
+ }
12418
+ return running;
12419
+ }
12420
+ function armedDrafts(r, engine) {
12421
+ const mine = Array.isArray(r.mine) ? r.mine.filter(isObject8) : [];
12422
+ return mine.filter((row) => {
12423
+ const route = row.route;
12424
+ if (!isObject8(route) || !armedFor(route.armed, engine) || route.implicit !== true)
12425
+ return false;
12426
+ if (route.drafting === true || route.proposed === true || route.draftParked)
12427
+ return false;
12428
+ if (strings(route.needsRoute).length === 0 || isPrMirror(row.source))
12429
+ return false;
12430
+ const states = isObject8(route.states) ? route.states : {};
12431
+ return !statesLanded(states) && keysIn(states, "running").length === 0;
12432
+ });
12433
+ }
12355
12434
  function redraftDue(route) {
12356
12435
  return isObject8(route) && isObject8(route.redraft) && route.drafting !== true && route.proposed !== true;
12357
12436
  }
@@ -12365,14 +12444,15 @@ function routeText(route, states) {
12365
12444
  }
12366
12445
  function sledsSource(client, o) {
12367
12446
  const routeOf = (q) => client.get(`/proxy/route?q=${encodeURIComponent(q)}`);
12368
- async function pickup(sled) {
12447
+ async function pickup(sled, drafted) {
12369
12448
  const engine = o.engine;
12370
12449
  const profile = await readProfile(client);
12371
12450
  if (profile?.pickup !== "auto")
12372
12451
  return null;
12373
12452
  if (profile.engine && !sameEngine(profile.engine, engine))
12374
12453
  return null;
12375
- const row = nextPickup(sled, { atOnce: o.atOnce ?? profile.atOnce ?? 1, engine });
12454
+ const atOnce = (o.atOnce ?? profile.atOnce ?? 1) - drafted;
12455
+ const row = nextPickup(sled, { atOnce, engine });
12376
12456
  if (!row)
12377
12457
  return null;
12378
12458
  const item = str6(row.key) ?? String(row.project);
@@ -12400,7 +12480,7 @@ function sledsSource(client, o) {
12400
12480
  ...armedTerms(armed)
12401
12481
  };
12402
12482
  }
12403
- async function draft(row, item, why) {
12483
+ async function draft(row, item, why, started = false) {
12404
12484
  const project = str6(row.project) ?? item;
12405
12485
  const pending = isObject8(row.route) && isObject8(row.route.redraft) ? row.route.redraft : null;
12406
12486
  const runner = typeof o.runner === "function" ? o.runner() : o.runner;
@@ -12412,7 +12492,7 @@ function sledsSource(client, o) {
12412
12492
  ...o.leaseMin !== undefined ? { leaseMin: o.leaseMin } : {}
12413
12493
  });
12414
12494
  if (!r || r.status >= 300 || !r.json || r.json.ok === false) {
12415
- o.log?.(`${pending ? `${item}: could not claim the re-draft` : `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}`);
12416
12496
  return null;
12417
12497
  }
12418
12498
  const j = r.json;
@@ -12434,7 +12514,7 @@ function sledsSource(client, o) {
12434
12514
  route: routeText(brief, isObject8(row.route) ? row.route.states : null)
12435
12515
  };
12436
12516
  }
12437
- o.log?.(redraft ? `${item}: re-drafting the route from ${redraft.by}'s answer — it waits for a yes` : `Pickup: Auto is drafting ${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`);
12438
12518
  const leaseUntil = num5(j.leaseUntil);
12439
12519
  const claim = {
12440
12520
  item,
@@ -12474,7 +12554,28 @@ function sledsSource(client, o) {
12474
12554
  if (claimed?.draft && it)
12475
12555
  it.draft = claimed.draft;
12476
12556
  }
12477
- const picked = await pickup(r);
12557
+ const waiting = armedDrafts(r, o.engine);
12558
+ let drafted = 0;
12559
+ if (waiting.length > 0) {
12560
+ const cap = o.atOnce ?? (await readProfile(client))?.atOnce ?? 1;
12561
+ let room = cap - sledRunning(r);
12562
+ for (const row of waiting) {
12563
+ const item = str6(row.key) ?? String(row.project);
12564
+ const it = items.find((x) => x.item === item);
12565
+ if (it)
12566
+ it.ready = [];
12567
+ if (room <= 0)
12568
+ continue;
12569
+ const route = isObject8(row.route) ? row.route : {};
12570
+ const claimed = await draft(row, item, strings(route.needsRoute), true);
12571
+ if (claimed?.draft && it) {
12572
+ it.draft = claimed.draft;
12573
+ drafted++;
12574
+ room--;
12575
+ }
12576
+ }
12577
+ }
12578
+ const picked = await pickup(r, drafted);
12478
12579
  if (picked)
12479
12580
  items.push(picked);
12480
12581
  }
@@ -12515,6 +12616,7 @@ function sledsSource(client, o) {
12515
12616
  }
12516
12617
  const leaseUntil = num5(hit.leaseUntil);
12517
12618
  const runToken = str6(hit.runToken) ?? (taken.length === 1 ? str6(r.json?.runToken) : undefined);
12619
+ const run = runOf(hit.run);
12518
12620
  const claim = {
12519
12621
  item,
12520
12622
  node: str6(hit.node) ?? node,
@@ -12526,7 +12628,8 @@ function sledsSource(client, o) {
12526
12628
  ...t.seatId ? { seatId: t.seatId } : {},
12527
12629
  ...str6(hit.answer) ? { answer: str6(hit.answer) } : {},
12528
12630
  ...runToken ? { runToken } : {},
12529
- ...group ? { group } : {}
12631
+ ...group ? { group } : {},
12632
+ ...run ? { run } : {}
12530
12633
  };
12531
12634
  return { ok: true, claim };
12532
12635
  },
@@ -13046,17 +13149,20 @@ var MANAGERS = new Set(["pnpm", "npm", "yarn", "bun"]);
13046
13149
  var INSTALL_VERBS = new Set(["install", "i", "ci"]);
13047
13150
  function installArgv(command) {
13048
13151
  const line = command?.trim().replace(/^`|`$/g, "") ?? "";
13049
- if (!line || /[;&|<>$`()]/.test(line))
13152
+ if (!line || /[;&|<>$`()\n]/.test(line))
13050
13153
  return null;
13051
13154
  const argv = shellWords(line);
13052
13155
  const [tool, verb] = argv;
13053
13156
  if (!tool || !MANAGERS.has(tool))
13054
13157
  return null;
13055
- if (tool !== "yarn" && (!verb || !INSTALL_VERBS.has(verb)))
13056
- return null;
13057
- 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
13058
13164
  return null;
13059
- return argv;
13165
+ return rest.every((a) => a.startsWith("-")) ? argv : null;
13060
13166
  }
13061
13167
  function lockfileInstall(path, exists) {
13062
13168
  if (exists(join15(path, "pnpm-lock.yaml")))
@@ -13069,57 +13175,59 @@ function lockfileInstall(path, exists) {
13069
13175
  return ["npm", "ci"];
13070
13176
  return null;
13071
13177
  }
13072
- function packInstallOf(pack, repo) {
13073
- let section = null;
13074
- let first;
13075
- const want = repo?.trim().toLowerCase();
13076
- for (const line of pack.split(`
13077
- `)) {
13078
- const h = line.match(/^###\s+(.+?)\s*$/);
13079
- if (h) {
13080
- section = h[1].toLowerCase();
13081
- continue;
13082
- }
13083
- const m = line.match(/^\s*-\s*Install:\s*(.+?)\s*$/i);
13084
- if (!m?.[1])
13085
- continue;
13086
- if (want && section === want)
13087
- return m[1];
13088
- first ??= m[1];
13089
- }
13090
- return first;
13091
- }
13092
- function packGateOf(pack, repo) {
13093
- let inDone = false;
13094
- let first;
13095
- const want = repo?.trim().toLowerCase();
13096
- for (const line of pack.split(`
13097
- `)) {
13098
- if (/^##\s/.test(line)) {
13099
- inDone = /^##\s+4\./.test(line);
13100
- continue;
13101
- }
13102
- if (!inDone)
13103
- continue;
13104
- const m = line.match(/^\s*-\s*([^:`]+?):\s*`(.+)`\s*$/);
13105
- if (!m?.[1] || !m[2])
13106
- continue;
13107
- const name = m[1].trim().toLowerCase();
13108
- if (name === "done means" || name.startsWith("try it"))
13109
- continue;
13110
- if (want && name === want)
13111
- return m[2];
13112
- first ??= m[2];
13113
- }
13114
- 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() ?? "");
13115
13209
  }
13116
13210
  function gateAllowRules(gate) {
13117
13211
  const whole = gate?.trim();
13118
13212
  if (!whole)
13119
13213
  return [];
13214
+ if (/[$`()<>|&\n]/.test(whole.replace(/&&|\|\|/g, " ")))
13215
+ return [];
13120
13216
  const parts = whole.split(/&&|\|\||;/).map((p) => p.trim()).filter(Boolean);
13217
+ if (parts.some(runsInterpreter))
13218
+ return [];
13121
13219
  return [...new Set([whole, ...parts])].map((c) => `Bash(${c})`);
13122
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
+ }
13123
13231
  function ensureInstalled(exec, path, fs, o = {}) {
13124
13232
  if (!fs.exists(join15(path, "package.json")) || fs.exists(join15(path, "node_modules")))
13125
13233
  return null;
@@ -13677,10 +13785,10 @@ async function tickOnce(d) {
13677
13785
  let mcpConfig;
13678
13786
  try {
13679
13787
  const base = d.defaultBranch(d.exec, repoPath);
13680
- 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);
13681
13790
  const prTitle = d.prTitleOf?.(claim);
13682
13791
  mcpConfig = engineMcpConfigFor(d, name, claim.runToken, at, worktree);
13683
- const gate = packGateOf(claim.pack, claim.repos[0]);
13684
13792
  const allow = gateAllowRules(gate);
13685
13793
  const prompt = nodePrompt({
13686
13794
  claim,
@@ -14654,7 +14762,7 @@ async function startDraft(d, claim, why, state, started, finished) {
14654
14762
  };
14655
14763
  state.runs.push(run);
14656
14764
  d.writeState(state);
14657
- 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`);
14658
14766
  try {
14659
14767
  await d.source.heartbeat(claim, watch);
14660
14768
  } catch (e) {
@@ -14671,7 +14779,7 @@ async function settleDraft(d, run, claim, runner, finished) {
14671
14779
  return true;
14672
14780
  }
14673
14781
  if (beat === "done") {
14674
- 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`);
14675
14783
  endDraft(d, run, runner);
14676
14784
  return false;
14677
14785
  }
@@ -14685,7 +14793,7 @@ async function settleDraft(d, run, claim, runner, finished) {
14685
14793
  return false;
14686
14794
  }
14687
14795
  if (beat === "lost") {
14688
- 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`);
14689
14797
  endDraft(d, run, runner);
14690
14798
  return false;
14691
14799
  }
@@ -14701,7 +14809,7 @@ async function settleDraft(d, run, claim, runner, finished) {
14701
14809
  let log = "";
14702
14810
  if (status === "exited") {
14703
14811
  try {
14704
- 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.";
14705
14813
  } catch (e) {
14706
14814
  log = `(the session's output could not be read: ${message(e)})`;
14707
14815
  }
@@ -15644,6 +15752,18 @@ init_machine();
15644
15752
  init_state();
15645
15753
  init_meter();
15646
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
+
15647
15767
  // src/runners/command.ts
15648
15768
  var expandCommandTemplate = (template, o) => {
15649
15769
  const values = {
@@ -16585,7 +16705,7 @@ function flagsFromProfile(flags, given, profile, home) {
16585
16705
  const used = [];
16586
16706
  const skipped = [];
16587
16707
  for (const k of profile.notYours ?? [])
16588
- 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)`);
16589
16709
  if (profile.atOnce !== undefined && !has("at-once")) {
16590
16710
  out.atOnce = profile.atOnce;
16591
16711
  used.push(`at-once ${profile.atOnce}`);
@@ -16749,7 +16869,11 @@ function engineClient(o, org) {
16749
16869
  const env = o.env ?? process.env;
16750
16870
  const src = meterSource(o.home, undefined, { ...org ? { flag: org } : {}, env });
16751
16871
  if (src)
16752
- return fetchClient({ ...src, timeoutMs: ENGINE_TIMEOUT_MS });
16872
+ return fetchClient({
16873
+ ...src,
16874
+ timeoutMs: ENGINE_TIMEOUT_MS,
16875
+ version: "0.1.47"
16876
+ });
16753
16877
  const asked = org?.trim() || env.SLEDS_ORG?.trim();
16754
16878
  if (asked && !selectOrg(readConfig(o.home), org, env).seat)
16755
16879
  return {
@@ -16813,7 +16937,7 @@ function engineToken(o, org) {
16813
16937
  }
16814
16938
  var withToken = (token, now) => token ? { token, tokenNow: now } : {};
16815
16939
  function engineDeps(o, flags, source, runner, stateName) {
16816
- const exec = o.exec ?? defaultExec;
16940
+ const exec = guardGit(o.exec ?? defaultExec);
16817
16941
  const cwd = o.cwd ?? process.cwd();
16818
16942
  const exists = o.exists ?? realExists;
16819
16943
  const log = o.log ?? console.log;
@@ -16944,7 +17068,15 @@ function engineDeps(o, flags, source, runner, stateName) {
16944
17068
  function sandboxDenyRead(home, env) {
16945
17069
  return {
16946
17070
  dirs: [...new Set([configDir(home, env), join16(home, ".config", "sleds")])],
16947
- 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
+ ]
16948
17080
  };
16949
17081
  }
16950
17082
  function engineSandboxSettings(home, env, gitCommonDir, allow) {
@@ -17001,7 +17133,7 @@ async function driveEngine(o, flags, deps, until = {}) {
17001
17133
  runner: deps.runner.name,
17002
17134
  atOnce: flags.atOnce,
17003
17135
  interval: flags.interval,
17004
- cliVersion: "0.1.45"
17136
+ cliVersion: "0.1.47"
17005
17137
  };
17006
17138
  const beat = (checkedAt) => {
17007
17139
  const m = deps.machine;
@@ -17187,7 +17319,7 @@ async function drive(o, flags, deps, until, beat) {
17187
17319
  var SEAT_CHANGED_EXIT = 3;
17188
17320
  function engineRunner(o, flags) {
17189
17321
  const runnerFor = o.runnerFor ?? runnerFor2;
17190
- return runnerFor(flags.runner, o.exec ?? defaultExec, {
17322
+ return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
17191
17323
  ...flags.runnerCmd ? { command: flags.runnerCmd } : {}
17192
17324
  });
17193
17325
  }
@@ -17274,7 +17406,7 @@ async function enginePauseCmd(o) {
17274
17406
  source = sledsSource(c, { engine, log });
17275
17407
  }
17276
17408
  const why = parsed.why ?? `paused on ${defaultEngineName(host)} (sleds engine pause)`;
17277
- const exec = o.exec ?? defaultExec;
17409
+ const exec = guardGit(o.exec ?? defaultExec);
17278
17410
  const gone = new Set;
17279
17411
  for (const run of running) {
17280
17412
  const at = `${run.item}/${run.node}`;
@@ -17323,13 +17455,18 @@ import {
17323
17455
  writeFileSync as writeFileSync15
17324
17456
  } from "node:fs";
17325
17457
  import { hostname as hostname3 } from "node:os";
17326
- 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";
17327
17459
  init_state();
17328
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
+
17329
17466
  // src/schedule.ts
17330
17467
  import { spawnSync as spawnSync4 } from "node:child_process";
17331
17468
  import { existsSync as existsSync14, mkdirSync as mkdirSync13, rmSync as rmSync5, writeFileSync as writeFileSync14 } from "node:fs";
17332
- import { join as join17 } from "node:path";
17469
+ import { join as join18 } from "node:path";
17333
17470
  var REVERT_LABEL = "ai.sleds.revert";
17334
17471
  var defaultExec2 = (cmd, args) => {
17335
17472
  const r = spawnSync4(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
@@ -17337,7 +17474,7 @@ var defaultExec2 = (cmd, args) => {
17337
17474
  return { ok: false, stderr: r.error.message };
17338
17475
  return { ok: r.status === 0, stderr: r.stderr ?? "" };
17339
17476
  };
17340
- var plistPath = (home) => join17(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
17477
+ var plistPath = (home) => join18(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
17341
17478
  var xmlEscape2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
17342
17479
  var buildLaunchdPlist = (sledsArgv, deadline) => {
17343
17480
  const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape2(a)}</string>`).join(`
@@ -17376,7 +17513,7 @@ var scheduleRevert = (d, deadlineMs) => {
17376
17513
  if (d.platform === "darwin") {
17377
17514
  const p = plistPath(d.home);
17378
17515
  try {
17379
- mkdirSync13(join17(d.home, "Library", "LaunchAgents"), { recursive: true });
17516
+ mkdirSync13(join18(d.home, "Library", "LaunchAgents"), { recursive: true });
17380
17517
  d.exec("launchctl", ["unload", p]);
17381
17518
  writeFileSync14(p, buildLaunchdPlist(d.sledsArgv, deadline));
17382
17519
  const r = d.exec("launchctl", ["load", p]);
@@ -17416,16 +17553,16 @@ var cancelRevert = (d, kind) => {
17416
17553
  };
17417
17554
 
17418
17555
  // src/commands/engineSystemd.ts
17419
- import { join as join18 } from "node:path";
17556
+ import { join as join19 } from "node:path";
17420
17557
  var BOX_ENV_UNIT_PATH = "%h/.config/sleds/box.env";
17421
17558
  function boxEnvPath(home) {
17422
- return join18(home, ".config", "sleds", "box.env");
17559
+ return join19(home, ".config", "sleds", "box.env");
17423
17560
  }
17424
17561
  function engineUnitDir(home) {
17425
- return join18(home, ".config", "systemd", "user");
17562
+ return join19(home, ".config", "systemd", "user");
17426
17563
  }
17427
17564
  function engineUnitPath(home, label) {
17428
- return join18(engineUnitDir(home), `${label}.service`);
17565
+ return join19(engineUnitDir(home), `${label}.service`);
17429
17566
  }
17430
17567
  function systemdQuote(s) {
17431
17568
  const body = s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/%/g, "%%").replace(/\$/g, "$$$$");
@@ -17468,9 +17605,10 @@ function parseEngineUnit(text) {
17468
17605
  var ENGINE_LABEL = "ai.sleds.engine";
17469
17606
  var ENGINE_INSTALL_USAGE = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
17470
17607
  ${ENGINE_USAGE}`;
17471
- function stableArgv(argv, realpath = realpathSync) {
17608
+ function stableArgv(argv, realpath = realpathSync, home) {
17609
+ const link = sledsLink(home);
17472
17610
  return argv.map((a) => {
17473
- if (!isAbsolute2(a))
17611
+ if (!isAbsolute2(a) || a === link)
17474
17612
  return a;
17475
17613
  try {
17476
17614
  return realpath(a);
@@ -17483,13 +17621,13 @@ function engineLabel(name, org, seat) {
17483
17621
  return [ENGINE_LABEL, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
17484
17622
  }
17485
17623
  function enginePlistPath(home, name, org, seat) {
17486
- return join19(home, "Library", "LaunchAgents", `${engineLabel(name, org, seat)}.plist`);
17624
+ return join20(home, "Library", "LaunchAgents", `${engineLabel(name, org, seat)}.plist`);
17487
17625
  }
17488
17626
  function engineLogPath(stateDir, name) {
17489
- return join19(stateDir, `${engineSlug(name)}.log`);
17627
+ return join20(stateDir, `${engineSlug(name)}.log`);
17490
17628
  }
17491
17629
  function engineEventsPath(stateDir, name) {
17492
- return join19(stateDir, `${engineSlug(name)}.events.jsonl`);
17630
+ return join20(stateDir, `${engineSlug(name)}.events.jsonl`);
17493
17631
  }
17494
17632
  var xmlEscape3 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
17495
17633
  function buildEnginePlist(o) {
@@ -17586,7 +17724,7 @@ function readEngines(dir, suffix, manager, parse) {
17586
17724
  }
17587
17725
  const out = [];
17588
17726
  for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL}.`) && n.endsWith(suffix))) {
17589
- const path = join19(dir, name);
17727
+ const path = join20(dir, name);
17590
17728
  let parsed;
17591
17729
  try {
17592
17730
  parsed = parse(readFileSync14(path, "utf8"), name);
@@ -17606,10 +17744,10 @@ function readEngines(dir, suffix, manager, parse) {
17606
17744
  }
17607
17745
  function installedEngines(home) {
17608
17746
  return [
17609
- ...readEngines(join19(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
17747
+ ...readEngines(join20(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
17610
17748
  ...readEngines(engineUnitDir(home), ".service", "systemd", (text, file) => {
17611
17749
  const parsed = parseEngineUnit(text);
17612
- return parsed && { label: basename4(file, ".service"), ...parsed };
17750
+ return parsed && { label: basename5(file, ".service"), ...parsed };
17613
17751
  })
17614
17752
  ];
17615
17753
  }
@@ -17644,7 +17782,7 @@ function engineInstall(o) {
17644
17782
  const label = engineLabel(parsed.name, parsed.org, seat);
17645
17783
  const logPath = engineLogPath(stateDir, parsed.name);
17646
17784
  mkdirSync14(stateDir, { recursive: true, mode: 448 });
17647
- const sledsArgv = stableArgv(o.sledsArgv, o.realpath);
17785
+ const sledsArgv = stableArgv(o.sledsArgv, o.realpath, o.home);
17648
17786
  const execPath = sledsArgv[0] ?? process.execPath;
17649
17787
  const agentEnv = {
17650
17788
  PATH: musherPath(o.home, execPath, env.PATH ?? ""),
@@ -17696,7 +17834,7 @@ function installUnit(a) {
17696
17834
  const log = o.log ?? console.log;
17697
17835
  const error = o.error ?? console.error;
17698
17836
  const unit = engineUnitPath(o.home, label);
17699
- const unitName = basename4(unit);
17837
+ const unitName = basename5(unit);
17700
17838
  const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
17701
17839
  mkdirSync14(dirname12(unit), { recursive: true });
17702
17840
  if (existsSync15(unit))
@@ -17706,7 +17844,7 @@ function installUnit(a) {
17706
17844
  continue;
17707
17845
  if (engineArg(other.programArgs, "name") !== parsed.name)
17708
17846
  continue;
17709
- systemctl("disable", "--now", basename4(other.plist));
17847
+ systemctl("disable", "--now", basename5(other.plist));
17710
17848
  rmSync6(other.plist, { force: true });
17711
17849
  log(`replaced ${other.label}, this engine as installed before`);
17712
17850
  }
@@ -17765,13 +17903,13 @@ function engineUninstall(o) {
17765
17903
  const unit = file.endsWith(".service");
17766
17904
  const exec = o.exec ?? defaultExec2;
17767
17905
  if (unit)
17768
- exec("systemctl", ["--user", "disable", "--now", basename4(file)]);
17906
+ exec("systemctl", ["--user", "disable", "--now", basename5(file)]);
17769
17907
  else
17770
17908
  exec("launchctl", ["unload", file]);
17771
17909
  rmSync6(file, { force: true });
17772
17910
  if (unit)
17773
17911
  exec("systemctl", ["--user", "daemon-reload"]);
17774
- 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`);
17775
17913
  return 0;
17776
17914
  }
17777
17915
 
@@ -17888,7 +18026,7 @@ function nodeOk(version, min = NODE_MIN) {
17888
18026
  }
17889
18027
  var MARK = { ok: "ok ", warn: "warn", fail: "FAIL" };
17890
18028
  function formatDoctor(checks) {
17891
- 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}`);
17892
18030
  const fixes = checks.filter((c) => c.level !== "ok" && c.fix);
17893
18031
  if (fixes.length > 0) {
17894
18032
  lines.push("");
@@ -17928,7 +18066,7 @@ async function runDoctor(o) {
17928
18066
  level: "fail",
17929
18067
  name: "config",
17930
18068
  detail: `${configPath(home)} does not exist${overrides.length ? ` (this shell has ${overrides.join(" ")})` : ""}`,
17931
- 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"
17932
18070
  });
17933
18071
  } else {
17934
18072
  checks.push({
@@ -17958,7 +18096,7 @@ async function runDoctor(o) {
17958
18096
  level: "warn",
17959
18097
  name: "claude",
17960
18098
  detail: `${sPath} carries a different token (${maskToken(pointed.token)}) than ${configPath(home)} (${maskToken(cfg.token)})`,
17961
- fix: "sleds init --token <the one you mean>"
18099
+ fix: "sleds init (or `sleds login` as the seat you mean)"
17962
18100
  });
17963
18101
  } else {
17964
18102
  checks.push({ level: "ok", name: "claude", detail: `${sPath} → ${pointed.url}` });
@@ -18124,13 +18262,16 @@ async function runDoctor(o) {
18124
18262
  }
18125
18263
  var SANDBOX_PROBE = "sandbox-probe";
18126
18264
  var PROBE_ENV = "SLEDS_DOCTOR_PROBE";
18265
+ var SETTINGS_ENV = "SLEDS_DOCTOR_SETTINGS";
18127
18266
  var SANDBOX_PROBE_COMMAND = [
18128
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=$?"`,
18129
18270
  `curl -sS -m 10 -o /dev/null -w "SLEDS_CURL_CODE=%{http_code}\\n" https://example.com; echo "SLEDS_CURL_EXIT=$?"`,
18130
18271
  `gh api user -q .login; echo "SLEDS_GH_EXIT=$?"`
18131
18272
  ].join("; ");
18132
18273
  var marker = (out, name) => new RegExp(`${name}=(\\d+)`).exec(out)?.[1] ?? null;
18133
- function readSandboxProbe(run, nonce) {
18274
+ function readSandboxProbe(run, nonce, o = {}) {
18134
18275
  const out = `${run.stdout}
18135
18276
  ${run.stderr}`;
18136
18277
  const failed = run.status !== 0;
@@ -18152,6 +18293,34 @@ ${run.stderr}`;
18152
18293
  detail: catExit === "0" ? "cat succeeded but printed no nonce — inconclusive" : `${why} — inconclusive`,
18153
18294
  fix
18154
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 };
18155
18324
  const code = marker(out, "SLEDS_CURL_CODE");
18156
18325
  const curlExit = marker(out, "SLEDS_CURL_EXIT");
18157
18326
  const egress = code !== null && code !== "000" ? {
@@ -18176,8 +18345,15 @@ ${run.stderr}`;
18176
18345
  detail: ghExit === null ? `${why} — inconclusive` : `gh fails inside the sandbox (exit ${ghExit}) — a sandboxed node cannot push or open its PR`,
18177
18346
  fix: ghExit === null ? fix : "gh auth status; api.github.com on the allowlist; on macOS gh (Go) needs sandbox.enableWeakerNetworkIsolation for TLS"
18178
18347
  };
18179
- return [read, egress, github];
18348
+ return [read, envRow, settingsRow, egress, github];
18180
18349
  }
18350
+ var proxyToken = (home, env) => {
18351
+ try {
18352
+ return readProxy(readSettings(home, env))?.token;
18353
+ } catch {
18354
+ return;
18355
+ }
18356
+ };
18181
18357
  function sandboxChecks(o, env) {
18182
18358
  const which = (c) => (o.which ?? defaultWhich2)(c)[0] ?? null;
18183
18359
  const exec = o.exec ?? sessionExec;
@@ -18202,17 +18378,14 @@ function sandboxChecks(o, env) {
18202
18378
  }
18203
18379
  ];
18204
18380
  const nonce = o.nonce ?? `sleds-probe-${randomBytes(16).toString("hex")}`;
18205
- const probe = join20(dir, SANDBOX_PROBE);
18206
- const work = mkdtempSync(join20(tmpdir(), "sleds-sandbox-"));
18381
+ const probe = join21(dir, SANDBOX_PROBE);
18382
+ const work = mkdtempSync(join21(tmpdir(), "sleds-sandbox-"));
18207
18383
  try {
18208
18384
  writeFileSync17(probe, `${nonce}
18209
18385
  `, { mode: 384 });
18210
- const settingsFile = join20(work, "settings.json");
18211
- const settings = sandboxSettings({
18212
- denyRead: [dir],
18213
- gitCommonDir: work,
18214
- allow: SANDBOX_DEFAULT_ALLOW
18215
- });
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);
18216
18389
  writeFileSync17(settingsFile, JSON.stringify(settings, null, 2), { mode: 384 });
18217
18390
  const prompt = `Run exactly this one Bash command, once, then reply with its complete output verbatim and nothing else:
18218
18391
 
@@ -18221,6 +18394,7 @@ ${SANDBOX_PROBE_COMMAND}`;
18221
18394
  "-u",
18222
18395
  "SLEDS_TOKEN",
18223
18396
  `${PROBE_ENV}=${probe}`,
18397
+ `${SETTINGS_ENV}=${claudeSettings}`,
18224
18398
  claude,
18225
18399
  "-p",
18226
18400
  "--model",
@@ -18233,7 +18407,9 @@ ${SANDBOX_PROBE_COMMAND}`;
18233
18407
  "3",
18234
18408
  prompt
18235
18409
  ], { cwd: work });
18236
- 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 });
18237
18413
  } finally {
18238
18414
  rmSync8(probe, { force: true });
18239
18415
  rmSync8(work, { recursive: true, force: true });
@@ -18470,7 +18646,7 @@ import {
18470
18646
  writeFileSync as writeFileSync18
18471
18647
  } from "node:fs";
18472
18648
  import { hostname as hostname4 } from "node:os";
18473
- import { join as join21, resolve as resolve10 } from "node:path";
18649
+ import { join as join22, resolve as resolve10 } from "node:path";
18474
18650
  init_machine();
18475
18651
  init_state();
18476
18652
  init_meter();
@@ -18652,7 +18828,7 @@ function flagsFromProfile2(flags, given, profile, home) {
18652
18828
  const used = [];
18653
18829
  const skipped = [];
18654
18830
  for (const k of profile.notYours ?? [])
18655
- 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)`);
18656
18832
  if (profile.atOnce !== undefined && !has("at-once")) {
18657
18833
  out.atOnce = profile.atOnce;
18658
18834
  used.push(`at-once ${profile.atOnce}`);
@@ -18725,7 +18901,7 @@ function flagsFromProfile2(flags, given, profile, home) {
18725
18901
  }
18726
18902
  }
18727
18903
  if (profile.reposDir && !has("repos-dir") && !has("repo")) {
18728
- 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(":");
18729
18905
  used.push(`repos ${profile.reposDir}`);
18730
18906
  }
18731
18907
  if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
@@ -18868,7 +19044,11 @@ function engineClient2(o, org) {
18868
19044
  const env = o.env ?? process.env;
18869
19045
  const src = meterSource(o.home, undefined, { ...org ? { flag: org } : {}, env });
18870
19046
  if (src)
18871
- return fetchClient({ ...src, timeoutMs: ENGINE_TIMEOUT_MS2 });
19047
+ return fetchClient({
19048
+ ...src,
19049
+ timeoutMs: ENGINE_TIMEOUT_MS2,
19050
+ version: "0.1.47"
19051
+ });
18872
19052
  const asked = org?.trim() || env.SLEDS_ORG?.trim();
18873
19053
  if (asked && !selectOrg(readConfig(o.home), org, env).seat)
18874
19054
  return {
@@ -18916,12 +19096,12 @@ function memberMcpConfigs2(o, cwd) {
18916
19096
  });
18917
19097
  const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
18918
19098
  return [
18919
- read(claudeDir ? join21(claudeDir, ".claude.json") : join21(o.home, ".claude.json")),
18920
- ...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"))] : []
18921
19101
  ];
18922
19102
  }
18923
19103
  function engineStateDir2(o, org, seat) {
18924
- 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);
18925
19105
  }
18926
19106
  function engineSeat2(o, org) {
18927
19107
  try {
@@ -18941,7 +19121,7 @@ function engineToken2(o, org) {
18941
19121
  }
18942
19122
  var withToken2 = (token, now) => token ? { token, tokenNow: now } : {};
18943
19123
  function engineDeps2(o, flags, source, runner, stateName) {
18944
- const exec = o.exec ?? defaultExec;
19124
+ const exec = guardGit(o.exec ?? defaultExec);
18945
19125
  const cwd = o.cwd ?? process.cwd();
18946
19126
  const exists = o.exists ?? realExists2;
18947
19127
  const log = o.log ?? console.log;
@@ -18951,8 +19131,8 @@ function engineDeps2(o, flags, source, runner, stateName) {
18951
19131
  const repo = flags.repo ? resolve10(cwd, flags.repo) : undefined;
18952
19132
  const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve10(cwd, d));
18953
19133
  const { branch, prTitle } = flags;
18954
- const hooksDir = join21(stateDir, "hooks");
18955
- const permissionMark = (name) => join21(hooksDir, `${name}.permission.json`);
19134
+ const hooksDir = join22(stateDir, "hooks");
19135
+ const permissionMark = (name) => join22(hooksDir, `${name}.permission.json`);
18956
19136
  const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
18957
19137
  return {
18958
19138
  source,
@@ -18977,9 +19157,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
18977
19157
  sandbox: true,
18978
19158
  writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
18979
19159
  const gitCommonDir = gitCommonDirOf2(exec, cwd);
18980
- const dir = join21(stateDir, "sandbox");
19160
+ const dir = join22(stateDir, "sandbox");
18981
19161
  mkdirSync16(dir, { recursive: true, mode: 448 });
18982
- const p = join21(dir, `${name}.json`);
19162
+ const p = join22(dir, `${name}.json`);
18983
19163
  const walls = engineSandboxSettings2(o.home, o.env ?? process.env, gitCommonDir, [
18984
19164
  ...SANDBOX_DEFAULT_ALLOW,
18985
19165
  ...flags.sandboxAllow ?? []
@@ -18996,7 +19176,7 @@ function engineDeps2(o, flags, source, runner, stateName) {
18996
19176
  } : {},
18997
19177
  writeHookSettings: (name, allow) => {
18998
19178
  mkdirSync16(hooksDir, { recursive: true, mode: 448 });
18999
- const p = join21(hooksDir, `${name}.json`);
19179
+ const p = join22(hooksDir, `${name}.json`);
19000
19180
  const base = allow?.length ? { permissions: { allow: [...allow] } } : {};
19001
19181
  writeFileSync18(p, `${JSON.stringify(withHook(name, base), null, 2)}
19002
19182
  `, { mode: 384 });
@@ -19024,9 +19204,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
19024
19204
  exists
19025
19205
  }),
19026
19206
  writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
19027
- const dir = join21(stateDir, "mcp");
19207
+ const dir = join22(stateDir, "mcp");
19028
19208
  mkdirSync16(dir, { recursive: true, mode: 448 });
19029
- const p = join21(dir, `${name}.json`);
19209
+ const p = join22(dir, `${name}.json`);
19030
19210
  let others = {};
19031
19211
  if (flags.strictMcp && flags.mcpAllow?.length) {
19032
19212
  const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs2(o, worktree));
@@ -19042,9 +19222,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
19042
19222
  }),
19043
19223
  removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync9(p, { force: true })),
19044
19224
  writePrompt: o.writePrompt ?? ((name, text) => {
19045
- const dir = join21(stateDir, "prompts");
19225
+ const dir = join22(stateDir, "prompts");
19046
19226
  mkdirSync16(dir, { recursive: true, mode: 448 });
19047
- const p = join21(dir, `${name}.md`);
19227
+ const p = join22(dir, `${name}.md`);
19048
19228
  writeFileSync18(p, text, { mode: 384 });
19049
19229
  return p;
19050
19230
  }),
@@ -19071,8 +19251,16 @@ function engineDeps2(o, flags, source, runner, stateName) {
19071
19251
  }
19072
19252
  function sandboxDenyRead2(home, env) {
19073
19253
  return {
19074
- dirs: [...new Set([configDir(home, env), join21(home, ".config", "sleds")])],
19075
- 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
+ ]
19076
19264
  };
19077
19265
  }
19078
19266
  function engineSandboxSettings2(home, env, gitCommonDir, allow) {
@@ -19096,6 +19284,8 @@ function sandboxRefusal(flags) {
19096
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";
19097
19285
  if (flags.agent && sandboxAgentKind(flags.agent) === null)
19098
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";
19099
19289
  return null;
19100
19290
  }
19101
19291
  function pinOrg3(configJson, org) {
@@ -19138,7 +19328,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
19138
19328
  runner: deps.runner.name,
19139
19329
  atOnce: flags.atOnce,
19140
19330
  interval: flags.interval,
19141
- cliVersion: "0.1.45"
19331
+ cliVersion: "0.1.47"
19142
19332
  };
19143
19333
  const beat = (checkedAt) => {
19144
19334
  const m = deps.machine;
@@ -19324,7 +19514,7 @@ async function drive2(o, flags, deps, until, beat) {
19324
19514
  var SEAT_CHANGED_EXIT2 = 3;
19325
19515
  function engineRunner2(o, flags) {
19326
19516
  const runnerFor = o.runnerFor ?? runnerFor2;
19327
- return runnerFor(flags.runner, o.exec ?? defaultExec, {
19517
+ return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
19328
19518
  ...flags.runnerCmd ? { command: flags.runnerCmd } : {}
19329
19519
  });
19330
19520
  }
@@ -19465,7 +19655,7 @@ var engineCmd = async (o) => {
19465
19655
  if (!r || r.ok || !r.refused || r.refused === refused)
19466
19656
  return;
19467
19657
  refused = r.refused;
19468
- 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.`);
19469
19659
  };
19470
19660
  afterTick = () => {
19471
19661
  try {
@@ -19563,7 +19753,7 @@ async function enginePauseCmd2(o) {
19563
19753
  source = sledsSource(c, { engine, log });
19564
19754
  }
19565
19755
  const why = parsed.why ?? `paused on ${defaultEngineName2(host)} (sleds engine pause)`;
19566
- const exec = o.exec ?? defaultExec;
19756
+ const exec = guardGit(o.exec ?? defaultExec);
19567
19757
  const gone = new Set;
19568
19758
  for (const run of running) {
19569
19759
  const at = `${run.item}/${run.node}`;
@@ -19612,14 +19802,15 @@ import {
19612
19802
  writeFileSync as writeFileSync19
19613
19803
  } from "node:fs";
19614
19804
  import { hostname as hostname5 } from "node:os";
19615
- 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";
19616
19806
  init_state();
19617
19807
  var ENGINE_LABEL2 = "ai.sleds.engine";
19618
19808
  var ENGINE_INSTALL_USAGE2 = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
19619
19809
  ${ENGINE_USAGE}`;
19620
- function stableArgv2(argv, realpath = realpathSync2) {
19810
+ function stableArgv2(argv, realpath = realpathSync2, home) {
19811
+ const link = sledsLink(home);
19621
19812
  return argv.map((a) => {
19622
- if (!isAbsolute3(a))
19813
+ if (!isAbsolute3(a) || a === link)
19623
19814
  return a;
19624
19815
  try {
19625
19816
  return realpath(a);
@@ -19632,13 +19823,13 @@ function engineLabel2(name, org, seat) {
19632
19823
  return [ENGINE_LABEL2, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
19633
19824
  }
19634
19825
  function enginePlistPath2(home, name, org, seat) {
19635
- return join22(home, "Library", "LaunchAgents", `${engineLabel2(name, org, seat)}.plist`);
19826
+ return join23(home, "Library", "LaunchAgents", `${engineLabel2(name, org, seat)}.plist`);
19636
19827
  }
19637
19828
  function engineLogPath2(stateDir, name) {
19638
- return join22(stateDir, `${engineSlug(name)}.log`);
19829
+ return join23(stateDir, `${engineSlug(name)}.log`);
19639
19830
  }
19640
19831
  function engineEventsPath2(stateDir, name) {
19641
- return join22(stateDir, `${engineSlug(name)}.events.jsonl`);
19832
+ return join23(stateDir, `${engineSlug(name)}.events.jsonl`);
19642
19833
  }
19643
19834
  var xmlEscape4 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19644
19835
  function buildEnginePlist2(o) {
@@ -19735,7 +19926,7 @@ function readEngines2(dir, suffix, manager, parse) {
19735
19926
  }
19736
19927
  const out = [];
19737
19928
  for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL2}.`) && n.endsWith(suffix))) {
19738
- const path = join22(dir, name);
19929
+ const path = join23(dir, name);
19739
19930
  let parsed;
19740
19931
  try {
19741
19932
  parsed = parse(readFileSync19(path, "utf8"), name);
@@ -19755,10 +19946,10 @@ function readEngines2(dir, suffix, manager, parse) {
19755
19946
  }
19756
19947
  function installedEngines2(home) {
19757
19948
  return [
19758
- ...readEngines2(join22(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
19949
+ ...readEngines2(join23(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
19759
19950
  ...readEngines2(engineUnitDir(home), ".service", "systemd", (text, file) => {
19760
19951
  const parsed = parseEngineUnit(text);
19761
- return parsed && { label: basename5(file, ".service"), ...parsed };
19952
+ return parsed && { label: basename6(file, ".service"), ...parsed };
19762
19953
  })
19763
19954
  ];
19764
19955
  }
@@ -19793,7 +19984,7 @@ async function ensureReposDir(o) {
19793
19984
  return false;
19794
19985
  }
19795
19986
  const exists = o.exists ?? existsSync18;
19796
- 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));
19797
19988
  if (missing.length) {
19798
19989
  error(`Not a folder on this machine: ${missing.join(", ")}. ${REPOS_DIR_NEEDED}`);
19799
19990
  return false;
@@ -19837,7 +20028,7 @@ function engineInstall2(o) {
19837
20028
  const label = engineLabel2(parsed.name, parsed.org, seat);
19838
20029
  const logPath = engineLogPath2(stateDir, parsed.name);
19839
20030
  mkdirSync17(stateDir, { recursive: true, mode: 448 });
19840
- const sledsArgv = stableArgv2(o.sledsArgv, o.realpath);
20031
+ const sledsArgv = stableArgv2(o.sledsArgv, o.realpath, o.home);
19841
20032
  const execPath = sledsArgv[0] ?? process.execPath;
19842
20033
  const agentEnv = {
19843
20034
  PATH: musherPath(o.home, execPath, env.PATH ?? ""),
@@ -19889,7 +20080,7 @@ function installUnit2(a) {
19889
20080
  const log = o.log ?? console.log;
19890
20081
  const error = o.error ?? console.error;
19891
20082
  const unit = engineUnitPath(o.home, label);
19892
- const unitName = basename5(unit);
20083
+ const unitName = basename6(unit);
19893
20084
  const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
19894
20085
  mkdirSync17(dirname13(unit), { recursive: true });
19895
20086
  if (existsSync18(unit))
@@ -19899,7 +20090,7 @@ function installUnit2(a) {
19899
20090
  continue;
19900
20091
  if (engineArg2(other.programArgs, "name") !== parsed.name)
19901
20092
  continue;
19902
- systemctl("disable", "--now", basename5(other.plist));
20093
+ systemctl("disable", "--now", basename6(other.plist));
19903
20094
  rmSync10(other.plist, { force: true });
19904
20095
  log(`replaced ${other.label}, this engine as installed before`);
19905
20096
  }
@@ -19958,13 +20149,13 @@ function engineUninstall2(o) {
19958
20149
  const unit = file.endsWith(".service");
19959
20150
  const exec = o.exec ?? defaultExec2;
19960
20151
  if (unit)
19961
- exec("systemctl", ["--user", "disable", "--now", basename5(file)]);
20152
+ exec("systemctl", ["--user", "disable", "--now", basename6(file)]);
19962
20153
  else
19963
20154
  exec("launchctl", ["unload", file]);
19964
20155
  rmSync10(file, { force: true });
19965
20156
  if (unit)
19966
20157
  exec("systemctl", ["--user", "daemon-reload"]);
19967
- 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`);
19968
20159
  return 0;
19969
20160
  }
19970
20161
 
@@ -20910,9 +21101,9 @@ init_meter();
20910
21101
  // src/owed.ts
20911
21102
  init_config();
20912
21103
  import { existsSync as existsSync22, mkdirSync as mkdirSync18, readFileSync as readFileSync23, renameSync as renameSync7, writeFileSync as writeFileSync20 } from "node:fs";
20913
- import { dirname as dirname14, join as join23 } from "node:path";
20914
- var owedPath = (home) => join23(configDir(home), "owed.json");
20915
- 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");
20916
21107
  var OWED_TTL_MS = 3 * 24 * 60 * 60000;
20917
21108
  var str13 = (v) => typeof v === "string" ? v : undefined;
20918
21109
  function sourceKey(s) {
@@ -21066,7 +21257,12 @@ function trackingClient(client, home, now) {
21066
21257
  function contextFor(deps) {
21067
21258
  const src = meterSource(deps.home, runTokenOf(deps.env));
21068
21259
  const now = deps.now ?? Date.now;
21069
- 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;
21070
21266
  return {
21071
21267
  channel: "code",
21072
21268
  client,
@@ -21335,7 +21531,7 @@ var DEVICE_REASONS = {
21335
21531
  bad_answer: "the proxy gave an answer this CLI does not understand — update it: curl -fsSL sleds.ai/install | sh"
21336
21532
  };
21337
21533
  function deviceFailureText(reason) {
21338
- 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\`.`;
21339
21535
  }
21340
21536
  function parseStart(body) {
21341
21537
  if (typeof body !== "object" || body === null)
@@ -21597,7 +21793,7 @@ var SIGNUP_REASONS = {
21597
21793
  not_configured: "the proxy is not set up for self-serve signup yet.",
21598
21794
  team: "the team needs a name (2–80 characters).",
21599
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.",
21600
- 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.",
21601
21797
  unavailable: "the proxy could not reach its control plane. Try again in a moment.",
21602
21798
  unreachable: "could not reach the proxy.",
21603
21799
  code: "that code is six digits.",
@@ -21724,7 +21920,7 @@ var resolveToken = async (o) => {
21724
21920
  return null;
21725
21921
  }
21726
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."}`);
21727
- 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.");
21728
21924
  return { token: r.token, source: "signup" };
21729
21925
  }
21730
21926
  const credential = (await o.prompt("Your Anthropic API key (sk-ant-…, stored encrypted, spends only your account): ")).trim();
@@ -21748,7 +21944,7 @@ var init = async (o) => {
21748
21944
  }
21749
21945
  const resolved = await resolveToken(o);
21750
21946
  if (!resolved) {
21751
- 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).");
21752
21948
  return 2;
21753
21949
  }
21754
21950
  if (!isSeatToken(resolved.token)) {
@@ -22464,7 +22660,7 @@ var on = (o) => {
22464
22660
  return 2;
22465
22661
  }
22466
22662
  if (!isSeatToken(token)) {
22467
- 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.");
22468
22664
  return 2;
22469
22665
  }
22470
22666
  if (cfg.org && !cfg.org.capabilities.upstreamKey) {
@@ -22632,7 +22828,7 @@ var orgCmd = (o) => {
22632
22828
  init_src();
22633
22829
  import { spawnSync as spawnSync8 } from "node:child_process";
22634
22830
  import { writeFileSync as writeFileSync23 } from "node:fs";
22635
- import { join as join24 } from "node:path";
22831
+ import { join as join25 } from "node:path";
22636
22832
  function packFileName(key) {
22637
22833
  return `pack-${slugify(key, 80) || "item"}.md`;
22638
22834
  }
@@ -22660,7 +22856,7 @@ var packCmd = async (o) => {
22660
22856
  log(r.text);
22661
22857
  return 0;
22662
22858
  }
22663
- const path = join24(o.cwd ?? process.cwd(), packFileName(key));
22859
+ const path = join25(o.cwd ?? process.cwd(), packFileName(key));
22664
22860
  (o.write ?? ((p, t) => writeFileSync23(p, t.endsWith(`
22665
22861
  `) ? t : `${t}
22666
22862
  `)))(path, r.text);
@@ -22919,7 +23115,9 @@ function parseVerbArgs(argv, allowed) {
22919
23115
  if (flag === "name")
22920
23116
  out.name = value;
22921
23117
  i++;
22922
- } else if (out.key === undefined)
23118
+ } else if (a.startsWith("-"))
23119
+ return { error: `unknown flag ${a}` };
23120
+ else if (out.key === undefined)
22923
23121
  out.key = a;
22924
23122
  else
22925
23123
  return { error: `one item at a time — "${a}" is extra` };
@@ -23101,7 +23299,7 @@ async function proposeCmd(o, argv) {
23101
23299
  log(`- ${w}`);
23102
23300
  const shown = typeof r.json?.key === "string" ? r.json.key : a.key;
23103
23301
  const text = typeof r.json?.text === "string" ? r.json.text : "";
23104
- 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`);
23105
23303
  log("");
23106
23304
  log(`Nothing runs until a person approves it: \`sleds route approve ${shown}\`, or Approve in the app.`);
23107
23305
  });
@@ -23143,7 +23341,7 @@ async function approveCmd(o, argv) {
23143
23341
  return said(o, a.key, a.json, r, () => log(approvedLine(a.key, r.json ?? {})));
23144
23342
  }
23145
23343
  async function redraftCmd(o, argv) {
23146
- 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));
23147
23345
  }
23148
23346
  async function singleCmd(o, argv) {
23149
23347
  return oneVerb(o, argv, SINGLE_USAGE, { single: true }, "nothing changed", (key) => singleLine(key));
@@ -23171,17 +23369,17 @@ async function oneVerb(o, argv, usage, body, unreachable, line) {
23171
23369
  return said(o, a.key, a.json, r, () => log(line(shown)));
23172
23370
  }
23173
23371
  function redraftLine(key) {
23174
- 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`;
23175
23373
  }
23176
23374
  function singleLine(key) {
23177
- return `${key} runs as one node — it is not drafted again`;
23375
+ return `${key} runs as one node — it is not planned again`;
23178
23376
  }
23179
23377
  function answeredLine(key, route, held) {
23180
23378
  const nodes = Array.isArray(held) && held.length ? ` (${held.join(", ")})` : "";
23181
23379
  if (route === "accept")
23182
23380
  return `${key}: change accepted — what it held${nodes} waits until the route is re-filed`;
23183
23381
  if (route === "redraft")
23184
- 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`;
23185
23383
  if (route === "keep")
23186
23384
  return `${key}: route kept as filed — what it held is released`;
23187
23385
  return `${key}: answered — what it held is released`;
@@ -23258,12 +23456,24 @@ function lookToReady(route, id) {
23258
23456
  return { error: `no decision ${id} on this item` };
23259
23457
  if (d.kind !== "look")
23260
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}` };
23261
23461
  if (d.state !== "escalated")
23262
23462
  return { error: `decision ${id} is ${String(d.state)} — not a look you owe` };
23263
23463
  const about = d.about && typeof d.about === "object" ? d.about : {};
23264
23464
  const pr = Array.isArray(about.prs) ? about.prs.find((p) => typeof p === "string" && p) : undefined;
23265
23465
  return typeof pr === "string" ? { pr } : { error: `decision ${id} names no PR` };
23266
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
+ }
23267
23477
  async function readyCmd(o, argv) {
23268
23478
  const log = o.log ?? console.log;
23269
23479
  const error = o.error ?? console.error;
@@ -23284,6 +23494,13 @@ async function readyCmd(o, argv) {
23284
23494
  error(reader.error);
23285
23495
  return 1;
23286
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
+ };
23287
23504
  const route = await reader.read(key).catch((e) => {
23288
23505
  error(e instanceof Error ? e.message : String(e));
23289
23506
  return;
@@ -23295,12 +23512,25 @@ async function readyCmd(o, argv) {
23295
23512
  error(`${key}: ${look.error}`);
23296
23513
  return 1;
23297
23514
  }
23298
- const gh = (o.exec ?? defaultExec)("gh", ["pr", "ready", look.pr]);
23299
- if (gh.status !== 0) {
23300
- 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}`));
23301
23522
  error(`${key}: the look is not answered`);
23302
23523
  return 1;
23303
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
+ }
23304
23534
  const r = await client.postFull("/proxy/route/decision", {
23305
23535
  project: key,
23306
23536
  id,
@@ -23310,7 +23540,13 @@ async function readyCmd(o, argv) {
23310
23540
  error(`${key}: ${look.pr} is ready for review, but SLEDS is unreachable — the look is not answered`);
23311
23541
  return 1;
23312
23542
  }
23313
- 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`));
23314
23550
  }
23315
23551
  var DECISIONS_USAGE = "usage: sleds route decisions [<key>] [--flagged] [--json]";
23316
23552
  function decisionsLines(raw) {
@@ -23323,7 +23559,7 @@ function decisionsLines(raw) {
23323
23559
  const first = q.replace(/\s+/g, " ").trim().slice(0, 100);
23324
23560
  const where = [d.project && !j.project ? d.project : null, d.node].filter(Boolean).join("/");
23325
23561
  const flag = d.flagged ? " · decided for you" : "";
23326
- const pending = d.redraftPending ? " · re-draft pending" : "";
23562
+ const pending = d.redraftPending ? " · plan again pending" : "";
23327
23563
  return `${String(d.state)}${flag}${pending} ${where || "—"} ${first} [${String(d.id)}]`;
23328
23564
  });
23329
23565
  }
@@ -23539,12 +23775,14 @@ function routeReader(o, org) {
23539
23775
  read: (k) => readOrSay(client, `/proxy/route?q=${encodeURIComponent(k)}`, k)
23540
23776
  };
23541
23777
  }
23542
- 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>…";
23543
23779
  async function sledCmd(o) {
23544
23780
  const log = o.log ?? console.log;
23545
23781
  const error = o.error ?? console.error;
23546
23782
  const top = o.argv[0] === "top" && o.argv.length === 2 && !o.argv[1]?.startsWith("-");
23547
- 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")) {
23548
23786
  error(SLED_USAGE);
23549
23787
  return 2;
23550
23788
  }
@@ -23555,6 +23793,8 @@ async function sledCmd(o) {
23555
23793
  }
23556
23794
  if (top)
23557
23795
  return sledTop(client, o.argv[1], log, error);
23796
+ if (order)
23797
+ return sledOrder(client, keys, log, error);
23558
23798
  try {
23559
23799
  log(JSON.stringify(await readOrSay(client, "/proxy/sled", "the sled")));
23560
23800
  return 0;
@@ -23576,6 +23816,19 @@ async function sledTop(client, key, log, error) {
23576
23816
  log(`${typeof r.json?.key === "string" ? r.json.key : key} is first on your sled`);
23577
23817
  return 0;
23578
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
+ }
23579
23832
 
23580
23833
  // src/commands/run.ts
23581
23834
  init_config();
@@ -23681,12 +23934,12 @@ var seatEvent = async (o) => {
23681
23934
  import { execFileSync as execFileSync5 } from "node:child_process";
23682
23935
  import { existsSync as existsSync26, mkdirSync as mkdirSync22, readFileSync as readFileSync28, readdirSync as readdirSync5, rmSync as rmSync16, writeFileSync as writeFileSync25 } from "node:fs";
23683
23936
  import { platform as platform2 } from "node:os";
23684
- import { dirname as dirname17, join as join26 } from "node:path";
23937
+ import { dirname as dirname17, join as join27 } from "node:path";
23685
23938
 
23686
23939
  // src/cookieDb.ts
23687
23940
  import { copyFileSync, rmSync as rmSync15 } from "node:fs";
23688
23941
  import { tmpdir as tmpdir2 } from "node:os";
23689
- import { join as join25 } from "node:path";
23942
+ import { join as join26 } from "node:path";
23690
23943
  var QUERY = "SELECT name, hex(encrypted_value) AS ev FROM cookies WHERE host_key LIKE '%claude.ai%'";
23691
23944
  var isBun = () => typeof globalThis.Bun !== "undefined";
23692
23945
  async function queryRows(dbPath) {
@@ -23715,7 +23968,7 @@ function nodeSqlite() {
23715
23968
  return mod;
23716
23969
  }
23717
23970
  async function readCookieRows(dbPath) {
23718
- const copy = join25(tmpdir2(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
23971
+ const copy = join26(tmpdir2(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
23719
23972
  copyFileSync(dbPath, copy);
23720
23973
  try {
23721
23974
  const rows = await queryRows(copy);
@@ -24008,7 +24261,7 @@ function findFile(root, name) {
24008
24261
  continue;
24009
24262
  }
24010
24263
  for (const e of entries) {
24011
- const p = join26(dir, e.name);
24264
+ const p = join27(dir, e.name);
24012
24265
  if (e.isDirectory())
24013
24266
  stack.push(p);
24014
24267
  else if (e.name === name)
@@ -24019,7 +24272,7 @@ function findFile(root, name) {
24019
24272
  }
24020
24273
  function findCookieDb(home, source) {
24021
24274
  const b = BROWSERS[source.browser];
24022
- const root = join26(home, APP_SUPPORT, b.appDir);
24275
+ const root = join27(home, APP_SUPPORT, b.appDir);
24023
24276
  if (!existsSync26(root))
24024
24277
  throw new Error(`no ${source.browser} data at ${root} (is it installed?)`);
24025
24278
  if (!b.profiled) {
@@ -24028,7 +24281,7 @@ function findCookieDb(home, source) {
24028
24281
  throw new Error(`no cookie store under ${root}`);
24029
24282
  return db;
24030
24283
  }
24031
- const localStatePath = join26(root, "Local State");
24284
+ const localStatePath = join27(root, "Local State");
24032
24285
  const localState = existsSync26(localStatePath) ? readFileSync28(localStatePath, "utf8") : null;
24033
24286
  const wanted = source.profile ?? "Default";
24034
24287
  const { dir, ambiguous } = resolveProfileDir(localState, wanted);
@@ -24036,7 +24289,7 @@ function findCookieDb(home, source) {
24036
24289
  throw new Error(`"${wanted}" names ${ambiguous.length} ${source.browser} profiles (${ambiguous.join(", ")}) — pass the directory or the account email instead`);
24037
24290
  if (!dir)
24038
24291
  throw new Error(`no ${source.browser} profile named "${wanted}" (check chrome://version)`);
24039
- const db = cookieDbCandidates(join26(root, dir)).find((p) => existsSync26(p));
24292
+ const db = cookieDbCandidates(join27(root, dir)).find((p) => existsSync26(p));
24040
24293
  if (!db)
24041
24294
  throw new Error(`profile "${dir}" has no cookie store yet (open claude.ai in it once)`);
24042
24295
  return db;
@@ -24078,11 +24331,11 @@ function fetchSeatUsage(jar, org, now, run) {
24078
24331
  return { usage: null, status };
24079
24332
  }
24080
24333
  }
24081
- function launchAgentPlist(bun, script, home, source) {
24334
+ function launchAgentPlist(argv, home, source) {
24082
24335
  const label = launchLabel(source);
24083
- 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`);
24084
24337
  const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
24085
- 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(`
24086
24339
  `);
24087
24340
  return `<?xml version="1.0" encoding="UTF-8"?>
24088
24341
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -24102,16 +24355,14 @@ ${args}
24102
24355
  `;
24103
24356
  }
24104
24357
  function plistPath2(home, source) {
24105
- return join26(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
24358
+ return join27(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
24106
24359
  }
24107
- function install(home, argv, source, log) {
24108
- const bun = argv[0] ?? process.execPath;
24109
- const script = argv[1] ?? "";
24110
- if (!script) {
24111
- 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");
24112
24363
  return 1;
24113
24364
  }
24114
- const dir = join26(home, "Library", "LaunchAgents");
24365
+ const dir = join27(home, "Library", "LaunchAgents");
24115
24366
  mkdirSync22(dir, { recursive: true });
24116
24367
  const path = plistPath2(home, source);
24117
24368
  const tokenPath = seatTokenPath(home, source);
@@ -24121,11 +24372,11 @@ function install(home, argv, source, log) {
24121
24372
  writeFileSync25(tokenPath, `${source.token}
24122
24373
  `, { mode: 384 });
24123
24374
  }
24124
- writeFileSync25(path, launchAgentPlist(bun, script, home, source), { mode: 384 });
24375
+ writeFileSync25(path, launchAgentPlist(argv, home, source), { mode: 384 });
24125
24376
  try {
24126
- execFileSync5("launchctl", ["unload", path], { stdio: "ignore" });
24377
+ launchctl(["unload", path]);
24127
24378
  } catch {}
24128
- execFileSync5("launchctl", ["load", "-w", path]);
24379
+ launchctl(["load", "-w", path]);
24129
24380
  log(`seat-sync timer installed (every ${SYNC_INTERVAL_S / 60} min) → ${path}`);
24130
24381
  return 0;
24131
24382
  }
@@ -24150,7 +24401,9 @@ var seatSync = async (o) => {
24150
24401
  if (source.uninstall)
24151
24402
  return uninstall(o.home, source, log);
24152
24403
  if (source.install)
24153
- 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
+ }));
24154
24407
  if (platform2() !== "darwin" && !o.readCookieRows) {
24155
24408
  log("seat-sync is macOS-only for now.");
24156
24409
  return 2;
@@ -24293,7 +24546,7 @@ var sessionEvent = async (o) => {
24293
24546
  // src/commands/specEvent.ts
24294
24547
  init_meter();
24295
24548
  import { readFileSync as readFileSync29, statSync as statSync2 } from "node:fs";
24296
- import { basename as basename6, isAbsolute as isAbsolute4, relative } from "node:path";
24549
+ import { basename as basename7, isAbsolute as isAbsolute4, relative } from "node:path";
24297
24550
  var HOOK_STDIN_TIMEOUT_MS3 = 1000;
24298
24551
  var ESTIMATE_TIMEOUT_MS = 4000;
24299
24552
  var MIN_SPEC_CHARS = 200;
@@ -24306,12 +24559,12 @@ function isSpecPath(path) {
24306
24559
  return false;
24307
24560
  if (NOT_SPEC.test(path))
24308
24561
  return false;
24309
- return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename6(path));
24562
+ return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename7(path));
24310
24563
  }
24311
24564
  function specTitle(body, path) {
24312
24565
  const m = /^#\s+(.+?)\s*$/m.exec(body);
24313
24566
  const t = m?.[1]?.trim();
24314
- 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);
24315
24568
  }
24316
24569
  function looksLikeSpec(body) {
24317
24570
  if (body.trim().length < MIN_SPEC_CHARS)
@@ -24369,7 +24622,7 @@ var specEvent = async (o) => {
24369
24622
  const spec = {
24370
24623
  title: specTitle(body, input.filePath),
24371
24624
  body: body.slice(0, MAX_SPEC_CHARS),
24372
- repoHint: input.cwd ? basename6(input.cwd) : undefined
24625
+ repoHint: input.cwd ? basename7(input.cwd) : undefined
24373
24626
  };
24374
24627
  try {
24375
24628
  const res = await (o.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
@@ -25089,12 +25342,12 @@ var webhooksCmd = async (o) => {
25089
25342
  // src/config.ts
25090
25343
  init_settings();
25091
25344
  import { chmodSync as chmodSync7, existsSync as existsSync30, mkdirSync as mkdirSync23, readFileSync as readFileSync31, renameSync as renameSync9, writeFileSync as writeFileSync26 } from "node:fs";
25092
- import { join as join27, resolve as resolve11 } from "node:path";
25345
+ import { join as join28, resolve as resolve11 } from "node:path";
25093
25346
  var configDir2 = (home, env = process.env) => {
25094
25347
  const o = env.SLEDS_HOME?.trim();
25095
- return o ? resolve11(home, o) : join27(home, ".config", "sleds");
25348
+ return o ? resolve11(home, o) : join28(home, ".config", "sleds");
25096
25349
  };
25097
- var configPath2 = (home) => join27(configDir2(home), "config.json");
25350
+ var configPath2 = (home) => join28(configDir2(home), "config.json");
25098
25351
  var isObject17 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
25099
25352
  var optString2 = (v) => typeof v === "string" ? v : undefined;
25100
25353
  var parsePriorEnv2 = (v) => {
@@ -25270,6 +25523,12 @@ function runnerFor3(name, exec = defaultExec, o = {}) {
25270
25523
  }
25271
25524
  }
25272
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
+
25273
25532
  // src/schedule.ts
25274
25533
  import { spawnSync as spawnSync11 } from "node:child_process";
25275
25534
  var defaultExec5 = (cmd, args) => {
@@ -25280,7 +25539,7 @@ var defaultExec5 = (cmd, args) => {
25280
25539
  };
25281
25540
 
25282
25541
  // src/settings.ts
25283
- 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";
25284
25543
  var withSeatEnv2 = (command, home, env = process.env, org) => {
25285
25544
  const parts = [];
25286
25545
  const sh = env.SLEDS_HOME?.trim();
@@ -25376,6 +25635,7 @@ commands:
25376
25635
  Token from SLEDS_DEPLOY_TOKEN (Settings \u203A Deploys). SLEDS down never fails a release.
25377
25636
  sled --json What is on your sled (mine with each route, proposed, sent), for a front end.
25378
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
25379
25639
  route <key> Print an item's route: its nodes, what each waits on, what is ready, where each
25380
25640
  run can be watched.
25381
25641
  --dot Graphviz instead: \`sleds route QW-142 --dot | dot -Tpng -o route.png\`
@@ -25385,10 +25645,10 @@ commands:
25385
25645
  disarms; --name <engine> sends it to that engine; --json)
25386
25646
  answer <key>/<node> answer a parked node: the words after it, or --stdin; it
25387
25647
  goes back to ready and the engine takes it (--json)
25388
- propose <key> hold a drafted route on the item for a person's yes, filing
25389
- 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
25390
25650
  <nodes.json> or --stdin, --name <engine> (--json)
25391
- 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
25392
25652
  Pickup: Auto, arms it; --file <nodes.json> approves an
25393
25653
  edited set instead (--json)
25394
25654
  run <key> run the engine for this one item until its route lands
@@ -25424,8 +25684,8 @@ commands:
25424
25684
  high, xhigh or max. With --agent, a claude command gets it;
25425
25685
  another runs as given and the engine says so
25426
25686
  --decider-effort <e> the effort every answerer launches with; default the node's
25427
- --drafter-model <id> the model a drafting session launches with; default the node's
25428
- --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
25429
25689
  --pr-title '<template>' the PR title the session must use: {key} {ticket} {item}
25430
25690
  {node} {title}, e.g. 'feat: [{key}] {title}'
25431
25691
  Flags left out come from your engine profile in SLEDS (Settings); with Pickup:
@@ -25552,14 +25812,20 @@ var hookStdin = async () => {
25552
25812
  const text = await readStdin2(300);
25553
25813
  return text.trim() ? text : undefined;
25554
25814
  };
25555
- 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
+ };
25556
25822
  var shellQuote = (s) => /^[\w./-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
25557
- var statusLineCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "statusline"].map(shellQuote).join(" "), home);
25558
- var seatEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "seat-event"].map(shellQuote).join(" "), home);
25559
- var promptEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "prompt-event"].map(shellQuote).join(" "), home);
25560
- var sessionEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "session-event"].map(shellQuote).join(" "), home);
25561
- var stopEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "stop-event"].map(shellQuote).join(" "), home);
25562
- 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);
25563
25829
  var mcpFlag = (flags) => flags["no-mcp"] === true ? false : flags.mcp === true ? true : undefined;
25564
25830
  var main = async (argv) => {
25565
25831
  const { cmd, flags } = parseArgs(argv);
@@ -25567,7 +25833,7 @@ var main = async (argv) => {
25567
25833
  console.log(commandUsage(cmd));
25568
25834
  return 0;
25569
25835
  }
25570
- const home = homedir();
25836
+ const home = homedir3();
25571
25837
  const scheduler = {
25572
25838
  platform: platform3(),
25573
25839
  home,
@@ -25777,7 +26043,7 @@ var main = async (argv) => {
25777
26043
  case "mcp":
25778
26044
  return mcp({ home });
25779
26045
  case "seat-sync":
25780
- return seatSync({ home, argv: process.argv.slice(3) });
26046
+ return seatSync({ home, argv: process.argv.slice(3), sledsArgv: sledsArgv() });
25781
26047
  case "statusline":
25782
26048
  return statusline({ home });
25783
26049
  case "help":
@@ -25790,7 +26056,7 @@ ${renderHelpText(argv[1])}`);
25790
26056
  case "version":
25791
26057
  case "--version":
25792
26058
  case "-v":
25793
- console.log("sleds 0.1.45");
26059
+ console.log("sleds 0.1.47");
25794
26060
  return 0;
25795
26061
  default:
25796
26062
  console.error(`unknown command: ${cmd}