@sleds/cli 0.1.48 → 0.1.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/sleds.mjs +508 -206
  2. package/package.json +1 -1
package/dist/sleds.mjs CHANGED
@@ -4246,7 +4246,7 @@ async function actualTool(ctx, args, to = { path: "/proxy/estimate/actual" }) {
4246
4246
  const from = str5(r.elapsedFrom);
4247
4247
  const unsized = r.unsized === true;
4248
4248
  const bits = [
4249
- recorded !== undefined ? `${recorded} min${from ? ` measured from the ${from}` : ""}${num3(r.saidMinutes) !== undefined && num3(r.saidMinutes) !== recorded ? ` (you said ${num3(r.saidMinutes)})` : ""}` : phases ? "phases recorded" : null,
4249
+ recorded !== undefined ? `${recorded} min${from === "runs" ? " of engine run time" : from ? ` measured from the ${from}` : ""}${num3(r.saidMinutes) !== undefined && num3(r.saidMinutes) !== recorded ? ` (you said ${num3(r.saidMinutes)})` : ""}` : phases ? "phases recorded" : null,
4250
4250
  num3(args.usd) !== undefined ? usd2(num3(args.usd)) : args.usd === null ? "$ cleared" : null,
4251
4251
  num3(args.tokensIn) !== undefined || num3(args.tokensOut) !== undefined ? `${(num3(args.tokensIn) ?? 0) + (num3(args.tokensOut) ?? 0)} tokens` : null,
4252
4252
  str5(args.model),
@@ -5479,6 +5479,9 @@ var init_agent = __esm(() => {
5479
5479
  init_mention();
5480
5480
  });
5481
5481
 
5482
+ // ../../packages/shared/src/slack/channel.ts
5483
+ var init_channel = () => {};
5484
+
5482
5485
  // ../../packages/shared/src/item/productHits.ts
5483
5486
  var PATH_STOP, COMMON;
5484
5487
  var init_productHits = __esm(() => {
@@ -6531,6 +6534,30 @@ var init_deploys = __esm(() => {
6531
6534
  SERVICE_RE = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,39}$/;
6532
6535
  });
6533
6536
 
6537
+ // ../../packages/shared/src/deploys/metrics.ts
6538
+ var WEEK_MS;
6539
+ var init_metrics = __esm(() => {
6540
+ WEEK_MS = 7 * 24 * 60 * 60 * 1000;
6541
+ });
6542
+
6543
+ // ../../packages/shared/src/deploys/period.ts
6544
+ var DAY_MS2;
6545
+ var init_period = __esm(() => {
6546
+ DAY_MS2 = 24 * 60 * 60 * 1000;
6547
+ });
6548
+
6549
+ // ../../packages/shared/src/deploys/stability.ts
6550
+ var init_stability = __esm(() => {
6551
+ init_outcome();
6552
+ init_metrics();
6553
+ });
6554
+
6555
+ // ../../packages/shared/src/deploys/batchSize.ts
6556
+ var init_batchSize = __esm(() => {
6557
+ init_outcome();
6558
+ init_metrics();
6559
+ });
6560
+
6534
6561
  // ../../packages/shared/src/newrelic/newrelic.ts
6535
6562
  var init_newrelic = () => {};
6536
6563
 
@@ -7921,6 +7948,7 @@ var init_src = __esm(() => {
7921
7948
  init_mention();
7922
7949
  init_agent();
7923
7950
  init_copy();
7951
+ init_channel();
7924
7952
  init_productHits();
7925
7953
  init_model();
7926
7954
  init_parse();
@@ -7936,6 +7964,10 @@ var init_src = __esm(() => {
7936
7964
  init_pack2();
7937
7965
  init_flags();
7938
7966
  init_deploys();
7967
+ init_metrics();
7968
+ init_period();
7969
+ init_stability();
7970
+ init_batchSize();
7939
7971
  init_sentry();
7940
7972
  init_newrelic();
7941
7973
  init_musher();
@@ -8611,7 +8643,7 @@ var init_seat = __esm(() => {
8611
8643
 
8612
8644
  // src/index.ts
8613
8645
  import { existsSync as existsSync36, realpathSync as realpathSync3 } from "fs";
8614
- import { homedir as homedir9, platform as platform3 } from "os";
8646
+ import { homedir as homedir10, platform as platform3 } from "os";
8615
8647
  import { fileURLToPath } from "url";
8616
8648
 
8617
8649
  // ../../packages/shared/src/index.ts
@@ -8640,6 +8672,7 @@ init_outcome();
8640
8672
  init_mention();
8641
8673
  init_agent();
8642
8674
  init_copy();
8675
+ init_channel();
8643
8676
  init_productHits();
8644
8677
  init_model();
8645
8678
  init_parse();
@@ -8655,6 +8688,10 @@ init_cheatSheet();
8655
8688
  init_pack2();
8656
8689
  init_flags();
8657
8690
  init_deploys();
8691
+ init_metrics();
8692
+ init_period();
8693
+ init_stability();
8694
+ init_batchSize();
8658
8695
  init_sentry();
8659
8696
  init_newrelic();
8660
8697
  init_musher();
@@ -9824,6 +9861,7 @@ var defer = async (o) => {
9824
9861
  init_src();
9825
9862
  import { execFileSync as execFileSync2 } from "node:child_process";
9826
9863
  var DEPLOYS_URL = "https://hooks.sleds.ai/deploys";
9864
+ var DEPLOY_WAIT_MS = 120000;
9827
9865
  var USAGE = "usage: sleds deploy --env <slug> [--service <name>] [--sha <sha>] [--repo <owner/name>]";
9828
9866
  var FLAGS = ["env", "service", "sha", "repo"];
9829
9867
  var set = (x) => x?.trim() ? x.trim() : undefined;
@@ -9880,7 +9918,7 @@ var defaultPost = async (url, token, body) => {
9880
9918
  method: "POST",
9881
9919
  headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
9882
9920
  body: JSON.stringify(body),
9883
- signal: AbortSignal.timeout(15000)
9921
+ signal: AbortSignal.timeout(DEPLOY_WAIT_MS)
9884
9922
  });
9885
9923
  let json = null;
9886
9924
  try {
@@ -9888,7 +9926,8 @@ var defaultPost = async (url, token, body) => {
9888
9926
  } catch {}
9889
9927
  return { status: res.status, json };
9890
9928
  } catch (e) {
9891
- return { error: e instanceof Error ? e.message : String(e) };
9929
+ const timedOut = e instanceof Error && e.name === "TimeoutError";
9930
+ return { error: e instanceof Error ? e.message : String(e), ...timedOut ? { timedOut } : {} };
9892
9931
  }
9893
9932
  };
9894
9933
  function deployLine(body, json) {
@@ -9921,6 +9960,10 @@ var deployCmd = async (o) => {
9921
9960
  const body = resolved.body;
9922
9961
  const url = set(env.SLEDS_DEPLOYS_URL) ?? DEPLOYS_URL;
9923
9962
  const r = await (o.post ?? defaultPost)(url, token, body);
9963
+ if ("error" in r && r.timedOut) {
9964
+ error(`notice: the report was sent but SLEDS did not answer within ${DEPLOY_WAIT_MS / 1000}s; it is usually still recorded — see Settings › Deploys › Recent deploys`);
9965
+ return 0;
9966
+ }
9924
9967
  if ("error" in r) {
9925
9968
  error(`warning: SLEDS unreachable, deploy not recorded — ${r.error}`);
9926
9969
  return 0;
@@ -9951,8 +9994,8 @@ import {
9951
9994
  rmSync as rmSync13,
9952
9995
  writeFileSync as writeFileSync19
9953
9996
  } from "node:fs";
9954
- import { tmpdir } from "node:os";
9955
- import { delimiter as delimiter3, dirname as dirname16, join as join25, resolve as resolve9 } from "node:path";
9997
+ import { tmpdir, userInfo as userInfo2 } from "node:os";
9998
+ import { delimiter as delimiter3, dirname as dirname17, join as join26, resolve as resolve9 } from "node:path";
9956
9999
 
9957
10000
  // src/agentMcp.ts
9958
10001
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -10328,8 +10371,36 @@ var runCockpit = async (cockpit, argv, opts = {}) => {
10328
10371
  // src/commands/doctor.ts
10329
10372
  init_config();
10330
10373
 
10374
+ // src/engine/credential.ts
10375
+ import { homedir } from "node:os";
10376
+ import { join as join11 } from "node:path";
10377
+ var API_KEY_VAR = "ANTHROPIC_API_KEY";
10378
+ var SEAT_TOKEN_VAR = "CLAUDE_CODE_OAUTH_TOKEN";
10379
+ function namesVar(text, name) {
10380
+ return new RegExp(`^\\s*(?:export\\s+)?${name}\\s*=\\s*\\S`, "m").test(text);
10381
+ }
10382
+ function loginPath(env, home = homedir()) {
10383
+ return join11(env.CLAUDE_CONFIG_DIR?.trim() || join11(home, ".claude"), ".credentials.json");
10384
+ }
10385
+ function detectCredential(env, o) {
10386
+ const file = o.boxEnvText ?? "";
10387
+ const fileWhere = o.boxEnvPath ?? "box.env";
10388
+ const vars = [
10389
+ [API_KEY_VAR, "key", "api_key"],
10390
+ [SEAT_TOKEN_VAR, "seat", "seat_token"]
10391
+ ];
10392
+ for (const [name, kind, source] of vars) {
10393
+ if (env[name]?.trim())
10394
+ return { kind, source, where: "this shell" };
10395
+ if (namesVar(file, name))
10396
+ return { kind, source, where: fileWhere };
10397
+ }
10398
+ const login = loginPath(env, o.home);
10399
+ return o.exists(login) ? { kind: "seat", source: "login", where: login } : null;
10400
+ }
10401
+
10331
10402
  // src/engine/repos.ts
10332
- import { basename as basename2, dirname as dirname9, join as join11 } from "node:path";
10403
+ import { basename as basename2, dirname as dirname9, join as join12 } from "node:path";
10333
10404
  function splitReposDirs(raw) {
10334
10405
  return (raw ?? "").split(/[:\n]/).map((d) => d.trim()).filter(Boolean);
10335
10406
  }
@@ -10356,13 +10427,13 @@ function resolveRepoPath(o) {
10356
10427
  if (name.startsWith("."))
10357
10428
  continue;
10358
10429
  for (const dir of dirs) {
10359
- const p = join11(dir, name);
10360
- if (o.exists(join11(p, ".git")))
10430
+ const p = join12(dir, name);
10431
+ if (o.exists(join12(p, ".git")))
10361
10432
  return p;
10362
10433
  }
10363
10434
  }
10364
10435
  const want = o.repos.join(", ");
10365
- const where = names.flatMap((n) => dirs.map((d) => join11(d, n))).join(" or ");
10436
+ const where = names.flatMap((n) => dirs.map((d) => join12(d, n))).join(" or ");
10366
10437
  return {
10367
10438
  error: `No checkout of ${want} on this engine's machine: expected ${where}. Clone it there (or pass --repo).`
10368
10439
  };
@@ -10370,7 +10441,7 @@ function resolveRepoPath(o) {
10370
10441
  var isRoot = (p) => dirname9(p) === p;
10371
10442
  function insideCheckout(dir, exists) {
10372
10443
  for (let d = dir;!isRoot(d); d = dirname9(d)) {
10373
- if (exists(join11(d, ".git")))
10444
+ if (exists(join12(d, ".git")))
10374
10445
  return true;
10375
10446
  }
10376
10447
  return false;
@@ -10400,12 +10471,12 @@ init_meter();
10400
10471
 
10401
10472
  // src/runners/cmux.ts
10402
10473
  import { existsSync as existsSync11, rmSync as rmSync2, writeFileSync as writeFileSync10 } from "node:fs";
10403
- import { delimiter, join as join13 } from "node:path";
10474
+ import { delimiter, join as join14 } from "node:path";
10404
10475
 
10405
10476
  // src/runners/exec.ts
10406
10477
  import { spawn, spawnSync as spawnSync3 } from "node:child_process";
10407
10478
  import { closeSync as closeSync2, fstatSync, openSync as openSync2, readSync as readSync2 } from "node:fs";
10408
- import { basename as basename3, dirname as dirname10, join as join12 } from "node:path";
10479
+ import { basename as basename3, dirname as dirname10, join as join13 } from "node:path";
10409
10480
 
10410
10481
  // src/runners/sandbox.ts
10411
10482
  var absRule = (dir) => `/${dir.replace(/\/+$/, "")}/**`;
@@ -10549,7 +10620,7 @@ var readLogTail = (path) => {
10549
10620
  };
10550
10621
  var logPathFor = (promptFile, ext, dir) => {
10551
10622
  const base = basename3(promptFile).replace(/\.md$/i, "");
10552
- return join12(dir ?? dirname10(promptFile), `${base}.${ext}`);
10623
+ return join13(dir ?? dirname10(promptFile), `${base}.${ext}`);
10553
10624
  };
10554
10625
  var tailText = (s, bytes = 4096) => {
10555
10626
  if (s.length <= bytes)
@@ -10573,7 +10644,7 @@ var isRunnerKey = (key) => /^(?:[1-9]|esc)$/.test(key);
10573
10644
  var CMUX_APP_BIN = "/Applications/cmux.app/Contents/Resources/bin/cmux";
10574
10645
  var resolveCmuxBin = (exists = existsSync11, path = process.env.PATH ?? "") => {
10575
10646
  for (const dir of path.split(delimiter)) {
10576
- if (dir && exists(join13(dir, "cmux")))
10647
+ if (dir && exists(join14(dir, "cmux")))
10577
10648
  return "cmux";
10578
10649
  }
10579
10650
  return exists(CMUX_APP_BIN) ? CMUX_APP_BIN : "cmux";
@@ -10934,7 +11005,7 @@ function cmuxRunner(exec, deps = {}) {
10934
11005
 
10935
11006
  // src/runners/orca.ts
10936
11007
  import { existsSync as existsSync12, lstatSync, readlinkSync, writeFileSync as writeFileSync11 } from "node:fs";
10937
- import { join as join14, resolve as resolve7 } from "node:path";
11008
+ import { join as join15, resolve as resolve7 } from "node:path";
10938
11009
  var obj = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
10939
11010
  var str8 = (v) => typeof v === "string" && v.length > 0 ? v : null;
10940
11011
  var parseOrcaJson = (stdout) => {
@@ -10995,7 +11066,7 @@ var realFs = { lstat: lstatSync, readlink: readlinkSync, exists: existsSync12 };
10995
11066
  var ORCA_LINK_FIX = "reinstall Orca's shell command from Orca (it links `orca` onto your PATH)";
10996
11067
  function danglingOrca(path, fs) {
10997
11068
  for (const dir of path.split(":").filter(Boolean)) {
10998
- const link = join14(dir, "orca");
11069
+ const link = join15(dir, "orca");
10999
11070
  try {
11000
11071
  if (!fs.lstat(link).isSymbolicLink())
11001
11072
  return null;
@@ -11142,10 +11213,10 @@ function orcaRunner(exec, deps = {}) {
11142
11213
  }
11143
11214
 
11144
11215
  // src/runtime.ts
11145
- import { homedir } from "node:os";
11146
- import { join as join15, win32 } from "node:path";
11216
+ import { homedir as homedir2 } from "node:os";
11217
+ import { join as join16, win32 } from "node:path";
11147
11218
  var isCompiled = (argv1 = process.argv[1]) => Boolean(argv1 && (argv1.startsWith("/$bunfs/") || argv1.startsWith("B:\\~BUN\\")));
11148
- var sledsLink = (home = homedir(), platform = process.platform) => platform === "win32" ? win32.join(process.env.LOCALAPPDATA ?? win32.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join15(home, ".sleds", "bin", "sleds");
11219
+ var sledsLink = (home = homedir2(), platform = process.platform) => platform === "win32" ? win32.join(process.env.LOCALAPPDATA ?? win32.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join16(home, ".sleds", "bin", "sleds");
11149
11220
 
11150
11221
  // src/commands/doctor.ts
11151
11222
  init_settings();
@@ -11161,10 +11232,11 @@ import {
11161
11232
  readFileSync as readFileSync15,
11162
11233
  existsSync as realExists,
11163
11234
  rmSync as rmSync10,
11235
+ statSync as statSync5,
11164
11236
  writeFileSync as writeFileSync16
11165
11237
  } from "node:fs";
11166
- import { hostname as hostname2 } from "node:os";
11167
- import { join as join23, resolve as resolve8 } from "node:path";
11238
+ import { hostname as hostname2, userInfo } from "node:os";
11239
+ import { dirname as dirname15, isAbsolute as isAbsolute3, join as join24, resolve as resolve8 } from "node:path";
11168
11240
 
11169
11241
  // src/engine/beat.ts
11170
11242
  var BEAT_EVERY_MS = 60000;
@@ -11176,10 +11248,11 @@ function beatBody(state, flags, host = {}, cap = {}) {
11176
11248
  name: flags.name,
11177
11249
  os: host.os ?? process.platform,
11178
11250
  runner: flags.runner,
11179
- version: host.version ?? "0.1.48" ?? "dev",
11251
+ version: host.version ?? "0.1.50" ?? "dev",
11180
11252
  running: live.length,
11181
11253
  items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
11182
11254
  ...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
11255
+ ...host.credential ? { credential: host.credential } : {},
11183
11256
  ...m ? {
11184
11257
  machine: {
11185
11258
  cpuPct: m.cpuPct,
@@ -13066,9 +13139,9 @@ function providerFailure(screen) {
13066
13139
  // src/engine/worktree.ts
13067
13140
  init_src();
13068
13141
  import { appendFileSync, existsSync as existsSync13, mkdirSync as mkdirSync11 } from "node:fs";
13069
- import { dirname as dirname11, isAbsolute, join as join16 } from "node:path";
13142
+ import { dirname as dirname11, isAbsolute, join as join17 } from "node:path";
13070
13143
  function worktreePath(repoPath, name) {
13071
- return join16(repoPath, ".worktrees", name);
13144
+ return join17(repoPath, ".worktrees", name);
13072
13145
  }
13073
13146
  var fail = (what, r) => new Error(`${what} failed: ${(r.stderr || r.stdout).trim() || `exit ${r.status}`}`);
13074
13147
  function defaultBranch(exec, repoPath) {
@@ -13103,7 +13176,7 @@ function ensureIgnored(exec, repoPath, fs = realWorktreeFs) {
13103
13176
  if (common.status !== 0)
13104
13177
  return;
13105
13178
  const dir = common.stdout.trim();
13106
- const exclude = join16(isAbsolute(dir) ? dir : join16(repoPath, dir), "info", "exclude");
13179
+ const exclude = join17(isAbsolute(dir) ? dir : join17(repoPath, dir), "info", "exclude");
13107
13180
  fs.append(exclude, `
13108
13181
  # sleds engine: one worktree per route node
13109
13182
  .worktrees/
@@ -13115,7 +13188,7 @@ function ensureWorktree(exec, repoPath, branch, path, base = "main", fs = realWo
13115
13188
  return path;
13116
13189
  }
13117
13190
  function makeWorktree(exec, repoPath, branch, path, base, fs, log) {
13118
- if (fs.exists(join16(path, ".git"))) {
13191
+ if (fs.exists(join17(path, ".git"))) {
13119
13192
  fastForwardUntouched(exec, path, base, log);
13120
13193
  return path;
13121
13194
  }
@@ -13191,13 +13264,13 @@ function installArgv(command) {
13191
13264
  return rest.every((a) => a.startsWith("-")) ? argv : null;
13192
13265
  }
13193
13266
  function lockfileInstall(path, exists) {
13194
- if (exists(join16(path, "pnpm-lock.yaml")))
13267
+ if (exists(join17(path, "pnpm-lock.yaml")))
13195
13268
  return ["pnpm", "install", "--frozen-lockfile"];
13196
- if (exists(join16(path, "bun.lock")) || exists(join16(path, "bun.lockb")))
13269
+ if (exists(join17(path, "bun.lock")) || exists(join17(path, "bun.lockb")))
13197
13270
  return ["bun", "install", "--frozen-lockfile"];
13198
- if (exists(join16(path, "yarn.lock")))
13271
+ if (exists(join17(path, "yarn.lock")))
13199
13272
  return ["yarn", "install", "--frozen-lockfile"];
13200
- if (exists(join16(path, "package-lock.json")))
13273
+ if (exists(join17(path, "package-lock.json")))
13201
13274
  return ["npm", "ci"];
13202
13275
  return null;
13203
13276
  }
@@ -13255,7 +13328,7 @@ function claimRunOf(run, repo) {
13255
13328
  };
13256
13329
  }
13257
13330
  function ensureInstalled(exec, path, fs, o = {}) {
13258
- if (!fs.exists(join16(path, "package.json")) || fs.exists(join16(path, "node_modules")))
13331
+ if (!fs.exists(join17(path, "package.json")) || fs.exists(join17(path, "node_modules")))
13259
13332
  return null;
13260
13333
  const argv = installArgv(o.command) ?? lockfileInstall(path, fs.exists);
13261
13334
  if (!argv)
@@ -13270,7 +13343,7 @@ function ensureInstalled(exec, path, fs, o = {}) {
13270
13343
  return { argv, ok };
13271
13344
  }
13272
13345
  function ensureDetachedWorktree(exec, repoPath, path, base = "main", fs = realWorktreeFs) {
13273
- if (fs.exists(join16(path, ".git")))
13346
+ if (fs.exists(join17(path, ".git")))
13274
13347
  return path;
13275
13348
  ensureIgnored(exec, repoPath, fs);
13276
13349
  const f = exec("git", ["-C", repoPath, "fetch", "origin", base]);
@@ -16559,8 +16632,8 @@ init_settings();
16559
16632
 
16560
16633
  // src/update/drain.ts
16561
16634
  import { closeSync as closeSync4, existsSync as existsSync18, mkdirSync as mkdirSync17, openSync as openSync4, rmSync as rmSync9, statSync as statSync4, writeSync as writeSync2 } from "node:fs";
16562
- import { homedir as homedir6 } from "node:os";
16563
- import { join as join22 } from "node:path";
16635
+ import { homedir as homedir7 } from "node:os";
16636
+ import { join as join23 } from "node:path";
16564
16637
 
16565
16638
  // ../../packages/shared/src/updates/manifest.ts
16566
16639
  var CLI_PLATFORMS = [
@@ -16702,13 +16775,13 @@ import {
16702
16775
  statSync as statSync2,
16703
16776
  writeFileSync as writeFileSync13
16704
16777
  } from "node:fs";
16705
- import { homedir as homedir2 } from "node:os";
16706
- import { dirname as dirname12, join as join17, win32 as win322 } from "node:path";
16778
+ import { homedir as homedir3 } from "node:os";
16779
+ import { dirname as dirname12, join as join18, win32 as win322 } from "node:path";
16707
16780
  var UPDATE_LOCK_STALE_MS = 10 * 60000;
16708
- function sledsRoot(home = homedir2(), platform = process.platform) {
16709
- return platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds") : join17(home, ".sleds");
16781
+ function sledsRoot(home = homedir3(), platform = process.platform) {
16782
+ return platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds") : join18(home, ".sleds");
16710
16783
  }
16711
- var pathFor = (platform) => platform === "win32" ? win322 : { join: join17 };
16784
+ var pathFor = (platform) => platform === "win32" ? win322 : { join: join18 };
16712
16785
  function versionDir(home, v, platform = process.platform) {
16713
16786
  return pathFor(platform).join(sledsRoot(home, platform), "versions", v);
16714
16787
  }
@@ -16900,7 +16973,7 @@ async function fetchVersion(o) {
16900
16973
  const platform = o.platform ?? process.platform;
16901
16974
  const arch = o.arch ?? process.arch;
16902
16975
  const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
16903
- const running = o.running ?? "0.1.48";
16976
+ const running = o.running ?? "0.1.50";
16904
16977
  if (!publicKey)
16905
16978
  return { ok: false, why: "no release key yet" };
16906
16979
  if (!VERSION_RE2.test(o.version))
@@ -16977,7 +17050,7 @@ async function fetchVersion(o) {
16977
17050
 
16978
17051
  // src/update/guard.ts
16979
17052
  import { existsSync as existsSync17 } from "node:fs";
16980
- import { homedir as homedir5 } from "node:os";
17053
+ import { homedir as homedir6 } from "node:os";
16981
17054
 
16982
17055
  // src/update/migrate.ts
16983
17056
  import { spawn as spawn2 } from "node:child_process";
@@ -16993,20 +17066,20 @@ import {
16993
17066
  symlinkSync,
16994
17067
  writeFileSync as writeFileSync15
16995
17068
  } from "node:fs";
16996
- import { homedir as homedir3 } from "node:os";
16997
- import { basename as basename5, delimiter as delimiter2, dirname as dirname13, isAbsolute as isAbsolute2, join as join20, relative } from "node:path";
17069
+ import { homedir as homedir4 } from "node:os";
17070
+ import { basename as basename5, delimiter as delimiter2, dirname as dirname13, isAbsolute as isAbsolute2, join as join21, relative } from "node:path";
16998
17071
 
16999
17072
  // src/commands/engineSystemd.ts
17000
- import { join as join18 } from "node:path";
17073
+ import { join as join19 } from "node:path";
17001
17074
  var BOX_ENV_UNIT_PATH = "%h/.config/sleds/box.env";
17002
17075
  function boxEnvPath(home) {
17003
- return join18(home, ".config", "sleds", "box.env");
17076
+ return join19(home, ".config", "sleds", "box.env");
17004
17077
  }
17005
17078
  function engineUnitDir(home) {
17006
- return join18(home, ".config", "systemd", "user");
17079
+ return join19(home, ".config", "systemd", "user");
17007
17080
  }
17008
17081
  function engineUnitPath(home, label) {
17009
- return join18(engineUnitDir(home), `${label}.service`);
17082
+ return join19(engineUnitDir(home), `${label}.service`);
17010
17083
  }
17011
17084
  function systemdQuote(s) {
17012
17085
  const body = s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/%/g, "%%").replace(/\$/g, "$$$$");
@@ -17048,7 +17121,7 @@ function parseEngineUnit(text) {
17048
17121
  // src/schedule.ts
17049
17122
  import { spawnSync as spawnSync4 } from "node:child_process";
17050
17123
  import { existsSync as existsSync15, mkdirSync as mkdirSync14, rmSync as rmSync6, writeFileSync as writeFileSync14 } from "node:fs";
17051
- import { join as join19 } from "node:path";
17124
+ import { join as join20 } from "node:path";
17052
17125
  var REVERT_LABEL = "ai.sleds.revert";
17053
17126
  var defaultExec2 = (cmd, args) => {
17054
17127
  const r = spawnSync4(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
@@ -17056,7 +17129,7 @@ var defaultExec2 = (cmd, args) => {
17056
17129
  return { ok: false, stderr: r.error.message };
17057
17130
  return { ok: r.status === 0, stderr: r.stderr ?? "" };
17058
17131
  };
17059
- var plistPath = (home) => join19(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
17132
+ var plistPath = (home) => join20(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
17060
17133
  var xmlEscape2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
17061
17134
  var buildLaunchdPlist = (sledsArgv, deadline) => {
17062
17135
  const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape2(a)}</string>`).join(`
@@ -17095,7 +17168,7 @@ var scheduleRevert = (d, deadlineMs) => {
17095
17168
  if (d.platform === "darwin") {
17096
17169
  const p = plistPath(d.home);
17097
17170
  try {
17098
- mkdirSync14(join19(d.home, "Library", "LaunchAgents"), { recursive: true });
17171
+ mkdirSync14(join20(d.home, "Library", "LaunchAgents"), { recursive: true });
17099
17172
  d.exec("launchctl", ["unload", p]);
17100
17173
  writeFileSync14(p, buildLaunchdPlist(d.sledsArgv, deadline));
17101
17174
  const r = d.exec("launchctl", ["load", p]);
@@ -17147,8 +17220,8 @@ var HOOK_SUBS = [
17147
17220
  "stop-event",
17148
17221
  "permission-event"
17149
17222
  ];
17150
- var migrateBakDir = (home) => join20(sledsRoot(home), "migrate.bak");
17151
- var manifestPath = (home) => join20(migrateBakDir(home), "manifest.json");
17223
+ var migrateBakDir = (home) => join21(sledsRoot(home), "migrate.bak");
17224
+ var manifestPath = (home) => join21(migrateBakDir(home), "manifest.json");
17152
17225
  var xmlEscape3 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
17153
17226
  var xmlUnescape = (s) => s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
17154
17227
  var shQuote = (s) => /^[\w./~-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
@@ -17248,13 +17321,13 @@ function rewriteSettings(text, link) {
17248
17321
  }
17249
17322
  var listDir = (dir, keep) => {
17250
17323
  try {
17251
- return readdirSync2(dir).filter(keep).sort().map((n) => join20(dir, n));
17324
+ return readdirSync2(dir).filter(keep).sort().map((n) => join21(dir, n));
17252
17325
  } catch {
17253
17326
  return [];
17254
17327
  }
17255
17328
  };
17256
17329
  function unitFiles(home) {
17257
- const agents = listDir(join20(home, "Library", "LaunchAgents"), (n) => n.startsWith("ai.sleds.") && n.endsWith(".plist")).map((path) => ({
17330
+ const agents = listDir(join21(home, "Library", "LaunchAgents"), (n) => n.startsWith("ai.sleds.") && n.endsWith(".plist")).map((path) => ({
17258
17331
  path,
17259
17332
  ...basename5(path).startsWith("ai.sleds.revert") ? {} : { reload: "launchd" }
17260
17333
  }));
@@ -17266,7 +17339,7 @@ function unitClaudeDir(text) {
17266
17339
  return plist ? xmlUnescape(plist) : undefined;
17267
17340
  }
17268
17341
  function claudeDirs(home, env) {
17269
- const dirs = [join20(home, ".claude"), claudeDir(home, env)];
17342
+ const dirs = [join21(home, ".claude"), claudeDir(home, env)];
17270
17343
  for (const u of unitFiles(home)) {
17271
17344
  try {
17272
17345
  const d = unitClaudeDir(readFileSync14(u.path, "utf8"));
@@ -17290,7 +17363,7 @@ function migrationPlan(home, link, env = process.env) {
17290
17363
  out.push({ ...u, text: next });
17291
17364
  }
17292
17365
  for (const dir of claudeDirs(home, env)) {
17293
- const path = join20(dir, "settings.json");
17366
+ const path = join21(dir, "settings.json");
17294
17367
  let text;
17295
17368
  try {
17296
17369
  text = readFileSync14(path, "utf8");
@@ -17305,7 +17378,7 @@ function migrationPlan(home, link, env = process.env) {
17305
17378
  }
17306
17379
  var backupFor = (home, path) => {
17307
17380
  const rel = relative(home, path);
17308
- return rel.startsWith("..") || isAbsolute2(rel) ? join20(migrateBakDir(home), "abs", path) : join20(migrateBakDir(home), rel);
17381
+ return rel.startsWith("..") || isAbsolute2(rel) ? join21(migrateBakDir(home), "abs", path) : join21(migrateBakDir(home), rel);
17309
17382
  };
17310
17383
  function writeKeepingMode(path, text) {
17311
17384
  let mode = 420;
@@ -17390,7 +17463,7 @@ function putBack(home, m) {
17390
17463
  return failed;
17391
17464
  }
17392
17465
  function restoreMigration(s, o) {
17393
- const home = o.home ?? homedir3();
17466
+ const home = o.home ?? homedir4();
17394
17467
  const m = readManifest(home);
17395
17468
  const to = m?.to ?? s.pending?.to ?? "?";
17396
17469
  const failed = m ? putBack(home, m) : [];
@@ -17402,7 +17475,7 @@ function restoreMigration(s, o) {
17402
17475
  return failed.length ? `moved back to the npm install, but could not restore ${failed.join(", ")} — the copies are in ${migrateBakDir(home)}` : "moved back to the npm install";
17403
17476
  }
17404
17477
  async function migrateToBinary(o) {
17405
- const home = o.home ?? homedir3();
17478
+ const home = o.home ?? homedir4();
17406
17479
  const log = o.log ?? console.error;
17407
17480
  const env = o.env ?? process.env;
17408
17481
  const platform = o.platform ?? process.platform;
@@ -17496,11 +17569,11 @@ import {
17496
17569
  rmSync as rmSync8,
17497
17570
  symlinkSync as symlinkSync2
17498
17571
  } from "node:fs";
17499
- import { homedir as homedir4 } from "node:os";
17500
- import { dirname as dirname14, join as join21 } from "node:path";
17572
+ import { homedir as homedir5 } from "node:os";
17573
+ import { dirname as dirname14, join as join22 } from "node:path";
17501
17574
  var NO_PREVIOUS = "no previous version on this machine";
17502
- function allStateFiles(home = homedir4(), env = process.env) {
17503
- const roots = [...new Set([configDir(home, env), join21(home, ".config", "sleds")])];
17575
+ function allStateFiles(home = homedir5(), env = process.env) {
17576
+ const roots = [...new Set([configDir(home, env), join22(home, ".config", "sleds")])];
17504
17577
  const out = [];
17505
17578
  const walk = (dir) => {
17506
17579
  let names;
@@ -17511,20 +17584,20 @@ function allStateFiles(home = homedir4(), env = process.env) {
17511
17584
  }
17512
17585
  for (const n of names.sort())
17513
17586
  if (n.endsWith(".json") && n !== "removed-engines.json")
17514
- out.push(join21(dir, n));
17587
+ out.push(join22(dir, n));
17515
17588
  for (const sub of ["orgs", "seats"]) {
17516
17589
  let kids;
17517
17590
  try {
17518
- kids = readdirSync3(join21(dir, sub));
17591
+ kids = readdirSync3(join22(dir, sub));
17519
17592
  } catch {
17520
17593
  continue;
17521
17594
  }
17522
17595
  for (const k of kids.sort())
17523
- walk(join21(dir, sub, k));
17596
+ walk(join22(dir, sub, k));
17524
17597
  }
17525
17598
  };
17526
17599
  for (const r of roots)
17527
- walk(join21(r, "engine"));
17600
+ walk(join22(r, "engine"));
17528
17601
  return out;
17529
17602
  }
17530
17603
  var backupPath2 = (file, v) => `${file}.${v}.bak`;
@@ -17620,7 +17693,7 @@ function applyConfirm(s, home, o = {}) {
17620
17693
  }
17621
17694
  for (const n of names)
17622
17695
  if (n.startsWith(prefix) && n.endsWith(".bak"))
17623
- rmSync8(join21(dir, n), { force: true });
17696
+ rmSync8(join22(dir, n), { force: true });
17624
17697
  }
17625
17698
  const keep = new Set([s.current, s.previous, s.drain?.to].filter(Boolean));
17626
17699
  const versions = dirname14(versionDir(home, s.current, platform));
@@ -17710,7 +17783,7 @@ function movedAway(s, home, version, platform) {
17710
17783
  return at && at !== version ? at : null;
17711
17784
  }
17712
17785
  async function startGuard(o) {
17713
- const home = o.home ?? homedir5();
17786
+ const home = o.home ?? homedir6();
17714
17787
  const platform = o.platform ?? process.platform;
17715
17788
  const version = o.version;
17716
17789
  if (!version || !guarded(home, version, platform))
@@ -17742,7 +17815,7 @@ async function startGuard(o) {
17742
17815
  }
17743
17816
  }
17744
17817
  function firstBeatWatchdog(o) {
17745
- const home = o.home ?? homedir5();
17818
+ const home = o.home ?? homedir6();
17746
17819
  const platform = o.platform ?? process.platform;
17747
17820
  const version = o.version;
17748
17821
  const idle = { beat: async () => {}, stop: () => {} };
@@ -17883,7 +17956,7 @@ async function machineAnswer(client, tokens) {
17883
17956
  }
17884
17957
  async function fetchOnce(o) {
17885
17958
  const dir = versionDir(o.home, o.version, o.platform);
17886
- const lock = join22(dir, "fetch.lock");
17959
+ const lock = join23(dir, "fetch.lock");
17887
17960
  mkdirSync17(dir, { recursive: true, mode: 493 });
17888
17961
  let fd;
17889
17962
  try {
@@ -17927,7 +18000,7 @@ var realPidAlive = (pid) => {
17927
18000
  }
17928
18001
  };
17929
18002
  function engineUpdater(o) {
17930
- const home = o.home ?? homedir6();
18003
+ const home = o.home ?? homedir7();
17931
18004
  const platform = o.platform ?? process.platform;
17932
18005
  const version = o.version;
17933
18006
  if (!version || !VERSION_RE3.test(version))
@@ -18166,10 +18239,11 @@ var VALUE_FLAGS = [
18166
18239
  "hold-cpu",
18167
18240
  "hold-load",
18168
18241
  "hold-pressure",
18169
- "hold"
18242
+ "hold",
18243
+ "lent-by"
18170
18244
  ];
18171
18245
  var BOOL_FLAGS = ["once", "strict-mcp", "no-strict-mcp", "sandbox", "no-sandbox"];
18172
- var ENGINE_USAGE = "usage: sleds engine [--name <n>] [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir[:dir…]>] [--jira <EPIC>] [--mode <permission-mode>] [--model <id>] [--decider-model <id>] [--effort <e>] [--decider-effort <e>] [--drafter-model <id>] [--drafter-effort <e>] [--branch '<template>'] [--pr-title '<template>'] [--events <file>] [--org <slug>] [--strict-mcp [--mcp-allow <a,b>] | --no-strict-mcp] [--sandbox [--sandbox-allow <a,b>] | --no-sandbox] [--hold-cpu <%>] [--hold-load <per-core>] [--hold-pressure warn|critical] [--hold on|off] [--once]";
18246
+ var ENGINE_USAGE = "usage: sleds engine [--name <n>] [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir[:dir…]>] [--jira <EPIC>] [--mode <permission-mode>] [--model <id>] [--decider-model <id>] [--effort <e>] [--decider-effort <e>] [--drafter-model <id>] [--drafter-effort <e>] [--branch '<template>'] [--pr-title '<template>'] [--events <file>] [--org <slug>] [--strict-mcp [--mcp-allow <a,b>] | --no-strict-mcp] [--sandbox [--sandbox-allow <a,b>] | --no-sandbox] [--lent-by <lender> --sandbox] [--hold-cpu <%>] [--hold-load <per-core>] [--hold-pressure warn|critical] [--hold on|off] [--once]";
18173
18247
  function templateProblem(flag, template, jira = false) {
18174
18248
  const known = flag === "branch" ? BRANCH_FIELDS : PR_TITLE_FIELDS;
18175
18249
  const used = templateFields(template);
@@ -18267,6 +18341,9 @@ function parseEngineArgs(argv, host) {
18267
18341
  return {
18268
18342
  error: `--sandbox-allow takes hosts like pypi.org or *.example.com — no scheme, port or path (got ${badHost})`
18269
18343
  };
18344
+ const lentBy = s("lent-by")?.trim();
18345
+ if (lentBy && !raw.sandbox)
18346
+ return { error: LENT_NEEDS_SANDBOX };
18270
18347
  const opt = (k, v) => v ? { [k]: v } : {};
18271
18348
  return {
18272
18349
  flags: {
@@ -18297,6 +18374,7 @@ function parseEngineArgs(argv, host) {
18297
18374
  ...mcpAllow.length ? { mcpAllow } : {},
18298
18375
  ...raw.sandbox ? { sandbox: true } : raw["no-sandbox"] ? { sandbox: false } : {},
18299
18376
  ...sandboxAllow.length ? { sandboxAllow: [...new Set(sandboxAllow)] } : {},
18377
+ ...opt("lentBy", lentBy),
18300
18378
  ...holdCpu !== undefined ? { holdCpu } : {},
18301
18379
  ...holdLoad !== undefined ? { holdLoad } : {},
18302
18380
  ...holdPressure ? { holdPressure } : {},
@@ -18385,7 +18463,7 @@ function flagsFromProfile(flags, given, profile, home) {
18385
18463
  }
18386
18464
  }
18387
18465
  if (profile.reposDir && !has("repos-dir") && !has("repo")) {
18388
- out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join23(home, d.slice(1)) : d).join(":");
18466
+ out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join24(home, d.slice(1)) : d).join(":");
18389
18467
  used.push(`repos ${profile.reposDir}`);
18390
18468
  }
18391
18469
  if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
@@ -18479,7 +18557,7 @@ function engineClient(o, org) {
18479
18557
  return fetchClient({
18480
18558
  ...src,
18481
18559
  timeoutMs: ENGINE_TIMEOUT_MS,
18482
- version: "0.1.48"
18560
+ version: "0.1.50"
18483
18561
  });
18484
18562
  const asked = org?.trim() || env.SLEDS_ORG?.trim();
18485
18563
  if (asked && !selectOrg(readConfig(o.home), org, env).seat)
@@ -18519,12 +18597,12 @@ function memberMcpConfigs(o, cwd) {
18519
18597
  });
18520
18598
  const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
18521
18599
  return [
18522
- read(claudeDir ? join23(claudeDir, ".claude.json") : join23(o.home, ".claude.json")),
18523
- ...cwd ? [read(join23(cwd, ".mcp.json"))] : []
18600
+ read(claudeDir ? join24(claudeDir, ".claude.json") : join24(o.home, ".claude.json")),
18601
+ ...cwd ? [read(join24(cwd, ".mcp.json"))] : []
18524
18602
  ];
18525
18603
  }
18526
18604
  function engineStateDir(o, org, seat) {
18527
- return seatStateDir(orgStateDir(o.stateDir ?? join23(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
18605
+ return seatStateDir(orgStateDir(o.stateDir ?? join24(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
18528
18606
  }
18529
18607
  function engineSeat(o, org) {
18530
18608
  try {
@@ -18554,8 +18632,8 @@ function engineDeps(o, flags, source, runner, stateName) {
18554
18632
  const repo = flags.repo ? resolve8(cwd, flags.repo) : undefined;
18555
18633
  const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve8(cwd, d));
18556
18634
  const { branch, prTitle } = flags;
18557
- const hooksDir = join23(stateDir, "hooks");
18558
- const permissionMark = (name) => join23(hooksDir, `${name}.permission.json`);
18635
+ const hooksDir = join24(stateDir, "hooks");
18636
+ const permissionMark = (name) => join24(hooksDir, `${name}.permission.json`);
18559
18637
  const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
18560
18638
  return {
18561
18639
  source,
@@ -18580,9 +18658,9 @@ function engineDeps(o, flags, source, runner, stateName) {
18580
18658
  sandbox: true,
18581
18659
  writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
18582
18660
  const gitCommonDir = gitCommonDirOf(exec, cwd);
18583
- const dir = join23(stateDir, "sandbox");
18661
+ const dir = join24(stateDir, "sandbox");
18584
18662
  mkdirSync18(dir, { recursive: true, mode: 448 });
18585
- const p = join23(dir, `${name}.json`);
18663
+ const p = join24(dir, `${name}.json`);
18586
18664
  const walls = engineSandboxSettings(o.home, o.env ?? process.env, gitCommonDir, [
18587
18665
  ...SANDBOX_DEFAULT_ALLOW,
18588
18666
  ...flags.sandboxAllow ?? []
@@ -18599,7 +18677,7 @@ function engineDeps(o, flags, source, runner, stateName) {
18599
18677
  } : {},
18600
18678
  writeHookSettings: (name, allow) => {
18601
18679
  mkdirSync18(hooksDir, { recursive: true, mode: 448 });
18602
- const p = join23(hooksDir, `${name}.json`);
18680
+ const p = join24(hooksDir, `${name}.json`);
18603
18681
  const base = allow?.length ? { permissions: { allow: [...allow] } } : {};
18604
18682
  writeFileSync16(p, `${JSON.stringify(withHook(name, base), null, 2)}
18605
18683
  `, { mode: 384 });
@@ -18627,9 +18705,9 @@ function engineDeps(o, flags, source, runner, stateName) {
18627
18705
  exists
18628
18706
  }),
18629
18707
  writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
18630
- const dir = join23(stateDir, "mcp");
18708
+ const dir = join24(stateDir, "mcp");
18631
18709
  mkdirSync18(dir, { recursive: true, mode: 448 });
18632
- const p = join23(dir, `${name}.json`);
18710
+ const p = join24(dir, `${name}.json`);
18633
18711
  let others = {};
18634
18712
  if (flags.strictMcp && flags.mcpAllow?.length) {
18635
18713
  const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs(o, worktree));
@@ -18645,9 +18723,9 @@ function engineDeps(o, flags, source, runner, stateName) {
18645
18723
  }),
18646
18724
  removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync10(p, { force: true })),
18647
18725
  writePrompt: o.writePrompt ?? ((name, text) => {
18648
- const dir = join23(stateDir, "prompts");
18726
+ const dir = join24(stateDir, "prompts");
18649
18727
  mkdirSync18(dir, { recursive: true, mode: 448 });
18650
- const p = join23(dir, `${name}.md`);
18728
+ const p = join24(dir, `${name}.md`);
18651
18729
  writeFileSync16(p, text, { mode: 384 });
18652
18730
  return p;
18653
18731
  }),
@@ -18674,14 +18752,14 @@ function engineDeps(o, flags, source, runner, stateName) {
18674
18752
  }
18675
18753
  function sandboxDenyRead(home, env) {
18676
18754
  return {
18677
- dirs: [...new Set([configDir(home, env), join23(home, ".config", "sleds")])],
18755
+ dirs: [...new Set([configDir(home, env), join24(home, ".config", "sleds")])],
18678
18756
  files: [
18679
18757
  ...new Set([
18680
18758
  tokenPath(home, env),
18681
- join23(home, ".sleds-token"),
18759
+ join24(home, ".sleds-token"),
18682
18760
  settingsPath(home, env),
18683
18761
  backupPath(home, env),
18684
- join23(claudeDir(home, env), "settings.local.json")
18762
+ join24(claudeDir(home, env), "settings.local.json")
18685
18763
  ])
18686
18764
  ]
18687
18765
  };
@@ -18700,6 +18778,36 @@ function gitCommonDirOf(exec, cwd) {
18700
18778
  throw new Error(`git has no common dir for ${cwd}, so the sandbox has nowhere to commit`);
18701
18779
  return resolve8(cwd, dir);
18702
18780
  }
18781
+ var LENT_NEEDS_SANDBOX = "a lent engine runs every session sandboxed (spec 48 rule 10) — add --sandbox to --lent-by";
18782
+ function lenderHome(accountHome, lentBy) {
18783
+ return isAbsolute3(lentBy) ? resolve8(lentBy) : join24(dirname15(accountHome), lentBy);
18784
+ }
18785
+ function lentHomeProblems(accountHome, lentBy, modeOf) {
18786
+ const lender = lenderHome(accountHome, lentBy);
18787
+ if (lender === resolve8(accountHome))
18788
+ return [
18789
+ `--lent-by ${lentBy} is this account — a lent engine runs as the borrower's own OS user, not the lender's`
18790
+ ];
18791
+ const problems = [];
18792
+ for (const [who, home] of [
18793
+ ["the borrower's", resolve8(accountHome)],
18794
+ ["the lender's", lender]
18795
+ ]) {
18796
+ const mode = modeOf(home);
18797
+ if (mode === null)
18798
+ problems.push(`${who} home ${home} cannot be read — is ${lentBy} right?`);
18799
+ else if ((mode & 63) !== 0)
18800
+ problems.push(`${who} home ${home} is ${(mode & 511).toString(8)}, open to other users — run: sudo chmod 700 ${home}`);
18801
+ }
18802
+ return problems;
18803
+ }
18804
+ var homeMode = (path) => {
18805
+ try {
18806
+ return statSync5(path).mode & 4095;
18807
+ } catch {
18808
+ return null;
18809
+ }
18810
+ };
18703
18811
  function pinOrg2(configJson, org) {
18704
18812
  if (!org)
18705
18813
  return configJson;
@@ -18740,7 +18848,7 @@ async function driveEngine(o, flags, deps, until = {}) {
18740
18848
  runner: deps.runner.name,
18741
18849
  atOnce: flags.atOnce,
18742
18850
  interval: flags.interval,
18743
- cliVersion: "0.1.48"
18851
+ cliVersion: "0.1.50"
18744
18852
  };
18745
18853
  const beat = (checkedAt) => {
18746
18854
  const m = deps.machine;
@@ -18818,6 +18926,7 @@ async function drive(o, flags, deps, until, beat) {
18818
18926
  deps.log = (line) => event(noteEvent(line));
18819
18927
  let running = 0;
18820
18928
  let down = 0;
18929
+ await until.beforeFirstTick?.();
18821
18930
  for (;; ) {
18822
18931
  let report = null;
18823
18932
  try {
@@ -19085,7 +19194,7 @@ import {
19085
19194
  writeFileSync as writeFileSync17
19086
19195
  } from "node:fs";
19087
19196
  import { hostname as hostname3 } from "node:os";
19088
- import { basename as basename6, dirname as dirname15, isAbsolute as isAbsolute3, join as join24 } from "node:path";
19197
+ import { basename as basename6, dirname as dirname16, isAbsolute as isAbsolute4, join as join25 } from "node:path";
19089
19198
  init_state();
19090
19199
  var ENGINE_LABEL = "ai.sleds.engine";
19091
19200
  var ENGINE_INSTALL_USAGE = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
@@ -19093,7 +19202,7 @@ ${ENGINE_USAGE}`;
19093
19202
  function stableArgv(argv, realpath = realpathSync, home) {
19094
19203
  const link = sledsLink(home);
19095
19204
  return argv.map((a) => {
19096
- if (!isAbsolute3(a) || a === link)
19205
+ if (!isAbsolute4(a) || a === link)
19097
19206
  return a;
19098
19207
  try {
19099
19208
  return realpath(a);
@@ -19106,13 +19215,13 @@ function engineLabel(name, org, seat) {
19106
19215
  return [ENGINE_LABEL, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
19107
19216
  }
19108
19217
  function enginePlistPath(home, name, org, seat) {
19109
- return join24(home, "Library", "LaunchAgents", `${engineLabel(name, org, seat)}.plist`);
19218
+ return join25(home, "Library", "LaunchAgents", `${engineLabel(name, org, seat)}.plist`);
19110
19219
  }
19111
19220
  function engineLogPath(stateDir, name) {
19112
- return join24(stateDir, `${engineSlug(name)}.log`);
19221
+ return join25(stateDir, `${engineSlug(name)}.log`);
19113
19222
  }
19114
19223
  function engineEventsPath(stateDir, name) {
19115
- return join24(stateDir, `${engineSlug(name)}.events.jsonl`);
19224
+ return join25(stateDir, `${engineSlug(name)}.events.jsonl`);
19116
19225
  }
19117
19226
  var xmlEscape4 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19118
19227
  function buildEnginePlist(o) {
@@ -19209,7 +19318,7 @@ function readEngines(dir, suffix, manager, parse) {
19209
19318
  }
19210
19319
  const out = [];
19211
19320
  for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL}.`) && n.endsWith(suffix))) {
19212
- const path = join24(dir, name);
19321
+ const path = join25(dir, name);
19213
19322
  let parsed;
19214
19323
  try {
19215
19324
  parsed = parse(readFileSync16(path, "utf8"), name);
@@ -19229,7 +19338,7 @@ function readEngines(dir, suffix, manager, parse) {
19229
19338
  }
19230
19339
  function installedEngines(home) {
19231
19340
  return [
19232
- ...readEngines(join24(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
19341
+ ...readEngines(join25(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
19233
19342
  ...readEngines(engineUnitDir(home), ".service", "systemd", (text, file) => {
19234
19343
  const parsed = parseEngineUnit(text);
19235
19344
  return parsed && { label: basename6(file, ".service"), ...parsed };
@@ -19279,7 +19388,7 @@ function engineInstall(o) {
19279
19388
  if (platform === "linux")
19280
19389
  return installUnit({ o, parsed, label, sledsArgv, env: agentEnv, logPath, exec });
19281
19390
  const plist = enginePlistPath(o.home, parsed.name, parsed.org, seat);
19282
- mkdirSync19(dirname15(plist), { recursive: true });
19391
+ mkdirSync19(dirname16(plist), { recursive: true });
19283
19392
  if (existsSync19(plist))
19284
19393
  exec("launchctl", ["unload", plist]);
19285
19394
  for (const other of installedEngines(o.home)) {
@@ -19321,7 +19430,7 @@ function installUnit(a) {
19321
19430
  const unit = engineUnitPath(o.home, label);
19322
19431
  const unitName = basename6(unit);
19323
19432
  const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
19324
- mkdirSync19(dirname15(unit), { recursive: true });
19433
+ mkdirSync19(dirname16(unit), { recursive: true });
19325
19434
  if (existsSync19(unit))
19326
19435
  systemctl("stop", unitName);
19327
19436
  for (const other of installedEngines(o.home)) {
@@ -19697,7 +19806,7 @@ async function runDoctor(o) {
19697
19806
  checks.push({ level: "ok", name: "path", detail: which[0] ?? "" });
19698
19807
  const link = sledsLink(home, o.platform);
19699
19808
  if (existsSync21(link)) {
19700
- const binDir = dirname16(link);
19809
+ const binDir = dirname17(link);
19701
19810
  const onPath = (env.PATH ?? "").split(delimiter3).includes(binDir);
19702
19811
  const first = which[0];
19703
19812
  const fix = `echo 'export PATH="${binDir}:$PATH"' >> ~/.zshrc`;
@@ -19886,12 +19995,12 @@ function sandboxChecks(o, env) {
19886
19995
  }
19887
19996
  ];
19888
19997
  const nonce = o.nonce ?? `sleds-probe-${randomBytes(16).toString("hex")}`;
19889
- const probe = join25(dir, SANDBOX_PROBE);
19890
- const work = mkdtempSync(join25(tmpdir(), "sleds-sandbox-"));
19998
+ const probe = join26(dir, SANDBOX_PROBE);
19999
+ const work = mkdtempSync(join26(tmpdir(), "sleds-sandbox-"));
19891
20000
  try {
19892
20001
  writeFileSync19(probe, `${nonce}
19893
20002
  `, { mode: 384 });
19894
- const settingsFile = join25(work, "settings.json");
20003
+ const settingsFile = join26(work, "settings.json");
19895
20004
  const settings = engineSandboxSettings(o.home, env, work, SANDBOX_DEFAULT_ALLOW);
19896
20005
  const claudeSettings = settingsPath(o.home, env);
19897
20006
  writeFileSync19(settingsFile, JSON.stringify(settings, null, 2), { mode: 384 });
@@ -19935,6 +20044,8 @@ function engineChecks(o, env) {
19935
20044
  const org = engineOrg({ home: o.home, env }).slug;
19936
20045
  const engines = installedEngines(o.home).filter((e) => e.manager === manager && (e.org === null || !org || e.org === org));
19937
20046
  const need = engines.length > 0 ? "fail" : "warn";
20047
+ if (o.lentBy && !engines.some((e) => engineArg(e.programArgs, "lent-by")))
20048
+ checks.push(...lentChecks(o, o.lentBy, null));
19938
20049
  const runner = engines.map((e) => engineArg(e.programArgs, "runner")).find(Boolean) ?? "tmux";
19939
20050
  const gh = which("gh");
19940
20051
  if (!gh)
@@ -20034,18 +20145,45 @@ function engineChecks(o, env) {
20034
20145
  detail: `${e.label} names no --repos-dir — it works only if your engine profile sets Repos folders`,
20035
20146
  fix: "set Repos folders in Settings › Running work, or sleds engine install --repos-dir ~/code"
20036
20147
  });
20148
+ const lentBy = engineArg(e.programArgs, "lent-by");
20149
+ if (lentBy)
20150
+ checks.push(...lentChecks(o, lentBy, e));
20037
20151
  }
20038
20152
  return checks;
20039
20153
  }
20154
+ function lentChecks(o, lentBy, engine) {
20155
+ const checks = [];
20156
+ const problems = lentHomeProblems((o.accountHome ?? (() => userInfo2().homedir))(), lentBy, o.homeMode ?? homeMode);
20157
+ checks.push(problems.length === 0 ? { level: "ok", name: "lent homes", detail: `lent by ${lentBy} · both homes 700` } : {
20158
+ level: "fail",
20159
+ name: "lent homes",
20160
+ detail: problems.join("; "),
20161
+ fix: "sudo chmod 700 on each home named (the lender runs it for theirs)"
20162
+ });
20163
+ if (engine)
20164
+ checks.push(engine.programArgs.includes("--sandbox") ? { level: "ok", name: "lent sandbox", detail: `${engine.label} runs --sandbox` } : {
20165
+ level: "fail",
20166
+ name: "lent sandbox",
20167
+ detail: `${engine.label}: ${LENT_NEEDS_SANDBOX}`,
20168
+ fix: `sleds engine install --lent-by ${lentBy} --sandbox`
20169
+ });
20170
+ return checks;
20171
+ }
20040
20172
  function boxChecks(o, env, which, need) {
20041
20173
  const claude = which("claude");
20042
20174
  const file = boxEnvPath(o.home);
20043
- let named = false;
20175
+ let boxEnvText = null;
20044
20176
  try {
20045
- named = /^\s*(?:export\s+)?ANTHROPIC_API_KEY\s*=\s*\S/m.test(readFileSync19(file, "utf8"));
20177
+ boxEnvText = readFileSync19(file, "utf8");
20046
20178
  } catch {
20047
- named = false;
20179
+ boxEnvText = null;
20048
20180
  }
20181
+ const cred = detectCredential(env, {
20182
+ home: o.home,
20183
+ boxEnvText,
20184
+ boxEnvPath: file,
20185
+ exists: o.exists ?? existsSync21
20186
+ });
20049
20187
  return [
20050
20188
  claude ? { level: "ok", name: "claude cli", detail: `${claude} · the headless runner's agent` } : {
20051
20189
  level: need,
@@ -20053,14 +20191,20 @@ function boxChecks(o, env, which, need) {
20053
20191
  detail: "`claude` not on PATH — the headless runner starts Claude Code for each node",
20054
20192
  fix: "npm install -g @anthropic-ai/claude-code"
20055
20193
  },
20056
- env.ANTHROPIC_API_KEY?.trim() ? { level: "ok", name: "api key", detail: "ANTHROPIC_API_KEY set in this shell" } : named ? { level: "ok", name: "api key", detail: `ANTHROPIC_API_KEY named in ${file}` } : {
20194
+ cred ? { level: "ok", name: "credential", detail: credentialDetail(cred) } : {
20057
20195
  level: need,
20058
- name: "api key",
20059
- detail: `ANTHROPIC_API_KEY is not set here or in ${file} — a headless session cannot sign in`,
20060
- fix: `add ANTHROPIC_API_KEY=… to ${file} (the engine's unit reads it at start)`
20196
+ name: "credential",
20197
+ detail: `no ${API_KEY_VAR}, ${SEAT_TOKEN_VAR} or claude login here or in ${file} — a headless session cannot sign in`,
20198
+ fix: `add ${API_KEY_VAR}=… (a key) or ${SEAT_TOKEN_VAR}=… (a seat, from \`claude setup-token\`) to ${file}, or sign in once with \`claude\` and /login`
20061
20199
  }
20062
20200
  ];
20063
20201
  }
20202
+ function credentialDetail(c) {
20203
+ if (c.source === "login")
20204
+ return `seat · claude login at ${c.where}`;
20205
+ const name = c.source === "api_key" ? API_KEY_VAR : SEAT_TOKEN_VAR;
20206
+ return `${c.kind} · ${name} ${c.where === "this shell" ? "set in this shell" : `named in ${c.where}`}`;
20207
+ }
20064
20208
  function cmuxCheck(o, env) {
20065
20209
  const exec = o.exec ?? defaultExec3;
20066
20210
  const bin = resolveCmuxBin(o.exists ?? existsSync21, env.PATH ?? "");
@@ -20151,10 +20295,11 @@ import {
20151
20295
  readFileSync as readFileSync20,
20152
20296
  existsSync as realExists2,
20153
20297
  rmSync as rmSync14,
20298
+ statSync as statSync6,
20154
20299
  writeFileSync as writeFileSync20
20155
20300
  } from "node:fs";
20156
- import { hostname as hostname4 } from "node:os";
20157
- import { join as join26, resolve as resolve10 } from "node:path";
20301
+ import { hostname as hostname4, userInfo as userInfo3 } from "node:os";
20302
+ import { dirname as dirname18, isAbsolute as isAbsolute5, join as join27, resolve as resolve10 } from "node:path";
20158
20303
  init_machine();
20159
20304
  init_state();
20160
20305
  init_meter();
@@ -20190,10 +20335,11 @@ var VALUE_FLAGS2 = [
20190
20335
  "hold-cpu",
20191
20336
  "hold-load",
20192
20337
  "hold-pressure",
20193
- "hold"
20338
+ "hold",
20339
+ "lent-by"
20194
20340
  ];
20195
20341
  var BOOL_FLAGS2 = ["once", "strict-mcp", "no-strict-mcp", "sandbox", "no-sandbox"];
20196
- var ENGINE_USAGE2 = "usage: sleds engine [--name <n>] [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir[:dir…]>] [--jira <EPIC>] [--mode <permission-mode>] [--model <id>] [--decider-model <id>] [--effort <e>] [--decider-effort <e>] [--drafter-model <id>] [--drafter-effort <e>] [--branch '<template>'] [--pr-title '<template>'] [--events <file>] [--org <slug>] [--strict-mcp [--mcp-allow <a,b>] | --no-strict-mcp] [--sandbox [--sandbox-allow <a,b>] | --no-sandbox] [--hold-cpu <%>] [--hold-load <per-core>] [--hold-pressure warn|critical] [--hold on|off] [--once]";
20342
+ var ENGINE_USAGE2 = "usage: sleds engine [--name <n>] [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir[:dir…]>] [--jira <EPIC>] [--mode <permission-mode>] [--model <id>] [--decider-model <id>] [--effort <e>] [--decider-effort <e>] [--drafter-model <id>] [--drafter-effort <e>] [--branch '<template>'] [--pr-title '<template>'] [--events <file>] [--org <slug>] [--strict-mcp [--mcp-allow <a,b>] | --no-strict-mcp] [--sandbox [--sandbox-allow <a,b>] | --no-sandbox] [--lent-by <lender> --sandbox] [--hold-cpu <%>] [--hold-load <per-core>] [--hold-pressure warn|critical] [--hold on|off] [--once]";
20197
20343
  function templateProblem2(flag, template, jira = false) {
20198
20344
  const known = flag === "branch" ? BRANCH_FIELDS : PR_TITLE_FIELDS;
20199
20345
  const used = templateFields(template);
@@ -20291,6 +20437,9 @@ function parseEngineArgs2(argv, host) {
20291
20437
  return {
20292
20438
  error: `--sandbox-allow takes hosts like pypi.org or *.example.com — no scheme, port or path (got ${badHost})`
20293
20439
  };
20440
+ const lentBy = s("lent-by")?.trim();
20441
+ if (lentBy && !raw.sandbox)
20442
+ return { error: LENT_NEEDS_SANDBOX2 };
20294
20443
  const opt = (k, v) => v ? { [k]: v } : {};
20295
20444
  return {
20296
20445
  flags: {
@@ -20321,6 +20470,7 @@ function parseEngineArgs2(argv, host) {
20321
20470
  ...mcpAllow.length ? { mcpAllow } : {},
20322
20471
  ...raw.sandbox ? { sandbox: true } : raw["no-sandbox"] ? { sandbox: false } : {},
20323
20472
  ...sandboxAllow.length ? { sandboxAllow: [...new Set(sandboxAllow)] } : {},
20473
+ ...opt("lentBy", lentBy),
20324
20474
  ...holdCpu !== undefined ? { holdCpu } : {},
20325
20475
  ...holdLoad !== undefined ? { holdLoad } : {},
20326
20476
  ...holdPressure ? { holdPressure } : {},
@@ -20409,7 +20559,7 @@ function flagsFromProfile2(flags, given, profile, home) {
20409
20559
  }
20410
20560
  }
20411
20561
  if (profile.reposDir && !has("repos-dir") && !has("repo")) {
20412
- out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join26(home, d.slice(1)) : d).join(":");
20562
+ out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join27(home, d.slice(1)) : d).join(":");
20413
20563
  used.push(`repos ${profile.reposDir}`);
20414
20564
  }
20415
20565
  if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
@@ -20555,7 +20705,7 @@ function engineClient2(o, org) {
20555
20705
  return fetchClient({
20556
20706
  ...src,
20557
20707
  timeoutMs: ENGINE_TIMEOUT_MS2,
20558
- version: "0.1.48"
20708
+ version: "0.1.50"
20559
20709
  });
20560
20710
  const asked = org?.trim() || env.SLEDS_ORG?.trim();
20561
20711
  if (asked && !selectOrg(readConfig(o.home), org, env).seat)
@@ -20604,12 +20754,12 @@ function memberMcpConfigs2(o, cwd) {
20604
20754
  });
20605
20755
  const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
20606
20756
  return [
20607
- read(claudeDir ? join26(claudeDir, ".claude.json") : join26(o.home, ".claude.json")),
20608
- ...cwd ? [read(join26(cwd, ".mcp.json"))] : []
20757
+ read(claudeDir ? join27(claudeDir, ".claude.json") : join27(o.home, ".claude.json")),
20758
+ ...cwd ? [read(join27(cwd, ".mcp.json"))] : []
20609
20759
  ];
20610
20760
  }
20611
20761
  function engineStateDir2(o, org, seat) {
20612
- return seatStateDir(orgStateDir(o.stateDir ?? join26(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
20762
+ return seatStateDir(orgStateDir(o.stateDir ?? join27(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
20613
20763
  }
20614
20764
  function engineSeat2(o, org) {
20615
20765
  try {
@@ -20628,6 +20778,19 @@ function engineToken2(o, org) {
20628
20778
  }
20629
20779
  }
20630
20780
  var withToken2 = (token, now) => token ? { token, tokenNow: now } : {};
20781
+ function engineCredential(o) {
20782
+ const file = boxEnvPath(o.home);
20783
+ let boxEnvText = null;
20784
+ try {
20785
+ boxEnvText = readFileSync20(file, "utf8");
20786
+ } catch {}
20787
+ return detectCredential(o.env ?? process.env, {
20788
+ home: o.home,
20789
+ boxEnvText,
20790
+ boxEnvPath: file,
20791
+ exists: o.exists ?? realExists2
20792
+ })?.kind;
20793
+ }
20631
20794
  function engineDeps2(o, flags, source, runner, stateName) {
20632
20795
  const exec = guardGit(o.exec ?? defaultExec);
20633
20796
  const cwd = o.cwd ?? process.cwd();
@@ -20639,8 +20802,8 @@ function engineDeps2(o, flags, source, runner, stateName) {
20639
20802
  const repo = flags.repo ? resolve10(cwd, flags.repo) : undefined;
20640
20803
  const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve10(cwd, d));
20641
20804
  const { branch, prTitle } = flags;
20642
- const hooksDir = join26(stateDir, "hooks");
20643
- const permissionMark = (name) => join26(hooksDir, `${name}.permission.json`);
20805
+ const hooksDir = join27(stateDir, "hooks");
20806
+ const permissionMark = (name) => join27(hooksDir, `${name}.permission.json`);
20644
20807
  const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
20645
20808
  return {
20646
20809
  source,
@@ -20665,9 +20828,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
20665
20828
  sandbox: true,
20666
20829
  writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
20667
20830
  const gitCommonDir = gitCommonDirOf2(exec, cwd);
20668
- const dir = join26(stateDir, "sandbox");
20831
+ const dir = join27(stateDir, "sandbox");
20669
20832
  mkdirSync21(dir, { recursive: true, mode: 448 });
20670
- const p = join26(dir, `${name}.json`);
20833
+ const p = join27(dir, `${name}.json`);
20671
20834
  const walls = engineSandboxSettings2(o.home, o.env ?? process.env, gitCommonDir, [
20672
20835
  ...SANDBOX_DEFAULT_ALLOW,
20673
20836
  ...flags.sandboxAllow ?? []
@@ -20684,7 +20847,7 @@ function engineDeps2(o, flags, source, runner, stateName) {
20684
20847
  } : {},
20685
20848
  writeHookSettings: (name, allow) => {
20686
20849
  mkdirSync21(hooksDir, { recursive: true, mode: 448 });
20687
- const p = join26(hooksDir, `${name}.json`);
20850
+ const p = join27(hooksDir, `${name}.json`);
20688
20851
  const base = allow?.length ? { permissions: { allow: [...allow] } } : {};
20689
20852
  writeFileSync20(p, `${JSON.stringify(withHook(name, base), null, 2)}
20690
20853
  `, { mode: 384 });
@@ -20712,9 +20875,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
20712
20875
  exists
20713
20876
  }),
20714
20877
  writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
20715
- const dir = join26(stateDir, "mcp");
20878
+ const dir = join27(stateDir, "mcp");
20716
20879
  mkdirSync21(dir, { recursive: true, mode: 448 });
20717
- const p = join26(dir, `${name}.json`);
20880
+ const p = join27(dir, `${name}.json`);
20718
20881
  let others = {};
20719
20882
  if (flags.strictMcp && flags.mcpAllow?.length) {
20720
20883
  const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs2(o, worktree));
@@ -20730,9 +20893,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
20730
20893
  }),
20731
20894
  removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync14(p, { force: true })),
20732
20895
  writePrompt: o.writePrompt ?? ((name, text) => {
20733
- const dir = join26(stateDir, "prompts");
20896
+ const dir = join27(stateDir, "prompts");
20734
20897
  mkdirSync21(dir, { recursive: true, mode: 448 });
20735
- const p = join26(dir, `${name}.md`);
20898
+ const p = join27(dir, `${name}.md`);
20736
20899
  writeFileSync20(p, text, { mode: 384 });
20737
20900
  return p;
20738
20901
  }),
@@ -20759,14 +20922,14 @@ function engineDeps2(o, flags, source, runner, stateName) {
20759
20922
  }
20760
20923
  function sandboxDenyRead2(home, env) {
20761
20924
  return {
20762
- dirs: [...new Set([configDir(home, env), join26(home, ".config", "sleds")])],
20925
+ dirs: [...new Set([configDir(home, env), join27(home, ".config", "sleds")])],
20763
20926
  files: [
20764
20927
  ...new Set([
20765
20928
  tokenPath(home, env),
20766
- join26(home, ".sleds-token"),
20929
+ join27(home, ".sleds-token"),
20767
20930
  settingsPath(home, env),
20768
20931
  backupPath(home, env),
20769
- join26(claudeDir(home, env), "settings.local.json")
20932
+ join27(claudeDir(home, env), "settings.local.json")
20770
20933
  ])
20771
20934
  ]
20772
20935
  };
@@ -20786,6 +20949,8 @@ function gitCommonDirOf2(exec, cwd) {
20786
20949
  return resolve10(cwd, dir);
20787
20950
  }
20788
20951
  function sandboxRefusal(flags) {
20952
+ if (flags.lentBy && !flags.sandbox)
20953
+ return LENT_NEEDS_SANDBOX2;
20789
20954
  if (!flags.sandbox)
20790
20955
  return null;
20791
20956
  if (flags.runner === "conductor")
@@ -20796,6 +20961,36 @@ function sandboxRefusal(flags) {
20796
20961
  return "sandboxed sessions: Codex's sandbox walls writes, not reads — the seat token stays readable; use Claude Code, or --no-sandbox";
20797
20962
  return null;
20798
20963
  }
20964
+ var LENT_NEEDS_SANDBOX2 = "a lent engine runs every session sandboxed (spec 48 rule 10) — add --sandbox to --lent-by";
20965
+ function lenderHome2(accountHome, lentBy) {
20966
+ return isAbsolute5(lentBy) ? resolve10(lentBy) : join27(dirname18(accountHome), lentBy);
20967
+ }
20968
+ function lentHomeProblems2(accountHome, lentBy, modeOf) {
20969
+ const lender = lenderHome2(accountHome, lentBy);
20970
+ if (lender === resolve10(accountHome))
20971
+ return [
20972
+ `--lent-by ${lentBy} is this account — a lent engine runs as the borrower's own OS user, not the lender's`
20973
+ ];
20974
+ const problems = [];
20975
+ for (const [who, home] of [
20976
+ ["the borrower's", resolve10(accountHome)],
20977
+ ["the lender's", lender]
20978
+ ]) {
20979
+ const mode = modeOf(home);
20980
+ if (mode === null)
20981
+ problems.push(`${who} home ${home} cannot be read — is ${lentBy} right?`);
20982
+ else if ((mode & 63) !== 0)
20983
+ problems.push(`${who} home ${home} is ${(mode & 511).toString(8)}, open to other users — run: sudo chmod 700 ${home}`);
20984
+ }
20985
+ return problems;
20986
+ }
20987
+ var homeMode2 = (path) => {
20988
+ try {
20989
+ return statSync6(path).mode & 4095;
20990
+ } catch {
20991
+ return null;
20992
+ }
20993
+ };
20799
20994
  function pinOrg3(configJson, org) {
20800
20995
  if (!org)
20801
20996
  return configJson;
@@ -20836,7 +21031,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
20836
21031
  runner: deps.runner.name,
20837
21032
  atOnce: flags.atOnce,
20838
21033
  interval: flags.interval,
20839
- cliVersion: "0.1.48"
21034
+ cliVersion: "0.1.50"
20840
21035
  };
20841
21036
  const beat = (checkedAt) => {
20842
21037
  const m = deps.machine;
@@ -20914,6 +21109,7 @@ async function drive2(o, flags, deps, until, beat) {
20914
21109
  deps.log = (line) => event(noteEvent(line));
20915
21110
  let running = 0;
20916
21111
  let down = 0;
21112
+ await until.beforeFirstTick?.();
20917
21113
  for (;; ) {
20918
21114
  let report = null;
20919
21115
  try {
@@ -21095,6 +21291,14 @@ var engineCmd = async (o) => {
21095
21291
  error(refusal);
21096
21292
  return 2;
21097
21293
  }
21294
+ if (flags.lentBy) {
21295
+ const open = lentHomeProblems2((o.accountHome ?? (() => userInfo3().homedir))(), flags.lentBy, o.homeMode ?? homeMode2);
21296
+ if (open.length) {
21297
+ for (const line of open)
21298
+ error(`lent engine: ${line}`);
21299
+ return 2;
21300
+ }
21301
+ }
21098
21302
  if (flags.sandbox && flags.runner === "managed")
21099
21303
  notes.push("sandboxed sessions: the managed runner's container is its own sandbox — the engine's settings do not reach it");
21100
21304
  let source;
@@ -21186,6 +21390,7 @@ var engineCmd = async (o) => {
21186
21390
  watch.beat();
21187
21391
  return update();
21188
21392
  };
21393
+ let beforeFirstTick;
21189
21394
  if (client) {
21190
21395
  const send = beater(client, o.now ?? Date.now);
21191
21396
  let noted;
@@ -21204,20 +21409,34 @@ var engineCmd = async (o) => {
21204
21409
  refused = r.refused;
21205
21410
  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.`);
21206
21411
  };
21412
+ const credential = engineCredential(o);
21413
+ const body = () => {
21414
+ const m = deps.machine;
21415
+ return beatBody(deps.readState(), { name: flags.name, runner: deps.runner.name }, credential ? { credential } : {}, {
21416
+ atOnce: deps.atOnce,
21417
+ ...m?.last ? { machine: m.last } : {},
21418
+ ...m?.hold && !m.off ? { hold: m.hold } : {}
21419
+ });
21420
+ };
21421
+ const heard = (r) => {
21422
+ sayRefused(r);
21423
+ if (r.ok) {
21424
+ updater.sawBeat(r.update);
21425
+ noteBeat(r.update);
21426
+ }
21427
+ };
21428
+ beforeFirstTick = async () => {
21429
+ try {
21430
+ heard(await postBeat(client, body()));
21431
+ } catch {}
21432
+ };
21207
21433
  afterTick = async () => {
21208
21434
  try {
21209
- const m = deps.machine;
21210
- send(beatBody(deps.readState(), { name: flags.name, runner: deps.runner.name }, {}, {
21211
- atOnce: deps.atOnce,
21212
- ...m?.last ? { machine: m.last } : {},
21213
- ...m?.hold && !m.off ? { hold: m.hold } : {}
21214
- }))?.then((r) => {
21215
- sayRefused(r);
21216
- if (r?.ok) {
21217
- updater.sawBeat(r.update);
21218
- noteBeat(r.update);
21219
- }
21220
- if (r && (r.ok || ("unreachable" in r)))
21435
+ send(body())?.then((r) => {
21436
+ if (!r)
21437
+ return;
21438
+ heard(r);
21439
+ if (r.ok || "unreachable" in r)
21221
21440
  watch.beat();
21222
21441
  }, () => {});
21223
21442
  } catch {}
@@ -21225,7 +21444,7 @@ var engineCmd = async (o) => {
21225
21444
  };
21226
21445
  }
21227
21446
  try {
21228
- return await driveEngine2(o, flags, deps, { afterTick });
21447
+ return await driveEngine2(o, flags, deps, { afterTick, beforeFirstTick });
21229
21448
  } finally {
21230
21449
  watch.stop();
21231
21450
  }
@@ -21435,7 +21654,7 @@ import {
21435
21654
  writeFileSync as writeFileSync21
21436
21655
  } from "node:fs";
21437
21656
  import { hostname as hostname5 } from "node:os";
21438
- import { basename as basename7, dirname as dirname17, isAbsolute as isAbsolute4, join as join27 } from "node:path";
21657
+ import { basename as basename7, dirname as dirname19, isAbsolute as isAbsolute6, join as join28 } from "node:path";
21439
21658
  init_state();
21440
21659
  var ENGINE_LABEL2 = "ai.sleds.engine";
21441
21660
  var ENGINE_INSTALL_USAGE2 = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
@@ -21443,7 +21662,7 @@ ${ENGINE_USAGE}`;
21443
21662
  function stableArgv2(argv, realpath = realpathSync2, home) {
21444
21663
  const link = sledsLink(home);
21445
21664
  return argv.map((a) => {
21446
- if (!isAbsolute4(a) || a === link)
21665
+ if (!isAbsolute6(a) || a === link)
21447
21666
  return a;
21448
21667
  try {
21449
21668
  return realpath(a);
@@ -21456,13 +21675,13 @@ function engineLabel2(name, org, seat) {
21456
21675
  return [ENGINE_LABEL2, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
21457
21676
  }
21458
21677
  function enginePlistPath2(home, name, org, seat) {
21459
- return join27(home, "Library", "LaunchAgents", `${engineLabel2(name, org, seat)}.plist`);
21678
+ return join28(home, "Library", "LaunchAgents", `${engineLabel2(name, org, seat)}.plist`);
21460
21679
  }
21461
21680
  function engineLogPath2(stateDir, name) {
21462
- return join27(stateDir, `${engineSlug(name)}.log`);
21681
+ return join28(stateDir, `${engineSlug(name)}.log`);
21463
21682
  }
21464
21683
  function engineEventsPath2(stateDir, name) {
21465
- return join27(stateDir, `${engineSlug(name)}.events.jsonl`);
21684
+ return join28(stateDir, `${engineSlug(name)}.events.jsonl`);
21466
21685
  }
21467
21686
  var xmlEscape5 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
21468
21687
  function buildEnginePlist2(o) {
@@ -21559,7 +21778,7 @@ function readEngines2(dir, suffix, manager, parse) {
21559
21778
  }
21560
21779
  const out = [];
21561
21780
  for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL2}.`) && n.endsWith(suffix))) {
21562
- const path = join27(dir, name);
21781
+ const path = join28(dir, name);
21563
21782
  let parsed;
21564
21783
  try {
21565
21784
  parsed = parse(readFileSync21(path, "utf8"), name);
@@ -21579,7 +21798,7 @@ function readEngines2(dir, suffix, manager, parse) {
21579
21798
  }
21580
21799
  function installedEngines2(home) {
21581
21800
  return [
21582
- ...readEngines2(join27(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
21801
+ ...readEngines2(join28(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
21583
21802
  ...readEngines2(engineUnitDir(home), ".service", "systemd", (text, file) => {
21584
21803
  const parsed = parseEngineUnit(text);
21585
21804
  return parsed && { label: basename7(file, ".service"), ...parsed };
@@ -21617,7 +21836,7 @@ async function ensureReposDir(o) {
21617
21836
  return false;
21618
21837
  }
21619
21838
  const exists = o.exists ?? existsSync22;
21620
- const missing = dirs.filter((d) => !exists(/^~(\/|$)/.test(d) ? join27(o.home, d.slice(1)) : d));
21839
+ const missing = dirs.filter((d) => !exists(/^~(\/|$)/.test(d) ? join28(o.home, d.slice(1)) : d));
21621
21840
  if (missing.length) {
21622
21841
  error(`Not a folder on this machine: ${missing.join(", ")}. ${REPOS_DIR_NEEDED}`);
21623
21842
  return false;
@@ -21673,7 +21892,7 @@ function engineInstall2(o) {
21673
21892
  if (platform === "linux")
21674
21893
  return installUnit2({ o, parsed, label, sledsArgv, env: agentEnv, logPath, exec });
21675
21894
  const plist = enginePlistPath2(o.home, parsed.name, parsed.org, seat);
21676
- mkdirSync22(dirname17(plist), { recursive: true });
21895
+ mkdirSync22(dirname19(plist), { recursive: true });
21677
21896
  if (existsSync22(plist))
21678
21897
  exec("launchctl", ["unload", plist]);
21679
21898
  for (const other of installedEngines2(o.home)) {
@@ -21715,7 +21934,7 @@ function installUnit2(a) {
21715
21934
  const unit = engineUnitPath(o.home, label);
21716
21935
  const unitName = basename7(unit);
21717
21936
  const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
21718
- mkdirSync22(dirname17(unit), { recursive: true });
21937
+ mkdirSync22(dirname19(unit), { recursive: true });
21719
21938
  if (existsSync22(unit))
21720
21939
  systemctl("stop", unitName);
21721
21940
  for (const other of installedEngines2(o.home)) {
@@ -22740,9 +22959,9 @@ init_meter();
22740
22959
  // src/owed.ts
22741
22960
  init_config();
22742
22961
  import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as readFileSync25, renameSync as renameSync11, writeFileSync as writeFileSync22 } from "node:fs";
22743
- import { dirname as dirname18, join as join28 } from "node:path";
22744
- var owedPath = (home) => join28(configDir(home), "owed.json");
22745
- var sessionPath = (home) => join28(configDir(home), "session.json");
22962
+ import { dirname as dirname20, join as join29 } from "node:path";
22963
+ var owedPath = (home) => join29(configDir(home), "owed.json");
22964
+ var sessionPath = (home) => join29(configDir(home), "session.json");
22746
22965
  var OWED_TTL_MS = 3 * 24 * 60 * 60000;
22747
22966
  var str14 = (v) => typeof v === "string" ? v : undefined;
22748
22967
  function sourceKey(s) {
@@ -22766,7 +22985,7 @@ var readJson = (p) => {
22766
22985
  }
22767
22986
  };
22768
22987
  var writeJson = (p, v) => {
22769
- mkdirSync23(dirname18(p), { recursive: true, mode: 448 });
22988
+ mkdirSync23(dirname20(p), { recursive: true, mode: 448 });
22770
22989
  const tmp = `${p}.${process.pid}.tmp`;
22771
22990
  writeFileSync22(tmp, `${JSON.stringify(v, null, 2)}
22772
22991
  `, { mode: 384 });
@@ -22900,7 +23119,7 @@ function contextFor(deps) {
22900
23119
  ...src,
22901
23120
  fetchFn: deps.fetchFn,
22902
23121
  timeoutMs: deps.timeoutMs,
22903
- version: "0.1.48"
23122
+ version: "0.1.50"
22904
23123
  }), deps.home, now) : null;
22905
23124
  return {
22906
23125
  channel: "code",
@@ -24029,7 +24248,7 @@ init_meter();
24029
24248
  import { spawnSync as spawnSync7 } from "node:child_process";
24030
24249
  import { existsSync as existsSync28, mkdirSync as mkdirSync25, readFileSync as readFileSync27, rmSync as rmSync17, writeFileSync as writeFileSync24 } from "node:fs";
24031
24250
  import { hostname as hostname11 } from "node:os";
24032
- import { dirname as dirname19 } from "node:path";
24251
+ import { dirname as dirname21 } from "node:path";
24033
24252
  var defaultWhich3 = (cmd) => {
24034
24253
  const path = process.env.PATH ?? "";
24035
24254
  for (const dir of path.split(":").filter(Boolean)) {
@@ -24067,7 +24286,7 @@ var musherInstall = (o) => {
24067
24286
  const plist = musherPlistPath(o.home, env);
24068
24287
  const label = musherLabel(env);
24069
24288
  const dir = configDir(o.home, env);
24070
- mkdirSync25(dirname19(plist), { recursive: true });
24289
+ mkdirSync25(dirname21(plist), { recursive: true });
24071
24290
  mkdirSync25(dir, { recursive: true, mode: 448 });
24072
24291
  const execPath = o.sledsArgv[0] ?? process.execPath;
24073
24292
  const agentEnv = {
@@ -24467,7 +24686,7 @@ var orgCmd = (o) => {
24467
24686
  init_src();
24468
24687
  import { spawnSync as spawnSync8 } from "node:child_process";
24469
24688
  import { writeFileSync as writeFileSync25 } from "node:fs";
24470
- import { join as join29 } from "node:path";
24689
+ import { join as join30 } from "node:path";
24471
24690
  function packFileName(key) {
24472
24691
  return `pack-${slugify(key, 80) || "item"}.md`;
24473
24692
  }
@@ -24495,7 +24714,7 @@ var packCmd = async (o) => {
24495
24714
  log(r.text);
24496
24715
  return 0;
24497
24716
  }
24498
- const path = join29(o.cwd ?? process.cwd(), packFileName(key));
24717
+ const path = join30(o.cwd ?? process.cwd(), packFileName(key));
24499
24718
  (o.write ?? ((p, t) => writeFileSync25(p, t.endsWith(`
24500
24719
  `) ? t : `${t}
24501
24720
  `)))(path, r.text);
@@ -24505,7 +24724,7 @@ var packCmd = async (o) => {
24505
24724
 
24506
24725
  // src/commands/permissionEvent.ts
24507
24726
  import { chmodSync as chmodSync7, mkdirSync as mkdirSync26, readFileSync as readFileSync28, renameSync as renameSync12, rmSync as rmSync19, writeFileSync as writeFileSync26 } from "node:fs";
24508
- import { dirname as dirname20 } from "node:path";
24727
+ import { dirname as dirname22 } from "node:path";
24509
24728
  var isObject13 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
24510
24729
  var messageOf = (text) => {
24511
24730
  try {
@@ -24529,7 +24748,7 @@ var permissionEvent = async (o) => {
24529
24748
  if (!isToolPermission2(message))
24530
24749
  return 0;
24531
24750
  const mark = { message, at: (o.now ?? Date.now)() };
24532
- mkdirSync26(dirname20(o.mark), { recursive: true, mode: 448 });
24751
+ mkdirSync26(dirname22(o.mark), { recursive: true, mode: 448 });
24533
24752
  const tmp = `${o.mark}.${process.pid}.tmp`;
24534
24753
  writeFileSync26(tmp, `${JSON.stringify(mark)}
24535
24754
  `, { mode: 384 });
@@ -25569,16 +25788,86 @@ var seatEvent = async (o) => {
25569
25788
  return 0;
25570
25789
  };
25571
25790
 
25791
+ // src/commands/seatRevoke.ts
25792
+ var SEAT_REVOKE_USAGE = "usage: sleds seat revoke [--box <name>] [--yes] [--json]";
25793
+ var LAG = "a proxy may honour it for up to 60 s more";
25794
+ function parseSeatRevokeArgs(argv) {
25795
+ let box = null;
25796
+ let yes = false;
25797
+ let json = false;
25798
+ for (let i = 0;i < argv.length; i++) {
25799
+ const a = argv[i];
25800
+ if (a === "--json")
25801
+ json = true;
25802
+ else if (a === "--yes" || a === "-y")
25803
+ yes = true;
25804
+ else if (a === "--box") {
25805
+ const value = argv[i + 1]?.trim();
25806
+ if (!value || value.startsWith("--"))
25807
+ return { error: "--box needs the box's name" };
25808
+ box = value.replace(/^box:/, "");
25809
+ i++;
25810
+ } else
25811
+ return { error: `unknown argument ${a}` };
25812
+ }
25813
+ return { box, yes, json };
25814
+ }
25815
+ function why(j, status) {
25816
+ if (typeof j?.reason === "string")
25817
+ return j.reason;
25818
+ if (typeof j?.error === "string")
25819
+ return j.error;
25820
+ const e = j?.error;
25821
+ return typeof e?.message === "string" ? e.message : `HTTP ${status}`;
25822
+ }
25823
+ async function seatRevokeCmd(o) {
25824
+ const log = o.log ?? console.log;
25825
+ const error = o.error ?? console.error;
25826
+ const a = parseSeatRevokeArgs(o.argv);
25827
+ if ("error" in a) {
25828
+ error(a.error);
25829
+ error(SEAT_REVOKE_USAGE);
25830
+ return 2;
25831
+ }
25832
+ if (!a.box && !a.yes) {
25833
+ error("this revokes this machine's own seat — SLEDS stops here until `sleds init` again.");
25834
+ error("Add --yes to go ahead, or --box <name> to revoke one of your boxes instead.");
25835
+ return 2;
25836
+ }
25837
+ const client = engineClient({ home: o.home, ...o.client ? { client: o.client } : {} });
25838
+ if ("error" in client) {
25839
+ error(client.error);
25840
+ return 1;
25841
+ }
25842
+ const r = await client.postFull("/proxy/seat/revoke", a.box ? { box: a.box } : {});
25843
+ if (!r) {
25844
+ error("SLEDS unreachable — nothing revoked");
25845
+ return 1;
25846
+ }
25847
+ const ok = r.status < 300 && r.json?.ok !== false;
25848
+ if (a.json) {
25849
+ log(JSON.stringify({ v: 1, ...r.json ?? { ok: false, reason: `HTTP ${r.status}` } }));
25850
+ return ok ? 0 : 1;
25851
+ }
25852
+ if (!ok) {
25853
+ error(clean(`nothing revoked — ${why(r.json, r.status)}`));
25854
+ return 1;
25855
+ }
25856
+ const label = typeof r.json?.label === "string" ? r.json.label : a.box ? `box:${a.box}` : "";
25857
+ log(clean(a.box ? `${label} revoked — its token is dead; ${LAG}` : `this machine's seat${label ? ` (${label})` : ""} revoked — its token is dead; ${LAG}. Run \`sleds init\` with a new one to use SLEDS here again`));
25858
+ return 0;
25859
+ }
25860
+
25572
25861
  // src/commands/seatSync.ts
25573
25862
  import { execFileSync as execFileSync5 } from "node:child_process";
25574
25863
  import { existsSync as existsSync30, mkdirSync as mkdirSync27, readFileSync as readFileSync30, readdirSync as readdirSync7, rmSync as rmSync21, writeFileSync as writeFileSync27 } from "node:fs";
25575
25864
  import { platform as platform2 } from "node:os";
25576
- import { dirname as dirname21, join as join31 } from "node:path";
25865
+ import { dirname as dirname23, join as join32 } from "node:path";
25577
25866
 
25578
25867
  // src/cookieDb.ts
25579
25868
  import { copyFileSync as copyFileSync3, rmSync as rmSync20 } from "node:fs";
25580
25869
  import { tmpdir as tmpdir2 } from "node:os";
25581
- import { join as join30 } from "node:path";
25870
+ import { join as join31 } from "node:path";
25582
25871
  var QUERY = "SELECT name, hex(encrypted_value) AS ev FROM cookies WHERE host_key LIKE '%claude.ai%'";
25583
25872
  var isBun = () => typeof globalThis.Bun !== "undefined";
25584
25873
  async function queryRows(dbPath) {
@@ -25607,7 +25896,7 @@ function nodeSqlite() {
25607
25896
  return mod;
25608
25897
  }
25609
25898
  async function readCookieRows(dbPath) {
25610
- const copy = join30(tmpdir2(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
25899
+ const copy = join31(tmpdir2(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
25611
25900
  copyFileSync3(dbPath, copy);
25612
25901
  try {
25613
25902
  const rows = await queryRows(copy);
@@ -25900,7 +26189,7 @@ function findFile(root, name) {
25900
26189
  continue;
25901
26190
  }
25902
26191
  for (const e of entries) {
25903
- const p = join31(dir, e.name);
26192
+ const p = join32(dir, e.name);
25904
26193
  if (e.isDirectory())
25905
26194
  stack.push(p);
25906
26195
  else if (e.name === name)
@@ -25911,7 +26200,7 @@ function findFile(root, name) {
25911
26200
  }
25912
26201
  function findCookieDb(home, source) {
25913
26202
  const b = BROWSERS[source.browser];
25914
- const root = join31(home, APP_SUPPORT, b.appDir);
26203
+ const root = join32(home, APP_SUPPORT, b.appDir);
25915
26204
  if (!existsSync30(root))
25916
26205
  throw new Error(`no ${source.browser} data at ${root} (is it installed?)`);
25917
26206
  if (!b.profiled) {
@@ -25920,7 +26209,7 @@ function findCookieDb(home, source) {
25920
26209
  throw new Error(`no cookie store under ${root}`);
25921
26210
  return db;
25922
26211
  }
25923
- const localStatePath = join31(root, "Local State");
26212
+ const localStatePath = join32(root, "Local State");
25924
26213
  const localState = existsSync30(localStatePath) ? readFileSync30(localStatePath, "utf8") : null;
25925
26214
  const wanted = source.profile ?? "Default";
25926
26215
  const { dir, ambiguous } = resolveProfileDir(localState, wanted);
@@ -25928,7 +26217,7 @@ function findCookieDb(home, source) {
25928
26217
  throw new Error(`"${wanted}" names ${ambiguous.length} ${source.browser} profiles (${ambiguous.join(", ")}) — pass the directory or the account email instead`);
25929
26218
  if (!dir)
25930
26219
  throw new Error(`no ${source.browser} profile named "${wanted}" (check chrome://version)`);
25931
- const db = cookieDbCandidates(join31(root, dir)).find((p) => existsSync30(p));
26220
+ const db = cookieDbCandidates(join32(root, dir)).find((p) => existsSync30(p));
25932
26221
  if (!db)
25933
26222
  throw new Error(`profile "${dir}" has no cookie store yet (open claude.ai in it once)`);
25934
26223
  return db;
@@ -25972,7 +26261,7 @@ function fetchSeatUsage(jar, org, now, run) {
25972
26261
  }
25973
26262
  function launchAgentPlist(argv, home, source) {
25974
26263
  const label = launchLabel(source);
25975
- const log = join31(home, ".config", "sleds", `${label.slice("ai.sleds.".length)}.log`);
26264
+ const log = join32(home, ".config", "sleds", `${label.slice("ai.sleds.".length)}.log`);
25976
26265
  const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
25977
26266
  const args = [...argv, "seat-sync", ...sourceArgs(source)].map((a) => ` <string>${esc(a)}</string>`).join(`
25978
26267
  `);
@@ -25994,20 +26283,20 @@ ${args}
25994
26283
  `;
25995
26284
  }
25996
26285
  function plistPath2(home, source) {
25997
- return join31(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
26286
+ return join32(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
25998
26287
  }
25999
26288
  function install(home, argv, source, log, launchctl) {
26000
26289
  if (!argv[0]) {
26001
26290
  log("cannot resolve the sleds command to install the timer");
26002
26291
  return 1;
26003
26292
  }
26004
- const dir = join31(home, "Library", "LaunchAgents");
26293
+ const dir = join32(home, "Library", "LaunchAgents");
26005
26294
  mkdirSync27(dir, { recursive: true });
26006
26295
  const path = plistPath2(home, source);
26007
26296
  const tokenPath = seatTokenPath(home, source);
26008
26297
  rmSync21(tokenPath, { force: true });
26009
26298
  if (source.token) {
26010
- mkdirSync27(dirname21(tokenPath), { recursive: true, mode: 448 });
26299
+ mkdirSync27(dirname23(tokenPath), { recursive: true, mode: 448 });
26011
26300
  writeFileSync27(tokenPath, `${source.token}
26012
26301
  `, { mode: 384 });
26013
26302
  }
@@ -26184,8 +26473,8 @@ var sessionEvent = async (o) => {
26184
26473
 
26185
26474
  // src/commands/specEvent.ts
26186
26475
  init_meter();
26187
- import { readFileSync as readFileSync31, statSync as statSync5 } from "node:fs";
26188
- import { basename as basename8, isAbsolute as isAbsolute5, relative as relative2 } from "node:path";
26476
+ import { readFileSync as readFileSync31, statSync as statSync7 } from "node:fs";
26477
+ import { basename as basename8, isAbsolute as isAbsolute7, relative as relative2 } from "node:path";
26189
26478
  var HOOK_STDIN_TIMEOUT_MS3 = 1000;
26190
26479
  var ESTIMATE_TIMEOUT_MS = 4000;
26191
26480
  var MIN_SPEC_CHARS = 200;
@@ -26229,7 +26518,7 @@ function parseHookInput(raw) {
26229
26518
  return { toolName, filePath, cwd };
26230
26519
  }
26231
26520
  function projectKey(filePath, cwd) {
26232
- if (cwd && isAbsolute5(filePath) && isAbsolute5(cwd)) {
26521
+ if (cwd && isAbsolute7(filePath) && isAbsolute7(cwd)) {
26233
26522
  const rel = relative2(cwd, filePath);
26234
26523
  if (rel && !rel.startsWith(".."))
26235
26524
  return rel;
@@ -26238,7 +26527,7 @@ function projectKey(filePath, cwd) {
26238
26527
  }
26239
26528
  function readFileOrNull(path) {
26240
26529
  try {
26241
- if (statSync5(path).size > 2000000)
26530
+ if (statSync7(path).size > 2000000)
26242
26531
  return null;
26243
26532
  return readFileSync31(path, "utf8");
26244
26533
  } catch {
@@ -26850,7 +27139,7 @@ var hasEitherKey = (settings) => {
26850
27139
  // src/commands/update.ts
26851
27140
  init_server();
26852
27141
  import { existsSync as existsSync34 } from "node:fs";
26853
- import { homedir as homedir7, userInfo } from "node:os";
27142
+ import { homedir as homedir8, userInfo as userInfo4 } from "node:os";
26854
27143
  import { basename as basename9 } from "node:path";
26855
27144
  init_config();
26856
27145
  init_state();
@@ -26916,7 +27205,7 @@ var realPidAlive4 = (pid) => {
26916
27205
  };
26917
27206
  function machineClient(home, env) {
26918
27207
  const src = meterSource(home, undefined, { env });
26919
- return src ? fetchClient({ ...src, version: "0.1.48" }) : null;
27208
+ return src ? fetchClient({ ...src, version: "0.1.50" }) : null;
26920
27209
  }
26921
27210
  async function noteAnswer2(home, a, now) {
26922
27211
  try {
@@ -26938,7 +27227,7 @@ function busyLine(busy) {
26938
27227
  return `${n} session${n === 1 ? " is" : "s are"} running on ${on} — sleds update --now releases ${n === 1 ? "it" : "them"}`;
26939
27228
  }
26940
27229
  async function updateCmd(o) {
26941
- const home = o.home ?? homedir7();
27230
+ const home = o.home ?? homedir8();
26942
27231
  const env = o.env ?? process.env;
26943
27232
  const log = o.log ?? console.log;
26944
27233
  const error = o.error ?? console.error;
@@ -26963,7 +27252,7 @@ async function updateCmd(o) {
26963
27252
  const r = await rollBack({
26964
27253
  home,
26965
27254
  restoreState: false,
26966
- why: `asked by ${o.user ?? userInfo().username}`,
27255
+ why: `asked by ${o.user ?? userInfo4().username}`,
26967
27256
  now: now(),
26968
27257
  platform
26969
27258
  });
@@ -27242,12 +27531,12 @@ var webhooksCmd = async (o) => {
27242
27531
  // src/config.ts
27243
27532
  init_settings();
27244
27533
  import { chmodSync as chmodSync8, existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as readFileSync33, renameSync as renameSync13, writeFileSync as writeFileSync28 } from "node:fs";
27245
- import { join as join32, resolve as resolve11 } from "node:path";
27534
+ import { join as join33, resolve as resolve11 } from "node:path";
27246
27535
  var configDir2 = (home, env = process.env) => {
27247
27536
  const o = env.SLEDS_HOME?.trim();
27248
- return o ? resolve11(home, o) : join32(home, ".config", "sleds");
27537
+ return o ? resolve11(home, o) : join33(home, ".config", "sleds");
27249
27538
  };
27250
- var configPath2 = (home) => join32(configDir2(home), "config.json");
27539
+ var configPath2 = (home) => join33(configDir2(home), "config.json");
27251
27540
  var isObject17 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
27252
27541
  var optString2 = (v) => typeof v === "string" ? v : undefined;
27253
27542
  var parsePriorEnv2 = (v) => {
@@ -27424,10 +27713,10 @@ function runnerFor3(name, exec = defaultExec, o = {}) {
27424
27713
  }
27425
27714
 
27426
27715
  // src/runtime.ts
27427
- import { homedir as homedir8 } from "node:os";
27428
- import { join as join33, win32 as win323 } from "node:path";
27716
+ import { homedir as homedir9 } from "node:os";
27717
+ import { join as join34, win32 as win323 } from "node:path";
27429
27718
  var isCompiled2 = (argv1 = process.argv[1]) => Boolean(argv1 && (argv1.startsWith("/$bunfs/") || argv1.startsWith("B:\\~BUN\\")));
27430
- var sledsLink2 = (home = homedir8(), platform = process.platform) => platform === "win32" ? win323.join(process.env.LOCALAPPDATA ?? win323.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join33(home, ".sleds", "bin", "sleds");
27719
+ var sledsLink2 = (home = homedir9(), platform = process.platform) => platform === "win32" ? win323.join(process.env.LOCALAPPDATA ?? win323.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join34(home, ".sleds", "bin", "sleds");
27431
27720
 
27432
27721
  // src/schedule.ts
27433
27722
  import { spawnSync as spawnSync11 } from "node:child_process";
@@ -27439,7 +27728,7 @@ var defaultExec5 = (cmd, args) => {
27439
27728
  };
27440
27729
 
27441
27730
  // src/settings.ts
27442
- import { dirname as dirname22, join as join34, resolve as resolve12 } from "node:path";
27731
+ import { dirname as dirname24, join as join35, resolve as resolve12 } from "node:path";
27443
27732
  var withSeatEnv2 = (command, home, env = process.env, org) => {
27444
27733
  const parts = [];
27445
27734
  const sh = env.SLEDS_HOME?.trim();
@@ -27625,10 +27914,16 @@ commands:
27625
27914
  needs (gh signed in, git, tmux, its launchd agent, a repos dir). --json: {v, checks}.
27626
27915
  --sandbox: also run one short sandboxed Claude Code session (haiku) and prove it
27627
27916
  cannot read the SLEDS config dir or reach a host off the allowlist.
27917
+ --lent-by <lender>: check this account as a lent engine's before the install \u2014
27918
+ both homes 700 (an installed engine with --lent-by is checked without it).
27628
27919
  meter Show the pipeline: built today, queued with its band, delivered overnight.
27629
27920
  mcp Run the MCP server on stdio: tools usage, estimate, overnight, jobs.
27630
27921
  Register with \`claude mcp add sleds -- sleds mcp\` (Cowork sees the same server).
27631
- seat-sync Read the seat's subscription usage (weekly/5h limits, per-model, credits) from a
27922
+ seat revoke [--box <name>] [--yes] [--json] Kill a seat's token in one step. --box revokes
27923
+ your own box:<name> seat, from any terminal; without it this machine's own seat
27924
+ is revoked (--yes, since SLEDS stops here until \`sleds init\` again). A proxy may
27925
+ honour the token for up to 60 s more. --json: {v, ok, seatId, label} or {v, ok, reason}
27926
+ seat-sync Read the seat's subscription usage (weekly/5h limits, per-model, credits) from a
27632
27927
  claude.ai session and post it to the proxy. macOS.
27633
27928
  --browser <claude|chrome|brave|edge|chromium|\u2026> which cookie store (default claude)
27634
27929
  --profile <name> browser profile dir ("Profile 1") or its display name/email
@@ -27681,6 +27976,7 @@ var parseArgs = (argv) => {
27681
27976
  }
27682
27977
  return { cmd, flags };
27683
27978
  };
27979
+ var lentByOf = (v) => typeof v === "string" && v.trim() ? { lentBy: v.trim() } : {};
27684
27980
  var HELP = new Set(["help", "--help", "-h"]);
27685
27981
  var wantsHelp = (argv) => {
27686
27982
  if (HELP.has(argv[0] ?? "--help"))
@@ -27729,12 +28025,12 @@ var sledsArgv = (execPath = process.execPath, script = process.argv[1], realpath
27729
28025
  return stableArgv2(script ? [execPath, script] : [execPath], realpath, o.home);
27730
28026
  };
27731
28027
  var shellQuote = (s) => /^[\w./-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
27732
- var statusLineCommand = (argv, home = homedir9()) => withSeatEnv2([...argv, "statusline"].map(shellQuote).join(" "), home);
27733
- var seatEventCommand = (argv, home = homedir9()) => withSeatEnv2([...argv, "seat-event"].map(shellQuote).join(" "), home);
27734
- var promptEventCommand = (argv, home = homedir9()) => withSeatEnv2([...argv, "prompt-event"].map(shellQuote).join(" "), home);
27735
- var sessionEventCommand = (argv, home = homedir9()) => withSeatEnv2([...argv, "session-event"].map(shellQuote).join(" "), home);
27736
- var stopEventCommand = (argv, home = homedir9()) => withSeatEnv2([...argv, "stop-event"].map(shellQuote).join(" "), home);
27737
- var specEventCommand = (argv, home = homedir9()) => withSeatEnv2([...argv, "spec-event"].map(shellQuote).join(" "), home);
28028
+ var statusLineCommand = (argv, home = homedir10()) => withSeatEnv2([...argv, "statusline"].map(shellQuote).join(" "), home);
28029
+ var seatEventCommand = (argv, home = homedir10()) => withSeatEnv2([...argv, "seat-event"].map(shellQuote).join(" "), home);
28030
+ var promptEventCommand = (argv, home = homedir10()) => withSeatEnv2([...argv, "prompt-event"].map(shellQuote).join(" "), home);
28031
+ var sessionEventCommand = (argv, home = homedir10()) => withSeatEnv2([...argv, "session-event"].map(shellQuote).join(" "), home);
28032
+ var stopEventCommand = (argv, home = homedir10()) => withSeatEnv2([...argv, "stop-event"].map(shellQuote).join(" "), home);
28033
+ var specEventCommand = (argv, home = homedir10()) => withSeatEnv2([...argv, "spec-event"].map(shellQuote).join(" "), home);
27738
28034
  var mcpFlag = (flags) => flags["no-mcp"] === true ? false : flags.mcp === true ? true : undefined;
27739
28035
  var main = async (argv) => {
27740
28036
  const { cmd, flags } = parseArgs(argv);
@@ -27742,7 +28038,7 @@ var main = async (argv) => {
27742
28038
  console.log(commandUsage(cmd));
27743
28039
  return 0;
27744
28040
  }
27745
- const home = homedir9();
28041
+ const home = homedir10();
27746
28042
  const scheduler = {
27747
28043
  platform: platform3(),
27748
28044
  home,
@@ -27754,7 +28050,7 @@ var main = async (argv) => {
27754
28050
  now: Date.now(),
27755
28051
  stderr: (line) => console.error(line),
27756
28052
  isTTY: !!process.stderr.isTTY,
27757
- version: "0.1.48"
28053
+ version: "0.1.50"
27758
28054
  });
27759
28055
  switch (cmd) {
27760
28056
  case "update":
@@ -27775,6 +28071,11 @@ var main = async (argv) => {
27775
28071
  return sledCmd({ home, argv: argv.slice(1) });
27776
28072
  case "reopen":
27777
28073
  return reopenCmd({ home, argv: argv.slice(1) });
28074
+ case "seat":
28075
+ if (argv[1] === "revoke")
28076
+ return seatRevokeCmd({ home, argv: argv.slice(2) });
28077
+ console.error(SEAT_REVOKE_USAGE);
28078
+ return 2;
27778
28079
  case "engine":
27779
28080
  case "route": {
27780
28081
  if (cmd === "engine" && argv[1] === "status")
@@ -27957,7 +28258,8 @@ var main = async (argv) => {
27957
28258
  return doctor({
27958
28259
  home,
27959
28260
  json: argv.slice(1).includes("--json"),
27960
- sandbox: argv.slice(1).includes("--sandbox")
28261
+ sandbox: argv.slice(1).includes("--sandbox"),
28262
+ ...lentByOf(parseArgs(argv).flags["lent-by"])
27961
28263
  });
27962
28264
  case "status":
27963
28265
  return status3({ home });
@@ -27981,7 +28283,7 @@ ${renderHelpText(argv[1])}`);
27981
28283
  case "version":
27982
28284
  case "--version":
27983
28285
  case "-v":
27984
- console.log("sleds 0.1.48");
28286
+ console.log("sleds 0.1.50");
27985
28287
  return 0;
27986
28288
  default:
27987
28289
  console.error(`unknown command: ${cmd}