@sleds/cli 0.1.37 → 0.1.38

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 +185 -11
  2. package/package.json +1 -1
package/dist/sleds.mjs CHANGED
@@ -7952,7 +7952,8 @@ function parseRun(v) {
7952
7952
  ...typeof v.pr.conflict === "string" ? { conflict: v.pr.conflict } : {},
7953
7953
  ...typeof v.pr.resolving === "string" ? { resolving: v.pr.resolving } : {},
7954
7954
  ...conflicted ? { conflicted } : {},
7955
- ...typeof v.pr.reviewed === "string" ? { reviewed: v.pr.reviewed } : {}
7955
+ ...typeof v.pr.reviewed === "string" ? { reviewed: v.pr.reviewed } : {},
7956
+ ...typeof v.pr.look === "string" ? { look: v.pr.look } : {}
7956
7957
  }
7957
7958
  } : {}
7958
7959
  };
@@ -8023,6 +8024,7 @@ function parseLock(text) {
8023
8024
  runner: typeof v.runner === "string" ? v.runner : "",
8024
8025
  atOnce: n(v.atOnce, 1),
8025
8026
  interval: n(v.interval, 0),
8027
+ ...typeof v.cliVersion === "string" && v.cliVersion ? { cliVersion: v.cliVersion } : {},
8026
8028
  ...typeof v.checkedAt === "number" ? { checkedAt: v.checkedAt } : {},
8027
8029
  ...typeof v.nextCheckAt === "number" ? { nextCheckAt: v.nextCheckAt } : {},
8028
8030
  ...machine ? { machine } : {},
@@ -10345,7 +10347,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
10345
10347
  name: flags.name,
10346
10348
  os: host.os ?? process.platform,
10347
10349
  runner: flags.runner,
10348
- version: host.version ?? "0.1.37" ?? "dev",
10350
+ version: host.version ?? "0.1.38" ?? "dev",
10349
10351
  running: live.length,
10350
10352
  items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
10351
10353
  ...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
@@ -10657,6 +10659,15 @@ function prForBranch(exec, repoPath, branch) {
10657
10659
  return { error: e instanceof Error ? e.message : String(e) };
10658
10660
  }
10659
10661
  }
10662
+ var URL_RE = /https:\/\/[^\s)>\]"']+/;
10663
+ var ARTIFACT_RE = /https:\/\/claude\.ai\/[^\s)>\]"']*artifact\/[^\s)>\]"']+/;
10664
+ function mockOf(body) {
10665
+ const header = /<!--\s*sleds:header\s*-->([\s\S]*?)<!--\s*\/sleds:header\s*-->/.exec(body)?.[1];
10666
+ const line = header?.split(`
10667
+ `).find((l) => /\*\*Mocks\*\*\s*:/i.test(l));
10668
+ const fromHeader = line ? URL_RE.exec(line)?.[0] : undefined;
10669
+ return fromHeader ?? ARTIFACT_RE.exec(body)?.[0];
10670
+ }
10660
10671
  var FAILED = new Set([
10661
10672
  "FAILURE",
10662
10673
  "ERROR",
@@ -10702,6 +10713,7 @@ function parsePrView(stdout) {
10702
10713
  pending++;
10703
10714
  }
10704
10715
  const mergeCommit = typeof o.mergeCommit === "object" && o.mergeCommit !== null ? o.mergeCommit.oid : undefined;
10716
+ const mock = typeof o.body === "string" ? mockOf(o.body) : undefined;
10705
10717
  return {
10706
10718
  state: o.state,
10707
10719
  author: loginOf(o.author),
@@ -10712,6 +10724,8 @@ function parsePrView(stdout) {
10712
10724
  reviewDecision: typeof o.reviewDecision === "string" ? o.reviewDecision : "",
10713
10725
  feedback: 0,
10714
10726
  authorFeedback: 0,
10727
+ draft: o.isDraft === true,
10728
+ ...mock ? { mock } : {},
10715
10729
  ...typeof o.headRefOid === "string" && o.headRefOid ? { head: o.headRefOid } : {},
10716
10730
  ...typeof mergeCommit === "string" && mergeCommit ? { mergeCommit } : {}
10717
10731
  };
@@ -10766,7 +10780,7 @@ function prView(exec, repoPath, url) {
10766
10780
  "view",
10767
10781
  url,
10768
10782
  "--json",
10769
- "state,author,statusCheckRollup,reviewDecision,comments,reviews,headRefOid,mergeable,baseRefName,mergeCommit"
10783
+ "state,author,statusCheckRollup,reviewDecision,comments,reviews,headRefOid,mergeable,baseRefName,mergeCommit,isDraft,body"
10770
10784
  ], { cwd: repoPath });
10771
10785
  const view = r.status === 0 ? parsePrView(r.stdout) : null;
10772
10786
  if (!view || view.state !== "OPEN")
@@ -11232,6 +11246,10 @@ init_machine();
11232
11246
 
11233
11247
  // src/engine/sledsSource.ts
11234
11248
  init_src();
11249
+ function looksOf(s) {
11250
+ const l = s;
11251
+ return l && typeof l.openLook === "function" && typeof l.clearLook === "function" ? s : null;
11252
+ }
11235
11253
  var FAIL_LOG_MAX = 2000;
11236
11254
  var UNREACHABLE2 = "SLEDS unreachable";
11237
11255
  function keysIn(states, state) {
@@ -11373,20 +11391,34 @@ var PROFILE_TEXT = [
11373
11391
  "reposDir",
11374
11392
  "engine"
11375
11393
  ];
11394
+ var SHELL_TEXT = ["agent", "launcher"];
11376
11395
  function profileOf(r) {
11377
11396
  if (!r || r.ok === false || !isObject8(r.profile))
11378
11397
  return null;
11379
11398
  const p = r.profile;
11399
+ const member = isObject8(r.member) ? r.member : {};
11380
11400
  const out = {
11381
11401
  pickup: p.pickup === "auto" ? "auto" : "approve",
11382
11402
  ...HOLD_DEFAULTS2,
11383
11403
  holdOff: p.holdOff === true
11384
11404
  };
11385
11405
  for (const k of PROFILE_TEXT) {
11406
+ if (SHELL_TEXT.includes(k))
11407
+ continue;
11386
11408
  const v = str6(p[k])?.trim();
11387
11409
  if (v)
11388
11410
  out[k] = v;
11389
11411
  }
11412
+ const notYours = [];
11413
+ for (const k of SHELL_TEXT) {
11414
+ const mine = str6(member[k])?.trim();
11415
+ if (mine)
11416
+ out[k] = mine;
11417
+ else if (str6(p[k])?.trim())
11418
+ notYours.push(k);
11419
+ }
11420
+ if (notYours.length)
11421
+ out.notYours = notYours;
11390
11422
  const atOnce = num5(p.atOnce);
11391
11423
  if (atOnce !== undefined && atOnce >= 1)
11392
11424
  out.atOnce = Math.round(atOnce);
@@ -11746,6 +11778,36 @@ function sledsSource(client, o) {
11746
11778
  throw new Error(serverMessage(r));
11747
11779
  return eventOpenOf(r.json);
11748
11780
  },
11781
+ async openLook(runId, look, engine) {
11782
+ const r = await client.postFull("/proxy/run", {
11783
+ runId,
11784
+ engine,
11785
+ event: {
11786
+ kind: "look",
11787
+ md: look.md,
11788
+ about: { prs: [look.pr], ...look.mock ? { mock: look.mock } : {} }
11789
+ }
11790
+ });
11791
+ if (!r)
11792
+ throw new Error(`${UNREACHABLE2} — the look not raised`);
11793
+ if (r.status >= 300 || !r.json || r.json.ok === false)
11794
+ throw new Error(serverMessage(r));
11795
+ const decisionId = str6(r.json.decisionId);
11796
+ const state = str6(r.json.state);
11797
+ return {
11798
+ opened: r.json.opened === true,
11799
+ ...decisionId ? { decisionId } : {},
11800
+ ...state ? { state } : {}
11801
+ };
11802
+ },
11803
+ async clearLook(runId, clear, engine) {
11804
+ const r = await client.postFull("/proxy/run", { runId, engine, clearLook: clear });
11805
+ if (!r)
11806
+ throw new Error(`${UNREACHABLE2} — the look not cleared`);
11807
+ if (r.status >= 300 || !r.json || r.json.ok === false)
11808
+ throw new Error(serverMessage(r));
11809
+ return r.json.cleared === true;
11810
+ },
11749
11811
  async decisionOf(item, decisionId) {
11750
11812
  const route = await routeOf(item);
11751
11813
  const decisions = Array.isArray(route?.decisions) ? route.decisions.filter(isObject8) : [];
@@ -12207,9 +12269,13 @@ async function tick(deps) {
12207
12269
  deps.providerHold = d.providerHold;
12208
12270
  deps.atOnce = d.atOnce;
12209
12271
  }
12272
+ removeEndedMcpConfigs(deps, made);
12210
12273
  }
12274
+ return report;
12275
+ }
12276
+ function removeEndedMcpConfigs(deps, made) {
12211
12277
  if (!deps.removeMcpConfig || made.size === 0)
12212
- return report;
12278
+ return;
12213
12279
  const state = deps.readState();
12214
12280
  const live = liveMcpConfigs(state);
12215
12281
  for (const p of made) {
@@ -12227,7 +12293,6 @@ async function tick(deps) {
12227
12293
  r.mcpConfig = undefined;
12228
12294
  deps.writeState(state);
12229
12295
  }
12230
- return report;
12231
12296
  }
12232
12297
  async function tickOnce(d) {
12233
12298
  d.tickProfile = profileOnce(d.readProfile);
@@ -13513,11 +13578,47 @@ var SELF_NUDGES = 2;
13513
13578
  function reviewNudge(url, count) {
13514
13579
  return `New review feedback on your PR (${count} ${count === 1 ? "comment" : "comments"} from people so far): ${url}. Read all of it (gh pr view ${url} --comments, and the inline threads), answer each comment on its own thread with the fix or a reasoned reply, push, and leave the threads for the reviewer to resolve. End every comment and reply you post on the PR with the line ${ENGINE_MARK} so the engine knows it is yours and not the reviewer's.`;
13515
13580
  }
13581
+ function lookQuestion(url, mock) {
13582
+ return `A draft PR waits for your look: ${url}.${mock ? ` The mock: ${mock}.` : " Its body names no mock; the PR is the place to look."} Looks good marks it ready for review.`;
13583
+ }
13584
+ async function judgeLook(d, run, view) {
13585
+ const looks = looksOf(d.source);
13586
+ const pr = run.pr;
13587
+ if (!looks || !run.runId)
13588
+ return;
13589
+ const draft = view.state === "OPEN" && view.draft;
13590
+ if (draft && !pr.look) {
13591
+ try {
13592
+ const r = await looks.openLook(run.runId, {
13593
+ md: lookQuestion(pr.url, view.mock),
13594
+ pr: pr.url,
13595
+ ...view.mock ? { mock: view.mock } : {}
13596
+ }, d.engine);
13597
+ if (!r.decisionId)
13598
+ return;
13599
+ pr.look = r.decisionId;
13600
+ if (r.opened)
13601
+ d.log(`${ref(run)}: ${pr.url} is a draft — a look waits for a person`);
13602
+ } catch (e) {
13603
+ d.log(`${ref(run)}: could not raise the look on ${pr.url}: ${message(e)}`);
13604
+ }
13605
+ } else if (!draft && pr.look) {
13606
+ const why = view.state === "MERGED" ? "the PR merged" : view.state === "CLOSED" ? "the PR closed without a merge" : "the PR left draft";
13607
+ try {
13608
+ if (await looks.clearLook(run.runId, { pr: pr.url, why }, d.engine))
13609
+ d.log(`${ref(run)}: the look on ${pr.url} is cleared — ${why}`);
13610
+ pr.look = undefined;
13611
+ } catch (e) {
13612
+ d.log(`${ref(run)}: could not clear the look on ${pr.url}: ${message(e)}`);
13613
+ }
13614
+ }
13615
+ }
13516
13616
  async function follow(d, state, run, claim, runner, finished, attention, changes, decided) {
13517
13617
  const pr = run.pr;
13518
13618
  const view = d.prView(d.exec, run.repoPath, pr.url);
13519
13619
  if (!view)
13520
13620
  return true;
13621
+ await judgeLook(d, run, view);
13521
13622
  if (view.state === "MERGED") {
13522
13623
  const landed = await ripple(d, state, run, claim, runner, pr.url, finished, decided, view.head, view.mergeCommit);
13523
13624
  return !landed;
@@ -15429,6 +15530,8 @@ function flagsFromProfile(flags, given, profile, home) {
15429
15530
  const out = { ...flags };
15430
15531
  const used = [];
15431
15532
  const skipped = [];
15533
+ for (const k of profile.notYours ?? [])
15534
+ skipped.push(`${k} (the workspace default — the engine runs only one you set yourself)`);
15432
15535
  if (profile.atOnce !== undefined && !has("at-once")) {
15433
15536
  out.atOnce = profile.atOnce;
15434
15537
  used.push(`at-once ${profile.atOnce}`);
@@ -15819,7 +15922,8 @@ async function driveEngine(o, flags, deps, until = {}) {
15819
15922
  startedAt: (o.now ?? Date.now)(),
15820
15923
  runner: deps.runner.name,
15821
15924
  atOnce: flags.atOnce,
15822
- interval: flags.interval
15925
+ interval: flags.interval,
15926
+ cliVersion: "0.1.38"
15823
15927
  };
15824
15928
  const beat = (checkedAt) => {
15825
15929
  const m = deps.machine;
@@ -17421,6 +17525,8 @@ function flagsFromProfile2(flags, given, profile, home) {
17421
17525
  const out = { ...flags };
17422
17526
  const used = [];
17423
17527
  const skipped = [];
17528
+ for (const k of profile.notYours ?? [])
17529
+ skipped.push(`${k} (the workspace default — the engine runs only one you set yourself)`);
17424
17530
  if (profile.atOnce !== undefined && !has("at-once")) {
17425
17531
  out.atOnce = profile.atOnce;
17426
17532
  used.push(`at-once ${profile.atOnce}`);
@@ -17849,7 +17955,8 @@ async function driveEngine2(o, flags, deps, until = {}) {
17849
17955
  startedAt: (o.now ?? Date.now)(),
17850
17956
  runner: deps.runner.name,
17851
17957
  atOnce: flags.atOnce,
17852
- interval: flags.interval
17958
+ interval: flags.interval,
17959
+ cliVersion: "0.1.38"
17853
17960
  };
17854
17961
  const beat = (checkedAt) => {
17855
17962
  const m = deps.machine;
@@ -18827,6 +18934,7 @@ function engineStatus(i) {
18827
18934
  ...opt("runner", lock.runner || undefined),
18828
18935
  atOnce: lock.atOnce,
18829
18936
  interval: lock.interval,
18937
+ cliVersion: lock.cliVersion ?? "",
18830
18938
  ...opt("checkedAt", iso2(lock.checkedAt)),
18831
18939
  ...opt("nextCheckAt", alive ? iso2(lock.nextCheckAt) : undefined),
18832
18940
  ...opt("machine", lock.machine ? { ...lock.machine, at: new Date(lock.machine.at).toISOString() } : undefined),
@@ -20764,8 +20872,9 @@ var mcp = async (o) => {
20764
20872
  (o.warn ?? ((line) => process.stderr.write(`${line}
20765
20873
  `)))("sleds mcp: on this run's token (SLEDS_RUN_TOKEN), not the seat's");
20766
20874
  let buffer = "";
20875
+ const decoder = new TextDecoder;
20767
20876
  for await (const chunk of stdin) {
20768
- buffer += typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk);
20877
+ buffer += typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
20769
20878
  let nl = buffer.indexOf(`
20770
20879
  `);
20771
20880
  while (nl !== -1) {
@@ -20778,6 +20887,7 @@ var mcp = async (o) => {
20778
20887
  `);
20779
20888
  }
20780
20889
  }
20890
+ buffer += decoder.decode();
20781
20891
  if (buffer.trim().length > 0) {
20782
20892
  const out = await handleLine2(buffer, { home: o.home, env });
20783
20893
  if (out !== null)
@@ -21381,13 +21491,13 @@ init_src();
21381
21491
  import { readFileSync as readFileSync24 } from "node:fs";
21382
21492
  import { hostname as hostname12 } from "node:os";
21383
21493
  var ARM_USAGE = "usage: sleds route arm <key> [--off] [--json] [--name <engine>] [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--mode <permission-mode>] [--model <id>] [--effort <e>] [--branch '<template>'] [--pr-title '<template>'] [--repos-dir <dir>]";
21384
- var USAGE = "usage: sleds route <key> [--long | --dot | --json] | sleds route arm <key> [--off] [--json] | sleds route answer <key>/<node> --stdin | sleds route propose <key> --file <nodes.json> | sleds route approve <key> | sleds route redraft <key> | sleds route single <key> | sleds route decisions [<key>] [--flagged] | sleds route decision <key> <id> --seen | --answer --stdin [--route accept|keep|redraft] | --keep-route | --apply [--answer --stdin] | --overrule --stdin | sleds route run <key> [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir>] [--mode <permission-mode>] [--model <id>] [--branch '<template>'] [--pr-title '<template>'] [--once]";
21494
+ var USAGE = "usage: sleds route <key> [--long | --dot | --json] | sleds route arm <key> [--off] [--json] | sleds route answer <key>/<node> --stdin | sleds route propose <key> --file <nodes.json> | sleds route approve <key> | sleds route redraft <key> | sleds route single <key> | sleds route decisions [<key>] [--flagged] | sleds route decision <key> <id> --seen | --answer --stdin [--route accept|keep|redraft] | --keep-route | --apply [--answer --stdin] | --overrule --stdin | --ready | sleds route run <key> [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir>] [--mode <permission-mode>] [--model <id>] [--branch '<template>'] [--pr-title '<template>'] [--once]";
21385
21495
  var ANSWER_USAGE = "usage: sleds route answer <key>/<node> <answer…> | sleds route answer <key>/<node> --stdin [--json]";
21386
21496
  var PROPOSE_USAGE = "usage: sleds route propose <key> (--file <nodes.json> | --stdin) [--name <engine>] [--json]";
21387
21497
  var APPROVE_USAGE = "usage: sleds route approve <key> [--file <nodes.json>] [--json]";
21388
21498
  var REDRAFT_USAGE = "usage: sleds route redraft <key> [--json]";
21389
21499
  var SINGLE_USAGE = "usage: sleds route single <key> [--json]";
21390
- var DECISION_USAGE = "usage: sleds route decision <key> <id> --seen | sleds route decision <key> <id> (--answer | --overrule) (<answer…> | --stdin) | sleds route decision <key> <id> [--answer (<answer…> | --stdin)] --route accept|keep|redraft | sleds route decision <key> <id> --keep-route | sleds route decision <key> <id> --apply [--answer (<answer…> | --stdin)] [--json]";
21500
+ var DECISION_USAGE = "usage: sleds route decision <key> <id> --seen | sleds route decision <key> <id> (--answer | --overrule) (<answer…> | --stdin) | sleds route decision <key> <id> [--answer (<answer…> | --stdin)] --route accept|keep|redraft | sleds route decision <key> <id> --keep-route | sleds route decision <key> <id> --apply [--answer (<answer…> | --stdin)] | sleds route decision <key> <id> --ready [--json]";
21391
21501
  var ROUTE_VERDICTS = ["accept", "keep", "redraft"];
21392
21502
  function nodesFromJson(text) {
21393
21503
  let parsed;
@@ -21716,6 +21826,8 @@ function appliedLine(key, applied) {
21716
21826
  return a.changed === false ? `${key}: ${what} was already set — answered` : `${key}: set ${what} — answered`;
21717
21827
  }
21718
21828
  async function decisionCmd(o, argv) {
21829
+ if (argv.includes("--ready"))
21830
+ return readyCmd(o, argv);
21719
21831
  const log = o.log ?? console.log;
21720
21832
  const error = o.error ?? console.error;
21721
21833
  const json = argv.includes("--json");
@@ -21769,6 +21881,68 @@ async function decisionCmd(o, argv) {
21769
21881
  }
21770
21882
  return said(o, key, json, r, () => log(seen ? `${key}: marked seen` : overrule ? `${key}: overruled — your answer stands in the log` : apply ? appliedLine(key, r.json?.applied) : answeredLine(key, r.json?.route ?? route, r.json?.held)));
21771
21883
  }
21884
+ var LOOK_READY_ANSWER = "Looks good — marked ready for review.";
21885
+ function lookToReady(route, id) {
21886
+ const rows = Array.isArray(route?.decisions) ? route.decisions : [];
21887
+ const d = rows.find((r) => r.id === id);
21888
+ if (!d)
21889
+ return { error: `no decision ${id} on this item` };
21890
+ if (d.kind !== "look")
21891
+ return { error: `decision ${id} is not a look — --ready marks a look` };
21892
+ if (d.state !== "escalated")
21893
+ return { error: `decision ${id} is ${String(d.state)} — not a look you owe` };
21894
+ const about = d.about && typeof d.about === "object" ? d.about : {};
21895
+ const pr = Array.isArray(about.prs) ? about.prs.find((p) => typeof p === "string" && p) : undefined;
21896
+ return typeof pr === "string" ? { pr } : { error: `decision ${id} names no PR` };
21897
+ }
21898
+ async function readyCmd(o, argv) {
21899
+ const log = o.log ?? console.log;
21900
+ const error = o.error ?? console.error;
21901
+ const json = argv.includes("--json");
21902
+ const words = argv.filter((a) => a !== "--ready" && a !== "--json");
21903
+ const [key, id] = words;
21904
+ if (!key || !id || words.length !== 2 || words.some((w) => w.startsWith("--"))) {
21905
+ error(DECISION_USAGE);
21906
+ return 2;
21907
+ }
21908
+ const client = engineClient(o);
21909
+ if ("error" in client) {
21910
+ error(client.error);
21911
+ return 1;
21912
+ }
21913
+ const reader = routeReader(o);
21914
+ if ("error" in reader) {
21915
+ error(reader.error);
21916
+ return 1;
21917
+ }
21918
+ const route = await reader.read(key).catch((e) => {
21919
+ error(e instanceof Error ? e.message : String(e));
21920
+ return;
21921
+ });
21922
+ if (route === undefined)
21923
+ return 1;
21924
+ const look = lookToReady(route, id);
21925
+ if ("error" in look) {
21926
+ error(`${key}: ${look.error}`);
21927
+ return 1;
21928
+ }
21929
+ const gh = (o.exec ?? defaultExec)("gh", ["pr", "ready", look.pr]);
21930
+ if (gh.status !== 0) {
21931
+ error(gh.stderr.trim() || `gh pr ready ${look.pr} exited ${gh.status}`);
21932
+ error(`${key}: the look is not answered`);
21933
+ return 1;
21934
+ }
21935
+ const r = await client.postFull("/proxy/route/decision", {
21936
+ project: key,
21937
+ id,
21938
+ answer: LOOK_READY_ANSWER
21939
+ });
21940
+ if (!r) {
21941
+ error(`${key}: ${look.pr} is ready for review, but SLEDS is unreachable — the look is not answered`);
21942
+ return 1;
21943
+ }
21944
+ return said(o, key, json, r, () => log(`${key}: ${look.pr} marked ready for review — the look is answered`));
21945
+ }
21772
21946
  var DECISIONS_USAGE = "usage: sleds route decisions [<key>] [--flagged] [--json]";
21773
21947
  function decisionsLines(raw) {
21774
21948
  const j = clean(raw);
@@ -24215,7 +24389,7 @@ ${renderHelpText(argv[1])}`);
24215
24389
  case "version":
24216
24390
  case "--version":
24217
24391
  case "-v":
24218
- console.log("sleds 0.1.37");
24392
+ console.log("sleds 0.1.38");
24219
24393
  return 0;
24220
24394
  default:
24221
24395
  console.error(`unknown command: ${cmd}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleds/cli",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "description": "SLEDS CLI — the cost and limits of AI agent work, decided at the wall. Point Claude Code at a SLEDS proxy; estimate before you run; hold, switch model, or run overnight when you hit a limit.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",