@sleds/cli 0.1.15 → 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 +297 -227
  2. package/package.json +17 -6
package/dist/sleds.mjs CHANGED
@@ -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
@@ -532,8 +539,8 @@ __export(exports_seat, {
532
539
  });
533
540
  import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync10, renameSync as renameSync5, writeFileSync as writeFileSync10 } from "node:fs";
534
541
  import { join as join11 } 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);
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;
@@ -605,27 +612,27 @@ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_
605
612
  return null;
606
613
  return `seat ${parts.join(SEP)}`;
607
614
  }, seatStatePath2 = (home) => join11(configDir(home), "seat.json"), parseWindowStored2 = (v) => {
608
- if (!isObject9(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;
@@ -1044,11 +1051,11 @@ var SEAT_POST_MIN_DELTA_PCT = 1;
1044
1051
  var SEAT_POST_MIN_INTERVAL_MS = 5 * 60000;
1045
1052
  var SEAT_POST_TIMEOUT_MS = 1500;
1046
1053
  var STDIN_TIMEOUT_MS = 300;
1047
- var isObject4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1048
- 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;
1049
1056
  var EPOCH_MS_THRESHOLD = 100000000000;
1050
1057
  var parseResetsAt = (v) => {
1051
- const n = num2(v);
1058
+ const n = num3(v);
1052
1059
  if (n !== undefined) {
1053
1060
  if (n <= 0)
1054
1061
  return;
@@ -1061,29 +1068,29 @@ var parseResetsAt = (v) => {
1061
1068
  return;
1062
1069
  };
1063
1070
  var parseBar = (v) => {
1064
- if (!isObject4(v))
1071
+ if (!isObject5(v))
1065
1072
  return;
1066
- const usedPct = num2(v.used_percentage) ?? num2(v.usedPct);
1073
+ const usedPct = num3(v.used_percentage) ?? num3(v.usedPct);
1067
1074
  const resetsAt = parseResetsAt(v.resets_at ?? v.resetsAt);
1068
1075
  if (usedPct === undefined || usedPct < 0 || resetsAt === undefined)
1069
1076
  return;
1070
1077
  return { usedPct, resetsAt };
1071
1078
  };
1072
1079
  var parseSeatWindow = (raw, capturedAt) => {
1073
- if (!isObject4(raw))
1080
+ if (!isObject5(raw))
1074
1081
  return null;
1075
- const limits = isObject4(raw.rate_limits) ? raw.rate_limits : raw;
1082
+ const limits = isObject5(raw.rate_limits) ? raw.rate_limits : raw;
1076
1083
  const fiveHour = parseBar(limits.five_hour ?? limits.fiveHour);
1077
1084
  const sevenDay = parseBar(limits.seven_day ?? limits.sevenDay);
1078
1085
  const spendLimit = parseBar(limits.spend_limit ?? limits.spendLimit);
1079
1086
  const models = {};
1080
- if (isObject4(limits.models))
1087
+ if (isObject5(limits.models))
1081
1088
  for (const [k, v] of Object.entries(limits.models)) {
1082
1089
  const bar = parseBar(v);
1083
1090
  if (bar)
1084
1091
  models[k] = bar;
1085
1092
  }
1086
- const usedCreditsUsd = num2(limits.usedCreditsUsd);
1093
+ const usedCreditsUsd = num3(limits.usedCreditsUsd);
1087
1094
  const hasModels = Object.keys(models).length > 0;
1088
1095
  if (!fiveHour && !sevenDay && !spendLimit && !hasModels && usedCreditsUsd === undefined)
1089
1096
  return null;
@@ -1126,28 +1133,28 @@ var formatSeatFragment = (w) => {
1126
1133
  };
1127
1134
  var seatStatePath = (home) => join5(configDir(home), "seat.json");
1128
1135
  var parseWindowStored = (v) => {
1129
- if (!isObject4(v))
1136
+ if (!isObject5(v))
1130
1137
  return;
1131
- const capturedAt = num2(v.capturedAt);
1138
+ const capturedAt = num3(v.capturedAt);
1132
1139
  if (capturedAt === undefined)
1133
1140
  return;
1134
1141
  return parseSeatWindow(v, capturedAt) ?? undefined;
1135
1142
  };
1136
1143
  var parseSeatState = (raw) => {
1137
- if (!isObject4(raw))
1144
+ if (!isObject5(raw))
1138
1145
  return {};
1139
1146
  const out = {};
1140
1147
  const window = parseWindowStored(raw.window);
1141
1148
  if (window)
1142
1149
  out.window = window;
1143
- const lastPostedAt = num2(raw.lastPostedAt);
1150
+ const lastPostedAt = num3(raw.lastPostedAt);
1144
1151
  if (lastPostedAt !== undefined)
1145
1152
  out.lastPostedAt = lastPostedAt;
1146
- if (isObject4(raw.lastPosted)) {
1153
+ if (isObject5(raw.lastPosted)) {
1147
1154
  const lp = {};
1148
- const f = num2(raw.lastPosted.fiveHour);
1149
- const s = num2(raw.lastPosted.sevenDay);
1150
- 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);
1151
1158
  if (f !== undefined)
1152
1159
  lp.fiveHour = f;
1153
1160
  if (s !== undefined)
@@ -1156,7 +1163,7 @@ var parseSeatState = (raw) => {
1156
1163
  lp.spendLimit = sp;
1157
1164
  out.lastPosted = lp;
1158
1165
  }
1159
- const lastWallResetsAt = num2(raw.lastWallResetsAt);
1166
+ const lastWallResetsAt = num3(raw.lastWallResetsAt);
1160
1167
  if (lastWallResetsAt !== undefined)
1161
1168
  out.lastWallResetsAt = lastWallResetsAt;
1162
1169
  const session = parseSeatSession(raw.session);
@@ -1165,9 +1172,9 @@ var parseSeatState = (raw) => {
1165
1172
  return out;
1166
1173
  };
1167
1174
  var parseSeatSession = (v) => {
1168
- if (!isObject4(v) || typeof v.id !== "string" || !v.id)
1175
+ if (!isObject5(v) || typeof v.id !== "string" || !v.id)
1169
1176
  return;
1170
- const at = num2(v.at);
1177
+ const at = num3(v.at);
1171
1178
  if (at === undefined)
1172
1179
  return;
1173
1180
  const out = { id: v.id, at };
@@ -1183,12 +1190,12 @@ var seatSessionFromStdin = (text, now) => {
1183
1190
  return null;
1184
1191
  try {
1185
1192
  const raw = JSON.parse(trimmed);
1186
- if (!isObject4(raw) || typeof raw.session_id !== "string" || !raw.session_id)
1193
+ if (!isObject5(raw) || typeof raw.session_id !== "string" || !raw.session_id)
1187
1194
  return null;
1188
1195
  const out = { id: raw.session_id, at: now };
1189
1196
  if (typeof raw.cwd === "string" && raw.cwd)
1190
1197
  out.cwd = raw.cwd;
1191
- const model = isObject4(raw.model) ? raw.model.id : raw.model;
1198
+ const model = isObject5(raw.model) ? raw.model.id : raw.model;
1192
1199
  if (typeof model === "string" && model)
1193
1200
  out.model = model;
1194
1201
  return out;
@@ -1315,11 +1322,11 @@ var readStdin = (timeoutMs, stdin = process.stdin) => new Promise((resolve3) =>
1315
1322
 
1316
1323
  // src/switch.ts
1317
1324
  init_settings();
1318
- var isObject5 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1319
- 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 : {};
1320
1327
  var capturePriorEnv = (settings) => {
1321
1328
  const env = envOf2(settings);
1322
- const prior = { hadEnv: isObject5(settings.env) };
1329
+ const prior = { hadEnv: isObject6(settings.env) };
1323
1330
  const url = env[BASE_URL_KEY];
1324
1331
  const token = env[AUTH_TOKEN_KEY];
1325
1332
  if (typeof url === "string")
@@ -2186,8 +2193,62 @@ var init = async (o) => {
2186
2193
  return 0;
2187
2194
  };
2188
2195
 
2189
- // src/mcp.ts
2190
- 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
+ }
2191
2252
  var PROTOCOL_VERSION = "2025-06-18";
2192
2253
  var SERVER_INFO = { name: "sleds", version: "0.0.1" };
2193
2254
  var MCP_TIMEOUT_MS = 5000;
@@ -2260,6 +2321,24 @@ var TOOLS = [
2260
2321
  required: ["task"]
2261
2322
  }
2262
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
+ },
2263
2342
  {
2264
2343
  name: "pickup",
2265
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.",
@@ -2271,109 +2350,37 @@ var TOOLS = [
2271
2350
  }
2272
2351
  ];
2273
2352
  var NOT_SET_UP = {
2274
- 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.",
2275
2354
  isError: true
2276
2355
  };
2277
2356
  var UNREACHABLE = {
2278
2357
  text: "Control plane unreachable. Nothing was recorded → try again in a moment.",
2279
2358
  isError: true
2280
2359
  };
2281
- var isObject6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
2282
- 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;
2283
2362
  var str2 = (v) => typeof v === "string" ? v : undefined;
2284
- async function proxyPost(deps, path, body) {
2285
- const src = meterSource(deps.home);
2286
- if (!src)
2287
- return null;
2288
- const fetchFn = deps.fetchFn ?? fetch;
2289
- try {
2290
- const res = await fetchFn(`${src.proxyUrl}${path}`, {
2291
- method: "POST",
2292
- headers: { "content-type": "application/json", authorization: `Bearer ${src.token}` },
2293
- body: JSON.stringify(body),
2294
- signal: AbortSignal.timeout(deps.timeoutMs ?? MCP_TIMEOUT_MS)
2295
- });
2296
- if (!res.ok)
2297
- return null;
2298
- const parsed = await res.json();
2299
- return isObject6(parsed) ? parsed : null;
2300
- } catch {
2301
- return null;
2302
- }
2303
- }
2304
- async function proxyPostFull(deps, path, body) {
2305
- const src = meterSource(deps.home);
2306
- if (!src)
2307
- return null;
2308
- const fetchFn = deps.fetchFn ?? fetch;
2309
- try {
2310
- const res = await fetchFn(`${src.proxyUrl}${path}`, {
2311
- method: "POST",
2312
- headers: { "content-type": "application/json", authorization: `Bearer ${src.token}` },
2313
- body: JSON.stringify(body),
2314
- signal: AbortSignal.timeout(deps.timeoutMs ?? MCP_TIMEOUT_MS)
2315
- });
2316
- let json = null;
2317
- try {
2318
- json = await res.json();
2319
- } catch {
2320
- json = null;
2321
- }
2322
- return { status: res.status, json: isObject6(json) ? json : null };
2323
- } catch {
2324
- return null;
2325
- }
2326
- }
2327
- var errorMessage = (j) => isObject6(j?.error) ? str2(j.error.message) : undefined;
2328
- async function proxyGet(deps, path) {
2329
- const src = meterSource(deps.home);
2330
- if (!src)
2331
- return null;
2332
- const fetchFn = deps.fetchFn ?? fetch;
2333
- try {
2334
- const res = await fetchFn(`${src.proxyUrl}${path}`, {
2335
- headers: { authorization: `Bearer ${src.token}` },
2336
- signal: AbortSignal.timeout(deps.timeoutMs ?? MCP_TIMEOUT_MS)
2337
- });
2338
- if (!res.ok)
2339
- return null;
2340
- const parsed = await res.json();
2341
- return isObject6(parsed) ? parsed : null;
2342
- } catch {
2343
- return null;
2344
- }
2345
- }
2346
- async function usageTool(deps) {
2347
- 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)
2348
2368
  return NOT_SET_UP;
2349
- const now = (deps.now ?? Date.now)();
2350
- const m = await loadMeter({
2351
- home: deps.home,
2352
- now,
2353
- fetchFn: deps.fetchFn,
2354
- timeoutMs: deps.timeoutMs
2355
- });
2356
- const frag = formatSeatFragment(readSeatState(deps.home).window ?? null);
2357
- if (!m) {
2358
- return {
2359
- text: frag ? `sleds offline (proxy did not answer) · ${frag}` : "sleds offline (proxy did not answer).",
2360
- isError: true
2361
- };
2362
- }
2363
- const lines = formatMeter(m, now);
2364
- if (frag)
2365
- lines.push(`${"Limits:".padEnd(12)}${frag.replace(/^seat /, "")}`);
2366
- 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(`
2367
2374
  `) };
2368
2375
  }
2369
2376
  function bandLine(band) {
2370
- if (!isObject6(band))
2377
+ if (!isObject7(band))
2371
2378
  return null;
2372
- const low = num3(band.lowUsd);
2373
- const high = num3(band.highUsd);
2374
- const lowM = num3(band.lowMinutes);
2375
- const highM = num3(band.highMinutes);
2376
- 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);
2377
2384
  if (low === undefined || high === undefined)
2378
2385
  return null;
2379
2386
  const d = high >= 10 ? 0 : 2;
@@ -2381,26 +2388,26 @@ function bandLine(band) {
2381
2388
  const pct = conf !== undefined ? ` · ${Math.round(conf * 100)}%` : "";
2382
2389
  return `$${low.toFixed(d)}–${high.toFixed(d)}${mins}${pct}`;
2383
2390
  }
2384
- async function estimateTool(deps, args) {
2385
- if (!meterSource(deps.home))
2391
+ async function estimateTool(ctx, args) {
2392
+ if (!ctx.client)
2386
2393
  return NOT_SET_UP;
2387
2394
  const spec = str2(args.spec)?.trim();
2388
2395
  if (!spec)
2389
2396
  return { text: "Nothing to estimate. Pass spec: what the job should do.", isError: true };
2390
- const source = isObject6(args.source) && str2(args.source.kind) && str2(args.source.project) ? args.source : undefined;
2391
- 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", {
2392
2399
  spec,
2393
2400
  model: str2(args.model),
2394
2401
  ...source ? { source } : {}
2395
2402
  });
2396
2403
  if (!r)
2397
2404
  return UNREACHABLE;
2398
- const band = isObject6(r.band) ? r.band : {};
2405
+ const band = isObject7(r.band) ? r.band : {};
2399
2406
  const line = bandLine(band) ?? "band unreadable";
2400
2407
  const method = str2(band.method) ?? "plan";
2401
- const cap = num3(band.capUsd);
2402
- const threshold = num3(r.approvalThresholdUsd);
2403
- 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"}.` : "";
2404
2411
  const assumptions = Array.isArray(band.assumptions) ? band.assumptions.filter((a) => typeof a === "string") : [];
2405
2412
  const tail = assumptions.length > 0 ? `
2406
2413
  Assumes: ${assumptions.join("; ")}.` : "";
@@ -2418,11 +2425,11 @@ function byModelText(raw) {
2418
2425
  return "";
2419
2426
  const parts = [];
2420
2427
  for (const row2 of raw) {
2421
- if (!isObject6(row2) || !isObject6(row2.standard))
2428
+ if (!isObject7(row2) || !isObject7(row2.standard))
2422
2429
  continue;
2423
2430
  const model = str2(row2.model);
2424
- const low = num3(row2.standard.lowUsd);
2425
- const high = num3(row2.standard.highUsd);
2431
+ const low = num4(row2.standard.lowUsd);
2432
+ const high = num4(row2.standard.highUsd);
2426
2433
  if (!model || low === undefined || high === undefined)
2427
2434
  continue;
2428
2435
  const m = /^claude-([a-z]+)-(\d+)(?:-(\d+))?/.exec(model);
@@ -2433,7 +2440,7 @@ function byModelText(raw) {
2433
2440
  By model: ${parts.join(" · ")} (overnight batch ½).` : "";
2434
2441
  }
2435
2442
  function routingText(raw) {
2436
- if (!isObject6(raw) || !Array.isArray(raw.segments) || !isObject6(raw.cost))
2443
+ if (!isObject7(raw) || !Array.isArray(raw.segments) || !isObject7(raw.cost))
2437
2444
  return "";
2438
2445
  const short = (model) => {
2439
2446
  const m = /^claude-([a-z]+)-(\d+)(?:-(\d+))?/.exec(model);
@@ -2441,10 +2448,10 @@ function routingText(raw) {
2441
2448
  };
2442
2449
  const parts = [];
2443
2450
  for (const s of raw.segments) {
2444
- if (!isObject6(s))
2451
+ if (!isObject7(s))
2445
2452
  continue;
2446
- const from = num3(s.from);
2447
- const to = num3(s.to);
2453
+ const from = num4(s.from);
2454
+ const to = num4(s.to);
2448
2455
  const model = str2(s.model);
2449
2456
  if (from === undefined || to === undefined || !model)
2450
2457
  continue;
@@ -2452,55 +2459,55 @@ function routingText(raw) {
2452
2459
  parts.push(`${from === to ? from : `${from}–${to}`} ${short(model)}${reasons.length ? ` (${reasons.slice(0, 3).join(", ")})` : ""}`);
2453
2460
  }
2454
2461
  const c = raw.cost;
2455
- const lo = num3(c.lowUsd);
2456
- const hi = num3(c.highUsd);
2457
- const slo = num3(c.singleLowUsd);
2458
- 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);
2459
2466
  const single = str2(c.singleModel);
2460
2467
  if (parts.length === 0 || lo === undefined || hi === undefined || slo === undefined || shi === undefined || !single)
2461
2468
  return "";
2462
2469
  return `
2463
2470
  Routing: ${parts.join(" · ")} ≈ ${usdRange(lo, hi)} vs ${usdRange(slo, shi)} all ${short(single)}.`;
2464
2471
  }
2465
- async function overnightTool(deps, args) {
2466
- if (!meterSource(deps.home))
2472
+ async function overnightTool(ctx, args) {
2473
+ if (!ctx.client)
2467
2474
  return NOT_SET_UP;
2468
2475
  const spec = str2(args.spec)?.trim();
2469
2476
  if (!spec)
2470
2477
  return { text: "Nothing to queue. Pass spec: what the job should do.", isError: true };
2471
- 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) });
2472
2479
  if (!r)
2473
2480
  return { text: `Could not queue the job. ${UNREACHABLE.text}`, isError: true };
2474
2481
  const jobId = str2(r.jobId) ?? "unknown";
2475
- const now = (deps.now ?? Date.now)();
2476
- const at = num3(r.scheduledAt);
2482
+ const now = (ctx.now ?? Date.now)();
2483
+ const at = num4(r.scheduledAt);
2477
2484
  const when = at !== undefined && at > now ? `Runs in ${shortDuration(at - now)}` : "Runs at the next tick";
2478
2485
  const band = bandLine(r.band);
2479
- const cap = isObject6(r.band) ? num3(r.band.capUsd) : undefined;
2486
+ const cap = isObject7(r.band) ? num4(r.band.capUsd) : undefined;
2480
2487
  const sized = band ? ` ${band}${cap !== undefined ? ` · cap ${usd(cap)}` : ""}.` : "";
2481
2488
  return {
2482
2489
  text: `Queued overnight. Batch tier · ½ price.${sized} ${when}. Check with the jobs tool; pull the result into a session with /sled resume ${jobId}.`
2483
2490
  };
2484
2491
  }
2485
- async function jobsTool(deps) {
2486
- if (!meterSource(deps.home))
2492
+ async function jobsTool(ctx) {
2493
+ if (!ctx.client)
2487
2494
  return NOT_SET_UP;
2488
- const r = await proxyGet(deps, "/proxy/jobs");
2495
+ const r = await ctx.client.get("/proxy/jobs");
2489
2496
  if (!r)
2490
2497
  return UNREACHABLE;
2491
- const rows = Array.isArray(r.jobs) ? r.jobs.filter(isObject6) : [];
2492
- const handoffs = Array.isArray(r.handoffs) ? r.handoffs.filter(isObject6) : [];
2493
- 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)();
2494
2501
  if (rows.length === 0 && handoffs.length === 0)
2495
2502
  return { text: "No jobs for this seat. Queue one with the overnight tool." };
2496
2503
  if (rows.length === 0)
2497
2504
  return { text: ["No jobs for this seat.", ...handoffLines(handoffs, now)].join(`
2498
2505
  `) };
2499
2506
  const lines = rows.map((j) => {
2500
- 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))) : "";
2501
2508
  const status = str2(j.status) ?? "unknown";
2502
- const cost = num3(j.costUsd);
2503
- 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) ?? "";
2504
2511
  return [
2505
2512
  str2(j.jobId) ?? "?",
2506
2513
  status.padEnd(12),
@@ -2522,7 +2529,7 @@ function handoffLines(handoffs, now) {
2522
2529
  const forMe = h.forMe === true;
2523
2530
  const to = str2(h.to);
2524
2531
  const who = forMe ? to ? "for you" : "parked for anyone" : `for ${to ?? "anyone"}`;
2525
- const created = num3(h.createdAt);
2532
+ const created = num4(h.createdAt);
2526
2533
  const age = created !== undefined ? `${shortDuration(Math.max(0, now - created))} ago` : "";
2527
2534
  const note = str2(h.note);
2528
2535
  const parts = [`from ${str2(h.from) ?? "?"}`, who, str2(h.wallKind) ?? "", age].filter(Boolean);
@@ -2533,16 +2540,16 @@ function handoffLines(handoffs, now) {
2533
2540
  out.push("Take one in Claude Code with /sled pickup <id>.");
2534
2541
  return out;
2535
2542
  }
2536
- async function handoffsTool(deps) {
2537
- if (!meterSource(deps.home))
2543
+ async function handoffsTool(ctx) {
2544
+ if (!ctx.client)
2538
2545
  return NOT_SET_UP;
2539
- const r = await proxyGet(deps, "/proxy/jobs");
2546
+ const r = await ctx.client.get("/proxy/jobs");
2540
2547
  if (!r)
2541
2548
  return UNREACHABLE;
2542
- const handoffs = Array.isArray(r.handoffs) ? r.handoffs.filter(isObject6) : [];
2549
+ const handoffs = Array.isArray(r.handoffs) ? r.handoffs.filter(isObject7) : [];
2543
2550
  if (handoffs.length === 0)
2544
2551
  return { text: "No open hand-offs on your team. Park one with the handoff tool." };
2545
- const now = (deps.now ?? Date.now)();
2552
+ const now = (ctx.now ?? Date.now)();
2546
2553
  const packets = handoffs.map((h) => str2(h.packet)).filter((p) => Boolean(p)).join(`
2547
2554
 
2548
2555
  ---
@@ -2555,14 +2562,14 @@ ${packets}` : ""].join(`
2555
2562
  `)
2556
2563
  };
2557
2564
  }
2558
- async function handoffTool(deps, args) {
2559
- if (!meterSource(deps.home))
2565
+ async function handoffTool(ctx, args) {
2566
+ if (!ctx.client)
2560
2567
  return NOT_SET_UP;
2561
2568
  const task = str2(args.task)?.trim();
2562
2569
  if (!task)
2563
2570
  return { text: "Nothing to hand off. Pass task: what the picker should do.", isError: true };
2564
2571
  const to = str2(args.to)?.trim();
2565
- const r = await proxyPostFull(deps, "/proxy/handoff/park", {
2572
+ const r = await ctx.client.postFull("/proxy/handoff/park", {
2566
2573
  task,
2567
2574
  to: to || undefined,
2568
2575
  note: str2(args.note)?.trim() || undefined
@@ -2581,13 +2588,13 @@ async function handoffTool(deps, args) {
2581
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.`
2582
2589
  };
2583
2590
  }
2584
- async function pickupTool(deps, args) {
2585
- if (!meterSource(deps.home))
2591
+ async function pickupTool(ctx, args) {
2592
+ if (!ctx.client)
2586
2593
  return NOT_SET_UP;
2587
2594
  const handoffId = str2(args.handoffId)?.trim();
2588
2595
  if (!handoffId)
2589
2596
  return { text: "Pass handoffId, from the handoffs tool.", isError: true };
2590
- const r = await proxyPostFull(deps, "/proxy/handoff/pickup", { handoffId });
2597
+ const r = await ctx.client.postFull("/proxy/handoff/pickup", { handoffId });
2591
2598
  if (!r)
2592
2599
  return { text: `Nothing was picked up. ${UNREACHABLE.text}`, isError: true };
2593
2600
  if (r.status !== 200)
@@ -2608,7 +2615,7 @@ ${str2(j.task) ?? ""}
2608
2615
  Carry it through from here.` };
2609
2616
  const first = str2(j.firstUserText) ?? "";
2610
2617
  const last = str2(j.lastUserText) ?? "";
2611
- const n = num3(j.messageCount);
2618
+ const n = num4(j.messageCount);
2612
2619
  return {
2613
2620
  text: [
2614
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.`,
@@ -2623,29 +2630,60 @@ ${last}`] : [],
2623
2630
  `)
2624
2631
  };
2625
2632
  }
2626
- 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) {
2627
2663
  switch (name) {
2628
2664
  case "usage":
2629
- return usageTool(deps);
2665
+ return usageTool(ctx);
2630
2666
  case "estimate":
2631
- return estimateTool(deps, args);
2667
+ return estimateTool(ctx, args);
2632
2668
  case "overnight":
2633
- return overnightTool(deps, args);
2669
+ return overnightTool(ctx, args);
2634
2670
  case "jobs":
2635
- return jobsTool(deps);
2671
+ return jobsTool(ctx);
2636
2672
  case "handoffs":
2637
- return handoffsTool(deps);
2673
+ return handoffsTool(ctx);
2638
2674
  case "handoff":
2639
- return handoffTool(deps, args);
2675
+ return handoffTool(ctx, args);
2640
2676
  case "pickup":
2641
- return pickupTool(deps, args);
2677
+ return pickupTool(ctx, args);
2678
+ case "defer":
2679
+ return deferTool(ctx, args);
2642
2680
  default:
2643
2681
  return { text: `Unknown tool: ${name}`, isError: true };
2644
2682
  }
2645
2683
  }
2646
2684
  var response = (id, result) => JSON.stringify({ jsonrpc: "2.0", id, result });
2647
2685
  var errorResponse = (id, code, message) => JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
2648
- async function handleLine(line, deps) {
2686
+ async function handleLine(line, ctx) {
2649
2687
  const trimmed = line.trim();
2650
2688
  if (trimmed.length === 0)
2651
2689
  return null;
@@ -2655,7 +2693,7 @@ async function handleLine(line, deps) {
2655
2693
  } catch {
2656
2694
  return errorResponse(null, -32700, "parse error");
2657
2695
  }
2658
- if (!isObject6(msg))
2696
+ if (!isObject7(msg))
2659
2697
  return errorResponse(null, -32600, "invalid request");
2660
2698
  const id = typeof msg.id === "string" || typeof msg.id === "number" ? msg.id : null;
2661
2699
  const method = str2(msg.method);
@@ -2664,7 +2702,7 @@ async function handleLine(line, deps) {
2664
2702
  return isNotification ? null : errorResponse(id, -32600, "invalid request");
2665
2703
  if (method.startsWith("notifications/"))
2666
2704
  return null;
2667
- const params = isObject6(msg.params) ? msg.params : {};
2705
+ const params = isObject7(msg.params) ? msg.params : {};
2668
2706
  switch (method) {
2669
2707
  case "initialize": {
2670
2708
  const requested = str2(params.protocolVersion);
@@ -2680,8 +2718,8 @@ async function handleLine(line, deps) {
2680
2718
  return response(id, { tools: TOOLS });
2681
2719
  case "tools/call": {
2682
2720
  const name = str2(params.name) ?? "";
2683
- const args = isObject6(params.arguments) ? params.arguments : {};
2684
- const r = await callTool(name, args, deps);
2721
+ const args = isObject7(params.arguments) ? params.arguments : {};
2722
+ const r = await callTool(name, args, ctx);
2685
2723
  return response(id, {
2686
2724
  content: [{ type: "text", text: r.text }],
2687
2725
  ...r.isError ? { isError: true } : {}
@@ -2692,6 +2730,38 @@ async function handleLine(line, deps) {
2692
2730
  }
2693
2731
  }
2694
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
+
2695
2765
  // src/commands/mcp.ts
2696
2766
  var mcp = async (o) => {
2697
2767
  const stdin = o.stdin ?? process.stdin;
@@ -2705,7 +2775,7 @@ var mcp = async (o) => {
2705
2775
  while (nl !== -1) {
2706
2776
  const line = buffer.slice(0, nl);
2707
2777
  buffer = buffer.slice(nl + 1);
2708
- const out = await handleLine(line, { home: o.home });
2778
+ const out = await handleLine2(line, { home: o.home });
2709
2779
  if (out !== null)
2710
2780
  write(out);
2711
2781
  nl = buffer.indexOf(`
@@ -2713,7 +2783,7 @@ var mcp = async (o) => {
2713
2783
  }
2714
2784
  }
2715
2785
  if (buffer.trim().length > 0) {
2716
- const out = await handleLine(buffer, { home: o.home });
2786
+ const out = await handleLine2(buffer, { home: o.home });
2717
2787
  if (out !== null)
2718
2788
  write(out);
2719
2789
  }
@@ -3225,11 +3295,11 @@ init_config();
3225
3295
  init_meter();
3226
3296
  var HOOK_STDIN_TIMEOUT_MS = 1000;
3227
3297
  var NOTIFICATION_TITLE = "sleds";
3228
- var isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3298
+ var isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3229
3299
  var notificationType = (text) => {
3230
3300
  try {
3231
3301
  const raw = JSON.parse(text);
3232
- if (!isObject7(raw))
3302
+ if (!isObject8(raw))
3233
3303
  return;
3234
3304
  return typeof raw.notification_type === "string" ? raw.notification_type : undefined;
3235
3305
  } catch {
@@ -3404,8 +3474,8 @@ function resolveProfileDir(localStateJson, profile) {
3404
3474
  if (localStateJson) {
3405
3475
  try {
3406
3476
  const raw = JSON.parse(localStateJson);
3407
- const p = isObject8(raw) && isObject8(raw.profile) ? raw.profile : null;
3408
- if (p && isObject8(p.info_cache))
3477
+ const p = isObject9(raw) && isObject9(raw.profile) ? raw.profile : null;
3478
+ if (p && isObject9(p.info_cache))
3409
3479
  cache = p.info_cache;
3410
3480
  } catch {}
3411
3481
  }
@@ -3414,7 +3484,7 @@ function resolveProfileDir(localStateJson, profile) {
3414
3484
  const want = profile.toLowerCase();
3415
3485
  const hits = [];
3416
3486
  for (const [dir, info] of Object.entries(cache)) {
3417
- if (!isObject8(info))
3487
+ if (!isObject9(info))
3418
3488
  continue;
3419
3489
  const match = ["name", "user_name", "gaia_name"].some((k) => {
3420
3490
  const v = info[k];
@@ -3452,23 +3522,23 @@ function sourceArgs(source) {
3452
3522
  out.push("--token", source.token);
3453
3523
  return out;
3454
3524
  }
3455
- var isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3456
- 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;
3457
3527
  var round2 = (n) => Math.round(n * 100) / 100;
3458
3528
  function parseUsageResponse(raw, now = Date.now()) {
3459
- if (!isObject8(raw))
3529
+ if (!isObject9(raw))
3460
3530
  return null;
3461
3531
  const out = { capturedAt: now, models: {} };
3462
3532
  for (const [k, v] of Object.entries(raw)) {
3463
- if (!isObject8(v))
3533
+ if (!isObject9(v))
3464
3534
  continue;
3465
3535
  if (k === "extra_usage") {
3466
- const credits = num4(v.used_credits);
3536
+ const credits = num5(v.used_credits);
3467
3537
  if (credits !== undefined)
3468
3538
  out.usedCreditsUsd = round2(credits / 100);
3469
3539
  continue;
3470
3540
  }
3471
- const usedPct = num4(v.utilization);
3541
+ const usedPct = num5(v.utilization);
3472
3542
  const resetsAt = parseResetsAt(v.resets_at);
3473
3543
  if (usedPct === undefined || usedPct < 0 || resetsAt === undefined)
3474
3544
  continue;
@@ -4433,7 +4503,7 @@ var main = async (argv) => {
4433
4503
  case "version":
4434
4504
  case "--version":
4435
4505
  case "-v":
4436
- console.log("sleds 0.1.15");
4506
+ console.log("sleds 0.1.16");
4437
4507
  return 0;
4438
4508
  default:
4439
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.15",
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
  }