@sleds/cli 0.1.14 → 0.1.16

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 +354 -254
  2. package/package.json +17 -6
package/dist/sleds.mjs CHANGED
@@ -24,7 +24,7 @@ import { dirname, join, resolve } from "node:path";
24
24
  var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN", claudeDir = (home, env = process.env) => {
25
25
  const o = env.CLAUDE_CONFIG_DIR?.trim();
26
26
  return o ? resolve(home, o) : join(home, ".claude");
27
- }, hasHomeOverride = (env = process.env) => Boolean(env.SLEDS_HOME?.trim() || env.CLAUDE_CONFIG_DIR?.trim()), settingsPath = (home) => join(claudeDir(home), "settings.json"), sledsCommand = (sub, home, env = process.env) => {
27
+ }, hasHomeOverride = (env = process.env) => Boolean(env.SLEDS_HOME?.trim() || env.CLAUDE_CONFIG_DIR?.trim()), settingsPath = (home) => join(claudeDir(home), "settings.json"), sledsCommand = (sub, home, env = process.env) => withSeatEnv(`sleds ${sub}`, home, env), withSeatEnv = (command, home, env = process.env) => {
28
28
  const parts = [];
29
29
  const sh = env.SLEDS_HOME?.trim();
30
30
  const cc = env.CLAUDE_CONFIG_DIR?.trim();
@@ -32,7 +32,7 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
32
32
  parts.push(`SLEDS_HOME=${shellWord(resolve(home, sh))}`);
33
33
  if (cc)
34
34
  parts.push(`CLAUDE_CONFIG_DIR=${shellWord(resolve(home, cc))}`);
35
- parts.push(`sleds ${sub}`);
35
+ parts.push(command);
36
36
  return parts.join(" ");
37
37
  }, sledsCommandsIn = (settings) => {
38
38
  const out = [];
@@ -303,10 +303,8 @@ var init_config = __esm(() => {
303
303
  init_settings();
304
304
  });
305
305
 
306
- // src/meter.ts
307
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "node:fs";
308
- import { join as join3 } from "node:path";
309
- var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, str = (v) => typeof v === "string" ? v : undefined, parseMeter = (raw) => {
306
+ // ../../packages/shared/src/mcp/format.ts
307
+ var isObject3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, str = (v) => typeof v === "string" ? v : undefined, parseMeter = (raw) => {
310
308
  if (!isObject3(raw))
311
309
  return null;
312
310
  const seat = isObject3(raw.seat) ? str(raw.seat.email) : undefined;
@@ -430,15 +428,29 @@ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject3 = (v) => typeof
430
428
  if (m.estimateAccuracyPct !== undefined)
431
429
  lines.push(row("Estimates:", `${Math.round(m.estimateAccuracyPct)}% landed in band`));
432
430
  return lines;
433
- }, meterCachePath = (home) => join3(configDir(home), "meter.json"), readMeterCache = (home, now) => {
431
+ };
432
+ var init_format = __esm(() => {
433
+ KIND_WORDS = {
434
+ rate_limit: "rate limit hit",
435
+ weekly_cap: "usage limit reached",
436
+ budget: "budget exhausted",
437
+ provider_down: "provider unavailable"
438
+ };
439
+ OFFLINE_LINE = `${PREFIX}offline`;
440
+ });
441
+
442
+ // src/meter.ts
443
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "node:fs";
444
+ import { join as join3 } from "node:path";
445
+ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, meterCachePath = (home) => join3(configDir(home), "meter.json"), readMeterCache = (home, now) => {
434
446
  const p = meterCachePath(home);
435
447
  if (!existsSync3(p))
436
448
  return null;
437
449
  try {
438
450
  const raw = JSON.parse(readFileSync3(p, "utf8"));
439
- if (!isObject3(raw))
451
+ if (!isObject4(raw))
440
452
  return null;
441
- const fetchedAt = num(raw.fetchedAt);
453
+ const fetchedAt = num2(raw.fetchedAt);
442
454
  if (fetchedAt === undefined || now - fetchedAt >= METER_CACHE_TTL_MS || fetchedAt > now)
443
455
  return null;
444
456
  return parseMeter(raw.meter);
@@ -491,15 +503,10 @@ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject3 = (v) => typeof
491
503
  return fresh;
492
504
  };
493
505
  var init_meter = __esm(() => {
506
+ init_format();
494
507
  init_config();
495
508
  init_settings();
496
- KIND_WORDS = {
497
- rate_limit: "rate limit hit",
498
- weekly_cap: "usage limit reached",
499
- budget: "budget exhausted",
500
- provider_down: "provider unavailable"
501
- };
502
- OFFLINE_LINE = `${PREFIX}offline`;
509
+ init_format();
503
510
  });
504
511
 
505
512
  // src/seat.ts
@@ -531,9 +538,9 @@ __export(exports_seat, {
531
538
  writeSeatState: () => writeSeatState2
532
539
  });
533
540
  import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync10, renameSync as renameSync5, writeFileSync as writeFileSync10 } from "node:fs";
534
- import { join as join10 } from "node:path";
535
- var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_MS2 = 1500, STDIN_TIMEOUT_MS2 = 300, isObject9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num5 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, EPOCH_MS_THRESHOLD2 = 100000000000, parseResetsAt2 = (v) => {
536
- const n = num5(v);
541
+ import { join as join11 } from "node:path";
542
+ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_MS2 = 1500, STDIN_TIMEOUT_MS2 = 300, isObject10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num6 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, EPOCH_MS_THRESHOLD2 = 100000000000, parseResetsAt2 = (v) => {
543
+ const n = num6(v);
537
544
  if (n !== undefined) {
538
545
  if (n <= 0)
539
546
  return;
@@ -545,28 +552,28 @@ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_
545
552
  }
546
553
  return;
547
554
  }, parseBar2 = (v) => {
548
- if (!isObject9(v))
555
+ if (!isObject10(v))
549
556
  return;
550
- const usedPct = num5(v.used_percentage) ?? num5(v.usedPct);
557
+ const usedPct = num6(v.used_percentage) ?? num6(v.usedPct);
551
558
  const resetsAt = parseResetsAt2(v.resets_at ?? v.resetsAt);
552
559
  if (usedPct === undefined || usedPct < 0 || resetsAt === undefined)
553
560
  return;
554
561
  return { usedPct, resetsAt };
555
562
  }, parseSeatWindow2 = (raw, capturedAt) => {
556
- if (!isObject9(raw))
563
+ if (!isObject10(raw))
557
564
  return null;
558
- const limits = isObject9(raw.rate_limits) ? raw.rate_limits : raw;
565
+ const limits = isObject10(raw.rate_limits) ? raw.rate_limits : raw;
559
566
  const fiveHour = parseBar2(limits.five_hour ?? limits.fiveHour);
560
567
  const sevenDay = parseBar2(limits.seven_day ?? limits.sevenDay);
561
568
  const spendLimit = parseBar2(limits.spend_limit ?? limits.spendLimit);
562
569
  const models = {};
563
- if (isObject9(limits.models))
570
+ if (isObject10(limits.models))
564
571
  for (const [k, v] of Object.entries(limits.models)) {
565
572
  const bar = parseBar2(v);
566
573
  if (bar)
567
574
  models[k] = bar;
568
575
  }
569
- const usedCreditsUsd = num5(limits.usedCreditsUsd);
576
+ const usedCreditsUsd = num6(limits.usedCreditsUsd);
570
577
  const hasModels = Object.keys(models).length > 0;
571
578
  if (!fiveHour && !sevenDay && !spendLimit && !hasModels && usedCreditsUsd === undefined)
572
579
  return null;
@@ -604,28 +611,28 @@ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_
604
611
  if (parts.length === 0)
605
612
  return null;
606
613
  return `seat ${parts.join(SEP)}`;
607
- }, seatStatePath2 = (home) => join10(configDir(home), "seat.json"), parseWindowStored2 = (v) => {
608
- if (!isObject9(v))
614
+ }, seatStatePath2 = (home) => join11(configDir(home), "seat.json"), parseWindowStored2 = (v) => {
615
+ if (!isObject10(v))
609
616
  return;
610
- const capturedAt = num5(v.capturedAt);
617
+ const capturedAt = num6(v.capturedAt);
611
618
  if (capturedAt === undefined)
612
619
  return;
613
620
  return parseSeatWindow2(v, capturedAt) ?? undefined;
614
621
  }, parseSeatState2 = (raw) => {
615
- if (!isObject9(raw))
622
+ if (!isObject10(raw))
616
623
  return {};
617
624
  const out = {};
618
625
  const window = parseWindowStored2(raw.window);
619
626
  if (window)
620
627
  out.window = window;
621
- const lastPostedAt = num5(raw.lastPostedAt);
628
+ const lastPostedAt = num6(raw.lastPostedAt);
622
629
  if (lastPostedAt !== undefined)
623
630
  out.lastPostedAt = lastPostedAt;
624
- if (isObject9(raw.lastPosted)) {
631
+ if (isObject10(raw.lastPosted)) {
625
632
  const lp = {};
626
- const f = num5(raw.lastPosted.fiveHour);
627
- const s = num5(raw.lastPosted.sevenDay);
628
- const sp = num5(raw.lastPosted.spendLimit);
633
+ const f = num6(raw.lastPosted.fiveHour);
634
+ const s = num6(raw.lastPosted.sevenDay);
635
+ const sp = num6(raw.lastPosted.spendLimit);
629
636
  if (f !== undefined)
630
637
  lp.fiveHour = f;
631
638
  if (s !== undefined)
@@ -634,7 +641,7 @@ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_
634
641
  lp.spendLimit = sp;
635
642
  out.lastPosted = lp;
636
643
  }
637
- const lastWallResetsAt = num5(raw.lastWallResetsAt);
644
+ const lastWallResetsAt = num6(raw.lastWallResetsAt);
638
645
  if (lastWallResetsAt !== undefined)
639
646
  out.lastWallResetsAt = lastWallResetsAt;
640
647
  const session = parseSeatSession2(raw.session);
@@ -642,9 +649,9 @@ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_
642
649
  out.session = session;
643
650
  return out;
644
651
  }, parseSeatSession2 = (v) => {
645
- if (!isObject9(v) || typeof v.id !== "string" || !v.id)
652
+ if (!isObject10(v) || typeof v.id !== "string" || !v.id)
646
653
  return;
647
- const at = num5(v.at);
654
+ const at = num6(v.at);
648
655
  if (at === undefined)
649
656
  return;
650
657
  const out = { id: v.id, at };
@@ -659,12 +666,12 @@ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_
659
666
  return null;
660
667
  try {
661
668
  const raw = JSON.parse(trimmed);
662
- if (!isObject9(raw) || typeof raw.session_id !== "string" || !raw.session_id)
669
+ if (!isObject10(raw) || typeof raw.session_id !== "string" || !raw.session_id)
663
670
  return null;
664
671
  const out = { id: raw.session_id, at: now };
665
672
  if (typeof raw.cwd === "string" && raw.cwd)
666
673
  out.cwd = raw.cwd;
667
- const model = isObject9(raw.model) ? raw.model.id : raw.model;
674
+ const model = isObject10(raw.model) ? raw.model.id : raw.model;
668
675
  if (typeof model === "string" && model)
669
676
  out.model = model;
670
677
  return out;
@@ -750,9 +757,9 @@ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_
750
757
  } catch {
751
758
  return false;
752
759
  }
753
- }, postSeatWindow2 = (o, w) => postJson2(o, "/proxy/seat", seatWindowBody2(w)), postSeatWall2 = (o, input) => postJson2(o, "/proxy/seat-wall", input), SEAT_WALL_LINE2 = "Seat limit hit. sleds on --until-reset to continue on the org key, or sleds defer to resume here at the reset.", SEAT_WALL_LINE_NO_KEY2 = "Seat limit hit. sleds defer resumes this session on this Mac at the reset; /sled 5 to hand off — this org has no platform key to switch to.", seatWallLine2 = (hasUpstreamKey) => hasUpstreamKey ? SEAT_WALL_LINE2 : SEAT_WALL_LINE_NO_KEY2, readStdin2 = (timeoutMs, stdin = process.stdin) => new Promise((resolve4) => {
760
+ }, postSeatWindow2 = (o, w) => postJson2(o, "/proxy/seat", seatWindowBody2(w)), postSeatWall2 = (o, input) => postJson2(o, "/proxy/seat-wall", input), SEAT_WALL_LINE2 = "Seat limit hit. sleds on --until-reset to continue on the org key, or sleds defer to resume here at the reset.", SEAT_WALL_LINE_NO_KEY2 = "Seat limit hit. sleds defer resumes this session on this Mac at the reset; /sled 5 to hand off — this org has no platform key to switch to.", seatWallLine2 = (hasUpstreamKey) => hasUpstreamKey ? SEAT_WALL_LINE2 : SEAT_WALL_LINE_NO_KEY2, readStdin2 = (timeoutMs, stdin = process.stdin) => new Promise((resolve5) => {
754
761
  if (stdin.isTTY) {
755
- resolve4("");
762
+ resolve5("");
756
763
  return;
757
764
  }
758
765
  let data = "";
@@ -762,7 +769,7 @@ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_
762
769
  return;
763
770
  settled = true;
764
771
  clearTimeout(timer);
765
- resolve4(data);
772
+ resolve5(data);
766
773
  };
767
774
  const timer = setTimeout(finish, timeoutMs);
768
775
  stdin.setEncoding("utf8");
@@ -793,13 +800,20 @@ import { hostname } from "node:os";
793
800
  // src/musher.ts
794
801
  import { spawnSync } from "node:child_process";
795
802
  import { createPublicKey, verify as cryptoVerify } from "node:crypto";
796
- import { dirname as dirname2, join as join4 } from "node:path";
803
+ import { basename, dirname as dirname2, join as join4 } from "node:path";
797
804
  var MUSHER_LABEL = "ai.sleds.musher";
798
805
  var MUSHER_INTERVAL_S = 300;
799
806
  var DEFAULT_PERMISSION_MODE = "acceptEdits";
800
807
  var DEFAULT_TIMEOUT_MINUTES = 90;
801
808
  var SUMMARY_MAX = 2000;
802
- var musherPlistPath = (home) => join4(home, "Library", "LaunchAgents", `${MUSHER_LABEL}.plist`);
809
+ var musherLabel = (env = process.env) => {
810
+ const sh = env.SLEDS_HOME?.trim();
811
+ if (!sh)
812
+ return MUSHER_LABEL;
813
+ const tag = basename(sh).replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]+/g, "-") || "seat";
814
+ return `${MUSHER_LABEL}.${tag}`;
815
+ };
816
+ var musherPlistPath = (home, env = process.env) => join4(home, "Library", "LaunchAgents", `${musherLabel(env)}.plist`);
803
817
  var musherLogPath = (configDir2) => join4(configDir2, "musher.log");
804
818
  var xmlEscape = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
805
819
  var musherPath = (home, execPath, currentPath = "") => {
@@ -817,6 +831,7 @@ var musherPath = (home, execPath, currentPath = "") => {
817
831
  return [...new Set(parts)].join(":");
818
832
  };
819
833
  var buildMusherPlist = (o) => {
834
+ const label = o.label ?? MUSHER_LABEL;
820
835
  const args = [...o.sledsArgv, "musher", "tick"].map((a) => ` <string>${xmlEscape(a)}</string>`).join(`
821
836
  `);
822
837
  const env = Object.entries(o.env).filter(([, v]) => v !== "").map(([k, v]) => ` <key>${xmlEscape(k)}</key>
@@ -827,7 +842,7 @@ var buildMusherPlist = (o) => {
827
842
  <plist version="1.0">
828
843
  <dict>
829
844
  <key>Label</key>
830
- <string>${MUSHER_LABEL}</string>
845
+ <string>${label}</string>
831
846
  <key>ProgramArguments</key>
832
847
  <array>
833
848
  ${args}
@@ -1036,11 +1051,11 @@ var SEAT_POST_MIN_DELTA_PCT = 1;
1036
1051
  var SEAT_POST_MIN_INTERVAL_MS = 5 * 60000;
1037
1052
  var SEAT_POST_TIMEOUT_MS = 1500;
1038
1053
  var STDIN_TIMEOUT_MS = 300;
1039
- var isObject4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1040
- var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
1054
+ var isObject5 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1055
+ var num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
1041
1056
  var EPOCH_MS_THRESHOLD = 100000000000;
1042
1057
  var parseResetsAt = (v) => {
1043
- const n = num2(v);
1058
+ const n = num3(v);
1044
1059
  if (n !== undefined) {
1045
1060
  if (n <= 0)
1046
1061
  return;
@@ -1053,29 +1068,29 @@ var parseResetsAt = (v) => {
1053
1068
  return;
1054
1069
  };
1055
1070
  var parseBar = (v) => {
1056
- if (!isObject4(v))
1071
+ if (!isObject5(v))
1057
1072
  return;
1058
- const usedPct = num2(v.used_percentage) ?? num2(v.usedPct);
1073
+ const usedPct = num3(v.used_percentage) ?? num3(v.usedPct);
1059
1074
  const resetsAt = parseResetsAt(v.resets_at ?? v.resetsAt);
1060
1075
  if (usedPct === undefined || usedPct < 0 || resetsAt === undefined)
1061
1076
  return;
1062
1077
  return { usedPct, resetsAt };
1063
1078
  };
1064
1079
  var parseSeatWindow = (raw, capturedAt) => {
1065
- if (!isObject4(raw))
1080
+ if (!isObject5(raw))
1066
1081
  return null;
1067
- const limits = isObject4(raw.rate_limits) ? raw.rate_limits : raw;
1082
+ const limits = isObject5(raw.rate_limits) ? raw.rate_limits : raw;
1068
1083
  const fiveHour = parseBar(limits.five_hour ?? limits.fiveHour);
1069
1084
  const sevenDay = parseBar(limits.seven_day ?? limits.sevenDay);
1070
1085
  const spendLimit = parseBar(limits.spend_limit ?? limits.spendLimit);
1071
1086
  const models = {};
1072
- if (isObject4(limits.models))
1087
+ if (isObject5(limits.models))
1073
1088
  for (const [k, v] of Object.entries(limits.models)) {
1074
1089
  const bar = parseBar(v);
1075
1090
  if (bar)
1076
1091
  models[k] = bar;
1077
1092
  }
1078
- const usedCreditsUsd = num2(limits.usedCreditsUsd);
1093
+ const usedCreditsUsd = num3(limits.usedCreditsUsd);
1079
1094
  const hasModels = Object.keys(models).length > 0;
1080
1095
  if (!fiveHour && !sevenDay && !spendLimit && !hasModels && usedCreditsUsd === undefined)
1081
1096
  return null;
@@ -1118,28 +1133,28 @@ var formatSeatFragment = (w) => {
1118
1133
  };
1119
1134
  var seatStatePath = (home) => join5(configDir(home), "seat.json");
1120
1135
  var parseWindowStored = (v) => {
1121
- if (!isObject4(v))
1136
+ if (!isObject5(v))
1122
1137
  return;
1123
- const capturedAt = num2(v.capturedAt);
1138
+ const capturedAt = num3(v.capturedAt);
1124
1139
  if (capturedAt === undefined)
1125
1140
  return;
1126
1141
  return parseSeatWindow(v, capturedAt) ?? undefined;
1127
1142
  };
1128
1143
  var parseSeatState = (raw) => {
1129
- if (!isObject4(raw))
1144
+ if (!isObject5(raw))
1130
1145
  return {};
1131
1146
  const out = {};
1132
1147
  const window = parseWindowStored(raw.window);
1133
1148
  if (window)
1134
1149
  out.window = window;
1135
- const lastPostedAt = num2(raw.lastPostedAt);
1150
+ const lastPostedAt = num3(raw.lastPostedAt);
1136
1151
  if (lastPostedAt !== undefined)
1137
1152
  out.lastPostedAt = lastPostedAt;
1138
- if (isObject4(raw.lastPosted)) {
1153
+ if (isObject5(raw.lastPosted)) {
1139
1154
  const lp = {};
1140
- const f = num2(raw.lastPosted.fiveHour);
1141
- const s = num2(raw.lastPosted.sevenDay);
1142
- const sp = num2(raw.lastPosted.spendLimit);
1155
+ const f = num3(raw.lastPosted.fiveHour);
1156
+ const s = num3(raw.lastPosted.sevenDay);
1157
+ const sp = num3(raw.lastPosted.spendLimit);
1143
1158
  if (f !== undefined)
1144
1159
  lp.fiveHour = f;
1145
1160
  if (s !== undefined)
@@ -1148,7 +1163,7 @@ var parseSeatState = (raw) => {
1148
1163
  lp.spendLimit = sp;
1149
1164
  out.lastPosted = lp;
1150
1165
  }
1151
- const lastWallResetsAt = num2(raw.lastWallResetsAt);
1166
+ const lastWallResetsAt = num3(raw.lastWallResetsAt);
1152
1167
  if (lastWallResetsAt !== undefined)
1153
1168
  out.lastWallResetsAt = lastWallResetsAt;
1154
1169
  const session = parseSeatSession(raw.session);
@@ -1157,9 +1172,9 @@ var parseSeatState = (raw) => {
1157
1172
  return out;
1158
1173
  };
1159
1174
  var parseSeatSession = (v) => {
1160
- if (!isObject4(v) || typeof v.id !== "string" || !v.id)
1175
+ if (!isObject5(v) || typeof v.id !== "string" || !v.id)
1161
1176
  return;
1162
- const at = num2(v.at);
1177
+ const at = num3(v.at);
1163
1178
  if (at === undefined)
1164
1179
  return;
1165
1180
  const out = { id: v.id, at };
@@ -1175,12 +1190,12 @@ var seatSessionFromStdin = (text, now) => {
1175
1190
  return null;
1176
1191
  try {
1177
1192
  const raw = JSON.parse(trimmed);
1178
- if (!isObject4(raw) || typeof raw.session_id !== "string" || !raw.session_id)
1193
+ if (!isObject5(raw) || typeof raw.session_id !== "string" || !raw.session_id)
1179
1194
  return null;
1180
1195
  const out = { id: raw.session_id, at: now };
1181
1196
  if (typeof raw.cwd === "string" && raw.cwd)
1182
1197
  out.cwd = raw.cwd;
1183
- const model = isObject4(raw.model) ? raw.model.id : raw.model;
1198
+ const model = isObject5(raw.model) ? raw.model.id : raw.model;
1184
1199
  if (typeof model === "string" && model)
1185
1200
  out.model = model;
1186
1201
  return out;
@@ -1307,11 +1322,11 @@ var readStdin = (timeoutMs, stdin = process.stdin) => new Promise((resolve3) =>
1307
1322
 
1308
1323
  // src/switch.ts
1309
1324
  init_settings();
1310
- var isObject5 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1311
- var envOf2 = (settings) => isObject5(settings.env) ? settings.env : {};
1325
+ var isObject6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1326
+ var envOf2 = (settings) => isObject6(settings.env) ? settings.env : {};
1312
1327
  var capturePriorEnv = (settings) => {
1313
1328
  const env = envOf2(settings);
1314
- const prior = { hadEnv: isObject5(settings.env) };
1329
+ const prior = { hadEnv: isObject6(settings.env) };
1315
1330
  const url = env[BASE_URL_KEY];
1316
1331
  const token = env[AUTH_TOKEN_KEY];
1317
1332
  if (typeof url === "string")
@@ -1500,7 +1515,7 @@ var findClaude = (home, configured, which) => {
1500
1515
  return null;
1501
1516
  };
1502
1517
  var musherAgentState = (home, env = process.env) => {
1503
- const plist = musherPlistPath(home);
1518
+ const plist = musherPlistPath(home, env);
1504
1519
  if (!existsSync6(plist))
1505
1520
  return { installed: false, thisSeat: false };
1506
1521
  try {
@@ -1696,7 +1711,11 @@ async function runDoctor(o) {
1696
1711
  name: "musher",
1697
1712
  detail: "agent installed for a different seat (SLEDS_HOME differs)",
1698
1713
  fix: "sleds musher --install"
1699
- } : { level: "ok", name: "musher", detail: `launchd agent ${MUSHER_LABEL}, every 5 min` });
1714
+ } : {
1715
+ level: "ok",
1716
+ name: "musher",
1717
+ detail: `launchd agent ${musherLabel(env)}, every 5 min`
1718
+ });
1700
1719
  const claude = findClaude(home, readConfig(home).musher?.claudePath, (c) => (o.which ?? defaultWhich2)(c)[0] ?? null);
1701
1720
  checks.push(claude ? { level: "ok", name: "claude cli", detail: claude } : {
1702
1721
  level: "warn",
@@ -2174,8 +2193,62 @@ var init = async (o) => {
2174
2193
  return 0;
2175
2194
  };
2176
2195
 
2177
- // src/mcp.ts
2178
- init_meter();
2196
+ // ../../packages/shared/src/mcp/server.ts
2197
+ init_format();
2198
+ function fetchClient(o) {
2199
+ const fetchFn = o.fetchFn ?? fetch;
2200
+ const base = o.proxyUrl.replace(/\/+$/, "");
2201
+ const headers = { "content-type": "application/json", authorization: `Bearer ${o.token}` };
2202
+ const timeout = () => AbortSignal.timeout(o.timeoutMs ?? MCP_TIMEOUT_MS);
2203
+ return {
2204
+ async post(path, body) {
2205
+ try {
2206
+ const res = await fetchFn(`${base}${path}`, {
2207
+ method: "POST",
2208
+ headers,
2209
+ body: JSON.stringify(body),
2210
+ signal: timeout()
2211
+ });
2212
+ if (!res.ok)
2213
+ return null;
2214
+ const parsed = await res.json();
2215
+ return isObject7(parsed) ? parsed : null;
2216
+ } catch {
2217
+ return null;
2218
+ }
2219
+ },
2220
+ async postFull(path, body) {
2221
+ try {
2222
+ const res = await fetchFn(`${base}${path}`, {
2223
+ method: "POST",
2224
+ headers,
2225
+ body: JSON.stringify(body),
2226
+ signal: timeout()
2227
+ });
2228
+ let json = null;
2229
+ try {
2230
+ json = await res.json();
2231
+ } catch {
2232
+ json = null;
2233
+ }
2234
+ return { status: res.status, json: isObject7(json) ? json : null };
2235
+ } catch {
2236
+ return null;
2237
+ }
2238
+ },
2239
+ async get(path) {
2240
+ try {
2241
+ const res = await fetchFn(`${base}${path}`, { headers, signal: timeout() });
2242
+ if (!res.ok)
2243
+ return null;
2244
+ const parsed = await res.json();
2245
+ return isObject7(parsed) ? parsed : null;
2246
+ } catch {
2247
+ return null;
2248
+ }
2249
+ }
2250
+ };
2251
+ }
2179
2252
  var PROTOCOL_VERSION = "2025-06-18";
2180
2253
  var SERVER_INFO = { name: "sleds", version: "0.0.1" };
2181
2254
  var MCP_TIMEOUT_MS = 5000;
@@ -2248,6 +2321,24 @@ var TOOLS = [
2248
2321
  required: ["task"]
2249
2322
  }
2250
2323
  },
2324
+ {
2325
+ name: "defer",
2326
+ description: "Hit a limit? Defer the work to the reset — the musher runs it then. With an org key it runs in the cloud on the pinned model; without one, the seat's own Mac resumes the last Claude Code session at the reset (sleds musher). Give `at` as +2h, +90m or an ISO time to override the binding reset.",
2327
+ inputSchema: {
2328
+ type: "object",
2329
+ properties: {
2330
+ at: {
2331
+ type: "string",
2332
+ description: "When to start: +2h, +90m, or an ISO timestamp. Omit for the binding reset."
2333
+ },
2334
+ model: { type: "string", description: "Pin the model the deferred run must use." },
2335
+ task: {
2336
+ type: "string",
2337
+ description: "Optional note on what the deferred run should finish (kept with the job)."
2338
+ }
2339
+ }
2340
+ }
2341
+ },
2251
2342
  {
2252
2343
  name: "pickup",
2253
2344
  description: "Take an open hand-off and get its context to continue here: a parked task comes back verbatim; a walled Claude Code session comes back as its first and last user messages. Marks it picked for the team.",
@@ -2259,109 +2350,37 @@ var TOOLS = [
2259
2350
  }
2260
2351
  ];
2261
2352
  var NOT_SET_UP = {
2262
- text: "SLEDS is not set up on this machine. Run `sleds init` first.",
2353
+ text: "SLEDS is not connected to a seat here. Run `sleds init` (CLI) or connect SLEDS as a connector.",
2263
2354
  isError: true
2264
2355
  };
2265
2356
  var UNREACHABLE = {
2266
2357
  text: "Control plane unreachable. Nothing was recorded → try again in a moment.",
2267
2358
  isError: true
2268
2359
  };
2269
- var isObject6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
2270
- var num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
2360
+ var isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
2361
+ var num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
2271
2362
  var str2 = (v) => typeof v === "string" ? v : undefined;
2272
- async function proxyPost(deps, path, body) {
2273
- const src = meterSource(deps.home);
2274
- if (!src)
2275
- return null;
2276
- const fetchFn = deps.fetchFn ?? fetch;
2277
- try {
2278
- const res = await fetchFn(`${src.proxyUrl}${path}`, {
2279
- method: "POST",
2280
- headers: { "content-type": "application/json", authorization: `Bearer ${src.token}` },
2281
- body: JSON.stringify(body),
2282
- signal: AbortSignal.timeout(deps.timeoutMs ?? MCP_TIMEOUT_MS)
2283
- });
2284
- if (!res.ok)
2285
- return null;
2286
- const parsed = await res.json();
2287
- return isObject6(parsed) ? parsed : null;
2288
- } catch {
2289
- return null;
2290
- }
2291
- }
2292
- async function proxyPostFull(deps, path, body) {
2293
- const src = meterSource(deps.home);
2294
- if (!src)
2295
- return null;
2296
- const fetchFn = deps.fetchFn ?? fetch;
2297
- try {
2298
- const res = await fetchFn(`${src.proxyUrl}${path}`, {
2299
- method: "POST",
2300
- headers: { "content-type": "application/json", authorization: `Bearer ${src.token}` },
2301
- body: JSON.stringify(body),
2302
- signal: AbortSignal.timeout(deps.timeoutMs ?? MCP_TIMEOUT_MS)
2303
- });
2304
- let json = null;
2305
- try {
2306
- json = await res.json();
2307
- } catch {
2308
- json = null;
2309
- }
2310
- return { status: res.status, json: isObject6(json) ? json : null };
2311
- } catch {
2312
- return null;
2313
- }
2314
- }
2315
- var errorMessage = (j) => isObject6(j?.error) ? str2(j.error.message) : undefined;
2316
- async function proxyGet(deps, path) {
2317
- const src = meterSource(deps.home);
2318
- if (!src)
2319
- return null;
2320
- const fetchFn = deps.fetchFn ?? fetch;
2321
- try {
2322
- const res = await fetchFn(`${src.proxyUrl}${path}`, {
2323
- headers: { authorization: `Bearer ${src.token}` },
2324
- signal: AbortSignal.timeout(deps.timeoutMs ?? MCP_TIMEOUT_MS)
2325
- });
2326
- if (!res.ok)
2327
- return null;
2328
- const parsed = await res.json();
2329
- return isObject6(parsed) ? parsed : null;
2330
- } catch {
2331
- return null;
2332
- }
2333
- }
2334
- async function usageTool(deps) {
2335
- if (!meterSource(deps.home))
2363
+ var errorMessage = (j) => isObject7(j?.error) ? str2(j.error.message) : undefined;
2364
+ async function usageTool(ctx) {
2365
+ if (ctx.usage)
2366
+ return ctx.usage();
2367
+ if (!ctx.client)
2336
2368
  return NOT_SET_UP;
2337
- const now = (deps.now ?? Date.now)();
2338
- const m = await loadMeter({
2339
- home: deps.home,
2340
- now,
2341
- fetchFn: deps.fetchFn,
2342
- timeoutMs: deps.timeoutMs
2343
- });
2344
- const frag = formatSeatFragment(readSeatState(deps.home).window ?? null);
2345
- if (!m) {
2346
- return {
2347
- text: frag ? `sleds offline (proxy did not answer) · ${frag}` : "sleds offline (proxy did not answer).",
2348
- isError: true
2349
- };
2350
- }
2351
- const lines = formatMeter(m, now);
2352
- if (frag)
2353
- lines.push(`${"Limits:".padEnd(12)}${frag.replace(/^seat /, "")}`);
2354
- return { text: lines.join(`
2369
+ const raw = await ctx.client.get("/proxy/meter");
2370
+ const m = raw ? parseMeter(raw) : null;
2371
+ if (!m)
2372
+ return { text: "sleds offline (proxy did not answer).", isError: true };
2373
+ return { text: formatMeter(m, (ctx.now ?? Date.now)()).join(`
2355
2374
  `) };
2356
2375
  }
2357
2376
  function bandLine(band) {
2358
- if (!isObject6(band))
2377
+ if (!isObject7(band))
2359
2378
  return null;
2360
- const low = num3(band.lowUsd);
2361
- const high = num3(band.highUsd);
2362
- const lowM = num3(band.lowMinutes);
2363
- const highM = num3(band.highMinutes);
2364
- const conf = num3(band.confidence);
2379
+ const low = num4(band.lowUsd);
2380
+ const high = num4(band.highUsd);
2381
+ const lowM = num4(band.lowMinutes);
2382
+ const highM = num4(band.highMinutes);
2383
+ const conf = num4(band.confidence);
2365
2384
  if (low === undefined || high === undefined)
2366
2385
  return null;
2367
2386
  const d = high >= 10 ? 0 : 2;
@@ -2369,26 +2388,26 @@ function bandLine(band) {
2369
2388
  const pct = conf !== undefined ? ` · ${Math.round(conf * 100)}%` : "";
2370
2389
  return `$${low.toFixed(d)}–${high.toFixed(d)}${mins}${pct}`;
2371
2390
  }
2372
- async function estimateTool(deps, args) {
2373
- if (!meterSource(deps.home))
2391
+ async function estimateTool(ctx, args) {
2392
+ if (!ctx.client)
2374
2393
  return NOT_SET_UP;
2375
2394
  const spec = str2(args.spec)?.trim();
2376
2395
  if (!spec)
2377
2396
  return { text: "Nothing to estimate. Pass spec: what the job should do.", isError: true };
2378
- const source = isObject6(args.source) && str2(args.source.kind) && str2(args.source.project) ? args.source : undefined;
2379
- const r = await proxyPost(deps, "/proxy/estimate", {
2397
+ const source = isObject7(args.source) && str2(args.source.kind) && str2(args.source.project) ? args.source : undefined;
2398
+ const r = await ctx.client.post("/proxy/estimate", {
2380
2399
  spec,
2381
2400
  model: str2(args.model),
2382
2401
  ...source ? { source } : {}
2383
2402
  });
2384
2403
  if (!r)
2385
2404
  return UNREACHABLE;
2386
- const band = isObject6(r.band) ? r.band : {};
2405
+ const band = isObject7(r.band) ? r.band : {};
2387
2406
  const line = bandLine(band) ?? "band unreadable";
2388
2407
  const method = str2(band.method) ?? "plan";
2389
- const cap = num3(band.capUsd);
2390
- const threshold = num3(r.approvalThresholdUsd);
2391
- const over = threshold !== undefined && threshold > 0 && num3(band.highUsd) !== undefined ? ` Over the ${usd(threshold)} threshold? ${num3(band.highUsd) > threshold ? "yes" : "no"}.` : "";
2408
+ const cap = num4(band.capUsd);
2409
+ const threshold = num4(r.approvalThresholdUsd);
2410
+ const over = threshold !== undefined && threshold > 0 && num4(band.highUsd) !== undefined ? ` Over the ${usd(threshold)} threshold? ${num4(band.highUsd) > threshold ? "yes" : "no"}.` : "";
2392
2411
  const assumptions = Array.isArray(band.assumptions) ? band.assumptions.filter((a) => typeof a === "string") : [];
2393
2412
  const tail = assumptions.length > 0 ? `
2394
2413
  Assumes: ${assumptions.join("; ")}.` : "";
@@ -2406,11 +2425,11 @@ function byModelText(raw) {
2406
2425
  return "";
2407
2426
  const parts = [];
2408
2427
  for (const row2 of raw) {
2409
- if (!isObject6(row2) || !isObject6(row2.standard))
2428
+ if (!isObject7(row2) || !isObject7(row2.standard))
2410
2429
  continue;
2411
2430
  const model = str2(row2.model);
2412
- const low = num3(row2.standard.lowUsd);
2413
- const high = num3(row2.standard.highUsd);
2431
+ const low = num4(row2.standard.lowUsd);
2432
+ const high = num4(row2.standard.highUsd);
2414
2433
  if (!model || low === undefined || high === undefined)
2415
2434
  continue;
2416
2435
  const m = /^claude-([a-z]+)-(\d+)(?:-(\d+))?/.exec(model);
@@ -2421,7 +2440,7 @@ function byModelText(raw) {
2421
2440
  By model: ${parts.join(" · ")} (overnight batch ½).` : "";
2422
2441
  }
2423
2442
  function routingText(raw) {
2424
- if (!isObject6(raw) || !Array.isArray(raw.segments) || !isObject6(raw.cost))
2443
+ if (!isObject7(raw) || !Array.isArray(raw.segments) || !isObject7(raw.cost))
2425
2444
  return "";
2426
2445
  const short = (model) => {
2427
2446
  const m = /^claude-([a-z]+)-(\d+)(?:-(\d+))?/.exec(model);
@@ -2429,10 +2448,10 @@ function routingText(raw) {
2429
2448
  };
2430
2449
  const parts = [];
2431
2450
  for (const s of raw.segments) {
2432
- if (!isObject6(s))
2451
+ if (!isObject7(s))
2433
2452
  continue;
2434
- const from = num3(s.from);
2435
- const to = num3(s.to);
2453
+ const from = num4(s.from);
2454
+ const to = num4(s.to);
2436
2455
  const model = str2(s.model);
2437
2456
  if (from === undefined || to === undefined || !model)
2438
2457
  continue;
@@ -2440,55 +2459,55 @@ function routingText(raw) {
2440
2459
  parts.push(`${from === to ? from : `${from}–${to}`} ${short(model)}${reasons.length ? ` (${reasons.slice(0, 3).join(", ")})` : ""}`);
2441
2460
  }
2442
2461
  const c = raw.cost;
2443
- const lo = num3(c.lowUsd);
2444
- const hi = num3(c.highUsd);
2445
- const slo = num3(c.singleLowUsd);
2446
- const shi = num3(c.singleHighUsd);
2462
+ const lo = num4(c.lowUsd);
2463
+ const hi = num4(c.highUsd);
2464
+ const slo = num4(c.singleLowUsd);
2465
+ const shi = num4(c.singleHighUsd);
2447
2466
  const single = str2(c.singleModel);
2448
2467
  if (parts.length === 0 || lo === undefined || hi === undefined || slo === undefined || shi === undefined || !single)
2449
2468
  return "";
2450
2469
  return `
2451
2470
  Routing: ${parts.join(" · ")} ≈ ${usdRange(lo, hi)} vs ${usdRange(slo, shi)} all ${short(single)}.`;
2452
2471
  }
2453
- async function overnightTool(deps, args) {
2454
- if (!meterSource(deps.home))
2472
+ async function overnightTool(ctx, args) {
2473
+ if (!ctx.client)
2455
2474
  return NOT_SET_UP;
2456
2475
  const spec = str2(args.spec)?.trim();
2457
2476
  if (!spec)
2458
2477
  return { text: "Nothing to queue. Pass spec: what the job should do.", isError: true };
2459
- const r = await proxyPost(deps, "/proxy/overnight", { spec, model: str2(args.model) });
2478
+ const r = await ctx.client.post("/proxy/overnight", { spec, model: str2(args.model) });
2460
2479
  if (!r)
2461
2480
  return { text: `Could not queue the job. ${UNREACHABLE.text}`, isError: true };
2462
2481
  const jobId = str2(r.jobId) ?? "unknown";
2463
- const now = (deps.now ?? Date.now)();
2464
- const at = num3(r.scheduledAt);
2482
+ const now = (ctx.now ?? Date.now)();
2483
+ const at = num4(r.scheduledAt);
2465
2484
  const when = at !== undefined && at > now ? `Runs in ${shortDuration(at - now)}` : "Runs at the next tick";
2466
2485
  const band = bandLine(r.band);
2467
- const cap = isObject6(r.band) ? num3(r.band.capUsd) : undefined;
2486
+ const cap = isObject7(r.band) ? num4(r.band.capUsd) : undefined;
2468
2487
  const sized = band ? ` ${band}${cap !== undefined ? ` · cap ${usd(cap)}` : ""}.` : "";
2469
2488
  return {
2470
2489
  text: `Queued overnight. Batch tier · ½ price.${sized} ${when}. Check with the jobs tool; pull the result into a session with /sled resume ${jobId}.`
2471
2490
  };
2472
2491
  }
2473
- async function jobsTool(deps) {
2474
- if (!meterSource(deps.home))
2492
+ async function jobsTool(ctx) {
2493
+ if (!ctx.client)
2475
2494
  return NOT_SET_UP;
2476
- const r = await proxyGet(deps, "/proxy/jobs");
2495
+ const r = await ctx.client.get("/proxy/jobs");
2477
2496
  if (!r)
2478
2497
  return UNREACHABLE;
2479
- const rows = Array.isArray(r.jobs) ? r.jobs.filter(isObject6) : [];
2480
- const handoffs = Array.isArray(r.handoffs) ? r.handoffs.filter(isObject6) : [];
2481
- const now = (deps.now ?? Date.now)();
2498
+ const rows = Array.isArray(r.jobs) ? r.jobs.filter(isObject7) : [];
2499
+ const handoffs = Array.isArray(r.handoffs) ? r.handoffs.filter(isObject7) : [];
2500
+ const now = (ctx.now ?? Date.now)();
2482
2501
  if (rows.length === 0 && handoffs.length === 0)
2483
2502
  return { text: "No jobs for this seat. Queue one with the overnight tool." };
2484
2503
  if (rows.length === 0)
2485
2504
  return { text: ["No jobs for this seat.", ...handoffLines(handoffs, now)].join(`
2486
2505
  `) };
2487
2506
  const lines = rows.map((j) => {
2488
- const when = (ts) => num3(ts) !== undefined ? shortDuration(Math.abs(now - num3(ts))) : "";
2507
+ const when = (ts) => num4(ts) !== undefined ? shortDuration(Math.abs(now - num4(ts))) : "";
2489
2508
  const status = str2(j.status) ?? "unknown";
2490
- const cost = num3(j.costUsd);
2491
- const tail = status === "delivered" ? `delivered ${when(j.deliveredAt)} ago` : status === "scheduled" ? num3(j.scheduledAt) !== undefined && num3(j.scheduledAt) > now ? `runs in ${when(j.scheduledAt)}` : "runs at the next tick" : str2(j.reason) ?? "";
2509
+ const cost = num4(j.costUsd);
2510
+ const tail = status === "delivered" ? `delivered ${when(j.deliveredAt)} ago` : status === "scheduled" ? num4(j.scheduledAt) !== undefined && num4(j.scheduledAt) > now ? `runs in ${when(j.scheduledAt)}` : "runs at the next tick" : str2(j.reason) ?? "";
2492
2511
  return [
2493
2512
  str2(j.jobId) ?? "?",
2494
2513
  status.padEnd(12),
@@ -2510,7 +2529,7 @@ function handoffLines(handoffs, now) {
2510
2529
  const forMe = h.forMe === true;
2511
2530
  const to = str2(h.to);
2512
2531
  const who = forMe ? to ? "for you" : "parked for anyone" : `for ${to ?? "anyone"}`;
2513
- const created = num3(h.createdAt);
2532
+ const created = num4(h.createdAt);
2514
2533
  const age = created !== undefined ? `${shortDuration(Math.max(0, now - created))} ago` : "";
2515
2534
  const note = str2(h.note);
2516
2535
  const parts = [`from ${str2(h.from) ?? "?"}`, who, str2(h.wallKind) ?? "", age].filter(Boolean);
@@ -2521,16 +2540,16 @@ function handoffLines(handoffs, now) {
2521
2540
  out.push("Take one in Claude Code with /sled pickup <id>.");
2522
2541
  return out;
2523
2542
  }
2524
- async function handoffsTool(deps) {
2525
- if (!meterSource(deps.home))
2543
+ async function handoffsTool(ctx) {
2544
+ if (!ctx.client)
2526
2545
  return NOT_SET_UP;
2527
- const r = await proxyGet(deps, "/proxy/jobs");
2546
+ const r = await ctx.client.get("/proxy/jobs");
2528
2547
  if (!r)
2529
2548
  return UNREACHABLE;
2530
- const handoffs = Array.isArray(r.handoffs) ? r.handoffs.filter(isObject6) : [];
2549
+ const handoffs = Array.isArray(r.handoffs) ? r.handoffs.filter(isObject7) : [];
2531
2550
  if (handoffs.length === 0)
2532
2551
  return { text: "No open hand-offs on your team. Park one with the handoff tool." };
2533
- const now = (deps.now ?? Date.now)();
2552
+ const now = (ctx.now ?? Date.now)();
2534
2553
  const packets = handoffs.map((h) => str2(h.packet)).filter((p) => Boolean(p)).join(`
2535
2554
 
2536
2555
  ---
@@ -2543,14 +2562,14 @@ ${packets}` : ""].join(`
2543
2562
  `)
2544
2563
  };
2545
2564
  }
2546
- async function handoffTool(deps, args) {
2547
- if (!meterSource(deps.home))
2565
+ async function handoffTool(ctx, args) {
2566
+ if (!ctx.client)
2548
2567
  return NOT_SET_UP;
2549
2568
  const task = str2(args.task)?.trim();
2550
2569
  if (!task)
2551
2570
  return { text: "Nothing to hand off. Pass task: what the picker should do.", isError: true };
2552
2571
  const to = str2(args.to)?.trim();
2553
- const r = await proxyPostFull(deps, "/proxy/handoff/park", {
2572
+ const r = await ctx.client.postFull("/proxy/handoff/park", {
2554
2573
  task,
2555
2574
  to: to || undefined,
2556
2575
  note: str2(args.note)?.trim() || undefined
@@ -2569,13 +2588,13 @@ async function handoffTool(deps, args) {
2569
2588
  text: `${to ? `Handed off to ${to}` : "Parked for the team"}. They take it in Claude Code with /sled pickup ${id}, or with the pickup tool here. The team was told on Slack.`
2570
2589
  };
2571
2590
  }
2572
- async function pickupTool(deps, args) {
2573
- if (!meterSource(deps.home))
2591
+ async function pickupTool(ctx, args) {
2592
+ if (!ctx.client)
2574
2593
  return NOT_SET_UP;
2575
2594
  const handoffId = str2(args.handoffId)?.trim();
2576
2595
  if (!handoffId)
2577
2596
  return { text: "Pass handoffId, from the handoffs tool.", isError: true };
2578
- const r = await proxyPostFull(deps, "/proxy/handoff/pickup", { handoffId });
2597
+ const r = await ctx.client.postFull("/proxy/handoff/pickup", { handoffId });
2579
2598
  if (!r)
2580
2599
  return { text: `Nothing was picked up. ${UNREACHABLE.text}`, isError: true };
2581
2600
  if (r.status !== 200)
@@ -2596,7 +2615,7 @@ ${str2(j.task) ?? ""}
2596
2615
  Carry it through from here.` };
2597
2616
  const first = str2(j.firstUserText) ?? "";
2598
2617
  const last = str2(j.lastUserText) ?? "";
2599
- const n = num3(j.messageCount);
2618
+ const n = num4(j.messageCount);
2600
2619
  return {
2601
2620
  text: [
2602
2621
  `${head} This was a Claude Code session${n !== undefined ? ` (${n} messages)` : ""} that hit a wall; its snapshot can also be replayed in Claude Code with /sled pickup ${handoffId} — but it is now marked picked by you.`,
@@ -2611,29 +2630,60 @@ ${last}`] : [],
2611
2630
  `)
2612
2631
  };
2613
2632
  }
2614
- async function callTool(name, args, deps) {
2633
+ function parseAt2(v, now) {
2634
+ const rel = /^\+(\d+)([hm])$/.exec(v.trim());
2635
+ if (rel)
2636
+ return now + Number.parseInt(rel[1] ?? "0", 10) * (rel[2] === "h" ? 3600000 : 60000);
2637
+ const t = Date.parse(v);
2638
+ return Number.isFinite(t) ? t : undefined;
2639
+ }
2640
+ async function deferTool(ctx, args) {
2641
+ if (!ctx.client)
2642
+ return NOT_SET_UP;
2643
+ const now = (ctx.now ?? Date.now)();
2644
+ const atRaw = str2(args.at)?.trim();
2645
+ const at = atRaw ? parseAt2(atRaw, now) : undefined;
2646
+ if (atRaw && at === undefined)
2647
+ return { text: "`at` takes +2h, +90m or an ISO time.", isError: true };
2648
+ const r = await ctx.client.post("/proxy/defer", {
2649
+ ...at !== undefined ? { resetAt: at } : {},
2650
+ ...str2(args.model) ? { model: str2(args.model) } : {},
2651
+ host: "mcp"
2652
+ });
2653
+ if (!r)
2654
+ return { text: `Nothing was deferred. ${UNREACHABLE.text}`, isError: true };
2655
+ const jobId = str2(r.jobId) ?? "unknown";
2656
+ const when = num4(r.scheduledAt);
2657
+ const startsIn = when !== undefined && when > now + 60000 ? `starts in ${shortDuration(when - now)}` : "starts at the next musher tick (within 5 min)";
2658
+ return {
2659
+ text: `Deferred. Job ${jobId} ${startsIn}. With no org key it runs on the seat's own Mac (sleds musher must be installed there — sleds doctor checks); with a key, in the cloud. Watch it with the jobs tool or /sled jobs.${str2(args.task) ? ` Note kept: ${str2(args.task)}` : ""}`
2660
+ };
2661
+ }
2662
+ async function callTool(name, args, ctx) {
2615
2663
  switch (name) {
2616
2664
  case "usage":
2617
- return usageTool(deps);
2665
+ return usageTool(ctx);
2618
2666
  case "estimate":
2619
- return estimateTool(deps, args);
2667
+ return estimateTool(ctx, args);
2620
2668
  case "overnight":
2621
- return overnightTool(deps, args);
2669
+ return overnightTool(ctx, args);
2622
2670
  case "jobs":
2623
- return jobsTool(deps);
2671
+ return jobsTool(ctx);
2624
2672
  case "handoffs":
2625
- return handoffsTool(deps);
2673
+ return handoffsTool(ctx);
2626
2674
  case "handoff":
2627
- return handoffTool(deps, args);
2675
+ return handoffTool(ctx, args);
2628
2676
  case "pickup":
2629
- return pickupTool(deps, args);
2677
+ return pickupTool(ctx, args);
2678
+ case "defer":
2679
+ return deferTool(ctx, args);
2630
2680
  default:
2631
2681
  return { text: `Unknown tool: ${name}`, isError: true };
2632
2682
  }
2633
2683
  }
2634
2684
  var response = (id, result) => JSON.stringify({ jsonrpc: "2.0", id, result });
2635
2685
  var errorResponse = (id, code, message) => JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
2636
- async function handleLine(line, deps) {
2686
+ async function handleLine(line, ctx) {
2637
2687
  const trimmed = line.trim();
2638
2688
  if (trimmed.length === 0)
2639
2689
  return null;
@@ -2643,7 +2693,7 @@ async function handleLine(line, deps) {
2643
2693
  } catch {
2644
2694
  return errorResponse(null, -32700, "parse error");
2645
2695
  }
2646
- if (!isObject6(msg))
2696
+ if (!isObject7(msg))
2647
2697
  return errorResponse(null, -32600, "invalid request");
2648
2698
  const id = typeof msg.id === "string" || typeof msg.id === "number" ? msg.id : null;
2649
2699
  const method = str2(msg.method);
@@ -2652,7 +2702,7 @@ async function handleLine(line, deps) {
2652
2702
  return isNotification ? null : errorResponse(id, -32600, "invalid request");
2653
2703
  if (method.startsWith("notifications/"))
2654
2704
  return null;
2655
- const params = isObject6(msg.params) ? msg.params : {};
2705
+ const params = isObject7(msg.params) ? msg.params : {};
2656
2706
  switch (method) {
2657
2707
  case "initialize": {
2658
2708
  const requested = str2(params.protocolVersion);
@@ -2668,8 +2718,8 @@ async function handleLine(line, deps) {
2668
2718
  return response(id, { tools: TOOLS });
2669
2719
  case "tools/call": {
2670
2720
  const name = str2(params.name) ?? "";
2671
- const args = isObject6(params.arguments) ? params.arguments : {};
2672
- const r = await callTool(name, args, deps);
2721
+ const args = isObject7(params.arguments) ? params.arguments : {};
2722
+ const r = await callTool(name, args, ctx);
2673
2723
  return response(id, {
2674
2724
  content: [{ type: "text", text: r.text }],
2675
2725
  ...r.isError ? { isError: true } : {}
@@ -2680,6 +2730,38 @@ async function handleLine(line, deps) {
2680
2730
  }
2681
2731
  }
2682
2732
 
2733
+ // src/mcp.ts
2734
+ init_meter();
2735
+ async function usageTool2(deps) {
2736
+ if (!meterSource(deps.home))
2737
+ return { text: "SLEDS is not set up on this machine. Run `sleds init` first.", isError: true };
2738
+ const now = (deps.now ?? Date.now)();
2739
+ const m = await loadMeter({
2740
+ home: deps.home,
2741
+ now,
2742
+ fetchFn: deps.fetchFn,
2743
+ timeoutMs: deps.timeoutMs
2744
+ });
2745
+ const frag = formatSeatFragment(readSeatState(deps.home).window ?? null);
2746
+ if (!m) {
2747
+ return {
2748
+ text: frag ? `sleds offline (proxy did not answer) · ${frag}` : "sleds offline (proxy did not answer).",
2749
+ isError: true
2750
+ };
2751
+ }
2752
+ const lines = formatMeter(m, now);
2753
+ if (frag)
2754
+ lines.push(`${"Limits:".padEnd(12)}${frag.replace(/^seat /, "")}`);
2755
+ return { text: lines.join(`
2756
+ `) };
2757
+ }
2758
+ function contextFor(deps) {
2759
+ const src = meterSource(deps.home);
2760
+ const client = src ? fetchClient({ ...src, fetchFn: deps.fetchFn, timeoutMs: deps.timeoutMs }) : null;
2761
+ return { client, now: deps.now, usage: () => usageTool2(deps) };
2762
+ }
2763
+ var handleLine2 = (line, deps) => handleLine(line, contextFor(deps));
2764
+
2683
2765
  // src/commands/mcp.ts
2684
2766
  var mcp = async (o) => {
2685
2767
  const stdin = o.stdin ?? process.stdin;
@@ -2693,7 +2775,7 @@ var mcp = async (o) => {
2693
2775
  while (nl !== -1) {
2694
2776
  const line = buffer.slice(0, nl);
2695
2777
  buffer = buffer.slice(nl + 1);
2696
- const out = await handleLine(line, { home: o.home });
2778
+ const out = await handleLine2(line, { home: o.home });
2697
2779
  if (out !== null)
2698
2780
  write(out);
2699
2781
  nl = buffer.indexOf(`
@@ -2701,7 +2783,7 @@ var mcp = async (o) => {
2701
2783
  }
2702
2784
  }
2703
2785
  if (buffer.trim().length > 0) {
2704
- const out = await handleLine(buffer, { home: o.home });
2786
+ const out = await handleLine2(buffer, { home: o.home });
2705
2787
  if (out !== null)
2706
2788
  write(out);
2707
2789
  }
@@ -2770,7 +2852,8 @@ var musherInstall = (o) => {
2770
2852
  return 1;
2771
2853
  }
2772
2854
  const env = o.env ?? process.env;
2773
- const plist = musherPlistPath(o.home);
2855
+ const plist = musherPlistPath(o.home, env);
2856
+ const label = musherLabel(env);
2774
2857
  const dir = configDir(o.home, env);
2775
2858
  mkdirSync7(dirname3(plist), { recursive: true });
2776
2859
  mkdirSync7(dir, { recursive: true, mode: 448 });
@@ -2784,7 +2867,7 @@ var musherInstall = (o) => {
2784
2867
  const exec = o.exec ?? defaultExecSync;
2785
2868
  if (existsSync8(plist))
2786
2869
  exec("launchctl", ["unload", plist]);
2787
- writeFileSync7(plist, buildMusherPlist({ sledsArgv: o.sledsArgv, env: agentEnv, logPath: musherLogPath(dir) }));
2870
+ writeFileSync7(plist, buildMusherPlist({ sledsArgv: o.sledsArgv, env: agentEnv, logPath: musherLogPath(dir), label }));
2788
2871
  const r = exec("launchctl", ["load", plist]);
2789
2872
  if (!r.ok) {
2790
2873
  error(`launchctl load failed: ${r.stderr.trim() || "unknown"}`);
@@ -2793,19 +2876,20 @@ var musherInstall = (o) => {
2793
2876
  const cfg = readConfig(o.home);
2794
2877
  writeConfig(o.home, { ...cfg, musher: { ...cfg.musher ?? {}, agent: "launchd" } });
2795
2878
  const claude = findClaude2(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich3);
2796
- log(`musher installed: launchd agent ${MUSHER_LABEL}, every ${5} min · log ${musherLogPath(dir)}`);
2879
+ log(`musher installed: launchd agent ${label}, every 5 min · log ${musherLogPath(dir)}`);
2797
2880
  if (!claude)
2798
2881
  log("warn: `claude` not found on PATH — set it with `sleds musher --claude /path/to/claude`");
2799
2882
  return 0;
2800
2883
  };
2801
2884
  var musherUninstall = (o) => {
2802
2885
  const log = o.log ?? console.log;
2803
- const plist = musherPlistPath(o.home);
2886
+ const env = o.env ?? process.env;
2887
+ const plist = musherPlistPath(o.home, env);
2804
2888
  const exec = o.exec ?? defaultExecSync;
2805
2889
  if (existsSync8(plist)) {
2806
2890
  exec("launchctl", ["unload", plist]);
2807
2891
  rmSync2(plist, { force: true });
2808
- log(`musher removed: ${MUSHER_LABEL}`);
2892
+ log(`musher removed: ${musherLabel(env)}`);
2809
2893
  } else
2810
2894
  log("musher was not installed.");
2811
2895
  const cfg = readConfig(o.home);
@@ -2834,9 +2918,10 @@ var clientFor = (o) => {
2834
2918
  var musherStatus = async (o) => {
2835
2919
  const log = o.log ?? console.log;
2836
2920
  const now = (o.now ?? Date.now)();
2837
- const plist = musherPlistPath(o.home);
2921
+ const env = o.env ?? process.env;
2922
+ const plist = musherPlistPath(o.home, env);
2838
2923
  const cfg = readConfig(o.home);
2839
- log(existsSync8(plist) ? `agent ${MUSHER_LABEL} installed (${plist})` : "agent not installed — sleds musher --install");
2924
+ log(existsSync8(plist) ? `agent ${musherLabel(env)} installed (${plist})` : "agent not installed — sleds musher --install");
2840
2925
  const claude = findClaude2(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich3);
2841
2926
  log(`claude ${claude ?? "not found — sleds musher --claude /path/to/claude"}`);
2842
2927
  log(`mode ${cfg.musher?.permissionMode ?? DEFAULT_PERMISSION_MODE} · timeout ${cfg.musher?.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES} min`);
@@ -3210,11 +3295,11 @@ init_config();
3210
3295
  init_meter();
3211
3296
  var HOOK_STDIN_TIMEOUT_MS = 1000;
3212
3297
  var NOTIFICATION_TITLE = "sleds";
3213
- var isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3298
+ var isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3214
3299
  var notificationType = (text) => {
3215
3300
  try {
3216
3301
  const raw = JSON.parse(text);
3217
- if (!isObject7(raw))
3302
+ if (!isObject8(raw))
3218
3303
  return;
3219
3304
  return typeof raw.notification_type === "string" ? raw.notification_type : undefined;
3220
3305
  } catch {
@@ -3389,8 +3474,8 @@ function resolveProfileDir(localStateJson, profile) {
3389
3474
  if (localStateJson) {
3390
3475
  try {
3391
3476
  const raw = JSON.parse(localStateJson);
3392
- const p = isObject8(raw) && isObject8(raw.profile) ? raw.profile : null;
3393
- if (p && isObject8(p.info_cache))
3477
+ const p = isObject9(raw) && isObject9(raw.profile) ? raw.profile : null;
3478
+ if (p && isObject9(p.info_cache))
3394
3479
  cache = p.info_cache;
3395
3480
  } catch {}
3396
3481
  }
@@ -3399,7 +3484,7 @@ function resolveProfileDir(localStateJson, profile) {
3399
3484
  const want = profile.toLowerCase();
3400
3485
  const hits = [];
3401
3486
  for (const [dir, info] of Object.entries(cache)) {
3402
- if (!isObject8(info))
3487
+ if (!isObject9(info))
3403
3488
  continue;
3404
3489
  const match = ["name", "user_name", "gaia_name"].some((k) => {
3405
3490
  const v = info[k];
@@ -3437,23 +3522,23 @@ function sourceArgs(source) {
3437
3522
  out.push("--token", source.token);
3438
3523
  return out;
3439
3524
  }
3440
- var isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3441
- var num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
3525
+ var isObject9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3526
+ var num5 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
3442
3527
  var round2 = (n) => Math.round(n * 100) / 100;
3443
3528
  function parseUsageResponse(raw, now = Date.now()) {
3444
- if (!isObject8(raw))
3529
+ if (!isObject9(raw))
3445
3530
  return null;
3446
3531
  const out = { capturedAt: now, models: {} };
3447
3532
  for (const [k, v] of Object.entries(raw)) {
3448
- if (!isObject8(v))
3533
+ if (!isObject9(v))
3449
3534
  continue;
3450
3535
  if (k === "extra_usage") {
3451
- const credits = num4(v.used_credits);
3536
+ const credits = num5(v.used_credits);
3452
3537
  if (credits !== undefined)
3453
3538
  out.usedCreditsUsd = round2(credits / 100);
3454
3539
  continue;
3455
3540
  }
3456
- const usedPct = num4(v.utilization);
3541
+ const usedPct = num5(v.utilization);
3457
3542
  const resetsAt = parseResetsAt(v.resets_at);
3458
3543
  if (usedPct === undefined || usedPct < 0 || resetsAt === undefined)
3459
3544
  continue;
@@ -3797,7 +3882,7 @@ async function postSeat(proxyUrl, token, body, fetchFn) {
3797
3882
  // src/commands/specEvent.ts
3798
3883
  init_meter();
3799
3884
  import { readFileSync as readFileSync9, statSync } from "node:fs";
3800
- import { basename, isAbsolute, relative } from "node:path";
3885
+ import { basename as basename2, isAbsolute, relative } from "node:path";
3801
3886
  var HOOK_STDIN_TIMEOUT_MS2 = 1000;
3802
3887
  var ESTIMATE_TIMEOUT_MS = 4000;
3803
3888
  var MIN_SPEC_CHARS = 200;
@@ -3810,12 +3895,12 @@ function isSpecPath(path) {
3810
3895
  return false;
3811
3896
  if (NOT_SPEC.test(path))
3812
3897
  return false;
3813
- return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename(path));
3898
+ return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename2(path));
3814
3899
  }
3815
3900
  function specTitle(body, path) {
3816
3901
  const m = /^#\s+(.+?)\s*$/m.exec(body);
3817
3902
  const t = m?.[1]?.trim();
3818
- return (t && t.length > 0 ? t : basename(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
3903
+ return (t && t.length > 0 ? t : basename2(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
3819
3904
  }
3820
3905
  function looksLikeSpec(body) {
3821
3906
  if (body.trim().length < MIN_SPEC_CHARS)
@@ -3873,7 +3958,7 @@ var specEvent = async (o) => {
3873
3958
  const spec = {
3874
3959
  title: specTitle(body, input.filePath),
3875
3960
  body: body.slice(0, MAX_SPEC_CHARS),
3876
- repoHint: input.cwd ? basename(input.cwd) : undefined
3961
+ repoHint: input.cwd ? basename2(input.cwd) : undefined
3877
3962
  };
3878
3963
  try {
3879
3964
  const res = await (o.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
@@ -4136,7 +4221,7 @@ var uninstall2 = (o) => {
4136
4221
  if (existsSync12(plist)) {
4137
4222
  (o.unloadAgent ?? defaultUnload)(plist);
4138
4223
  rmSync5(plist, { force: true });
4139
- removed.push(`launchd agent ${MUSHER_LABEL}`);
4224
+ removed.push(`launchd agent ${musherLabel()}`);
4140
4225
  }
4141
4226
  if (removed.length === 0) {
4142
4227
  log("Nothing to remove; SLEDS was not installed.");
@@ -4212,6 +4297,21 @@ var defaultExec = (cmd, args) => {
4212
4297
  return { ok: r.status === 0, stderr: r.stderr ?? "" };
4213
4298
  };
4214
4299
 
4300
+ // src/settings.ts
4301
+ import { dirname as dirname4, join as join10, resolve as resolve4 } from "node:path";
4302
+ var withSeatEnv2 = (command, home, env = process.env) => {
4303
+ const parts = [];
4304
+ const sh = env.SLEDS_HOME?.trim();
4305
+ const cc = env.CLAUDE_CONFIG_DIR?.trim();
4306
+ if (sh)
4307
+ parts.push(`SLEDS_HOME=${shellWord2(resolve4(home, sh))}`);
4308
+ if (cc)
4309
+ parts.push(`CLAUDE_CONFIG_DIR=${shellWord2(resolve4(home, cc))}`);
4310
+ parts.push(command);
4311
+ return parts.join(" ");
4312
+ };
4313
+ var shellWord2 = (v) => /^[\w./~-]+$/.test(v) ? v : `'${v.replace(/'/g, "'\\''")}'`;
4314
+
4215
4315
  // src/index.ts
4216
4316
  var USAGE = `usage: sleds <command> [options]
4217
4317
 
@@ -4309,9 +4409,9 @@ var sledsArgv = () => {
4309
4409
  return script ? [process.execPath, script] : [process.execPath];
4310
4410
  };
4311
4411
  var shellQuote = (s) => /^[\w./-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
4312
- var statusLineCommand = (argv) => [...argv, "statusline"].map(shellQuote).join(" ");
4313
- var seatEventCommand = (argv) => [...argv, "seat-event"].map(shellQuote).join(" ");
4314
- var specEventCommand = (argv) => [...argv, "spec-event"].map(shellQuote).join(" ");
4412
+ var statusLineCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "statusline"].map(shellQuote).join(" "), home);
4413
+ var seatEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "seat-event"].map(shellQuote).join(" "), home);
4414
+ var specEventCommand = (argv, home = homedir()) => withSeatEnv2([...argv, "spec-event"].map(shellQuote).join(" "), home);
4315
4415
  var main = async (argv) => {
4316
4416
  const { cmd, flags } = parseArgs(argv);
4317
4417
  const home = homedir();
@@ -4403,7 +4503,7 @@ var main = async (argv) => {
4403
4503
  case "version":
4404
4504
  case "--version":
4405
4505
  case "-v":
4406
- console.log("sleds 0.1.14");
4506
+ console.log("sleds 0.1.16");
4407
4507
  return 0;
4408
4508
  default:
4409
4509
  console.error(`unknown command: ${cmd}
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@sleds/cli",
3
- "version": "0.1.14",
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.",
3
+ "version": "0.1.16",
4
+ "description": "SLEDS CLI \u2014 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",
7
- "bin": { "sleds": "dist/sleds.mjs" },
7
+ "bin": {
8
+ "sleds": "dist/sleds.mjs"
9
+ },
8
10
  "files": ["dist/sleds.mjs", "README.md"],
9
- "engines": { "node": ">=22.5" },
11
+ "engines": {
12
+ "node": ">=22.5"
13
+ },
10
14
  "os": ["darwin", "linux"],
11
15
  "repository": {
12
16
  "type": "git",
@@ -24,12 +28,19 @@
24
28
  "batch",
25
29
  "mcp"
26
30
  ],
27
- "publishConfig": { "access": "restricted" },
31
+ "publishConfig": {
32
+ "access": "restricted"
33
+ },
28
34
  "scripts": {
29
35
  "build": "bun scripts/build.ts",
30
36
  "prepack": "bun scripts/build.ts",
31
37
  "typecheck": "tsc --noEmit",
32
38
  "test": "vitest run"
33
39
  },
34
- "devDependencies": { "@types/bun": "^1.1.13", "typescript": "^5.6.3", "vitest": "^2.1.4" }
40
+ "devDependencies": {
41
+ "@types/bun": "^1.1.13",
42
+ "typescript": "^5.6.3",
43
+ "vitest": "^2.1.4",
44
+ "@sleds/shared": "workspace:*"
45
+ }
35
46
  }